The aws:cloudfront/originAccessIdentity:OriginAccessIdentity resource, part of the Pulumi AWS provider, creates a CloudFront origin access identity that allows CloudFront to access private S3 content without making buckets publicly readable. This guide focuses on three capabilities: creating origin access identities, connecting them to CloudFront distributions, and configuring S3 bucket policies for access.
Origin access identities establish a trust relationship between CloudFront and S3. The examples are intentionally small. Combine them with your own CloudFront distributions and S3 buckets to build complete content delivery workflows.
Create an origin access identity
CloudFront origin access identities enable CloudFront to serve private S3 content securely without exposing buckets to the public internet.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.cloudfront.OriginAccessIdentity("example", {comment: "Some comment"});
import pulumi
import pulumi_aws as aws
example = aws.cloudfront.OriginAccessIdentity("example", comment="Some comment")
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.NewOriginAccessIdentity(ctx, "example", &cloudfront.OriginAccessIdentityArgs{
Comment: pulumi.String("Some comment"),
})
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.OriginAccessIdentity("example", new()
{
Comment = "Some comment",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudfront.OriginAccessIdentity;
import com.pulumi.aws.cloudfront.OriginAccessIdentityArgs;
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 OriginAccessIdentity("example", OriginAccessIdentityArgs.builder()
.comment("Some comment")
.build());
}
}
resources:
example:
type: aws:cloudfront:OriginAccessIdentity
properties:
comment: Some comment
The comment property adds human-readable metadata to identify the identity’s purpose. Once created, the identity generates several output properties including cloudfrontAccessIdentityPath and iamArn, which you’ll use in subsequent configuration steps.
Reference the identity in CloudFront distributions
After creating the identity, connect it to your CloudFront distribution’s S3 origin configuration.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.cloudfront.Distribution("example", {origins: [{
s3OriginConfig: {
originAccessIdentity: exampleAwsCloudfrontOriginAccessIdentity.cloudfrontAccessIdentityPath,
},
}]});
import pulumi
import pulumi_aws as aws
example = aws.cloudfront.Distribution("example", origins=[{
"s3_origin_config": {
"origin_access_identity": example_aws_cloudfront_origin_access_identity["cloudfrontAccessIdentityPath"],
},
}])
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.NewDistribution(ctx, "example", &cloudfront.DistributionArgs{
Origins: cloudfront.DistributionOriginArray{
&cloudfront.DistributionOriginArgs{
S3OriginConfig: &cloudfront.DistributionOriginS3OriginConfigArgs{
OriginAccessIdentity: pulumi.Any(exampleAwsCloudfrontOriginAccessIdentity.CloudfrontAccessIdentityPath),
},
},
},
})
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.Distribution("example", new()
{
Origins = new[]
{
new Aws.CloudFront.Inputs.DistributionOriginArgs
{
S3OriginConfig = new Aws.CloudFront.Inputs.DistributionOriginS3OriginConfigArgs
{
OriginAccessIdentity = exampleAwsCloudfrontOriginAccessIdentity.CloudfrontAccessIdentityPath,
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudfront.Distribution;
import com.pulumi.aws.cloudfront.DistributionArgs;
import com.pulumi.aws.cloudfront.inputs.DistributionOriginArgs;
import com.pulumi.aws.cloudfront.inputs.DistributionOriginS3OriginConfigArgs;
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 Distribution("example", DistributionArgs.builder()
.origins(DistributionOriginArgs.builder()
.s3OriginConfig(DistributionOriginS3OriginConfigArgs.builder()
.originAccessIdentity(exampleAwsCloudfrontOriginAccessIdentity.cloudfrontAccessIdentityPath())
.build())
.build())
.build());
}
}
resources:
example:
type: aws:cloudfront:Distribution
properties:
origins:
- s3OriginConfig:
originAccessIdentity: ${exampleAwsCloudfrontOriginAccessIdentity.cloudfrontAccessIdentityPath}
The cloudfrontAccessIdentityPath property provides the correctly formatted path for CloudFront’s s3OriginConfig. This establishes the trust relationship, allowing CloudFront to request objects from S3 using the identity’s credentials rather than requiring public bucket access.
Grant S3 bucket access using IAM ARN
The S3 bucket policy must explicitly grant the origin access identity permission to read objects.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const s3Policy = aws.iam.getPolicyDocument({
statements: [{
actions: ["s3:GetObject"],
resources: [`${exampleAwsS3Bucket.arn}/*`],
principals: [{
type: "AWS",
identifiers: [exampleAwsCloudfrontOriginAccessIdentity.iamArn],
}],
}],
});
const example = new aws.s3.BucketPolicy("example", {
bucket: exampleAwsS3Bucket.id,
policy: s3Policy.then(s3Policy => s3Policy.json),
});
import pulumi
import pulumi_aws as aws
s3_policy = aws.iam.get_policy_document(statements=[{
"actions": ["s3:GetObject"],
"resources": [f"{example_aws_s3_bucket['arn']}/*"],
"principals": [{
"type": "AWS",
"identifiers": [example_aws_cloudfront_origin_access_identity["iamArn"]],
}],
}])
example = aws.s3.BucketPolicy("example",
bucket=example_aws_s3_bucket["id"],
policy=s3_policy.json)
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
s3Policy, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Actions: []string{
"s3:GetObject",
},
Resources: []string{
fmt.Sprintf("%v/*", exampleAwsS3Bucket.Arn),
},
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "AWS",
Identifiers: interface{}{
exampleAwsCloudfrontOriginAccessIdentity.IamArn,
},
},
},
},
},
}, nil);
if err != nil {
return err
}
_, err = s3.NewBucketPolicy(ctx, "example", &s3.BucketPolicyArgs{
Bucket: pulumi.Any(exampleAwsS3Bucket.Id),
Policy: pulumi.String(s3Policy.Json),
})
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 s3Policy = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Actions = new[]
{
"s3:GetObject",
},
Resources = new[]
{
$"{exampleAwsS3Bucket.Arn}/*",
},
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "AWS",
Identifiers = new[]
{
exampleAwsCloudfrontOriginAccessIdentity.IamArn,
},
},
},
},
},
});
var example = new Aws.S3.BucketPolicy("example", new()
{
Bucket = exampleAwsS3Bucket.Id,
Policy = s3Policy.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.s3.BucketPolicy;
import com.pulumi.aws.s3.BucketPolicyArgs;
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) {
final var s3Policy = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.actions("s3:GetObject")
.resources(String.format("%s/*", exampleAwsS3Bucket.arn()))
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("AWS")
.identifiers(exampleAwsCloudfrontOriginAccessIdentity.iamArn())
.build())
.build())
.build());
var example = new BucketPolicy("example", BucketPolicyArgs.builder()
.bucket(exampleAwsS3Bucket.id())
.policy(s3Policy.json())
.build());
}
}
resources:
example:
type: aws:s3:BucketPolicy
properties:
bucket: ${exampleAwsS3Bucket.id}
policy: ${s3Policy.json}
variables:
s3Policy:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- actions:
- s3:GetObject
resources:
- ${exampleAwsS3Bucket.arn}/*
principals:
- type: AWS
identifiers:
- ${exampleAwsCloudfrontOriginAccessIdentity.iamArn}
The iamArn property provides a stable IAM principal format for bucket policies. Using iamArn instead of s3CanonicalUserId avoids spurious diffs caused by AWS API translations. The policy grants s3:GetObject permission on all objects in the bucket to the CloudFront identity.
Beyond these examples
These snippets focus on specific origin access identity features: identity creation, CloudFront distribution integration, and S3 bucket policy configuration. They’re intentionally minimal rather than complete content delivery setups.
The examples reference pre-existing infrastructure such as S3 buckets for origin content and CloudFront distributions for integration examples. They focus on configuring the origin access identity rather than provisioning the surrounding infrastructure.
To keep things focused, common patterns are omitted, including:
- CloudFront distribution configuration beyond origin settings
- S3 bucket creation and versioning
- Alternative authentication methods (S3 bucket policies with canonical user ID)
- Multi-origin CloudFront setups
These omissions are intentional: the goal is to illustrate how origin access identities are wired, not provide drop-in CDN modules. See the CloudFront OriginAccessIdentity resource reference for all available configuration options.
Let's create AWS CloudFront Origin Access Identities
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
CloudFront Integration
cloudfrontAccessIdentityPath property in your distribution’s s3OriginConfig.originAccessIdentity field. This provides the correctly formatted path without needing to manually add the origin-access-identity/cloudfront/ prefix.origin-access-identity/cloudfront/ prefix already included, so you don’t have to construct it manually.S3 Bucket Policies
s3CanonicalUserId CanonicalUser principal into an AWS IAM ARN principal in bucket policies, causing Pulumi to detect changes on every run. Use iamArn instead of s3CanonicalUserId in your bucket policy principals to avoid this issue.iamArn in the bucket policy’s principal field. While s3CanonicalUserId is available, it causes spurious diffs because AWS translates it to an IAM ARN format.Properties & Outputs
s3CanonicalUserId is the canonical user ID format while iamArn is the pre-generated IAM ARN format (e.g., arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2QWRUHAPOMQZL). Use iamArn in bucket policies to avoid spurious diffs.Using a different cloud?
Explore networking guides for other cloud providers: