From 444175a7403e9c4d0aefb5af03bee5414c03baee Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Fri, 26 Jun 2026 10:49:30 -0300 Subject: [PATCH 1/5] fix: replace WriteString(fmt.Sprintf) with fmt.Fprintf and add nil guard Fixes revive unhandled-error lint failures and a nil pointer dereference when c.client is nil before IsVersion8() is called. Co-Authored-By: Claude Sonnet 4.6 --- pkg/client/client.go | 12 +++++------- pkg/client/client_test.go | 10 +++++----- pkg/connector/connector.go | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 715cdee0..6dd3f865 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -47,12 +47,12 @@ func (t dbResourceID) Column() dbResourceID { func (t dbResourceID) SQLString() (string, error) { var sb strings.Builder - _, err := sb.WriteString(fmt.Sprintf("`%s`", t.DatabaseName)) + _, err := fmt.Fprintf(&sb, "`%s`", t.DatabaseName) if err != nil { return "", err } if t.ResourceName != "" && (t.ResourceTypeID == TableType || t.ResourceTypeID == ColumnType) { - _, err = sb.WriteString(fmt.Sprintf(".`%s`", t.ResourceName)) + _, err = fmt.Fprintf(&sb, ".`%s`", t.ResourceName) if err != nil { return "", err } @@ -63,15 +63,13 @@ func (t dbResourceID) SQLString() (string, error) { func (t dbResourceID) String() string { var sb strings.Builder - sb.WriteString(fmt.Sprintf("%s:%s", t.ResourceTypeID, t.DatabaseName)) + fmt.Fprintf(&sb, "%s:%s", t.ResourceTypeID, t.DatabaseName) if t.ResourceName != "" { - sb.WriteString(".") - sb.WriteString(t.ResourceName) + fmt.Fprintf(&sb, ".%s", t.ResourceName) if t.SubResourceName != "" { - sb.WriteString(".") - sb.WriteString(t.SubResourceName) + fmt.Fprintf(&sb, ".%s", t.SubResourceName) } } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index e6b43c42..845c8bc6 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -286,18 +286,18 @@ func Test_generateRandomGrants(t *testing.T) { _, _ = grantStatements.WriteString(", ") } - _, _ = grantStatements.WriteString(fmt.Sprintf(`%s (`, p)) + _, _ = fmt.Fprintf(&grantStatements, "%s (", p) for jj, col := range g.resourceIDs { if jj != 0 { _, _ = grantStatements.WriteString(", ") } - _, _ = grantStatements.WriteString(fmt.Sprintf("`%s`", col.SubResourceName)) + _, _ = fmt.Fprintf(&grantStatements, "`%s`", col.SubResourceName) } _, _ = grantStatements.WriteString(")") } resourceString, err := g.resourceIDs[0].SQLString() require.NoError(t, err) - _, _ = grantStatements.WriteString(fmt.Sprintf(" ON %s TO %s;", resourceString, accountID)) + _, _ = fmt.Fprintf(&grantStatements, " ON %s TO %s;", resourceString, accountID) _ = grantStatements.WriteByte('\n') case TableType: @@ -318,7 +318,7 @@ func Test_generateRandomGrants(t *testing.T) { } resourceString, err := g.resourceIDs[0].SQLString() require.NoError(t, err) - _, _ = grantStatements.WriteString(fmt.Sprintf(" ON %s TO %s;\n", resourceString, accountID)) + _, _ = fmt.Fprintf(&grantStatements, " ON %s TO %s;\n", resourceString, accountID) case DatabaseType: privs := randomPrivs(r, dbPrivs(), privCount) @@ -338,7 +338,7 @@ func Test_generateRandomGrants(t *testing.T) { } resourceString, err := g.resourceIDs[0].SQLString() require.NoError(t, err) - _, _ = grantStatements.WriteString(fmt.Sprintf(" ON %s.* TO %s;\n", resourceString, accountID)) + _, _ = fmt.Fprintf(&grantStatements, " ON %s.* TO %s;\n", resourceString, accountID) default: require.NoError(t, fmt.Errorf("invalid resource type for grant item")) } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 4bcffb4c..5ac36368 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -79,7 +79,7 @@ func (c *Connector) ResourceSyncers(ctx context.Context) []connectorbuilder.Reso newUserSyncer(c.client, c.skipDbs, c.expandCols, c.collapseUsers), } - if c.client.IsVersion8() { + if c.client != nil && c.client.IsVersion8() { syncers = append(syncers, newRoleSyncer(c.client, c.skipDbs, c.expandCols)) } From f19c551af5c388e31ace6bd21af9849cdc46ccb1 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Fri, 26 Jun 2026 10:58:00 -0300 Subject: [PATCH 2/5] chore: add baton_capabilities.json and config_schema.json These files are required by the Generate Baton Metadata CI workflow to validate that committed metadata matches the binary output. Co-Authored-By: Claude Sonnet 4.6 --- baton_capabilities.json | 78 +++++++++++++++++++++++++ config_schema.json | 126 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 baton_capabilities.json create mode 100644 config_schema.json diff --git a/baton_capabilities.json b/baton_capabilities.json new file mode 100644 index 00000000..e261c031 --- /dev/null +++ b/baton_capabilities.json @@ -0,0 +1,78 @@ +{ + "@type": "type.googleapis.com/c1.connector.v2.ConnectorCapabilities", + "resourceTypeCapabilities": [ + { + "resourceType": { + "id": "database", + "displayName": "Database" + }, + "capabilities": [ + "CAPABILITY_SYNC", + "CAPABILITY_PROVISION" + ], + "permissions": {} + }, + { + "resourceType": { + "id": "routine", + "displayName": "Routine" + }, + "capabilities": [ + "CAPABILITY_SYNC", + "CAPABILITY_PROVISION" + ], + "permissions": {} + }, + { + "resourceType": { + "id": "server", + "displayName": "Server" + }, + "capabilities": [ + "CAPABILITY_SYNC", + "CAPABILITY_PROVISION" + ], + "permissions": {} + }, + { + "resourceType": { + "id": "table", + "displayName": "Table" + }, + "capabilities": [ + "CAPABILITY_SYNC", + "CAPABILITY_PROVISION" + ], + "permissions": {} + }, + { + "resourceType": { + "id": "user", + "displayName": "User", + "traits": [ + "TRAIT_USER" + ] + }, + "capabilities": [ + "CAPABILITY_SYNC", + "CAPABILITY_ACCOUNT_PROVISIONING", + "CAPABILITY_RESOURCE_DELETE" + ], + "permissions": {} + } + ], + "connectorCapabilities": [ + "CAPABILITY_PROVISION", + "CAPABILITY_SYNC", + "CAPABILITY_ACCOUNT_PROVISIONING", + "CAPABILITY_RESOURCE_DELETE" + ], + "credentialDetails": { + "capabilityAccountProvisioning": { + "supportedCredentialOptions": [ + "CAPABILITY_DETAIL_CREDENTIAL_OPTION_RANDOM_PASSWORD" + ], + "preferredCredentialOption": "CAPABILITY_DETAIL_CREDENTIAL_OPTION_RANDOM_PASSWORD" + } + } +} \ No newline at end of file diff --git a/config_schema.json b/config_schema.json new file mode 100644 index 00000000..f01944b4 --- /dev/null +++ b/config_schema.json @@ -0,0 +1,126 @@ +{ + "fields": [ + { + "name": "log-level", + "description": "The log level: debug, info, warn, error", + "isOps": true, + "stringField": { + "defaultValue": "info" + } + }, + { + "name": "log-level-debug-expires-at", + "description": "The timestamp indicating when debug-level logging should expire", + "isOps": true, + "stringField": {} + }, + { + "name": "session-store-maximum-size", + "description": "The maximum size of the local in-memory session store cache in bytes.", + "isOps": true, + "intField": { + "defaultValue": "15728640" + } + }, + { + "name": "otel-collector-endpoint", + "description": "The endpoint of the OpenTelemetry collector to send observability data to (used for both tracing and logging if specific endpoints are not provided)", + "isOps": true, + "stringField": {} + }, + { + "name": "otel-collector-endpoint-tls-cert-path", + "description": "Path to a file containing a PEM-encoded certificate to use as a CA for TLS connections to the OpenTelemetry collector", + "isOps": true, + "stringField": {} + }, + { + "name": "otel-collector-endpoint-tls-cert", + "description": "A PEM-encoded certificate to use as a CA for TLS connections to the OpenTelemetry collector", + "isOps": true, + "stringField": {} + }, + { + "name": "otel-collector-endpoint-tls-insecure", + "description": "Allow insecure connections to the OpenTelemetry collector", + "isOps": true, + "boolField": {} + }, + { + "name": "otel-tracing-disabled", + "description": "Disable OpenTelemetry tracing", + "isOps": true, + "boolField": {} + }, + { + "name": "otel-logging-disabled", + "description": "Disable OpenTelemetry logging", + "isOps": true, + "boolField": {} + }, + { + "name": "health-check", + "description": "Enable the HTTP health check endpoint", + "isOps": true, + "boolField": {} + }, + { + "name": "health-check-port", + "description": "Port for the HTTP health check endpoint", + "isOps": true, + "intField": { + "defaultValue": "8081" + } + }, + { + "name": "health-check-bind-address", + "description": "Bind address for health check server (127.0.0.1 for localhost-only)", + "isOps": true, + "stringField": { + "defaultValue": "127.0.0.1" + } + }, + { + "name": "http-timeout-seconds", + "description": "HTTP client timeout in seconds (max 1800)", + "isOps": true, + "intField": { + "defaultValue": "300", + "rules": { + "lte": "1800", + "gte": "1" + } + } + }, + { + "name": "connection-string", + "description": "The connection string for connecting to MySQL ($BATON_CONNECTION_STRING)", + "isRequired": true, + "isSecret": true, + "stringField": { + "rules": { + "isRequired": true + } + } + }, + { + "name": "skip-database", + "description": "Skip syncing privileges from these databases ($BATON_SKIP_DATABASE)", + "stringSliceField": { + "rules": {} + } + }, + { + "name": "expand-columns", + "description": "Provide a table like db.table to expand the column privileges into their own entitlements. $(BATON_EXPAND_COLUMNS)", + "stringSliceField": { + "rules": {} + } + }, + { + "name": "collapse-users", + "description": "Combine user@host pairs into a single user@[hosts...] identity $(BATON_COLLAPSE_USERS)", + "boolField": {} + } + ] +} \ No newline at end of file From 037dcc7825db199f66677ed9f1206dbfc49f4863 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Fri, 26 Jun 2026 11:01:14 -0300 Subject: [PATCH 3/5] docs: add connector.mdx and docs-info.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Required by the Generate Baton Metadata CI workflow — the docs freshness check requires docs/connector.mdx to be present and updated whenever baton_capabilities.json changes. Co-Authored-By: Claude Sonnet 4.6 --- docs/connector.mdx | 227 +++++++++++++++++++++++++++++++++++++++++++++ docs/docs-info.md | 59 ++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 docs/connector.mdx create mode 100644 docs/docs-info.md diff --git a/docs/connector.mdx b/docs/connector.mdx new file mode 100644 index 00000000..b76c8826 --- /dev/null +++ b/docs/connector.mdx @@ -0,0 +1,227 @@ +--- +title: "Set up a MySQL connector" +og:title: "Set up a MySQL connector" +description: "ConductorOne provides identity governance for MySQL. Integrate your MySQL instance with ConductorOne to run user access reviews (UARs), enable just-in-time access requests, and automatically provision and deprovision access." +og:description: "ConductorOne provides identity governance for MySQL. Integrate your MySQL instance with ConductorOne to run user access reviews (UARs), enable just-in-time access requests, and automatically provision and deprovision access." +sidebarTitle: "MySQL" +--- + +{/* AUTO-GENERATED:START - capabilities + Generated from baton_capabilities.json. Do not edit manually. */} + +## Capabilities + +The MySQL connector syncs the following resources: + +| Resource | Sync | Provision | +| :--- | :--- | :--- | +| Databases | | Grant, Revoke | +| Routines | | Grant, Revoke | +| Servers | | Grant, Revoke | +| Tables | | Grant, Revoke | +| Users | | Create, Delete | + +{/* AUTO-GENERATED:END - capabilities */} + +**Notes:** + +- Roles are synced and their privilege assignments can be granted and revoked on **MySQL 8+** only. The role resource type is enabled automatically when a MySQL 8 server is detected. +- Columns are synced as sub-resources of tables when the `--expand-columns` flag is configured. + +## Gather MySQL credentials + + + The ConductorOne connector requires a dedicated MySQL user with `SELECT` + privileges on the `mysql` system database tables that contain privilege + information. Creating a least-privilege user is strongly recommended over + using a root account. + + +### Create a MySQL connector user + + + + Log in to your MySQL server using an account with `GRANT` privileges (for example, `root`). + + + Create a dedicated user for the connector: + + ```sql + CREATE USER conductorone IDENTIFIED BY 'secure-password'; + ``` + + + Grant the minimum required privileges. Choose the block that matches your MySQL version. + + **MySQL 5.7:** + + ```sql + GRANT SELECT (Host, User, Db, Select_priv, Insert_priv, Update_priv, Delete_priv, + Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, + Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Create_view_priv, + Show_view_priv, Create_routine_priv, Alter_routine_priv, Event_priv, + Trigger_priv) ON mysql.db TO conductorone; + GRANT SELECT (Host, User, Db, Table_priv, Table_name) ON mysql.tables_priv TO conductorone; + GRANT SELECT (Host, User, Db, Column_name, Column_priv, Table_name) ON mysql.columns_priv TO conductorone; + GRANT SELECT (Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, + Drop_priv, Reload_priv, Shutdown_priv, Process_priv, References_priv, Index_priv, + Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, + Execute_priv, Repl_slave_priv, Repl_client_priv, Create_view_priv, Show_view_priv, + Create_routine_priv, Alter_routine_priv, Create_user_priv, Event_priv, Trigger_priv, + Create_tablespace_priv, File_priv, Grant_priv, authentication_string) ON mysql.user TO conductorone; + ``` + + **MySQL 8+:** + + ```sql + GRANT SELECT (USER, HOST, PRIV, WITH_GRANT_OPTION) ON mysql.global_grants TO conductorone; + GRANT SELECT (Host, User, Db, Select_priv, Insert_priv, Update_priv, Delete_priv, + Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, + Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Create_view_priv, + Show_view_priv, Create_routine_priv, Alter_routine_priv, Event_priv, + Trigger_priv) ON mysql.db TO conductorone; + GRANT SELECT (Host, User, Db, Table_priv, Table_name) ON mysql.tables_priv TO conductorone; + GRANT SELECT (Host, User, Db, Column_name, Column_priv, Table_name) ON mysql.columns_priv TO conductorone; + GRANT SELECT (Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, + Drop_priv, Reload_priv, Shutdown_priv, Process_priv, References_priv, Index_priv, + Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, + Execute_priv, Repl_slave_priv, Repl_client_priv, Create_view_priv, Show_view_priv, + Create_routine_priv, Alter_routine_priv, Create_user_priv, Event_priv, Trigger_priv, + Create_tablespace_priv, Create_role_priv, Drop_role_priv, File_priv, Grant_priv, + authentication_string) ON mysql.user TO conductorone; + GRANT SELECT (FROM_HOST, FROM_USER, TO_HOST, TO_USER, WITH_ADMIN_OPTION) ON mysql.role_edges TO conductorone; + ``` + + + Grant `SELECT` on all databases so the connector can introspect schemas: + + ```sql + GRANT SELECT ON *.* TO conductorone; + ``` + + + Note the connection string in DSN format — you will need it when configuring the connector: + + ``` + conductorone:secure-password@tcp(your-mysql-host:3306)/ + ``` + + + +That's it! You now have the credentials needed to configure the connector. + +## Configure the MySQL connector + + + You must have the **Connector Administrator** or **Super Administrator** role in ConductorOne to add a connector. You will need: + + - MySQL connection string (`user:password@tcp(host:port)/`) + + + + + + + In ConductorOne, go to **Connectors** and click **Add connector**. + + + Search for **MySQL** and select it. + + + Set an owner and click **Next**. + + + Click **Edit Settings** and enter the connector configuration. + +{/* AUTO-GENERATED:START - config-params + Generated from config_schema.json. Do not edit manually. */} + + - **connection-string** (required): The connection string for connecting to MySQL in DSN format, e.g. `user:password@tcp(host:3306)/` + - **skip-database**: Comma-separated list of database names to exclude from the sync. + - **expand-columns**: Tables (in `db.table` format) whose column-level privileges should be surfaced as individual entitlements. + - **collapse-users**: When enabled, combines `user@host` pairs that share the same username into a single identity. + +{/* AUTO-GENERATED:END - config-params */} + + + Click **Save**. The connector will begin syncing and show **Connected** when complete. + + + + **Done.** Your MySQL connector is now pulling access data into ConductorOne. + + + ### Resources + + - Binary and packages: [https://dist.conductorone.com/ConductorOne/baton-mysql](https://dist.conductorone.com/ConductorOne/baton-mysql) + - Source code: [https://github.com/conductorone/baton-mysql](https://github.com/conductorone/baton-mysql) + + ### Step 1 + + Add a Baton connector in ConductorOne and rotate credentials to get a C1 Client ID and Client Secret. + + + + In ConductorOne, go to **Connectors** → **Add connector** → **Baton**. + + + Name the connector and set an owner, then save. + + + On the connector detail page, click **Rotate credentials** and copy the **Client ID** and **Client Secret**. + + + + ### Step 2 + + Deploy the connector using Kubernetes. Create the following manifests: + + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: baton-mysql-secret + type: Opaque + stringData: + BATON_CLIENT_ID: "" + BATON_CLIENT_SECRET: "" + BATON_CONNECTION_STRING: "" + ``` + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: baton-mysql + spec: + replicas: 1 + selector: + matchLabels: + app: baton-mysql + template: + metadata: + labels: + app: baton-mysql + spec: + containers: + - name: baton-mysql + image: public.ecr.aws/conductorone/baton-mysql:latest + envFrom: + - secretRef: + name: baton-mysql-secret + ``` + + ### Step 3 + + Apply the manifests and verify the connector appears as **Connected** in ConductorOne. + + ```bash + kubectl apply -f baton-mysql-secret.yaml + kubectl apply -f baton-mysql-deployment.yaml + ``` + + + + + Download the `baton-mysql` binary and packages from the [ConductorOne distribution center](https://dist.conductorone.com/ConductorOne/baton-mysql). + diff --git a/docs/docs-info.md b/docs/docs-info.md new file mode 100644 index 00000000..17d8cb75 --- /dev/null +++ b/docs/docs-info.md @@ -0,0 +1,59 @@ +# Baton MySQL - Connector Documentation + +This document provides information needed to set up and use the connector. + +## Connector Capabilities + +### 1. What resources does the connector sync? + +| Resource | Description | +|----------|-------------| +| **Server** | The MySQL server instance itself; root of the resource hierarchy | +| **Database** | Individual databases hosted on the server; scoped privilege assignments | +| **Table** | Tables within databases; table-level privilege grants | +| **Routine** | Stored procedures and functions; execute/alter privilege grants | +| **User** | MySQL accounts (`user@host`); principal identities in the access graph | +| **Role** | Named role objects (MySQL 8+ only); role-to-user assignment grants | +| **Column** | Individual table columns (optional, requires `--expand-columns`); column-level privilege grants | + +### 2. Can the connector provision any resources? If so, which ones? + +Yes. + +| Resource | Grant | Revoke | Create | Delete | +|----------|-------|--------|--------|--------| +| **Database privileges** | ✅ Grants a privilege on a database to a user | ✅ Revokes a privilege on a database from a user | - | - | +| **Table privileges** | ✅ Grants a privilege on a table to a user | ✅ Revokes a privilege on a table from a user | - | - | +| **Routine privileges** | ✅ Grants a privilege on a routine to a user | ✅ Revokes a privilege on a routine from a user | - | - | +| **Role assignments** | ✅ Assigns a role to a user (MySQL 8+ only) | ✅ Removes a role from a user (MySQL 8+ only) | - | - | +| **User accounts** | - | - | ✅ Creates a new MySQL user with a generated password | ✅ Drops a MySQL user account | + +## Connector Credentials + +### 1. What credentials or information are needed to set up the connector? + +| Credential | Required | Description | +|------------|----------|-------------| +| **connection-string** | Yes | MySQL DSN in Go driver format: `user:password@tcp(host:port)/` | +| **skip-database** | No | Comma-separated list of database names to exclude from sync | +| **expand-columns** | No | Tables (`db.table`) whose column-level privileges are expanded into individual entitlements | +| **collapse-users** | No | Combines `user@host` accounts with the same username into a single identity (default: false) | + +### 2. How are these credentials obtained? + +Create a dedicated MySQL user and grant it the minimum read privileges on `mysql` system tables. See `README.md` (Advanced Setup section) for the exact `GRANT` statements for MySQL 5.7 and MySQL 8+. + +The connection string format is: `username:password@tcp(hostname:3306)/` + +## Additional Notes + +### MySQL Version Requirements + +- **MySQL 5.7 and 8.x** are supported. +- Role sync and role grant/revoke are available on **MySQL 8+** only. The connector detects the server version at runtime and enables role support automatically. + +### API Documentation Links + +- [MySQL 8.0 Reference Manual](https://dev.mysql.com/doc/refman/8.0/en/) +- [MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/) +- [Go MySQL Driver DSN format](https://github.com/go-sql-driver/mysql#dsn-data-source-name) From f22e8aece84c048686db303f0bae22a65003cd39 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Fri, 26 Jun 2026 12:02:16 -0300 Subject: [PATCH 4/5] docs: remove cloud-hosted tab, MySQL is self-hosted only Co-Authored-By: Claude Sonnet 4.6 --- docs/connector.mdx | 172 ++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 95 deletions(-) diff --git a/docs/connector.mdx b/docs/connector.mdx index b76c8826..3e7a5bd3 100644 --- a/docs/connector.mdx +++ b/docs/connector.mdx @@ -113,114 +113,96 @@ That's it! You now have the credentials needed to configure the connector. ## Configure the MySQL connector - You must have the **Connector Administrator** or **Super Administrator** role in ConductorOne to add a connector. You will need: + You must have the **Connector Administrator** or **Super Administrator** role in ConductorOne to add a connector. MySQL is a self-hosted connector — you run the Baton binary in your own infrastructure. You will need: - MySQL connection string (`user:password@tcp(host:port)/`) + - A C1 Client ID and Client Secret (obtained in Step 1 below) - - - - - In ConductorOne, go to **Connectors** and click **Add connector**. - - - Search for **MySQL** and select it. - - - Set an owner and click **Next**. - - - Click **Edit Settings** and enter the connector configuration. +### Resources + +- Binary and packages: [https://dist.conductorone.com/ConductorOne/baton-mysql](https://dist.conductorone.com/ConductorOne/baton-mysql) +- Source code: [https://github.com/conductorone/baton-mysql](https://github.com/conductorone/baton-mysql) + +### Step 1 + +Add a Baton connector in ConductorOne and rotate credentials to get a C1 Client ID and Client Secret. + + + + In ConductorOne, go to **Connectors** → **Add connector** → **Baton**. + + + Name the connector and set an owner, then save. + + + On the connector detail page, click **Rotate credentials** and copy the **Client ID** and **Client Secret**. + + + +### Step 2 + +Deploy the connector using Kubernetes. Create the following manifests: {/* AUTO-GENERATED:START - config-params Generated from config_schema.json. Do not edit manually. */} - - **connection-string** (required): The connection string for connecting to MySQL in DSN format, e.g. `user:password@tcp(host:3306)/` - - **skip-database**: Comma-separated list of database names to exclude from the sync. - - **expand-columns**: Tables (in `db.table` format) whose column-level privileges should be surfaced as individual entitlements. - - **collapse-users**: When enabled, combines `user@host` pairs that share the same username into a single identity. +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: baton-mysql-secret +type: Opaque +stringData: + BATON_CLIENT_ID: "" + BATON_CLIENT_SECRET: "" + BATON_CONNECTION_STRING: "" + # Optional: + # BATON_SKIP_DATABASE: "performance_schema,information_schema" + # BATON_EXPAND_COLUMNS: "mydb.mytable" + # BATON_COLLAPSE_USERS: "true" +``` + +The supported environment variables are: + +- **BATON_CONNECTION_STRING** (required): MySQL connection string in DSN format, e.g. `user:password@tcp(host:3306)/` +- **BATON_SKIP_DATABASE**: Comma-separated list of database names to exclude from the sync. +- **BATON_EXPAND_COLUMNS**: Tables (in `db.table` format) whose column-level privileges should be surfaced as individual entitlements. +- **BATON_COLLAPSE_USERS**: When `true`, combines `user@host` pairs that share the same username into a single identity. {/* AUTO-GENERATED:END - config-params */} - - - Click **Save**. The connector will begin syncing and show **Connected** when complete. - - - - **Done.** Your MySQL connector is now pulling access data into ConductorOne. - - - ### Resources - - - Binary and packages: [https://dist.conductorone.com/ConductorOne/baton-mysql](https://dist.conductorone.com/ConductorOne/baton-mysql) - - Source code: [https://github.com/conductorone/baton-mysql](https://github.com/conductorone/baton-mysql) - - ### Step 1 - - Add a Baton connector in ConductorOne and rotate credentials to get a C1 Client ID and Client Secret. - - - - In ConductorOne, go to **Connectors** → **Add connector** → **Baton**. - - - Name the connector and set an owner, then save. - - - On the connector detail page, click **Rotate credentials** and copy the **Client ID** and **Client Secret**. - - - - ### Step 2 - - Deploy the connector using Kubernetes. Create the following manifests: - - ```yaml - apiVersion: v1 - kind: Secret - metadata: - name: baton-mysql-secret - type: Opaque - stringData: - BATON_CLIENT_ID: "" - BATON_CLIENT_SECRET: "" - BATON_CONNECTION_STRING: "" - ``` - ```yaml - apiVersion: apps/v1 - kind: Deployment +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: baton-mysql +spec: + replicas: 1 + selector: + matchLabels: + app: baton-mysql + template: metadata: - name: baton-mysql + labels: + app: baton-mysql spec: - replicas: 1 - selector: - matchLabels: - app: baton-mysql - template: - metadata: - labels: - app: baton-mysql - spec: - containers: - - name: baton-mysql - image: public.ecr.aws/conductorone/baton-mysql:latest - envFrom: - - secretRef: - name: baton-mysql-secret - ``` - - ### Step 3 - - Apply the manifests and verify the connector appears as **Connected** in ConductorOne. - - ```bash - kubectl apply -f baton-mysql-secret.yaml - kubectl apply -f baton-mysql-deployment.yaml - ``` - - + containers: + - name: baton-mysql + image: public.ecr.aws/conductorone/baton-mysql:latest + envFrom: + - secretRef: + name: baton-mysql-secret +``` + +### Step 3 + +Apply the manifests and verify the connector appears as **Connected** in ConductorOne. + +```bash +kubectl apply -f baton-mysql-secret.yaml +kubectl apply -f baton-mysql-deployment.yaml +``` Download the `baton-mysql` binary and packages from the [ConductorOne distribution center](https://dist.conductorone.com/ConductorOne/baton-mysql). From 790bbbe90326c0b6c2bf5883844ad12cf1998fb7 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Wed, 1 Jul 2026 09:42:12 -0300 Subject: [PATCH 5/5] docs: show comma-separated example for BATON_EXPAND_COLUMNS expand-columns is a string slice like skip-database; show a comma-separated example and note it in the description. Co-Authored-By: Claude Opus 4.8 --- docs/connector.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/connector.mdx b/docs/connector.mdx index 3e7a5bd3..2894cc11 100644 --- a/docs/connector.mdx +++ b/docs/connector.mdx @@ -159,7 +159,7 @@ stringData: BATON_CONNECTION_STRING: "" # Optional: # BATON_SKIP_DATABASE: "performance_schema,information_schema" - # BATON_EXPAND_COLUMNS: "mydb.mytable" + # BATON_EXPAND_COLUMNS: "mydb.mytable,otherdb.othertable" # BATON_COLLAPSE_USERS: "true" ``` @@ -167,7 +167,7 @@ The supported environment variables are: - **BATON_CONNECTION_STRING** (required): MySQL connection string in DSN format, e.g. `user:password@tcp(host:3306)/` - **BATON_SKIP_DATABASE**: Comma-separated list of database names to exclude from the sync. -- **BATON_EXPAND_COLUMNS**: Tables (in `db.table` format) whose column-level privileges should be surfaced as individual entitlements. +- **BATON_EXPAND_COLUMNS**: Comma-separated list of tables (in `db.table` format) whose column-level privileges should be surfaced as individual entitlements. - **BATON_COLLAPSE_USERS**: When `true`, combines `user@host` pairs that share the same username into a single identity. {/* AUTO-GENERATED:END - config-params */}