This check flags AWS Elasticsearch (OpenSearch) domains that store data on disk without encryption at rest. Without it, anyone who gains access to the underlying storage or snapshots can read your indexed data in plaintext. The fix is to enable encryption at rest, but on existing domains it requires creating a new encrypted domain and reindexing.
Search clusters tend to accumulate sensitive data without anyone planning for it. You start by indexing application logs, then someone adds user records to power a search feature, then a support tool dumps ticket history in for fast lookups. Before long your Elasticsearch domain holds a copy of much of your most interesting data, sitting on EBS volumes. The elasticsearch_unencrypted check catches the case where those volumes are not encrypted at rest.
What this check detects
The check inspects each AWS Elasticsearch Service domain (now branded as Amazon OpenSearch Service) and reports any domain where the EncryptionAtRestOptions.Enabled setting is false or absent. When that flag is off, the data nodes write index data, automated snapshots, and swap files to unencrypted storage.
Note: Amazon Elasticsearch Service was renamed Amazon OpenSearch Service in 2021. The underlying APIs, CLI commands, and encryption options still carry the es / elasticsearch naming, so you will see both terms. This check applies to both managed Elasticsearch and OpenSearch domains.
Encryption at rest on an OpenSearch domain covers more than the primary indices. When enabled, AWS encrypts:
- The indices stored on the data nodes
- Automated snapshots used for domain recovery
- OpenSearch logs
- Swap files
- All other data in the application directory
Encryption uses keys managed through AWS KMS, either the service default key or a customer managed key (CMK) that you control.
Why it matters
Encryption at rest is a defense-in-depth control. It does not stop someone who has valid credentials and network access from querying the cluster, but it closes a specific and realistic set of exposure paths.
Snapshot and storage exposure
Automated snapshots are stored by AWS, and manual snapshots can be written to S3. If a snapshot or its underlying storage is exposed through a misconfigured bucket policy, a leaked backup, or an over-permissive IAM role, unencrypted data is readable as plaintext. With encryption at rest, an attacker also needs access to the KMS key, which is governed by separate IAM and key policies.
Compliance requirements
If your domain holds personal data, cardholder data, or health records, encryption at rest is usually mandatory rather than optional. PCI DSS, HIPAA, SOC 2, and many internal data classification policies expect sensitive data to be encrypted on disk. An unencrypted domain is a straightforward audit finding.
Warning: Encryption at rest cannot be toggled on an existing domain. AWS does not support enabling it in place. You must create a new domain with encryption enabled and migrate your data, so treat this as a planned change rather than a quick console flip.
Insider and shared-tenancy risk
Encryption with a customer managed KMS key gives you a clean way to revoke access. If you ever need to cut off a compromised account or decommission data quickly, disabling the key renders the data unreadable. That is a control you simply do not have when the data sits in plaintext.
How to fix it
Because encryption at rest is set only at creation time, remediation means standing up a new encrypted domain and moving your indices across. Here is the practical sequence.
Step 1: Confirm the current state
Check whether encryption is enabled on the existing domain:
aws opensearch describe-domain \
--domain-name my-search-domain \
--query 'DomainStatus.EncryptionAtRestOptions'
If you are still on the legacy CLI namespace, the equivalent is:
aws es describe-elasticsearch-domain \
--domain-name my-search-domain \
--query 'DomainStatus.EncryptionAtRestOptions'
A result of "Enabled": false confirms the finding.
Step 2: Create a new encrypted domain
Create a replacement domain with encryption at rest enabled. Reference your KMS key by ARN or alias. Node-to-node encryption and HTTPS enforcement are usually required alongside at-rest encryption, so enable them together.
aws opensearch create-domain \
--domain-name my-search-domain-encrypted \
--engine-version 'OpenSearch_2.11' \
--cluster-config InstanceType=r6g.large.search,InstanceCount=3 \
--ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=100 \
--encryption-at-rest-options Enabled=true,KmsKeyId=alias/opensearch-cmk \
--node-to-node-encryption-options Enabled=true \
--domain-endpoint-options EnforceHTTPS=true,TLSSecurityPolicy=Policy-Min-TLS-1-2-2019-07
Note: Encryption at rest requires an instance type that supports it. The older T2 instances and a few first-generation types do not. Stick with current-generation instances such as the r6g, m6g, or c6g families to avoid a creation error.
Step 3: Migrate your data
Use the remote reindex feature to copy indices from the old domain into the new one without an intermediate export. Run this against the new encrypted domain:
POST _reindex
{
"source": {
"remote": {
"host": "https://old-domain-endpoint:443",
"username": "admin",
"password": "your-password"
},
"index": "logs-*"
},
"dest": {
"index": "logs-migrated"
}
}
For large datasets, restoring from a manual snapshot in S3 is often faster and more reliable than remote reindex. Take a snapshot of the old domain, then restore it into the new encrypted one.
Step 4: Cut over and decommission
Update your application connection strings or DNS alias to point at the new domain endpoint, verify queries return expected results, then delete the old domain.
Danger: The command below permanently deletes the domain and all of its data. Confirm that your new encrypted domain is fully populated and serving traffic before you run it. There is no undo.
aws opensearch delete-domain --domain-name my-search-domain
Terraform example
If you manage infrastructure as code, define the domain with encryption enabled from the start:
resource "aws_opensearch_domain" "search" {
domain_name = "my-search-domain"
engine_version = "OpenSearch_2.11"
cluster_config {
instance_type = "r6g.large.search"
instance_count = 3
}
ebs_options {
ebs_enabled = true
volume_type = "gp3"
volume_size = 100
}
encrypt_at_rest {
enabled = true
kms_key_id = aws_kms_key.opensearch.arn
}
node_to_node_encryption {
enabled = true
}
domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}
}
Tip: Use a customer managed KMS key rather than the AWS owned default. A CMK lets you set your own key policy, control rotation, and audit every decrypt call through CloudTrail. The cost is a few dollars per month per key, which is trivial next to the control it gives you.
How to prevent it from happening again
The recurring pain with this check is that the fix involves a migration. The way to avoid ever paying that cost is to make encryption non-negotiable at creation time.
Enforce it with Service Control Policies
If you run AWS Organizations, you can deny creation of any domain without encryption at rest. Attach an SCP like this to the relevant accounts:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedOpenSearch",
"Effect": "Deny",
"Action": "es:CreateElasticsearchDomain",
"Resource": "*",
"Condition": {
"Bool": {
"es:EncryptionAtRestEnabled": "false"
}
}
}
]
}
Gate it in CI/CD with policy as code
Catch unencrypted domains in pull requests before they ever reach AWS. A Checkov or OPA policy run against your Terraform plan stops the merge. Checkov ships a built-in rule for this:
checkov -d ./infra --check CKV_AWS_5
CKV_AWS_5 verifies that Elasticsearch/OpenSearch domains have encryption at rest enabled. Add it to your pipeline so the build fails on any non-compliant resource.
Tip: Pair the static check in CI with continuous monitoring in Lensix. Policy-as-code catches what flows through your pipeline, but it will not catch domains created by hand in the console or by a forgotten script. Lensix scans the live account and surfaces drift regardless of how the resource was created.
Best practices
- Enable all three encryption layers together. Encryption at rest, node-to-node encryption, and HTTPS enforcement protect data on disk, between nodes, and in transit to clients. Turning on only one leaves obvious gaps.
- Use customer managed KMS keys for sensitive workloads. They give you control over rotation, revocation, and an audit trail of key usage.
- Lock down domain access policies and VPC placement. Encryption does not replace network controls. Keep domains in a VPC and scope the access policy to specific principals.
- Set encryption as a default in your module library. If your internal Terraform module enables encryption out of the box, every team that uses it inherits the right behavior without thinking about it.
- Audit existing fleets periodically. Domains created years ago, before encryption was standard practice, are the ones most likely to fail this check. Sweep the whole account, not just new deployments.
Encryption at rest is one of the cheapest security wins available on a search cluster. The only real friction is that you cannot retrofit it, which is exactly why building it in from the first create-domain call matters so much. Set the default once, enforce it in the pipeline, and this finding stops appearing.

