Integrating Terraform with Backstage
In the drive to enhance developer experience and streamline infrastructure workflows, integrating Infrastructure as Code (IaC) tools with developer portals has become a strategic imperative. Backstage, a popular open-source framework for building developer portals, combined with Terraform, the de facto standard for IaC, offers a potent solution for enabling developer self-service, enforcing standardization, and improving visibility.
Why Bridge Backstage and Terraform?
The core motivation is to empower developers. By integrating Terraform into Backstage, organizations allow development teams to provision and manage necessary infrastructure—like databases, CI/CD pipelines, or cloud storage—directly from a familiar interface. This abstracts away the underlying complexities of HCL and cloud provider APIs, enabling faster development cycles. Furthermore, it ensures that all provisioned infrastructure adheres to organizational best practices, security policies, and governance standards through pre-defined, validated templates. This synergy solves common pain points like slow provisioning, inconsistent tooling, and lack of discoverability for infrastructure resources.
Navigating the Integration Landscape
Several paths exist for this integration:
- The Open-Source Route: Leveraging Backstage's Scaffolder with custom CI/CD pipelines to run Terraform CLI commands offers maximum flexibility. This approach provides complete control but demands significant engineering effort for setup, maintenance, and security.
- Terraform Cloud: HashiCorp's managed service can offload Terraform execution and state management. Backstage plugins can provide visibility and sometimes control over Terraform Cloud workspaces. This simplifies operations but introduces costs and reliance on the HashiCorp ecosystem, which is exclusively Terraform-centric.
- Terraform Cloud Alternatives like Scalr: Platforms such as Scalr offer a compelling alternative for managing Terraform (and other tools like OpenTofu and Terragrunt) at scale, presenting distinct advantages in a Backstage integration.
Conceptual Code Sample (Backstage Plugin interacting with Scalr API):
// backstage-scalr-plugin-component.ts (Simplified)
// Assuming a Scalr API client library or direct fetch calls
async function provisionWithScalr(environmentId: string, workspaceName: string, variables: Record<string, any>) {
const SCALR_API_ENDPOINT = 'https://mycompany.scalr.io/api/iac/v3'; // Example
const SCALR_TOKEN = '...'; // Securely obtained token
try {
// 1. Find or create workspace (simplified)
// This might involve checking if a workspace with `workspaceName` exists in `environmentId`
// or creating it if it doesn't.
// 2. Create a new configuration version (if not VCS-driven)
// This would involve uploading the Terraform code or pointing to a VCS commit.
// 3. Create and run a deployment (plan & apply)
const response = await fetch(`${SCALR_API_ENDPOINT}/environments/${environmentId}/workspaces/${workspaceName}/runs`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${SCALR_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: {
type: 'runs',
attributes: {
message: 'Deployment triggered from Backstage',
'is-destroy': false,
// 'auto-apply': true, // If desired
variables: Object.entries(variables).map(([key, value]) => ({
name: key,
value: String(value),
sensitive: false,
hcl: false, // Or true if it's HCL
})),
// Specify configuration version, etc.
},
},
}),
});
if (!response.ok) {
throw new Error(`Scalr API error: ${response.statusText}`);
}
const run = await response.json();
console.log(`Scalr deployment ${run.data.id} initiated.`);
// Monitor run status via further API calls or Scalr UI
} catch (error) {
console.error('Error provisioning with Scalr:', error);
}
}
Conceptual Code Sample (Backstage Plugin interacting with TFC API):
// backstage-tfc-plugin-component.ts (Simplified)
import { tfeApiRef } from '@backstage/plugin-terraform-common';
// ...
async function provisionWithTFC(workspaceId: string, variables: Record<string, any>) {
const tfeApi = useApi(tfeApiRef);
try {
// 1. Create a new run
const run = await tfeApi.createRun({
workspaceId,
message: 'Run triggered from Backstage',
// Potentially set autoApply: true if desired
});
// 2. (Optional) Upload configuration versions if not VCS-driven
// 3. (Optional) Set variables for the run
await tfeApi.setVariables({
workspaceId,
runId: run.id, // Or apply to workspace directly
variables: Object.entries(variables).map(([key, value]) => ({
key,
value: String(value),
category: 'terraform',
sensitive: false,
})),
});
// 4. (If not auto-apply) Apply the run after plan review
// This might involve manual steps in TFC UI or further API calls
console.log(`Terraform Cloud run ${run.id} created. Review and apply in TFC.`);
} catch (error) {
console.error('Error provisioning with Terraform Cloud:', error);
}
}
Conceptual Code Sample (Backstage Scaffolder Template Action):
# scaffolder-template.yaml
# ...
steps:
- id: trigger-terraform-pipeline
name: Trigger Terraform CI/CD Pipeline
action: 'http:request' # Or a custom action for your CI/CD system
input:
url: 'https://my-ci-cd.example.com/api/v1/trigger'
method: 'POST'
headers:
Content-Type: 'application/json'
Authorization: 'Bearer ${{ parameters.ciCdToken }}'
body:
repository: '${{ parameters.gitRepoUrl }}'
branch: 'main'
terraformAction: 'apply'
variables:
instance_type: '${{ parameters.instanceType }}'
region: '${{ parameters.region }}'
# ...
In the CI/CD pipeline (e.g., Jenkins, GitLab CI, GitHub Actions):
# ci-cd-pipeline-script.sh
terraform init
terraform validate
terraform plan -out=tfplan -var="instance_type=$INSTANCE_TYPE" -var="region=$REGION"
# Potentially add an approval gate here
terraform apply -auto-approve tfplan
Considering Your Options: The Scalr Perspective
While each approach has its merits, organizations with complex environments or those seeking greater adaptability may find platforms like Scalr particularly aligned with their needs. Scalr's architecture, for instance, provides notable backend flexibility, allowing teams to use their existing state storage solutions rather than being tied to a proprietary backend. This can be a significant advantage for enterprises with established practices.
Furthermore, Scalr's hierarchical model for organizing accounts, environments, and workspaces, coupled with its approach to sharing credentials and policies, can map more effectively to the intricate structures of larger organizations. This facilitates more granular governance and simpler management across diverse teams and projects. When Backstage aims to be the single pane of glass for a wide array of infrastructure needs, the underlying IaC management platform's ability to support this complexity without imposing undue restrictions becomes critical.
Summary Comparison
Feature | Open-Source (Custom CI/CD) | Terraform Cloud | Scalr (and similar alternatives) |
---|---|---|---|
Control & Flexibility | Very High | Medium | High |
Engineering Effort | High | Low | Medium |
Cost | Potentially Low (infra) | Usage-based (HashiCorp) | Subscription-based |
State Management | Self-managed | Managed by TFC | Flexible (self or managed by Scalr) |
Governance | Custom implementation | TFC Policies (OPA) | Scalr Policies (OPA), RBAC, Hierarchy |
Multi-IaC Tooling | Yes (with custom work) | Terraform only | Yes (Terraform, OpenTofu, etc.) |
Vendor Lock-in | Low | Medium (HashiCorp ecosystem) | Low |
Setup Complexity | High | Medium | Medium |
Scalability | Depends on CI/CD setup | High | High |
Community Support | Large (Backstage, TF) | Large (Terraform) | Growing |
Making the Right Choice
Ultimately, the decision on how to integrate Terraform with Backstage depends on an organization's specific requirements, existing infrastructure, technical expertise, and budget. The open-source path offers unparalleled customization, while Terraform Cloud provides a managed, albeit Terraform-specific, solution. For those prioritizing flexibility, robust governance in multifaceted environments, and broader IaC tool support, exploring alternatives like Scalr is a prudent step. The goal remains a seamless developer experience, underpinned by powerful, governed, and efficient infrastructure automation.