Provider Authentication #

Provider Terraform — AWS, GCP, Azure, dan lainnya — membutuhkan credentials untuk bisa membuat, membaca, dan menghapus resource. Bagaimana credentials ini didapat dan dikelola adalah salah satu keputusan keamanan paling mendasar dalam setup Terraform. Pilihan yang salah — misalnya hardcode credentials di file konfigurasi atau menggunakan credentials dengan permission berlebihan — bisa membuka celah yang dampaknya jauh melampaui Terraform itu sendiri.

Cara Provider Mendapat Credentials (AWS) #

AWS provider Terraform mengikuti urutan pencarian credentials yang sama dengan AWS SDK secara umum.

URUTAN PENCARIAN CREDENTIALS AWS PROVIDER:

  1. Konfigurasi eksplisit di blok provider (HINDARI)
     provider "aws" { access_key = "...", secret_key = "..." }

  2. Environment variable
     AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY

  3. AWS credentials file
     ~/.aws/credentials (untuk lokal developer)

  4. AWS config file
     ~/.aws/config (bisa menyimpan profile dan assume role)

  5. Container credentials (ECS task role)
     Otomatis tersedia jika berjalan di ECS

  6. Instance profile (EC2 instance role)
     Otomatis tersedia jika berjalan di EC2

  7. OIDC / Web Identity Token
     Untuk CI/CD (GitHub Actions, GitLab CI, dll.)

Terraform menggunakan credentials pertama yang ditemukan dalam urutan ini.

Static Credentials: Cara yang Salah #

# ANTI-PATTERN: Hardcode credentials di provider — JANGAN PERNAH
provider "aws" {
  region     = "ap-southeast-1"
  access_key = "AKIAIOSFODNN7EXAMPLE"     # ✗ Akan masuk ke Git history
  secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"  # ✗
}

# ANTI-PATTERN: Credentials di .tfvars (tetap berbahaya)
# terraform.tfvars:
# aws_access_key = "AKIAIOSFODNN7EXAMPLE"
# → File ini mungkin tidak di-.gitignore dan bisa ter-commit
# BENAR: Provider tanpa credentials eksplisit
# Terraform akan otomatis cari credentials dari environment
provider "aws" {
  region = "ap-southeast-1"
  # Tidak ada access_key atau secret_key di sini
  # Credentials didapat dari environment atau instance profile
}

AWS Profile untuk Development Lokal #

Untuk developer yang bekerja secara lokal, cara yang benar adalah menggunakan AWS profile yang dikonfigurasi di ~/.aws/.

# Setup AWS SSO (cara modern, lebih aman dari static credentials)
aws configure sso
# Ikuti prompt: SSO start URL, region, account, role name

# Login via SSO (perlu dijalankan setiap session atau saat token expire)
aws sso login --profile my-dev-profile

# Gunakan profile tertentu saat terraform
AWS_PROFILE=my-dev-profile terraform plan

# Atau konfigurasi di shell untuk session ini
export AWS_PROFILE=my-dev-profile
terraform plan
# ~/.aws/config — contoh konfigurasi multi-account dengan SSO
[profile dev]
sso_start_url = https://mycompany.awsapps.com/start
sso_region = ap-southeast-1
sso_account_id = 111111111
sso_role_name = DeveloperRole
region = ap-southeast-1

[profile production]
sso_start_url = https://mycompany.awsapps.com/start
sso_region = ap-southeast-1
sso_account_id = 333333333
sso_role_name = ReadOnlyRole  # Developer hanya read-only di production
region = ap-southeast-1

Assume Role untuk Multi-Account #

Ketika konfigurasi Terraform dijalankan dari satu account (management/CI account) tapi perlu membuat resource di account lain (production), gunakan assume_role di provider.

# Konfigurasi untuk multi-account deployment
# CI/CD berjalan dengan credentials management account
# lalu assume role ke account target

provider "aws" {
  region = "ap-southeast-1"

  assume_role {
    role_arn     = "arn:aws:iam::${var.target_account_id}:role/TerraformDeployRole"
    session_name = "terraform-${var.environment}"
    # external_id  = var.external_id  # Tambahkan untuk keamanan ekstra
  }
}

# IAM Role di account target (TerraformDeployRole) perlu trust policy:
# {
#   "Effect": "Allow",
#   "Principal": {
#     "AWS": "arn:aws:iam::MANAGEMENT_ACCOUNT_ID:role/TerraformCIRole"
#   },
#   "Action": "sts:AssumeRole"
# }

OIDC untuk CI/CD: Cara yang Paling Aman #

OIDC (OpenID Connect) memungkinkan CI/CD platform mendapatkan credentials AWS sementara tanpa perlu menyimpan access key permanen di secret storage.

CARA KERJA OIDC:

  GitHub Actions            AWS
       |                     |
       | 1. Request OIDC token dari GitHub
       |------ OIDC JWT ------>|
       |                     | 2. Verify JWT dengan GitHub OIDC provider
       |                     | 3. Buat temporary credentials (STS)
       |<-- Temp Credentials--|
       |                     |
       | 4. Gunakan temp credentials untuk Terraform
       |
  Temporary credentials expire otomatis (biasanya 1 jam)
  Tidak ada static key yang perlu dirotasi atau bisa bocor
# GitHub Actions dengan OIDC
# .github/workflows/terraform.yml

permissions:
  id-token: write   # Izin untuk request OIDC token
  contents: read

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: ap-southeast-1
          # Tidak perlu AWS_ACCESS_KEY_ID atau AWS_SECRET_ACCESS_KEY

      - name: Terraform Plan
        run: terraform plan
// IAM Role Trust Policy untuk GitHub OIDC
// Hanya izinkan repository dan branch tertentu
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub":
            "repo:myorg/infra-repo:ref:refs/heads/main"
          // Hanya main branch yang bisa assume role ini
        }
      }
    }
  ]
}

Credentials Berbeda untuk Plan dan Apply #

Memberikan permission yang sama antara plan dan apply adalah pemborosan privilege. Plan hanya butuh read, apply butuh write.

# CI pipeline: dua job dengan credentials berbeda

# Job 1: Plan — butuh read-only access
# Role: TerraformPlanRole (read-only policy)
# assume_role { role_arn = "...TerraformPlanRole" }

# Job 2: Apply — butuh write access, hanya di main branch
# Role: TerraformApplyRole (full access, tapi restrict by trust policy)
# Trust policy hanya izinkan main branch
MATRIX CREDENTIALS:

  Developer lokal   → AWS SSO profile, read-only di production
  CI Plan job       → OIDC, TerraformPlanRole (ReadOnlyAccess)
  CI Apply job      → OIDC, TerraformApplyRole (PowerUserAccess)
                       Trust policy: hanya main branch
  Atlantis server   → Instance profile, TerraformApplyRole

Ringkasan #

  • Jangan pernah hardcode credentials di konfigurasi Terraform — access key yang masuk ke Git history adalah insiden keamanan yang serius.
  • Untuk development lokal, gunakan AWS SSO dengan profile — lebih aman dari static credentials dan credentials bisa dirotasi terpusat.
  • assume_role di provider adalah cara yang tepat untuk multi-account deployment — CI/CD berjalan di satu account, assume role ke account target.
  • OIDC adalah standar emas untuk CI/CD — tidak ada static credentials yang perlu disimpan atau dirotasi, credentials expire otomatis.
  • Pisahkan credentials plan dan apply — plan hanya butuh read, apply butuh write. Prinsip least privilege berlaku di sini.
  • Trust policy yang ketat untuk apply role — batasi siapa yang bisa assume role apply (hanya main branch, hanya repository tertentu) untuk mencegah penyalahgunaan.

← Sebelumnya: Terraform Cloud   Berikutnya: Environment & Secret →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact