Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions docs/administration/user-groups/workload-identity/gitlab-ci.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
---
title: Workload Identity for GitLab CI/CD
---

This guide explains how to configure Workload Identity for GitLab CI/CD to authenticate with Bytebase without storing long-lived credentials.

## Step 1: Create a Workload Identity in Bytebase

1. Go to **IAM & Admin** > **Users & Groups**.
2. Click **Add User** in the upper-right corner.
3. Select **Workload Identity** as the Type.
4. Fill in the configuration:

| Field | Description | Example |
|-------|-------------|---------|
| **Name** | Display name for this identity | `GitLab Deploy` |
| **Email** | Unique email prefix (automatically appended with `@workload.bytebase.com`) | `gitlab-deploy` |
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

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

The email field description is inconsistent with the GitHub Actions documentation. In the GitHub Actions guide (line 17), it states 'Unique email for this identity (must end with @workload.bytebase.com)' suggesting users should provide the full email. However, this documentation suggests users provide only the prefix. This inconsistency could confuse users. Please clarify whether users should provide the full email or just the prefix.

Suggested change
| **Email** | Unique email prefix (automatically appended with `@workload.bytebase.com`) | `gitlab-deploy` |
| **Email** | Unique email for this identity (must end with `@workload.bytebase.com`) | `gitlab-deploy@workload.bytebase.com` |

Copilot uses AI. Check for mistakes.
| **Platform** | Select GitLab CI | `GitLab CI` |
| **Group / Username** | GitLab group or username (required) | `my-group` |
| **Project** | Project name (leave empty to allow all projects) | `my-project` |
| **Allowed Branches/Tags** | Select branch/tag restrictions | `All branches and tags` |
| **Roles** | Assign workspace roles | `GitOps Service Agent` |

5. 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:

1. Go to your project's **Settings** > **Members**.
2. Click **Grant Access**.
3. Enter the Workload Identity email (e.g., `gitlab-ci-deploy@workload.bytebase.com`).
4. Select the **GitOps Service Agent** role.
5. Click **Confirm**.

<Tip>

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](/administration/roles) for details.

</Tip>

## Step 3: Configure GitLab CI/CD Pipeline

In your GitLab CI/CD pipeline, add the following configuration:

### Request OIDC Token

Add `id_tokens` configuration to get the JWT token from GitLab:

```yaml
stages:
- deploy

deploy-database:
stage: deploy
image: alpine:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
variables:
BYTEBASE_URL: https://bytebase.example.com
WORKLOAD_IDENTITY_EMAIL: gitlab-ci-deploy@workload.bytebase.com
before_script:
- apk add --no-cache curl jq
script:
- |
# Exchange GitLab OIDC token for Bytebase API token
RESPONSE=$(curl -s -X POST "${BYTEBASE_URL}/v1/auth:exchangeToken" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${GITLAB_OIDC_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

# Verify the token by calling the user info API
USER_INFO=$(curl -s "${BYTEBASE_URL}/v1/users/me" \
-H "Authorization: Bearer $ACCESS_TOKEN")
echo "Authenticated as: $USER_INFO"
rules:
- if: $CI_COMMIT_BRANCH == "main"
```

## Complete Example

Here's a complete GitOps workflow that uses Workload Identity to deploy database migrations:

```yaml
# .gitlab-ci.yml
stages:
- review
- deploy

variables:
BYTEBASE_URL: https://bytebase.example.com
WORKLOAD_IDENTITY_EMAIL: gitlab-deploy@workload.bytebase.com

# SQL Review on merge requests
sql-review:
stage: review
image: bytebase/sql-review-action:latest
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

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

Incorrect Docker image reference. Based on other GitLab CI/CD examples in the codebase (e.g., docs/gitops/migration-based-workflow/sql-review-ci.mdx line 63), GitLab CI should use bytebase/bytebase-action:latest, not bytebase/sql-review-action:latest. The sql-review-action is a GitHub Action and cannot be used as a Docker image in GitLab CI.

Suggested change
image: bytebase/sql-review-action:latest
image: bytebase/bytebase-action:latest

Copilot uses AI. Check for mistakes.
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
script:
- |
# Exchange OIDC token for Bytebase token
export BYTEBASE_TOKEN=$(curl -s -X POST "${BYTEBASE_URL}/v1/auth:exchangeToken" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${GITLAB_OIDC_TOKEN}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}" \
| jq -r '.accessToken')

# Run SQL review
sql-review --url ${BYTEBASE_URL} --token ${BYTEBASE_TOKEN} \
--file-pattern "migrations/**/*.sql"
Comment on lines +117 to +118
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

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

Incorrect command for SQL review. Based on the bytebase-action Docker image usage in other GitLab CI examples (e.g., docs/gitops/migration-based-workflow/sql-review-ci.mdx line 69), the correct command should be bytebase-action check instead of sql-review. The command format should match the established pattern used in GitLab CI pipelines.

Copilot uses AI. Check for mistakes.
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- migrations/**

# Deploy on merge to main
rollout:
stage: deploy
image: bytebase/bytebase-action:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
script:
- |
# Exchange OIDC token for Bytebase token
export BYTEBASE_TOKEN=$(curl -s -X POST "${BYTEBASE_URL}/v1/auth:exchangeToken" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${GITLAB_OIDC_TOKEN}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}" \
| jq -r '.accessToken')

# Create release and rollout
bytebase-action rollout \
--url ${BYTEBASE_URL} \
--token ${BYTEBASE_TOKEN} \
--file-pattern "migrations/**/*.sql" \
--project projects/my-project \
--targets instances/prod/databases/mydb
rules:
- if: $CI_COMMIT_BRANCH == "main"
changes:
- migrations/**
```

<Tip>

For more details on GitOps workflows, see [GitOps Overview](/gitops/overview) and [Migration-Based Workflow](/gitops/migration-based-workflow/overview).

</Tip>

## Self-Hosted GitLab

For self-hosted GitLab instances, update the audience (`aud`) to match your GitLab instance URL:

```yaml
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.your-company.com
```

When creating the Workload Identity in Bytebase, ensure the configuration matches your self-hosted GitLab instance.

## Troubleshooting

### Token Exchange Fails

If the token exchange returns an error:

1. **Verify the project path and branch**: Check that your pipeline's project path and branch match the configured values in Bytebase.

2. **Check the audience**: Ensure the `aud` in your `id_tokens` configuration matches your GitLab instance URL (e.g., `https://gitlab.com` for GitLab.com).

3. **Verify OIDC is enabled**: GitLab CI/CD OIDC tokens require GitLab 15.7 or later.

### Permission Denied

If API calls return permission errors:

1. Verify the Workload Identity has the `GitOps Service Agent` role assigned.
2. Check that the Workload Identity is a member of the target project.

### Debug Token Claims

To inspect the OIDC token claims, decode the JWT:

```yaml
script:
- |
echo "$GITLAB_OIDC_TOKEN" | cut -d. -f2 | base64 -d | jq .
```

This shows the token's claims including `sub`, `aud`, `namespace_path`, `project_path`, and `ref` that Bytebase validates.
3 changes: 2 additions & 1 deletion docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@
"group": "Users & Groups",
"pages": [
"administration/user-groups/overview",
"administration/user-groups/workload-identity/github-actions"
"administration/user-groups/workload-identity/github-actions",
"administration/user-groups/workload-identity/gitlab-ci"
]
},
"administration/roles",
Expand Down