Giới thiệu

Khi xây dựng hạ tầng ngân hàng trên AWS, việc triển khai một hệ thống lớn, bao phủ nhiều tài khoản và môi trường khác nhau đòi hỏi phải sử dụng Infrastructure as Code (IaC). Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách sử dụng Terraform để tự động hóa việc tạo hạ tầng, tổ chức mã nguồn, và quy trình thực thi từ tài khoản Operation.

Infrastructure as Code (IaC)

IaC là phương pháp sử dụng mã nguồn để định nghĩa và triển khai hạ tầng, thay vì thực hiện thủ công trên AWS Console. Đối với hệ thống ngân hàng phức tạp, IaC là công cụ bắt buộc để đảm bảo tính nhất quán, dễ quản lý và khả năng sao chép giữa các môi trường.

Một số công cụ IaC phổ biến bao gồm Terraform, AWS CDK, và Pulumi. Trong bài viết này, chúng ta sẽ tập trung vào Terraform – một công cụ mạnh mẽ, được sử dụng rộng rãi để quản lý hạ tầng trên nhiều cloud provider, bao gồm AWS.

Dùng một hay nhiều Git Repo?

Dựa trên mô hình tài khoản đã trình bày trong bài trước, chúng ta cần quản lý mã nguồn IaC cho các môi trường nonprod (DEV, UAT, STAGING) và prod (PRODUCTION). Để tối ưu quản lý và tách biệt các môi trường, nên:

  1. Tạo một Git repository cho môi trường nonprod (vd: nonprod-terraform).
  2. Tạo một Git repository riêng cho môi trường prod (vd: prod-terraform).

Việc chia tách này giúp bảo vệ môi trường prod khỏi những thay đổi không mong muốn ở các môi trường khác, đồng thời dễ dàng áp dụng các quy trình kiểm duyệt chặt chẽ hơn.

Tổ chức thư mục trong Git Repository

Trong mỗi repository, tổ chức thư mục cần phản ánh cấu trúc tài khoản và môi trường. Dưới đây là ví dụ cấu trúc thư mục cho repository nonprod-terraform:

└── nonprod-terraform
    ├── data-nonprod
    │   ├── dev
    │   └── uat
    ├── networking-nonprod
    │   ├── dev
    │   └── uat
    ├── observability-nonprod
    │   ├── dev
    │   └── uat
    ├── operation-nonprod
    │   ├── dev
    │   └── uat
    └── workload-nonprod
        ├── dev
        └── uat

Trong mỗi thư mục môi trường (vd: data-nonprod/dev), tạo thêm các thư mục con cho từng thành phần hạ tầng, chẳng hạn như:

  • vpc: Quản lý mạng.
  • eks: Quản lý cluster Kubernetes.
  • rds: Quản lý cơ sở dữ liệu.

Terraform Backend

Terraform lưu trạng thái hạ tầng (state file) để đối chiếu mã nguồn với hạ tầng thực tế. Khi làm việc theo nhóm, trạng thái này cần được lưu trữ ở một nơi dùng chung, chẳng hạn như AWS S3 Bucket, kết hợp với DynamoDB để quản lý khóa trạng thái.

Ví dụ, khai báo Terraform Backend để quản lý trạng thái hạ tầng của data-nonprod/dev/vpc:

terraform {
  backend "s3" {
    bucket         = "nonprod-terraform-s3-backend"
    key            = "data-nonprod/dev/vpc"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "nonprod-terraform-s3-backend"
  }
}

Tương tự, khi triển khai cơ sở dữ liệu (RDS) cho môi trường UAT:

terraform {
  backend "s3" {
    bucket         = "nonprod-terraform-s3-backend"
    key            = "data-nonprod/uat/rds"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "nonprod-terraform-s3-backend"
  }
}

Luồng triển khai hạ tầng từ tài khoản Operation

Để tạo hạ tầng, ta thực thi các tác vụ từ tài khoản Operation. Trong tài khoản Operation, ta tạo một IAM Role với các quyền truy cập vào S3, DynamoDB và KMS. Mục đích của IAM Role này là để lưu trữ tệp tin trạng thái hạ tầng của các tài khoản khác vào S3 Bucket.

Sau khi tạo IAM Role trong tài khoản Operation, ta sử dụng tính năng “Assume Role Cross Account” để lấy thông tin đăng nhập (Credentials) của tài khoản khác. Điều này cho phép ta thực thi các tác vụ tạo hạ tầng từ tài khoản Operation, nhưng sử dụng quyền truy cập của tài khoản khác.

Ví dụ, trong tài khoản Operation, ta tạo một IAM Role có tên là “nonprod-terraform-operation”. Trước khi chạy Terraform, ta sử dụng user của tài khoản Operation thực thi câu lệnh sau để lấy token:

export JSON=$(aws sts assume-role --role-arn arn:aws:iam::0123456789:role/nonprod-terraform-operation --role-session-name "execution")
export AWS_ACCESS_KEY_ID=$(echo ${JSON} | jq --raw-output ".Credentials[\"AccessKeyId\"]")
export AWS_SECRET_ACCESS_KEY=$(echo ${JSON} | jq --raw-output ".Credentials[\"SecretAccessKey\"]")
export AWS_SESSION_TOKEN=$(echo ${JSON} | jq --raw-output ".Credentials[\"SessionToken\"]")

Token này có quyền truy cập vào S3 trong tài khoản Operation (mặc định Token tồn tại trong vòng 15 phút). Bên cạnh đó, Token này còn định danh cho một user tạm thời có quyền Assume Role ở các tài khoản khác. Ví dụ, với câu lệnh CLI trên, user tạm thời được tạo ra có tên là “execution”. Tên này được chỉ định thông qua tham số --role-session-name trong câu lệnh aws sts assume-role. Đầy đủ ARN (Amazon Resource Name) như sau:Copy

arn:aws:sts::0123456789:assumed-role/nonprod-terraform-operation/execution

Tiếp theo, ở các tài khoản khác, ta tạo một IAM Role với các quyền cần thiết để tạo hạ tầng trên đó. Lưu ý rằng chỉ nên cấp quyền vừa đủ và tuân thủ Security best practices in IAM của AWS. Ví dụ, trong tài khoản “data-nonprod”, ta tạo một IAM Role có tên là “nonprod-terraform-operation”. Sau đó, ta cho phép arn:aws:sts::0123456789:assumed-role/nonprod-terraform-operation/execution có quyền Assume Role.

Cuối cùng ở Terraform ta khai báo AWS Provider như sau, thư mục data-nonpord/dev/vpc:

terraform {
  backend "s3" {
    bucket         = "nonprod-terraform-s3-backend"
    key            = "data-nonprod/dev/vpc"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "nonprod-terraform-s3-backend"
  }
}

provider "aws" {
  assume_role {
    role_arn = "arn:aws:iam::<data-nonprod-account-id>:role/nonprod-terraform-operation"
  }
}

Tương tự cho các tài khoản khác, ví dụ networking-nonprod, thư mục networking-nonprod/uat/rds:

terraform {
  backend "s3" {
    bucket         = "nonprod-terraform-s3-backend"
    key            = "networking-nonprod/uat/rds"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "nonprod-terraform-s3-backend"
  }
}

provider "aws" {
  assume_role {
    role_arn = "arn:aws:iam::<networking-nonprod-account-id>:role/nonprod-terraform-operation"
  }
}

Để thuận tiện, những bước lấy Token có thể được tự động hóa thông qua CI/CD. Khi chạy CI/CD, ta cần chạy một script để phát hiện thư mục nào đã thay đổi, sau đó nhảy vào trong thư mục đó để chạy Terraform. Ví dụ, khi sử dụng GitHub Actions, ta có thể dùng action tj-actions/changed-files để xác định các thư mục đã thay đổi.

Kết luận

Việc triển khai hạ tầng Cloud trên nhiều tài khoản AWS đòi hỏi sự phối hợp chặt chẽ giữa tổ chức mã nguồn, thiết lập quyền truy cập và tự động hóa quy trình. Sử dụng Terraform, kết hợp với các dịch vụ như S3 và DynamoDB, giúp đảm bảo tính nhất quán và bảo mật cho hạ tầng của bạn.

Trong bài tiếp theo, chúng ta sẽ cùng khám phá cách thiết kế Networking for Multi AWS Accounts, một thành phần cốt lõi trong kiến trúc Cloud.

Trích: Quân Huỳnh – Cloud Engineer, Tác giả trang devopsvn.tech

Leave a Reply

This site uses cookies to offer you a better browsing experience. By browsing this website, you agree to our use of cookies.