AWS Builder Center
@claude in Your PRs, on Your Terms: Using Claude Code Action with Amazon Bedrock

@claude in Your PRs, on Your Terms: Using Claude Code Action with Amazon Bedrock

Data in your account. Guardrails you control. Full audit trail. No secrets to rotate.

The anthropics/claude-code-action lets you drop @claude in any GitHub issue or PR comment and get an agentic coding assistant to respond — reviewing code, implementing fixes, writing tests, opening PRs. You can run it against Anthropic's API or point it at Amazon Bedrock. Both work. The right choice depends on what your team needs.
This post covers the Bedrock path — what it unlocks for teams that want platform-level governance, private networking, and AWS-native controls, and why running Claude in GitHub Actions is a fundamentally better way to work than local sessions: parallel branches, no laptop dependency, and agents scoped to exactly the credentials they need rather than inheriting everything you have.

What the Bedrock path gives you

Data stays in your AWS account. Every model invocation goes through Bedrock in a region you control. Prompts and code don't leave your AWS environment, which matters for teams with data residency requirements or security reviews gating AI adoption.
Platform-level content controls. Amazon Bedrock Guardrails  gives you admin-configurable content filters, PII redaction, denied topics, and prompt injection detection — applied to every Claude invocation across your account.
AWS-native audit trail. Bedrock model invocation logging captures full input/output to S3 or CloudWatch. CloudTrail records every API call. You can break down token usage by IAM principal using CloudWatch Logs Insights grouped by identity.arn — the same observability patterns you'd use for any other AWS service.
IAM as your access control plane. Permissions flow through the same IAM policies, roles, and SCPs you use for everything else. Per-request metadata tagging lets you split spend by team, environment, or application in Cost Explorer.

How the request flows

1
2
3
4
5
GitHub issue comment (@claude)
→ GitHub Actions runner (ubuntu-latest)
→ OIDC token exchange → IAM role (no stored credentials)
→ Amazon Bedrock (Claude Sonnet, in your account)
→ response posted back to GitHub via github.token
Two auth concerns, cleanly separated:
  • AWS access — OIDC short-lived credentials (~15 min), nothing stored anywhere
  • GitHub access — the built-in github.token every Actions run already has

Prerequisites

  • An AWS account with access to Claude Sonnet 4.6 on Bedrock. As of October 2025, the Model Access page has been retired — all serverless foundation models are enabled automatically on first invocation. For Anthropic models specifically, first-time users need to submit use case details once: open the Bedrock → Model catalog, select any Anthropic Claude model, and complete the short form. Access is granted immediately, and submitting at the organization's management account covers all member accounts.
  • GitHub CLI (gh) authenticated
  • AWS CLI configured with permissions to create IAM roles

Step 1 — Register the GitHub OIDC provider (one-time per AWS account)

GitHub Actions can exchange a short-lived OIDC token for temporary AWS credentials. First, tell your AWS account to trust GitHub's identity provider.
You only ever do this once per AWS account. In the console, go to IAM → Identity providers → Add provider, select OpenID Connect, and enter:
  • Provider URL: https://token.actions.githubusercontent.com
  • Audience: sts.amazonaws.com
Or via the CLI:
1
2
3
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com
Check if it already exists before running this:
1
aws iam list-open-id-connect-providers

Step 2 — Create an IAM role

Create a role that GitHub Actions can assume via OIDC, scoped to your specific repository. Use the following as the trust policy — swap in your account ID and repo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:YOUR_ORG/YOUR_REPO:*"
}
}
}
]
}
Attach an inline policy granting Bedrock invocation:
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "*"
}
]
}
Or automate the whole thing with a setup script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env bash
set -euo pipefail

ROLE_NAME="GitHubActions-ClaudeCodeAction"
REPO="your-org/your-repo"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
OIDC_ARN="arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"

TRUST=$(cat <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "${OIDC_ARN}" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
"StringLike": { "token.actions.githubusercontent.com:sub": "repo:${REPO}:*" }
}
}]
}
EOF

)

PERMS=$(cat <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
"Resource": "*"
}]
}
EOF

)

aws iam create-role --role-name "$ROLE_NAME" \
--assume-role-policy-document "$TRUST" \
--description "GitHub Actions OIDC role for claude-code-action" > /dev/null

aws iam put-role-policy --role-name "$ROLE_NAME" \
--policy-name "BedrockInvoke" --policy-document "$PERMS"

ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query Role.Arn --output text)
echo "Role ARN: $ROLE_ARN"

gh secret set AWS_ROLE_TO_ASSUME --body "$ROLE_ARN" --repo "$REPO"
echo "Secret AWS_ROLE_TO_ASSUME set on $REPO"

Step 3 — Add the workflow

Create .github/workflows/claude.yml in your repository:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
name: Claude Code Action

permissions:
contents: write
pull-requests: write
issues: write
id-token: write # required for OIDC → AWS credentials

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]

env:
AWS_REGION: us-east-1

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}

- uses: anthropics/claude-code-action@v1
with:
github_token: ${{ github.token }}
use_bedrock: "true"
claude_args: "--model us.anthropic.claude-sonnet-4-6 --max-turns 5"
A few things worth noting here:
github_token: ${{ github.token }} — This is the built-in token every Actions run already has. No custom GitHub App, no .pem file, no extra secrets. Claude will post comments as github-actions[bot].
id-token: write — Despite the name, this doesn't write anything. It grants the runner permission to request a short-lived JWT from GitHub's OIDC endpoint. That JWT contains signed claims about the workflow run (repo, branch, workflow path) — a statement from GitHub that this request genuinely comes from your repo. Without this permission, the runner can't get the JWT and the OIDC exchange never starts. configure-aws-credentials takes the JWT and sends it to AWS STS's AssumeRoleWithWebIdentity API, which validates it against the OIDC provider you registered and hands back temporary credentials scoped to the IAM role.
use_bedrock: "true" — Tells claude-code-action to call Bedrock instead of the Anthropic API. The action picks up the AWS credentials from the environment automatically.
--model us.anthropic.claude-sonnet-4-6 — Bedrock model IDs require a region prefix (us., eu., ap.). The plain claude-sonnet-4-6 ID used with the Anthropic API will not work here.

Step 4 — Test it

Push the workflow and open an issue:
1
2
3
gh issue create \
--title "Test: @claude via Bedrock" \
--body "@claude can you say hello and confirm which model you are running on?"
Within about a minute you should see a comment back from github-actions[bot] confirming the model ID and that it reached Bedrock.

Things that will trip you up

Sonnet 4.6 is CRIS-only — there are no in-region endpoints. Claude Sonnet 4.6 is only available through Cross-Region Inference (CRIS) profiles: us.anthropic.claude-sonnet-4-6, eu.anthropic.claude-sonnet-4-6, ap.anthropic.claude-sonnet-4-6, or global.anthropic.claude-sonnet-4-6. You cannot call it with a bare anthropic.claude-sonnet-4-6 model ID. Pick the CRIS profile that matches where your traffic should route.
Model access is still required even with CRIS. You don't need to enable access per region, but you do still need to go to Bedrock → Model access and accept the EULA once per account.
--max-turns is your cost guard. Each agentic turn is a separate Bedrock API call billed to your account. Set a low value (3–5) while testing and raise it once you know how your typical tasks look.
github.token has limited scope by default. If Claude tries to push to a branch or open a PR on a fork, it may hit permission errors. For those use cases a custom GitHub App token gives you more control — but for typical in-repo tasks the built-in token is sufficient.

Who this is for

The Bedrock path is a natural fit for teams that want private networking and data residency, need platform-level guardrails and audit controls that satisfy a security review, or are already running other AI workloads through Bedrock and want a consistent governance model across all of them.
If none of those are constraints for your team, Anthropic's hosted option is simpler to set up and gives you Anthropic's admin console, SSO, SCIM, and spend controls out of the box.
The setup here is also notably minimal: no credentials to rotate, no API keys to accidentally commit, nothing stored in GitHub Secrets beyond a role ARN. Every AWS access token lives for ~15 minutes and is scoped to a specific repository and workflow.

A better way to work with agentic coding

Before this workflow existed, the common pattern was multiple VS Code windows open side by side, each running its own Claude Code session. It worked, but it created real friction: sessions on the same repo would step on each other — editing the same files, conflicting on the same git state. Working on multiple branches concurrently was painful. And when you closed your laptop at the end of the day, everything stopped. The agent had no way to keep going without you.
There's also a subtler problem with local Claude Code sessions that's easy to miss: the agent inherits your full user context. It runs bash commands as you, with your filesystem access, your AWS credentials, your SSH keys, your dotfiles. Convenient — but it means a runaway or misdirected agent has broad access to everything you do.
GitHub Actions flips all of this. Each @claude invocation runs in a clean, ephemeral container with a fresh checkout of the exact branch and commit it's working on. Concurrent runs on different branches don't interfere — they never share a filesystem. The agent keeps running after you close your laptop; you come back to a completed PR or a comment waiting for your review. And crucially, its only credentials are the ones you explicitly granted: an IAM role scoped to Bedrock invocation and a github.token scoped to the repository. It can't touch anything else.
The result is agentic coding that runs at the pace of GitHub, not the pace of your laptop — parallel, persistent, and least-privilege by design.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article