From 84aa812d86d93129e87e90e3b80369f7e99c84f1 Mon Sep 17 00:00:00 2001 From: Lee Hannigan <29015211+LeeroyHannigan@users.noreply.github.com> Date: Mon, 2 Nov 2026 22:56:50 +0000 Subject: [PATCH] ci: read the project board App key from Secrets Manager via OIDC The project status sweep minted its GitHub App token from a private key stored as a GitHub environment secret. Read the key at run time from AWS Secrets Manager through an OIDC role that trusts only the project-board environment, as the Docker Hub credential is now read. The job gets id-token: write and a 15-minute AWS session. After minting the token, a step blanks every variable the secrets action exported and the AWS credentials, so the sweep script runs with only the installation token, as before. The header's setup notes cover where the key lives, how to build the secret's JSON, and how to rotate the key. --- .github/workflows/project-status-sweep.yml | 46 ++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/.github/workflows/project-status-sweep.yml b/.github/workflows/project-status-sweep.yml index 649c5dc9f..85bdcd39c 100644 --- a/.github/workflows/project-status-sweep.yml +++ b/.github/workflows/project-status-sweep.yml @@ -20,7 +20,13 @@ name: Project status sweep # Repository: Issues, Pull requests, Metadata read. No webhook. Install it # on every repo whose issues or PRs are on the board (today: extenddb). # 2. Environment "project-board", deployment branches: main only. -# In it: variable PROJECT_APP_CLIENT_ID and secret PROJECT_APP_PRIVATE_KEY. +# In it: variable PROJECT_APP_CLIENT_ID. No secret: the App's private key +# is in AWS Secrets Manager as JSON {"private_key": ""} and is read +# at run time through the OIDC role in the steps below, which trusts only +# this environment. Build that JSON with +# `jq -n --rawfile k app.pem '{private_key: $k}'`, which keeps the PEM's +# line breaks. To rotate the key, generate a new one for the App, store +# it in the secret, then delete the old key in the App's settings. # 3. Board workflows: keep "Item closed" and "Pull request merged" (they set # Done). Turn off every other workflow that sets Status; the sweep warns # while any is on. @@ -55,11 +61,14 @@ jobs: if: github.repository == 'ExtendDB/extenddb' runs-on: ubuntu-latest timeout-minutes: 10 - # Secrets live in this environment, which only main can use. + # The OIDC role trusts only this environment, which only main can use. # deployment: false keeps that, without a deployment record every run. environment: name: project-board deployment: false + permissions: + contents: read + id-token: write # OIDC role that reads the App key from Secrets Manager steps: - name: Check out sweep script uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -67,12 +76,27 @@ jobs: sparse-checkout: .github/scripts persist-credentials: false + - name: Assume the App-key role via OIDC + uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3 + with: + role-to-assume: arn:aws:iam::975306274793:role/ExtendDBProjectBoardApp + role-session-name: extenddb-project-sweep-${{ github.run_id }} + role-duration-seconds: 900 # one secret read; the minimum session + aws-region: us-east-1 + + - name: Read the App private key from Secrets Manager + # Masked in the log, line by line as well as whole. + uses: aws-actions/aws-secretsmanager-get-secrets@2297f9a879480a9e3af9b293ed15c70caf8e1c88 # v3.0.2 + with: + secret-ids: PROJECT_APP,extenddb/project-board-app + parse-json-secrets: true + - name: Mint App token id: app-token uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 with: client-id: ${{ vars.PROJECT_APP_CLIENT_ID }} - private-key: ${{ secrets.PROJECT_APP_PRIVATE_KEY }} + private-key: ${{ env.PROJECT_APP_PRIVATE_KEY }} # No repositories list: the token covers the repos the App is # installed on, so cards from a newly added repo work once it is. owner: ExtendDB @@ -80,6 +104,22 @@ jobs: permission-issues: read permission-pull-requests: read + - name: Drop the App key and the AWS credentials from the job environment + # Both are exported for every later step. The sweep needs only the + # one-hour installation token, so every variable the secrets action + # exported (it lists them in SECRETS_LIST_CLEAN_UP) and the credentials + # that can read the secret are cleared before the sweep script runs. + # A later step can still request an OIDC token; the sweep script is + # under the same code-owner review as this file. + run: | + set -euo pipefail + { + jq -r '.[] | . + "="' <<< "${SECRETS_LIST_CLEAN_UP:-[]}" + echo "AWS_ACCESS_KEY_ID=" + echo "AWS_SECRET_ACCESS_KEY=" + echo "AWS_SESSION_TOKEN=" + } >> "$GITHUB_ENV" + - name: Sweep board uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: