Skip to content

CI/CD Integration

If it runs terraform init, it works with compliance.tf. Here is how to set up authentication in your pipeline.

At a glance
  • compliance.tf is a private Terraform registry. Any CI/CD system that can run the Terraform CLI can use compliance.tf modules.
  • The only setup required is providing an API token so terraform init can authenticate.
  • Your Terraform commands (init, plan, apply) stay exactly the same. Only the token configuration is new.

Prerequisites

What you need before starting

Interactive tokens vs CI tokens

When you run terraform login soc2.compliance.tf on your machine, the CLI stores a short-lived token that expires after 1 day. This works for local development but not for CI/CD pipelines.

For pipelines, create a long-lived token from the Access Tokens page. This token is valid until you revoke it. Store it as a secret in your CI/CD platform and pass it to Terraform as an environment variable.

New to compliance.tf? Complete the Get Started guide first.


How Authentication Works

Terraform needs a token to download modules from the compliance.tf registry. In CI/CD, the standard approach is to set an environment variable:

TF_TOKEN_soc2_compliance_tf=ctf_YOUR_TOKEN_HERE

Terraform reads TF_TOKEN_* environment variables automatically. The variable name is derived from the registry hostname by replacing dots with underscores and adding the TF_TOKEN_ prefix:

Registry hostnameEnvironment variable
soc2.compliance.tfTF_TOKEN_soc2_compliance_tf
hipaa.compliance.tfTF_TOKEN_hipaa_compliance_tf
pcidssv40.compliance.tfTF_TOKEN_pcidssv40_compliance_tf

If you use multiple framework endpoints in the same configuration, set one TF_TOKEN_* variable per hostname. The same token value works for all endpoints — only the variable name changes.

There is also a file-based method using .terraformrc or .netrc. The environment variable approach is simpler for CI/CD and is what all platform examples below use. For file-based authentication, see the Registry Endpoints page.

Reference: Terraform CLI TF_TOKEN_* documentation


Choose Your Platform

Every platform uses the same pattern: store your compliance.tf token as a secret, then expose it as TF_TOKEN_soc2_compliance_tf when Terraform runs. Select your platform for the complete setup guide.


Multi-Environment Setup

Teams often need different compliance postures for different environments. Production might enforce all SOC 2 controls, while development relaxes controls that slow iteration (like S3 object lock, which requires bucket recreation).

Option 1: Same framework, different controls per environment

Use the HTTPS URL format with disable= parameters to relax specific controls in non-production environments:

environments/prod/main.tf
module "s3_bucket" {
  source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0"

  bucket = "my-app-data-prod"

  logging = {
    target_bucket = module.logging_bucket.s3_bucket_id
    target_prefix = "s3-access-logs/my-app-prod/"
  }
}
environments/dev/main.tf
module "s3_bucket" {
  source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&disable=s3_bucket_object_lock_enabled"

  bucket = "my-app-data-dev"

  logging = {
    target_bucket = module.logging_bucket.s3_bucket_id
    target_prefix = "s3-access-logs/my-app-dev/"
  }
}

Each environment directory has its own Terraform configuration. Your CI/CD pipeline runs against the appropriate directory based on the target environment.

Option 2: Variable-driven source selection

Using a Terraform variable to switch the source URL works with the HTTPS URL format:

main.tf
variable "environment" {
  type    = string
  default = "dev"
}

locals {
  s3_source = var.environment == "prod" ? (
    "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0"
  ) : (
    "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&disable=s3_bucket_object_lock_enabled"
  )
}

module "s3_bucket" {
  source = local.s3_source

  bucket = "my-app-data-${var.environment}"

  logging = {
    target_bucket = module.logging_bucket.s3_bucket_id
    target_prefix = "s3-access-logs/my-app-${var.environment}/"
  }
}

Registry format does not support variables in source

The Terraform Registry format (source = "soc2.compliance.tf/...") does not allow variables or interpolation in the source argument. Variable-driven source selection only works with the HTTPS URL format. See Customize controls for details.

Token setup for multiple environments

If your environments use different framework endpoints, set a TF_TOKEN_* variable for each hostname:

GitHub Actions multi-framework example
env:
  TF_TOKEN_soc2_compliance_tf: ${{ secrets.CTF_TOKEN }}
  TF_TOKEN_hipaa_compliance_tf: ${{ secrets.CTF_TOKEN }}

The same token value works for all compliance.tf endpoints. Only the variable name changes to match the hostname.

For more on control customization per environment, see Customize controls.


Generating Audit Artifacts from CI

Your CI/CD pipeline already produces the evidence auditors need. By saving plan output and scan reports as artifacts, every pipeline run becomes a compliance record.

Save plan output as JSON

Terraform plan output in JSON format shows exactly which resources will be created, what controls were enforced, and what values are set. This is direct evidence that compliance controls were active at deployment time.

GitHub Actions artifact steps
      - name: Save Plan JSON
        run: terraform show -json tfplan > plan.json

      - name: Upload Plan Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: terraform-plan-${{ github.sha }}
          path: plan.json
          retention-days: 365

Set retention-days to match your audit retention requirements. SOC 2 typically requires 12 months; PCI DSS requires 12 months; HIPAA requires 6 years.

Save scan reports

If you run Checkov or another scanner, save its output alongside the plan:

Save Checkov report
      - name: Upload Scan Report
        uses: actions/upload-artifact@v4
        with:
          name: checkov-report-${{ github.sha }}
          path: checkov-report.json
          retention-days: 365

These artifacts — plan JSON and scan reports — demonstrate to auditors that controls were enforced at every deployment, not just spot-checked. For a complete guide to building an audit evidence package, see the Audit Evidence Guide.


Reversibility

If you stop using compliance.tf, remove the TF_TOKEN_* secret from your CI/CD platform and change the module source URLs back to the upstream terraform-aws-modules paths. No pipeline restructuring required. See Compatibility for details.


Registry Availability

Compliance.tf is only contacted during terraform init. Once modules are cached in .terraform/, terraform plan and terraform apply run entirely locally — no network call to compliance.tf.

  • Uptime commitment: compliance.tf provides a 99.9% uptime SLA.
  • Module caching: After terraform init, modules are cached locally in the .terraform/modules/ directory. Repeat runs of plan and apply use the cache. Modules are only re-downloaded when you run terraform init -upgrade or change the module version.
  • CI/CD resilience: If your CI pipeline caches the .terraform/ directory between runs (common in GitHub Actions, GitLab CI, and most platforms), terraform init will skip downloading modules that are already cached at the correct version.

For more on this topic, see "What if compliance.tf goes down?" in the advocacy guide.


Token Management for Teams

When setting up compliance.tf for a team, consider how tokens are managed:

  • One token per team or service account — recommended for CI/CD pipelines. A single token shared across team workspaces simplifies rotation and revocation.
  • One token per engineer — useful for local development. Each engineer generates their own token via terraform login.
  • Token rotation — CI tokens created from the Access Tokens page are valid until revoked. Rotate tokens on a regular cadence (quarterly recommended) by creating a new token, updating your CI secrets, and revoking the old token.
  • Revocation — If a token is compromised, revoke it immediately from the Access Tokens page. Generate a new token and update all pipelines that use the revoked token.

Air-Gapped Environments

Compliance.tf modules are served from a cloud-hosted registry. Air-gapped environments without internet access cannot download modules directly.

What is possible:

  • Module pre-downloading — Run terraform init in a network-connected environment, then copy the .terraform/modules/ directory into the air-gapped environment. Subsequent plan and apply runs work offline.
  • Private registry mirroring — Set up a Terraform network mirror or filesystem mirror that contains compliance.tf modules. Terraform supports filesystem mirrors and network mirrors for this use case.
  • Registry proxying — Deploy an internal proxy that forwards module requests to the compliance.tf registry from a controlled network boundary.

To set up any of these options, contact us to discuss your environment requirements.


Troubleshooting

Common errors and fixes

Error: Failed to query available provider packages

The token is not set or the hostname in the variable name does not match your module source. Verify:

  • The TF_TOKEN_* variable is available in the step that runs terraform init
  • The hostname in the variable name matches your module source exactly (e.g., soc2.compliance.tf becomes TF_TOKEN_soc2_compliance_tf)

401 Unauthorized

The token is invalid or expired.

  • CI tokens created from the Access Tokens page do not expire unless revoked. Verify the token has not been revoked.
  • If you used terraform login to generate the token, it expires after 1 day. Use a long-lived CI token instead.
  • Check that the full token value was copied (tokens start with ctf_).

403 Forbidden

The token is valid but your subscription does not include the requested framework.

  • Check your subscription at app.compliance.tf to confirm the framework endpoint is included.
  • If you are using a framework-specific endpoint like hipaa.compliance.tf, confirm your subscription covers HIPAA.

Variable name conversion mistakes

The most common mistake is getting the TF_TOKEN_* variable name wrong. The conversion rule:

  1. Start with the registry hostname: soc2.compliance.tf
  2. Replace every dot with an underscore: soc2_compliance_tf
  3. Add the TF_TOKEN_ prefix: TF_TOKEN_soc2_compliance_tf

Double-check that you have not used dashes, uppercase letters, or extra characters.


.netrc not working

.netrc is used with the HTTPS URL format, not the Registry format. If your module source looks like source = "soc2.compliance.tf/..." (no https:// prefix), you need TF_TOKEN_* or .terraformrc credentials, not .netrc.

If your source uses source = "https://soc2.compliance.tf/...", ensure your .netrc file:

  • Is in your home directory (or the path specified by NETRC env var)
  • Has the correct machine value matching the hostname
  • Uses password for the token value (login can be any string)

What's Next