Skip to content
40 changes: 40 additions & 0 deletions .github/actions/attest_file/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Attest files
description: Generates and verifies SLSA build provenance for one or more files.

inputs:
subject_paths:
description: Newline-separated paths to the files to attest.
required: true
signer_workflow:
description: Exact owner/repository/path of the workflow signing the attestation.
required: true

runs:
using: composite
steps:
- name: Attest build provenance
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-path: ${{ inputs.subject_paths }}

- name: Verify attestations
shell: bash
env:
GH_TOKEN: ${{ github.token }}
SUBJECT_PATHS: ${{ inputs.subject_paths }}
SIGNER_WORKFLOW: ${{ inputs.signer_workflow }}
run: |
set -euo pipefail

while IFS= read -r subject_path; do
[[ -z "$subject_path" ]] && continue

if [[ ! -f "$subject_path" ]]; then
echo "::error file=${subject_path}::Attestation subject does not exist"
exit 1
fi

gh attestation verify "$subject_path" \
--repo "$GITHUB_REPOSITORY" \
--signer-workflow "$SIGNER_WORKFLOW"
done <<< "$SUBJECT_PATHS"
47 changes: 38 additions & 9 deletions .github/actions/build_ami/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ outputs:
enclave_id:
description: the Enclave_ID of the EIF used to create the AMI
value: ${{ steps.extractAmiIdAndEnclaveId.outputs.ENCLAVE_ID }}
measurement_path:
description: Path to the generated AMI measurement metadata file
value: ${{ steps.measurementPath.outputs.path }}

runs:
using: "composite"
Expand Down Expand Up @@ -87,10 +90,6 @@ runs:
FILE=$(echo $ARTIFACTS | jq -r '.[0].name')
unzip -o -d ./scripts/aws/uid2-operator-ami/artifacts $FILE.zip
rm $FILE.zip
cd "./scripts/aws/uid2-operator-ami/artifacts/"
zip "uid2operatoreif.zip" "uid2operator.eif"
cd -
rm ./scripts/aws/uid2-operator-ami/artifacts/uid2operator.eif
ls ./scripts/aws/uid2-operator-ami/artifacts/ -al

- name: Configure UID2 AWS credentials
Expand Down Expand Up @@ -122,6 +121,34 @@ runs:
echo "VERSION_NUMBER=$VERSION_NUMBER" >> $GITHUB_OUTPUT
echo $VERSION_NUMBER

- name: Verify consumed EIF provenance
Comment thread
swibi-ttd marked this conversation as resolved.
if: ${{ !contains(steps.versionNumber.outputs.VERSION_NUMBER, 'SNAPSHOT') }}
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}
EIF_PATH: ${{ github.workspace }}/scripts/aws/uid2-operator-ami/artifacts/uid2operator.eif
EIF_REPO: ${{ inputs.eif_repo_owner }}/${{ inputs.eif_repo_name }}
run: |
set -euo pipefail
if [[ ! -f "$EIF_PATH" ]]; then
echo "::error file=${EIF_PATH}::Expected EIF subject is missing before AMI build"
exit 1
fi
# EIF may have been attested by the standalone Nitro workflow or by
# the same reusable Nitro workflow invoked by Publish All Operators.
gh attestation verify "$EIF_PATH" \
--repo "$EIF_REPO" \
--signer-workflow "${EIF_REPO}/.github/workflows/publish-aws-nitro-eif.yaml"

- name: Prepare EIF archive for Packer
shell: bash
run: |
set -euo pipefail
cd "./scripts/aws/uid2-operator-ami/artifacts/"
zip "uid2operatoreif.zip" "uid2operator.eif"
rm "uid2operator.eif"
ls -al

- name: Setup Packer
id: setup-packer
uses: hashicorp/setup-packer@3286471d6cc6756d056a0b199fea5e0becdbc189 # v3.3.0
Expand Down Expand Up @@ -189,8 +216,10 @@ runs:
cat euid_AMI_measurement.txt
ls -al

- name: Upload artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.identity_scope }}_AMI_measurement
path: ./scripts/aws/uid2-operator-ami/${{ inputs.identity_scope }}_AMI_measurement.txt
- name: Set measurement metadata path
id: measurementPath
shell: bash
env:
IDENTITY_SCOPE: ${{ inputs.identity_scope }}
run: |
echo "path=${GITHUB_WORKSPACE}/scripts/aws/uid2-operator-ami/${IDENTITY_SCOPE}_AMI_measurement.txt" >> "$GITHUB_OUTPUT"
58 changes: 55 additions & 3 deletions .github/actions/build_eks_docker_image/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ runs:
run: |
df -h

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Log in to the Docker container registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
Expand All @@ -126,6 +129,15 @@ runs:
tags: |
type=raw,value=${{ steps.versionNumber.outputs.VERSION_NUMBER }}.${{ github.run_number }}

- name: Set image repository reference
id: image-ref
shell: bash
env:
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-eks-${{ inputs.identity_scope }}
run: |
image="$(printf '%s' "$IMAGE" | tr '[:upper:]' '[:lower:]')"
echo "value=${image}" >> "$GITHUB_OUTPUT"

- name: Build and export to Docker
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
Expand All @@ -138,17 +150,57 @@ runs:
IMAGE_VERSION=${{ steps.versionNumber.outputs.VERSION_NUMBER }}
BUILD_TARGET=${{ env.ENCLAVE_PROTOCOL }}

- name: Push to Docker
- name: Push to Docker by digest
id: push-to-docker
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: ${{ inputs.artifacts_output_dir }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ steps.image-ref.outputs.value }},oci-mediatypes=false,push-by-digest=true,push=true
# Keep the private image as a plain single-platform manifest. Signed
# SLSA provenance is added separately by attest_image below.
provenance: false
build-args: |
JAR_VERSION=${{ steps.versionNumber.outputs.VERSION_NUMBER }}
IMAGE_VERSION=${{ steps.versionNumber.outputs.VERSION_NUMBER }}
BUILD_TARGET=${{ env.ENCLAVE_PROTOCOL }}

- name: Attest image
if: ${{ !contains(steps.versionNumber.outputs.VERSION_NUMBER, 'SNAPSHOT') }}
uses: IABTechLab/uid2-shared-actions/actions/attest_image@v3
with:
subject_name: ${{ steps.image-ref.outputs.value }}
subject_digest: ${{ steps.push-to-docker.outputs.digest }}

- name: Verify image attestation from registry
if: ${{ !contains(steps.versionNumber.outputs.VERSION_NUMBER, 'SNAPSHOT') }}
uses: ./.github/actions/verify_oci_attestation
with:
subject_name: ${{ steps.image-ref.outputs.value }}
subject_digest: ${{ steps.push-to-docker.outputs.digest }}
signer_workflow: ${{ github.repository }}/.github/workflows/publish-aws-eks-nitro-enclave-docker.yaml

- name: Promote digest to Docker tags
shell: bash
env:
DIGEST: ${{ steps.push-to-docker.outputs.digest }}
IMAGE: ${{ steps.image-ref.outputs.value }}
TAGS: ${{ steps.meta.outputs.tags }}
run: |
set -euo pipefail
while IFS= read -r tag; do
[[ -z "$tag" ]] && continue
docker buildx imagetools create --prefer-index=false -t "$tag" "${IMAGE}@${DIGEST}"
done <<< "$TAGS"

while IFS= read -r tag; do
[[ -z "$tag" ]] && continue
resolved="$(docker buildx imagetools inspect "$tag" --format '{{.Manifest.Digest}}')"
if [[ "$resolved" != "$DIGEST" ]]; then
echo "::error::Promoted tag $tag resolved to $resolved, expected $DIGEST"
exit 1
fi
done <<< "$TAGS"

- name: Check disk usage
shell: bash
Expand Down
36 changes: 36 additions & 0 deletions .github/actions/verify_oci_attestation/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Verify OCI attestation
description: |
Verifies that a registry-stored SLSA attestation bundle is retrievable for an
OCI image digest and was signed by the explicitly trusted workflow.

inputs:
subject_name:
description: Fully qualified image reference (registry/owner/repo[+suffix]).
required: true
subject_digest:
description: OCI manifest digest (sha256:...) emitted by docker/build-push-action.
required: true
signer_workflow:
description: Exact owner/repository/path of the workflow signing the attestation.
required: true

runs:
using: composite
steps:
- name: Verify attestation from registry
shell: bash
env:
GH_TOKEN: ${{ github.token }}
SUBJECT_NAME: ${{ inputs.subject_name }}
SUBJECT_DIGEST: ${{ inputs.subject_digest }}
SIGNER_WORKFLOW: ${{ inputs.signer_workflow }}
run: |
set -euo pipefail

image_ref="$(printf '%s' "$SUBJECT_NAME" | tr '[:upper:]' '[:lower:]')"

gh attestation verify \
"oci://${image_ref}@${SUBJECT_DIGEST}" \
--bundle-from-oci \
--repo "$GITHUB_REPOSITORY" \
--signer-workflow "$SIGNER_WORKFLOW"
34 changes: 34 additions & 0 deletions .github/workflows/build-uid2-ami.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ jobs:
name: UID2 Operator AMI
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
outputs:
version_number: ${{ steps.buildAMI.outputs.version_number }}
ami_id: ${{ steps.buildAMI.outputs.ami_id }}
Expand All @@ -55,6 +58,20 @@ jobs:
euid_aws_role: ${{ env.EUID_AWS_ROLE }}
euid_aws_region: ${{ env.EUID_AWS_REGION }}

- name: Attest UID2 AMI metadata
if: ${{ !contains(steps.buildAMI.outputs.version_number, 'SNAPSHOT') }}
uses: ./.github/actions/attest_file
with:
subject_paths: ${{ steps.buildAMI.outputs.measurement_path }}
signer_workflow: ${{ github.repository }}/.github/workflows/build-uid2-ami.yaml

- name: Upload UID2 AMI metadata
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: uid2_AMI_measurement
path: ${{ steps.buildAMI.outputs.measurement_path }}
if-no-files-found: error

testUID2Ami:
name: E2E Tests UID2 AMI
uses: ./.github/workflows/run-e2e-tests-on-operator.yaml
Expand All @@ -71,7 +88,10 @@ jobs:
name: EUID Operator AMI
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
outputs:
version_number: ${{ steps.buildAMI.outputs.version_number }}
ami_id: ${{ steps.buildAMI.outputs.ami_id }}
Expand Down Expand Up @@ -105,6 +125,20 @@ jobs:
euid_aws_role: ${{ env.EUID_AWS_ROLE }}
euid_aws_region: ${{ env.EUID_AWS_REGION }}

- name: Attest EUID AMI metadata
if: ${{ !contains(steps.buildAMI.outputs.version_number, 'SNAPSHOT') }}
uses: ./.github/actions/attest_file
with:
subject_paths: ${{ steps.buildAMI.outputs.measurement_path }}
signer_workflow: ${{ github.repository }}/.github/workflows/build-uid2-ami.yaml

- name: Upload EUID AMI metadata
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: euid_AMI_measurement
path: ${{ steps.buildAMI.outputs.measurement_path }}
if-no-files-found: error

testEUIDAmi:
name: E2E Tests EUID AMI
uses: ./.github/workflows/run-e2e-tests-on-operator.yaml
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/publish-all-operators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ jobs:
createRelease:
name: Create Release
runs-on: ubuntu-latest
permissions:
Comment thread
swibi-ttd marked this conversation as resolved.
contents: write
pull-requests: read
id-token: write
attestations: write
artifact-metadata: write
# Also publish on scheduled builds, not just manual dispatch: the deployed
# operator versions may come from the daily scheduled run, so
# the uid2-deployment pre-deploy release gate won't hard-block
Expand Down Expand Up @@ -241,6 +247,19 @@ jobs:
(cd ./deployment/gcp-oidc-deployment-files-${{ needs.start.outputs.new_version }} && zip -r ../../gcp-oidc-deployment-files-${{ needs.start.outputs.new_version }}.zip . )
(cd manifests && zip -r ../uid2-operator-release-manifests-${{ needs.start.outputs.new_version }}.zip .)

- name: Attest release archives
if: ${{ !contains(needs.start.outputs.new_version, 'SNAPSHOT') }}
uses: ./.github/actions/attest_file
with:
subject_paths: |
./aws-euid-deployment-files-${{ needs.start.outputs.new_version }}.zip
./aws-uid2-deployment-files-${{ needs.start.outputs.new_version }}.zip
./azure-cc-deployment-files-${{ needs.start.outputs.new_version }}.zip
./azure-aks-deployment-files-${{ needs.start.outputs.new_version }}.zip
./gcp-oidc-deployment-files-${{ needs.start.outputs.new_version }}.zip
./uid2-operator-release-manifests-${{ needs.start.outputs.new_version }}.zip
signer_workflow: ${{ github.repository }}/.github/workflows/publish-all-operators.yaml

# Publish as a pre-release (not a draft): durable + fetchable by tag
# without claiming GA. The Major-release approval gate stays the
# check_major job above, and promoting this to Latest in the UI remains
Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/publish-aws-eks-nitro-enclave-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
contents: write
security-events: write
packages: write
id-token: write
attestations: write
artifact-metadata: write
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
Expand Down Expand Up @@ -63,6 +66,9 @@ jobs:
contents: write
security-events: write
packages: write
id-token: write
attestations: write
artifact-metadata: write
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
Expand Down Expand Up @@ -110,7 +116,15 @@ jobs:
name: Cleanup Building AWS Image
runs-on: ubuntu-latest
needs: [buildUID2Image, buildEUIDImage, testUID2Eks, testEUIDEks]
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- name: Check disk usage
shell: bash
run: |
Expand All @@ -127,6 +141,15 @@ jobs:
echo "EUID Image Tag: ${{ needs.buildEUIDImage.outputs.image_tag }}" >> ${{ env.ARTIFACTS_BASE_OUTPUT_DIR }}/manifests/aws-eks-euid-enclave-id-${{ needs.buildEUIDImage.outputs.image_tag }}.txt
echo "Enclave ID (maybe shared by other images): " ${{ needs.buildEUIDImage.outputs.enclave_id }} >> ${{ env.ARTIFACTS_BASE_OUTPUT_DIR }}/manifests/aws-eks-euid-enclave-id-${{ needs.buildEUIDImage.outputs.image_tag }}.txt

- name: Attest enclave ID manifests
if: ${{ !contains(needs.buildUID2Image.outputs.eif_version_number, 'SNAPSHOT') }}
uses: ./.github/actions/attest_file
with:
subject_paths: |
${{ env.ARTIFACTS_BASE_OUTPUT_DIR }}/manifests/aws-eks-uid2-enclave-id-${{ needs.buildUID2Image.outputs.image_tag }}.txt
${{ env.ARTIFACTS_BASE_OUTPUT_DIR }}/manifests/aws-eks-euid-enclave-id-${{ needs.buildEUIDImage.outputs.image_tag }}.txt
signer_workflow: ${{ github.repository }}/.github/workflows/publish-aws-eks-nitro-enclave-docker.yaml

- name: Save Manifests as build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
Expand Down
Loading