Skip to content

Expert · Infrastructure as code · topic 38 of 50 · 30 min

IaC in a team: reviews, pipelines and policy

Explanation

In a team, infrastructure changes go through Git like application code: a pull request shows the plan, a teammate reviews it, and a CI pipeline applies it after merge. Environments come from the same code with different settings, secrets stay in a secrets manager, and automated policy checks stop risky changes, such as a public bucket, before they are applied.

Why process matters

IaC removes click mistakes, but a wrong line of code can now delete a production database in seconds. The answer is the same discipline developers use for application code: version control, review, automated checks and a controlled way to release. The goal is simple: no change reaches production without a reviewed plan.

The pull request workflow

  1. Create a branch and change the .tf files or the template.
  2. Open a pull request (PR). The CI pipeline (an automated build system such as GitHub Actions, GitLab CI or AWS CodePipeline) runs fmt, validate, policy checks and plan.
  3. The pipeline posts the plan output in the PR, so the reviewer sees "Plan: 1 to add, 0 to change, 0 to destroy." and the details.
  4. A teammate reviews both the code and the plan. A surprise destroy or replace is a reason to stop.
  5. After merge to main, the pipeline applies. For production, it waits for a manual approval first.
yaml
name: infra
on:
  pull_request:
    paths: ['infra/**']
  push:
    branches: [main]
    paths: ['infra/**']
permissions:
  id-token: write   # lets the job get short-lived AWS credentials (OIDC), no stored keys
  contents: read
jobs:
  terraform:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra
    steps:
      - uses: actions/checkout@v7
      - uses: hashicorp/setup-terraform@v3
      - uses: aws-actions/configure-aws-credentials@v6
        with:
          role-to-assume: arn:aws:iam::111122223333:role/github-terraform
          aws-region: ap-south-1
      - run: terraform init -input=false
      - run: terraform fmt -check
      - run: terraform validate
      - run: terraform plan -input=false -out=tfplan
      - if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        run: terraform apply -input=false tfplan
A simplified GitHub Actions workflow: plan on every PR, apply only after merge to main. Real pipelines also post the plan as a PR comment.

Environments: dev, stage and prod

Every environment should come from the same code, with differences only in settings. In Terraform, use a variable file per environment (dev.tfvars, prod.tfvars) and a separate state for each, either a separate folder and backend key per environment or Terraform workspaces. In CloudFormation, deploy the same template as separate stacks with different parameters. Many companies also put production in its own AWS account, so a mistake in dev cannot touch it.

Never put secrets in templates

A secret (a password, API key or token) written in a .tf file or template ends up in Git history forever, where anyone with read access can find it. Store secrets in AWS Secrets Manager, AWS Systems Manager Parameter Store, Azure Key Vault or Google Secret Manager, and let the code reference them. CloudFormation has dynamic references such as {{resolve:secretsmanager:prod/results/db:SecretString:password}}. Even better, let the service manage the secret: Amazon RDS can create and store the master password in Secrets Manager for you (ManageMasterUserPassword in CloudFormation, manage_master_user_password in Terraform).

Careful: If Terraform reads a secret through a data source, the value is saved in the state file. That is one more reason the state must be encrypted and access to it limited.

Policy as code

Policy as code means writing your rules ("no public buckets", "every resource has an owner tag", "only these instance types") as code that runs automatically in the pipeline, before apply. A human reviewer gets tired on Friday evening; a policy check does not.

  • Checkov: an open-source scanner with hundreds of ready-made checks for Terraform, CloudFormation, Kubernetes and more.
  • Open Policy Agent (OPA): a general policy engine. You write rules in a language called Rego and run them against the plan in JSON form, often with a tool called conftest.
  • AWS CloudFormation Guard (cfn-guard): an AWS open-source tool that checks templates against rules you write.
  • At the cloud level, AWS Config rules, Service Control Policies and Azure Policy catch what slips through, even for changes made outside IaC.

Tagging standards

Tags are key and value labels on resources, such as env=prod, owner=payments-team, cost-centre=CC-104 and project=results. They let finance split the bill by team, let operations find who owns a forgotten server, and let backup plans select resources. Agree on required tags, check them with policy as code, and set them once for all resources: the Terraform AWS provider supports default_tags in the provider block.

Importing what was built by hand

Most companies already have resources created in the console. You do not need to delete and rebuild them. Terraform can bring existing resources under management with an import block (Terraform 1.5 and later) or the terraform import command, and CloudFormation can import existing resources into a stack. After importing, run plan until it shows no changes, which proves the code matches reality.

Stop console changes

Give people read-only console access to production and let only the pipeline role make changes. Keep a "break-glass" admin role for real emergencies, log its use, and copy any emergency fix back into the code the same day. Run plan or drift detection on a schedule so drift is noticed within hours, not months.

Careful: Common mistakes: (1) Applying from a laptop "just this once", which skips review and leaves no record. Fix: only the pipeline applies to prod. (2) One giant state for everything, so a small change plans for ten minutes and risks everything. Fix: split state by environment and by system. (3) Approving PRs without opening the plan. Fix: make the plan visible in the PR and treat any destroy as a red flag.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

IaC in a team: reviews, pipelines and policy · 1/7

IaC in a team

In a team, infrastructure changes go through the same process as application code: Git, review, automated checks and a pipeline.

Prefer a video by a teacher? Find free videos on “terraform github actions pull request plan apply pipeline policy as code checkov” on YouTube ↗

In real life: A hospital chain stops public buckets before they exist

A hospital chain in Chennai stores lab reports in S3. After a near miss where a test bucket was made public, the platform team added Checkov and a small custom policy to the Terraform pipeline. Now any PR that creates a bucket without the public access block, without encryption settings, or without the owner and data-class tags fails before a human even reviews it. The developer sees the exact rule and line in the PR, fixes it in minutes, and the production AWS account only accepts changes from the pipeline role.

Practice (0/3 done)

Task 1 · Question

A developer needs the database password in a Terraform configuration. What is the safest approach?

Task 2 · Code · Javascript

Write checkPolicy(resources, requiredTags). Each resource is an object like { name: "results", type: "s3_bucket", encrypted: true, public: false, tags: { env: "prod" } }. Return a list of problems as strings, in resource order. For each resource, check in this order: (1) only for type "s3_bucket": if encrypted is not true, add "<name>: not encrypted"; if public is true, add "<name>: public access". (2) for every resource: for each tag in requiredTags (in that order) that is missing from tags, add "<name>: missing tag <tag>". (AWS now encrypts new S3 objects by default, but many companies still require an explicit encryption setting, often with their own KMS key, so the policy checks it.)

Task 3 · Practice

Write a one-page "IaC rules" document for a team of five engineers who manage AWS with Terraform. Cover how a change goes from a laptop to production, how environments are separated, where state and secrets live, which automated checks run, and what happens in an emergency.

Quick quiz

Question 1

1.In a good IaC workflow, when does the change get applied to production?

Question 2

2.What is policy as code?

Question 3

3.Your company has 200 resources that were created in the console. What is the usual way to bring them under Terraform?

Question 4

4.Why do teams define required tags like owner and cost-centre?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

In a good IaC workflow, when does the change get applied to production?

Answer: After the PR is reviewed and merged, by the pipeline, usually with an approval step

The pipeline applies reviewed, merged code, with a manual approval for production.

What is policy as code?

Answer: Rules such as "no public buckets" written as code and checked automatically before apply

Tools like Checkov, OPA and cfn-guard check templates and plans against written rules in the pipeline.

Your company has 200 resources that were created in the console. What is the usual way to bring them under Terraform?

Answer: Import them (import blocks or terraform import), then plan until it shows no changes

Importing adds existing resources to the state; a clean plan proves the code matches them.

Why do teams define required tags like owner and cost-centre?

Answer: To split the bill by team, find owners of resources and select resources for backups and policies

Tags drive cost reports, ownership and automation. AWS does not require them by default, so teams enforce them with policy.

What is a main risk of using workspaces for dev and prod?Related

Answer: It is easy to run apply in the wrong workspace, and all environments share one backend and credentials

Workspaces share code, backend and usually credentials, so a slip can hit prod.

From Modules, environments and Terraform in CI

Why should terraform.tfstate not be committed to Git?Related

Answer: It can contain secrets in plain text and it must be shared with locking, which Git cannot do

State can hold passwords and keys, and it needs locking to stop two applies at once. Use an encrypted remote backend.

From Terraform for the cloud

You run the same IaC apply twice in a row with no changes to the files. What should happen the second time?Related

Answer: Nothing changes, because the apply is idempotent

Idempotent means running it again gives the same result, so the second run finds nothing to do.

From Why infrastructure as code

A bucket was created by hand last year. How do you bring it under Terraform without recreating it?Related

Answer: Use an import block (or terraform import), then plan and apply

Import adopts an existing object into state. A plain resource block would try to create a new one.

From Terraform state, backends and drift

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Infrastructure as code”. The module exam comes next.
  2. Module 9 exam: Infrastructure as code · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, High availability, scaling and disaster recovery. 50 topics left in the course before the final exam.

← Previous: Terraform for the cloud