The aws:s3/accessPoint:AccessPoint resource, part of the Pulumi AWS provider, creates named network endpoints for S3 buckets that simplify permission management and network access control. This guide focuses on three capabilities: general purpose bucket access points, VPC-restricted access, and directory bucket access points.
Access points attach to existing S3 buckets and can restrict traffic to specific VPCs. The examples are intentionally small. Combine them with your own bucket policies, public access blocks, and network configuration.
Create an access point for a general purpose bucket
Most deployments start with a general purpose bucket in a standard AWS region, using access points to delegate access through named endpoints.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.Bucket("example", {bucket: "example"});
const exampleAccessPoint = new aws.s3.AccessPoint("example", {
bucket: example.id,
name: "example",
});
import pulumi
import pulumi_aws as aws
example = aws.s3.Bucket("example", bucket="example")
example_access_point = aws.s3.AccessPoint("example",
bucket=example.id,
name="example")
package main
import (
"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 {
example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
Bucket: pulumi.String("example"),
})
if err != nil {
return err
}
_, err = s3.NewAccessPoint(ctx, "example", &s3.AccessPointArgs{
Bucket: example.ID(),
Name: pulumi.String("example"),
})
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.S3.Bucket("example", new()
{
BucketName = "example",
});
var exampleAccessPoint = new Aws.S3.AccessPoint("example", new()
{
Bucket = example.Id,
Name = "example",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.s3.AccessPoint;
import com.pulumi.aws.s3.AccessPointArgs;
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 Bucket("example", BucketArgs.builder()
.bucket("example")
.build());
var exampleAccessPoint = new AccessPoint("exampleAccessPoint", AccessPointArgs.builder()
.bucket(example.id())
.name("example")
.build());
}
}
resources:
example:
type: aws:s3:Bucket
properties:
bucket: example
exampleAccessPoint:
type: aws:s3:AccessPoint
name: example
properties:
bucket: ${example.id}
name: example
The bucket property references an S3 bucket by ID. The name property assigns a unique identifier for the access point. Without additional configuration, the access point inherits the bucket’s network origin (Internet or VPC) and allows access subject to bucket and access point policies.
Restrict access to requests from a VPC
Applications in private subnets often need S3 access without traversing the public internet. VPC-restricted access points keep traffic within your network boundary.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3control.Bucket("example", {bucket: "example"});
const exampleVpc = new aws.ec2.Vpc("example", {cidrBlock: "10.0.0.0/16"});
const exampleAccessPoint = new aws.s3.AccessPoint("example", {
bucket: example.arn,
name: "example",
vpcConfiguration: {
vpcId: exampleVpc.id,
},
});
import pulumi
import pulumi_aws as aws
example = aws.s3control.Bucket("example", bucket="example")
example_vpc = aws.ec2.Vpc("example", cidr_block="10.0.0.0/16")
example_access_point = aws.s3.AccessPoint("example",
bucket=example.arn,
name="example",
vpc_configuration={
"vpc_id": example_vpc.id,
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3control"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := s3control.NewBucket(ctx, "example", &s3control.BucketArgs{
Bucket: pulumi.String("example"),
})
if err != nil {
return err
}
exampleVpc, err := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
_, err = s3.NewAccessPoint(ctx, "example", &s3.AccessPointArgs{
Bucket: example.Arn,
Name: pulumi.String("example"),
VpcConfiguration: &s3.AccessPointVpcConfigurationArgs{
VpcId: exampleVpc.ID(),
},
})
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.S3Control.Bucket("example", new()
{
BucketName = "example",
});
var exampleVpc = new Aws.Ec2.Vpc("example", new()
{
CidrBlock = "10.0.0.0/16",
});
var exampleAccessPoint = new Aws.S3.AccessPoint("example", new()
{
Bucket = example.Arn,
Name = "example",
VpcConfiguration = new Aws.S3.Inputs.AccessPointVpcConfigurationArgs
{
VpcId = exampleVpc.Id,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3control.Bucket;
import com.pulumi.aws.s3control.BucketArgs;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.s3.AccessPoint;
import com.pulumi.aws.s3.AccessPointArgs;
import com.pulumi.aws.s3.inputs.AccessPointVpcConfigurationArgs;
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 Bucket("example", BucketArgs.builder()
.bucket("example")
.build());
var exampleVpc = new Vpc("exampleVpc", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var exampleAccessPoint = new AccessPoint("exampleAccessPoint", AccessPointArgs.builder()
.bucket(example.arn())
.name("example")
.vpcConfiguration(AccessPointVpcConfigurationArgs.builder()
.vpcId(exampleVpc.id())
.build())
.build());
}
}
resources:
example:
type: aws:s3control:Bucket
properties:
bucket: example
exampleAccessPoint:
type: aws:s3:AccessPoint
name: example
properties:
bucket: ${example.arn}
name: example
vpcConfiguration:
vpcId: ${exampleVpc.id}
exampleVpc:
type: aws:ec2:Vpc
name: example
properties:
cidrBlock: 10.0.0.0/16
The vpcConfiguration block restricts access to requests originating from the specified VPC. The vpcId property identifies which VPC can reach this access point. For S3 on Outposts, VPC configuration is required; the access point uses an s3control.Bucket rather than a standard s3.Bucket.
Create an access point for a directory bucket
Directory buckets provide single-digit millisecond latency for performance-sensitive workloads. Access points for directory buckets follow zone-specific naming conventions.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const available = aws.getAvailabilityZones({
state: "available",
});
const example = new aws.s3.DirectoryBucket("example", {
bucket: "example--zoneId--x-s3",
location: {
name: available.then(available => available.zoneIds?.[0]),
},
});
const exampleAccessPoint = new aws.s3.AccessPoint("example", {
bucket: test.bucket,
name: "example--zoneId--xa-s3",
});
import pulumi
import pulumi_aws as aws
available = aws.get_availability_zones(state="available")
example = aws.s3.DirectoryBucket("example",
bucket="example--zoneId--x-s3",
location={
"name": available.zone_ids[0],
})
example_access_point = aws.s3.AccessPoint("example",
bucket=test["bucket"],
name="example--zoneId--xa-s3")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
"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 {
available, err := aws.GetAvailabilityZones(ctx, &aws.GetAvailabilityZonesArgs{
State: pulumi.StringRef("available"),
}, nil)
if err != nil {
return err
}
_, err = s3.NewDirectoryBucket(ctx, "example", &s3.DirectoryBucketArgs{
Bucket: pulumi.String("example--zoneId--x-s3"),
Location: &s3.DirectoryBucketLocationArgs{
Name: pulumi.String(available.ZoneIds[0]),
},
})
if err != nil {
return err
}
_, err = s3.NewAccessPoint(ctx, "example", &s3.AccessPointArgs{
Bucket: pulumi.Any(test.Bucket),
Name: pulumi.String("example--zoneId--xa-s3"),
})
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 available = Aws.GetAvailabilityZones.Invoke(new()
{
State = "available",
});
var example = new Aws.S3.DirectoryBucket("example", new()
{
Bucket = "example--zoneId--x-s3",
Location = new Aws.S3.Inputs.DirectoryBucketLocationArgs
{
Name = available.Apply(getAvailabilityZonesResult => getAvailabilityZonesResult.ZoneIds[0]),
},
});
var exampleAccessPoint = new Aws.S3.AccessPoint("example", new()
{
Bucket = test.Bucket,
Name = "example--zoneId--xa-s3",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetAvailabilityZonesArgs;
import com.pulumi.aws.s3.DirectoryBucket;
import com.pulumi.aws.s3.DirectoryBucketArgs;
import com.pulumi.aws.s3.inputs.DirectoryBucketLocationArgs;
import com.pulumi.aws.s3.AccessPoint;
import com.pulumi.aws.s3.AccessPointArgs;
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 available = AwsFunctions.getAvailabilityZones(GetAvailabilityZonesArgs.builder()
.state("available")
.build());
var example = new DirectoryBucket("example", DirectoryBucketArgs.builder()
.bucket("example--zoneId--x-s3")
.location(DirectoryBucketLocationArgs.builder()
.name(available.zoneIds()[0])
.build())
.build());
var exampleAccessPoint = new AccessPoint("exampleAccessPoint", AccessPointArgs.builder()
.bucket(test.bucket())
.name("example--zoneId--xa-s3")
.build());
}
}
resources:
example:
type: aws:s3:DirectoryBucket
properties:
bucket: example--zoneId--x-s3
location:
name: ${available.zoneIds[0]}
exampleAccessPoint:
type: aws:s3:AccessPoint
name: example
properties:
bucket: ${test.bucket}
name: example--zoneId--xa-s3
variables:
available:
fn::invoke:
function: aws:getAvailabilityZones
arguments:
state: available
Directory bucket access points require names that include the zone ID suffix (e.g., --zoneId--xa-s3). The bucket property references a DirectoryBucket resource. Directory buckets are tied to specific availability zones for consistent low-latency access.
Beyond these examples
These snippets focus on specific access point features: general purpose and directory bucket access points, and VPC-restricted access. They’re intentionally minimal rather than full access control solutions.
The examples reference pre-existing infrastructure such as S3 buckets (general purpose, Outposts, or directory) and VPCs for network-restricted access points. They focus on creating the access point rather than provisioning buckets or network infrastructure.
To keep things focused, common access point patterns are omitted, including:
- Access point policies (policy property or aws.s3control.AccessPointPolicy)
- Public access block configuration (publicAccessBlockConfiguration)
- Cross-account access and bucket ownership
- Tags for organization and cost tracking
These omissions are intentional: the goal is to illustrate how each access point feature is wired, not provide drop-in access control modules. See the S3 AccessPoint resource reference for all available configuration options.
Let's configure AWS S3 Access Points
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Policy Management
policy on the AccessPoint resource together with a separate aws.s3control.AccessPointPolicy resource. Choose one approach or the other to avoid conflicts and policy overwrites.policy to "{}" (an empty JSON document). Setting it to null or an empty string won’t delete the policy, since it may have been set by aws.s3control.AccessPointPolicy.Configuration & Setup
s3control endpoint provider configuration, not the s3 endpoint provider. Using the wrong endpoint will cause API errors.accountId, bucket, bucketAccountId, name, publicAccessBlockConfiguration, and vpcConfiguration.vpcConfiguration with a VPC ID to restrict access to the specified VPC. This is required for S3 on Outposts buckets.Bucket Types & Compatibility
Security & Access
accountId:name (e.g., 123456789012:example). For S3 on Outposts, use the full ARN.