Atlas Kubernetes Operator v0.8: Drift Detection, Security Scanning, and Per-Resource Dev Databases
Hey everyone!
We just released Atlas Kubernetes Operator v0.8, which adds drift detection before and between deployments, security scanning for deployed databases, and a setting for controlling dev databases per resource:
- Pre-Apply Drift Check:
policy.drifton anAtlasMigrationchecks the database for drift before pending migrations are applied, and can block the deployment. - Scheduled Drift Checks:
AtlasDriftCheckchecks the database of anAtlasMigrationfor drift on an interval and reports the result through conditions and Kubernetes events. - Security Scanning:
AtlasSecurityScanscans a database for extensions affected by published CVEs, on a schedule or after a schema change, and grades the findings against a policy. - Per-Resource Dev Database Prewarming:
AtlasSchemaandAtlasMigrationacceptprewarmDevDB, overriding the operator-wide default.
To upgrade an existing installation:
helm upgrade atlas-operator oci://ghcr.io/ariga/charts/atlas-operator --version 0.8.0
To install the operator for the first time, see Installation.
Drift Detection
Drift is any change made to a database outside its migration directory. The operator now detects it in two places: right before a deployment applies pending migrations, and on a schedule between deployments.
Pre-Apply Drift Check
The policy.drift block on an AtlasMigration enables the
pre-apply drift check. Before applying pending migrations, Atlas
compares the target database with the latest applied version stored in the
Atlas Registry:
spec:
dir:
remote:
name: "atlas"
tag: "commit-id"
cloud:
tokenFrom:
secretKeyRef:
key: token
name: atlas-credentials
policy:
drift:
onError: FAIL # FAIL (default) or CONTINUE
exclude:
- "public.audit_*"
With onError: FAIL, a drifted database blocks the deployment before any migration file runs. The Ready
condition turns False with the reason DriftDetected, and the operator retries until backoffLimit is
reached:
$ kubectl get atlasmigrations
NAME READY REASON
app False DriftDetected
With onError: CONTINUE, the drift is logged and the migrations are applied. exclude takes glob patterns
for objects that intentionally live outside the migration directory. The check requires a registry
directory (dir.remote), since the expected state is read from the registry.
See policy.drift for the full reference, including how to
recover from a blocked deployment.
Scheduled Drift Checks
The pre-apply check runs only when a deployment has pending migrations, so a database that drifts while
nothing is pending is not reported until the next deployment. AtlasDriftCheck runs
atlas migrate drift on an interval, so a change made between
deployments is reported when it happens. The check never modifies the database.
apiVersion: db.atlasgo.io/v1alpha1
kind: AtlasDriftCheck
metadata:
name: myapp-drift
spec:
targetRef:
name: myapp # An AtlasMigration in the same namespace.
interval: 5m
onDrift: Report # Report (default) or Fail
exclude:
- "public.audit_*"
The check compares the database with the schema the migration directory defines at the applied version.
When the target uses a registry directory, that state is read from the Atlas Registry.
When it uses a ConfigMap or an inline directory, Atlas replays the migrations on the target's dev database.
The result is stored in the Drifted condition, which counts the drifted objects by kind:
Drifted=True DriftDetected: 2 drifted objects (extra 1, modified 1) at version 20250901000000: table 2
With onDrift: Report, the resource stays Ready and drift shows up only in Drifted. With onDrift: Fail,
drift also sets Ready=False, so GitOps tools that track readiness report the resource as unhealthy.
The check emits DriftDetected, DriftChanged, and DriftResolved events only when the result changes. A
database that stays drifted across many checks produces a single event, so events can feed alerts directly:
kubectl get events --field-selector involvedObject.kind=AtlasDriftCheck
See Drift Detection for the full field reference.
Security Scanning
AtlasSecurityScan runs atlas security scan from the operator. It reports the
extensions installed in the database that are affected by a published CVE, resolved against the
Security Graph.
apiVersion: db.atlasgo.io/v1alpha1
kind: AtlasSecurityScan
metadata:
name: app
spec:
urlFrom:
secretKeyRef:
name: app-db
key: url
cloud:
tokenFrom:
secretKeyRef:
name: atlas-token
key: ATLAS_TOKEN
schedule: "0 6 * * *"
timeZone: UTC
triggers:
- kind: AtlasMigration
name: app-migrations
policy:
minSeverity: ELEVATED
failOn: HIGH
This scan runs once when the resource is created, every day at 06:00 UTC, and again each time the
app-migrations resource applies a new version. A scan can also be requested on demand with the
db.atlasgo.io/scan-requested-at annotation.
The result is split across two conditions. Ready says whether the scan ran. Compliant says whether
the database is within the policy: it turns False when a finding at or above failOn is found. Use
kubectl wait --for=condition=Compliant as a deployment gate:
kubectl get atlassecurityscans
NAME READY REASON COMPLIANT FINDINGS HIGHEST LAST SCAN NEXT SCAN AGE
app True Scanned False 3 HIGH 0s 2026-10-01T06:00:00Z 6s
To accept a known finding, add a waiver under policy.ignore with a reason and an optional expiration time.
A waived finding stays in the report but no longer counts toward the verdict, and the scan runs again
when the waiver expires:
policy:
failOn: HIGH
ignore:
- id: CVE-2026-14678
reason: "pg_trgm is not reachable from the application role; SEC-1234"
expirationTime: "2026-12-31T00:00:00Z"
Reports and Access
The scan status holds only a summary: counts per severity level, with no extension names or CVE
identifiers. The findings are stored in an AtlasSecurityReport with the same name, which lists each
extension, its version, the CVEs affecting it, and a suggested fix.
Since the report shows which extensions are vulnerable, it is excluded from the built-in view and edit
roles. The Helm chart ships a dedicated securityreport-viewer ClusterRole, aggregated into admin by
default and configurable with rbac.securityReports.
See Security Scanning with the Kubernetes Operator for the complete guide.
Per-Resource Dev Database
The operator keeps the dev database it manages for each resource running between
reconciliations, controlled by the operator-wide prewarmDevDB Helm value. AtlasSchema and
AtlasMigration now accept spec.prewarmDevDB, which overrides that default for a single resource:
apiVersion: db.atlasgo.io/v1alpha1
kind: AtlasMigration
metadata:
name: myapp
spec:
prewarmDevDB: false
urlFrom:
secretKeyRef:
key: url
name: db-credentials
dir:
configMapRef:
name: migrations
With false, the operator scales the dev database down to zero after the resource is reconciled. With
true, it stays running. When the field is unset, the Helm value applies.
Wrapping Up
Operator v0.8 checks a deployed database for drift both before and between deployments, scans it for
extensions affected by published CVEs, and lets each AtlasSchema and AtlasMigration decide whether its
dev database stays running. For the full changelog, see the
v0.8.0 release on GitHub.
We'd love to hear your feedback! Join our Discord server or schedule a demo.
