WAF-SEC-030 โ Encryption at Rest with CMK
Description
All data stores containing sensitive or classified data MUST be encrypted at rest using customer-managed keys (CMK) stored in AWS KMS. Automatic key rotation MUST be enabled for all CMKs. Encryption using only provider-managed keys (SSE-S3/AES256) is NOT sufficient for sensitive, PII, financial, or regulated data. KMS key deletion windows MUST be set to a minimum of 7 days. KMS key policies MUST restrict access to explicitly authorized principals only.
Rationale
| Risk | Description |
|---|---|
Risk |
Sensitive data is exposed if storage or transport lacks strong encryption. |
Risk |
Compromised keys or weak key rotation extend the blast radius of a breach. |
Requirements
-
All data stores containing sensitive or classified data MUST be encrypted at rest using customer-managed keys (CMK) stored in AWS KMS.
-
Automatic key rotation MUST be enabled for all CMKs.
-
KMS key deletion windows MUST be set to a minimum of 7 days.
-
KMS key policies MUST restrict access to explicitly authorized principals only.
Implementation Guidance
-
Implement the required configuration as code in Terraform or equivalent IaC.
-
Add an automated check to CI/CD so deviations are caught before deployment.
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-sec-030.tf.aws.rds-encryption-enabled
Engine: terraform | Provider: aws | Automated: Yes
RDS instances and clusters must be encrypted at rest with a CMK
All RDS database instances and Aurora clusters must have storage_encrypted = true and must reference a customer-managed KMS key via kms_key_id.
Scope: resource โ aws_db_instance, aws_rds_cluster
Assertions:
* storage_encrypted is true โ RDS instance/cluster must have storage encryption enabled (storage_encrypted = true).
* kms_key_id attribute exists โ RDS instance/cluster must use a customer-managed KMS key (kms_key_id must be set).
Remediation: Set storage_encrypted = true and kms_key_id = aws_kms_key.rds_key.arn on the aws_db_instance or aws_rds_cluster resource. Note: enabling encryption on an existing unencrypted RDS instance requires creating an encrypted snapshot and restoring to a new instance. Plan for a maintenance window.
resource "aws_kms_key" "rds" {
description = "CMK for RDS encryption"
enable_key_rotation = true
deletion_window_in_days = 30
}
resource "aws_db_instance" "main" {
identifier = "app-db-prod"
engine = "postgres"
instance_class = "db.t3.medium"
storage_encrypted = true
kms_key_id = aws_kms_key.rds.arn
# ... other required attributes
}
resource "aws_db_instance" "main" {
identifier = "app-db-prod"
engine = "postgres"
instance_class = "db.t3.medium"
storage_encrypted = false # WAF-SEC-030 violation
# kms_key_id not set โ using default AWS-managed key
}
waf-sec-030.tf.aws.kms-key-rotation
Engine: terraform | Provider: aws | Automated: Yes
KMS keys must have automatic rotation enabled and a sufficient deletion window
All customer-managed KMS keys must have enable_key_rotation = true and deletion_window_in_days >= 7 to ensure keys are regularly rotated and accidental deletion can be recovered.
Scope: resource โ aws_kms_key
Assertions:
* enable_key_rotation is true โ KMS key must have automatic rotation enabled (enable_key_rotation = true).
* deletion_window_in_days greater than or equal 7 โ KMS key deletion window must be at least 7 days to allow recovery from accidental deletion.
Remediation: Set enable_key_rotation = true on all aws_kms_key resources. Set deletion_window_in_days to at least 7 (recommend 30 for production keys). Note: key rotation does not apply to asymmetric keys or keys in external key stores; those require separate rotation procedures.
resource "aws_kms_key" "app_data" {
description = "CMK for application data encryption"
enable_key_rotation = true
deletion_window_in_days = 30
tags = {
owner = "platform-team"
environment = "production"
}
}
resource "aws_kms_key" "app_data" {
description = "CMK for application data"
enable_key_rotation = false # WAF-SEC-030 violation
deletion_window_in_days = 3 # WAF-SEC-030 violation: below 7-day minimum
}
waf-sec-030.tf.azurerm.key-vault-key-expiration
Engine: terraform | Provider: azurerm | Automated: Yes
Azure Key Vault keys used for encryption must have an expiration date
All azurerm_key_vault_key resources that protect sensitive data must have expiration_date set to enforce key lifecycle and rotation.
Scope: resource โ azurerm_key_vault_key
Assertions:
* expiration_date attribute exists โ Key Vault key must have an expiration_date for lifecycle management.
Remediation: Set expiration_date on every azurerm_key_vault_key resource used for workload encryption. Establish a key rotation process that refreshes keys before expiration.
resource "azurerm_key_vault_key" "app" {
name = "app-encryption-key"
key_vault_id = azurerm_key_vault.main.id
key_type = "RSA"
key_size = 2048
expiration_date = "2026-01-01T00:00:00Z"
}
resource "azurerm_key_vault_key" "app" {
name = "app-encryption-key"
key_vault_id = azurerm_key_vault.main.id
key_type = "RSA"
key_size = 2048
# expiration_date not set
}
waf-sec-030.tf.azurerm.key-vault-purge-protection
Engine: terraform | Provider: azurerm | Automated: Yes
Azure Key Vault must have purge protection and soft delete enabled
All azurerm_key_vault resources must have purge_protection_enabled = true and soft_delete_retention_days >= 7 to protect against accidental or malicious key destruction.
Scope: resource โ azurerm_key_vault
Assertions:
* purge_protection_enabled is true โ Key Vault purge protection must be enabled.
* soft_delete_retention_days greater than or equal 7 โ Key Vault soft delete retention must be at least 7 days.
Remediation: Set purge_protection_enabled = true and soft_delete_retention_days to at least 7 on every azurerm_key_vault resource that stores workload keys.
resource "azurerm_key_vault" "main" {
name = "workload-keyvault"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
soft_delete_retention_days = 7
purge_protection_enabled = true
}
resource "azurerm_key_vault" "main" {
name = "workload-keyvault"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
# purge_protection_enabled defaults to false
}
waf-sec-030.tf.google.sql-cmek-encryption
Engine: terraform | Provider: google | Automated: Yes
Cloud SQL instances must be encrypted with a customer-managed key
All google_sql_database_instance resources must reference a customer-managed encryption key via encryption_key_name.
Scope: resource โ google_sql_database_instance
Assertions:
* settings.encryption_key_name attribute exists โ Cloud SQL instance must use a customer-managed encryption key (CMEK).
Remediation: Set encryption_key_name to a Cloud KMS key for every google_sql_database_instance that stores sensitive or regulated data.
resource "google_sql_database_instance" "main" {
name = "app-db"
database_version = "POSTGRES_15"
region = "europe-west3"
settings {
tier = "db-custom-2-7680"
encryption_key_name = google_kms_crypto_key.db_key.id
}
}
resource "google_sql_database_instance" "main" {
name = "app-db"
database_version = "POSTGRES_15"
region = "europe-west3"
settings {
tier = "db-custom-2-7680"
# encryption_key_name not set โ uses Google-managed key
}
}
waf-sec-030.tf.google.kms-key-rotation
Engine: terraform | Provider: google | Automated: Yes
Cloud KMS keys must have a rotation period configured
All google_kms_crypto_key resources must have rotation_period set to enforce regular key rotation.
Scope: resource โ google_kms_crypto_key
Assertions:
* rotation_period attribute exists โ Cloud KMS key must have a rotation_period configured.
Remediation: Set rotation_period (e.g., "7776000s" for 90 days) on every google_kms_crypto_key resource used for workload encryption.
resource "google_kms_crypto_key" "app" {
name = "app-key"
key_ring = google_kms_key_ring.app.id
rotation_period = "7776000s"
}
resource "google_kms_crypto_key" "app" {
name = "app-key"
key_ring = google_kms_key_ring.app.id
# rotation_period not set
}
waf-sec-030.tf.stackit.resource-encryption-enabled
Engine: terraform | Provider: stackit | Automated: Yes
STACKIT managed resources must use encryption at rest
STACKIT resources that store data (e.g., stackit_postgres_flex_instance, stackit_redis_instance, stackit_opensearch_instance, stackit_mysql_instance) must have encryption at rest enabled or use a customer-managed key where supported.
Scope: resource โ stackit_postgres_flex_instance, stackit_mysql_instance, stackit_redis_instance, stackit_opensearch_instance, stackit_object_storage_bucket
Assertions:
* name attribute exists โ STACKIT data resource must be defined with encryption at rest enabled by default or explicitly configured.
Remediation: Enable encryption at rest on all STACKIT managed data services. Use customer-managed keys via stackit_object_storage_bucket or service-specific encryption settings where available.
resource "stackit_postgres_flex_instance" "app" {
project_id = var.stackit_project_id
name = "app-db"
version = "15"
# encryption enabled by default; CMK configured via STACKIT console/API
}
resource "stackit_postgres_flex_instance" "app" {
project_id = var.stackit_project_id
name = "app-db"
# WAF-SEC-030 violation: encryption not verified or disabled
}
waf-sec-030.config.ovh.ovh-identity-access
Engine: config | Provider: ovh | Automated: Yes
OVHcloud data services must have encryption at rest enabled and documented
A version-controlled policy document must exist at docs/security/waf-sec-030-ovh-identity-access.md and document the OVHcloud implementation of this control. The checker validates that the file exists and contains a normative requirement statement (MUST/SHALL/required/mandatory).
Scope: file โ docs/security/waf-sec-030-ovh-identity-access.md
Assertions:
* content matches pattern (?i)MUST|SHALL|required|mandatory|enforced|documented โ Policy file docs/security/waf-sec-030-ovh-identity-access.md must contain a normative requirement statement.
Remediation: Create or update docs/security/waf-sec-030-ovh-identity-access.md. State the requirement, how it is implemented for OVHcloud, the review cadence, and the owner.
docs/security/waf-sec-030-ovh-identity-access.md:
- The OVHcloud implementation of WAF-SEC-030 is documented.
- Implementation status and owner are recorded.
- Review cadence is defined (e.g. quarterly).
# `docs/security/waf-sec-030-ovh-identity-access.md` is missing or does not contain a normative requirement.
# WAF-SEC-030 violation: OVHcloud control is not documented
waf-sec-030.tf.hcloud.volume-encryption
Engine: terraform | Provider: hcloud | Automated: Yes
Hetzner Cloud volumes must be encrypted at rest
All hcloud_volume resources attached to production servers must use Hetzner Cloud encryption at rest. Validate via the resource definition or a documented standard.
Scope: resource โ hcloud_volume
Assertions:
* name attribute exists โ Hetzner Cloud volume must exist and have encryption at rest enabled or documented.
Remediation: Create hcloud_volume resources with encryption enabled. For operating-system-level encryption, document LUKS/dm-crypt configuration in a version-controlled standard.
resource "hcloud_volume" "app" {
name = "app-data"
size = 100
server_id = hcloud_server.app.id
format = "ext4"
# Hetzner Cloud volume encryption at rest is enabled by default for new volumes
}
resource "hcloud_volume" "app" {
name = "app-data"
size = 100
server_id = hcloud_server.app.id
# WAF-SEC-030 violation: encryption at rest not verified
}
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
-
WAF-AGN-010 == Regulatory Mapping
| Framework | Controls |
|---|---|
ISO 27001:2022 |
* A.8.24 โ Use of cryptography * A.5.10 โ Acceptable use of information |
ISO 27017 |
* CLD.10.1 โ Cryptographic controls in cloud services |
ISO 27018 |
* A.10.1 โ Cryptographic controls for PII protection |
CIS Controls v8 |
* CIS 3.11 โ Encrypt sensitive data at rest |
CSA STAR |
* CCM CEK-01 โ Encryption and Key Management Policy * CCM CEK-03 โ Data Encryption |
PCI DSS v4.0 |
* Req 3.5 โ Cryptographic keys protection * Req 3.6 โ Encryption of stored cardholder data |
SOC 2 Type II |
* CC6.1 โ Logical access security * C1.1 โ Confidentiality of information |
GDPR |
* Art. 32 โ Security of processing (encryption) * Art. 25 โ Data protection by design and by default |
NIS2 |
* Art. 21(2)(h) โ Cryptography and encryption policies |
DORA |
* Art. 9 โ Protection and prevention |
EUCS (ENISA) |
* CKM-01 โ Cryptographic policy * CKM-02 โ Key management |
BSI C5:2020 |
* CRY-01 โ Use of cryptography * CRY-02 โ Key management * CRY-03 โ Encryption of stored data |
IT-Grundschutz |
* CON.1 โ Kryptokonzept * SYS.1.5 โ Speichersysteme |
TISAX |
* Information security โ Cryptographic protection of information |
ANSSI SecNumCloud |
* Domain โ Cryptography and key management |
BIO |
* BIO โ Cryptografische maatregelen |
ENS High |
* mp.info.3 โ Cifrado |
UK NCSC CAF |
* B3.d โ Data at rest โ encryption |
UK GDPR |
* Art. 32 โ Security of processing |
NIST SP 800-53 |
* SC-12 โ Cryptographic Key Establishment and Management * SC-13 โ Cryptographic Protection * SC-28 โ Protection of Information at Rest |
NIST CSF 2.0 |
* PR.DS-01 โ Data-at-rest is protected |
FedRAMP |
* SC-12, SC-13, SC-28 (Moderate/High baseline) |
HIPAA |
* ยง 164.312(a)(2)(iv) โ Encryption and decryption of ePHI |
CMMC 2.0 |
* SC.L2-3.13.11 โ Employ FIPS-validated cryptography * SC.L2-3.13.16 โ Protect confidentiality of CUI at rest |
IRAP |
* ISM โ Cryptography |
CCCS PBMM |
* SC-12, SC-13, SC-28 โ Cryptographic protection |
MAS TRM |
* Ch.11 โ Cryptography |
ISMAP |
* Cryptographic controls |
FISC |
* Technical measures โ Encryption of stored data |