Back to blog
AWSBest PracticesCloud SecurityMonitoring & LoggingOperations & Compliance

X-Ray Not Using KMS Encryption: Why It Matters and How to Fix It

AWS X-Ray defaults to an AWS-owned key, leaving trace data outside your control. Learn how to enable customer-managed KMS encryption and prevent drift.

TL;DR

This check flags AWS X-Ray when it stores trace data with default AWS-owned keys instead of a customer-managed KMS key. Trace segments can leak internal hostnames, request paths, and metadata, so switch X-Ray encryption to a KMS key with a single API call or console toggle.

AWS X-Ray collects request traces as your application flows through services, queues, and databases. Those traces are genuinely useful for debugging, but they also capture a surprising amount of context about how your systems are wired together. By default, X-Ray encrypts trace data with an AWS-owned key that you cannot see, manage, or audit. This check fires when X-Ray has not been switched to a customer-managed KMS key.

The difference sounds small. In practice it changes who controls access to your observability data and whether you can prove that control to an auditor.


What this check detects

The account_xrayencryption check inspects the X-Ray encryption configuration for an AWS account and region. X-Ray has a single account-level encryption setting that applies to all trace segments, and it has two possible modes:

  • NONE — X-Ray uses an AWS-owned key. This is the default. The key is managed entirely by AWS, never appears in your account, and generates no CloudTrail key-usage events you can review.
  • KMS — X-Ray uses a KMS key you specify, either an AWS-managed key or, ideally, a customer-managed key (CMK).

Lensix raises a finding when the mode is NONE, meaning trace data is not protected by a KMS key under your control.

Note: X-Ray encryption is configured per region. If you run workloads in multiple regions, each one has its own setting, and you can point each at a different KMS key.


Why it matters

People tend to think of trace data as harmless metadata. It is not. A single X-Ray segment can include:

  • Internal service names, hostnames, and ARNs that map out your architecture
  • Full request URLs and query strings, which sometimes carry tokens or identifiers
  • SQL statements, DynamoDB table names, and other downstream resource details
  • Custom annotations and metadata your developers attached, which can include user IDs or business data

That collection is essentially a blueprint of your application. An attacker who reads it learns your dependency graph, your naming conventions, and where the soft spots are, all without touching the workloads themselves.

The risk with the default AWS-owned key is not that AWS leaks your data. It is about control and accountability:

  • No revocation lever. With a customer-managed key you can disable or schedule deletion of the key to instantly cut off access to historical traces. With an AWS-owned key you have no such control.
  • No key access auditing. CMK usage shows up in CloudTrail as Decrypt and GenerateDataKey events. AWS-owned key usage does not, so you cannot tie trace access back to a principal.
  • No fine-grained key policy. A CMK lets you restrict who and what can decrypt, layering a second control on top of IAM.
  • Compliance gaps. Frameworks like PCI DSS, HIPAA, and SOC 2 frequently expect customer-managed encryption with documented key rotation. The default key rarely satisfies an auditor asking "show me how you control this key."

Warning: Switching to a customer-managed key means X-Ray calls KMS for every batch of trace data. High-volume tracing generates KMS API requests, which carry a small per-request cost. For most accounts this is negligible, but very chatty services can push KMS request charges into the noticeable range.


How to fix it

The fix has two parts: create or pick a KMS key, then point X-Ray at it. You do this once per region.

Step 1: Create a customer-managed KMS key

If you do not already have a dedicated key for observability data, create one:

aws kms create-key \
  --description "X-Ray trace encryption" \
  --tags TagKey=purpose,TagValue=xray-encryption \
  --region us-east-1

Grab the key ID or ARN from the output, then give it a friendly alias so it is easy to reference later:

aws kms create-alias \
  --alias-name alias/xray-encryption \
  --target-key-id <key-id> \
  --region us-east-1

Step 2: Grant X-Ray permission to use the key

The key policy must allow the X-Ray service to generate data keys. Attach a statement like this to the key policy:

{
  "Sid": "AllowXRayToUseKey",
  "Effect": "Allow",
  "Principal": {
    "Service": "xray.amazonaws.com"
  },
  "Action": [
    "kms:GenerateDataKey",
    "kms:Decrypt"
  ],
  "Resource": "*"
}

Note: Keep the existing root account statement in the key policy so your administrators do not lock themselves out. Add the X-Ray statement alongside it, do not replace the whole policy.

Step 3: Switch X-Ray to KMS encryption

Apply the encryption config to X-Ray for the region:

aws xray put-encryption-config \
  --type KMS \
  --key-id alias/xray-encryption \
  --region us-east-1

Confirm the change took effect:

aws xray get-encryption-config --region us-east-1

You want to see "Type": "KMS" and a Status of ACTIVE. The status may briefly read UPDATING while X-Ray re-keys.

Tip: In the console, go to X-Ray → Settings → Encryption, choose Use a KMS key, pick your key, and save. It maps directly to the put-encryption-config call above.

Terraform example

If you manage X-Ray through infrastructure as code, define the key and the encryption config together so the relationship is explicit:

resource "aws_kms_key" "xray" {
  description             = "X-Ray trace encryption"
  enable_key_rotation     = true
  deletion_window_in_days = 30
}

resource "aws_kms_alias" "xray" {
  name          = "alias/xray-encryption"
  target_key_id = aws_kms_key.xray.key_id
}

resource "aws_xray_encryption_config" "this" {
  type   = "KMS"
  key_id = aws_kms_key.xray.arn
}

Warning: Changing the encryption config does not re-encrypt traces already stored under the old key, and it briefly affects how new segments are written while the status is UPDATING. Apply this during a low-traffic window if you trace high-throughput services.


How to prevent it from happening again

A one-time fix drifts. New regions, new accounts, and console experiments all reintroduce the default. Bake the control into your pipeline instead.

Catch it in IaC review

If you use Terraform, a missing aws_xray_encryption_config resource is the signal. Write a policy-as-code rule with OPA or Conftest that fails any plan in which X-Ray is in use but no KMS encryption config exists. For Checkov-style scanning, enforce that the type attribute equals KMS.

Detect drift at runtime

Use AWS Config with a custom rule, or a scheduled Lambda, that calls get-encryption-config across every active region and flags any account where the type is NONE:

for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
  type=$(aws xray get-encryption-config --region "$region" --query 'Type' --output text)
  echo "$region: $type"
done

Tip: Rather than wiring up custom Lambdas and Config rules yourself, let Lensix run the account_xrayencryption check continuously across every account and region, and alert you the moment X-Ray drops back to an AWS-owned key.

Enforce with an SCP

You cannot mandate KMS encryption purely through an SCP, but you can deny the action that disables it. Block any attempt to set the encryption type back to NONE outside of a break-glass role:

{
  "Sid": "DenyXRayDefaultEncryption",
  "Effect": "Deny",
  "Action": "xray:PutEncryptionConfig",
  "Resource": "*",
  "Condition": {
    "StringNotLike": {
      "aws:PrincipalArn": "arn:aws:iam::*:role/SecurityBreakGlass"
    }
  }
}

Danger: An SCP this broad blocks all changes to the X-Ray encryption config, including legitimate ones, for everyone except the exempt role. Test it in a non-production OU first, and make sure your IaC deployment role is the exempt principal, or your pipelines will start failing.


Best practices

  • Use a dedicated key for X-Ray. Do not reuse a key that already protects unrelated data. A purpose-built key keeps its policy tight and its CloudTrail trail readable.
  • Turn on automatic key rotation. Annual rotation is a single flag and satisfies most compliance requirements with zero operational effort.
  • Set the encryption config in every region you trace in. It is easy to fix your primary region and forget the others. Loop over all active regions when you remediate.
  • Treat trace data as sensitive. Train developers not to put secrets, full tokens, or raw PII into X-Ray annotations and metadata in the first place. Encryption protects data at rest, but the cleanest fix is to never capture sensitive fields.
  • Audit key access regularly. Now that decryption shows up in CloudTrail, review which principals call Decrypt on your X-Ray key and confirm they have a reason to read traces.
  • Apply least privilege to the key policy. Grant X-Ray exactly the two actions it needs and nothing more, and scope read access on the key to the teams that actually use tracing.

Encrypting X-Ray with a customer-managed key is one of the lowest-effort, highest-leverage hardening steps available in AWS observability. One API call gives you revocation control, audit visibility, and a clean answer when an auditor asks who holds the keys to your trace data.