From 3ea20cb3d8e5c735ff15d1e3c1c4d7f8b0f6b561 Mon Sep 17 00:00:00 2001 From: adela Date: Mon, 23 Feb 2026 13:44:23 +0100 Subject: [PATCH 01/12] update sso docs --- docs/administration/sso/idp-initiated.mdx | 27 ++----------------- docs/administration/sso/oidc-entra-id.mdx | 10 +++++-- docs/administration/sso/oidc.mdx | 6 +++++ docs/administration/sso/overview.mdx | 33 ++++++++++++++++++----- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/docs/administration/sso/idp-initiated.mdx b/docs/administration/sso/idp-initiated.mdx index d12837098..17134f96c 100644 --- a/docs/administration/sso/idp-initiated.mdx +++ b/docs/administration/sso/idp-initiated.mdx @@ -2,32 +2,9 @@ title: IdP-Initiated Flow --- -Identity Provider-initiated (IdP-initiated) flow allows users to access Bytebase directly from their identity provider's dashboard or portal, without needing to first visit Bytebase and click a "Sign in with..." button. +By default, SSO uses a **Service Provider-initiated (SP-initiated)** flow: users visit Bytebase, click "Sign in with X", get redirected to the identity provider, then back. **IdP-initiated** flow reverses this — users click the Bytebase tile directly from their identity provider's dashboard (e.g. Okta portal) and land in Bytebase already authenticated. -## Overview - -In a traditional Service Provider-initiated (SP-initiated) flow, the authentication process starts when a user tries to access Bytebase and clicks the SSO login button. With IdP-initiated flow, the process begins at the identity provider's side—for example, when a user clicks the Bytebase tile in their Okta dashboard. - -### IdP-Initiated vs SP-Initiated - -**SP-Initiated (Traditional Flow)**: - -1. User visits Bytebase -2. User clicks "Sign in with Okta" button -3. User is redirected to Okta for authentication -4. After authentication, user is redirected back to Bytebase - -**IdP-Initiated Flow**: - -1. User is already logged into their IdP (e.g., Okta) -2. User clicks Bytebase tile/bookmark in their IdP dashboard -3. User is directly authenticated and redirected to Bytebase - -### Benefits - -- **Streamlined user experience**: Users can access Bytebase with a single click from their IdP dashboard -- **Centralized access**: All applications are accessible from one place (the IdP portal) -- **Reduced friction**: Eliminates the extra step of clicking the SSO button in Bytebase +This eliminates the extra step of visiting Bytebase first and works with both OAuth 2.0 and OIDC providers. ## Prerequisites diff --git a/docs/administration/sso/oidc-entra-id.mdx b/docs/administration/sso/oidc-entra-id.mdx index 56bdba62b..f697565d5 100644 --- a/docs/administration/sso/oidc-entra-id.mdx +++ b/docs/administration/sso/oidc-entra-id.mdx @@ -1,8 +1,14 @@ --- -title: Microsoft Entra ID (Azure AD) OIDC +title: OIDC with Microsoft Entra ID --- -Microsoft Entra ID (formerly Azure Active Directory) can be configured as an OpenID Connect (OIDC) identity provider for Bytebase, providing secure Single Sign-On with group synchronization support. +This guide walks through configuring Microsoft Entra ID (formerly Azure Active Directory) as an [OIDC](/administration/sso/oidc) identity provider for Bytebase, including group synchronization. + + + +Entra ID can also be configured via [OAuth 2.0](/administration/sso/oauth2#microsoft-entra-azure-ad) if you don't need group syncing or OIDC-specific features. + + diff --git a/docs/administration/sso/oidc.mdx b/docs/administration/sso/oidc.mdx index d7c218b2a..3ceb0739d 100644 --- a/docs/administration/sso/oidc.mdx +++ b/docs/administration/sso/oidc.mdx @@ -4,6 +4,12 @@ title: OpenID Connect (OIDC) OpenID Connect (OIDC) is a simple identity layer on top of the OAuth 2.0 protocol. Bytebase supports using OIDC for configuring Single Sign-On (SSO). + + +For **Microsoft Entra ID (Azure AD)**, see the dedicated [Entra ID OIDC guide](/administration/sso/oidc-entra-id) which covers app registration, API permissions, group claims, and troubleshooting. + + + ## Configuration diff --git a/docs/administration/sso/overview.mdx b/docs/administration/sso/overview.mdx index 907742289..9da9c2ea4 100644 --- a/docs/administration/sso/overview.mdx +++ b/docs/administration/sso/overview.mdx @@ -4,13 +4,34 @@ title: Overview Single Sign-On (SSO) is an authentication method that enables users to securely authenticate with multiple applications and websites by using just one set of credentials. -Bytebase supports the following standard protocols that provide SSO: +## Supported Protocols -- [OAuth 2.0](/administration/sso/oauth2) -- [OpenID Connect (OIDC)](/administration/sso/oidc) -- [Microsoft Entra ID (Azure AD) OIDC](/administration/sso/oidc-entra-id) -- [Lightweight Directory Access Protocol (LDAP)](/administration/sso/ldap) -- [IdP-Initiated Flow](/administration/sso/idp-initiated) - Access Bytebase directly from your identity provider's dashboard +Bytebase supports three SSO protocols: + +- **[OAuth 2.0](/administration/sso/oauth2)** — Authorization protocol. Bytebase gets a token and fetches your profile from the provider. Good for providers that don't support OIDC (e.g. GitHub). +- **[OpenID Connect (OIDC)](/administration/sso/oidc)** — Identity layer built on top of OAuth 2.0. Adds a standardized ID token so Bytebase gets user info directly. Preferred when available. +- **[LDAP](/administration/sso/ldap)** — Directory lookup protocol. Bytebase queries a user directory directly with username/password. No browser redirects involved. + +## Authentication Flow + +There are two ways SSO authentication can start: + +- **SP-Initiated (default)** — User visits Bytebase, clicks "Sign in with X", gets redirected to the identity provider, then back to Bytebase after authentication. +- **[IdP-Initiated](/administration/sso/idp-initiated)** — User clicks the Bytebase tile directly from their identity provider's dashboard (e.g. Okta portal) and lands in Bytebase already authenticated. Works with OAuth 2.0 and OIDC providers. + +## Which Protocol to Use + +| Identity Provider | Recommended Protocol | Notes | +|---|---|---| +| Google | [OIDC](/administration/sso/oidc#google) | Also available via [OAuth 2.0](/administration/sso/oauth2#google) | +| GitHub | [OAuth 2.0](/administration/sso/oauth2#github) | GitHub does not support OIDC | +| GitLab | [OIDC](/administration/sso/oidc#gitlab) | Also available via [OAuth 2.0](/administration/sso/oauth2#gitlab) | +| Microsoft Entra ID (Azure AD) | [OIDC](/administration/sso/oidc-entra-id) | Dedicated guide with group sync. Also available via [OAuth 2.0](/administration/sso/oauth2#microsoft-entra-azure-ad) | +| Okta | [OIDC](/administration/sso/oidc#okta) | Also available via [LDAP](/administration/sso/ldap#okta) | +| Keycloak | [OIDC](/administration/sso/oidc#keycloak) | | +| Casdoor | [OIDC](/administration/sso/oidc#casdoor) | | +| Authing | [OIDC](/administration/sso/oidc#authing) | | +| JumpCloud | [LDAP](/administration/sso/ldap#jumpcloud) | | ## Prerequisites From 72e58415bdc262530e3bf7dcefdb5de153e9f944 Mon Sep 17 00:00:00 2001 From: adela Date: Mon, 23 Feb 2026 14:00:56 +0100 Subject: [PATCH 02/12] update --- docs/administration/sso/overview.mdx | 32 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/administration/sso/overview.mdx b/docs/administration/sso/overview.mdx index 9da9c2ea4..359f2655a 100644 --- a/docs/administration/sso/overview.mdx +++ b/docs/administration/sso/overview.mdx @@ -19,19 +19,29 @@ There are two ways SSO authentication can start: - **SP-Initiated (default)** — User visits Bytebase, clicks "Sign in with X", gets redirected to the identity provider, then back to Bytebase after authentication. - **[IdP-Initiated](/administration/sso/idp-initiated)** — User clicks the Bytebase tile directly from their identity provider's dashboard (e.g. Okta portal) and lands in Bytebase already authenticated. Works with OAuth 2.0 and OIDC providers. +## User & Group Provisioning (SCIM) + +SSO handles **authentication** (who is this person), but not **provisioning** (creating/updating/deactivating accounts). For automatic user and group provisioning, Bytebase supports [SCIM 2.0](/administration/scim/overview) with [Entra ID](/administration/scim/entra-id) and [Okta](/administration/scim/okta). + + + +SCIM requires the IdP to communicate with Bytebase over HTTP. **LDAP does not support SCIM** — if you need SCIM with a provider like Microsoft Entra ID, you must configure SSO via [OIDC](/administration/sso/oidc-entra-id) or [OAuth 2.0](/administration/sso/oauth2#microsoft-entra-azure-ad), not LDAP. + + + ## Which Protocol to Use -| Identity Provider | Recommended Protocol | Notes | -|---|---|---| -| Google | [OIDC](/administration/sso/oidc#google) | Also available via [OAuth 2.0](/administration/sso/oauth2#google) | -| GitHub | [OAuth 2.0](/administration/sso/oauth2#github) | GitHub does not support OIDC | -| GitLab | [OIDC](/administration/sso/oidc#gitlab) | Also available via [OAuth 2.0](/administration/sso/oauth2#gitlab) | -| Microsoft Entra ID (Azure AD) | [OIDC](/administration/sso/oidc-entra-id) | Dedicated guide with group sync. Also available via [OAuth 2.0](/administration/sso/oauth2#microsoft-entra-azure-ad) | -| Okta | [OIDC](/administration/sso/oidc#okta) | Also available via [LDAP](/administration/sso/ldap#okta) | -| Keycloak | [OIDC](/administration/sso/oidc#keycloak) | | -| Casdoor | [OIDC](/administration/sso/oidc#casdoor) | | -| Authing | [OIDC](/administration/sso/oidc#authing) | | -| JumpCloud | [LDAP](/administration/sso/ldap#jumpcloud) | | +| Identity Provider | Recommended Protocol | [SCIM](/administration/scim/overview) | Notes | +|---|---|---|---| +| Google | [OIDC](/administration/sso/oidc#google) | — | Also available via [OAuth 2.0](/administration/sso/oauth2#google) | +| GitHub | [OAuth 2.0](/administration/sso/oauth2#github) | — | GitHub does not support OIDC | +| GitLab | [OIDC](/administration/sso/oidc#gitlab) | — | Also available via [OAuth 2.0](/administration/sso/oauth2#gitlab) | +| Microsoft Entra ID (Azure AD) | [OIDC](/administration/sso/oidc-entra-id) | [Yes](/administration/scim/entra-id) | Also available via [OAuth 2.0](/administration/sso/oauth2#microsoft-entra-azure-ad) | +| Okta | [OIDC](/administration/sso/oidc#okta) | [Yes](/administration/scim/okta) | Also available via [LDAP](/administration/sso/ldap#okta) (no SCIM) | +| Keycloak | [OIDC](/administration/sso/oidc#keycloak) | — | | +| Casdoor | [OIDC](/administration/sso/oidc#casdoor) | — | | +| Authing | [OIDC](/administration/sso/oidc#authing) | — | | +| JumpCloud | [LDAP](/administration/sso/ldap#jumpcloud) | — | | ## Prerequisites From 53763003e812d1c7fbe74383191241287863a7d0 Mon Sep 17 00:00:00 2001 From: adela Date: Mon, 23 Feb 2026 14:06:37 +0100 Subject: [PATCH 03/12] reorder --- docs/docs.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index 84057acf5..509e65465 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -231,6 +231,15 @@ { "group": "Security", "pages": [ + { + "group": "Users & Groups", + "pages": [ + "administration/user-groups/overview", + "administration/user-groups/workload-identity/github-actions", + "administration/user-groups/workload-identity/gitlab-ci" + ] + }, + "administration/roles", { "group": "Single Sign-On", "pages": [ @@ -242,15 +251,6 @@ "administration/sso/idp-initiated" ] }, - { - "group": "Users & Groups", - "pages": [ - "administration/user-groups/overview", - "administration/user-groups/workload-identity/github-actions", - "administration/user-groups/workload-identity/gitlab-ci" - ] - }, - "administration/roles", { "group": "SCIM", "pages": [ @@ -259,8 +259,8 @@ "administration/scim/okta" ] }, - "administration/2fa", "administration/password", + "administration/2fa", "administration/sign-in-restriction" ] }, From f3e02a9b42fdd1e0bca53146f6b2bd7ae983068a Mon Sep 17 00:00:00 2001 From: adela Date: Mon, 23 Feb 2026 14:14:06 +0100 Subject: [PATCH 04/12] update --- docs/administration/service-account.mdx | 33 +++ docs/administration/user-groups/overview.mdx | 32 +-- .../workload-identity/github-actions.mdx | 205 ++++++++++++++++++ .../workload-identity/gitlab-ci.mdx | 199 +++++++++++++++++ .../workload-identity/overview.mdx | 29 +++ docs/docs.json | 10 +- 6 files changed, 480 insertions(+), 28 deletions(-) create mode 100644 docs/administration/service-account.mdx create mode 100644 docs/administration/workload-identity/github-actions.mdx create mode 100644 docs/administration/workload-identity/gitlab-ci.mdx create mode 100644 docs/administration/workload-identity/overview.mdx diff --git a/docs/administration/service-account.mdx b/docs/administration/service-account.mdx new file mode 100644 index 000000000..d7be879c2 --- /dev/null +++ b/docs/administration/service-account.mdx @@ -0,0 +1,33 @@ +--- +title: Service Account +--- + +Service accounts are machine identities designed for automated processes and applications. Unlike human [users](/administration/user-groups/overview), service accounts authenticate via API keys and are intended for programmatic access. + +## Workspace vs Project Level + +Service accounts can be created at two levels: + +- **Workspace level** — Has access governed by workspace IAM policies. Suitable for cross-project automation. +- **Project level** — Scoped to a single project, following the principle of least privilege. Suitable for isolated automation within one project. + +## Create a Service Account + +1. For workspace-level: go to **IAM & Admin** > **Service Accounts** tab and click **Add Service Account**. +2. For project-level: go to **Project** > **Settings** > **Service Accounts** and click **Add Service Account**. + + + +Service accounts cannot be part of [user groups](/administration/user-groups/overview). Since service accounts are for automated processes with specific access needs, including them in groups could grant unintended permissions. This is considered an [anti-pattern](https://cloud.google.com/iam/docs/best-practices-service-accounts#groups). + + + +## Service Account vs Workload Identity + +| | Service Account | [Workload Identity](/administration/workload-identity/overview) | +|---|---|---| +| **Credential** | Long-lived API key | Short-lived OIDC token | +| **Best for** | Scripts, Terraform, general API access | CI/CD pipelines (GitHub Actions, GitLab CI) | +| **Security** | Key must be stored as a secret | No secrets to manage | + +If your automation runs in a CI/CD platform that supports OIDC, prefer [Workload Identity](/administration/workload-identity/overview) for better security. diff --git a/docs/administration/user-groups/overview.mdx b/docs/administration/user-groups/overview.mdx index 4c1095e5a..4f3dc882b 100644 --- a/docs/administration/user-groups/overview.mdx +++ b/docs/administration/user-groups/overview.mdx @@ -1,39 +1,23 @@ --- -title: Overview +title: Users & Groups --- ## User -A `User` represents anyone who can access and perform operations in Bytebase. Users include both human team members and service accounts. +A `User` represents a human team member who can access and perform operations in Bytebase. -## Service Account - -Service accounts are special users designed for automated processes and applications. - -## Workload Identity - -Workload Identity is a secure authentication method for CI/CD pipelines and external services using OpenID Connect (OIDC) tokens, eliminating the need for long-lived credentials. - -Unlike traditional Service Accounts that require storing API keys as secrets, Workload Identity: -- Uses short-lived tokens generated per job -- Validates tokens against your CI/CD platform's identity provider -- Restricts access to specific repositories, branches, and workflows - -### Setup Workload Identity - - - - Configure OIDC authentication for GitHub Actions workflows - - +For machine identities, see [Service Accounts](/administration/service-account) and [Workload Identity](/administration/workload-identity/overview). ## User Group A `User Group` organizes multiple users together for easier permission management. Workspace admins create groups and add users, then assign these groups to roles within projects. -- Bytebase does not support nested groups. A group can only contain users, it can't contain another group. -- Service accounts cannot be part of user groups. Since service accounts are for automated processes with specific access needs, including them in groups could grant unintended permissions. This is considered an [anti-pattern](https://cloud.google.com/iam/docs/best-practices-service-accounts#groups). +Bytebase does not support nested groups. A group can only contain users, it can't contain another group. + + + +Service accounts cannot be part of user groups. Since service accounts are for automated processes with specific access needs, including them in groups could grant unintended permissions. This is considered an [anti-pattern](https://cloud.google.com/iam/docs/best-practices-service-accounts#groups). ## Add group diff --git a/docs/administration/workload-identity/github-actions.mdx b/docs/administration/workload-identity/github-actions.mdx new file mode 100644 index 000000000..c71da337b --- /dev/null +++ b/docs/administration/workload-identity/github-actions.mdx @@ -0,0 +1,205 @@ +--- +title: Workload Identity for GitHub Actions +--- + +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 + +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 | `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` | + +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., `github-actions-deploy@workload.bytebase.com`). +4. Select the **GitOps Service Agent** role. +5. 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](/administration/roles) for details. + + + +## Step 3: Configure GitHub Actions Workflow + +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: + +```yaml +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: + +```yaml +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-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: + +1. **Verify the repository and branch**: Check that your workflow's repository, branch match the configured values in Bytebase. + +2. **Check the audience**: Ensure the audience in your `getIDToken()` call matches `https://github.com/{owner}`. + +### 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 +- 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. diff --git a/docs/administration/workload-identity/gitlab-ci.mdx b/docs/administration/workload-identity/gitlab-ci.mdx new file mode 100644 index 000000000..cde83099d --- /dev/null +++ b/docs/administration/workload-identity/gitlab-ci.mdx @@ -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` | +| **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**. + + + +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. + + + +## 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 + 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" + 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/** +``` + + + +For more details on GitOps workflows, see [GitOps Overview](/gitops/overview) and [Migration-Based Workflow](/gitops/migration-based-workflow/overview). + + + +## 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. diff --git a/docs/administration/workload-identity/overview.mdx b/docs/administration/workload-identity/overview.mdx new file mode 100644 index 000000000..f275f7444 --- /dev/null +++ b/docs/administration/workload-identity/overview.mdx @@ -0,0 +1,29 @@ +--- +title: Overview +--- + +Workload Identity is a secure authentication method for CI/CD pipelines and external services using OpenID Connect (OIDC) tokens, eliminating the need for long-lived credentials. + +Unlike [Service Accounts](/administration/service-account) that require storing API keys as secrets, Workload Identity: + +- Uses short-lived tokens generated per job +- Validates tokens against your CI/CD platform's identity provider +- Restricts access to specific repositories, branches, and workflows + +## Workspace vs Project Level + +Workload identities can be created at two levels: + +- **Workspace level** — Has access governed by workspace IAM policies. Suitable for cross-project CI/CD workflows. +- **Project level** — Scoped to a single project, following the principle of least privilege. Suitable for project-specific pipelines. + +## Supported Platforms + + + + Configure OIDC authentication for GitHub Actions workflows + + + Configure OIDC authentication for GitLab CI/CD pipelines + + diff --git a/docs/docs.json b/docs/docs.json index 509e65465..49ebdc09c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -231,12 +231,14 @@ { "group": "Security", "pages": [ + "administration/user-groups/overview", + "administration/service-account", { - "group": "Users & Groups", + "group": "Workload Identity", "pages": [ - "administration/user-groups/overview", - "administration/user-groups/workload-identity/github-actions", - "administration/user-groups/workload-identity/gitlab-ci" + "administration/workload-identity/overview", + "administration/workload-identity/github-actions", + "administration/workload-identity/gitlab-ci" ] }, "administration/roles", From 6a3664eee8e2e1f00abdbae7a45d1533914ae418 Mon Sep 17 00:00:00 2001 From: Adela Date: Wed, 25 Feb 2026 17:10:27 +0100 Subject: [PATCH 05/12] Update docs/administration/workload-identity/gitlab-ci.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/administration/workload-identity/gitlab-ci.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/administration/workload-identity/gitlab-ci.mdx b/docs/administration/workload-identity/gitlab-ci.mdx index cde83099d..1b7c369ec 100644 --- a/docs/administration/workload-identity/gitlab-ci.mdx +++ b/docs/administration/workload-identity/gitlab-ci.mdx @@ -13,8 +13,8 @@ This guide explains how to configure Workload Identity for GitLab CI/CD to authe | Field | Description | Example | |-------|-------------|---------| -| **Name** | Display name for this identity | `GitLab Deploy` | -| **Email** | Unique email prefix (automatically appended with `@workload.bytebase.com`) | `gitlab-deploy` | +| **Name** | Display name for this identity | `GitLab CI Deploy` | +| **Email** | Unique email prefix (automatically appended with `@workload.bytebase.com`) | `gitlab-ci-deploy` | | **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` | From 4f2159f2f76b5a8c5ca72f21f92e4c85c7da96cc Mon Sep 17 00:00:00 2001 From: adela Date: Wed, 25 Feb 2026 17:10:57 +0100 Subject: [PATCH 06/12] update service account add --- docs/administration/service-account.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/administration/service-account.mdx b/docs/administration/service-account.mdx index d7be879c2..6293c9e5e 100644 --- a/docs/administration/service-account.mdx +++ b/docs/administration/service-account.mdx @@ -14,7 +14,7 @@ Service accounts can be created at two levels: ## Create a Service Account 1. For workspace-level: go to **IAM & Admin** > **Service Accounts** tab and click **Add Service Account**. -2. For project-level: go to **Project** > **Settings** > **Service Accounts** and click **Add Service Account**. +2. For project-level: go to **Project** > **Manage** > **Service Accounts** and click **Add Service Account**. From f507465284ea15fcfd8206ee94d504ed6b146ea3 Mon Sep 17 00:00:00 2001 From: Adela Date: Wed, 25 Feb 2026 17:12:14 +0100 Subject: [PATCH 07/12] Update docs/administration/workload-identity/gitlab-ci.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/administration/workload-identity/gitlab-ci.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/administration/workload-identity/gitlab-ci.mdx b/docs/administration/workload-identity/gitlab-ci.mdx index 1b7c369ec..a4eda8768 100644 --- a/docs/administration/workload-identity/gitlab-ci.mdx +++ b/docs/administration/workload-identity/gitlab-ci.mdx @@ -69,10 +69,10 @@ deploy-database: -H "Content-Type: application/json" \ -d "{\"token\": \"${GITLAB_OIDC_TOKEN}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}") - ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.accessToken') + ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.accessToken') if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then echo "Failed to get access token" - echo $RESPONSE + echo "$RESPONSE" exit 1 fi From f54e1b78d83498bf1b5f4611b4733b6bb2eff527 Mon Sep 17 00:00:00 2001 From: Adela Date: Wed, 25 Feb 2026 17:12:53 +0100 Subject: [PATCH 08/12] Update docs/administration/workload-identity/github-actions.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/administration/workload-identity/github-actions.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/administration/workload-identity/github-actions.mdx b/docs/administration/workload-identity/github-actions.mdx index c71da337b..eb4a9288f 100644 --- a/docs/administration/workload-identity/github-actions.mdx +++ b/docs/administration/workload-identity/github-actions.mdx @@ -84,7 +84,7 @@ jobs: -H "Content-Type: application/json" \ -d "{\"token\": \"${{ steps.bytebase-token.outputs.token }}\", \"email\": \"${WORKLOAD_IDENTITY_EMAIL}\"}") - ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.accessToken') + ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.accessToken') echo "::add-mask::$ACCESS_TOKEN" echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT From e85c437e4e7ed159d7ba11f4a22ab8719b7ac4ee Mon Sep 17 00:00:00 2001 From: adela Date: Wed, 25 Feb 2026 17:21:33 +0100 Subject: [PATCH 09/12] update changelog links --- docs/changelog/bytebase-3-13-0.mdx | 2 +- docs/changelog/bytebase-3-14-0.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog/bytebase-3-13-0.mdx b/docs/changelog/bytebase-3-13-0.mdx index 7c6f80e02..733284bc4 100644 --- a/docs/changelog/bytebase-3-13-0.mdx +++ b/docs/changelog/bytebase-3-13-0.mdx @@ -38,7 +38,7 @@ import InstallUpgrade from '/snippets/install/install-upgrade.mdx'; ## 🚀 Features - Support [MCP integration](/integrations/mcp). -- Add **Workload Identity** as a dedicated account type for OIDC-based authentication, with [GitHub Actions support](/administration/user-groups/workload-identity/github-actions). +- Add **Workload Identity** as a dedicated account type for OIDC-based authentication, with [GitHub Actions support](/administration/workload-identity/github-actions). - Support direct messages for **Microsoft Teams**. ## 🎄 Enhancements diff --git a/docs/changelog/bytebase-3-14-0.mdx b/docs/changelog/bytebase-3-14-0.mdx index c5a956c58..4e9fec440 100644 --- a/docs/changelog/bytebase-3-14-0.mdx +++ b/docs/changelog/bytebase-3-14-0.mdx @@ -77,7 +77,7 @@ import InstallUpgrade from '/snippets/install/install-upgrade.mdx'; - Improve access and refresh token support. Add refresh tokens (previously only access tokens on the web were supported) and allow separate configuration of **access token duration** and **refresh token duration** (previously the sign-in frequency setting). - Allow setting `No approval required` in approval rules when configured conditions are met. -- Support [**Workload Identity** with **GitLab**](/administration/user-groups/workload-identity/gitlab-ci). +- Support [**Workload Identity** with **GitLab**](/administration/workload-identity/gitlab-ci). ## 🎄 Enhancements From 88a0e993e2561b6335835fdf67649f0437f7661b Mon Sep 17 00:00:00 2001 From: adela Date: Wed, 25 Feb 2026 17:27:55 +0100 Subject: [PATCH 10/12] update --- .../workload-identity/github-actions.mdx | 205 ------------------ .../workload-identity/gitlab-ci.mdx | 199 ----------------- .../workload-identity/github-actions.mdx | 2 +- 3 files changed, 1 insertion(+), 405 deletions(-) delete mode 100644 docs/administration/user-groups/workload-identity/github-actions.mdx delete mode 100644 docs/administration/user-groups/workload-identity/gitlab-ci.mdx diff --git a/docs/administration/user-groups/workload-identity/github-actions.mdx b/docs/administration/user-groups/workload-identity/github-actions.mdx deleted file mode 100644 index c71da337b..000000000 --- a/docs/administration/user-groups/workload-identity/github-actions.mdx +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Workload Identity for GitHub Actions ---- - -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 - -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 | `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` | - -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., `github-actions-deploy@workload.bytebase.com`). -4. Select the **GitOps Service Agent** role. -5. 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](/administration/roles) for details. - - - -## Step 3: Configure GitHub Actions Workflow - -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: - -```yaml -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: - -```yaml -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-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: - -1. **Verify the repository and branch**: Check that your workflow's repository, branch match the configured values in Bytebase. - -2. **Check the audience**: Ensure the audience in your `getIDToken()` call matches `https://github.com/{owner}`. - -### 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 -- 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. diff --git a/docs/administration/user-groups/workload-identity/gitlab-ci.mdx b/docs/administration/user-groups/workload-identity/gitlab-ci.mdx deleted file mode 100644 index cde83099d..000000000 --- a/docs/administration/user-groups/workload-identity/gitlab-ci.mdx +++ /dev/null @@ -1,199 +0,0 @@ ---- -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` | -| **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**. - - - -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. - - - -## 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 - 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" - 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/** -``` - - - -For more details on GitOps workflows, see [GitOps Overview](/gitops/overview) and [Migration-Based Workflow](/gitops/migration-based-workflow/overview). - - - -## 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. diff --git a/docs/administration/workload-identity/github-actions.mdx b/docs/administration/workload-identity/github-actions.mdx index eb4a9288f..6d3650ebf 100644 --- a/docs/administration/workload-identity/github-actions.mdx +++ b/docs/administration/workload-identity/github-actions.mdx @@ -113,7 +113,7 @@ permissions: env: BYTEBASE_URL: https://bytebase.example.com - WORKLOAD_IDENTITY_EMAIL: github-deploy@workload.bytebase.com + WORKLOAD_IDENTITY_EMAIL: github-actions-deploy@workload.bytebase.com PROJECT: projects/my-project jobs: From 26c5aa82aff496b2035f2ce4b87ca97c2f8bec31 Mon Sep 17 00:00:00 2001 From: adela Date: Wed, 25 Feb 2026 17:32:06 +0100 Subject: [PATCH 11/12] update --- docs/administration/user-groups/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/administration/user-groups/overview.mdx b/docs/administration/user-groups/overview.mdx index 4f3dc882b..e3d185cea 100644 --- a/docs/administration/user-groups/overview.mdx +++ b/docs/administration/user-groups/overview.mdx @@ -17,7 +17,7 @@ Bytebase does not support nested groups. A group can only contain users, it can' -Service accounts cannot be part of user groups. Since service accounts are for automated processes with specific access needs, including them in groups could grant unintended permissions. This is considered an [anti-pattern](https://cloud.google.com/iam/docs/best-practices-service-accounts#groups). +Machine identities (service accounts and workload identities) cannot be part of user groups. Since they are for automated processes with specific access needs, including them in groups could grant unintended permissions. This is considered an [anti-pattern](https://cloud.google.com/iam/docs/best-practices-service-accounts#groups). ## Add group From b51c30c59e559e75c9ad6f1cf6082c2fdfbbe2a9 Mon Sep 17 00:00:00 2001 From: adela Date: Wed, 25 Feb 2026 17:35:43 +0100 Subject: [PATCH 12/12] update --- docs/administration/sso/idp-initiated.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/administration/sso/idp-initiated.mdx b/docs/administration/sso/idp-initiated.mdx index 17134f96c..1e18edb16 100644 --- a/docs/administration/sso/idp-initiated.mdx +++ b/docs/administration/sso/idp-initiated.mdx @@ -2,9 +2,7 @@ title: IdP-Initiated Flow --- -By default, SSO uses a **Service Provider-initiated (SP-initiated)** flow: users visit Bytebase, click "Sign in with X", get redirected to the identity provider, then back. **IdP-initiated** flow reverses this — users click the Bytebase tile directly from their identity provider's dashboard (e.g. Okta portal) and land in Bytebase already authenticated. - -This eliminates the extra step of visiting Bytebase first and works with both OAuth 2.0 and OIDC providers. +By default, SSO uses a **Service Provider-initiated (SP-initiated)** flow: users visit Bytebase, click "Sign in with X", get redirected to the identity provider, then back. **IdP-initiated** flow reverses this — users click the Bytebase tile directly from their identity provider's dashboard (e.g. Okta portal) and land in Bytebase already authenticated. This eliminates the extra step of visiting Bytebase first and works with both OAuth 2.0 and OIDC providers. ## Prerequisites