Skip to content

Commit 9f323c7

Browse files
authored
feat: add secure-enclave EIF build and GHCR carrier image workflow (#9)
1 parent 13ef75a commit 9f323c7

4 files changed

Lines changed: 263 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Builds the secure-enclave EIF and pushes the carrier image to GHCR.
2+
# Pull requests build without publishing.
3+
name: Build Enclave EIF Image
4+
5+
on:
6+
pull_request:
7+
paths:
8+
- "secure-enclave/**"
9+
- "shared/**"
10+
- "Cargo.toml"
11+
- "Cargo.lock"
12+
- "rust-toolchain.toml"
13+
- "scripts/build-eif.sh"
14+
- ".github/workflows/build-enclave-eif.yml"
15+
push:
16+
branches:
17+
- main
18+
tags:
19+
- "v*"
20+
workflow_dispatch:
21+
inputs:
22+
version:
23+
description: "Version tag to publish (including v prefix, e.g. v0.1.0)"
24+
required: false
25+
type: string
26+
27+
permissions:
28+
contents: read
29+
30+
env:
31+
NITRO_CLI_VERSION: v1.4.2
32+
33+
jobs:
34+
build-enclave-eif:
35+
name: Build enclave EIF + carrier image
36+
runs-on: ubuntu-latest
37+
permissions:
38+
contents: read
39+
id-token: write
40+
packages: write
41+
attestations: write
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
45+
46+
- name: Install Rust toolchain
47+
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
48+
49+
- name: Cache nitro-cli build
50+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
51+
with:
52+
path: target/eif/aws-nitro-enclaves-cli-${{ env.NITRO_CLI_VERSION }}
53+
key: nitro-cli-${{ runner.os }}-${{ env.NITRO_CLI_VERSION }}
54+
55+
- name: Resolve version
56+
id: version
57+
if: github.ref_type == 'tag' || inputs.version != ''
58+
env:
59+
INPUT_VERSION: ${{ inputs.version }}
60+
run: |
61+
if [[ -n "$INPUT_VERSION" ]]; then
62+
VERSION="$INPUT_VERSION"
63+
else
64+
VERSION="$GITHUB_REF_NAME"
65+
fi
66+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
67+
if [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
68+
echo "is_stable=true" >> "$GITHUB_OUTPUT"
69+
else
70+
echo "is_stable=false" >> "$GITHUB_OUTPUT"
71+
fi
72+
73+
- name: Prepare nitro-cli log directory
74+
run: sudo install -d -m 1777 /var/log/nitro_enclaves
75+
76+
- name: Build EIF and PCRs
77+
run: scripts/build-eif.sh target/eif
78+
79+
- name: Publish PCR measurements
80+
run: |
81+
{
82+
echo '### Enclave PCR measurements'
83+
echo '```json'
84+
cat target/eif/pcrs.json
85+
echo '```'
86+
} >> "$GITHUB_STEP_SUMMARY"
87+
88+
- name: Upload PCR measurements
89+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
90+
with:
91+
name: enclave-pcrs
92+
path: target/eif/pcrs.json
93+
if-no-files-found: error
94+
95+
- name: Docker meta
96+
id: meta
97+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
98+
with:
99+
images: ghcr.io/${{ github.repository }}-enclave-eif
100+
tags: |
101+
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || steps.version.outputs.is_stable == 'true' }}
102+
type=sha
103+
type=raw,value=${{ steps.version.outputs.version }},enable=${{ steps.version.outputs.version != '' }}
104+
105+
- name: Set up Docker Buildx
106+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
107+
108+
- name: Login to GitHub Container Registry
109+
if: github.event_name != 'pull_request'
110+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
111+
with:
112+
registry: ghcr.io
113+
username: ${{ github.actor }}
114+
password: ${{ secrets.GITHUB_TOKEN }}
115+
116+
- name: Build and push carrier image
117+
id: build
118+
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
119+
with:
120+
# Context is the EIF output dir so the .eif is always included.
121+
context: target/eif
122+
file: secure-enclave/Dockerfile.eif
123+
push: ${{ github.event_name != 'pull_request' }}
124+
tags: ${{ steps.meta.outputs.tags }}
125+
labels: ${{ steps.meta.outputs.labels }}
126+
platforms: linux/amd64
127+
128+
- name: Attest build provenance
129+
if: github.event_name != 'pull_request'
130+
uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1
131+
with:
132+
push-to-registry: true
133+
subject-name: ghcr.io/${{ github.repository }}-enclave-eif
134+
subject-digest: ${{ steps.build.outputs.digest }}

scripts/build-eif.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# Build the secure-enclave EIF and emit its PCR measurements. Needs Linux
5+
# x86_64 + Docker; Nitro hardware is only required to run the enclave, not
6+
# build it.
7+
#
8+
# Usage: scripts/build-eif.sh [output-dir] (default: target/eif)
9+
# Outputs: embedding-verifier-enclave.eif, pcrs.json
10+
# Env: NITRO_CLI_VERSION (default v1.4.2), ENCLAVE_IMAGE_TAG
11+
12+
if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then
13+
echo "[ERROR] EIF builds require Linux x86_64 (got $(uname -s)/$(uname -m))." >&2
14+
exit 1
15+
fi
16+
17+
NITRO_CLI_VERSION="${NITRO_CLI_VERSION:-v1.4.2}"
18+
ENCLAVE_IMAGE_TAG="${ENCLAVE_IMAGE_TAG:-embedding-verifier-enclave:local}"
19+
20+
repo_root="$(git rev-parse --show-toplevel)"
21+
cd "$repo_root"
22+
23+
out_dir="${1:-target/eif}"
24+
mkdir -p "$out_dir"
25+
out_dir="$(cd "$out_dir" && pwd)"
26+
27+
echo "[1/3] Building enclave container image ($ENCLAVE_IMAGE_TAG)..."
28+
docker build -t "$ENCLAVE_IMAGE_TAG" -f secure-enclave/Dockerfile .
29+
30+
echo "[2/3] Building nitro-cli $NITRO_CLI_VERSION..."
31+
nitro_cli_dir="$out_dir/aws-nitro-enclaves-cli-$NITRO_CLI_VERSION"
32+
nitro_cli="$nitro_cli_dir/target/release/nitro-cli"
33+
if [ ! -x "$nitro_cli" ]; then
34+
rm -rf "$nitro_cli_dir"
35+
git clone --depth 1 --branch "$NITRO_CLI_VERSION" \
36+
https://github.com/aws/aws-nitro-enclaves-cli "$nitro_cli_dir"
37+
cargo build --release --bin nitro-cli --manifest-path "$nitro_cli_dir/Cargo.toml"
38+
fi
39+
40+
echo "[3/3] Converting to EIF..."
41+
eif_path="$out_dir/embedding-verifier-enclave.eif"
42+
build_json="$out_dir/build-enclave.json"
43+
NITRO_CLI_BLOBS="$nitro_cli_dir/blobs/x86_64" \
44+
NITRO_CLI_ARTIFACTS="$out_dir/artifacts" \
45+
"$nitro_cli" build-enclave \
46+
--docker-uri "$ENCLAVE_IMAGE_TAG" \
47+
--output-file "$eif_path" | tee "$build_json"
48+
49+
jq '.Measurements' "$build_json" > "$out_dir/pcrs.json"
50+
51+
echo
52+
echo "EIF: $eif_path"
53+
echo "PCRs: $out_dir/pcrs.json"
54+
jq . "$out_dir/pcrs.json"

secure-enclave/Dockerfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# syntax=docker/dockerfile:1
2+
# Enclave workload image, converted to an EIF by scripts/build-eif.sh.
3+
#
4+
# Base images are tag-pinned and the build is --locked. Before a PRODUCTION
5+
# deploy, pin base images by digest + apt to a snapshot.debian.org timestamp so
6+
# PCRs are reproducible, then register the real PCRs (dev runs --debug-mode,
7+
# which zeroes PCRs and skips attestation).
8+
9+
FROM rust:1.97.0-bookworm AS builder
10+
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
ca-certificates \
13+
clang \
14+
pkg-config \
15+
&& rm -rf /var/lib/apt/lists/*
16+
17+
WORKDIR /src
18+
COPY . .
19+
20+
RUN cargo build --release --locked --package secure-enclave --bin secure-enclave
21+
22+
FROM debian:bookworm-slim
23+
24+
RUN apt-get update && apt-get install -y --no-install-recommends \
25+
ca-certificates \
26+
&& rm -rf /var/lib/apt/lists/*
27+
28+
COPY --from=builder /src/target/release/secure-enclave /usr/local/bin/secure-enclave
29+
30+
ENV RUST_LOG=info
31+
32+
ENTRYPOINT ["/usr/local/bin/secure-enclave"]

secure-enclave/Dockerfile.eif

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# syntax=docker/dockerfile:1
2+
# Carrier image that launches the enclave EIF on Nitro-enabled nodes.
3+
# Build context: target/eif/ (produced by scripts/build-eif.sh).
4+
5+
FROM public.ecr.aws/amazonlinux/amazonlinux:2023
6+
7+
RUN dnf install -y aws-nitro-enclaves-cli aws-nitro-enclaves-cli-devel jq && \
8+
dnf clean all
9+
10+
COPY embedding-verifier-enclave.eif /home/embedding-verifier-enclave.eif
11+
12+
ENV EIF_PATH="/home/embedding-verifier-enclave.eif" \
13+
ENCLAVE_CPU_COUNT=2 \
14+
ENCLAVE_MEMORY_SIZE=1024 \
15+
ENCLAVE_DEBUG_MODE=false
16+
17+
COPY <<'EOF' /home/run.sh
18+
#!/bin/bash
19+
set -euo pipefail
20+
21+
echo "[run.sh] Starting enclave: eif=${EIF_PATH} cpu=${ENCLAVE_CPU_COUNT} mem=${ENCLAVE_MEMORY_SIZE}MiB debug=${ENCLAVE_DEBUG_MODE}"
22+
23+
DEBUG_FLAG=""
24+
if [[ "${ENCLAVE_DEBUG_MODE}" == "true" || "${ENCLAVE_DEBUG_MODE}" == "1" ]]; then
25+
DEBUG_FLAG="--debug-mode"
26+
fi
27+
28+
run_output=$(nitro-cli run-enclave \
29+
--cpu-count "${ENCLAVE_CPU_COUNT}" \
30+
--memory "${ENCLAVE_MEMORY_SIZE}" \
31+
--eif-path "${EIF_PATH}" \
32+
${DEBUG_FLAG})
33+
34+
enclave_id=$(echo "${run_output}" | jq -r '.EnclaveID')
35+
echo "[run.sh] Enclave started: ${enclave_id}"
36+
37+
# Blocking — keeps the container alive.
38+
nitro-cli console --enclave-id "${enclave_id}"
39+
EOF
40+
41+
RUN chmod +x /home/run.sh
42+
43+
CMD ["/home/run.sh"]

0 commit comments

Comments
 (0)