From d3d13c454c27ea588e7c4c7d46244b1a638a2092 Mon Sep 17 00:00:00 2001 From: adela Date: Tue, 14 Apr 2026 20:38:17 +0200 Subject: [PATCH 1/2] docs: sync Terraform tutorial series to provider 3.17.1 Fix schema drift across all 8 parts of the Bytebase Terraform Provider tutorial series after months of provider evolution. - Part 1: bump provider version 3.8.6 -> 3.17.1; unify DISABLE_COPY_DATA + DATA_SOURCE_QUERY into DATA_QUERY / query_data_policy; remove non-existent checkers block from rollout_policy - Part 3: remove removed fields (auto_enable_backup, allow_modify_statement, auto_resolve_issue); fix notification_types to current Activity enum values (ISSUE_CREATED, ISSUE_APPROVAL_REQUESTED, PIPELINE_COMPLETED) - Part 4: remove non-existent bytebase_risk resource; rewrite approval_flow to current schema (flow.roles list + source + CEL condition) - Part 6: migrate SERVICE_ACCOUNT bytebase_user to bytebase_service_account + bytebase_workload_identity resources; drop removed type field - Part 7: drop parent = "workspaces/-" (fails validation, parent defaults to current workspace); update bindings to serviceAccount: / workloadIdentity: member prefixes - Part 8: rename MASKING_EXCEPTION -> MASKING_EXEMPTION and nested fields; drop deprecated actions field on exemptions; fix classification schema (levels.level as Number, not levels.id); prefix CEL conditions with resource. and use integer comparison for classification_level Co-Authored-By: Claude Opus 4.6 --- .../manage-data-masking-with-terraform.mdx | 58 ++++----- ...database-access-control-with-terraform.mdx | 14 +- .../manage-environments-with-terraform.mdx | 83 +++--------- ...manage-general-settings-with-terraform.mdx | 123 ++++++------------ .../manage-projects-with-terraform.mdx | 39 ++++-- ...manage-users-and-groups-with-terraform.mdx | 55 ++++---- 6 files changed, 154 insertions(+), 218 deletions(-) diff --git a/docs/tutorials/manage-data-masking-with-terraform.mdx b/docs/tutorials/manage-data-masking-with-terraform.mdx index abb42db6c..52a9a2cf8 100644 --- a/docs/tutorials/manage-data-masking-with-terraform.mdx +++ b/docs/tutorials/manage-data-masking-with-terraform.mdx @@ -146,11 +146,11 @@ resource "bytebase_setting" "classification" { title = "Classification Example" levels { - id = "1" + level = 1 title = "Level 1" } levels { - id = "2" + level = 2 title = "Level 2" } @@ -162,13 +162,13 @@ resource "bytebase_setting" "classification" { classifications { id = "1-1" title = "User basic" - level = "1" + level = 1 } classifications { id = "1-2" title = "User contact info" - level = "2" + level = 2 } classifications { @@ -179,7 +179,7 @@ resource "bytebase_setting" "classification" { classifications { id = "2-1" title = "Employment info" - level = "2" + level = 2 } } } @@ -227,7 +227,7 @@ resource "bytebase_policy" "global_masking_policy" { bytebase_setting.environments ] - parent = "workspaces/-" + # parent defaults to the current workspace when omitted. type = "MASKING_RULE" enforce = true inherit_from_parent = false @@ -235,21 +235,21 @@ resource "bytebase_policy" "global_masking_policy" { global_masking_policy { rules { - condition = "column_name == \"birth_date\"" + condition = "resource.column_name == \"birth_date\"" id = "birth-date-mask" semantic_type = "date-year-mask" title = "Mask Birth Date Year" } rules { - condition = "column_name == \"last_name\"" + condition = "resource.column_name == \"last_name\"" id = "last-name-first-letter-only" semantic_type = "name-first-letter-only" title = "Last Name Only Show First Letter" } rules { - condition = "classification_level in [\"2\"]" + condition = "resource.classification_level == 2" id = "classification-level-2" semantic_type = "full-mask" # Maps Level 2 classification to full-mask semantic type title = "Full Mask for Classification Level 2" @@ -344,45 +344,37 @@ Verify in Bytebase: | | | | --------------------- | ---------------------------------------------------------------------------------------------------------------------- | | Terraform resource | [bytebase_policy](https://registry.terraform.io/providers/bytebase/bytebase/latest/docs/resources/policy) | -| Sample file | [8-5-masking-exception.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/8-5-masking-exception.tf) | +| Sample file | [8-5-masking-exemption.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/8-5-masking-exemption.tf) | -Create `8-5-masking-exception.tf` to grant bypass permissions: +Create `8-5-masking-exemption.tf` to grant bypass permissions: -- Workspace Admin (`admin@example.com`) has Masking Exemptions for `birth_date` in table `employee` for Query -- Workspace Admin (`admin@example.com`) has Masking Exemptions for `last_name` in table `employee` for Export +- Workspace Admin (`admin@example.com`) and QA (`qa1@example.com`) can see unmasked `birth_date` and `last_name` in the `employee` table (expires 2027-07-30). +- Developer 1 (`dev1@example.com`) can see unmasked `first_name`, `last_name`, and `gender` in the `employee` table (via `raw_expression`, no expiry). -```hcl 8-5-masking-exception.tf -resource "bytebase_policy" "masking_exception_policy" { +```hcl 8-5-masking-exemption.tf +resource "bytebase_policy" "masking_exemption_policy" { depends_on = [ bytebase_project.project-two, bytebase_instance.prod ] parent = bytebase_project.project-two.name - type = "MASKING_EXCEPTION" + type = "MASKING_EXEMPTION" enforce = true inherit_from_parent = false - masking_exception_policy { - exceptions { + masking_exemption_policy { + exemptions { reason = "Business requirement" database = "instances/prod-sample-instance/databases/hr_prod" table = "employee" columns = ["birth_date", "last_name"] - members = ["user:admin@example.com"] - actions = ["QUERY", "EXPORT"] - expire_timestamp = "2027-07-30T16:11:49Z" - } - exceptions { - reason = "Export data for analysis" - members = ["user:qa1@example.com"] - actions = ["EXPORT"] + members = ["user:admin@example.com", "user:qa1@example.com"] expire_timestamp = "2027-07-30T16:11:49Z" } - exceptions { + exemptions { reason = "Grant query access" - members = ["user:dev1@example.com"] - actions = ["QUERY"] + members = ["user:dev1@example.com"] raw_expression = "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.table_name == \"employee\" && resource.column_name in [\"first_name\", \"last_name\", \"gender\"]" } } @@ -414,16 +406,12 @@ terraform plan terraform apply ``` -Verify the masking exceptions are working: +Verify the masking exemptions are working: -1. Log in as Workspace Admin (`admin@example.com`), then go to **SQL Editor** to access `hr_prod`, double-click `employee` table on the left. You may notice the `birth_date` is not masked any longer. +1. Log in as Workspace Admin (`admin@example.com`), then go to **SQL Editor** to access `hr_prod` and double-click the `employee` table. Both `birth_date` and `last_name` are now unmasked for both query and export. ![admin-employee-query](/content/docs/tutorials/manage-data-masking-with-terraform/bb-admin-employee-query.webp) -1. Click **Export**, and then open the file. You should notice the `birth_date` is still masked while `last_name` is no longer masked. - - ![admin-employee-export](/content/docs/tutorials/manage-data-masking-with-terraform/bb-admin-employee-export.webp) - 1. You may go to **Manage > Masking Exemptions** to view current exemptions. They will expire automatically after the expiration time. ![masking-exceptions](/content/docs/tutorials/manage-data-masking-with-terraform/bb-masking-exceptions.webp) diff --git a/docs/tutorials/manage-database-access-control-with-terraform.mdx b/docs/tutorials/manage-database-access-control-with-terraform.mdx index a61fd3a97..83db7ba82 100644 --- a/docs/tutorials/manage-database-access-control-with-terraform.mdx +++ b/docs/tutorials/manage-database-access-control-with-terraform.mdx @@ -72,13 +72,14 @@ Create `7-1-workspace-iam.tf` with workspace-level permissions: resource "bytebase_iam_policy" "workspace_iam" { depends_on = [ bytebase_user.workspace_admin, - bytebase_user.tf_service_account, + bytebase_service_account.tf_service_account, + bytebase_workload_identity.github_ci, bytebase_user.workspace_dba1, bytebase_user.workspace_dba2, bytebase_group.qa ] - parent = "workspaces/-" + # parent defaults to the current workspace when omitted. iam_policy { @@ -86,7 +87,6 @@ resource "bytebase_iam_policy" "workspace_iam" { role = "roles/workspaceAdmin" members = [ format("user:%s", bytebase_user.workspace_admin.email), - format("user:%s", bytebase_user.tf_service_account.email), ] } @@ -94,7 +94,9 @@ resource "bytebase_iam_policy" "workspace_iam" { role = "roles/workspaceDBA" members = [ format("user:%s", bytebase_user.workspace_dba1.email), - format("user:%s", bytebase_user.workspace_dba2.email) + format("user:%s", bytebase_user.workspace_dba2.email), + format("serviceAccount:%s", bytebase_service_account.tf_service_account.email), + format("workloadIdentity:%s", bytebase_workload_identity.github_ci.email), ] } @@ -117,6 +119,10 @@ resource "bytebase_iam_policy" "workspace_iam" { } ``` + +Service accounts use the `serviceAccount:` member prefix, workload identities use `workloadIdentity:`, users use `user:`, and groups use `group:`. + + `allUsers` is a special member representing everyone in the workspace. Without it, users may be unable to access the workspace. diff --git a/docs/tutorials/manage-environments-with-terraform.mdx b/docs/tutorials/manage-environments-with-terraform.mdx index 6bddc7dc8..c5038426e 100644 --- a/docs/tutorials/manage-environments-with-terraform.mdx +++ b/docs/tutorials/manage-environments-with-terraform.mdx @@ -90,7 +90,7 @@ Navigate to **Environments** in Bytebase. You'll see two default environments: ` required_providers { bytebase = { source = "registry.terraform.io/bytebase/bytebase" - version = "3.8.6" # Check for latest version + version = "3.17.1" # Check for latest version } } } @@ -198,40 +198,25 @@ Let's add rollout and data protection policies, for more details, see: [Environm | Terraform resource | [bytebase_policy](https://registry.terraform.io/providers/bytebase/bytebase/latest/docs/resources/policy) | | Sample file | [1-2-env-policy-rollout.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/1-2-env-policy-rollout.tf) | -When no rollout policy is found for an environment, Bytebase applies a default rollout policy with the following checkers: - -- **Required Issue Approval**: Changes must be approved before deployment -- **Plan Check Enforcement**: SQL plan checks must pass (errors only) - -You can explicitly configure these policies using Terraform. Create `1-2-env-policy-rollout.tf`: +The rollout policy controls whether changes deploy automatically and which roles can manually roll out. Create `1-2-env-policy-rollout.tf`: ```hcl 1-2-env-policy-rollout.tf -# Test environment - automatic deployment with default checkers +# Test environment - automatic deployment resource "bytebase_policy" "rollout_policy_test" { depends_on = [bytebase_setting.environments] parent = bytebase_setting.environments.environment_setting[0].environment[0].name type = "ROLLOUT_POLICY" rollout_policy { - automatic = true # Deploy changes automatically + automatic = true # Deploy changes automatically when all checks pass roles = [ "roles/workspaceAdmin", - "roles/projectOwner", - "roles/LAST_APPROVER", - "roles/CREATOR" + "roles/projectOwner" ] - - # Default checkers (explicitly configured) - checkers { - required_issue_approval = true - required_status_checks { - plan_check_enforcement = "ERROR_ONLY" # Block on errors only - } - } } } -# Production - manual deployment with stricter checks +# Production - manual deployment resource "bytebase_policy" "rollout_policy_prod" { depends_on = [bytebase_setting.environments] parent = bytebase_setting.environments.environment_setting[0].environment[1].name @@ -241,31 +226,16 @@ resource "bytebase_policy" "rollout_policy_prod" { automatic = false # Require manual deployment roles = [ "roles/workspaceAdmin", - "roles/projectOwner", - "roles/LAST_APPROVER", - "roles/CREATOR" + "roles/projectOwner" ] - - # Enforce all plan checks (errors and warnings) - checkers { - required_issue_approval = true - required_status_checks { - plan_check_enforcement = "STRICT" # Block on both errors and warnings - } - } } } ``` **Key Configuration Options:** -- `automatic`: When `true`, changes deploy automatically after approval. When `false`, requires manual click to deploy. -- `roles`: List of roles allowed to manually deploy changes. Required even with automatic rollout, as manual approval is needed when checks fail. -- `checkers.required_issue_approval`: When `true`, requires issue approval before rollout. -- `checkers.required_status_checks.plan_check_enforcement`: Controls SQL plan check enforcement: - - `PLAN_CHECK_ENFORCEMENT_UNSPECIFIED`: Allow rollout regardless of plan check results (no enforcement) - - `ERROR_ONLY`: Block rollout only when plan check finds errors (default) - - `STRICT`: Block rollout when plan check finds errors or warnings (stricter for production) +- `automatic`: When `true`, changes deploy automatically after all checks pass. When `false`, requires manual click to deploy. +- `roles`: List of roles allowed to manually roll out changes. Required even with automatic rollout, as manual approval is needed when checks fail. ### Data Protection Policy @@ -277,38 +247,27 @@ resource "bytebase_policy" "rollout_policy_prod" { Create `1-3-env-policy-data.tf`: ```hcl 1-3-env-policy-data.tf -# Prevent copying data in SQL Editor from production -resource "bytebase_policy" "disable_copy_data_policy_prod" { - depends_on = [bytebase_setting.environments] - parent = bytebase_setting.environments.environment_setting[0].environment[1].name - type = "DISABLE_COPY_DATA" - - disable_copy_data_policy { - enable = true # Block data copy - } -} - -# Restrict SQL execution in SQL Editor from production -resource "bytebase_policy" "data_source_query_policy_prod" { +# Restrict SQL Editor data access on production +resource "bytebase_policy" "query_data_policy_prod" { depends_on = [bytebase_setting.environments] parent = bytebase_setting.environments.environment_setting[0].environment[1].name - type = "DATA_SOURCE_QUERY" + type = "DATA_QUERY" - data_source_query_policy { - restriction = "RESTRICTION_UNSPECIFIED" - disallow_ddl = true # No schema changes via SQL Editor - disallow_dml = true # No data changes via SQL Editor + query_data_policy { + maximum_result_rows = 1000 # Cap rows returned per query + disable_copy_data = true # Block copy-to-clipboard + disable_export = true # Block export + allow_admin_data_source = false # Force read-only data source when configured } } ``` -- Here data protection policy is only applied to the `Prod` environment. Which means in `Test` environment, by default, users may execute DDL and DML statements or copy data directly in SQL Editor. +- The policy is only applied to the `Prod` environment. In `Test`, the defaults apply (no row cap, copy/export allowed, admin data source usable). -- `restriction` controls [access to the data source](/sql-editor/settings/data-source-restriction): +- `allow_admin_data_source` controls [access to the data source](/sql-editor/settings/data-source-restriction): - - `RESTRICTION_UNSPECIFIED`: Admin data source is allowed. - - `DISALLOW`: Admin data source is completely disallowed. - - `FALLBACK`: Prefer the read-only data source; use admin only if read-only is not configured. + - `true`: Admin data source is allowed. + - `false`: When a read-only data source is configured, users are forced onto it; otherwise falls back to admin. ## Step 6 - Apply Configuration diff --git a/docs/tutorials/manage-general-settings-with-terraform.mdx b/docs/tutorials/manage-general-settings-with-terraform.mdx index 5614c40cf..39b84416d 100644 --- a/docs/tutorials/manage-general-settings-with-terraform.mdx +++ b/docs/tutorials/manage-general-settings-with-terraform.mdx @@ -33,8 +33,7 @@ This tutorial is part of the **Bytebase Terraform Provider** series: ## What You'll Learn - **Configure** workspace profile settings including signup controls and external URL -- **Define** risk policies to automatically assess database operations -- **Create** multi-step and risk-based approval flows for database changes +- **Create** multi-step, risk-based approval flows for database changes using CEL conditions ## Prerequisites @@ -83,90 +82,66 @@ This configuration: - Restricts users to specific email domains - Sets your Bytebase workspace's external URL -### Step 2 - Risk Management Policies +### Step 2 - Approval Flow Settings -| | | -| --------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| Terraform resource | [bytebase_risk](https://registry.terraform.io/providers/bytebase/bytebase/latest/docs/resources/risk) | -| Sample file | [4-2-risk.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/4-2-risk.tf) | - -Create `4-2-risk.tf` with risk policies to assess the database operations' risk level: - -```hcl 4-2-risk.tf -# Risk management policies -resource "bytebase_risk" "dml_moderate" { - title = "DML Moderate Risk" - source = "DML" - level = 200 - active = true - condition = "environment_id == \"prod\" && affected_rows >= 100" -} - -resource "bytebase_risk" "ddl_high" { - title = "DDL High Risk" - source = "DDL" - level = 300 - active = true - condition = "environment_id == \"prod\"" -} -``` - -Risk levels: +| | | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------ | +| Terraform resource | [bytebase_setting](https://registry.terraform.io/providers/bytebase/bytebase/latest/docs/resources/setting) | +| Sample file | [4-2-approval-flow.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/4-2-approval-flow.tf) | -- **100 (LOW)**. -- **200 (MODERATE)**: DML operations in production affecting 100+ rows -- **300 (HIGH)**: All DDL operations in production +Create `4-2-approval-flow.tf` with approval flow configuration that requires multiple approvals for risky operations: -### Step 3 - Approval Flow Settings - -| | | -| --------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| Terraform resource | [bytebase_setting](https://registry.terraform.io/providers/bytebase/bytebase/latest/docs/resources/setting) | -| Sample file | [4-3-approval-flow.tf](https://github.com/bytebase/terraform-provider-bytebase/blob/main/tutorials/4-3-approval-flow.tf) | - -Create `4-3-approval-flow.tf` with approval flow configuration that requires multiple approvals for risky operations: - -```hcl 4-3-approval-flow.tf +```hcl 4-2-approval-flow.tf # Approval flow settings resource "bytebase_setting" "approval_flow" { name = "settings/WORKSPACE_APPROVAL" approval_flow { + # Rule 1: risky database changes need a three-step approval rules { flow { title = "Project Owner → DBA → Admin" description = "Need DBA and workspace admin approval" - - steps { role = "roles/projectOwner" } - steps { role = "roles/workspaceDBA" } - steps { role = "roles/workspaceAdmin" } + # The steps of the flow are executed in the order of the roles list. + roles = [ + "roles/projectOwner", + "roles/workspaceDBA", + "roles/workspaceAdmin" + ] } - conditions { - source = "DML" - level = "MODERATE" - } - conditions { - source = "DDL" - level = "HIGH" + source = "CHANGE_DATABASE" + condition = "request.risk >= 100" + } + + # Rule 2: fallback — everything else only needs a DBA + rules { + flow { + title = "Fallback rule" + roles = [ + "roles/workspaceDBA" + ] } + condition = "true" } } } ``` -This creates a three-step approval flow that triggers for: +**Key Configuration Options:** -- DML operations with MODERATE risk level -- DDL operations with HIGH risk level +- `flow.roles`: Ordered list of roles that must approve the issue, in sequence. +- `source`: The activity source this rule matches — `CHANGE_DATABASE`, `CREATE_DATABASE`, `EXPORT_DATA`, `REQUEST_ROLE`, or `REQUEST_ACCESS`. Omit for a fallback rule. +- `condition`: A CEL expression evaluated against the request. Common variables include `request.risk` (100 = LOW, 200 = MODERATE, 300 = HIGH) and `resource.project_id`. Use `"true"` for a catch-all fallback. +- Rules are evaluated in order; the **first matching rule applies**, so place the most specific rules first and keep a fallback last. -### Step 4 - Apply Configuration +### Step 3 - Apply Configuration ```bash terraform plan terraform apply ``` -### Step 5 - Verify Configuration +### Step 4 - Verify Configuration #### Workspace Profile Settings @@ -174,39 +149,23 @@ terraform apply 1. Log out and try to signup which should be disabled. 1. Visit the external URL to verify it is set. -#### Risk Policies - -1. Go to **CI/CD > Risks** to view risk policies. - - ![risks](/content/docs/tutorials/manage-general-settings-with-terraform/bb-risks.webp) - -1. You should see both "DML Moderate Risk" and "DDL High Risk" policies active. - #### Approval Flows 1. Go to **CI/CD > Custom Approval** to see the approval flow. ![custom-approval](/content/docs/tutorials/manage-general-settings-with-terraform/bb-custom-approval.webp) -1. Verify the `Project Owner → DBA → Admin` flow is configured. - -#### Test the Flow - -1. Go to `Project Two`, click **Database > Databases** on the left sidebar. -1. Check `hr_prod`, click **Edit Schema**, add a new table `t0`. -1. After creating the issue, you should see: +1. Verify the `Project Owner → DBA → Admin` flow is configured for the `CHANGE_DATABASE` source with `request.risk >= 100`, and the `Fallback rule` catches everything else. - - Risk level: `DDL High` - - Approval flow: `Project Owner → DBA → Admin` - - ![issue-risk-high](/content/docs/tutorials/manage-general-settings-with-terraform/bb-issue-risk-high.webp) + +Risk levels (returned by `request.risk` in the CEL expression) are configured separately in **CI/CD > Risks** in the UI. Each risk rule maps an activity (DDL/DML/CREATE_DATABASE/EXPORT/REQUEST_ROLE) plus a CEL condition to a numeric level (100 LOW / 200 MODERATE / 300 HIGH), which is then evaluated against your approval-flow conditions here. + ## Key Points - **Workspace Profile**: Controls signup, domain restrictions, and external URL for your entire Bytebase workspace -- **Risk Policies**: Automatically assess database operations based on conditions like environment and affected rows -- **Approval Flows**: Define multi-step approval processes that trigger based on risk levels -- **Integration**: Risk policies and approval flows work together to ensure proper governance for database changes +- **Approval Flows**: Define multi-step approval processes. Each rule binds a `source` + CEL `condition` to an ordered list of approver roles; rules are evaluated top-down, first match wins +- **Fallback Rule**: Include a final rule with `condition = "true"` and no `source` so that every issue has a defined approval path You can configure additional @@ -215,7 +174,7 @@ terraform apply Date: Tue, 14 Apr 2026 20:56:06 +0200 Subject: [PATCH 2/2] docs: address Copilot review feedback on Terraform tutorials - Part 6: clarify bytebase_service_account adopts the Part 1 bootstrap account - Part 7: move tf service account to workspaceAdmin to prevent self-demotion - Part 8: rename 'Masking Exceptions' to 'Masking Exemptions' for consistency --- docs/tutorials/manage-data-masking-with-terraform.mdx | 6 +++--- .../manage-database-access-control-with-terraform.mdx | 4 +++- docs/tutorials/manage-users-and-groups-with-terraform.mdx | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/manage-data-masking-with-terraform.mdx b/docs/tutorials/manage-data-masking-with-terraform.mdx index 52a9a2cf8..39a732b8a 100644 --- a/docs/tutorials/manage-data-masking-with-terraform.mdx +++ b/docs/tutorials/manage-data-masking-with-terraform.mdx @@ -31,7 +31,7 @@ This tutorial is part of the **Bytebase Terraform Provider** series: - **Configure** data classification levels and categories - **Create** global masking policies that apply workspace-wide - **Set up** database-specific column masking -- **Grant** masking exceptions for specific users +- **Grant** masking exemptions for specific users ## Prerequisites @@ -339,7 +339,7 @@ Verify in Bytebase: ![dev1-salary](/content/docs/tutorials/manage-data-masking-with-terraform/bb-dev1-salary.webp) -## Step 6: Grant Masking Exceptions +## Step 6: Grant Masking Exemptions | | | | --------------------- | ---------------------------------------------------------------------------------------------------------------------- | @@ -399,7 +399,7 @@ If you specify `raw_expression`, it defines the exemption condition directly as ## Step 7: Apply Final Configuration and Test -Apply the masking exceptions and test everything: +Apply the masking exemptions and test everything: ```bash terraform plan diff --git a/docs/tutorials/manage-database-access-control-with-terraform.mdx b/docs/tutorials/manage-database-access-control-with-terraform.mdx index 83db7ba82..bafd0b81c 100644 --- a/docs/tutorials/manage-database-access-control-with-terraform.mdx +++ b/docs/tutorials/manage-database-access-control-with-terraform.mdx @@ -87,6 +87,9 @@ resource "bytebase_iam_policy" "workspace_iam" { role = "roles/workspaceAdmin" members = [ format("user:%s", bytebase_user.workspace_admin.email), + # Keep the Terraform-running service account as Workspace Admin so + # subsequent `terraform apply` runs retain full permissions. + format("serviceAccount:%s", bytebase_service_account.tf_service_account.email), ] } @@ -95,7 +98,6 @@ resource "bytebase_iam_policy" "workspace_iam" { members = [ format("user:%s", bytebase_user.workspace_dba1.email), format("user:%s", bytebase_user.workspace_dba2.email), - format("serviceAccount:%s", bytebase_service_account.tf_service_account.email), format("workloadIdentity:%s", bytebase_workload_identity.github_ci.email), ] } diff --git a/docs/tutorials/manage-users-and-groups-with-terraform.mdx b/docs/tutorials/manage-users-and-groups-with-terraform.mdx index dc7d49711..7ce2f9c3b 100644 --- a/docs/tutorials/manage-users-and-groups-with-terraform.mdx +++ b/docs/tutorials/manage-users-and-groups-with-terraform.mdx @@ -133,6 +133,10 @@ resource "bytebase_workload_identity" "github_ci" { } ``` + +You created `tf@service.bytebase.com` manually in Part 1 to bootstrap the provider. The `bytebase_service_account` resource here adopts that existing account on first apply (you'll see a "Service account already exists" warning) — no manual import needed. + + ### Step 2 - Apply User Configuration ```bash