Elastic Cache Encrypted At Rest And Transit Remediation
Triage and Remediation
- Remediation
Remediation
Using Console
Below are step‑by‑step console instructions to enable encryption at rest and encryption in transit for Amazon OpenSearch Service / Amazon Elasticsearch Service (the managed service often called “AWS Elasticsearch”).
Important: Some encryption options cannot be changed on an existing domain. If the options are grayed out, you must create a new domain with encryption enabled and migrate data.
1. Check Current Encryption Settings
- Sign in to the AWS Management Console.
- Go to Amazon OpenSearch Service (or “Amazon Elasticsearch Service” if you’re on an older console).
- In the left pane, choose Domains.
- Click your domain name.
- On the domain’s detail page:
- Look at Security or Encryption sections:
- Encryption at rest: check if it’s Enabled.
- Node-to-node encryption: check if it’s Enabled.
- Domain endpoint: verify if it’s using HTTPS only.
- Look at Security or Encryption sections:
If any of these are disabled and you cannot edit them, proceed to create a new domain.
2. Enable Encryption (New Domain – Recommended if Current One Isn’t Encrypted)
2.1 Create a New Domain with Encryption
- In the OpenSearch Service console, click Create domain.
- Engine version: choose your required OpenSearch/Elasticsearch version.
- Domain name: enter a unique name (e.g.,
my-secure-domain). - Continue through:
- Network:
- Choose VPC access if possible (recommended).
- Data nodes: choose instance type and count.
- Network:
2.2 Enable Encryption at Rest
- Scroll to the Data protection or Encryption section.
- Check Enable encryption at rest.
- Choose a KMS key:
- Use the AWS managed key or
- Choose a customer-managed CMK in KMS.
- (Optional) Enable Auto-Tune and other performance settings as needed.
2.3 Enable Node-to-Node Encryption (In-Transit Within the Cluster)
- In the same security/encryption section, check Enable node-to-node encryption.
- This encrypts traffic between cluster nodes.
2.4 Enforce HTTPS for Client Connections (In Transit from Clients)
-
In the Domain endpoint or Network/“Security” section:
- Ensure Require HTTPS is selected (or equivalent option that disallows HTTP).
- If there’s an Endpoint security or TLS policy field, select a modern TLS policy (e.g.,
Policy-Min-TLS-1-2-2019-07).
-
Configure access policy:
- Use fine-grained access control + IAM, or
- Restrict by VPC and security groups, or
- If using a public endpoint, restrict by IAM and/or source IP.
-
Click Next, review all settings, then click Create.
AWS will now create the secure domain (this can take several minutes).
3. Migrate Data from Old Domain to New Secure Domain
-
Once the new domain is Active, note its HTTPS endpoint.
-
From an EC2 instance, container, or your workstation (with network access to both domains), use:
- reindex from remote (if supported by your version), or
- A tool such as Logstash, Elasticsearch/OpenSearch reindex APIs, or a custom script:
- Read from
http(s)://old-domain-endpoint - Write to
https://new-domain-endpoint
- Read from
-
Update:
- Application configuration
- Lambda functions
- Log shippers (Filebeat, Fluentd, CloudWatch Logs subscription filters, etc.) to use the new domain’s HTTPS endpoint.
-
Validate:
- Index and document counts between old and new domains.
- Application functionality and performance.
-
When fully migrated and tested, delete the old (unencrypted) domain from the console.
4. If You Must Modify an Existing Domain
- In the OpenSearch Service console, open your domain.
- Click Edit (or Edit domain).
- Look for:
- Encryption at rest: Try to select Enable encryption at rest and choose a KMS key.
- Node-to-node encryption: Try to select Enable.
- Require HTTPS: Ensure it is turned on.
- If any are grayed out or locked, AWS does not allow changing them in-place for that domain → you must use the new domain + migration approach above.
- Save/Apply changes and wait for the domain to finish updating.
5. Verify Encryption
- On the domain’s details page:
- Encryption at rest: shows Enabled with the KMS key.
- Node-to-node encryption: shows Enabled.
- Endpoint: begins with
https://and Only HTTPS allowed.
- From a client:
- Ensure all connections use the HTTPS endpoint.
- Confirm TLS negotiation (e.g., using
curl -v https://your-domain-endpoint).
If you tell me whether you’re on the OpenSearch or legacy Elasticsearch console and whether the domain is in a VPC or public, I can tailor the exact console menu/field names for your environment.
Using CLI
For Amazon Elasticsearch / OpenSearch, encryption at rest and in-transit cannot be turned on for an existing domain. You must create a new domain with encryption enabled, migrate data, then cut over.
Below are concise, CLI-focused steps.
1. Capture current domain config (for reference)
aws es describe-elasticsearch-domain \
--domain-name OLD_DOMAIN_NAME \
> old-domain-config.json
Use this JSON to copy any important settings (instance type, count, EBS size, access policy, etc.) into the new domain command.
2. Create a new domain with encryption enabled
Key options:
--encryption-at-rest-options Enabled=true--node-to-node-encryption-options Enabled=true--domain-endpoint-options EnforceHTTPS=true,TLSecurityPolicy=Policy-Min-TLS-1-2-2019-07
Example (adjust values as needed):
aws es create-elasticsearch-domain \
--domain-name NEW_DOMAIN_NAME \
--elasticsearch-version 7.10 \
--elasticsearch-cluster-config InstanceType=m5.large.elasticsearch,InstanceCount=2,ZoneAwarenessEnabled=true \
--ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=200 \
--encryption-at-rest-options Enabled=true \
--node-to-node-encryption-options Enabled=true \
--domain-endpoint-options EnforceHTTPS=true,TLSecurityPolicy=Policy-Min-TLS-1-2-2019-07 \
--access-policies file://access-policy.json
To use a specific KMS key for encryption at rest:
--encryption-at-rest-options Enabled=true,KmsKeyId=YOUR_KMS_KEY_ARN
Wait for the domain to be active:
aws es describe-elasticsearch-domain \
--domain-name NEW_DOMAIN_NAME \
--query "DomainStatus.Processing"
Repeat until it returns false.
3. Verify encryption settings
aws es describe-elasticsearch-domain \
--domain-name NEW_DOMAIN_NAME \
--query "DomainStatus.{AtRest:EncryptionAtRestOptions,NodeToNode:NodeToNodeEncryptionOptions,EndpointOptions:DomainEndpointOptions}"
Confirm:
EncryptionAtRestOptions.Enabled = trueNodeToNodeEncryptionOptions.Enabled = trueDomainEndpointOptions.EnforceHTTPS = true
4. Migrate data from old to new domain
Use reindex-from-remote via the Elasticsearch/OpenSearch API (not CLI) from the new domain, for each index:
curl -X POST "https://NEW_DOMAIN_ENDPOINT/_reindex?wait_for_completion=false" \
-H 'Content-Type: application/json' \
-d '{
"source": {
"remote": {
"host": "https://OLD_DOMAIN_ENDPOINT"
},
"index": "old-index-name"
},
"dest": {
"index": "new-index-name"
}
}'
Repeat for all indices (you can keep same index names if desired).
5. Update clients to use HTTPS endpoint of new domain
From CLI, get the endpoint:
aws es describe-elasticsearch-domain \
--domain-name NEW_DOMAIN_NAME \
--query "DomainStatus.Endpoints"
Update all applications, Lambdas, etc. to use:
- The HTTPS endpoint of
NEW_DOMAIN_NAME - TLS 1.2–compatible clients
6. Decommission old domain
Once you have:
- Verified data in the new domain
- Switched all traffic to the new domain
- Observed stable operations
Delete old domain:
aws es delete-elasticsearch-domain \
--domain-name OLD_DOMAIN_NAME
If instead you actually meant ElastiCache, say so and I’ll give the corresponding aws elasticache CLI steps.
Using Python
You’re mixing two different services in the question, so I’ll answer for what you explicitly asked: AWS Elasticsearch / OpenSearch Service (not ElastiCache).
For Amazon Elasticsearch / OpenSearch, “encrypted at rest and in transit” means:
- At rest:
EncryptAtRestOptions.Enabled = True - Node-to-node:
NodeToNodeEncryptionOptions.Enabled = True - Client-to-domain (in transit): HTTPS-only endpoint (
DomainEndpointOptions.EnforceHTTPS = True)
You cannot turn on at-rest encryption on an existing domain where it was disabled at creation; you must create a new domain with encryption and migrate your data.
Below are step‑by‑step instructions and Python (boto3) examples.
1. Prerequisites
- Install boto3 and configure AWS credentials:
pip install boto3
aws configure # or use env vars/instance role
- Use Python 3 and import boto3:
import boto3
es = boto3.client("es") # For OpenSearch service; still named "es" in boto3
2. Check current domain encryption settings
domain_name = "your-domain-name"
response = es.describe_elasticsearch_domain(
DomainName=domain_name
)
domain_status = response["DomainStatus"]
encrypt_at_rest = domain_status.get("EncryptionAtRestOptions", {}).get("Enabled")
node_to_node = domain_status.get("NodeToNodeEncryptionOptions", {}).get("Enabled")
endpoint_opts = domain_status.get("DomainEndpointOptions", {})
enforce_https = endpoint_opts.get("EnforceHTTPS")
print("Encrypt at rest:", encrypt_at_rest)
print("Node-to-node:", node_to_node)
print("Enforce HTTPS:", enforce_https)
If Encrypt at rest or Node-to-node is False or missing, you must create a new domain.
3. Create a new encrypted domain (recommended path)
3.1. Decide on new domain name and region
SOURCE_DOMAIN = "your-domain-name"
TARGET_DOMAIN = "your-new-secure-domain-name"
es = boto3.client("es", region_name="us-east-1") # choose your region
3.2. Read configuration from existing domain
src = es.describe_elasticsearch_domain(DomainName=SOURCE_DOMAIN)["DomainStatus"]
ebs_opts = src.get("EBSOptions", {})
cluster_cfg = src.get("ElasticsearchClusterConfig", {})
vpc_options = src.get("VPCOptions", {})
access_policies = src.get("AccessPolicies", "{}") # JSON string
snapshot_opts = src.get("SnapshotOptions", {})
engine_version = src.get("ElasticsearchVersion", "OpenSearch_1.3") # or whatever you use
3.3. Create new domain with encryption enabled
resp = es.create_elasticsearch_domain(
DomainName=TARGET_DOMAIN,
ElasticsearchVersion=engine_version,
ElasticsearchClusterConfig=cluster_cfg,
EBSOptions=ebs_opts,
VPCOptions=vpc_options, # omit if public domain
SnapshotOptions=snapshot_opts,
AccessPolicies=access_policies,
EncryptionAtRestOptions={
"Enabled": True,
# Optionally specify a custom KMS key:
# "KmsKeyId": "arn:aws:kms:region:account-id:key/key-id"
},
NodeToNodeEncryptionOptions={
"Enabled": True
},
DomainEndpointOptions={
"EnforceHTTPS": True,
"TLSSecurityPolicy": "Policy-Min-TLS-1-2-2019-07" # recommended
}
)
print("Creating domain:", resp["DomainStatus"]["DomainName"])
Wait for the domain to become active:
import time
def wait_for_domain(domain):
while True:
status = es.describe_elasticsearch_domain(DomainName=domain)["DomainStatus"]
if status["Processing"] is False:
print("Domain ready:", domain)
break
print("Waiting for domain to be ready...")
time.sleep(60)
wait_for_domain(TARGET_DOMAIN)
4. Migrate data from old (unencrypted) to new (encrypted) domain
Use a migration method like:
- reindex from remote (if supported by your engine version), or
- Logstash, or
- a custom Python script using
elasticsearch/opensearch-pyclient.
Example using reindex from remote (conceptual, done via HTTP, not boto3):
- Get endpoints:
src_endpoint = src["Endpoints"]["vpc"] if "vpc" in src["Endpoints"] else src["Endpoint"]
tgt_status = es.describe_elasticsearch_domain(DomainName=TARGET_DOMAIN)["DomainStatus"]
tgt_endpoint = tgt_status["Endpoints"].get("vpc", tgt_status.get("Endpoint"))
- Use an HTTP client (e.g.,
requests) oropensearch-pyto call_reindexfrom target domain:
from opensearchpy import OpenSearch
src_client = OpenSearch(
hosts=[{"host": src_endpoint, "port": 443}],
http_auth=("user", "password"), # or IAM auth plugin, etc.
use_ssl=True,
verify_certs=True,
)
tgt_client = OpenSearch(
hosts=[{"host": tgt_endpoint, "port": 443}],
http_auth=("user", "password"),
use_ssl=True,
verify_certs=True,
)
# Example: reindex one index
body = {
"source": {
"remote": {
"host": f"https://{src_endpoint}"
},
"index": "my-index"
},
"dest": {
"index": "my-index"
}
}
tgt_client.transport.perform_request("POST", "/_reindex", body=body, params={"wait_for_completion": "true"})
Repeat for all indices. Validate data, aliases, index settings, etc.
5. Switch traffic and delete old domain
- Update any clients, apps, or DNS records to use the new domain endpoint (
https://<new-endpoint>). - Test thoroughly.
- Delete the old domain once you’re sure:
es.delete_elasticsearch_domain(DomainName=SOURCE_DOMAIN)
6. If encryption is already enabled but HTTPS is not
You can update the endpoint options in-place:
domain_name = "your-domain-name"
es.update_elasticsearch_domain_config(
DomainName=domain_name,
DomainEndpointOptions={
"EnforceHTTPS": True,
"TLSSecurityPolicy": "Policy-Min-TLS-1-2-2019-07"
}
)
wait_for_domain(domain_name)
This enforces in-transit encryption for clients; node-to-node and at-rest must have been enabled at creation time.
Summary
- Use
create_elasticsearch_domainwith:EncryptionAtRestOptions.Enabled = TrueNodeToNodeEncryptionOptions.Enabled = TrueDomainEndpointOptions.EnforceHTTPS = True
- If encryption wasn’t enabled originally, create a new domain and migrate data.
- Manage all of this via boto3 as shown above.
Using Terraform
resource "aws_opensearch_domain" "THIS_DOMAIN" {
domain_name = "YOUR_DOMAIN_NAME" # replace with your domain name
engine_version = "OpenSearch_2.11" # replace with your required engine version
cluster_config {
instance_type = "m6g.large.search" # replace with your desired instance type
# other cluster config as needed
}
# Enable encryption at rest (forces replacement if changed from false -> true)
encrypt_at_rest {
enabled = true
kms_key_id = "YOUR_KMS_KEY_ARN_OR_ID" # optional; omit to use AWS managed key
}
# Enable node-to-node encryption (in-transit inside the cluster; forces replacement if changed)
node_to_node_encryption {
enabled = true
}
# Enforce HTTPS for client connections (encryption in transit)
domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}
# add/keep any other settings you already manage here (e.g., access_policies, vpc_options, etc.)
}
Changing encrypt_at_rest.enabled or node_to_node_encryption.enabled from false to true forces replacement of the OpenSearch/Elasticsearch domain, which can cause downtime unless you manage cutover (e.g., with blue/green or DNS).
To verify, terraform plan should show encrypt_at_rest.enabled = true, node_to_node_encryption.enabled = true, and domain_endpoint_options.enforce_https = true, with a resource replacement if you are enabling these on an existing unencrypted domain.