CodeBuild Nâng Cao: Biến Môi Trường, Secret và Cache

K
Kai··4 min read

Build của bài trước chỉ in ra vài dòng. Build thật cần nhiều hơn: một URL API tùy môi trường, một khóa để gọi dịch vụ, mật khẩu để chạy migration database. Câu hỏi là truyền những giá trị đó vào build thế nào cho an toàn — không hardcode vào source, không in ra log. Bài này làm đúng việc đó, phân biệt rõ biến thường và secret, rồi bật cache để build nhanh hơn.

Mục tiêu

Truyền biến môi trường và secret vào CodeBuild đúng cách (biến thường vs SSM vs Secrets Manager), thấy CodeBuild che secret trong log ra sao, và bật cache.

Ba nguồn biến môi trường

Khối env trong buildspec.yml nhận giá trị từ ba nguồn, mỗi nguồn cho một mục đích:

env:
  variables:
    APP_ENV: "production"
  parameter-store:
    GREETING: /cicddemo/greeting
    API_KEY: /cicddemo/api-key
  secrets-manager:
    DB_PASSWORD: awscicd/demo/db:password

variables là giá trị thường, ghi thẳng vào buildspec — dùng cho config không nhạy cảm (môi trường, cờ tính năng). parameter-store lấy giá trị từ SSM Parameter Store theo tên tham số. secrets-manager lấy từ Secrets Manager, cú pháp tên-secret:khóa-json. Khác biệt cốt lõi: hai nguồn sau giữ giá trị ngoài source code; buildspec chỉ ghi tên tham chiếu, giá trị thật được CodeBuild đọc lúc build.

Tạo tham số và secret

SSM Parameter Store — một tham số thường và một dạng SecureString (mã hóa):

$ aws ssm put-parameter --name /cicddemo/greeting --value "hello-from-ssm" --type String
$ aws ssm put-parameter --name /cicddemo/api-key --value "s3cr3t-ssm-value" --type SecureString

(Lưu ý: tên tham số SSM không được bắt đầu bằng aws — đó là tiền tố dành riêng, sẽ bị từ chối; dùng tên khác như /cicddemo/.)

Secrets Manager — một secret dạng JSON:

$ aws secretsmanager create-secret --name awscicd/demo/db \
    --secret-string '{"password":"p@ss-from-secretsmanager"}'

Service role CodeBuild (bài 2) chưa có quyền đọc hai thứ này, nên cấp thêm — giới hạn đúng vào đường dẫn của ta, không mở rộng:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["ssm:GetParameters","ssm:GetParameter"],
      "Resource": "arn:aws:ssm:*:*:parameter/cicddemo/*" },
    { "Effect": "Allow", "Action": ["secretsmanager:GetSecretValue"],
      "Resource": "arn:aws:secretsmanager:*:*:secret:awscicd/*" }
  ]
}
$ aws iam put-role-policy --role-name awscicd-codebuild-role \
    --policy-name awscicd-codebuild-secrets --policy-document file://cb-secrets.json

CodeBuild tự che secret trong log

Đây là điểm quan trọng nhất của bài. Sửa buildspec để in các biến ra (cố tình, để xem), rồi chạy build và đọc log:

$ aws logs get-log-events --log-group-name /aws/codebuild/awscicd-demo-build ...
Install phase — APP_ENV=production
GREETING from SSM = ***
API_KEY present? yes
DB_PASSWORD present? yes

Đọc kỹ từng dòng. APP_ENV=production hiện nguyên — nó là variables, không nhạy cảm. Nhưng GREETING (lấy từ Parameter Store) bị thay bằng ***, dù giá trị của nó chỉ là "hello-from-ssm" vô hại. CodeBuild tự động che mọi giá trị đến từ parameter-storesecrets-manager trong log, bất kể nó có thật sự bí mật hay không. Còn API_KEYDB_PASSWORD ta chỉ in "present? yes" để không lộ, và chúng đã được bơm vào môi trường đúng như mong đợi.

Hệ quả thực hành rút ra: đặt secret vào parameter-store/secrets-manager thì được CodeBuild che giúp; đặt secret vào variables thì nó hiện nguyên trong log nằm trong source code — đừng bao giờ làm vậy.

   buildspec env:
     variables:        APP_ENV=production          ──────────▶ hiện trong log
     parameter-store:  GREETING = /cicddemo/...   ──┐
     secrets-manager:  DB_PASSWORD = awscicd/...  ──┤ CodeBuild đọc lúc build
                                                    ▼
                          bơm vào biến môi trường, giá trị BỊ CHE (***) trong log

Bật cache để build nhanh hơn

Mỗi build dựng container mới, sạch — tốt cho tính tái lập nhưng chậm nếu phải tải lại dependency mỗi lần. Cache giữ lại một số thứ giữa các build. Bật cache LOCAL cho project:

$ aws codebuild update-project --name awscicd-demo-build \
    --cache '{"type":"LOCAL","modes":["LOCAL_SOURCE_CACHE","LOCAL_CUSTOM_CACHE"]}' \
    --query 'project.cache.type' --output text
LOCAL

Có ba chế độ cache LOCAL: LOCAL_SOURCE_CACHE giữ lại git metadata (clone nhanh hơn ở lần sau), LOCAL_DOCKER_LAYER_CACHE giữ layer Docker (cho build image), LOCAL_CUSTOM_CACHE giữ các thư mục bạn khai trong cache.paths của buildspec (ví dụ node_modules, ~/.m2). Cache LOCAL gắn với máy chạy build nên chỉ giúp khi cùng máy được tái dùng; với cache bền hơn qua mọi build, dùng type: S3 trỏ vào một bucket. Với app có nhiều dependency, cache cắt được phần lớn thời gian install.

🧹 Dọn dẹp

SSM param và secret giữ tới cuối series (build ở các bài sau vẫn tham chiếu chúng). Khi dọn:

$ aws ssm delete-parameter --name /cicddemo/greeting
$ aws ssm delete-parameter --name /cicddemo/api-key
$ aws secretsmanager delete-secret --secret-id awscicd/demo/db --force-delete-without-recovery

SSM Parameter Store (standard) miễn phí; Secrets Manager tính khoảng 0,40 USD/secret/tháng theo tỉ lệ, nên giữ vài ngày chỉ vài cent. --force-delete-without-recovery xóa ngay thay vì chờ cửa sổ khôi phục.

Tổng kết

CodeBuild nhận biến môi trường từ ba nguồn: variables cho config thường (hiện trong log), parameter-store (SSM) và secrets-manager cho giá trị nhạy cảm — hai nguồn sau giữ giá trị ngoài source và được CodeBuild tự che (***) trong log. Cấp quyền đọc cho role theo least-privilege, giới hạn đúng đường dẫn tham số. Cache (LOCAL với các mode source/docker-layer/custom, hoặc S3) giữ lại dependency giữa các build để chạy nhanh hơn. Quy tắc vàng: secret không bao giờ nằm trong variables hay source.

Bài tới khép Part II: cho CodeBuild chạy test và xuất test report — gom kết quả test (JUnit, v.v.) thành báo cáo xem được trong CodeBuild, để biết build không chỉ chạy mà còn đúng.