The aws:cloudfront/originAccessIdentity:OriginAccessIdentity resource, part of the Pulumi AWS provider, creates a CloudFront origin access identity that allows distributions to access private S3 content without making buckets public. This guide focuses on three capabilities: identity creation, distribution integration, and S3 bucket policy configuration.
Origin access identities work with CloudFront distributions and S3 buckets to establish secure access patterns. The examples are intentionally small. Combine them with your own distribution and bucket configuration.
Create an origin access identity
CloudFront distributions serving content from private S3 buckets need an origin access identity to authenticate requests.
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 descriptive metadata to help identify the identity’s purpose. CloudFront generates a unique ID and canonical user ID that you’ll reference in distribution and bucket configurations.
Reference the identity in a CloudFront distribution
Once created, the identity must be referenced in the 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 between the distribution and the identity, allowing CloudFront to present credentials when requesting objects from S3.
Grant S3 bucket access using the identity
The S3 bucket policy must explicitly allow the origin access identity 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 the principal identifier for bucket policies. Using iamArn instead of s3CanonicalUserId avoids spurious diffs caused by AWS API translations. The policy grants s3:GetObject permission, allowing CloudFront to retrieve objects on behalf of viewers.
Beyond these examples
These snippets focus on specific origin access identity features: identity creation and CloudFront integration, and S3 bucket policy authorization. They’re intentionally minimal rather than complete CDN configurations.
The examples reference pre-existing infrastructure such as S3 buckets and CloudFront distributions. They focus on configuring the identity and its integration points rather than provisioning the full CDN stack.
To keep things focused, common patterns are omitted, including:
- Distribution configuration beyond origin settings
- S3 bucket creation and versioning
- Alternative access methods (CloudFront Functions, Lambda@Edge)
These omissions are intentional: the goal is to illustrate how the origin access identity is 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
S3 Bucket Policies
s3CanonicalUserId CanonicalUser principal into an AWS IAM ARN principal in bucket policies, causing spurious diffs. Use iamArn instead of s3CanonicalUserId in your bucket policy to avoid this issue.iamArn property as the principal identifier. This avoids spurious diffs that occur when using s3CanonicalUserId.s3CanonicalUserId is the canonical user ID while iamArn is a pre-generated ARN. Use iamArn in bucket policies to prevent AWS from translating the principal and causing spurious diffs.CloudFront Integration
cloudfrontAccessIdentityPath property in the s3OriginConfig of your CloudFront distribution. This property provides the full path with the required origin-access-identity/cloudfront/ prefix automatically.Using a different cloud?
Explore networking guides for other cloud providers: