Skip to content

Commit 763a166

Browse files
committed
Create jobs to separate AWS environments from build environments
This allows more granular control over which environments are used for which steps, and avoids requiring a single environment to define how to build, sign, and publish. Initially this workflow will still fallback to the existing monolith environments and the behaviour should be unchanged. Change-type: minor Signed-off-by: Kyle Harding <[email protected]>
1 parent a5d24c7 commit 763a166

File tree

1 file changed

+120
-23
lines changed

1 file changed

+120
-23
lines changed

.github/workflows/yocto-build-deploy.yml

Lines changed: 120 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,20 @@ on:
7373
required: true
7474
type: string
7575
deploy-environment:
76-
description: The GitHub environment to deploy to - includes the balena Cloud environment and related vars
76+
description: The balena environment to use for hostApp deployment - includes the related vars and secrets
7777
required: false
7878
type: string
7979
default: balena-cloud.com
80+
source-mirror-environment:
81+
description: The AWS environment to use for the S3 source mirror - includes related vars and OIDC role(s)
82+
required: false
83+
type: string
84+
default: ''
85+
aws-deploy-environment:
86+
description: The AWS environment to use for the S3 and AMI deployment - includes related vars and OIDC role(s)
87+
required: false
88+
type: string
89+
default: ''
8090
# This input exists because we want the option to not auto-finalise for some device types, even if they have tests and those tests pass - for example some custom device types, the customer doesn't want new releases published until they green light it
8191
finalize-on-push-if-tests-passed:
8292
description: Whether to finalize a hostApp container image to a balena environment, if tests pass.
@@ -177,10 +187,99 @@ env:
177187
permissions: {}
178188

179189
jobs:
190+
# This job is used to centralize AWS configuration for S3 source mirror.
191+
# It is used to separate the AWS configuration from the build environment.
192+
source-mirror-config:
193+
name: Configure source mirror
194+
runs-on: ubuntu-24.04
195+
196+
# This environment should contain the following variables:
197+
# - AWS_IAM_ROLE: AWS IAM role to assume
198+
# - SOURCE_MIRROR_S3_SSE_ALGORITHM: AWS S3 server-side encryption algorithm
199+
# - SOURCE_MIRROR_S3_URL: AWS S3 URL of the source mirror
200+
# - SOURCE_MIRROR_URL: HTTPS URL of the source mirror
201+
# - SOURCE_MIRROR_REGION: AWS region of the source mirror
202+
environment: ${{ inputs.source-mirror-environment || inputs.deploy-environment }}
203+
204+
outputs:
205+
# Include a number of similar variable keys to allow for flexibility in the environment and backwards compatibility
206+
aws-iam-role: ${{ vars.AWS_IAM_ROLE }}
207+
aws-region: ${{ vars.SOURCE_MIRROR_REGION || vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
208+
s3-url: ${{ vars.SOURCE_MIRROR_S3_URL || vars.AWS_S3_URL || vars.S3_URL || 's3://yocto-72c1c258-81bb-11ef-b722-0efcede062c9/shared-downloads' }}
209+
https-url: ${{ vars.SOURCE_MIRROR_URL || vars.AWS_S3_HTTPS_URL || vars.S3_HTTPS_URL || 'https://yocto-72c1c258-81bb-11ef-b722-0efcede062c9.s3.us-east-1.amazonaws.com/shared-downloads/' }}
210+
aws-s3-sse-algorithm: ${{ vars.SOURCE_MIRROR_S3_SSE_ALGORITHM || vars.AWS_S3_SSE_ALGORITHM || vars.S3_SSE_ALGORITHM || vars.SSE_ALGORITHM || vars.SSE || 'AES256' }}
211+
212+
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
213+
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
214+
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings
215+
permissions:
216+
id-token: write # This is required for requesting the JWT #https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#requesting-the-access-token
217+
218+
steps:
219+
# We don't use this session, it's just to check if the credentials are valid
220+
# https://github.com/aws-actions/configure-aws-credentials
221+
- name: Configure AWS credentials
222+
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
223+
continue-on-error: true # Don't fail at this point as there is still value in running builds and tests
224+
with:
225+
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
226+
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
227+
aws-region: ${{ vars.SOURCE_MIRROR_REGION || vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
228+
# https://github.com/orgs/community/discussions/26636#discussioncomment-3252664
229+
mask-aws-account-id: false
230+
231+
# This job is used to centralize AWS configuration for S3 and AMI deployment.
232+
# It is used to separate the AWS configuration from the build environment.
233+
aws-deploy-config:
234+
name: Configure AWS
235+
runs-on: ubuntu-24.04
236+
237+
# This environment should contain the following variables:
238+
# - AWS_SECURITY_GROUP: AWS security group to use for AMI testing
239+
# - AWS_SUBNET: AWS subnet for AMI testing
240+
# - AWS_KMS_KEY_ID: AWS KMS key ID make AMIs public
241+
# - AWS_REGION: AWS region for S3 image deployment
242+
# - AWS_IAM_ROLE: AWS IAM role to assume for S3 image deployment, AMI deployment
243+
# - AWS_S3_BUCKET: AWS S3 bucket for image deployment, and AMI deployment
244+
# - AWS_S3_SSE_ALGORITHM: AWS S3 server-side encryption algorithm
245+
environment: ${{ inputs.aws-deploy-environment || inputs.deploy-environment }}
246+
247+
outputs:
248+
# Include a number of similar variable keys to allow for flexibility in the environment and backwards compatibility
249+
aws-iam-role: ${{ vars.AWS_IAM_ROLE }}
250+
aws-region: ${{ vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
251+
aws-security-group: ${{ vars.AWS_SECURITY_GROUP }}
252+
aws-subnet: ${{ vars.AWS_SUBNET }}
253+
aws-kms-key-id: ${{ vars.AWS_KMS_KEY_ID }}
254+
aws-s3-bucket: ${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}
255+
aws-s3-sse-algorithm: ${{ vars.AWS_S3_SSE_ALGORITHM || 'AES256' }}
256+
257+
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
258+
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
259+
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings
260+
permissions:
261+
id-token: write # This is required for requesting the JWT #https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#requesting-the-access-token
262+
263+
steps:
264+
# We don't use this session, it's just to check if the credentials are valid
265+
# https://github.com/aws-actions/configure-aws-credentials
266+
- name: Configure AWS credentials
267+
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
268+
continue-on-error: true # Don't fail at this point as there is still value in running builds and tests
269+
with:
270+
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
271+
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
272+
aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
273+
# https://github.com/orgs/community/discussions/26636#discussioncomment-3252664
274+
mask-aws-account-id: false
275+
180276
build:
181277
name: Build
182278
runs-on: ${{ fromJSON(inputs.build-runs-on) }}
183279
environment: ${{ inputs.deploy-environment }}
280+
needs:
281+
- aws-deploy-config
282+
- source-mirror-config
184283

185284
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
186285
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
@@ -200,9 +299,6 @@ jobs:
200299
# https://docs.yoctoproject.org/3.1.21/overview-manual/overview-manual-concepts.html#user-configuration
201300
# Create an autobuilder configuration file that is loaded before local.conf
202301
AUTO_CONF_FILE: "${{ github.workspace }}/build/conf/auto.conf"
203-
SOURCE_MIRROR_REGION: ${{ vars.SOURCE_MIRROR_REGION || vars.AWS_REGION || 'us-east-1' }}
204-
SOURCE_MIRROR_S3_URL: ${{ vars.SOURCE_MIRROR_S3_URL || 's3://yocto-72c1c258-81bb-11ef-b722-0efcede062c9/shared-downloads' }}
205-
SOURCE_MIRROR_URL: ${{ vars.SOURCE_MIRROR_URL || 'https://yocto-72c1c258-81bb-11ef-b722-0efcede062c9.s3.us-east-1.amazonaws.com/shared-downloads/' }}
206302

207303
outputs:
208304
os_version: ${{ steps.balena-lib.outputs.os_version }}
@@ -515,9 +611,9 @@ jobs:
515611
# The own-mirrors class makes it easier to set up your own PREMIRRORS from which to first fetch source before
516612
# attempting to fetch it from the upstream specified in SRC_URI within each recipe.
517613
- name: Add S3 shared-downloads to MIRRORS
518-
if: env.SOURCE_MIRROR_URL
614+
if: needs.source-mirror-config.outputs.s3-url
519615
env:
520-
SOURCE_MIRROR_URL: ${{ env.SOURCE_MIRROR_URL }}
616+
SOURCE_MIRROR_URL: ${{ needs.source-mirror-config.outputs.s3-url }}
521617
run: |
522618
mkdir -p "$(dirname "${AUTO_CONF_FILE}")"
523619
cat <<EOF >> "${AUTO_CONF_FILE}"
@@ -638,9 +734,9 @@ jobs:
638734
- name: Configure AWS credentials
639735
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
640736
with:
641-
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
737+
role-to-assume: ${{ needs.source-mirror-config.outputs.aws-iam-role }}
642738
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
643-
aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
739+
aws-region: ${{ needs.source-mirror-config.outputs.aws-region }}
644740
# https://github.com/orgs/community/discussions/26636#discussioncomment-3252664
645741
mask-aws-account-id: false
646742

@@ -650,14 +746,14 @@ jobs:
650746
- name: Sync shared downloads to S3
651747
# Do not publish shared downloads for pull_request_target events to prevent cache poisoning
652748
# Do not publish shared downloads for private device-types as the mirror is public-read
653-
if: github.event_name != 'pull_request_target' && steps.balena-lib.outputs.is_private == 'false' && env.SOURCE_MIRROR_S3_URL
749+
if: github.event_name != 'pull_request_target' && steps.balena-lib.outputs.is_private == 'false' && needs.source-mirror-config.outputs.s3-url
654750
# Ignore errors for now, as we may have upload conflicts with other jobs
655751
continue-on-error: true
656752
env:
657753
SHARED_DOWNLOADS_DIR: ${{ github.workspace }}/shared/shared-downloads
658-
S3_SSE: AES256
659-
S3_URL: ${{ env.SOURCE_MIRROR_S3_URL }}
660-
S3_REGION: ${{ env.SOURCE_MIRROR_REGION }}
754+
S3_SSE: ${{ needs.source-mirror-config.outputs.aws-s3-sse-algorithm }}
755+
S3_URL: ${{ needs.source-mirror-config.outputs.s3-url }}
756+
S3_REGION: ${{ needs.source-mirror-config.outputs.aws-region }}
661757
# Create a symlink to the from the relative container path to the workspace in order to resolve symlinks
662758
# created in the build container runtime.
663759
run: |
@@ -805,9 +901,9 @@ jobs:
805901
if: steps.should-deploy.outputs.deploy && steps.balena-lib.outputs.deploy_artifact != 'docker-image'
806902
env:
807903
S3_ACL: ${{ steps.s3-acl-private.outputs.string || 'public-read' }}
808-
S3_SSE: AES256
809-
S3_URL: "s3://${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}/${{ steps.s3-esr-images-dir.outputs.string || 'images' }}"
810-
S3_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
904+
S3_SSE: ${{ needs.aws-deploy-config.outputs.aws-s3-sse-algorithm }}
905+
S3_URL: "s3://${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}/${{ steps.s3-esr-images-dir.outputs.string || 'images' }}"
906+
S3_REGION: ${{ needs.aws-deploy-config.outputs.aws-region }}
811907
SLUG: ${{ steps.balena-lib.outputs.device_slug }}
812908
VERSION: ${{ steps.balena-lib.outputs.os_version }}
813909
SOURCE_DIR: ${{ runner.temp }}/deploy
@@ -1151,10 +1247,11 @@ jobs:
11511247
id: ami-ebs-snapshot
11521248
env:
11531249
IMAGE: ${{ env.DEPLOY_PATH }}/image/balena.img
1154-
AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
1155-
S3_BUCKET: "${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}"
1250+
AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
1251+
S3_BUCKET: "${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}"
11561252
IMPORT_SNAPSHOT_TIMEOUT_MINS: 30
1157-
AWS_KMS_KEY_ID: ${{ vars.AWS_KMS_KEY_ID }}
1253+
AWS_KMS_KEY_ID: ${{ needs.aws-deploy-config.outputs.aws-kms-key-id }}
1254+
AWS_S3_SSE_ALGORITHM: ${{ needs.aws-deploy-config.outputs.aws-s3-sse-algorithm }}
11581255
run: |
11591256
# https://github.com/koalaman/shellcheck/wiki/SC2155#correct-code-1
11601257
# Randomize to lower the chance of parallel builds colliding.
@@ -1164,7 +1261,7 @@ jobs:
11641261
echo "* Pushing ${IMAGE} to s3://${S3_BUCKET}"
11651262
s3_url="s3://${S3_BUCKET}/preloaded-images/${s3_key}"
11661263
echo "s3_url=${s3_url}" >>"${GITHUB_OUTPUT}"
1167-
aws s3 cp --no-progress --sse AES256 "${IMAGE}" "${s3_url}"
1264+
aws s3 cp --no-progress --sse "${AWS_S3_SSE_ALGORITHM}" "${IMAGE}" "${s3_url}"
11681265
11691266
import_task_id=$(aws ec2 import-snapshot \
11701267
--description "snapshot-${AMI_NAME}" \
@@ -1203,9 +1300,9 @@ jobs:
12031300
id: ami-create
12041301
env:
12051302
IMAGE: ${{ env.DEPLOY_PATH }}/image/balena.img
1206-
AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
1207-
S3_BUCKET: "${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}"
1208-
AWS_KMS_KEY_ID: ${{ vars.AWS_KMS_KEY_ID }}
1303+
AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
1304+
S3_BUCKET: "${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}"
1305+
AWS_KMS_KEY_ID: ${{ needs.aws-deploy-config.outputs.aws-kms-key-id }}
12091306
AMI_ARCHITECTURE: "${{ steps.ami-arch.outputs.string }}"
12101307
AMI_SNAPSHOT_ID: "${{ steps.ami-ebs-snapshot.outputs.snapshot_id }}"
12111308
AMI_ROOT_DEVICE_NAME: /dev/sda1
@@ -1396,7 +1493,7 @@ jobs:
13961493
# AWS_AMI_PUBLIC_QUOTA: 5
13971494
# AMI_ARCHITECTURE: "${{ steps.ami-arch.outputs.string }}"
13981495
# AMI_IMAGE_ID: "${{ steps.ami-test.outputs.ami_image_id }}"
1399-
# AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
1496+
# AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
14001497
# run: |
14011498
# # We have x86_64 and aarch64, and want one slot free for customers requests
14021499
# AWS_AMI_PUBLIC_ARCH_QUOTA=$(((AWS_AMI_PUBLIC_QUOTA - 1)/2))

0 commit comments

Comments
 (0)