feat(otel): use dedicated least-privilege monitoring user for OTel Collector sidecar#420
feat(otel): use dedicated least-privilege monitoring user for OTel Collector sidecar#420udsmicrosoft wants to merge 5 commits into
Conversation
…tor sidecar Copilot-Session: ba406fac-b035-4384-a495-46e2661fafdb Signed-off-by: urismiley <urismiley@microsoft.com>
|
🤖 Auto-triaged by documentdb-triage-tool. Applied: Reasoningcomponent from path globs (controllers, test, manifests); effort from diff stats (568+33 LOC, 17 files); LLM: Multi-file, cross-component security improvement introducing a dedicated least-privilege monitoring role, new secret management, RBAC updates, and sidecar wiring — touches controllers, manifests, and the kubectl-plugin sidecar-injector. If a label is wrong, remove it manually and ping |
There was a problem hiding this comment.
Pull request overview
This PR updates the DocumentDB operator and CNPG sidecar-injector plugin to use a dedicated least-privilege PostgreSQL role (otel_monitor) and a dedicated per-cluster Secret (<cluster>-otel-monitor) for OTel Collector sidecar credentials, instead of reusing the broad CNPG application user credentials.
Changes:
- Introduces
otel_monitorrole +<cluster>-otel-monitorbasic-auth Secret generation/cleanup in the operator and wires CNPG managed roles + plugin params to use it. - Extends CNPG cluster sync to reconcile managed roles independently (so monitoring can be toggled on/off for existing clusters).
- Updates the sidecar-injector plugin to require and consume the new
otelMonitorSecretparameter forPGUSER/PGPASSWORD.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| operator/src/internal/otel/config.go | Adds constants/helpers for monitoring role name and Secret naming. |
| operator/src/internal/otel/config_test.go | Adds unit tests for the new role/secret helpers. |
| operator/src/internal/controller/physical_replication.go | Refactors Azure Fleet managed-services setup to preserve existing spec.managed (e.g., roles). |
| operator/src/internal/controller/physical_replication_test.go | Adds tests for Azure Fleet managed-services behavior and role preservation. |
| operator/src/internal/controller/documentdb_controller.go | Reconciles the new monitoring Secret and cleans it up when monitoring is disabled; adds Secrets RBAC annotation. |
| operator/src/internal/controller/documentdb_controller_test.go | Adds tests for monitoring Secret create/stability and delete behavior. |
| operator/src/internal/cnpg/cnpg_sync.go | Syncs otelMonitorSecret plugin param and adds managed-roles reconciliation logic. |
| operator/src/internal/cnpg/cnpg_sync_test.go | Adds tests for managed-role add/remove/preserve/no-op sync scenarios. |
| operator/src/internal/cnpg/cnpg_patch.go | Adds JSON patch paths for /spec/managed and /spec/managed/roles. |
| operator/src/internal/cnpg/cnpg_cluster.go | Declares the managed otel_monitor role and passes otelMonitorSecret plugin param when monitoring is enabled. |
| operator/src/internal/cnpg/cnpg_cluster_test.go | Adds tests validating managed role + plugin param when monitoring enabled/disabled. |
| operator/src/config/rbac/role.yaml | Grants Secrets write verbs; adjusts ClusterRole rules (kustomize path). |
| operator/documentdb-helm-chart/templates/05_clusterrole.yaml | Grants Secrets write verbs and documents the new per-cluster monitoring Secret. |
| operator/cnpg-plugins/sidecar-injector/internal/lifecycle/lifecycle.go | Requires otelMonitorSecret for sidecar injection and sources PG creds from it. |
| operator/cnpg-plugins/sidecar-injector/internal/lifecycle/lifecycle_test.go | Adds tests asserting the sidecar uses the monitoring Secret for PG creds. |
| operator/cnpg-plugins/sidecar-injector/internal/config/config.go | Adds otelMonitorSecret parameter parsing into typed configuration. |
| operator/cnpg-plugins/sidecar-injector/internal/config/config_test.go | Adds unit test coverage for parsing the new OTel parameters. |
Copilot-Session: ba406fac-b035-4384-a495-46e2661fafdb Signed-off-by: urismiley <urismiley@microsoft.com>
Copilot-Session: ba406fac-b035-4384-a495-46e2661fafdb Signed-off-by: urismiley <urismiley@microsoft.com>
Copilot-Session: ba406fac-b035-4384-a495-46e2661fafdb Signed-off-by: urismiley <urismiley@microsoft.com>
Copilot-Session: ba406fac-b035-4384-a495-46e2661fafdb Signed-off-by: urismiley <urismiley@microsoft.com>
| - apiGroups: [""] | ||
| resources: ["secrets"] | ||
| verbs: ["get", "list", "watch"] | ||
| verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] |
There was a problem hiding this comment.
[Suggestion] Since this adds required Secret write/delete permissions, please call out upgrade ordering in release notes/changelog (apply updated RBAC before or with controller rollout). In local kind testing, running the new controller against old RBAC repeatedly failed with cannot create resource "secrets" until ClusterRole was updated.
xgerman
left a comment
There was a problem hiding this comment.
Summary
[Required] No blocking issues found in this PR.
I validated the key behavior changes locally (including kind):
- dedicated
<cluster>-otel-monitorsecret lifecycle (create/preserve/delete) spec.managed.rolesreconciliation forotel_monitor- sidecar credential wiring (
PGUSER/PGPASSWORD) tootelMonitorSecret - monitoring disable/enable cleanup and re-create path
Targeted tests run clean:
go test ./...(sidecar-injector module)go test ./internal/otel ./internal/cnpg ./internal/controller(operator module)
I left one non-blocking inline suggestion about documenting RBAC upgrade ordering, based on local rollout behavior with stale ClusterRole.
Summary
Closes #344.
The OTel Collector sidecar (added in #342) connected to PostgreSQL using
PGUSER/PGPASSWORDfrom the<cluster>-appsecret — the CNPG applicationuser, which has broad read/write access to application data. This PR switches
the sidecar to a dedicated least-privilege monitoring role that only has
membership in the built-in
pg_monitorrole.What changed
otel_monitorPostgreSQL role via CNPG's managed-roles reconciler(
spec.managed.roles):LOGIN, member ofpg_monitor, nothing else.basic-authsecret<cluster>-otel-monitor(username=otel_monitor, random password). Thepassword is generated once and preserved across reconciles. CNPG consumes it
as the role's
passwordSecret(which requires the secretusernameto matchthe role name exactly).
otelMonitorSecretparameter and sources
PGUSER/PGPASSWORDfrom that secret instead of<cluster>-app.SyncCnpgClusternow reconcilesspec.managed.rolessotoggling monitoring on an existing cluster creates/removes the role. The
Azure-Fleet managed-services path was refactored (
addAzureFleetManagedServices)to preserve managed roles instead of overwriting the whole
spec.managed.05_clusterrole.yamland kustomizerole.yaml) gainscreate;update;patchon secrets.Design notes
connectionLimit=-1,inherit=true,ensure=present) explicitly so the sync diff stays stable anddoesn't re-patch every reconcile.
pg_hbais currentlytrust, so the password isn't strictly enforced today —but scoping the sidecar to a
pg_monitor-only role still delivers theleast-privilege, audit-attribution, and blast-radius benefits, and is
future-proof if auth is tightened.
Testing
go test ./...(operator module) — all passgo test ./...(sidecar-injector plugin module) — all passgo vet/gofmtclean;make manifests generateproduce no diffmanaged-role sync (add/remove/preserve-services/no-op), Azure-Fleet role
preservation, secret reconcile (create + password stability) and delete, and
plugin config/sidecar credential sourcing.