🚀 Chapter 4 — Production: Phần G — Production Governance với GitHub Actions và Amazon ECR
Ở Chapter 4F, chúng ta đã hoàn thành Artifact Promotion:
GitHub
↓
GitHub Actions
↓
Docker Build
↓
Amazon ECR
↓
Security Gate
↓
Dev
↓
Staging
↓
Production
Image được build một lần và sử dụng cùng một image digest xuyên suốt các môi trường.
Tuy nhiên, quy trình hiện tại vẫn còn một vấn đề:
Bất kỳ ai có quyền chạy workflow cũng có thể promote image lên Production.
Trong môi trường Production, chúng ta cần thêm:
- Quyền truy cập rõ ràng.
- Approval trước Production.
- Không cho phép image chưa được kiểm tra đi tiếp.
- Không cho phép ghi đè image tag quan trọng.
- Kiểm tra image digest trước khi promotion.
- Lưu lại lịch sử release.
- Có thể rollback về artifact trước đó.
Trong phần này, chúng ta sẽ xây dựng Production Governance bằng:
GitHub Actions
GitHub Environments
Amazon ECR
AWS IAM
OIDC
Image Digest
Manual Approval
1. Mục tiêu
Sau khi hoàn thành phần này, chúng ta sẽ có flow:
Developer
↓
GitHub
↓
GitHub Actions
↓
Test
↓
Docker Build
↓
Push Image vào ECR
↓
Security Gate
↓
Deploy Dev
↓
Deploy Staging
↓
[Production Approval]
↓
Deploy Production
Các nguyên tắc chính:
✅ Không build lại image ở từng environment
✅ Production chỉ nhận image đã được kiểm tra
✅ Production cần approval
✅ Sử dụng image digest để xác định artifact
✅ Không sử dụng AWS Access Key dài hạn nếu có thể dùng OIDC
✅ Có lịch sử promotion trên GitHub Actions
✅ Có thể kiểm tra và rollback về image cũ
2. Kiến trúc của Chapter 4G
GitHub
│
▼
GitHub Actions
│
▼
Security Gate
│
▼
Amazon ECR
│
┌──────────┼──────────┐
▼ ▼ ▼
Dev Staging Production
│
▼
Required Approval
│
▼
Production Release
GitHub Environments sẽ kiểm soát từng môi trường:
dev
└── Không cần approval
staging
└── Có thể yêu cầu approval
production
└── Bắt buộc approval
3. Kiểm tra môi trường hiện tại
Di chuyển vào repository:
cd online-boutique-cicd
Kiểm tra Git:
git status
Kiểm tra các workflow:
find .github/workflows -type f
Ví dụ:
.github/workflows/
├── reusable-ci-cd.yml
├── scale-ci-cd.yml
├── security-gate.yml
├── artifact-promotion.yml
└── ...
Kiểm tra script promotion:
ls -l scripts/promote-ecr-image.sh
Kiểm tra AWS CLI:
aws --version
Kiểm tra AWS account:
aws sts get-caller-identity
Kiểm tra Region:
aws configure get region
Nếu chưa cấu hình Region:
aws configure set region ap-northeast-1
Đặt biến môi trường:
export AWS_REGION=ap-northeast-1
export ECR_REPOSITORY=online-boutique-frontend
export IMAGE_TAG=a81c92f
Thay
a81c92fbằng Git SHA image tag thực tế trong ECR.
4. Kiểm tra image trong Amazon ECR
Kiểm tra image:
aws ecr describe-images \
--repository-name "$ECR_REPOSITORY" \
--image-ids imageTag="$IMAGE_TAG" \
--region "$AWS_REGION" \
--query 'imageDetails[0].{Tags:imageTags,Digest:imageDigest,Pushed:imagePushedAt}' \
--output table
Ví dụ:
----------------------------------------------------
| DescribeImages |
+----------+---------------------------------------+
| Digest | sha256:abc123... |
| Pushed | 2026-09-12T10:20:00+00:00 |
| Tags | a81c92f |
+----------+---------------------------------------+
Lấy digest của image:
export IMAGE_DIGEST=$(aws ecr describe-images \
--repository-name "$ECR_REPOSITORY" \
--image-ids imageTag="$IMAGE_TAG" \
--region "$AWS_REGION" \
--query 'imageDetails[0].imageDigest' \
--output text)
Kiểm tra:
echo "$IMAGE_DIGEST"
Kết quả ví dụ:
sha256:abc123456789...
Từ thời điểm này, chúng ta dùng:
Git SHA → xác định version
Digest → xác định chính xác nội dung image
5. Tạo GitHub Environments
Mở GitHub repository:
Repository
↓
Settings
↓
Environments
Tạo ba Environment:
dev
staging
production
5.1. Environment dev
Tạo:
dev
Không cần cấu hình approval.
Mục đích:
Image đã vượt qua Security Gate
↓
Deploy Dev
5.2. Environment staging
Tạo:
staging
Có thể cấu hình approval nếu muốn mô phỏng quy trình kiểm thử nghiêm ngặt hơn.
Mục đích:
Dev
↓
Staging
↓
Integration Test
↓
Acceptance Test
5.3. Environment production
Tạo:
production
Trong phần Environment protection rules, cấu hình:
Required reviewers
Thêm GitHub account được phép approve Production.
Ví dụ:
Required reviewers:
- maintainer-account
Nếu repository hỗ trợ thêm các rule khác, có thể cấu hình:
Deployment branches
Required reviewers
Wait timer
Environment secrets
Environment variables
Chọn branch được phép deploy Production, ví dụ:
main
Kết quả mong đợi:
production
└── Required reviewers: enabled
6. Tạo GitHub Variables
Vào:
Settings
↓
Secrets and variables
↓
Actions
↓
Variables
Tạo Repository Variable:
Name:
AWS_REGION
Value:
ap-northeast-1
Có thể tạo thêm:
ECR_REGISTRY
Ví dụ:
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
Tuy nhiên, không nên hard-code AWS Account ID trong workflow nếu có thể lấy thông tin registry từ AWS CLI.
7. Cấu hình AWS IAM cho GitHub Actions
Có hai phương án.
Option A — Sử dụng AWS Access Key
Workflow sử dụng:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Phương án này dễ bắt đầu nhưng có nhược điểm:
❌ Phải quản lý secret dài hạn
❌ Có nguy cơ bị lộ
❌ Cần rotate key
Nếu bạn đã sử dụng phương án này ở Chapter 4F, workflow vẫn có thể chạy.
Option B — Sử dụng GitHub OIDC
Đây là phương án nên dùng cho Production.
Flow:
GitHub Actions
↓
GitHub OIDC Token
↓
AWS IAM Role
↓
Temporary AWS Credentials
↓
Amazon ECR
Ưu điểm:
✅ Không cần lưu AWS Secret Access Key
✅ Không sử dụng credential dài hạn
✅ Có thể giới hạn repository và branch
✅ Phù hợp với CI/CD Production
8. Tạo IAM OIDC Provider
Đăng nhập AWS Console:
IAM
↓
Identity providers
↓
Add provider
Chọn:
Provider type:
OpenID Connect
Nhập:
Provider URL:
https://token.actions.githubusercontent.com
Chọn:
Audience:
sts.amazonaws.com
Sau đó tạo provider.
Nếu tài khoản AWS đã có provider này thì không cần tạo lại.
9. Tạo IAM Policy cho ECR Promotion
Tạo policy mới trong IAM.
Tên policy:
GitHubActionsECRPromotionPolicy
Nội dung:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadECRImages",
"Effect": "Allow",
"Action": [
"ecr:DescribeImages",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:ap-northeast-1:AWS_ACCOUNT_ID:repository/online-boutique-*"
},
{
"Sid": "PromoteECRImages",
"Effect": "Allow",
"Action": [
"ecr:PutImage"
],
"Resource": "arn:aws:ecr:ap-northeast-1:AWS_ACCOUNT_ID:repository/online-boutique-*"
}
]
}
Thay:
AWS_ACCOUNT_ID
bằng AWS Account ID của bạn.
Policy này cho phép workflow:
DescribeImages
BatchGetImage
PutImage
Không cấp các quyền không cần thiết như:
ecr:DeleteRepository
ecr:DeleteRepositoryPolicy
ecr:SetRepositoryPolicy
10. Tạo IAM Role cho GitHub Actions
Vào:
IAM
↓
Roles
↓
Create role
Chọn Web identity hoặc cấu hình trust policy thủ công.
Tên role:
GitHubActionsECRPromotionRole
Trust policy mẫu:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::AWS_ACCOUNT_ID: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:GITHUB_OWNER/GITHUB_REPOSITORY:environment:production"
}
}
}
]
}
Thay:
AWS_ACCOUNT_ID
GITHUB_OWNER
GITHUB_REPOSITORY
Ví dụ:
repo:Juu-dev/online-boutique-cicd:environment:production
Gắn policy:
GitHubActionsECRPromotionPolicy
Trust policy nên giới hạn đúng repository và environment Production. Không nên cho phép toàn bộ GitHub repository assume role.
11. Thêm AWS Role ARN vào GitHub
Vào:
Settings
↓
Environments
↓
production
↓
Environment variables
Tạo variable:
Name:
AWS_ROLE_ARN
Value:
arn:aws:iam::AWS_ACCOUNT_ID:role/GitHubActionsECRPromotionRole
Nếu sử dụng cùng role cho dev và staging, có thể tạo variables tương ứng ở từng Environment.
12. Cập nhật script promotion
Kiểm tra script hiện tại:
cat scripts/promote-ecr-image.sh
Script cần có các bước:
1. Nhận repository name
2. Nhận source tag
3. Nhận target tag
4. Lấy source digest
5. Lấy image manifest
6. Tạo target tag
7. Lấy target digest
8. So sánh source digest và target digest
9. Dừng nếu digest khác nhau
Một phiên bản hoàn chỉnh:
#!/usr/bin/env bash
set -euo pipefail
REPOSITORY_NAME="${1:?Repository name is required}"
SOURCE_TAG="${2:?Source tag is required}"
TARGET_TAG="${3:?Target tag is required}"
AWS_REGION="${AWS_REGION:-ap-northeast-1}"
echo "========================================"
echo "ECR Production Governance Promotion"
echo "========================================"
echo "Repository: $REPOSITORY_NAME"
echo "Source tag: $SOURCE_TAG"
echo "Target tag: $TARGET_TAG"
echo "Region: $AWS_REGION"
echo "========================================"
SOURCE_DIGEST="$(
aws ecr describe-images \
--repository-name "$REPOSITORY_NAME" \
--image-ids imageTag="$SOURCE_TAG" \
--region "$AWS_REGION" \
--query 'imageDetails[0].imageDigest' \
--output text
)"
if [[ -z "$SOURCE_DIGEST" || "$SOURCE_DIGEST" == "None" ]]; then
echo "Source image was not found."
exit 1
fi
echo "Source digest:"
echo "$SOURCE_DIGEST"
MANIFEST="$(
aws ecr batch-get-image \
--repository-name "$REPOSITORY_NAME" \
--image-ids imageTag="$SOURCE_TAG" \
--region "$AWS_REGION" \
--query 'images[0].imageManifest' \
--output text
)"
if [[ -z "$MANIFEST" || "$MANIFEST" == "None" ]]; then
echo "Image manifest was not found."
exit 1
fi
echo "Applying target tag: $TARGET_TAG"
aws ecr put-image \
--repository-name "$REPOSITORY_NAME" \
--image-tag "$TARGET_TAG" \
--image-manifest "$MANIFEST" \
--region "$AWS_REGION" \
> /dev/null
TARGET_DIGEST="$(
aws ecr describe-images \
--repository-name "$REPOSITORY_NAME" \
--image-ids imageTag="$TARGET_TAG" \
--region "$AWS_REGION" \
--query 'imageDetails[0].imageDigest' \
--output text
)"
echo "Target digest:"
echo "$TARGET_DIGEST"
if [[ "$SOURCE_DIGEST" != "$TARGET_DIGEST" ]]; then
echo "Promotion failed: digest mismatch."
exit 1
fi
echo "========================================"
echo "Promotion successful"
echo "========================================"
echo "Source tag: $SOURCE_TAG"
echo "Target tag: $TARGET_TAG"
echo "Digest: $SOURCE_DIGEST"
Cấp quyền thực thi:
chmod +x scripts/promote-ecr-image.sh
13. Tạo workflow Production Governance
Tạo file:
nano .github/workflows/production-governance.yml
Thêm nội dung:
name: Production Governance
on:
workflow_dispatch:
inputs:
service:
description: "ECR repository name"
required: true
type: string
image_tag:
description: "Git SHA image tag"
required: true
type: string
target_environment:
description: "Target environment"
required: true
type: choice
options:
- dev
- staging
- production
permissions:
contents: read
id-token: write
jobs:
promote:
name: Promote artifact
runs-on: ubuntu-latest
environment:
name: ${{ inputs.target_environment }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Configure AWS credentials with OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- name: Verify source image
env:
AWS_REGION: ${{ vars.AWS_REGION }}
ECR_REPOSITORY: ${{ inputs.service }}
IMAGE_TAG: ${{ inputs.image_tag }}
run: |
aws ecr describe-images \
--repository-name "$ECR_REPOSITORY" \
--image-ids imageTag="$IMAGE_TAG" \
--region "$AWS_REGION" \
--query 'imageDetails[0].{Tags:imageTags,Digest:imageDigest}' \
--output table
- name: Promote artifact
env:
AWS_REGION: ${{ vars.AWS_REGION }}
ECR_REPOSITORY: ${{ inputs.service }}
SOURCE_TAG: ${{ inputs.image_tag }}
TARGET_TAG: ${{ inputs.target_environment }}
run: |
chmod +x scripts/promote-ecr-image.sh
./scripts/promote-ecr-image.sh \
"$ECR_REPOSITORY" \
"$SOURCE_TAG" \
"$TARGET_TAG"
Workflow này thực hiện:
Run workflow
↓
Chọn service
↓
Chọn image tag
↓
Chọn environment
↓
GitHub Environment kiểm tra rule
↓
Nếu được phép → promotion
14. Commit và push workflow
Kiểm tra file:
git status
Add:
git add \
scripts/promote-ecr-image.sh \
.github/workflows/production-governance.yml
Commit:
git commit -m "add production governance workflow"
Push:
git push origin main
15. Test promotion lên Dev
Mở GitHub:
Actions
↓
Production Governance
↓
Run workflow
Nhập:
Service:
online-boutique-frontend
Image tag:
a81c92f
Target environment:
dev
Chọn:
Run workflow
Kết quả mong đợi:
Checkout repository
↓
Configure AWS credentials
↓
Verify source image
↓
Promote artifact
↓
Promotion successful
Kiểm tra ECR:
aws ecr describe-images \
--repository-name online-boutique-frontend \
--image-ids imageTag=dev \
--query 'imageDetails[0].{Tags:imageTags,Digest:imageDigest}' \
--output table
16. Test promotion lên Staging
Chạy workflow lần nữa.
Nhập:
Service:
online-boutique-frontend
Image tag:
a81c92f
Target environment:
staging
Chọn:
Run workflow
Kết quả:
a81c92f
↓
staging
Kiểm tra digest:
aws ecr describe-images \
--repository-name online-boutique-frontend \
--image-ids imageTag=staging \
--query 'imageDetails[0].imageDigest' \
--output text
Lấy digest gốc:
aws ecr describe-images \
--repository-name online-boutique-frontend \
--image-ids imageTag=a81c92f \
--query 'imageDetails[0].imageDigest' \
--output text
Hai kết quả phải giống nhau.
17. Test Production Approval
Chạy workflow lần nữa.
Nhập:
Service:
online-boutique-frontend
Image tag:
a81c92f
Target environment:
production
Chọn:
Run workflow
Workflow sẽ dừng tại GitHub Environment:
production
↓
Waiting for approval
Trên GitHub:
Actions
↓
Production Governance
↓
Review deployments
Kiểm tra:
Environment:
production
Image:
a81c92f
Repository:
online-boutique-frontend
Nếu thông tin chính xác, chọn:
Approve and deploy
Sau khi approve:
Production Approval
↓
Configure AWS credentials
↓
Verify source image
↓
Promote artifact
↓
Promotion successful
Nếu không approve:
Workflow
↓
Waiting
Image sẽ không được gắn tag production.
18. Kiểm tra toàn bộ digest
Đặt biến:
export ECR_REPOSITORY=online-boutique-frontend
Chạy:
for tag in a81c92f dev staging production
do
echo "===== $tag ====="
aws ecr describe-images \
--repository-name "$ECR_REPOSITORY" \
--image-ids imageTag="$tag" \
--query 'imageDetails[0].{Tag:imageTags,Digest:imageDigest}' \
--output table
done
Kết quả mong đợi:
a81c92f → sha256:abc123...
dev → sha256:abc123...
staging → sha256:abc123...
production → sha256:abc123...
Hoặc lấy digest trực tiếp:
for tag in a81c92f dev staging production
do
echo "$tag"
aws ecr describe-images \
--repository-name "$ECR_REPOSITORY" \
--image-ids imageTag="$tag" \
--query 'imageDetails[0].imageDigest' \
--output text
done
Kết quả cần đạt:
sha256:abc123...
sha256:abc123...
sha256:abc123...
sha256:abc123...
Điều này chứng minh:
Build một lần
↓
Security Gate
↓
Dev
↓
Staging
↓
Production
Tất cả environment sử dụng cùng một artifact.
19. Thử nghiệm Security Gate thất bại
Để kiểm tra governance, hãy thử promote một image không đạt điều kiện.
Ví dụ:
Image tag:
unknown-tag
Chạy workflow:
Actions
↓
Production Governance
↓
Run workflow
Nhập:
Service:
online-boutique-frontend
Image tag:
unknown-tag
Target environment:
production
Workflow phải thất bại ở bước:
Verify source image
Kết quả:
Source image was not found
Image không được promote.
Điều này chứng minh workflow không thể promote một artifact không tồn tại trong ECR.
20. Thêm bước kiểm tra digest trước Production
Để tăng tính an toàn, có thể tạo một file manifest lưu artifact đã được approve.
Tạo thư mục:
mkdir -p release-manifests
Tạo file:
nano release-manifests/online-boutique-frontend.json
Nội dung ví dụ:
{
"service": "online-boutique-frontend",
"imageTag": "a81c92f",
"imageDigest": "sha256:abc123456789...",
"approvedForProduction": true
}
Trong môi trường thực tế, file này có thể được tạo tự động sau khi:
Security Gate
↓
Staging Test
↓
Manual Review
Sau đó Production chỉ được phép sử dụng image digest đã được ghi nhận.
Trong lab này, file manifest chỉ dùng để minh họa. Ở hệ thống lớn, nên quản lý release metadata bằng một hệ thống release hoặc GitOps repository riêng.
21. Rollback về artifact trước đó
Giả sử Production hiện tại đang sử dụng:
production → sha256:new-image
Artifact trước đó là:
previous-release → sha256:old-image
Kiểm tra các tag trong ECR:
aws ecr describe-images \
--repository-name online-boutique-frontend \
--query 'imageDetails[].{Tags:imageTags,Digest:imageDigest,Pushed:imagePushedAt}' \
--output table
Nếu tag cũ vẫn tồn tại, có thể promote lại:
./scripts/promote-ecr-image.sh \
online-boutique-frontend \
previous-release \
production
Kiểm tra:
aws ecr describe-images \
--repository-name online-boutique-frontend \
--image-ids imageTag=production \
--query 'imageDetails[0].imageDigest' \
--output text
Kết quả phải trùng với digest của artifact cũ.
Flow rollback:
Production hiện tại
↓
Phát hiện lỗi
↓
Chọn artifact trước đó
↓
Kiểm tra digest
↓
Approval
↓
Promote lại production
22. Áp dụng cho nhiều service
Online Boutique có nhiều service:
online-boutique-frontend
online-boutique-cartservice
online-boutique-paymentservice
online-boutique-checkoutservice
online-boutique-shippingservice
online-boutique-productcatalogservice
online-boutique-currencyservice
online-boutique-emailservice
Có thể sử dụng cùng một workflow:
Production Governance
Ví dụ promote cartservice:
Service:
online-boutique-cartservice
Image tag:
b72d81a
Target environment:
production
Ví dụ promote paymentservice:
Service:
online-boutique-paymentservice
Image tag:
c63e91b
Target environment:
production
Mỗi service có image tag riêng:
frontend:
a81c92f
cartservice:
b72d81a
paymentservice:
c63e91b
Nhưng cùng sử dụng:
Reusable Promotion Logic
23. Kiểm tra lịch sử release
Trên GitHub:
Actions
↓
Production Governance
Có thể xem:
Workflow run
Commit
Actor
Environment
Input image tag
Target environment
Approval status
Execution log
Ví dụ:
Run #25
Service: online-boutique-frontend
Image: a81c92f
Environment: production
Approved by: maintainer-account
Status: Success
Đây là một phần quan trọng của Production Governance:
Không chỉ deploy được, mà còn phải biết ai đã promote artifact nào lên Production và vào thời điểm nào.
24. Kết quả cuối cùng
Sau khi hoàn thành Chapter 4G, hệ thống sẽ có kiến trúc:
Developer
↓
GitHub
↓
GitHub Actions
↓
Reusable Workflow
↓
Test
↓
Docker Build
↓
Amazon ECR
↓
Vulnerability Scan
↓
Security Gate
↓
Artifact Promotion
↓
Dev
↓
Staging
↓
Production Approval
↓
Production
Amazon ECR quản lý:
Docker Images
Image Tags
Image Digests
Lifecycle Policy
Image Scanning
GitHub quản lý:
Workflow
Environment
Required Reviewers
Approval
Release History
AWS IAM quản lý:
Who can access ECR
Which repository can be accessed
Which action is allowed
Which GitHub repository can assume the role
25. Tổng kết Chapter 4
Toàn bộ Chapter 4 có thể được nhìn như sau:
4A — Amazon ECR
↓
4B — Lifecycle Policy
↓
4C — Image Security
↓
4D — Immutable Tags
↓
4E — Security Gate
↓
4F — Artifact Promotion
↓
4G — Production Governance
Sự khác biệt giữa các phần:
| Phần | Câu hỏi cần giải quyết |
|---|---|
| 4A | Image được lưu ở đâu? |
| 4B | Image cũ được quản lý như thế nào? |
| 4C | Image có vulnerability hay không? |
| 4D | Image tag có bị ghi đè hay không? |
| 4E | Image không an toàn có bị chặn hay không? |
| 4F | Làm sao sử dụng cùng một image qua các environment? |
| 4G | Ai được phép đưa image lên Production? |
Kết quả cuối cùng:
Build Once
↓
Scan Once
↓
Promote Same Artifact
↓
Approve Production
↓
Release with Governance
Đây là nền tảng cần thiết trước khi chuyển sang Chapter 5 — Kubernetes + GitOps với Amazon EKS và ArgoCD.
All rights reserved