May 23, 2025malcolm-matalka

Secrets as Code, Not Secrets in Code: Terraform GitOps with Infisical

This guide extends the principles in Infisical's Secure GitOps Workflows post. It's written for Terraform-first teams looking to adopt ephemeral secrets and OIDC authentication without Kubernetes.

Introduction

Infisical's blog post, Secure GitOps Workflows, makes a compelling case: secrets, encrypted or not, don't belong in Git repositories. The post effectively dismantles the operational friction created by tools like SOPS and SealedSecrets, from complex secret rotation to unwieldy encryption key management across environments. The solution is elegant: ephemeral secrets with identity-based authentication (OIDC) eliminate these problems at their source.

Yet a gap exists. The setup assumes a Kubernetes-centric workflow with tools like ArgoCD or External Secrets Operator. What about the numerous infrastructure teams whose world centers around Terraform? These teams manage multi-cloud resources and foundational platform components and understand the principles, but lack a clear implementation path for their context.

These Terraform-first teams have already embraced GitOps principles through pull request workflows, often using automation tools like Terrateam. They seek modern security for their secrets without abandoning their established workflows.

This post extends Infisical's security principles to Terraform-driven environments and attempts to demonstrate how to implement proper secrets management without compromising the GitOps practices that keep your infrastructure workflows efficient and transparent.

The Challenge for Terraform-Driven Workflows

Infrastructure teams using Terraform face distinct secrets management hurdles that don't fit neatly into typical GitOps best practices. These challenges arise precisely because Terraform operates at the foundational infrastructure layer, often provisioning the very systems that would later handle secrets in application workflows.

Despite its power in declarative infrastructure definition, Terraform's state-based approach wasn't designed with secrets lifecycle management in mind. The result? Infrastructure teams often resort to problematic patterns: hardcoded credentials in .tfvars files, environment variables passed through CI/CD pipelines, or secrets embedded directly in Terraform code. Even when teams know better, the path to proper implementation isn't obvious.

When infrastructure teams automate Terraform, they commonly turn to GitHub Actions. However, its secrets handling model presents limitations: repository secrets become long-lived credentials with minimal rotation capabilities, usually creating broad access and contradicting the principle of least privilege. The access controls are binary rather than role-based, making it challenging to implement nuanced permission structures.

Most guidance for modern secrets management presupposes tools like ArgoCD or External Secrets Operator running in Kubernetes clusters. Yet many infrastructure teams are building foundational layers that exist before or entirely outside Kubernetes environments. Their toolchain doesn't include these components, leaving them without a clear path for implementing advanced secrets management.

TACOS

Newer tools like Terrateam (part of the emerging "TACOS" category: Terraform Automation & Collaboration Software) have made infrastructure workflows more GitOps-friendly through PR-driven automation. However, these tools still need secure patterns for handling credentials throughout the infrastructure lifecycle.

This confluence of factors drives many teams toward suboptimal workarounds: encrypting secrets into Git repositories, creating long-lived API tokens with expansive permissions, or storing sensitive values in CI/CD variables. Each approach creates substantial risks and operational debt that compounds over time.

The Stack: Infisical, Terrateam, and Terraform

InfisicalTerrateamTerraform
Secure vaultPR-based automationIaC engine
OIDC authAccess controlsDeclarative references
Ephemeral secretsWorkflowInfisical provider
Audit trailFull auditabilityProvider ecosystem

The solution combines three specialized tools to create a secure, GitOps-friendly workflow for infrastructure teams.

  1. Infisical delivers secrets management designed for modern engineering practices. Its ephemeral secrets delivery, OIDC-based machine identities, and comprehensive access controls keep sensitive values away from risky surfaces. By centralizing secrets governance while distributing access securely, Infisical solves the primary security challenge.

  2. Terrateam handles the GitOps workflow, turning pull requests into infrastructure operations. Its PR-based automation model, with customizable workflows and fine-grained access controls, gives infrastructure teams the GitOps experience without Kubernetes-specific tooling. Terrateam's robust configuration model drives consistent Terraform operations across environments without storing secrets in GitHub.

  3. Terraform, with its Infisical provider, ties everything together. Teams can reference secrets declaratively while ensuring values never persist in the state, preserving the "infrastructure as code" principle without sacrificing security.

This integrated stack delivers the core benefits of GitOps: a declarative configuration, Git-based workflows, and automated operations. It also properly solves the secrets management challenge.

Secure GitOps Flow
Engineer opens PR
GitHub triggers Terrateam
Terrateam requests OIDC token from GitHub
GitHub issues short-lived token
Terrateam authenticates with Infisical
Terraform fetches ephemeral secrets from Infisical
Terraform runs plan (secrets exist in memory only)
Pull request is reviewed and merged
Terrateam reauthenticates via OIDC
Terraform applies changes with fresh secrets
Infisical logs access and operations

Example Configuration and Walkthrough

Before diving into the setup steps, let's look at what a typical configuration looks like. This gives you the full picture of what we're building toward.

The Terraform configurations shown focus on the Infisical integration. This example demonstrates the secrets management pattern, where secrets exist in Infisical's vault and are referenced ephemerally by Terraform.

The ephemeral resource acts as a secure bridge between Infisical's vault and your Terraform configuration, retrieving secrets only when needed and keeping them in memory.

  • The Ephemeral Resource: Terraform's temporary way to fetch that secret during execution (the ephemeral "infisical_secret" block)
  • The Secret: Actual sensitive data stored in Infisical's vault (e.g., DB_CREDENTIALS containing username/password)

The following code shows a simple use case of the Infisical Provider and ephemeral secret:

terraform {
  required_providers {
    infisical = {
      source = "infisical/infisical"
    }
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

provider "infisical" {
  host = "https://app.infisical.com" # Required for self-hosted
  auth {
    oidc {
      identity_id = var.infisical_identity_id
    }
  }
}

# Variables for Infisical configuration
variable "infisical_identity_id" {
  description = "Infisical machine identity ID"
  type        = string
}

variable "infisical_workspace_id" {
  description = "Infisical workspace ID" 
  type        = string
}

# This ephemeral resource fetches the DB_CREDENTIALS secret from Infisical
ephemeral "infisical_secret" "db_creds" {
  name         = "DB_CREDENTIALS"      # The secret name in Infisical
  env_slug     = "prod"
  workspace_id = var.infisical_workspace_id
  folder_path  = "/database"
}

# RDS instance using ephemeral secrets from Infisical
resource "aws_db_instance" "example" {
  identifier           = "prod-postgres"
  allocated_storage    = 100
  engine               = "postgres"
  engine_version       = "14.5"
  instance_class       = "db.t3.large"
  db_name              = "production"
  
  # Securely inject credentials from Infisical ephemeral resource
  username = jsondecode(ephemeral.infisical_secret.db_creds.value)["username"]
  password = jsondecode(ephemeral.infisical_secret.db_creds.value)["password"]
  
  # Network configuration - requires VPC, subnets, and security groups
  # db_subnet_group_name   = aws_db_subnet_group.example.name
  # vpc_security_group_ids = [aws_security_group.rds.id]
  
  # Backup and security settings
  backup_retention_period = 7
  multi_az               = true
  storage_encrypted      = true
  skip_final_snapshot    = true  # Set to false in production
  
  tags = {
    Name        = "Production PostgreSQL"
    Environment = "prod"
  }
}

# Note: In a complete setup, you would also need:
# - VPC and subnets (aws_vpc, aws_subnet)
# - DB subnet group (aws_db_subnet_group) 
# - Security groups (aws_security_group)
# - Internet Gateway and routing (for connectivity)

Walkthrough: Setting Up the Infrastructure

Now let's walk through setting up the components that enable this secure workflow:

Step 1: Set up Infisical with OIDC machine identity

Create a machine identity in Infisical with OIDC authentication to enable short-lived, automatically rotated credentials. These configurations are fully covered in the Infisical documentation.

Create the Identity

  1. Go to Organization Settings → Access Control → Identities
  2. Click Create Identity
  3. Provide a Name and assign an Organization Role
  4. Click Create

Create Identity

Configure OIDC Authentication

  1. Open the newly created identity and scroll to the Authentication section
  2. Click Edit, remove any existing Universal Auth method
  3. Click Add Auth Method and choose OIDC Auth
  4. Fill in the required fields:
    • OIDC Discovery URL: https://token.actions.githubusercontent.com
    • Issuer: https://token.actions.githubusercontent.com
    • Subject: repo:<org>/<repo>:ref:refs/heads/<branch>
    • Audience: sts.infisical.com (or your custom value)
    • Claims: (optional; add any specific claim validations you require)
  5. Click Add Auth Method

Configure OIDC

Assign the Identity to Your Project

  1. Navigate to your Project → Access Control → Machine Identities
  2. Click Add Identity
  3. Select the identity you just created and assign a Project Role
  4. Click Add

Assign Identity

Note on Secrets: This walkthrough assumes secrets already exist in your Infisical project through your organization's established processes. In production environments, secrets are typically:

  • Provisioned via Infisical's API or CLI as part of deployment pipelines
  • Synchronized from existing secret management systems
  • Created through platform team governance workflows
  • Never manually created for production workloads

The Terraform configuration references these existing secrets using ephemeral resources, maintaining the infrastructure-as-code principle.

Step 2: Define ephemeral secret references in Terraform

Set up your Terraform configuration using the patterns shown in the example above. You're not creating secrets in Terraform, but rather you're creating ephemeral references that fetch existing secrets from Infisical at runtime.

The ephemeral resource type ensures secret values are never written to state files, existing only in memory during resource creation. Here is the configuration again:

ephemeral "infisical_secret" "db_creds" {
  name         = "DB_CREDENTIALS"      # The secret name in Infisical
  env_slug     = "prod"
  workspace_id = var.infisical_workspace_id
  folder_path  = "/database"
}

Step 3: Connect Terrateam to your GitHub repository

Now we'll configure Terrateam to securely execute the Terraform code from the example:

  1. Install Terrateam

    • Go to Terrateam signup
    • Install the GitHub App and grant access to your repository
  2. Create the Terrateam configuration

    • Add the .terrateam/config.yml file to your repository root
workflows:
  - tag_query: ""
    plan:
      - type: env
        method: source
        cmd: ['${TERRATEAM_ROOT}/fetch-token.sh']
        sensitive: true
      - type: init
      - type: plan
    apply:
      - type: env
        method: source
        cmd: ['${TERRATEAM_ROOT}/fetch-token.sh']
        sensitive: true
      - type: init
      - type: apply
  1. Add the token fetch script
    • Create the fetch-token.sh in your repository root. The ${TERRATEAM_ROOT} variable points to the root of your Git repository. You’ll need to commit a fetch-token.sh.
    • Make it executable: chmod +x fetch-token.sh
    • Commit both files to your repository
#!/bin/bash
set -euo pipefail

echo "Requesting OIDC token..."
TOKEN=$(curl -s -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value')
export INFISICAL_AUTH_JWT="$TOKEN"

Note: The environment variables ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL are automatically provided by GitHub's runtime environment when Terrateam executes workflows.

This setup enables Terrateam to securely execute your Terraform configuration using the OIDC authentication we configured in Step 1, without storing any secrets in Git or using long-lived credentials.

Security and Developer Experience Benefits

This stack delivers significant advantages that strengthen security posture and developer productivity:

  1. Sensitive credentials never touch persistent storage in your infrastructure pipeline. By treating secrets as runtime-only resources, you eliminate entire categories of potential exposure from your security threat model.

  2. The zero-trust authentication model eliminates manual rotation cycles, key distribution challenges, and the administrative burden of tracking access. Teams can focus on building infrastructure rather than managing credentials.

  3. Your Terraform configurations remain fully declarative and version-controlled, with references to secrets that maintain auditability without exposing values. The approach strengthens rather than compromises GitOps principles.

  4. The PR workflow creates checkpoints for review and approval and builds an audit trail. This approach dissolves the tension between security requirements and developer experience: security strengthens through systematic best practices while developers keep their streamlined workflow without friction.

Infisical Principles in Action

The solution we've outlined implements the core security principles advocated in Infisical's "Secure GitOps Workflows" guidance, adapted for infrastructure teams. Let's examine how each principle manifests in this architecture:

  1. The ephemeral resource pattern in Terraform transforms how secrets interact with infrastructure code. Values are delivered just-in-time during execution, exist only for the duration of the operation, and disappear after use. This runtime-only approach means secrets never touch persistent storage, dramatically reducing exposure risks during the infrastructure lifecycle.

  2. Unlike Git-encrypted approaches like SOPS, this architecture strictly separates configuration and credentials. Infrastructure code in Git contains only references to secrets, never the values themselves, and is not even encrypted. This separation eliminates an entire category of management complexity and security risk that plagues infrastructure teams.

  3. With Infisical as the central authority for secrets, teams gain comprehensive visibility and control. Every secret access generates an audit trail tied to specific identities and operations. Role-based access controls enable precise permission management across environments, which keeps production credentials tightly restricted while preserving developer productivity in non-production environments.

  4. The OIDC integration implements modern zero-trust principles for infrastructure automation. Each Terraform operation establishes its authentication context with just-in-time, short-lived credentials. Static tokens and long-lived credentials are therefore eliminated, which creates a security model based on verified identity rather than persistent access keys.

By implementing these principles in a Terraform-native way, infrastructure teams gain the security benefits Infisical advocates without disrupting their established workflows. The result is a system that's both more secure and more usable.

Conclusion: A Terraform-Native Path to Secure GitOps

Secure GitOps Workflows laid the foundation for secure secrets management in GitOps environments. This post has extended those principles to teams using Terraform-first workflows, providing a concrete implementation path that works with pull request-driven infrastructure automation.

By combining Infisical for secure secrets management, Terrateam for GitOps-style workflow automation, and Terraform's ephemeral resources, infrastructure teams can enjoy all the benefits of declarative, version-controlled infrastructure without compromising secrets security.

This approach "just works" for teams building infrastructure through code and provides a clear path to declarative, reviewable, and secure secrets management in your Terraform workflows with Terrateam. The days of encrypting secrets in Git or managing long-lived tokens are over. With this stack, you can implement security and convenience in your infrastructure automation.