WAF-OPS-090 โ Configuration Drift Detection & Remediation
Description
All production infrastructure MUST be continuously compared against its IaC definition. Configuration drift โ any difference between the actual infrastructure state and the declared IaC state โ MUST be detected automatically, reported to the owning team, and remediated within defined SLAs based on severity. Emergency manual changes MUST be codified in IaC within 24 hours.
Rationale
| Risk | Description |
|---|---|
Risk |
Drift between IaC and actual infrastructure leads to shadow IT and unexpected configurations. |
Risk |
Undetected manual changes undermine compliance and security controls. |
Requirements
-
All production infrastructure MUST be continuously compared against its IaC definition.
-
Configuration drift โ any difference between the actual infrastructure state and the declared IaC state โ MUST be detected automatically, reported to the owning team, and remediated within defined SLAs based on severity.
-
Emergency manual changes MUST be codified in IaC within 24 hours.
Implementation Guidance
-
Document the requirement in a version-controlled policy or standard.
-
Assign ownership and establish a review cadence (e.g., quarterly).
-
Implement the required configuration as code in Terraform or equivalent IaC.
Maturity Levels
| Level | Name | Criteria |
|---|---|---|
L1 |
Ad hoc โ control not consistently applied |
* Manual evidence exists for some workloads, but coverage is unknown. |
L2 |
Standardised โ policy defined and communicated |
* A version-controlled policy, ADR, or standard describes the requirement. |
L3 |
Integrated โ automated validation in CI/CD |
* Terraform checks run automatically on pull requests and report results. |
L4 |
Auditable โ metrics and exceptions tracked |
* Control coverage, failures, and approved exceptions are reported quarterly. |
L5 |
Optimised โ continuous improvement based on data |
* Control effectiveness is measured and iteratively improved. |
Checks
waf-ops-090.tf.aws.config-rule-enabled
Engine: terraform | Provider: aws | Automated: Yes
AWS Config must be enabled with compliance rules for drift detection
AWS Config MUST be enabled in production accounts and MUST have compliance rules configured to detect configuration changes and non-compliant resource states.
Scope: resource โ aws_config_configuration_recorder
Assertions:
* recording_group attribute exists โ AWS Config recorder must define recording_group.
Remediation: Enable AWS Config with a configuration recorder and delivery channel. Add aws_config_config_rule resources for key compliance checks.
resource "aws_config_configuration_recorder" "main" {
name = "default"
role_arn = aws_iam_role.config_role.arn
recording_group {
all_supported = true
include_global_resource_types = true
}
}
resource "aws_config_delivery_channel" "main" {
name = "default"
s3_bucket_name = aws_s3_bucket.config.bucket
}
resource "aws_config_config_rule" "s3_public_read_prohibited" {
name = "s3-bucket-public-read-prohibited"
source {
owner = "AWS"
source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED"
}
}
# No AWS Config recorder or rules defined
# WAF-OPS-090 Violation: no configuration drift detection
waf-ops-090.tf.aws.cloudtrail-enabled
Engine: terraform | Provider: aws | Automated: Yes
AWS CloudTrail must be enabled for all regions to detect console changes
AWS CloudTrail MUST be enabled across all regions to audit all API calls, including console changes that may indicate configuration drift from IaC.
Scope: resource โ aws_cloudtrail
Assertions:
* is_multi_region_trail is true โ CloudTrail must be a multi-region trail to capture all console changes.
* enable_log_file_validation is true โ CloudTrail must have log file validation enabled.
Remediation: Set is_multi_region_trail = true and enable_log_file_validation = true on your aws_cloudtrail resource.
resource "aws_cloudtrail" "main" {
name = "production-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail.id
is_multi_region_trail = true
enable_log_file_validation = true
include_global_service_events = true
}
resource "aws_cloudtrail" "main" {
name = "production-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail.id
is_multi_region_trail = false
enable_log_file_validation = false
# Single-region trail without validation โ WAF-OPS-090 Violation
}
waf-ops-090.tf.azurerm.policy-assignment-drift
Engine: terraform | Provider: azurerm | Automated: Yes
Azure Policy must be assigned for configuration compliance monitoring
Azure Policy initiatives MUST be assigned to production subscriptions or resource groups to continuously evaluate configuration compliance and detect drift.
Scope: resource โ azurerm_subscription_policy_assignment
Assertions:
* policy_definition_id not empty โ Policy assignment must reference a policy or initiative definition.
Remediation: Assign Azure Policy or built-in initiative (e.g., Azure Security Benchmark) to the production subscription using azurerm_subscription_policy_assignment.
data "azurerm_policy_set_definition" "security_benchmark" {
display_name = "Azure Security Benchmark"
}
resource "azurerm_subscription_policy_assignment" "security" {
name = "security-benchmark"
subscription_id = data.azurerm_subscription.current.id
policy_definition_id = data.azurerm_policy_set_definition.security_benchmark.id
description = "Azure Security Benchmark for configuration drift detection"
display_name = "Security Benchmark โ Production"
}
# No Azure Policy assigned to subscription
# Configuration drift undetectable โ WAF-OPS-090 Violation
waf-ops-090.tf.google.security-command-center-asset-drift
Engine: terraform | Provider: google | Automated: Yes
GCP Security Command Center must be enabled for asset inventory and drift detection
GCP Security Command Center (SCC) or Asset Inventory feeds must be enabled to continuously compare cloud resources against the IaC definition. Audit logging must be enabled to detect console/API changes.
Scope: resource โ google_security_center_notification_config, google_logging_project_sink
Assertions:
* pubsub_topic attribute exists โ Security Command Center notification config must route asset findings to a Pub/Sub topic.
Remediation: Enable Security Command Center at the organization level. Create google_security_center_notification_config resources to route asset changes and findings. Ensure google_logging_project_sink routes audit logs to a durable store.
resource "google_security_center_notification_config" "asset_changes" {
config_id = "asset-drift"
organization = var.org_id
pubsub_topic = google_pubsub_topic.scc.id
streaming_config {
filter = "category = \"CATEGORY_ASSET\""
}
}
resource "google_logging_project_sink" "audit" {
name = "audit-logs"
destination = "bigquery.googleapis.com/projects/${var.project_id}/datasets/audit_logs"
filter = "protoPayload.@type=\"type.googleapis.com/google.cloud.audit.AuditLog\""
}
# Security Command Center not enabled; no audit log sink configured.
# Manual console changes can drift undetected.
waf-ops-090.tf.stackit.ci-cd-enabled
Engine: terraform | Provider: stackit | Automated: Yes
STACKIT infrastructure must be deployed via CI/CD
STACKIT infrastructure must be deployed via CI/CD. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ stackit_ske_cluster
Assertions:
* labels.cicd-pipeline key exists โ STACKIT SKE cluster is missing the 'cicd-pipeline' label.
Remediation: Review the Terraform configuration for the listed resource types and ensure the required attribute or tag is present. See the control narrative for provider-specific guidance.
# Example resource meets the requirement.
resource "stackit_ske_cluster" "example" {
# required attribute/tag/label present
}
# Example resource does not meet the requirement.
resource "stackit_ske_cluster" "example" {
# Missing required attribute/tag/label
}
waf-ops-090.tf.ovh.ci-cd-enabled
Engine: terraform | Provider: ovh | Automated: Yes
OVHcloud infrastructure must be deployed via CI/CD
OVHcloud infrastructure must be deployed via CI/CD. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ ovh_cloud_project_kube
Assertions:
* tags.cicd-pipeline key exists โ OVHcloud Kubernetes cluster is missing the 'cicd-pipeline' tag.
Remediation: Review the Terraform configuration for the listed resource types and ensure the required attribute or tag is present. See the control narrative for provider-specific guidance.
# Example resource meets the requirement.
resource "ovh_cloud_project_kube" "example" {
# required attribute/tag/label present
}
# Example resource does not meet the requirement.
resource "ovh_cloud_project_kube" "example" {
# Missing required attribute/tag/label
}
waf-ops-090.tf.hcloud.ci-cd-enabled
Engine: terraform | Provider: hcloud | Automated: Yes
Hetzner Cloud infrastructure must be deployed via CI/CD
Hetzner Cloud infrastructure must be deployed via CI/CD. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ hcloud_server
Assertions:
* labels.cicd-pipeline key exists โ Hetzner Cloud server is missing the 'cicd-pipeline' label.
Remediation: Review the Terraform configuration for the listed resource types and ensure the required attribute or tag is present. See the control narrative for provider-specific guidance.
# Example resource meets the requirement.
resource "hcloud_server" "example" {
# required attribute/tag/label present
}
# Example resource does not meet the requirement.
resource "hcloud_server" "example" {
# Missing required attribute/tag/label
}
Evidence
| Kind | Required | Description |
|---|---|---|
|
Required |
Terraform configuration implementing the control. |
|
Required |
Policy, ADR, or standard documenting the requirement. |
|
Optional |
Cloud console or API output confirming runtime state. |