Skip to content

ci: use OIDC for ECR deployment - #3029

Merged
fahreddinozcan merged 2 commits into
masterfrom
ctx7-1981-update-actions-to-use-oidc-and-roles
Aug 13, 2026
Merged

ci: use OIDC for ECR deployment#3029
fahreddinozcan merged 2 commits into
masterfrom
ctx7-1981-update-actions-to-use-oidc-and-roles

Conversation

@fahreddinozcan

@fahreddinozcan fahreddinozcan commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • replace static AWS access keys in the ECR deployment workflow with GitHub OIDC role assumption
  • grant the workflow only contents: read and id-token: write
  • validate the expected AWS account, mask the account ID in logs, and use a per-run role session name
  • retain the ECR registry and repository as GitHub secrets

Required configuration

Before running the workflow, create these GitHub repository secrets:

  • AWS_ECR_ROLE_ARN
  • AWS_ACCOUNT_ID
  • AWS_REGION
  • ECR_REGISTRY
  • ECR_REPOSITORY

The IAM role must trust:

repo:upstash/context7:ref:refs/heads/master

and grant ECR push access only to:

arn:aws:ecr:us-east-1:640168447591:repository/context7mcp

After a successful OIDC deployment, only the legacy AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY secrets can be removed and the github-actions-context7-mcp IAM user can be retired.

Validation

  • git diff --check
  • parsed .github/workflows/ecr-deploy.yml as YAML
  • live deployment not run because the IAM role and repository variables must be configured first

@linear-code

linear-code Bot commented Aug 13, 2026

Copy link
Copy Markdown

CTX7-1981

@fahreddinozcan
fahreddinozcan marked this pull request as ready for review August 13, 2026 10:28

Copilot AI 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.

Pull request overview

This PR updates the ECR deployment workflow to authenticate to AWS via GitHub OIDC role assumption instead of long-lived AWS access keys, while tightening workflow token permissions.

Changes:

  • Add explicit workflow permissions for OIDC (id-token: write) and minimal repo access (contents: read).
  • Switch aws-actions/configure-aws-credentials to assume an IAM role (role-to-assume) instead of using static access keys.
  • Add account allowlisting/masking and a per-run role session name for safer, more traceable credential use.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +11 to +13
permissions:
contents: read
id-token: write

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

actions: write is not required here. BuildKit’s type=gha backend uses the GitHub-provided ACTIONS_RUNTIME_TOKEN, and docker/build-push-action automatically supplies the cache URL and token. We also have the same contents: read + id-token: write configuration running successfully with GHA cache import/export in context7parser. Keeping the current permissions preserves least privilege.

@fahreddinozcan
fahreddinozcan merged commit 449bc6c into master Aug 13, 2026
2 checks passed
@fahreddinozcan
fahreddinozcan deleted the ctx7-1981-update-actions-to-use-oidc-and-roles branch August 13, 2026 11:38
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
role-to-assume: ${{ secrets.AWS_ECR_ROLE_ARN }}
aws-region: ${{ secrets.AWS_REGION }}
allowed-account-ids: ${{ secrets.AWS_ACCOUNT_ID }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

allowed-account-ids fails open when this secret is empty, so the guardrail can silently disappear.

In configure-aws-credentials@v6 the input is parsed as getInput('allowed-account-ids').split(','), and the check bails out early when the first element is an empty string:

// src/helpers.ts:169
export function validateAccountId(expectedAccountIds: string[] | undefined, account: string | undefined): void {
  if (!expectedAccountIds || expectedAccountIds.length === 0 || expectedAccountIds[0] === '') {
    return;
  }
  ...
}

An unset, renamed, or typo'd AWS_ACCOUNT_ID therefore turns the account check into a no-op with no warning and no failure — the deploy just proceeds unguarded. The secret does exist today, so this works as intended right now; it's a latent trap for whenever secrets get rotated or renamed.

The earlier revision of this PR had the literal allowed-account-ids: "640168447591", which can't go missing. The account ID isn't really a secret either — it's already embedded in the role ARN and in the ECR registry hostname — so a literal or a repo variable would be a safer home for it than a secret.

Related nit on the next line: mask-aws-account-id: true is redundant when the ID comes from a secret (GitHub already masks it), and its main effect is to render the guardrail's own failure message as does not match any of the expected account IDs: *** — which is exactly the message you want readable when it trips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants