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 initcan authenticate. - Your Terraform commands (
init,plan,apply) stay exactly the same. Only the token configuration is new.
Prerequisites
What you need before starting
- A compliance.tf account with an active subscription — start a free trial or sign in
- A long-lived API token from the Access Tokens page
- Terraform >= 1.0 or OpenTofu >= 1.6 installed in your pipeline
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 hostname | Environment variable |
|---|---|
soc2.compliance.tf | TF_TOKEN_soc2_compliance_tf |
hipaa.compliance.tf | TF_TOKEN_hipaa_compliance_tf |
pcidssv40.compliance.tf | TF_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:
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/"
}
}
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:
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:
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.
- 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:
- 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 ofplanandapplyuse the cache. Modules are only re-downloaded when you runterraform init -upgradeor 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 initwill 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 initin a network-connected environment, then copy the.terraform/modules/directory into the air-gapped environment. Subsequentplanandapplyruns 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 runsterraform init - The hostname in the variable name matches your module source exactly (e.g.,
soc2.compliance.tfbecomesTF_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 loginto 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:
- Start with the registry hostname:
soc2.compliance.tf - Replace every dot with an underscore:
soc2_compliance_tf - 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
NETRCenv var) - Has the correct
machinevalue matching the hostname - Uses
passwordfor the token value (logincan be any string)
What's Next
- Find modules for your infrastructure — Module catalog
- Control which checks are enforced — Customize controls
- Understand framework endpoints — Registry Endpoints
- Prepare for an audit — Audit evidence guide