State Sources
State sources tell DriftWise where your Terraform state lives. During drift detection, DriftWise fetches state from these sources and compares it against live cloud infrastructure. Endpoint shapes live in the state-sources tag of the API reference.
No state-lock interaction
DriftWise reads your state file. It never acquires the Terraform
state lock. No DynamoDB, Cloud Storage lock object, Azure blob
lease, or Terraform Cloud lock API is touched. Running
terraform apply while DriftWise fetches is safe — the fetcher
issues a single object read against the configured key, nothing
more.
Supported kinds
| Kind | Driver status | Description |
|---|---|---|
s3 | Shipped | AWS S3 bucket |
gcs | Shipped | Google Cloud Storage |
azure_blob | Shipped | Azure Blob Storage |
tfc | Roadmap | Terraform Cloud / Enterprise |
upload | Roadmap | Manual state upload |
The three shipped drivers share the same credential path as the
scanner: static keys, role-chain (AWS sts:AssumeRole), and OIDC
federation (AWS sts:AssumeRoleWithWebIdentity, GCP workload
identity, Azure OIDC client assertion) all work identically for
state fetches.
Adding an S3 state source
- Have an AWS cloud account registered in DriftWise. The account's IAM principal must have state-bucket read permissions — see Reading Terraform state from S3.
- Open Settings → State Sources → Add state source.
- Fill in:
- Display name — any label.
- AWS cloud account — which linked account's credentials to use for the S3 read. Operators with strict least-privilege can register a second cloud account scoped only to the state bucket and link it here.
- Bucket — the S3 bucket name.
- Key — the state object key, e.g.
env/prod/terraform.tfstate. - Region — optional; defaults to the linked cloud account's default region.
- Save. DriftWise does not fetch on create — the next scan (or a manual Refresh click) triggers the first fetch.
Adding a GCS state source
- Have a GCP cloud account registered in
DriftWise. The account's principal (service-account JSON key,
or the target SA for workload identity) must have
roles/storage.objectVieweron the state bucket — see Reading Terraform state from GCS. - Open Settings → State Sources → Add state source.
- Fill in:
- Display name — any label.
- GCP cloud account — which linked account's credentials to use for the GCS read.
- Bucket — the GCS bucket name.
- Object — the state object path, e.g.
terraform/prod/terraform.tfstate.
- Save.
GCS buckets have no region field on the state source — the bucket's location is intrinsic to the bucket.
Adding an Azure Blob state source
- Have an Azure cloud account registered in DriftWise. The service principal (or OIDC-federated identity) must have the Storage Blob Data Reader role on the storage account — see Reading Terraform state from Azure Blob.
- Open Settings → State Sources → Add state source.
- Fill in:
- Display name — any label.
- Azure cloud account — which linked account's credentials to use for the blob read.
- Storage account — the storage account name (not a URL).
DriftWise builds the service URL internally as
https://{storage_account}.blob.core.windows.net. - Container — the container holding the blob.
- Blob — the blob path within the container, e.g.
prod/terraform.tfstate.
- Save.
Azure authentication uses Entra ID (AAD) tokens only — storage account keys and shared-access signatures are not supported. The Storage Blob Data Reader grant is therefore the only thing that matters for blob access.
How state is fetched
- Automatic, on-demand. When the drift worker claims a completed scan, it refreshes every linked state source whose staleness exceeds 5 minutes before computing drift. Content-hash dedupe skips the parse + ingest tail when the state is unchanged.
- Manual refresh. The Refresh button on each state source row forces a fetch, bypassing the 5-minute staleness window. The UI disables the button while the refresh is in flight; the server-side budget is 5 minutes.
Per-source fetch errors land in last_fetch_error on the source
row and render as an inline red banner. The error clears
automatically on the next successful refresh — there is no "dismiss"
button.
Globs (auto-discovery)
A glob points at a bucket (or Azure container) and an optional
prefix. DriftWise lists every .tfstate object under that prefix
(excluding .tfstate.backup files Terraform writes on every apply)
and creates a normal state source for each match. New files added to
the bucket later are picked up automatically on the next scan, or
immediately via the Rescan button.
Available on Team and Enterprise plans. Free plans cannot create
globs — the per-org max_state_sources cap of 1 makes the feature a
no-op there.
How it works:
- Open Settings → State Sources → Add Glob.
- Pick provider (S3 / GCS / Azure Blob), the matching cloud account,
the bucket / container, and an optional prefix to narrow the
scope (e.g.
prod/). - Click Preview — DriftWise lists the bucket and tells you how
many
.tfstatefiles it found and whether the count fits within your plan's remaining state-source budget. - Click Save. Every match becomes a normal state source row, grouped under the glob in the State Sources table. Drift, refresh, and snapshot history all behave identically to a hand-added source.
Limits and behavior:
- A single glob discovers up to 500 files per LIST. If your bucket exceeds that, the first 500 (alphabetical order) are added and the glob's status row tells you to narrow the prefix.
- Each discovered file counts as one state source against
max_state_sources. Globs themselves don't count. - A file deleted from the bucket appears as Missing from source on its child row — the row stays so you don't lose drift history by accident. Manually delete the row when you're sure the state is gone for good.
- Deleting a glob soft-deletes every child it created. Hand-added state sources in the same bucket are unaffected.
- Supported on all three providers (S3, GCS, Azure Blob). The
cloud account's principal needs list permissions on the bucket
in addition to the per-object read permissions a normal source
needs (S3:
s3:ListBucket; GCS:storage.objects.list; Azure: Storage Blob Data Reader at the container level).
Plan limits
max_state_sources is enforced per plan. Hitting the limit returns
402 Payment Required; the UI surfaces this as an upgrade prompt.
Current plan numbers live on the
billing page.
Multi-source scans
A scan_run's cloud_account_id can match multiple state sources
(an account-scoped source plus any number of org-wide sources with
cloud_account_id = NULL). The drift worker refreshes each in
sequence. Partial failure — one source errors while others succeed
— does not block drift computation: the worker proceeds against
whatever IaC data is available and surfaces per-source errors in
the UI. Drift is marked error only when every linked source
errors AND none has a prior snapshot (fail-closed — avoids the
worst failure mode where an empty IaC set makes every live resource
look "extra").
API
See the state-sources tag of the API
reference. Endpoints
require the caller's role to be owner or admin on state-source
mutations; viewer roles can GET but not mutate.