WAF-OPS-030 โ Observability Stack Configured
Description
Every production workload MUST emit structured logs, expose metrics, and support distributed tracing. An observability stack MUST be configured with centralized log aggregation, a metrics collection system, and distributed tracing. Logs MUST be structured (JSON), include trace IDs and request IDs, and be routed to a centralized platform with defined retention periods.
Rationale
| Risk | Description |
|---|---|
Risk |
Unstructured logs and missing metrics delay troubleshooting and incident detection. |
Risk |
Without centralized observability data, SLO breaches and security incidents cannot be correlated. |
Requirements
-
Every production workload MUST emit structured logs, expose metrics, and support distributed tracing.
-
An observability stack MUST be configured with centralized log aggregation, a metrics collection system, and distributed tracing.
-
Logs MUST be structured (JSON), include trace IDs and request IDs, and be routed to a centralized platform with defined retention periods.
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-030.tf.aws.cloudwatch-log-group-retention
Engine: terraform | Provider: aws | Automated: Yes
CloudWatch log groups must define retention period
All AWS CloudWatch log groups MUST define a retention_in_days value. Log groups without retention will accumulate indefinitely, increasing costs and violating data governance requirements.
Scope: resource โ aws_cloudwatch_log_group
Assertions:
* retention_in_days attribute exists โ CloudWatch log group must define retention_in_days.
* retention_in_days greater than or equal 1 โ Log group retention must be at least 30 days.
Remediation: Add retention_in_days to all aws_cloudwatch_log_group resources. Recommended: 90 days for application logs, 365 days for security/audit logs.
resource "aws_cloudwatch_log_group" "app_logs" {
name = "/aws/ecs/payment-service"
retention_in_days = 90
tags = {
environment = "production"
workload = "payment-service"
}
}
resource "aws_cloudwatch_log_group" "app_logs" {
name = "/aws/ecs/payment-service"
# No retention_in_days โ logs stored indefinitely
# WAF-OPS-030 Violation
}
waf-ops-030.tf.aws.xray-tracing-enabled
Engine: terraform | Provider: aws | Automated: Yes
AWS Lambda functions must have X-Ray tracing enabled
AWS Lambda functions in production MUST have X-Ray tracing enabled to support distributed request tracing and latency analysis.
Scope: resource โ aws_lambda_function
Assertions:
* tracing_config.mode not in ['0.0.0.0/0', ''] โ Lambda tracing mode must be Active, not PassThrough.
Remediation: Add tracing_config { mode = "Active" } to all aws_lambda_function resources.
resource "aws_lambda_function" "processor" {
function_name = "payment-processor"
role = aws_iam_role.lambda_exec.arn
handler = "index.handler"
runtime = "nodejs20.x"
tracing_config {
mode = "Active"
}
}
resource "aws_lambda_function" "processor" {
function_name = "payment-processor"
role = aws_iam_role.lambda_exec.arn
handler = "index.handler"
runtime = "nodejs20.x"
# No tracing_config โ WAF-OPS-030 Violation
}
waf-ops-030.tf.azurerm.log-analytics-workspace
Engine: terraform | Provider: azurerm | Automated: Yes
Azure Log Analytics workspace must be configured with retention
Azure deployments MUST configure a Log Analytics workspace with an appropriate retention period for centralized log aggregation.
Scope: resource โ azurerm_log_analytics_workspace
Assertions:
* retention_in_days greater than or equal 1 โ Log Analytics workspace retention must be at least 30 days.
Remediation: Set retention_in_days to at least 90 for application logs in the azurerm_log_analytics_workspace resource.
resource "azurerm_log_analytics_workspace" "main" {
name = "law-payment-service-prod"
location = var.location
resource_group_name = azurerm_resource_group.main.name
sku = "PerGB2018"
retention_in_days = 90
}
resource "azurerm_log_analytics_workspace" "main" {
name = "law-payment-service-prod"
location = var.location
resource_group_name = azurerm_resource_group.main.name
sku = "PerGB2018"
retention_in_days = 7
# 7 days is insufficient โ WAF-OPS-030 Violation
}
waf-ops-030.tf.google.logging-project-sink-exists
Engine: terraform | Provider: google | Automated: Yes
GCP Cloud Logging sink must route structured logs to a centralized destination
Every production GCP project must define a google_logging_project_sink that routes structured logs to a central BigQuery dataset or Cloud Storage bucket. Cloud Trace must be enabled via the trace API usage.
Scope: resource โ google_logging_project_sink
Assertions:
* destination attribute exists โ GCP project must route logs to a centralized BigQuery or Cloud Storage destination.
Remediation: Create a google_logging_project_sink for each production project with filter capturing application, audit, and security logs. Enable Cloud Trace API and configure applications to export traces.
resource "google_logging_project_sink" "central" {
name = "centralized-logs"
destination = "bigquery.googleapis.com/projects/${var.project_id}/datasets/logs"
filter = "severity >= WARNING OR protoPayload.serviceName != \"\""
unique_writer_identity = true
}
# No google_logging_project_sink defined
# Application logs remain only in default log buckets
waf-ops-030.tf.stackit.log-destination-exists
Engine: terraform | Provider: stackit | Automated: Yes
STACKIT workloads must ship logs to a central destination
STACKIT workloads must ship logs to a central destination. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ stackit_argus_instance, stackit_logme_instance, stackit_observability_instance
Assertions:
* project_id attribute exists โ STACKIT observability/log instance must be configured.
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_argus_instance" "example" {
# required attribute/tag/label present
}
# Example resource does not meet the requirement.
resource "stackit_argus_instance" "example" {
# Missing required attribute/tag/label
}
waf-ops-030.tf.ovh.log-destination-exists
Engine: terraform | Provider: ovh | Automated: Yes
OVHcloud workloads must ship logs to a central destination
OVHcloud workloads must ship logs to a central destination. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ ovh_cloud_project_database_postgresql, ovh_cloud_project_kube, ovh_dedicated_server
Assertions:
* service_name attribute exists โ OVHcloud service must be configured for log forwarding.
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_database_postgresql" "example" {
# required attribute/tag/label present
}
# Example resource does not meet the requirement.
resource "ovh_cloud_project_database_postgresql" "example" {
# Missing required attribute/tag/label
}
waf-ops-030.tf.hcloud.log-destination-exists
Engine: terraform | Provider: hcloud | Automated: Yes
Hetzner Cloud workloads must ship logs to a central destination
Hetzner Cloud workloads must ship logs to a central destination. This check validates the Terraform configuration uses the expected resource and attribute.
Scope: resource โ hcloud_server
Assertions:
* labels.log-destination key exists โ Hetzner Cloud server must declare a log destination 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. |
Related Controls
| Framework | Controls |
|---|---|
ISO/IEC 20000-1 |
* Monitoring, measurement, analysis, and evaluation * Service availability management |
ITIL 4 |
* Monitoring and event management * Service configuration management |
SOC 2 Type II |
* CC7.1 โ Detect and Monitor โ Vulnerability and Threat Detection |
BSI C5:2020 |
* OIS-10 Protokollierung und Monitoring |