Auto-Create Tenant SonarQube User and Connector with Tekton
When a new tenant starts running SonarQube code scans on Alauda
Container Platform, the administrator has to manage the tenant's
SonarQube account and permissions, create and maintain the tenant
sonarqube Connector and auth Secret on the cluster, and keep the
user token rotated before it expires — for every tenant, on every
rotation cycle. This guide automates that whole flow with a single
Tekton TaskRun: run it once to provision the tenant, and schedule the
same TaskRun on a recurring cadence to rotate the token in place
without manual intervention.
The implementation mechanism is the
sonarqube-connector-automatic-creation Task.
This page focuses on the operator workflow. For the parameter,
workspace, result, and step reference, see the
Task reference.
TOC
Before You BeginCluster prerequisitesSonarQube instance prerequisitesKubernetes RBACLocal user creation must be allowedOnboarding walkthrough1. Verify the admin Connector2. Pick the tenant's project key pattern3. Apply the onboarding TaskRun4. Smoke-test the tenant tokenRotationMulti-tenant onboardingTenant offboardingTroubleshootingSee alsoBefore You Begin
Cluster prerequisites
- Tekton Pipelines is installed. See the Tekton Pipelines installation guide.
- The Connectors system and the SonarQube ConnectorClass are
installed — the connectors-operator handles both via
ConnectorsConfig. See the Connectors Installation Guide and make sureConnectorsSonarQubeis enabled in yourConnectorsConfig. - The
sonarqube-connector-automatic-creationTask is installed in the namespace where you will run the TaskRun. See Installation in the Task reference for the apply recipe. - The default
sonarqubeAutomationImage(or its mirror) is reachable from the cluster.
SonarQube instance prerequisites
Configure these once at the instance level so the tenant model behaves correctly. These are set by a SonarQube administrator, not the Task.
Only P5 is enforced by the Task. P1–P4 are tenant-isolation hardening: the Task still succeeds without them, but the boundaries between tenants weaken. Audit them before onboarding the first tenant.
Kubernetes RBAC
The TaskRun's ServiceAccount needs get/create/patch/update/delete
on Secret and Connector in each tenant namespace. The recommended
shape is a per-tenant-namespace Role — sharing a ClusterRole across
tenants removes the boundary that keeps a misconfigured tenant
TaskRun from writing into a sibling namespace.
The Task uses Server-Side Apply with field manager connector-auto,
so a re-run is a no-op when the live spec already matches.
Cross-cluster variant. When the tenant Connector + Secret live on
a different cluster, bind the kubeconfig workspace at TaskRun time;
the kubeconfig's embedded identity replaces this cluster-side RBAC.
Local user creation must be allowed
The Task provisions the tenant bot user via
POST /api/users/create local=true. The target instance must accept
that call. There is no preflight — when local user creation is
disabled, the failure surfaces the first time the Task tries to
create a user, as HTTP 400 with a body explaining that user
management has been delegated.
SonarQube Community does not include the mechanisms below, and pure SSO login (SAML / OIDC / GitHub-as-login / GitLab-as-login, without provisioning) does not trigger this. The known blockers are SonarQube Enterprise / Data Center provisioning integrations:
If one is active, pick a fallback before onboarding:
- Recommended — turn off the provisioning integration, keep SSO login. SonarQube returns to admin-managed users; the SSO login integration stays intact.
- Have the IDP provision the bot users. Pre-provision each
<tenant>-botfrom the IDP; the Task'susers/searchpath reuses the IDP-provisioned user and proceeds to grant + template + token. - Manual fallback — pre-create in a provisioning-off window. An
admin disables provisioning briefly, creates each
<tenant>-botlocal user, then re-enables provisioning and runs the Task.
In all three cases the permission template + provisioning grant +
token mint still run automatically.
Onboarding walkthrough
This walkthrough provisions tenant acme onto the SonarQube instance
behind the admin Connector connectors-management/admin-sonar. It
creates acme-prod/acme-sonarqube as the tenant sonarqube
Connector.
1. Verify the admin Connector
The Connector should be Ready=True. Before onboarding the first
tenant, also confirm P5 — the admin token must hold global admin:
Your admin login must appear in the output.
2. Pick the tenant's project key pattern
The projectPattern regex must match all tenant project keys and
must not overlap with other tenants. Anchor on a tenant prefix:
Document the chosen prefix in your tenant catalog so sibling tenants respect the boundary.
3. Apply the onboarding TaskRun
The Task auto-detects how the sonarqube-config workspace is bound.
Pick one mode:
The example below uses Secret-direct. The TaskRun assumes a
pre-created Secret admin-sonar-credentials in the
connectors-management namespace carrying the admin token verified
in step 1:
For the Connectors CSI Driver binding, swap the workspaces: block
to a CSI projection of the SonarQube sonar-scanner ConnectorClass —
the rest of the TaskRun is identical.
Apply with kubectl apply -f onboarding.yaml, then watch the TaskRun:
A successful run leaves these results:
And these cluster objects in acme-prod:
Secret/acme-sonarqube-secret(typeconnectors.cpaas.io/bearer-token)Connector/acme-sonarqube(Ready=True, points to the Secret above)
4. Smoke-test the tenant token
A negative check — pretending to be tenant bravo:
A HTTP 404 here would mean the projectKeyPattern check is being
bypassed — re-verify the permission template's pattern matches what
you set in projectPattern.
Delete the smoke-test project (api/projects/delete) once you have
verified visibility and the cross-tenant denial.
Rotation
The Task is idempotent: re-running it with the same params reuses the
tenant user, template, and provisioning grant; the token is reused
when it is still tracked by SonarQube and the tenant Secret holds
a non-empty token. The simplest rotation is to re-run the same
TaskRun on a cron — with one wrinkle (below) about when the Task
actually mints a new token.
The Task does not inspect expirationDate. SonarQube has no
token-renew API; if a token is still in user_tokens/search but
expired, the Task treats it as reused and the expiry surfaces at scan
time as a 401. The operator decides how to bridge this:
- Time-driven rotation (recommended). Run the TaskRun on a
schedule shorter than
tokenDuration(e.g. every 15 days fortokenDuration=30), and before each run delete the tenant Secret. The Task's next run sees the empty Secret, mints a freshtokenDuration-day token, and rewrites the Secret. The live token always has≥ tokenDuration/2days left. - Lazy rotation. Schedule the TaskRun at
tokenDuration/2cadence with no other action. The Task reuses the token until SonarQube revokes it onexpirationDate; the next scan-time401is followed by the next cron tick, which mints fresh. Simple, but leaves a brief 401 window. - No cron — manual on 401. The Task only re-runs when an operator triggers it after a scan-time 401. Suitable for low-throughput tenants.
The exact cron wiring (Tekton-on-cron controller, TriggerSchedule,
or a CronJob that kubectl creates the TaskRun) is operator-specific;
the Task's contract is just "re-run me with the same params, after
deleting the tenant Secret".
Multi-tenant onboarding
Onboard a second tenant bravo by applying a second TaskRun with a
non-overlapping projectPattern:
The two tenants' permission templates do not overlap, so:
acme-botcan auto-createacme:*projects but notbravo:*.bravo-botcan auto-createbravo:*projects but notacme:*.- Cross-tenant API reads return
403 Insufficient privileges.
The cross-tenant denial holds only when P3 is enforced — i.e. the
Default Template has no project-level grants on sonar-users or
Anyone. Otherwise the default group's grants leak into every
auto-created project regardless of the per-tenant template. Audit the
Default Template before treating cross-tenant denial as a security
boundary.
Maintain a tenant catalog (project pattern + connector ref) so future tenants do not pick an overlapping pattern. The Task itself does not enforce non-overlap.
Tenant offboarding
When a tenant is decommissioned, undo what the Task created — the
SonarQube-side artifacts (token, permission template, provisioning
grant, bot user) first, then the cluster-side Connector + Secret.
This ordering closes the "Connector deleted but tenant token still
valid" window. Every call is idempotent: a 404 from SonarQube and a
missing Kubernetes object are both treated as already-gone, so a
partial or aborted run heals on re-run.
Save the script below as sonarqube-tenant-offboard.sh and run it
with the tenant + admin credentials:
Required env vars: TENANT, CONNECTOR_REF (in namespace/name
form, as passed to the Task's connector param), SONAR (the
SonarQube base URL), ADMIN_TOKEN (a SonarQube user token from a
user holding Administer System — see P5; pass
it without the trailing colon, the script appends it internally for
curl Basic auth). The script runs a preflight against
/api/users/current and refuses to proceed when the token holder
lacks the global admin permission, so a misconfigured token fails
fast instead of partway through the SonarQube teardown.
Optional overrides: USERNAME (defaults to <tenant>-bot),
TEMPLATE (defaults to <tenant>-template), and DEACTIVATE_USER
(defaults to true; set false to keep the SonarQube user
reactivatable — templates and tokens are still removed).
Existing tenant projects on SonarQube are not deleted by this
script — admins can still see them, and (because P1 makes them
private) other tenants cannot. Delete via api/projects/delete once
the data is exported or migrated.
Troubleshooting
For connector-class-side errors that surface after the Task has run, see the SonarQube Connector troubleshooting guide.
See also
- Task reference — parameters, workspaces, results, and step details.
- SonarQube ConnectorClass — the Connector model the Task writes to the cluster.
- Quick start — manual onboarding without the Task, useful for one-off SonarQube integrations.