From cc60f9307027c7016f80dcaeaf54060ee86d24e0 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Sun, 29 Mar 2026 14:23:01 +0800 Subject: [PATCH] feat(key-provider): single-container image with systemd lifecycle management Consolidate aesmd and gramine-sealing-key-provider into a single container to eliminate cross-container startup ordering issues that caused cascading failures after power outage reboots. Move config to /etc so it no longer depends on external disk mounts. --- .github/workflows/key-provider-release.yml | 85 +++++++++++++++++++ key-provider-build/Dockerfile | 55 ++++++++++++ .../dstack-key-provider.service | 30 +++++++ key-provider-build/entrypoint.sh | 39 +++++++++ 4 files changed, 209 insertions(+) create mode 100644 .github/workflows/key-provider-release.yml create mode 100644 key-provider-build/Dockerfile create mode 100644 key-provider-build/dstack-key-provider.service create mode 100644 key-provider-build/entrypoint.sh diff --git a/.github/workflows/key-provider-release.yml b/.github/workflows/key-provider-release.yml new file mode 100644 index 00000000..90f55542 --- /dev/null +++ b/.github/workflows/key-provider-release.yml @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: © 2025 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +name: Key Provider Release + +on: + workflow_dispatch: + push: + tags: + - 'key-provider-v*' +permissions: + attestations: write + id-token: write + contents: write + packages: write + +jobs: + build-and-release: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Parse version from tag + run: | + # Extract version from tag (e.g., key-provider-v1.2.3 -> 1.2.3) + VERSION=${GITHUB_REF#refs/tags/key-provider-v} + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "Parsed version: $VERSION" + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Get Git commit timestamps + run: | + echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV + echo "GIT_REV=$(git rev-parse HEAD)" >> $GITHUB_ENV + + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v5 + env: + SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }} + with: + context: key-provider-build + push: true + tags: | + ${{ vars.DOCKERHUB_ORG }}/dstack-gramine-key-provider:${{ env.VERSION }} + ghcr.io/dstack-tee/dstack/dstack-gramine-key-provider:${{ env.VERSION }} + platforms: linux/amd64 + provenance: false + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-name: "docker.io/${{ vars.DOCKERHUB_ORG }}/dstack-gramine-key-provider" + subject-digest: ${{ steps.build-and-push.outputs.digest }} + push-to-registry: true + + - name: GitHub Release + uses: softprops/action-gh-release@v1 + with: + name: "Key Provider Release v${{ env.VERSION }}" + body: | + ## Docker Image Information + + **Image**: `docker.io/${{ vars.DOCKERHUB_ORG }}/dstack-gramine-key-provider:${{ env.VERSION }}` + + **Digest (SHA256)**: `${{ steps.build-and-push.outputs.digest }}` + + **Verification**: [Verify on Sigstore](https://search.sigstore.dev/?hash=${{ steps.build-and-push.outputs.digest }}) diff --git a/key-provider-build/Dockerfile b/key-provider-build/Dockerfile new file mode 100644 index 00000000..e7740005 --- /dev/null +++ b/key-provider-build/Dockerfile @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: © 2024-2025 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +# Stage 1: Build +FROM gramineproject/gramine:1.9-jammy@sha256:84b3d222e0bd9ab941f0078a462af0dbc5518156b99b147c10a7b83722ac0c38 AS builder + +RUN apt-get update && apt-get install -y \ + git \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.85 -y +ENV PATH="/root/.cargo/bin:${PATH}" + +ENV SGX=1 DEBUG=0 DEV_MODE=0 RUST_LOG=info + +RUN git clone https://github.com/MoeMahhouk/gramine-sealing-key-provider && \ + cd gramine-sealing-key-provider && \ + git checkout 180ff4691dce5aae7cd7d6c1344c3e1ec872f174 + +WORKDIR /gramine-sealing-key-provider +COPY Cargo.lock . + +RUN make target/release/gramine-sealing-key-provider && \ + gramine-sgx-gen-private-key && \ + make RUST_LOG=info + +# Stage 2: Runtime +# Same base image = same /lib/x86_64-linux-gnu/ (except libgcc-s1 from build-essential) +FROM gramineproject/gramine:1.9-jammy@sha256:84b3d222e0bd9ab941f0078a462af0dbc5518156b99b147c10a7b83722ac0c38 + +# libgcc-s1: only /lib/x86_64-linux-gnu/ addition from build-essential, needed for manifest hash match +# libsgx-dcap-default-qpl: not in base image, needed by aesmd for DCAP +RUN curl -fsSL https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + | gpg --dearmor -o /usr/share/keyrings/intel-sgx-deb.gpg && \ + echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/intel-sgx-deb.gpg] https://download.01.org/intel-sgx/sgx_repo/ubuntu jammy main' \ + > /etc/apt/sources.list.d/intel-sgx.list && \ + apt-get update && apt-get install -y \ + libgcc-s1 \ + libsgx-dcap-default-qpl \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /gramine-sealing-key-provider/target/release/gramine-sealing-key-provider /gramine-sealing-key-provider/target/release/gramine-sealing-key-provider +COPY --from=builder /gramine-sealing-key-provider/gramine-sealing-key-provider.manifest.sgx /gramine-sealing-key-provider/ +COPY --from=builder /gramine-sealing-key-provider/gramine-sealing-key-provider.sig /gramine-sealing-key-provider/ + +WORKDIR /gramine-sealing-key-provider + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +EXPOSE 3443 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/key-provider-build/dstack-key-provider.service b/key-provider-build/dstack-key-provider.service new file mode 100644 index 00000000..4b79b46c --- /dev/null +++ b/key-provider-build/dstack-key-provider.service @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: © 2025 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +[Unit] +Description=Gramine Sealing Key Provider +After=docker.service +Requires=docker.service + +[Service] +Type=simple +ExecStart=/bin/bash -c '\ + if /usr/bin/docker inspect gramine-sealing-key-provider >/dev/null 2>&1; then \ + /usr/bin/docker start -a gramine-sealing-key-provider; \ + else \ + /usr/bin/docker run \ + --name gramine-sealing-key-provider \ + --privileged \ + --device /dev/sgx_enclave:/dev/sgx_enclave \ + --device /dev/sgx_provision:/dev/sgx_provision \ + -v /etc/dstack-key-provider/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf \ + -p 127.0.0.1:3443:3443 \ + dstacktee/dstack-gramine-key-provider:0.1.0; \ + fi' +ExecStop=/usr/bin/docker stop gramine-sealing-key-provider +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/key-provider-build/entrypoint.sh b/key-provider-build/entrypoint.sh new file mode 100644 index 00000000..cb642270 --- /dev/null +++ b/key-provider-build/entrypoint.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +# SPDX-FileCopyrightText: © 2025 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +set -e + +# Start AESM service in background +echo "Starting AESM service..." +mkdir -p /var/run/aesmd +chmod 755 /var/run/aesmd +export AESM_PATH=/opt/intel/sgx-aesm-service/aesm +export LD_LIBRARY_PATH=/opt/intel/sgx-aesm-service/aesm +/opt/intel/sgx-aesm-service/aesm/aesm_service --no-daemon & +AESM_PID=$! + +# Clean up aesmd on exit +trap 'kill "$AESM_PID" 2>/dev/null; exit' INT TERM EXIT + +# Wait for AESM socket +echo "Waiting for AESM socket..." +AESM_SOCKET="/var/run/aesmd/aesm.socket" +while [ ! -S "$AESM_SOCKET" ]; do + if ! kill -0 "$AESM_PID" 2>/dev/null; then + echo "Error: AESM service exited unexpectedly" + exit 1 + fi + sleep 1 +done +echo "AESM socket is available." + +# Show enclave info +echo "Enclave info:" +gramine-sgx-sigstruct-view --output-format json gramine-sealing-key-provider.sig + +# Replace shell with gramine-sgx so it receives signals directly as PID 1 +echo "Starting Gramine Sealing Key Provider" +exec gramine-sgx gramine-sealing-key-provider