1212 s3-bucket :
1313 description : " S3 bucket name for deployment"
1414 type : string
15- required : true
15+ required : false
1616 cloudfront-distribution-id :
1717 description : " CloudFront distribution ID for cache invalidation"
1818 type : string
19- required : true
19+ required : false
20+ role-session-name :
21+ description : " AWS role session name for OIDC authentication (default: {repo}-{short-sha}-{run-number})"
22+ type : string
23+ required : false
24+ default : " "
2025
2126 # Environment Configuration
2227 environment :
23- description : " Deployment environment ( GitHub environment name for protection rules )"
28+ description : " GitHub Environment name for secrets/variables (e.g. Staging, Production )"
2429 type : string
25- required : false
26- default : " staging"
30+ required : true
2731
2832 # Build Configuration
2933 package-manager :
9296 required : false
9397 default : false
9498
95- secrets :
96- aws-access-key-id :
97- description : " AWS access key ID"
98- required : true
99- aws-secret-access-key :
100- description : " AWS secret access key"
101- required : true
102-
10399 outputs :
104100 deployment-url :
105101 description : " URL of the deployed application"
@@ -113,14 +109,83 @@ jobs:
113109 prepare :
114110 name : 🔍 Prepare Deployment
115111 runs-on : ubuntu-latest
112+ environment : ${{ inputs.environment }}
116113 outputs :
117114 cache-control-static : ${{ steps.cache-config.outputs.cache-control-static }}
118115 cache-control-html : ${{ steps.cache-config.outputs.cache-control-html }}
119116 s3-prefix : ${{ steps.deployment-config.outputs.s3-prefix }}
120117 deployment-url : ${{ steps.deployment-config.outputs.deployment-url }}
121118 brand-matrix : ${{ steps.brand-config.outputs.matrix }}
122119 invalidation-paths : ${{ steps.cache-config.outputs.invalidation-paths }}
120+ auth-mode : ${{ steps.validate-inputs.outputs.auth-mode }}
121+ role-session-name : ${{ steps.resolve-session-name.outputs.role-session-name }}
123122 steps :
123+ - name : Validate required inputs
124+ id : validate-inputs
125+ env :
126+ ENVIRONMENT : ${{ inputs.environment }}
127+ S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
128+ CLOUDFRONT_DISTRIBUTION_ID : ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} || ${{ inputs.cloudfront-distribution-id }}
129+ VAR_AWS_ACCESS_KEY_ID : ${{ vars.AWS_ACCESS_KEY_ID }}
130+ SECRET_AWS_SECRET_ACCESS_KEY : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
131+ VAR_AWS_ROLE_ARN : ${{ vars.AWS_ROLE_ARN }}
132+ run : |
133+ echo "🔍 Validating deployment configuration..."
134+ echo "ℹ️ Using variables from $ENVIRONMENT environment"
135+
136+ if [ -z "$S3_BUCKET" ]; then
137+ echo "❌ Error: S3_BUCKET must be set as a variable in your $ENVIRONMENT environment"
138+ exit 1
139+ fi
140+ echo "✅ S3_BUCKET: $S3_BUCKET"
141+
142+ if [ -z "$CLOUDFRONT_DISTRIBUTION_ID" ]; then
143+ echo "❌ Error: CLOUDFRONT_DISTRIBUTION_ID must be set as a variable in your $ENVIRONMENT environment"
144+ exit 1
145+ fi
146+ echo "✅ CLOUDFRONT_DISTRIBUTION_ID: $CLOUDFRONT_DISTRIBUTION_ID"
147+
148+ if [ -n "$VAR_AWS_ACCESS_KEY_ID" ]; then
149+ echo "ℹ️ AWS_ACCESS_KEY_ID set from variable: $VAR_AWS_ACCESS_KEY_ID"
150+ if [ -z "$SECRET_AWS_SECRET_ACCESS_KEY" ]; then
151+ echo "❌ Error: AWS_SECRET_ACCESS_KEY is not defined as a secret in your $ENVIRONMENT environment"
152+ exit 1
153+ fi
154+ echo "✅ AWS_SECRET_ACCESS_KEY secret is configured"
155+ echo "✅ Using static credential authentication"
156+ echo "auth-mode=static" >> $GITHUB_OUTPUT
157+ elif [ -n "$VAR_AWS_ROLE_ARN" ]; then
158+ echo "ℹ️ AWS_ROLE_ARN set from variable: $VAR_AWS_ROLE_ARN"
159+ echo "✅ Using OIDC authentication"
160+ echo "auth-mode=oidc" >> $GITHUB_OUTPUT
161+ else
162+ echo "❌ Error: No AWS credentials configured in your $ENVIRONMENT environment."
163+ echo " Configure one of the following:"
164+ echo " - Static credentials: AWS_ACCESS_KEY_ID (variable) + AWS_SECRET_ACCESS_KEY (secret)"
165+ echo " - OIDC: AWS_ROLE_ARN (variable)"
166+ exit 1
167+ fi
168+
169+ echo "✅ All inputs validated successfully"
170+
171+ - name : Resolve role session name
172+ id : resolve-session-name
173+ if : steps.validate-inputs.outputs.auth-mode == 'oidc'
174+ env :
175+ ROLE_SESSION_NAME : ${{ inputs.role-session-name }}
176+ COMMIT_SHA : ${{ github.sha }}
177+ REPOSITORY_NAME : ${{ github.event.repository.name }}
178+ RUN_NUMBER : ${{ github.run_number }}
179+ run : |
180+ SESSION_NAME="$ROLE_SESSION_NAME"
181+ if [ -z "$SESSION_NAME" ]; then
182+ SHORT_SHA=$(echo "$COMMIT_SHA" | cut -c1-7)
183+ SESSION_NAME="${REPOSITORY_NAME}-${SHORT_SHA}-${RUN_NUMBER}"
184+ fi
185+ # AWS session names: max 64 chars, allowed [a-zA-Z0-9=,.@-]
186+ SESSION_NAME=$(echo "$SESSION_NAME" | tr -c '[:alnum:]=,.@-' '-' | cut -c1-64)
187+ echo "role-session-name=$SESSION_NAME" >> $GITHUB_OUTPUT
188+
124189 - name : Configure cache strategy
125190 id : cache-config
126191 run : |
@@ -196,7 +261,7 @@ jobs:
196261 fi
197262 env :
198263 INPUTS_PREVIEW_BASE_URL : ${{ inputs.preview-base-url }}
199- INPUTS_S3_BUCKET : ${{ inputs.s3-bucket }}
264+ INPUTS_S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
200265
201266 - name : Configure multi-brand matrix
202267 id : brand-config
@@ -212,11 +277,14 @@ jobs:
212277 env :
213278 INPUTS_BRAND_CONFIG : ${{ inputs.brand-config }}
214279
215- # Build and test the application
280+ # Build and deploy the application
216281 build-and-deploy :
217282 name : 🚀 Build Application and Deploy to AWS
218283 runs-on : ubuntu-latest
219284 needs : [prepare]
285+ permissions :
286+ id-token : write
287+ contents : read
220288 environment :
221289 name : ${{ inputs.environment }}
222290 url : ${{ needs.prepare.outputs.deployment-url }}
@@ -301,9 +369,17 @@ jobs:
301369 - name : Configure AWS credentials
302370 uses : aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
303371 with :
304- aws-access-key-id : ${{ secrets.aws-access-key-id }}
305- aws-secret-access-key : ${{ secrets.aws-secret-access-key }}
306- aws-region : ${{ inputs.aws-region }}
372+ aws-access-key-id : ${{ vars.AWS_ACCESS_KEY_ID }}
373+ aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
374+ aws-region : ${{ vars.AWS_REGION || inputs.aws-region }}
375+
376+ - name : Configure AWS credentials (OIDC)
377+ if : needs.prepare.outputs.auth-mode == 'oidc'
378+ uses : aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
379+ with :
380+ role-to-assume : ${{ vars.AWS_ROLE_ARN }}
381+ role-session-name : ${{ needs.prepare.outputs.role-session-name }}
382+ aws-region : ${{ vars.AWS_REGION || inputs.aws-region }}
307383
308384 - name : Configure S3 deployment paths
309385 id : s3-config
@@ -319,7 +395,7 @@ jobs:
319395 env :
320396 NEEDS_PREPARE_OUTPUTS_S3_PREFIX : ${{ needs.prepare.outputs.s3-prefix }}
321397 MATRIX_BRAND : ${{ matrix.brand }}
322- INPUTS_S3_BUCKET : ${{ inputs.s3-bucket }}
398+ INPUTS_S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
323399
324400 - name : Deploy static assets to S3
325401 run : |
@@ -336,7 +412,7 @@ jobs:
336412 ${INPUTS_EXTRA_SYNC_ARGS}
337413 env :
338414 INPUTS_BUILD_DIRECTORY : ${{ inputs.build-directory }}
339- INPUTS_S3_BUCKET : ${{ inputs.s3-bucket }}
415+ INPUTS_S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
340416 STEPS_S3_CONFIG_OUTPUTS_S3_PATH : ${{ steps.s3-config.outputs.s3-path }}
341417 NEEDS_PREPARE_OUTPUTS_CACHE_CONTROL_STATIC : ${{ needs.prepare.outputs.cache-control-static }}
342418 INPUTS_EXTRA_SYNC_ARGS : ${{ inputs.extra-sync-args }}
@@ -356,7 +432,7 @@ jobs:
356432 ${INPUTS_EXTRA_SYNC_ARGS}
357433 env :
358434 INPUTS_BUILD_DIRECTORY : ${{ inputs.build-directory }}
359- INPUTS_S3_BUCKET : ${{ inputs.s3-bucket }}
435+ INPUTS_S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
360436 STEPS_S3_CONFIG_OUTPUTS_S3_PATH : ${{ steps.s3-config.outputs.s3-path }}
361437 NEEDS_PREPARE_OUTPUTS_CACHE_CONTROL_HTML : ${{ needs.prepare.outputs.cache-control-html }}
362438 INPUTS_EXTRA_SYNC_ARGS : ${{ inputs.extra-sync-args }}
@@ -384,7 +460,7 @@ jobs:
384460 echo "Invalidating paths: $PATHS"
385461
386462 INVALIDATION_ID=$(aws cloudfront create-invalidation \
387- --distribution-id "${INPUTS_CLOUDFRONT_DISTRIBUTION_ID }" \
463+ --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID }" \
388464 --paths $PATHS \
389465 --query 'Invalidation.Id' \
390466 --output text)
@@ -394,16 +470,15 @@ jobs:
394470 if [ "${{ inputs.debug }}" = "true" ]; then
395471 echo "🔍 Waiting for invalidation to complete..."
396472 aws cloudfront wait invalidation-completed \
397- --distribution-id "${INPUTS_CLOUDFRONT_DISTRIBUTION_ID }" \
473+ --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID }" \
398474 --id "$INVALIDATION_ID"
399475 echo "✅ CloudFront invalidation completed"
400476 fi
401477 env :
402478 NEEDS_PREPARE_OUTPUTS_INVALIDATION_PATHS : ${{ needs.prepare.outputs.invalidation-paths }}
403479 MATRIX_BRAND : ${{ matrix.brand }}
404480 STEPS_S3_CONFIG_OUTPUTS_S3_PATH : ${{ steps.s3-config.outputs.s3-path }}
405- INPUTS_CLOUDFRONT_DISTRIBUTION_ID : ${{ inputs.cloudfront-distribution-id }}
406-
481+ CLOUDFRONT_DISTRIBUTION_ID : ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} || ${{ inputs.cloudfront-distribution-id }}
407482 - name : Generate deployment summary
408483 run : |
409484 echo "## 🚀 Deployment Summary" >> $GITHUB_STEP_SUMMARY
@@ -437,7 +512,7 @@ jobs:
437512 env :
438513 INPUTS_ENVIRONMENT : ${{ inputs.environment }}
439514 MATRIX_BRAND : ${{ matrix.brand }}
440- INPUTS_S3_BUCKET : ${{ inputs.s3-bucket }}
515+ INPUTS_S3_BUCKET : ${{ vars.S3_BUCKET }} || ${{ inputs.s3-bucket }}
441516 STEPS_S3_CONFIG_OUTPUTS_S3_PATH : ${{ steps.s3-config.outputs.s3-path }}
442517 INPUTS_CACHE_STRATEGY : ${{ inputs.cache-strategy }}
443518 NEEDS_PREPARE_OUTPUTS_DEPLOYMENT_URL : ${{ needs.prepare.outputs.deployment-url }}
0 commit comments