Configure AWS CloudFront Response Headers Policies

The aws:cloudfront/responseHeadersPolicy:ResponseHeadersPolicy resource, part of the Pulumi AWS provider, defines a reusable set of HTTP response headers that CloudFront adds to responses for matching cache behaviors. This guide focuses on three capabilities: CORS header configuration, custom header injection, and header removal with performance monitoring.

Response headers policies are attached to cache behaviors in CloudFront distributions. The policy defines which headers to add or remove; you attach it to one or more cache behaviors to apply those headers to matching requests. The examples are intentionally small. Combine them with your own CloudFront distribution and cache behavior configuration.

Configure CORS headers for cross-origin requests

Web applications serving content to browsers on different domains need CORS headers to allow cross-origin requests.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cloudfront.ResponseHeadersPolicy("example", {
    name: "example-policy",
    comment: "test comment",
    corsConfig: {
        accessControlAllowCredentials: true,
        accessControlAllowHeaders: {
            items: ["test"],
        },
        accessControlAllowMethods: {
            items: ["GET"],
        },
        accessControlAllowOrigins: {
            items: ["test.example.comtest"],
        },
        originOverride: true,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.cloudfront.ResponseHeadersPolicy("example",
    name="example-policy",
    comment="test comment",
    cors_config={
        "access_control_allow_credentials": True,
        "access_control_allow_headers": {
            "items": ["test"],
        },
        "access_control_allow_methods": {
            "items": ["GET"],
        },
        "access_control_allow_origins": {
            "items": ["test.example.comtest"],
        },
        "origin_override": True,
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudfront"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudfront.NewResponseHeadersPolicy(ctx, "example", &cloudfront.ResponseHeadersPolicyArgs{
			Name:    pulumi.String("example-policy"),
			Comment: pulumi.String("test comment"),
			CorsConfig: &cloudfront.ResponseHeadersPolicyCorsConfigArgs{
				AccessControlAllowCredentials: pulumi.Bool(true),
				AccessControlAllowHeaders: &cloudfront.ResponseHeadersPolicyCorsConfigAccessControlAllowHeadersArgs{
					Items: pulumi.StringArray{
						pulumi.String("test"),
					},
				},
				AccessControlAllowMethods: &cloudfront.ResponseHeadersPolicyCorsConfigAccessControlAllowMethodsArgs{
					Items: pulumi.StringArray{
						pulumi.String("GET"),
					},
				},
				AccessControlAllowOrigins: &cloudfront.ResponseHeadersPolicyCorsConfigAccessControlAllowOriginsArgs{
					Items: pulumi.StringArray{
						pulumi.String("test.example.comtest"),
					},
				},
				OriginOverride: pulumi.Bool(true),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.CloudFront.ResponseHeadersPolicy("example", new()
    {
        Name = "example-policy",
        Comment = "test comment",
        CorsConfig = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCorsConfigArgs
        {
            AccessControlAllowCredentials = true,
            AccessControlAllowHeaders = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowHeadersArgs
            {
                Items = new[]
                {
                    "test",
                },
            },
            AccessControlAllowMethods = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowMethodsArgs
            {
                Items = new[]
                {
                    "GET",
                },
            },
            AccessControlAllowOrigins = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowOriginsArgs
            {
                Items = new[]
                {
                    "test.example.comtest",
                },
            },
            OriginOverride = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicy;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicyArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCorsConfigArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowHeadersArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowMethodsArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCorsConfigAccessControlAllowOriginsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ResponseHeadersPolicy("example", ResponseHeadersPolicyArgs.builder()
            .name("example-policy")
            .comment("test comment")
            .corsConfig(ResponseHeadersPolicyCorsConfigArgs.builder()
                .accessControlAllowCredentials(true)
                .accessControlAllowHeaders(ResponseHeadersPolicyCorsConfigAccessControlAllowHeadersArgs.builder()
                    .items("test")
                    .build())
                .accessControlAllowMethods(ResponseHeadersPolicyCorsConfigAccessControlAllowMethodsArgs.builder()
                    .items("GET")
                    .build())
                .accessControlAllowOrigins(ResponseHeadersPolicyCorsConfigAccessControlAllowOriginsArgs.builder()
                    .items("test.example.comtest")
                    .build())
                .originOverride(true)
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cloudfront:ResponseHeadersPolicy
    properties:
      name: example-policy
      comment: test comment
      corsConfig:
        accessControlAllowCredentials: true
        accessControlAllowHeaders:
          items:
            - test
        accessControlAllowMethods:
          items:
            - GET
        accessControlAllowOrigins:
          items:
            - test.example.comtest
        originOverride: true

When attached to a cache behavior, CloudFront injects the specified CORS headers into every response. The accessControlAllowOrigins property lists domains that can make cross-origin requests. The accessControlAllowMethods property specifies which HTTP methods are permitted. The originOverride property controls whether CloudFront’s headers replace any CORS headers from the origin server.

Add custom headers to responses

Applications often inject custom headers for security policies or client-side behavior without modifying origin servers.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cloudfront.ResponseHeadersPolicy("example", {
    name: "example-headers-policy",
    customHeadersConfig: {
        items: [
            {
                header: "X-Permitted-Cross-Domain-Policies",
                override: true,
                value: "none",
            },
            {
                header: "X-Test",
                override: true,
                value: "none",
            },
        ],
    },
});
import pulumi
import pulumi_aws as aws

example = aws.cloudfront.ResponseHeadersPolicy("example",
    name="example-headers-policy",
    custom_headers_config={
        "items": [
            {
                "header": "X-Permitted-Cross-Domain-Policies",
                "override": True,
                "value": "none",
            },
            {
                "header": "X-Test",
                "override": True,
                "value": "none",
            },
        ],
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudfront"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudfront.NewResponseHeadersPolicy(ctx, "example", &cloudfront.ResponseHeadersPolicyArgs{
			Name: pulumi.String("example-headers-policy"),
			CustomHeadersConfig: &cloudfront.ResponseHeadersPolicyCustomHeadersConfigArgs{
				Items: cloudfront.ResponseHeadersPolicyCustomHeadersConfigItemArray{
					&cloudfront.ResponseHeadersPolicyCustomHeadersConfigItemArgs{
						Header:   pulumi.String("X-Permitted-Cross-Domain-Policies"),
						Override: pulumi.Bool(true),
						Value:    pulumi.String("none"),
					},
					&cloudfront.ResponseHeadersPolicyCustomHeadersConfigItemArgs{
						Header:   pulumi.String("X-Test"),
						Override: pulumi.Bool(true),
						Value:    pulumi.String("none"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.CloudFront.ResponseHeadersPolicy("example", new()
    {
        Name = "example-headers-policy",
        CustomHeadersConfig = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCustomHeadersConfigArgs
        {
            Items = new[]
            {
                new Aws.CloudFront.Inputs.ResponseHeadersPolicyCustomHeadersConfigItemArgs
                {
                    Header = "X-Permitted-Cross-Domain-Policies",
                    Override = true,
                    Value = "none",
                },
                new Aws.CloudFront.Inputs.ResponseHeadersPolicyCustomHeadersConfigItemArgs
                {
                    Header = "X-Test",
                    Override = true,
                    Value = "none",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicy;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicyArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCustomHeadersConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ResponseHeadersPolicy("example", ResponseHeadersPolicyArgs.builder()
            .name("example-headers-policy")
            .customHeadersConfig(ResponseHeadersPolicyCustomHeadersConfigArgs.builder()
                .items(                
                    ResponseHeadersPolicyCustomHeadersConfigItemArgs.builder()
                        .header("X-Permitted-Cross-Domain-Policies")
                        .override(true)
                        .value("none")
                        .build(),
                    ResponseHeadersPolicyCustomHeadersConfigItemArgs.builder()
                        .header("X-Test")
                        .override(true)
                        .value("none")
                        .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cloudfront:ResponseHeadersPolicy
    properties:
      name: example-headers-policy
      customHeadersConfig:
        items:
          - header: X-Permitted-Cross-Domain-Policies
            override: true
            value: none
          - header: X-Test
            override: true
            value: none

The customHeadersConfig property defines headers CloudFront adds to responses. Each item specifies a header name, value, and whether to override existing headers with the same name. This example adds X-Permitted-Cross-Domain-Policies and X-Test headers to every response for cache behaviors using this policy.

Combine custom headers with header removal and timing

Production deployments often add custom headers while removing sensitive ones and enabling performance monitoring.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cloudfront.ResponseHeadersPolicy("example", {
    name: "example-headers-policy",
    customHeadersConfig: {
        items: [{
            header: "X-Permitted-Cross-Domain-Policies",
            override: true,
            value: "none",
        }],
    },
    removeHeadersConfig: {
        items: [{
            header: "Set-Cookie",
        }],
    },
    serverTimingHeadersConfig: {
        enabled: true,
        samplingRate: 50,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.cloudfront.ResponseHeadersPolicy("example",
    name="example-headers-policy",
    custom_headers_config={
        "items": [{
            "header": "X-Permitted-Cross-Domain-Policies",
            "override": True,
            "value": "none",
        }],
    },
    remove_headers_config={
        "items": [{
            "header": "Set-Cookie",
        }],
    },
    server_timing_headers_config={
        "enabled": True,
        "sampling_rate": 50,
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudfront"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudfront.NewResponseHeadersPolicy(ctx, "example", &cloudfront.ResponseHeadersPolicyArgs{
			Name: pulumi.String("example-headers-policy"),
			CustomHeadersConfig: &cloudfront.ResponseHeadersPolicyCustomHeadersConfigArgs{
				Items: cloudfront.ResponseHeadersPolicyCustomHeadersConfigItemArray{
					&cloudfront.ResponseHeadersPolicyCustomHeadersConfigItemArgs{
						Header:   pulumi.String("X-Permitted-Cross-Domain-Policies"),
						Override: pulumi.Bool(true),
						Value:    pulumi.String("none"),
					},
				},
			},
			RemoveHeadersConfig: &cloudfront.ResponseHeadersPolicyRemoveHeadersConfigArgs{
				Items: cloudfront.ResponseHeadersPolicyRemoveHeadersConfigItemArray{
					&cloudfront.ResponseHeadersPolicyRemoveHeadersConfigItemArgs{
						Header: pulumi.String("Set-Cookie"),
					},
				},
			},
			ServerTimingHeadersConfig: &cloudfront.ResponseHeadersPolicyServerTimingHeadersConfigArgs{
				Enabled:      pulumi.Bool(true),
				SamplingRate: pulumi.Float64(50),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.CloudFront.ResponseHeadersPolicy("example", new()
    {
        Name = "example-headers-policy",
        CustomHeadersConfig = new Aws.CloudFront.Inputs.ResponseHeadersPolicyCustomHeadersConfigArgs
        {
            Items = new[]
            {
                new Aws.CloudFront.Inputs.ResponseHeadersPolicyCustomHeadersConfigItemArgs
                {
                    Header = "X-Permitted-Cross-Domain-Policies",
                    Override = true,
                    Value = "none",
                },
            },
        },
        RemoveHeadersConfig = new Aws.CloudFront.Inputs.ResponseHeadersPolicyRemoveHeadersConfigArgs
        {
            Items = new[]
            {
                new Aws.CloudFront.Inputs.ResponseHeadersPolicyRemoveHeadersConfigItemArgs
                {
                    Header = "Set-Cookie",
                },
            },
        },
        ServerTimingHeadersConfig = new Aws.CloudFront.Inputs.ResponseHeadersPolicyServerTimingHeadersConfigArgs
        {
            Enabled = true,
            SamplingRate = 50,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicy;
import com.pulumi.aws.cloudfront.ResponseHeadersPolicyArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyCustomHeadersConfigArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyRemoveHeadersConfigArgs;
import com.pulumi.aws.cloudfront.inputs.ResponseHeadersPolicyServerTimingHeadersConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ResponseHeadersPolicy("example", ResponseHeadersPolicyArgs.builder()
            .name("example-headers-policy")
            .customHeadersConfig(ResponseHeadersPolicyCustomHeadersConfigArgs.builder()
                .items(ResponseHeadersPolicyCustomHeadersConfigItemArgs.builder()
                    .header("X-Permitted-Cross-Domain-Policies")
                    .override(true)
                    .value("none")
                    .build())
                .build())
            .removeHeadersConfig(ResponseHeadersPolicyRemoveHeadersConfigArgs.builder()
                .items(ResponseHeadersPolicyRemoveHeadersConfigItemArgs.builder()
                    .header("Set-Cookie")
                    .build())
                .build())
            .serverTimingHeadersConfig(ResponseHeadersPolicyServerTimingHeadersConfigArgs.builder()
                .enabled(true)
                .samplingRate(50.0)
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cloudfront:ResponseHeadersPolicy
    properties:
      name: example-headers-policy
      customHeadersConfig:
        items:
          - header: X-Permitted-Cross-Domain-Policies
            override: true
            value: none
      removeHeadersConfig:
        items:
          - header: Set-Cookie
      serverTimingHeadersConfig:
        enabled: true
        samplingRate: 50

This configuration extends the custom headers pattern by adding removeHeadersConfig to strip Set-Cookie headers from responses, preventing cookie leakage. The serverTimingHeadersConfig enables Server-Timing headers for performance monitoring, with samplingRate controlling what percentage of responses include timing data.

Beyond these examples

These snippets focus on specific response headers policy features: CORS configuration, custom header injection, and header removal and Server-Timing. They’re intentionally minimal rather than full CloudFront configurations.

The examples assume pre-existing infrastructure such as CloudFront distributions with cache behaviors. They focus on defining the policy rather than attaching it to distributions.

To keep things focused, common policy patterns are omitted, including:

  • Security headers (Content-Security-Policy, X-Frame-Options, etc.)
  • Policy attachment to cache behaviors
  • Multiple header configurations in a single policy
  • Conditional header logic based on request properties

These omissions are intentional: the goal is to illustrate how each policy feature is wired, not provide drop-in CloudFront modules. See the CloudFront ResponseHeadersPolicy resource reference for all available configuration options.

Let's configure AWS CloudFront Response Headers Policies

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Policy Basics
What is a CloudFront response headers policy?
A response headers policy contains HTTP response headers and their values that CloudFront adds to responses. After creating a policy, you attach it to cache behaviors in a CloudFront distribution using its ID. The only required field is name.
How do I attach a response headers policy to a CloudFront distribution?
After creating the policy, use its ID to attach it to one or more cache behaviors in a CloudFront distribution. CloudFront will then add the configured headers to every response matching that cache behavior.
What types of headers can I configure?
You can configure five types of headers: CORS headers (corsConfig), custom headers (customHeadersConfig), security headers (securityHeadersConfig), headers to remove (removeHeadersConfig), and Server-Timing headers (serverTimingHeadersConfig).
What's the maximum length for the comment field?
The comment cannot be longer than 128 characters.
Header Configuration
How do I configure CORS headers?
Use corsConfig with accessControlAllowCredentials, accessControlAllowHeaders, accessControlAllowMethods, accessControlAllowOrigins, and originOverride. Each allow property contains an items array with the allowed values.
How do I add custom headers to responses?
Configure customHeadersConfig with an items array. Each item specifies a header name, value, and override flag to control whether CloudFront overrides existing headers.
Can I remove headers from CloudFront responses?
Yes, use removeHeadersConfig with an items array specifying which headers to remove. For example, you can remove Set-Cookie headers from responses.
What does the override flag do in header configurations?
The override flag controls whether CloudFront overrides existing headers with the same name. When set to true, CloudFront replaces any existing header; when false, it only adds the header if it doesn’t already exist.
How do I enable Server-Timing headers?
Configure serverTimingHeadersConfig with enabled: true and a samplingRate (0-100) to control what percentage of requests include the Server-Timing header. For example, samplingRate: 50 enables it for 50% of requests.

Using a different cloud?

Explore networking guides for other cloud providers: