Skip to main content

API Gateway REST API Stage Cache Data Is Encrypted at Rest

Overview

This check ensures that API Gateway REST API stages with caching enabled have their cached data encrypted at rest. When you enable caching on an API Gateway stage, responses are stored temporarily to reduce backend load and improve performance. This check verifies that the "Encrypt cache data" setting is turned on.

Risk

If cache encryption is not enabled, cached API responses could be exposed in plaintext. This creates several security concerns:

  • Data exposure: Response payloads may contain sensitive information like tokens, session data, or personally identifiable information (PII)
  • Replay attacks: Attackers with access to unencrypted cache data could use captured responses for session hijacking
  • Information leakage: Exposed API patterns help attackers understand your system and plan further attacks

Remediation Steps

Prerequisites

You need permission to modify API Gateway stage settings. Specifically, you need the apigateway:UpdateStage permission.

Required IAM permissions

Your IAM user or role needs these permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"apigateway:GET",
"apigateway:UpdateStage"
],
"Resource": "arn:aws:apigateway:us-east-1::/restapis/*/stages/*"
}
]
}

AWS Console Method

  1. Open the API Gateway console
  2. In the left navigation, click APIs
  3. Select the REST API that has the affected stage
  4. Click Stages in the left panel
  5. Select the stage name (e.g., "prod" or "dev")
  6. Click the Settings tab
  7. Scroll to find the Cache Settings section
  8. Check the box for Encrypt cache data
  9. Click Save Changes

Note: If you do not see cache settings, caching may not be enabled for this stage. You can enable caching by setting a cache cluster size, but this incurs additional costs.

AWS CLI

Use the update-stage command to enable cache encryption. Replace <rest-api-id> and <stage-name> with your values.

Enable cache encryption for all methods:

aws apigateway update-stage \
--rest-api-id <rest-api-id> \
--stage-name <stage-name> \
--patch-operations op=replace,path=/*/*/caching/dataEncrypted,value=true \
--region us-east-1

Enable cache encryption for a specific method:

aws apigateway update-stage \
--rest-api-id <rest-api-id> \
--stage-name <stage-name> \
--patch-operations op=replace,path=/example/GET/caching/dataEncrypted,value=true \
--region us-east-1

Find your REST API ID:

aws apigateway get-rest-apis --region us-east-1 --query 'items[*].[name,id]' --output table

List stages for an API:

aws apigateway get-stages --rest-api-id <rest-api-id> --region us-east-1
CloudFormation

To enable cache encryption in CloudFormation, set CacheDataEncrypted: true in your AWS::ApiGateway::Stage resource's MethodSettings.

AWSTemplateFormatVersion: '2010-09-09'
Description: API Gateway REST API with encrypted cache

Parameters:
ApiName:
Type: String
Default: MySecureAPI
Description: Name of the API Gateway REST API

StageName:
Type: String
Default: prod
Description: Name of the deployment stage

Resources:
MyRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Ref ApiName
Description: REST API with encrypted caching

MyResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref MyRestApi
ParentId: !GetAtt MyRestApi.RootResourceId
PathPart: example

MyMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref MyRestApi
ResourceId: !Ref MyResource
HttpMethod: GET
AuthorizationType: NONE
Integration:
Type: MOCK
RequestTemplates:
application/json: '{"statusCode": 200}'
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: '{"message": "Hello World"}'
MethodResponses:
- StatusCode: 200

MyDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: MyMethod
Properties:
RestApiId: !Ref MyRestApi

MyStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref MyRestApi
DeploymentId: !Ref MyDeployment
StageName: !Ref StageName
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- ResourcePath: /example
HttpMethod: GET
CachingEnabled: true
CacheTtlInSeconds: 300
CacheDataEncrypted: true # This enables cache encryption

Outputs:
ApiEndpoint:
Description: API Gateway endpoint URL
Value: !Sub 'https://${MyRestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageName}'

Key setting: The CacheDataEncrypted: true property in MethodSettings enables encryption for cached responses.

Terraform

To enable cache encryption in Terraform, set cache_data_encrypted = true in the aws_api_gateway_method_settings resource.

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "us-east-1"
}

variable "api_name" {
description = "Name of the API Gateway REST API"
type = string
default = "my-secure-api"
}

variable "stage_name" {
description = "Name of the deployment stage"
type = string
default = "prod"
}

resource "aws_api_gateway_rest_api" "example" {
name = var.api_name
description = "REST API with encrypted caching"
}

resource "aws_api_gateway_resource" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id
parent_id = aws_api_gateway_rest_api.example.root_resource_id
path_part = "example"
}

resource "aws_api_gateway_method" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id
resource_id = aws_api_gateway_resource.example.id
http_method = "GET"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id
resource_id = aws_api_gateway_resource.example.id
http_method = aws_api_gateway_method.example.http_method
type = "MOCK"
request_templates = {
"application/json" = "{\"statusCode\": 200}"
}
}

resource "aws_api_gateway_deployment" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id

depends_on = [aws_api_gateway_integration.example]

lifecycle {
create_before_destroy = true
}
}

resource "aws_api_gateway_stage" "example" {
deployment_id = aws_api_gateway_deployment.example.id
rest_api_id = aws_api_gateway_rest_api.example.id
stage_name = var.stage_name
cache_cluster_enabled = true
cache_cluster_size = "0.5"
}

resource "aws_api_gateway_method_settings" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id
stage_name = aws_api_gateway_stage.example.stage_name
method_path = "example/GET"

settings {
caching_enabled = true
cache_ttl_in_seconds = 300
cache_data_encrypted = true # This enables cache encryption
}
}

output "api_endpoint" {
description = "API Gateway endpoint URL"
value = "${aws_api_gateway_stage.example.invoke_url}/example"
}

Key setting: The cache_data_encrypted = true in the settings block enables encryption for cached responses.

Verification

After enabling cache encryption, verify the change was applied:

  1. In the API Gateway console, navigate to your stage
  2. Click the Settings tab
  3. Confirm that Encrypt cache data is checked
Verify with AWS CLI
aws apigateway get-stage \
--rest-api-id <rest-api-id> \
--stage-name <stage-name> \
--region us-east-1 \
--query 'methodSettings'

Look for cacheDataEncrypted: true in the output for each method path.

Run the Prowler check again to confirm remediation:

prowler aws --checks apigateway_restapi_cache_encrypted --region us-east-1

Additional Resources

Notes

  • Cost consideration: Enabling a cache cluster incurs additional charges. Cache sizes range from 0.5 GB to 237 GB. See AWS pricing for details.
  • Cache invalidation: When you enable encryption, consider also setting up cache invalidation policies and short TTLs (time-to-live) for sensitive data.
  • Sensitive endpoints: For endpoints returning highly sensitive data, consider whether caching is appropriate at all. Some data should never be cached.
  • Compliance: This control helps meet requirements in several compliance frameworks including PCI DSS, ISO 27001, and NIS2.