Kubernetes operator
Running the operator
Day-to-day operation of a running policy.
Reconciliation
The operator reconciles on five paths:
PostgresPolicyspec changes- referenced Secret changes
- force-reconcile annotation changes
PostgresPolicyPlanchanges, matched back to the owning policy by controller-owner UID — this is what makes approving or rejecting a plan take effect immediately rather than at the nextinterval- the normal periodic
interval
Each reconcile inspects the current database state, computes a diff from the policy, and then either applies it or publishes a plan depending on spec.mode. Observe mode is non-mutating: it does not execute PostgreSQL DDL and it does not create generated password Secrets. Same-database policies are serialized, and status-only updates do not retrigger the controller.
Use this page for the external behavior and operating model. For the internal controller pipeline and locking model, see the operator architecture page.
Read policy and Secret
Load the PostgresPolicy, fetch DATABASE_URL from the referenced Secret, and refresh the cached pool when credentials change.
Build desired state
Convert the CRD to the shared PolicyManifest model, then expand profiles and schemas into concrete roles, grants, and memberships.
Inspect PostgreSQL
Query the live database state that matters for this policy, including managed roles, privileges, memberships, and provider-specific constraints.
Diff and safety checks
Compute the convergent change plan, detect conflicts, and enforce per-database locking before any mutation is attempted.
Apply in one transaction
Execute the rendered SQL statements inside a single transaction so the reconcile either commits fully or rolls back cleanly.
Patch status and emit telemetry
Write conditions, summaries, and last-error state back to Kubernetes, and export OTLP metrics for runtime visibility.
Interval
The interval field controls how often the operator re-reconciles, even when the resource hasn't changed. This catches drift from manual SQL changes. Supports durations like 30s, 5m, 1h, or compound forms like 1h30m. Defaults to 5m.
Force reconcile
Set reconcile.pgroles.io/requestedAt to a new RFC 3339 timestamp to request an immediate reconcile without changing spec:
kubectl annotate postgrespolicy my-policy \
reconcile.pgroles.io/requestedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--overwrite
The same timestamp is idempotent. Re-setting it is a no-op, while setting a newer value bypasses the normal interval wait. The operator mirrors successfully handled requests to status.lastHandledReconcileAt, which is useful for scripts and runbooks that need to verify the request completed or produced a plan.
The CLI wraps the same annotation flow:
pgroles reconcile postgrespolicy/my-policy -n platform --wait
Suspending
Set suspend: true to pause reconciliation without deleting the resource. The operator will skip the resource until suspend is set back to false.
Reconciliation mode
The reconciliation_mode field controls how aggressively the operator converges the database, independent of mode (which controls whether changes are applied or only planned).
spec:
connection:
secretRef:
name: postgres-credentials
reconciliation_mode: additive # only grant, never revoke
| Value | Behavior |
|---|---|
authoritative (default) | Full convergence — anything not in the manifest is revoked or dropped |
additive | Only grant, never revoke — safe for incremental adoption, and it leaves pre-existing role attributes/comments unchanged |
adopt | Manage declared roles fully, but never drop undeclared roles |
This is the same behavior as the CLI --mode flag. See the CLI reconciliation modes section for detailed semantics.
Deletion behaviour
When a PostgresPolicy resource is deleted, the operator does not revoke grants or drop roles. The database is left as-is. This is intentional — resource deletion means "stop managing", not "undo everything".