search

16-Best Practice: Quản lý AWS Credentials trong Terraform

calendar_today Đăng ngày: 03/05/2026

Bài này mình sẽ giải thích tại sao không nên để credentials trong file .tf, Terraform tự động đọc credentials như thế nào, và cách thiết lập đúng cho cả môi trường local lẫn CI/CD.

Xem thêm:

03-Terraform Provider là gì? Tại sao bắt buộc phải có Provider

18-Terraform Cloud – Cộng tác và quản lý hạ tầng ở tầm team

Hướng dẫn xây dựng AWS VPC cơ bản bằng Terraform

1. Terraform load file .tf như thế nào?

Terraform có cơ chế tự động quét và gộp toàn bộ file .tf trong cùng một thư mục lại thành một cấu hình duy nhất. Điều này có nghĩa là khi bạn chạy:

terraform init
terraform plan
terraform apply

Terraform không quan tâm bạn đặt resource ở file nào. Nó gom hết lại rồi xử lý cùng nhau.

Dựa vào cơ chế này, nhiều người bắt đầu tách provider và credentials sang provider.tf cho gọn – và đây là bước đi đúng hướng so với hard-code key trực tiếp trong từng file resource. Nhưng về lâu dài, cách này vẫn có vấn đề.

2. Tại sao không nên để credentials trong provider.tf?

1. provider.tf vẫn là code, vẫn bị commit lên Git

Dù bạn đã tách riêng, file .tf vẫn rất dễ:

  • Bị commit nhầm lên Git (đặc biệt khi không có .gitignore cẩn thận)
  • Bị chia sẻ khi backup hoặc copy source code
  • Lộ credentials cho người không có quyền truy cập

Một khi key đã push lên GitHub public repo, coi như xong. AWS sẽ gửi mail cảnh báo trong vài phút, và nếu chậm xử lý, tài khoản của bạn có thể bị dùng để đào coin hoặc tệ hơn.

2. Không linh hoạt khi làm việc với nhiều AWS account

Thực tế một tổ chức thường có nhiều account riêng biệt: dev, staging, production. Nếu credentials nằm cứng trong provider.tf, mỗi lần chuyển môi trường bạn phải:

  • Sửa file thủ công
  • Hoặc duy trì nhiều bản copy code song song
  • Hoặc dùng logic điều kiện phức tạp trong config

Cả ba cách đều tệ.

3. CI/CD không đọc credentials từ file .tf

Trong pipeline CI/CD (GitHub Actions, GitLab CI, Jenkins…), credentials thường được inject qua:

  • Secret Manager của platform
  • Biến môi trường của runner
  • IAM Role gắn trực tiếp vào máy chủ hoặc container

Pipeline không đọc từ file .tf, và chắc chắn không cho phép commit key vào repo. Vì vậy, nếu bạn để credentials trong provider.tf, workflow CI/CD gần như không dùng được.

3. Terraform tự động đọc credentials như thế nào?

Khi chạy terraform plan hoặc terraform apply, Terraform khởi tạo AWS provider, provider đó gọi AWS SDK, và SDK kiểm tra một số nơi theo thứ tự ưu tiên. Trong đó, phổ biến nhất là các biến môi trường tiêu chuẩn:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION

Nếu các biến này đã được set trong shell hiện tại, Terraform tự động dùng mà không cần bạn khai báo gì thêm trong file .tf.

4. Thiết lập credentials bằng Environment Variables

Đây là cách phổ biến nhất cho môi trường local. Trên Linux hoặc macOS:

export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
export AWS_DEFAULT_REGION=us-east-1

Kiểm tra lại cho chắc:

echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY
echo $AWS_DEFAULT_REGION

Nếu terminal hiển thị đúng giá trị, bạn đã sẵn sàng chạy Terraform.

Lưu ý: Biến môi trường này chỉ tồn tại trong session hiện tại. Mở terminal mới là mất. Nếu muốn giữ lâu dài, thêm vào ~/.bashrc hoặc ~/.zshrc.

Khi đó provider.tf của bạn chỉ cần khai báo tối giản như này:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  # Không cần khai báo access_key hay secret_key
  # Terraform tự đọc từ biến môi trường
}

Sạch, không có credentials nào trong code.

5. Các phương pháp khác (theo độ phức tạp tăng dần)

AWS Shared Credentials File

AWS CLI tạo file credentials tại ~/.aws/credentials khi bạn chạy aws configure. Terraform cũng đọc file này tự động.

[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

[production]
aws_access_key_id = PROD_ACCESS_KEY
aws_secret_access_key = PROD_SECRET_KEY

Dùng profile cụ thể trong provider:

provider "aws" {
  region  = "us-east-1"
  profile = "production"
}

Hoặc set qua biến môi trường:

export AWS_PROFILE=production

IAM Role (dành cho EC2, ECS, Lambda)

Nếu Terraform chạy trên máy EC2 hoặc container ECS, bạn có thể gắn IAM Role trực tiếp vào instance/task đó. Terraform tự động lấy credentials từ instance metadata – không cần key, không cần file, không cần biến môi trường.

Đây là cách an toàn nhất và là best practice trong môi trường production.

CI/CD: Inject qua Secret

Ví dụ với GitHub Actions:

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_DEFAULT_REGION: us-east-1

Terraform chạy trong pipeline sẽ tự đọc các biến môi trường này. Key được lưu trong GitHub Secrets, không bao giờ xuất hiện trong log hay source code.

6. So sánh các phương pháp

Phương pháp Môi trường phù hợp Mức độ an toàn Độ linh hoạt
Hard-code trong .tf Không nên dùng Rất thấp Thấp
Environment variables Local dev, CI/CD Tốt Cao
AWS credentials file Local dev Tốt Trung bình
IAM Role EC2, ECS, Lambda Cao nhất Cao
CI/CD Secrets Pipeline Cao Cao

Tóm lại

Trong bài này mình đã đi qua:

  • Vì sao không nên để credentials trong provider.tf dù đã tách file
  • Cơ chế Terraform tự đọc credentials từ biến môi trường
  • Cách thiết lập environment variables cho local dev
  • Các phương pháp khác: credentials file, IAM Role, CI/CD Secrets

Nguyên tắc cốt lõi: credentials không được xuất hiện trong source code, dù ở bất kỳ file .tf nào. Environment variables là điểm xuất phát tốt nhất, còn IAM Role là đích đến khi bạn chạy Terraform trong môi trường cloud thực tế.