Skip to content

Commit

Permalink
Create jobs to separate AWS environments from build environments
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
klutchell committed Jan 2, 2025
1 parent a5d24c7 commit 763a166
Showing 1 changed file with 120 additions and 23 deletions.
143 changes: 120 additions & 23 deletions .github/workflows/yocto-build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,20 @@ on:
required: true
type: string
deploy-environment:
description: The GitHub environment to deploy to - includes the balena Cloud environment and related vars
description: The balena environment to use for hostApp deployment - includes the related vars and secrets
required: false
type: string
default: balena-cloud.com
source-mirror-environment:
description: The AWS environment to use for the S3 source mirror - includes related vars and OIDC role(s)
required: false
type: string
default: ''
aws-deploy-environment:
description: The AWS environment to use for the S3 and AMI deployment - includes related vars and OIDC role(s)
required: false
type: string
default: ''
# 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
finalize-on-push-if-tests-passed:
description: Whether to finalize a hostApp container image to a balena environment, if tests pass.
Expand Down Expand Up @@ -177,10 +187,99 @@ env:
permissions: {}

jobs:
# This job is used to centralize AWS configuration for S3 source mirror.
# It is used to separate the AWS configuration from the build environment.
source-mirror-config:
name: Configure source mirror
runs-on: ubuntu-24.04

# This environment should contain the following variables:
# - AWS_IAM_ROLE: AWS IAM role to assume
# - SOURCE_MIRROR_S3_SSE_ALGORITHM: AWS S3 server-side encryption algorithm
# - SOURCE_MIRROR_S3_URL: AWS S3 URL of the source mirror
# - SOURCE_MIRROR_URL: HTTPS URL of the source mirror
# - SOURCE_MIRROR_REGION: AWS region of the source mirror
environment: ${{ inputs.source-mirror-environment || inputs.deploy-environment }}

outputs:
# Include a number of similar variable keys to allow for flexibility in the environment and backwards compatibility
aws-iam-role: ${{ vars.AWS_IAM_ROLE }}
aws-region: ${{ vars.SOURCE_MIRROR_REGION || vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
s3-url: ${{ vars.SOURCE_MIRROR_S3_URL || vars.AWS_S3_URL || vars.S3_URL || 's3://yocto-72c1c258-81bb-11ef-b722-0efcede062c9/shared-downloads' }}
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/' }}
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' }}

# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings
permissions:
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

steps:
# We don't use this session, it's just to check if the credentials are valid
# https://github.com/aws-actions/configure-aws-credentials
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
continue-on-error: true # Don't fail at this point as there is still value in running builds and tests
with:
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
aws-region: ${{ vars.SOURCE_MIRROR_REGION || vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
# https://github.com/orgs/community/discussions/26636#discussioncomment-3252664
mask-aws-account-id: false

# This job is used to centralize AWS configuration for S3 and AMI deployment.
# It is used to separate the AWS configuration from the build environment.
aws-deploy-config:
name: Configure AWS
runs-on: ubuntu-24.04

# This environment should contain the following variables:
# - AWS_SECURITY_GROUP: AWS security group to use for AMI testing
# - AWS_SUBNET: AWS subnet for AMI testing
# - AWS_KMS_KEY_ID: AWS KMS key ID make AMIs public
# - AWS_REGION: AWS region for S3 image deployment
# - AWS_IAM_ROLE: AWS IAM role to assume for S3 image deployment, AMI deployment
# - AWS_S3_BUCKET: AWS S3 bucket for image deployment, and AMI deployment
# - AWS_S3_SSE_ALGORITHM: AWS S3 server-side encryption algorithm
environment: ${{ inputs.aws-deploy-environment || inputs.deploy-environment }}

outputs:
# Include a number of similar variable keys to allow for flexibility in the environment and backwards compatibility
aws-iam-role: ${{ vars.AWS_IAM_ROLE }}
aws-region: ${{ vars.AWS_REGION || vars.AWS_S3_REGION || vars.S3_REGION || 'us-east-1' }}
aws-security-group: ${{ vars.AWS_SECURITY_GROUP }}
aws-subnet: ${{ vars.AWS_SUBNET }}
aws-kms-key-id: ${{ vars.AWS_KMS_KEY_ID }}
aws-s3-bucket: ${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}
aws-s3-sse-algorithm: ${{ vars.AWS_S3_SSE_ALGORITHM || 'AES256' }}

# https://docs.github.com/en/actions/security-guides/automatic-token-authentication
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings
permissions:
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

steps:
# We don't use this session, it's just to check if the credentials are valid
# https://github.com/aws-actions/configure-aws-credentials
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
continue-on-error: true # Don't fail at this point as there is still value in running builds and tests
with:
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
# https://github.com/orgs/community/discussions/26636#discussioncomment-3252664
mask-aws-account-id: false

build:
name: Build
runs-on: ${{ fromJSON(inputs.build-runs-on) }}
environment: ${{ inputs.deploy-environment }}
needs:
- aws-deploy-config
- source-mirror-config

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

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

Expand All @@ -650,14 +746,14 @@ jobs:
- name: Sync shared downloads to S3
# Do not publish shared downloads for pull_request_target events to prevent cache poisoning
# Do not publish shared downloads for private device-types as the mirror is public-read
if: github.event_name != 'pull_request_target' && steps.balena-lib.outputs.is_private == 'false' && env.SOURCE_MIRROR_S3_URL
if: github.event_name != 'pull_request_target' && steps.balena-lib.outputs.is_private == 'false' && needs.source-mirror-config.outputs.s3-url
# Ignore errors for now, as we may have upload conflicts with other jobs
continue-on-error: true
env:
SHARED_DOWNLOADS_DIR: ${{ github.workspace }}/shared/shared-downloads
S3_SSE: AES256
S3_URL: ${{ env.SOURCE_MIRROR_S3_URL }}
S3_REGION: ${{ env.SOURCE_MIRROR_REGION }}
S3_SSE: ${{ needs.source-mirror-config.outputs.aws-s3-sse-algorithm }}
S3_URL: ${{ needs.source-mirror-config.outputs.s3-url }}
S3_REGION: ${{ needs.source-mirror-config.outputs.aws-region }}
# Create a symlink to the from the relative container path to the workspace in order to resolve symlinks
# created in the build container runtime.
run: |
Expand Down Expand Up @@ -805,9 +901,9 @@ jobs:
if: steps.should-deploy.outputs.deploy && steps.balena-lib.outputs.deploy_artifact != 'docker-image'
env:
S3_ACL: ${{ steps.s3-acl-private.outputs.string || 'public-read' }}
S3_SSE: AES256
S3_URL: "s3://${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}/${{ steps.s3-esr-images-dir.outputs.string || 'images' }}"
S3_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
S3_SSE: ${{ needs.aws-deploy-config.outputs.aws-s3-sse-algorithm }}
S3_URL: "s3://${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}/${{ steps.s3-esr-images-dir.outputs.string || 'images' }}"
S3_REGION: ${{ needs.aws-deploy-config.outputs.aws-region }}
SLUG: ${{ steps.balena-lib.outputs.device_slug }}
VERSION: ${{ steps.balena-lib.outputs.os_version }}
SOURCE_DIR: ${{ runner.temp }}/deploy
Expand Down Expand Up @@ -1151,10 +1247,11 @@ jobs:
id: ami-ebs-snapshot
env:
IMAGE: ${{ env.DEPLOY_PATH }}/image/balena.img
AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
S3_BUCKET: "${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}"
AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
S3_BUCKET: "${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}"
IMPORT_SNAPSHOT_TIMEOUT_MINS: 30
AWS_KMS_KEY_ID: ${{ vars.AWS_KMS_KEY_ID }}
AWS_KMS_KEY_ID: ${{ needs.aws-deploy-config.outputs.aws-kms-key-id }}
AWS_S3_SSE_ALGORITHM: ${{ needs.aws-deploy-config.outputs.aws-s3-sse-algorithm }}
run: |
# https://github.com/koalaman/shellcheck/wiki/SC2155#correct-code-1
# Randomize to lower the chance of parallel builds colliding.
Expand All @@ -1164,7 +1261,7 @@ jobs:
echo "* Pushing ${IMAGE} to s3://${S3_BUCKET}"
s3_url="s3://${S3_BUCKET}/preloaded-images/${s3_key}"
echo "s3_url=${s3_url}" >>"${GITHUB_OUTPUT}"
aws s3 cp --no-progress --sse AES256 "${IMAGE}" "${s3_url}"
aws s3 cp --no-progress --sse "${AWS_S3_SSE_ALGORITHM}" "${IMAGE}" "${s3_url}"
import_task_id=$(aws ec2 import-snapshot \
--description "snapshot-${AMI_NAME}" \
Expand Down Expand Up @@ -1203,9 +1300,9 @@ jobs:
id: ami-create
env:
IMAGE: ${{ env.DEPLOY_PATH }}/image/balena.img
AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
S3_BUCKET: "${{ vars.AWS_S3_BUCKET || vars.S3_BUCKET }}"
AWS_KMS_KEY_ID: ${{ vars.AWS_KMS_KEY_ID }}
AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
S3_BUCKET: "${{ needs.aws-deploy-config.outputs.aws-s3-bucket }}"
AWS_KMS_KEY_ID: ${{ needs.aws-deploy-config.outputs.aws-kms-key-id }}
AMI_ARCHITECTURE: "${{ steps.ami-arch.outputs.string }}"
AMI_SNAPSHOT_ID: "${{ steps.ami-ebs-snapshot.outputs.snapshot_id }}"
AMI_ROOT_DEVICE_NAME: /dev/sda1
Expand Down Expand Up @@ -1396,7 +1493,7 @@ jobs:
# AWS_AMI_PUBLIC_QUOTA: 5
# AMI_ARCHITECTURE: "${{ steps.ami-arch.outputs.string }}"
# AMI_IMAGE_ID: "${{ steps.ami-test.outputs.ami_image_id }}"
# AWS_DEFAULT_REGION: "${{ vars.AWS_REGION || 'us-east-1' }}"
# AWS_DEFAULT_REGION: "${{ needs.aws-deploy-config.outputs.aws-region }}"
# run: |
# # We have x86_64 and aarch64, and want one slot free for customers requests
# AWS_AMI_PUBLIC_ARCH_QUOTA=$(((AWS_AMI_PUBLIC_QUOTA - 1)/2))
Expand Down

0 comments on commit 763a166

Please sign in to comment.