Có một team mất 3 ngày để deploy static website lên AWS vì S3 public, ACM ở sai region, CloudFront cache không clear. Câu trả lời cho tất cả những vấn đề đó: một CDK stack + GitHub Actions OIDC, không access key, không chỉnh tay.
flowchart LR
Dev["git push main"] --> GHA["GitHub Actions<br/>build + deploy"]
GHA --> S3["S3 private"]
S3 --> CF["CloudFront OAC"]
CF --> R53["Route 53 myapp.com"]
ACM["ACM us-east-1"] --> CF
R53 --> User["User"]
CDK Stack
const bucket = new s3.Bucket(this, "WebsiteBucket", {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
encryption: s3.BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
});
const zone = route53.HostedZone.fromLookup(this, "Zone", {
domainName: "myapp.com",
});
const certificate = new acm.Certificate(this, "Cert", {
domainName: "myapp.com",
subjectAlternativeNames: ["www.myapp.com"],
validation: acm.CertificateValidation.fromDns(zone),
});
const distribution = new cloudfront.Distribution(this, "CDN", {
defaultRootObject: "index.html",
domainNames: ["myapp.com", "www.myapp.com"],
certificate,
defaultBehavior: {
origin: origins.S3BucketOrigin.withOriginAccessControl(bucket),
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
},
errorResponses: [
{
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: "/index.html",
},
],
});
new route53.ARecord(this, "AliasRecord", {
zone,
target: route53.RecordTarget.fromAlias(
new route53targets.CloudFrontTarget(distribution)
),
});
new s3deploy.BucketDeployment(this, "Deploy", {
sources: [s3deploy.Source.asset("../dist")],
destinationBucket: bucket,
distribution,
distributionPaths: ["/*"],
});
GitHub Actions OIDC
Mình thấy nhiều team vẫn dùng access key trong CI dù AWS đã có OIDC từ năm 2022. Lý do: setup ban đầu hơi rắc rối, nhưng làm một lần xong quên.
name: Deploy
on: push
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
aws-region: ap-southeast-1
- run: npm ci && npm run build
- run: aws s3 sync dist/ s3://myapp-website --delete
- run: aws cloudfront create-invalidation --distribution-id $CF_ID --paths "/*"
OIDC deploy không access key là thứ mất 1 tiếng setup mà mỗi lần deploy sau đó đều tiết kiệm được vài phút loay hoay với credential. Và nó cũng là prerequisite để CI/CD pipeline của bạn pass security review.
- S3 private + CloudFront OAC: không public bucket
- ACM us-east-1: bắt buộc cho CloudFront
- SPA fallback: 404 → 200 /index.html
- OIDC deploy: không access key, token expire 1h