Input Parameters and Output Mapping¶
Overview¶
Terraform resources in Omnistrate support two key integration mechanisms:
- Input parameters: Pass dynamic values into your Terraform configuration through variables — including system parameters, API parameters, and inline variable overrides
- Output mapping: Export values from your Terraform state (endpoints, ARNs, IDs) and inject them into dependent resources like Helm charts, Operators, or other Terraform stacks
Together, these let you build fully wired, multi-resource SaaS Products where infrastructure provisioned by Terraform is seamlessly connected to application layers.
Input Parameters¶
System Parameters in Terraform Templates¶
Omnistrate injects system parameters directly into your .tf files at deployment time. Wrap system parameter references in {{ }} within your Terraform configuration:
provider "aws" {
region = "{{ $sys.deploymentCell.region }}"
}
resource "aws_security_group" "app_sg" {
name = "app-sg-{{ $sys.id }}"
vpc_id = "{{ $sys.deploymentCell.cloudProviderNetworkID }}"
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["{{ $sys.deploymentCell.cidrRange }}"]
}
}
resource "aws_db_subnet_group" "main" {
name = "db-subnet-{{ $sys.id }}"
subnet_ids = [
"{{ $sys.deploymentCell.privateSubnetIDs[0].id }}",
"{{ $sys.deploymentCell.privateSubnetIDs[1].id }}"
]
}
Commonly used system parameters in Terraform templates:
| Parameter | Description |
|---|---|
$sys.id | Unique deployment identifier — use for naming resources to avoid collisions |
$sys.deploymentCell.region | Target deployment region |
$sys.deploymentCell.cloudProviderNetworkID | VPC / VNet / Network ID |
$sys.deploymentCell.cidrRange | CIDR range of the deployment cell |
$sys.deploymentCell.publicSubnetIDs[i].id | Public subnet IDs |
$sys.deploymentCell.privateSubnetIDs[i].id | Private subnet IDs |
For the complete list, see System Parameters.
Variable Overrides with Inline Values¶
Use the variablesValuesFileOverride property to pass Terraform variable values directly from your Plan specification — no separate .tfvars file needed in your repository. This is useful for injecting system parameters into Terraform variables.
Define variables in your Terraform stack:
# variables.tf
variable "vpc_id" {
type = string
description = "VPC ID for the deployment"
}
variable "region" {
type = string
description = "AWS region"
}
variable "instance_type" {
type = string
default = "db.t3.medium"
description = "RDS instance class"
}
variable "subnet_ids" {
type = list(string)
description = "Subnet IDs for the database subnet group"
}
Then override them in your Plan specification:
services:
- name: dbInfra
internal: true
terraformConfigurations:
configurationPerCloudProvider:
aws:
terraformPath: /terraform/aws
variablesValuesFileOverride: |
vpc_id = "{{ $sys.deploymentCell.cloudProviderNetworkID }}"
region = "{{ $sys.deploymentCell.region }}"
instance_type = "db.t3.medium"
subnet_ids = [
"{{ $sys.deploymentCell.privateSubnetIDs[0].id }}",
"{{ $sys.deploymentCell.privateSubnetIDs[1].id }}"
]
gitConfiguration:
reference: refs/heads/main
repositoryUrl: https://github.com/your-org/infra-repo.git
Tip
The variablesValuesFileOverride is useful when you want to customize Terraform behavior on the Omnistrate platform without modifying the underlying Terraform code. Your Terraform stack stays generic and reusable while environment-specific values are injected from the Plan specification.
API Parameters as Terraform Inputs¶
You can connect API parameters — values your customers provide at deployment time — to Terraform variables through the same mechanism. Define an API parameter on the parent resource and reference it in the Terraform variable override:
services:
- name: MyApp
dependsOn:
- dbInfra
apiParameters:
- key: dbInstanceClass
description: Database instance size
name: Database Instance Class
type: String
modifiable: true
required: false
export: true
defaultValue: "db.t3.medium"
options:
- "db.t3.micro"
- "db.t3.medium"
- "db.t3.large"
parameterDependencyMap:
dbInfra: dbInstanceClass
- name: dbInfra
internal: true
apiParameters:
- key: dbInstanceClass
description: Database instance class
name: Database Instance Class
type: String
modifiable: true
required: false
export: false
defaultValue: "db.t3.medium"
terraformConfigurations:
configurationPerCloudProvider:
aws:
terraformPath: /terraform/aws
variablesValuesFileOverride: |
instance_type = "{{ $var.dbInstanceClass }}"
vpc_id = "{{ $sys.deploymentCell.cloudProviderNetworkID }}"
region = "{{ $sys.deploymentCell.region }}"
gitConfiguration:
reference: refs/heads/main
repositoryUrl: https://github.com/your-org/infra-repo.git
In this pattern:
- The customer selects a
dbInstanceClasswhen creating a deployment - The value is passed through the
parameterDependencyMapto thedbInfraresource - The
variablesValuesFileOverrideinjects the value into the Terraform variable
Output Mapping¶
Defining Terraform Outputs¶
In your Terraform stack, define outputs for any values you want to expose to other resources:
# outputs.tf
output "database_endpoint" {
value = aws_db_instance.main.endpoint
description = "RDS instance endpoint"
}
output "database_port" {
value = aws_db_instance.main.port
description = "RDS instance port"
}
output "s3_bucket_arn" {
value = aws_s3_bucket.data.arn
description = "S3 bucket ARN for data storage"
}
output "connection_details" {
value = {
endpoint = aws_db_instance.main.endpoint
port = aws_db_instance.main.port
database = aws_db_instance.main.db_name
}
description = "Structured connection details"
}
output "cache_endpoint" {
value = aws_elasticache_cluster.cache.cache_nodes[0].address
sensitive = true
}
Omnistrate automatically captures all values from the Terraform output block after each apply.
Referencing Outputs in Dependent Resources¶
Use the {{ $<resourceName>.out.<outputKey> }} syntax to inject Terraform outputs into other resources. The <resourceName> is the name of the Terraform resource as defined in your Plan specification.
In Helm Chart Values¶
services:
- name: infraTerraform
internal: true
terraformConfigurations:
configurationPerCloudProvider:
aws:
terraformPath: /terraform/aws
gitConfiguration:
reference: refs/heads/main
repositoryUrl: https://github.com/your-org/infra-repo.git
- name: MyApp
dependsOn:
- infraTerraform
helmChartConfiguration:
chartName: my-app
chartVersion: 1.0.0
chartRepoName: my-charts
chartRepoURL: https://charts.example.com
chartValues:
database:
host: "{{ $infraTerraform.out.database_endpoint }}"
port: "{{ $infraTerraform.out.database_port }}"
storage:
bucketArn: "{{ $infraTerraform.out.s3_bucket_arn }}"
cache:
endpoint: "{{ $infraTerraform.out.cache_endpoint }}"
Accessing Nested Output Values¶
When a Terraform output returns a structured object, you can access nested properties with dot notation:
# Terraform output
output "connection_details" {
value = {
endpoint = aws_db_instance.main.endpoint
port = aws_db_instance.main.port
}
}
# Plan specification reference
chartValues:
dbHost: "{{ $infraTerraform.out.connection_details.endpoint }}"
dbPort: "{{ $infraTerraform.out.connection_details.port }}"
In Operator CRD Configuration¶
services:
- name: infraTerraform
internal: true
terraformConfigurations:
configurationPerCloudProvider:
aws:
terraformPath: /terraform/aws
gitConfiguration:
reference: refs/heads/main
repositoryUrl: https://github.com/your-org/infra-repo.git
- name: DatabaseOperator
dependsOn:
- infraTerraform
operatorCRDConfiguration:
template: |
apiVersion: db.example.com/v1
kind: Database
spec:
externalEndpoint: "{{ $infraTerraform.out.database_endpoint }}"
bucketArn: "{{ $infraTerraform.out.s3_bucket_arn }}"
Outputs Across Multi-Cloud Stacks¶
When you define Terraform stacks for multiple cloud providers, keep output names consistent so dependent resources work without cloud-specific logic:
AWS outputs:
GCP outputs:
Azure outputs:
The dependent resource references {{ $infraTerraform.out.database_endpoint }} regardless of which cloud provider is in use.
End-to-End Example¶
This complete example demonstrates a multi-resource Plan with a Terraform stack provisioning cloud infrastructure, API parameters exposed to customers, and output mapping to a Helm chart application:
name: Full Stack SaaS
deployment:
hostedDeployment:
awsAccountId: "<AWS_ACCOUNT_ID>"
awsBootstrapRoleAccountArn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/omnistrate-bootstrap-role
services:
- name: cloudInfra
internal: true
apiParameters:
- key: dbInstanceClass
description: Database instance class
name: Database Instance Class
type: String
modifiable: true
required: false
export: false
defaultValue: "db.t3.medium"
- key: storageSize
description: Database storage size in GB
name: Storage Size (GB)
type: String
modifiable: true
required: false
export: false
defaultValue: "20"
terraformConfigurations:
configurationPerCloudProvider:
aws:
terraformPath: /terraform/aws
variablesValuesFileOverride: |
vpc_id = "{{ $sys.deploymentCell.cloudProviderNetworkID }}"
region = "{{ $sys.deploymentCell.region }}"
instance_class = "{{ $var.dbInstanceClass }}"
storage_size = {{ $var.storageSize }}
subnet_ids = [
"{{ $sys.deploymentCell.privateSubnetIDs[0].id }}",
"{{ $sys.deploymentCell.privateSubnetIDs[1].id }}"
]
resource_prefix = "saas-{{ $sys.id }}"
gitConfiguration:
reference: refs/tags/v1.0.0
repositoryUrl: https://github.com/your-org/infra-repo.git
- name: WebApp
dependsOn:
- cloudInfra
network:
ports:
- 8080
compute:
instanceTypes:
- apiParam: instanceType
cloudProvider: aws
helmChartConfiguration:
chartName: web-app
chartVersion: 2.0.0
chartRepoName: my-charts
chartRepoURL: https://charts.example.com
chartValues:
config:
databaseUrl: "{{ $cloudInfra.out.database_endpoint }}"
databasePort: "{{ $cloudInfra.out.database_port }}"
s3BucketArn: "{{ $cloudInfra.out.s3_bucket_arn }}"
apiParameters:
- key: instanceType
description: Compute instance type
name: Instance Type
type: String
modifiable: true
required: false
export: true
defaultValue: "t4g.small"
- key: dbInstanceClass
description: Database instance size
name: Database Instance Class
type: String
modifiable: true
required: false
export: true
defaultValue: "db.t3.medium"
options:
- "db.t3.micro"
- "db.t3.medium"
- "db.t3.large"
parameterDependencyMap:
cloudInfra: dbInstanceClass
- key: storageSize
description: Database storage in GB
name: Storage Size (GB)
type: String
modifiable: true
required: false
export: true
defaultValue: "20"
parameterDependencyMap:
cloudInfra: storageSize
In this example:
cloudInfrais an internal Terraform resource that provisions an RDS database and S3 bucketWebAppis the customer-facing Helm chart that depends oncloudInfra- API parameters (
dbInstanceClass,storageSize) are defined onWebAppand mapped tocloudInfrathroughparameterDependencyMap - Terraform outputs (
database_endpoint,database_port,s3_bucket_arn) are injected into the Helm chart values - System parameters provide the VPC, region, and subnet context to Terraform
Best Practices¶
Consistent Output Names¶
Use the same output key names across your AWS, GCP, and Azure Terraform stacks. This ensures dependent resources work without cloud-specific branching.
Use Git Tags for Versioning¶
Reference specific Git tags (refs/tags/v1.0.0) instead of branches for production Plans. This ensures deployments are reproducible and upgrades are intentional.
Unique Resource Names¶
Always include $sys.id in cloud resource names to prevent naming collisions between customer deployments:
Mark Terraform Resources as Internal¶
Terraform resources are infrastructure dependencies — mark them as internal: true so they are not directly exposed in your customer-facing API. Customers interact with the parent resource that depends on the Terraform stack.
Sensitive Outputs¶
Mark Terraform outputs as sensitive = true for values like passwords or connection strings that should not appear in logs:
Next Steps¶
- Terraform Overview: Understand how Terraform integrates with the Omnistrate platform
- Multi-Cloud Configuration: Configure per-cloud-provider Terraform stacks
- Helm and Terraform: Complete walkthrough combining Helm with Terraform
- API Parameters: Full guide on defining customer-facing parameters
- Resource Dependencies: How resource ordering and parameter mapping works