Documentation Index
Fetch the complete documentation index at: https://docs.bytebase.com/llms.txt
Use this file to discover all available pages before exploring further.
This guide explains how to configure Workload Identity for GitHub Actions to authenticate with Bytebase without storing long-lived credentials.
Step 1: Create a Workload Identity in Bytebase
- Go to IAM & Admin > Users & Groups.
- Click Add User in the upper-right corner.
- Select Workload Identity as the Type.
- Fill in the configuration:
| Field | Description | Example |
|---|
| Name | Display name for this identity | GitHub Actions Deploy |
| Email | Unique email for this identity (must end with @workload.bytebase.com) | github-actions-deploy@workload.bytebase.com |
| Platform | Select GitHub Actions | GitHub Actions |
| Owner | GitHub organization or username | my-org |
| Repository | Repository name | my-repo |
| Branch | Branch name (use * for all branches) | main |
- Click Confirm to create the Workload Identity.
Step 2: Assign Roles
After creating the Workload Identity, assign the GitOps Service Agent role to enable automated CI/CD workflows:
- Go to your project’s Settings > Members.
- Click Grant Access.
- Enter the Workload Identity email (e.g.,
github-actions-deploy@workload.bytebase.com).
- Select the GitOps Service Agent role.
- Click Confirm.
The GitOps Service Agent role is designed for automated CI/CD workflows, allowing the identity to create and execute database changes. See Roles and Permissions for details.
In your GitHub Actions workflow, add the following configuration:
Request OIDC Token
Add id-token: write permission and use the actions/github-script action to get the token:
name: Deploy Database Changes
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC token
contents: read
env:
BYTEBASE_URL: https://bytebase.example.com
WORKLOAD_IDENTITY_EMAIL: github-actions-deploy@workload.bytebase.com
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get Bytebase Token
id: bytebase-token
uses: actions/github-script@v7
with:
script: |
const token = await core.getIDToken('https://github.com/${{ github.repository_owner }}');
core.setSecret(token);
core.setOutput('token', token);
- name: Exchange for Bytebase API Token
id: exchange
run: |
RESPONSE=$(curl -s -X POST "${BYTEBASE_URL}/v1/auth:exchangeToken" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${{ steps.bytebase-token.outputs.token }}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}")
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.accessToken')
echo "::add-mask::$ACCESS_TOKEN"
echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT
- name: Call Bytebase API
run: |
curl -s "${BYTEBASE_URL}/v1/projects" \
-H "Authorization: Bearer ${{ steps.exchange.outputs.access_token }}"
Complete Example
Here’s a complete workflow that creates a database change using Workload Identity:
name: Database Schema Change
on:
push:
branches: [main]
paths:
- 'migrations/**'
permissions:
id-token: write
contents: read
env:
BYTEBASE_URL: https://bytebase.example.com
WORKLOAD_IDENTITY_EMAIL: github-actions-deploy@workload.bytebase.com
PROJECT: projects/my-project
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get OIDC Token
id: oidc
uses: actions/github-script@v7
with:
script: |
const token = await core.getIDToken('https://github.com/${{ github.repository_owner }}');
core.setSecret(token);
core.setOutput('token', token);
- name: Exchange Token
id: auth
run: |
RESPONSE=$(curl -s -X POST "${BYTEBASE_URL}/v1/auth:exchangeToken" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${{ steps.oidc.outputs.token }}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}")
ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.accessToken')
if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then
echo "Failed to get access token"
echo $RESPONSE
exit 1
fi
echo "::add-mask::$ACCESS_TOKEN"
echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT
- name: Create Plan
id: plan
run: |
# Read migration SQL file
SQL_CONTENT=$(cat migrations/latest.sql | jq -Rs .)
RESPONSE=$(curl -s -X POST "${BYTEBASE_URL}/v1/${PROJECT}/plans" \
-H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Migration from GitHub Actions\",
\"steps\": [{
\"specs\": [{
\"changeDatabaseConfig\": {
\"target\": \"instances/prod/databases/mydb\",
\"type\": \"MIGRATE\",
\"sheet\": \"${SQL_CONTENT}\"
}
}]
}]
}")
PLAN_NAME=$(echo $RESPONSE | jq -r '.name')
echo "plan_name=$PLAN_NAME" >> $GITHUB_OUTPUT
Troubleshooting
Token Exchange Fails
If the token exchange returns an error:
-
Verify the repository and branch: Check that your workflow’s repository, branch match the configured values in Bytebase.
-
Check the audience: Ensure the audience in your
getIDToken() call matches https://github.com/{owner}.
Permission Denied
If API calls return permission errors:
- Verify the Workload Identity has the
GitOps Service Agent role assigned.
- Check that the Workload Identity is a member of the target project.
Debug Token Claims
To inspect the OIDC token claims, decode the JWT:
- name: Debug Token
run: |
echo "${{ steps.oidc.outputs.token }}" | cut -d. -f2 | base64 -d | jq .
This shows the token’s claims including sub, aud, and iss that Bytebase validates.