TFLAB35-HCP Terraform: Teams, Policies, Health Checks and Dynamic Credentials

HCP Terraform: Teams, Policies, Health Checks and Dynamic Credentials

🔧 HCP Terraform ⭐ Advanced Sentinel / OPA Workspace Health Dynamic Credentials (OIDC) Teams & Permissions

Scenario

Your organization is rolling out HCP Terraform to all engineering teams. You need to set up teams with role-based access, enforce policies that prevent non-compliant infrastructure, enable drift detection via health assessments, and eliminate static AWS credentials with OIDC dynamic credentials.

Your Objectives
  • Understand HCP Terraform Teams and permission levels (read, plan, write, admin).
  • Understand Sentinel and OPA policy enforcement (advisory, soft-mandatory, hard-mandatory).
  • Enable Workspace Health Assessments for automated drift detection.
  • Understand Dynamic Credentials (OIDC) — how HCP Terraform authenticates to AWS without static keys.

Additional Context

Sentinel is HashiCorp's policy-as-code framework. Policies are written in the Sentinel language and enforced between plan and apply. OPA (Open Policy Agent) is an open-source alternative using Rego.

Policy enforcement levels:
- advisory: log warning, don't block
- soft-mandatory: block by default, but can be overridden by admins
- hard-mandatory: block always, no override

Dynamic Credentials (OIDC): HCP Terraform generates a short-lived OIDC token for each run. AWS trusts this token via an IAM OIDC provider → IAM role. No static AWS_ACCESS_KEY_ID needed. Credentials are scoped to a single run and expire automatically.

Teams & Permissions (HCP Terraform UI)

# Teams are configured in the HCP Terraform UI:
# Settings → Teams → Create Team

# Permission Levels:
# ┌────────────┬───────┬──────┬───────┬───────┐
# │ Permission │ Read  │ Plan │ Write │ Admin │
# ├────────────┼───────┼──────┼───────┼───────┤
# │ View state │  ✓    │  ✓   │  ✓    │  ✓    │
# │ Queue plan │       │  ✓   │  ✓    │  ✓    │
# │ Apply runs │       │      │  ✓    │  ✓    │
# │ Lock/unlock│       │      │  ✓    │  ✓    │
# │ Settings   │       │      │       │  ✓    │
# └────────────┴───────┴──────┴───────┴───────┘

Sentinel Policy Example

# policy.sentinel — require all S3 buckets to have a ManagedBy tag
import "tfplan/v2" as tfplan

s3_buckets = filter tfplan.resource_changes as _, rc {
  rc.type is "aws_s3_bucket" and
  rc.mode is "managed" and
  (rc.change.actions contains "create" or rc.change.actions contains "update")
}

main = rule {
  all s3_buckets as _, bucket {
    bucket.change.after.tags contains "ManagedBy"
  }
}

# sentinel.hcl — policy configuration
# policy "require-managed-by-tag" {
#   enforcement_level = "hard-mandatory"   # no override allowed
# }

Workspace Health Assessment (UI Configuration)

# Enable in HCP Terraform UI:
# Workspace → Settings → Health → Enable Health Assessments

# What it does:
# 1. Periodically runs terraform plan -refresh-only
# 2. Compares cloud reality to state
# 3. Reports drift as "unhealthy" workspace
# 4. Shows exactly what changed outside Terraform

# Requires:
# - HCP Terraform Plus or Enterprise tier
# - Workspace must have cloud credentials configured

Dynamic Credentials (OIDC) Setup

# AWS side: Create an OIDC provider and IAM role

# Step 1: OIDC Provider in AWS
resource "aws_iam_openid_connect_provider" "hcp_terraform" {
  url             = "https://app.terraform.io"
  client_id_list  = ["aws.workload.identity"]
  thumbprint_list = ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"]
}

# Step 2: IAM Role that HCP Terraform can assume
resource "aws_iam_role" "hcp_terraform" {
  name = "hcp-terraform-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = { Federated = aws_iam_openid_connect_provider.hcp_terraform.arn }
      Action    = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringEquals = {
          "app.terraform.io:aud" = "aws.workload.identity"
        }
        StringLike = {
          "app.terraform.io:sub" = "organization:my-org:project:*:workspace:*:run_phase:*"
        }
      }
    }]
  })
}

# Step 3: Attach permissions to the role
resource "aws_iam_role_policy_attachment" "admin" {
  role       = aws_iam_role.hcp_terraform.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

# Step 4: In HCP Terraform workspace settings:
# Add environment variable: TFC_AWS_PROVIDER_AUTH = true
# Add environment variable: TFC_AWS_RUN_ROLE_ARN = arn:aws:iam::ACCOUNT:role/hcp-terraform-role
# No more static AWS keys needed!
✓ Sentinel Policy Check Output
Sentinel Result: true

This result means that all Sentinel policies passed and the
protected behavior is allowed.

1 policies evaluated:
  ✓ require-managed-by-tag: hard-mandatory — PASSED