Repository navigation
ci: read the project board App key from Secrets Manager via OIDC - #764
Conversation
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.
eliseong
left a comment
There was a problem hiding this comment.
I ran the changed steps on a local machine with the pinned action versions. A local HTTP server replaced Secrets Manager, and a second local server replaced the GitHub API. The workflow code works as intended. One statement in the PR description is not correct.
Results:
- The secrets action exports the key as
PROJECT_APP_PRIVATE_KEY. The mint step reads that variable. The test server verified the JWT signature with the original key, and the signature was valid. - The log masking is correct. The action masks the full value. The runner then masks each line of the value. No line of the key was visible in the step output.
- The cleanup step writes an empty value for each name in
SECRETS_LIST_CLEAN_UPand for the three AWS credential variables. After the cleanup step, no variable in the job environment contained key data. - The post-job cleanup of each action still passes after the cleanup step.
- I tested these secret formats: PKCS#1, PKCS#8, CRLF line endings, literal
\nsequences, no final newline, and extra JSON keys. The mint step made a token for each format. - I tested these incorrect formats: a raw PEM that is not JSON, an incorrect JSON key name, an empty value, and a truncated PEM. Each run failed before the sweep step. No error message showed key data.
- I tested these Secrets Manager errors: throttling, access denied, not found, and a server error. Each run failed before the sweep step. No error message showed key data.
actionlint1.7.12 with shellcheck 0.11.0 shows no errors for this file.
Change requested:
The PR description says: "The sweep script then runs with only the installation token, as it did before." This is not correct. The job has id-token: write, so the sweep step can request an OIDC token, assume the role, and read the key. The cleanup step cannot prevent this, because the runner adds ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN to the environment of each step. The comment in the workflow file states this correctly. Please make the PR description agree with that comment.
Question:
Please confirm the trust policy of ExtendDBProjectBoardApp. The comments say that the role trusts only the project-board environment, but the repo does not show the policy. Does the trust policy use StringEquals with these two conditions and no wildcards?
token.actions.githubusercontent.com:subequalsrepo:ExtendDB/extenddb:environment:project-boardtoken.actions.githubusercontent.com:audequalssts.amazonaws.com
Also, does the permission policy allow only secretsmanager:GetSecretValue on extenddb/project-board-app?
|
Update on the two rollout preconditions. The secret The role When you create the role, set its trust policy to
Set the permission policy to one statement: |
The branch was 90 commits behind main. Main does not change the sweep workflow or the sweep script, and the merge has no conflicts.
|
@eliseong On your two points:
I merged |
eliseong
left a comment
There was a problem hiding this comment.
Both points are resolved.
The description now matches the workflow comment about the OIDC token.
The role exists and is scoped as requested: one trust statement with no wildcards, and read access to the one secret only.
The workflow file is unchanged from the version I reviewed, so the earlier results still hold. Approving.
What
The project status sweep mints a GitHub App installation token every five minutes. Until now the App's private key was a GitHub environment secret. With this change, the job reads the key at run time from AWS Secrets Manager. The read goes through an OIDC role that trusts only the
project-boardenvironment. #744 made the same change for the Docker Hub credential.id-token: writeand assumes the role for a 15-minute session.id-token: write. The cleanup step cannot prevent this. The runner setsACTIONS_ID_TOKEN_REQUEST_URLandACTIONS_ID_TOKEN_REQUEST_TOKENin the environment of every step. The comment above the cleanup step says this too. The same code owners approve changes to the sweep script and to this workflow.Rollout: the role and the secret exist. After the first green run, delete the environment secret and the old key in the App's settings. If the secret holds the same key as the environment secret, rotate it first. Generate a new key, store it in the secret, and wait for a green run.
Why
A person who has the App's private key can act as the App until someone rotates the key. The App can write to the organization's projects. With OIDC, a run can read the key only from
mainin theproject-boardenvironment. CloudTrail records each read. To rotate the key, an admin updates the secret.Testing done
actionlintwith shellcheck is clean.sts:AssumeRoleWithWebIdentityfor GitHub's OIDC provider, withStringEqualsonsubandaudand no wildcards. The permission policy has one statement, which allowssecretsmanager:GetSecretValueon the board App's secret.PutSecretValueandDeleteSecreton that secret, andGetSecretValueon a secret whose name starts with the same text.Checklist
cargo test --workspace)cargo fmt --check)cargo clippy -- -W clippy::pedantic)Storagetrait, auth model, on-diskformat, or public CLI surface, an RFC has been accepted or is linked
below. Otherwise, an ADR captures the decision (link below).
ADR / RFC: n/a. The change is to one CI workflow, and it follows #744.
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.