Skip to content
This repository was archived by the owner on Aug 3, 2026. It is now read-only.

ci(sgx): signed SGX release image build via Secret Manager + WIF - #705

Open
kimo-ice wants to merge 3 commits into
mainfrom
feat/sgx-release-image-wif
Open

ci(sgx): signed SGX release image build via Secret Manager + WIF#705
kimo-ice wants to merge 3 commits into
mainfrom
feat/sgx-release-image-wif

Conversation

@kimo-ice

@kimo-ice kimo-ice commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Adds a workflow_dispatch release workflow that builds & pushes the signed SGX release image, pulling the enclave signing key from GCP Secret Manager at build time — so no engineer ever needs direct access to raiko-enclave-key.

Why

Engineers don't (and shouldn't) have access to the GCE/Secret Manager secret raiko-enclave-key in the evmchain project. But script/publish-image.sh already knows how to fetch it itself: when GCP_ENCLAVE_KEY_SECRET/GCP_ENCLAVE_KEY_PROJECT are set it runs gcloud secrets versions access --out-file <tmpfile>, passes it to the build as a BuildKit --secret id=enclave_key (never baked into a layer), puts only the public key SHA256 in a build-arg, and deletes the tmpfile on exit.

So the only thing needed is for the CI identity to have secretAccessor on that one secret.

GCP wiring (already provisioned, least-privilege)

  • Dedicated GSA [email protected].
  • roles/secretmanager.secretAccessor on only raiko-enclave-key (secret-level, not project-wide).
  • roles/artifactregistry.writer on only the images repo (us) — for the image push.
  • roles/iam.workloadIdentityUser scoped to exactly this workflow file on refs/heads/mainprincipalSet://…/github-raiko-signer/attribute.job_workflow_ref/taikoxyz/raiko/.github/workflows/release-sgx-image.yml@refs/heads/main. This lives in a dedicated WIF pool (github-raiko-signer) whose provider is locked to assertion.repository == 'taikoxyz/raiko' — deliberately not the shared terraform-pool that federates taiko-mono. No JSON keys.

The push target is Artifact Registry (DOCKER_REPOSITORY=us-docker.pkg.dev/evmchain/images, hardcoded in publish-image.sh), so the workflow authenticates Docker with gcloud auth configure-docker us-docker.pkg.dev using the same WIF credential — no registry secret needed. Both interactive prompts (proof type + push confirm) are fed via stdin, so it runs unattended.

Repo config

These are set as repo Actions variables (non-secret):

Variable Value
GCP_WORKLOAD_IDENTITY_PROVIDER projects/790288402401/…/workloadIdentityPools/github-raiko-signer/providers/github
GCP_ENCLAVE_SIGNER_SA [email protected]
GCP_ENCLAVE_KEY_SECRET raiko-enclave-key
GCP_ENCLAVE_KEY_PROJECT evmchain

Security hardening (from an adversarial review of this PR)

Applied in this branch / on the GCP side:

  • Shell-injection fix (was critical): dispatch inputs are no longer interpolated into the run: script. They pass through env: and are regex-validated; edmm is a constrained choice.
  • WIF blast radius (was high): signer trust re-scoped from repo-wide to exactly this workflow file on main, in a dedicated pool isolated from terraform-pool/taiko-mono (see above). Consequence: dispatch only works from the main branch after merge — it will not run from this feature branch by design.
  • Environment gate: job now references environment: sgx-release-signing.
  • Supply chain: all actions pinned to commit SHAs.

Needs a repo admin / follow-up (can't do with push access)

  • Configure the sgx-release-signing environment: required reviewers, disallow self-review, restrict deployment branch to main. The environment referenced here is inert until these rules are set.
  • Ephemeral signer runner: taiko-runner is a persistent self-hosted pool; the MRSIGNER key lands on it as a tmpfile. Ideally sign on a single-use runner not shared with PR/CI workloads (or a non-exportable signing service).
  • Split signer vs. pusher identity: today one GSA both reads the key and pushes to AR. A cleaner design builds+signs and pushes in two isolated jobs with separate identities, handing off by immutable digest. Left as a follow-up because it means restructuring publish-image.sh's build+push flow.
  • publish-image.sh hardening (upstream tooling, not this PR): install the key-cleanup trap immediately after mktemp and cover HUP INT TERM; drop global set -x for the key's lifetime.

Builds tee/SGX by default (stdin feeds 0); flip to 1 for a zk variant. Runs on [taiko-runner] to match ci-sgx-docker.yml.

Fetches the SGX enclave signing key (raiko-enclave-key) from GCP Secret
Manager at build time via script/publish-image.sh, using Workload
Identity Federation. No engineer needs direct access to the key, and it
never lands in an image layer (passed as a BuildKit --secret).

Auth uses a dedicated least-privilege GSA
(raiko-enclave-signer@evmchain) that holds secretAccessor on only
raiko-enclave-key. Provider/SA/secret/project are wired via repo Actions
variables.
Copilot AI review requested due to automatic review settings July 24, 2026 08:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a manually-triggered GitHub Actions workflow to build and push the signed SGX release image by authenticating to GCP via Workload Identity Federation and letting script/publish-image.sh fetch the enclave signing key from GCP Secret Manager at build time.

Changes:

  • Introduces .github/workflows/release-sgx-image.yml with workflow_dispatch inputs (tag, edmm) to drive signed SGX image publishing.
  • Uses google-github-actions/auth@v2 (OIDC/WIF) + setup-gcloud@v2 to enable Secret Manager access during the build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release-sgx-image.yml Outdated
Comment on lines +45 to +48
run: |
# publish-image.sh prompts for proof type (0=tee/SGX, 1=zk); feed via stdin.
# args: $1 = EDMM flag, $2 = tag
echo "0" | ./script/publish-image.sh "${{ inputs.edmm }}" "${{ inputs.tag }}"
Comment thread .github/workflows/release-sgx-image.yml Outdated
Comment on lines +36 to +40
- uses: google-github-actions/setup-gcloud@v2

# (registry login step here — your existing release convention)

- name: Build, sign & push SGX image
Comment on lines +22 to +24
build-sign-push:
runs-on: [taiko-runner] # SGX-capable runner (same as ci-sgx-docker)
timeout-minutes: 90

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77fc8d9182

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/release-sgx-image.yml Outdated
run: |
# publish-image.sh prompts for proof type (0=tee/SGX, 1=zk); feed via stdin.
# args: $1 = EDMM flag, $2 = tag
echo "0" | ./script/publish-image.sh "${{ inputs.edmm }}" "${{ inputs.tag }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move dispatch inputs out of the shell script

When someone who can manually dispatch this workflow provides tag or edmm containing shell syntax such as $(...), GitHub substitutes the input into this run block before bash parses it, so the command executes in a job that has already impersonated the enclave signer and has the Secret Manager identifiers in its environment. Pass the inputs through env variables and quote those variables, or validate them against a strict Docker-tag/EDMM pattern before invoking the script.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/release-sgx-image.yml Outdated
run: |
# publish-image.sh prompts for proof type (0=tee/SGX, 1=zk); feed via stdin.
# args: $1 = EDMM flag, $2 = tag
echo "0" | ./script/publish-image.sh "${{ inputs.edmm }}" "${{ inputs.tag }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Answer the push prompt in CI

When this workflow_dispatch job reaches the end of script/publish-image.sh, the script asks a second interactive question before pushing (read -p "Do you want to push..."), but this pipeline only supplies the proof-type answer. Because the script runs with set -e, that second read hits EOF and exits nonzero before docker push, so the release workflow fails after the build instead of publishing the image; feed the push confirmation too or add a noninteractive publish mode.

Useful? React with 👍 / 👎.

kimo-ice added 2 commits July 24, 2026 10:45
DOCKER_REPOSITORY in publish-image.sh is us-docker.pkg.dev/evmchain/images,
so add gcloud auth configure-docker for that AR host (reuses the WIF
credential, no registry secret) and feed both interactive prompts
(proof type + push confirm) via stdin. Signer GSA granted
artifactregistry.writer on the evmchain images repo.
… pins)

Addresses adversarial review findings:
- Critical: stop interpolating ${{ inputs.* }} into run: (shell injection).
  Pass via env + validate; constrain edmm to a choice input.
- High: signer WIF re-scoped to THIS workflow file on refs/heads/main via a
  dedicated pool (github-raiko-signer), replacing the repo-wide binding on the
  shared terraform-pool. Provider locked to repository == taikoxyz/raiko.
- High: gate the job on a protected environment (admin must add reviewers +
  restrict to main).
- Low: pin actions to commit SHAs.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants