Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -768,5 +768,8 @@ jobs:
role-session-name: GHA@linux-images=RegisterAMI-${{ matrix.suite }}-${{ matrix.arch }}

- name: Register AMI
env:
AWS_AMI_KMS_KEY_ID: ${{ vars.AWS_AMI_KMS_KEY_ID }}
AWS_AMI_SHARE_ORG_ARN: ${{ vars.AWS_AMI_SHARE_ORG_ARN }}
run: scripts/register-ami-for-release.sh "${{ matrix.arch }}" "${{ matrix.suite }}" "${{ env.VERSION }}"
timeout-minutes: 60
88 changes: 86 additions & 2 deletions scripts/register-ami-for-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -euo pipefail
# Designed for use in CI (GitHub Actions) after a tagged release.
#
# The cloud image (no LUKS) is the correct variant for AWS — EBS provides
# encryption at rest.
# encryption at rest via the snapshot import below.
#
# Usage: ./register-ami-for-release.sh <arch> <suite> <version> [region] [s3-bucket]
#
Expand All @@ -16,6 +16,19 @@ set -euo pipefail
# region AWS region (default: ap-southeast-2)
# s3-bucket S3 bucket for import staging (default: bes-ops-tools)
#
# Required environment:
# AWS_AMI_KMS_KEY_ID ARN (or alias) of a customer-managed KMS key whose
# key policy grants the BES AWS Organization
# permission to launch from snapshots it encrypts.
# AWS-managed CMKs (the default aws/ebs key) cannot
# be shared cross-account, so without a customer-
# managed key the resulting AMI cannot be shared
# org-wide.
# AWS_AMI_SHARE_ORG_ARN ARN of the AWS Organization to grant launch
# permission on the AMI and create-volume permission
# on its backing snapshot. Format:
# arn:aws:organizations::<mgmt-account>:organization/o-XXXXXXXXXX
#
# The raw.zst image is expected under output/<arch>/cloud/*.img.zst

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand All @@ -32,6 +45,27 @@ if [ -z "$ARCH" ] || [ -z "$SUITE" ] || [ -z "$VERSION" ]; then
exit 1
fi

KMS_KEY_ID="${AWS_AMI_KMS_KEY_ID:-}"
if [ -z "$KMS_KEY_ID" ]; then
echo "ERROR: AWS_AMI_KMS_KEY_ID env var is required."
echo " It must be the ARN (or alias) of a customer-managed KMS key"
echo " whose policy grants the BES AWS Organization permission to"
echo " launch from snapshots it encrypts. Without one the snapshot"
echo " defaults to the aws/ebs managed key, which cannot be shared"
echo " cross-account."
exit 1
fi

SHARE_ORG_ARN="${AWS_AMI_SHARE_ORG_ARN:-}"
if [ -z "$SHARE_ORG_ARN" ]; then
echo "ERROR: AWS_AMI_SHARE_ORG_ARN env var is required."
echo " It must be the ARN of the AWS Organization that should be"
echo " granted launch permission on the registered AMI (and its"
echo " backing snapshot). Format:"
echo " arn:aws:organizations::<management-account-id>:organization/o-XXXXXXXXXX"
exit 1
fi

case "$ARCH" in
amd64|arm64) ;;
*) echo "ERROR: arch must be amd64 or arm64, got: $ARCH"; exit 1 ;;
Expand Down Expand Up @@ -102,9 +136,14 @@ echo ""
# --- Start snapshot import ---

echo "Starting snapshot import ..."
# --encrypted + --kms-key-id force the import to use our customer-managed
# CMK instead of the account's default (aws/ebs), so the resulting snapshot
# and AMI can be shared across the BES AWS Organization.
TASK_ID=$(aws ec2 import-snapshot \
--region "$REGION" \
--description "$AMI_NAME" \
--encrypted \
--kms-key-id "$KMS_KEY_ID" \
--disk-container "Description=${AMI_NAME},Format=raw,UserBucket={S3Bucket=${BUCKET},S3Key=${S3_KEY}}" \
--query 'ImportTaskId' \
--output text)
Expand Down Expand Up @@ -162,6 +201,22 @@ if [ -z "$SNAPSHOT_ID" ] || [ "$SNAPSHOT_ID" = "None" ]; then
fi

echo "Snapshot ID: $SNAPSHOT_ID"

# Fail fast if the import landed under a different key (e.g. account-level
# default-encryption pinned to aws/ebs would override an unrecognised alias).
SNAPSHOT_KEY=$(aws ec2 describe-snapshots \
--region "$REGION" \
--snapshot-ids "$SNAPSHOT_ID" \
--query 'Snapshots[0].KmsKeyId' \
--output text)
case "$SNAPSHOT_KEY" in
*":alias/aws/ebs"|"")
echo "ERROR: snapshot $SNAPSHOT_ID is encrypted with $SNAPSHOT_KEY,"
echo " not the customer-managed key requested."
exit 1
;;
esac
echo "Snapshot key: $SNAPSHOT_KEY"
echo ""

# --- Register AMI ---
Expand Down Expand Up @@ -209,5 +264,34 @@ aws ec2 create-tags \
echo "Tagged AMI and snapshot"
echo ""

# --- Grant org-wide launch permission ---

# Grant the org launch permission on the AMI and create-volume permission
# on the snapshot, so other accounts in the org can both run instances from
# the AMI and (if they want to) create volumes directly from the snapshot.
# The customer-managed KMS key set earlier already permits org-wide use.
echo "Granting org launch permission to $SHARE_ORG_ARN ..."
aws ec2 modify-image-attribute \
--region "$REGION" \
--image-id "$AMI_ID" \
--launch-permission "Add=[{OrganizationArn=${SHARE_ORG_ARN}}]"
aws ec2 modify-snapshot-attribute \
--region "$REGION" \
--snapshot-id "$SNAPSHOT_ID" \
--create-volume-permission "Add=[{OrganizationArn=${SHARE_ORG_ARN}}]"

LAUNCH_GRANT=$(aws ec2 describe-image-attribute \
--region "$REGION" \
--image-id "$AMI_ID" \
--attribute launchPermission \
--query "LaunchPermissions[?OrganizationArn=='${SHARE_ORG_ARN}'] | [0].OrganizationArn" \
--output text)
if [ "$LAUNCH_GRANT" != "$SHARE_ORG_ARN" ]; then
echo "ERROR: launch permission for $SHARE_ORG_ARN did not stick on $AMI_ID"
exit 1
fi
echo "Granted and verified"
echo ""

echo "Done."
echo "AMI $AMI_ID ($AMI_NAME) is registered and ready."
echo "AMI $AMI_ID ($AMI_NAME) is registered and shared with $SHARE_ORG_ARN."
Loading