A Terraform-first Approach to Internal Developer Portals

March 14, 2023

A Terraform-first Approach to Internal Developer Portals

Ready to start?

Introduction

Port provides a platform for building internal developer portals. Building and managing an internal developer portal can be a challenging task, even for experienced platform engineers. They need to ensure that the developers get a great self-service experience that makes sense, and that the portal is built in a way that maximizes its benefits. They also need to make many design choices about how to model their software catalog, when to apply workflow automation and the extent of self-service they want to provide developers. 

To make it easy for platform engineers, we chose to make Port both API and Terraform first, so that everything can be configurable using Terraform. In this post we’ll explain why.

What about No-code?

Port is a no-code internal developer portal platform. We plan to keep it this way. Using Port’s UI, exporters, connectors, blueprints and RBAC modules, you can indeed set up an internal developer portal without coding. You’ll get the ability to model your services, CI/CD and cloud resources and to deliver a great UI for developers, all without coding.

But that doesn’t mean that no-code is all there is. We also made Port API-first, so that platform engineers can interact with anything in Port using the API. We know that this is what DevOps prefer, and it works well in many cases involving automations in Port. But the more we thought about it, we understood that Port also needs to be Terraform-first.

Platform engineers want to use Terraform

Platform engineers are usually familiar with Terraform and use it to manage infrastructure as code. This solves version control, automation, and repeatability for them. So, it's natural for platform engineers to prefer using Terraform to configure the developer portal rather than using a user interface.

Internal developer portals are part of the infrastructure

At Port, we see the developer portal as part of the infrastructure. It then follows that platform engineers should manage the IDP as code. By managing the developer portal as code, platform engineers can automate configuration and apply version control, just like they do with other infrastructure components. This approach ensures consistency across the infrastructure and the developer portal.

{{cta_4}}

Managing different experiences for different developers

Internal developer portals are made to offer different experiences for different developers. This can be a result of the team they are in, role-based access control policies, as well as developer proficiency in different aspects CI/CD, Kubernetes, etc. Similarly, developers will get access to different types of developer self-service actions, with different TTLs etc. 

Manually managing all these configurations can be a daunting task. Using Terraform, platform engineers can automate the configuration process and ensure that the portal is configured according to the policies they’ve set.

Internal developer portals are infrastructure and changes should be treated as such 

The developer portal is the product that platform engineers provide to their customers, the developers, so it's crucial to ensure that it's thoroughly tested and validated before deploying to production - as with any other product.

With Terraform, platform engineers can define the developer portal for both test and production environments in code and then easily apply it to the corresponding environments. Terraform's ability to create resources in a consistent and repeatable way ensures that the test and production environments are identical, minimizing the risk of issues arising in production due to environmental differences.

Moreover, Terraform's state management system ensures that changes made to the infrastructure in one environment are recorded and can be quickly replicated to another environment, reducing the risk of human errors when moving changes between environments.

Conclusion

While it’s super important to be API-first and provide a no-code platform for developer portals, we believe that many platform engineers will prefer to interact with Port through Terraform. By using Terraform to configure the developer portal, platform engineers can leverage their existing skills, manage the portal as part of the infrastructure, and provide a customized experience for developers. Most importantly, they get to interact with the IDP through the tool they know and love.

Assuming platform engineers have many additional favorite IaC tools, we’re working on adding them. Soon, we hope to have the option to set up the developer portal using Pulumi (thank you Engin!) and Crossplane. This will give our users even more flexibility and choice in how they manage their developer portal infrastructure.

{{cta_1}}

Check out Port's pre-populated demo and see what it's all about.

Check live demo

No email required

{{cta_2}}

Contact sales for a technical product walkthrough

Let’s start
{{cta_3}}

Open a free Port account. No credit card required

Let’s start
{{cta_4}}

Watch Port live coding videos - setting up an internal developer portal & platform

{{cta_5}}

Check out Port's pre-populated demo and see what it's all about.

(no email required)

Let’s start
{{cta_6}}

Contact sales for a technical product walkthrough

Let’s start
{{cta_7}}

Open a free Port account. No credit card required

Let’s start
{{cta_8}}

Watch Port live coding videos - setting up an internal developer portal & platform

{{cta-demo}}
{{reading-box-backstage-vs-port}}

Example JSON block

{
  "foo": "bar"
}

Order Domain

{
  "properties": {},
  "relations": {},
  "title": "Orders",
  "identifier": "Orders"
}

Cart System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Cart",
  "title": "Cart"
}

Products System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Products",
  "title": "Products"
}

Cart Resource

{
  "properties": {
    "type": "postgress"
  },
  "relations": {},
  "icon": "GPU",
  "title": "Cart SQL database",
  "identifier": "cart-sql-sb"
}

Cart API

{
 "identifier": "CartAPI",
 "title": "Cart API",
 "blueprint": "API",
 "properties": {
   "type": "Open API"
 },
 "relations": {
   "provider": "CartService"
 },
 "icon": "Link"
}

Core Kafka Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Kafka Library",
  "identifier": "CoreKafkaLibrary"
}

Core Payment Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Payment Library",
  "identifier": "CorePaymentLibrary"
}

Cart Service JSON

{
 "identifier": "CartService",
 "title": "Cart Service",
 "blueprint": "Component",
 "properties": {
   "type": "service"
 },
 "relations": {
   "system": "Cart",
   "resources": [
     "cart-sql-sb"
   ],
   "consumesApi": [],
   "components": [
     "CorePaymentLibrary",
     "CoreKafkaLibrary"
   ]
 },
 "icon": "Cloud"
}

Products Service JSON

{
  "identifier": "ProductsService",
  "title": "Products Service",
  "blueprint": "Component",
  "properties": {
    "type": "service"
  },
  "relations": {
    "system": "Products",
    "consumesApi": [
      "CartAPI"
    ],
    "components": []
  }
}

Component Blueprint

{
 "identifier": "Component",
 "title": "Component",
 "icon": "Cloud",
 "schema": {
   "properties": {
     "type": {
       "enum": [
         "service",
         "library"
       ],
       "icon": "Docs",
       "type": "string",
       "enumColors": {
         "service": "blue",
         "library": "green"
       }
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "system": {
     "target": "System",
     "required": false,
     "many": false
   },
   "resources": {
     "target": "Resource",
     "required": false,
     "many": true
   },
   "consumesApi": {
     "target": "API",
     "required": false,
     "many": true
   },
   "components": {
     "target": "Component",
     "required": false,
     "many": true
   },
   "providesApi": {
     "target": "API",
     "required": false,
     "many": false
   }
 }
}

Resource Blueprint

{
 “identifier”: “Resource”,
 “title”: “Resource”,
 “icon”: “DevopsTool”,
 “schema”: {
   “properties”: {
     “type”: {
       “enum”: [
         “postgress”,
         “kafka-topic”,
         “rabbit-queue”,
         “s3-bucket”
       ],
       “icon”: “Docs”,
       “type”: “string”
     }
   },
   “required”: []
 },
 “mirrorProperties”: {},
 “formulaProperties”: {},
 “calculationProperties”: {},
 “relations”: {}
}

API Blueprint

{
 "identifier": "API",
 "title": "API",
 "icon": "Link",
 "schema": {
   "properties": {
     "type": {
       "type": "string",
       "enum": [
         "Open API",
         "grpc"
       ]
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "provider": {
     "target": "Component",
     "required": true,
     "many": false
   }
 }
}

Domain Blueprint

{
 "identifier": "Domain",
 "title": "Domain",
 "icon": "Server",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {}
}

System Blueprint

{
 "identifier": "System",
 "title": "System",
 "icon": "DevopsTool",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "domain": {
     "target": "Domain",
     "required": true,
     "many": false
   }
 }
}
{{tabel-1}}

Microservices SDLC

  • Scaffold a new microservice

  • Deploy (canary or blue-green)

  • Feature flagging

  • Revert

  • Lock deployments

  • Add Secret

  • Force merge pull request (skip tests on crises)

  • Add environment variable to service

  • Add IaC to the service

  • Upgrade package version

Development environments

  • Spin up a developer environment for 5 days

  • ETL mock data to environment

  • Invite developer to the environment

  • Extend TTL by 3 days

Cloud resources

  • Provision a cloud resource

  • Modify a cloud resource

  • Get permissions to access cloud resource

SRE actions

  • Update pod count

  • Update auto-scaling group

  • Execute incident response runbook automation

Data Engineering

  • Add / Remove / Update Column to table

  • Run Airflow DAG

  • Duplicate table

Backoffice

  • Change customer configuration

  • Update customer software version

  • Upgrade - Downgrade plan tier

  • Create - Delete customer

Machine learning actions

  • Train model

  • Pre-process dataset

  • Deploy

  • A/B testing traffic route

  • Revert

  • Spin up remote Jupyter notebook

{{tabel-2}}

Engineering tools

  • Observability

  • Tasks management

  • CI/CD

  • On-Call management

  • Troubleshooting tools

  • DevSecOps

  • Runbooks

Infrastructure

  • Cloud Resources

  • K8S

  • Containers & Serverless

  • IaC

  • Databases

  • Environments

  • Regions

Software and more

  • Microservices

  • Docker Images

  • Docs

  • APIs

  • 3rd parties

  • Runbooks

  • Cron jobs

Starting with Port is simple, fast and free.

Let’s start