Skip to content
Open
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
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
coverage/
test_results/
logs/
bin/
artifacts/
!artifacts/nitro-enclave-image/
deploy/
66 changes: 66 additions & 0 deletions .github/actions/cloudsmith-login/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Cloudsmith Docker Login
description: Exchange GitHub OIDC token for Cloudsmith credentials and log in to the Docker registry.

inputs:
registry:
description: Cloudsmith Docker registry hostname
required: true
org:
description: Cloudsmith organization
required: false
default: circle
service-slug:
description: Cloudsmith OIDC service account slug
required: false
default: arc-publisher-gha-service

runs:
using: composite
steps:
- name: Get Cloudsmith token
id: get-token
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
CLOUDSMITH_ORG: ${{ inputs.org }}
CLOUDSMITH_SERVICE_SLUG: ${{ inputs.service-slug }}
with:
script: |-
let oidc_token;
try {
oidc_token = await core.getIDToken();
core.setSecret(oidc_token);
} catch (error) {
core.setFailed(`Failed to get OIDC token: ${error}`);
return;
}
try {
const response = await fetch(`https://api.cloudsmith.io/openid/${process.env.CLOUDSMITH_ORG}/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
oidc_token: oidc_token,
service_slug: process.env.CLOUDSMITH_SERVICE_SLUG
}),
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
core.setFailed(`Cloudsmith OIDC exchange failed: ${response.status} ${response.statusText}`);
return;
}
const data = await response.json();
core.setSecret(data.token);
core.setOutput('cloudsmith_user', process.env.CLOUDSMITH_SERVICE_SLUG);
core.setOutput('cloudsmith_token', data.token);
} catch (error) {
core.setFailed(`Failed to login to Cloudsmith: ${error}`);
return;
}

- name: Login to Cloudsmith
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ${{ inputs.registry }}
username: ${{ steps.get-token.outputs.cloudsmith_user }}
password: ${{ steps.get-token.outputs.cloudsmith_token }}
34 changes: 34 additions & 0 deletions .github/workflows/build-docker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Build Docker

on:
pull_request:
types: [labeled, synchronize]
branches:
- main
- release/*
push:
tags:
- "v*"

concurrency:
group: docker-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
enclave:
if: >-
github.event_name == 'push' ||
contains(github.event.pull_request.labels.*.name, 'build-docker')
uses: ./.github/workflows/nitro-enclave-build.yaml

docker:
needs: [enclave]
uses: ./.github/workflows/build-enclave-image.yaml
with:
push: ${{ github.event_name == 'push' }}
version: ${{ github.ref_name }}
enclave_artifact_name: ${{ needs.enclave.outputs.image_artifact_name }}
enclave_file: ${{ needs.enclave.outputs.output_file }}
enclave_pcr0: ${{ needs.enclave.outputs.pcr0 }}
enclave_pcr1: ${{ needs.enclave.outputs.pcr1 }}
enclave_pcr2: ${{ needs.enclave.outputs.pcr2 }}
114 changes: 114 additions & 0 deletions .github/workflows/build-enclave-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Build Docker

on:
workflow_call:
outputs:
docker_archive_artifact_name:
description: Docker archive artifact name for the built signer-with-enclave image
value: ${{ jobs.build.outputs.docker_archive_artifact_name }}
inputs:
runner:
type: string
default: ubuntu-latest
docker_archive_artifact_name:
description: Artifact name for an optional signer-with-enclave docker archive upload
type: string
default: ""
enclave_artifact_name:
type: string
required: true
enclave_file:
type: string
required: true
enclave_pcr0:
type: string
required: true
enclave_pcr1:
type: string
required: true
enclave_pcr2:
type: string
required: true

jobs:
build:
name: Build signer-with-enclave
permissions:
contents: read
runs-on: ${{ inputs.runner }}
outputs:
docker_archive_artifact_name: ${{ steps.archive_meta.outputs.name }}
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Download EIF artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
with:
name: ${{ inputs.enclave_artifact_name }}
path: artifacts/${{ inputs.enclave_artifact_name }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

- name: Build image
id: build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0
with:
source: .
files: docker-bake.hcl
targets: signer-with-enclave
set: |
signer-with-enclave.platform=linux/amd64
signer-with-enclave.tags=
signer-with-enclave.output=type=oci,tar=false,dest=./oci-image
env:
BUILDX_NO_DEFAULT_ATTESTATIONS: 1
CI: true
ENCLAVE_EIF: artifacts/${{ inputs.enclave_artifact_name }}/${{ inputs.enclave_file }}
ENCLAVE_PCR0: ${{ inputs.enclave_pcr0 }}
ENCLAVE_PCR1: ${{ inputs.enclave_pcr1 }}
ENCLAVE_PCR2: ${{ inputs.enclave_pcr2 }}

- name: Trivy vulnerability scan
env:
TRIVY_IMAGE: aquasec/trivy:0.71.2@sha256:f5d0e600ecda7449e2a9b272805aef698631d3bb3f3a739a750de2c6819acdc9
run: |
docker run --rm \
-v "${GITHUB_WORKSPACE}:/workspace" \
"${TRIVY_IMAGE}" image \
--input /workspace/oci-image \
--format sarif \
--output /workspace/trivy-results.sarif \
--severity CRITICAL \
--ignore-unfixed \
--exit-code 1

- name: Upload Trivy scan results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: trivy-signer-with-enclave
path: trivy-results.sarif

- name: Record docker archive artifact name
id: archive_meta
run: echo "name=${ARTIFACT_NAME}" >> "$GITHUB_OUTPUT"
env:
ARTIFACT_NAME: ${{ inputs.docker_archive_artifact_name }}

- name: Export docker archive for smoke validation
if: ${{ inputs.docker_archive_artifact_name != '' }}
run: |
skopeo copy \
"oci:./oci-image" \
"docker-archive:./signer-with-enclave.tar:nitro-enclave-signer/signer-with-enclave:smoke"

- name: Upload docker archive artifact
if: ${{ inputs.docker_archive_artifact_name != '' }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ inputs.docker_archive_artifact_name }}
path: signer-with-enclave.tar
compression-level: 0
retention-days: 1
130 changes: 130 additions & 0 deletions .github/workflows/nitro-enclave-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Nitro Enclave Build

on:
workflow_call:
inputs:
runner:
description: "Runner label for the build job."
type: string
default: "ubuntu-latest"
artifact_name:
description: "Name for the uploaded EIF artifact."
type: string
default: "nitro-enclave-image"
retention_days:
description: "Artifact retention in days."
type: number
default: 1
cli_commit:
description: >-
Commit SHA of aws-nitro-enclaves-cli to build from.
WARNING: changing this value can alter PCR0 and PCR2 measurements
because nitro-cli controls the kernel and init ramdisk bundled
into the EIF. Coordinate with downstream attestation policies.
type: string
default: "18a5f6f35f110c0f235f193ae3caff9434d64ee1" # v1.4.5
outputs:
image_artifact_name:
description: "Name of the artifact containing the EIF."
value: ${{ jobs.build.outputs.image_artifact_name }}
output_file:
description: "Path to the EIF file within the artifact."
value: ${{ jobs.build.outputs.output_file }}
pcr0:
description: "PCR0 measurement (enclave image hash)."
value: ${{ jobs.build.outputs.pcr0 }}
pcr1:
description: "PCR1 measurement (Linux kernel hash)."
value: ${{ jobs.build.outputs.pcr1 }}
pcr2:
description: "PCR2 measurement (application hash)."
value: ${{ jobs.build.outputs.pcr2 }}

permissions:
contents: read

jobs:
build:
runs-on: ${{ inputs.runner }}
timeout-minutes: 30
outputs:
image_artifact_name: ${{ steps.eif.outputs.image_artifact_name }}
output_file: ${{ steps.eif.outputs.output_file }}
pcr0: ${{ steps.eif.outputs.pcr0 }}
pcr1: ${{ steps.eif.outputs.pcr1 }}
pcr2: ${{ steps.eif.outputs.pcr2 }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

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

- name: Build enclave image
run: docker buildx bake --provenance=false --allow fs.read=./docker/certs enclave

- name: Restore nitro-cli from cache
id: cli-cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/nitro-install
key: nitro-cli-${{ inputs.cli_commit }}-${{ runner.os }}-${{ runner.arch }}

- name: Install Rust toolchain
if: steps.cli-cache.outputs.cache-hit != 'true'
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with:
toolchain: stable

- name: Build nitro-cli from source
if: steps.cli-cache.outputs.cache-hit != 'true'
env:
COMMIT: ${{ inputs.cli_commit }}
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
curl tar build-essential clang gcc \
libssl-dev pkg-config musl-tools

mkdir -p /tmp/nitro-src
curl -sSfL "https://github.com/aws/aws-nitro-enclaves-cli/archive/${COMMIT}.tar.gz" | \
tar -C /tmp/nitro-src -xz --strip-components=1

cd /tmp/nitro-src
make vsock-proxy-native nitro-cli-native
mkdir -p /tmp/nitro-install
NITRO_CLI_INSTALL_DIR=/tmp/nitro-install make install-tools

- name: Install nitro-cli
run: sudo cp -a /tmp/nitro-install/. /

- name: Build EIF
id: eif
run: |
sudo mkdir -p /var/log/nitro_enclaves
sudo chmod 777 /var/log/nitro_enclaves

nitro-cli build-enclave \
--docker-uri nitro-enclave-signer/enclave:latest \
--output-file enclave.eif

nitro-cli describe-eif \
--eif-path enclave.eif \
> describe_eif.json

echo "image_artifact_name=${{ inputs.artifact_name }}" >> "$GITHUB_OUTPUT"
echo "output_file=enclave.eif" >> "$GITHUB_OUTPUT"
pcr0=$(jq -er '.Measurements.PCR0' describe_eif.json)
pcr1=$(jq -er '.Measurements.PCR1' describe_eif.json)
pcr2=$(jq -er '.Measurements.PCR2' describe_eif.json)
echo "pcr0=${pcr0}" >> "$GITHUB_OUTPUT"
echo "pcr1=${pcr1}" >> "$GITHUB_OUTPUT"
echo "pcr2=${pcr2}" >> "$GITHUB_OUTPUT"

- name: Upload EIF and metadata
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.artifact_name }}
retention-days: ${{ inputs.retention_days }}
path: |
enclave.eif
describe_eif.json
4 changes: 2 additions & 2 deletions .github/workflows/pipeline-common-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ jobs:
env:
APP_ENV: qa
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@v4

- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
- uses: actions/setup-go@v5
with:
go-version: "1.24"

Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ proto: ## Generate protocol buffers
build: proto ## Build application binary
@$(SCRIPTS)/build.sh

local-enclave-docker: build ## Build local enclave docker image
@docker buildx bake --set "*.tags=$(ENCLAVE_NAME):local" signer
local-enclave-docker: ## Build local enclave docker image
@docker buildx bake --set "*.tags=$(ENCLAVE_NAME):local" signer-dev

#------------------------------------------------------------------------------
# Test
Expand All @@ -25,7 +25,7 @@ local-enclave-docker: build ## Build local enclave docker image
test: build ## Run unit tests and linting
@$(SCRIPTS)/test.sh

test-it: up ## Run integration tests
test-it: build up ## Run integration tests
@RUN_IT_TESTS=true $(SCRIPTS)/test.sh

test-all: test-it smoke ## Run all tests
Expand All @@ -40,7 +40,7 @@ test-reproducibility: ## Verify enclave build reproducibility
# Development
#------------------------------------------------------------------------------

dev: up ## Start local development
dev: build up ## Start local development
@$(SCRIPTS)/dev.sh

up: local-enclave-docker ## Start dependencies
Expand Down
Loading
Loading