The aws:storagegateway/gateway:Gateway resource, part of the Pulumi AWS provider, provisions a Storage Gateway appliance that bridges on-premises or cloud environments with AWS storage services. This guide focuses on three capabilities: gateway type selection (S3, FSx, tape, volume), Active Directory integration, and local cache configuration.
Storage Gateway requires a deployed VM (on-premises or EC2) that Pulumi can reach on port 80 for activation. Gateways may reference Active Directory domains or EBS volumes for cache storage. The examples are intentionally small. Combine them with your own VM deployment, networking, and storage configuration.
Deploy an S3 file gateway for NFS/SMB access
Teams often need to expose S3 buckets as network file shares for applications that expect traditional file protocols. S3 file gateways bridge this gap by presenting S3 storage through NFS or SMB.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.Gateway("example", {
gatewayIpAddress: "1.2.3.4",
gatewayName: "example",
gatewayTimezone: "GMT",
gatewayType: "FILE_S3",
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.Gateway("example",
gateway_ip_address="1.2.3.4",
gateway_name="example",
gateway_timezone="GMT",
gateway_type="FILE_S3")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/storagegateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := storagegateway.NewGateway(ctx, "example", &storagegateway.GatewayArgs{
GatewayIpAddress: pulumi.String("1.2.3.4"),
GatewayName: pulumi.String("example"),
GatewayTimezone: pulumi.String("GMT"),
GatewayType: pulumi.String("FILE_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 example = new Aws.StorageGateway.Gateway("example", new()
{
GatewayIpAddress = "1.2.3.4",
GatewayName = "example",
GatewayTimezone = "GMT",
GatewayType = "FILE_S3",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.Gateway;
import com.pulumi.aws.storagegateway.GatewayArgs;
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 Gateway("example", GatewayArgs.builder()
.gatewayIpAddress("1.2.3.4")
.gatewayName("example")
.gatewayTimezone("GMT")
.gatewayType("FILE_S3")
.build());
}
}
resources:
example:
type: aws:storagegateway:Gateway
properties:
gatewayIpAddress: 1.2.3.4
gatewayName: example
gatewayTimezone: GMT
gatewayType: FILE_S3
The gatewayIpAddress points to your deployed Storage Gateway VM, which Pulumi contacts on port 80 to retrieve an activation key. The gatewayType of FILE_S3 configures the gateway to present S3 buckets as file shares. The gatewayTimezone sets the schedule for maintenance windows and snapshots.
Connect to FSx for Windows File Server
Organizations with FSx for Windows File Server deployments use FSx file gateways to provide low-latency local access to cloud file shares, with Active Directory integration for authentication.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.Gateway("example", {
gatewayIpAddress: "1.2.3.4",
gatewayName: "example",
gatewayTimezone: "GMT",
gatewayType: "FILE_FSX_SMB",
smbActiveDirectorySettings: {
domainName: "corp.example.com",
password: "avoid-plaintext-passwords",
username: "Admin",
},
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.Gateway("example",
gateway_ip_address="1.2.3.4",
gateway_name="example",
gateway_timezone="GMT",
gateway_type="FILE_FSX_SMB",
smb_active_directory_settings={
"domain_name": "corp.example.com",
"password": "avoid-plaintext-passwords",
"username": "Admin",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/storagegateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := storagegateway.NewGateway(ctx, "example", &storagegateway.GatewayArgs{
GatewayIpAddress: pulumi.String("1.2.3.4"),
GatewayName: pulumi.String("example"),
GatewayTimezone: pulumi.String("GMT"),
GatewayType: pulumi.String("FILE_FSX_SMB"),
SmbActiveDirectorySettings: &storagegateway.GatewaySmbActiveDirectorySettingsArgs{
DomainName: pulumi.String("corp.example.com"),
Password: pulumi.String("avoid-plaintext-passwords"),
Username: pulumi.String("Admin"),
},
})
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.StorageGateway.Gateway("example", new()
{
GatewayIpAddress = "1.2.3.4",
GatewayName = "example",
GatewayTimezone = "GMT",
GatewayType = "FILE_FSX_SMB",
SmbActiveDirectorySettings = new Aws.StorageGateway.Inputs.GatewaySmbActiveDirectorySettingsArgs
{
DomainName = "corp.example.com",
Password = "avoid-plaintext-passwords",
Username = "Admin",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.Gateway;
import com.pulumi.aws.storagegateway.GatewayArgs;
import com.pulumi.aws.storagegateway.inputs.GatewaySmbActiveDirectorySettingsArgs;
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 Gateway("example", GatewayArgs.builder()
.gatewayIpAddress("1.2.3.4")
.gatewayName("example")
.gatewayTimezone("GMT")
.gatewayType("FILE_FSX_SMB")
.smbActiveDirectorySettings(GatewaySmbActiveDirectorySettingsArgs.builder()
.domainName("corp.example.com")
.password("avoid-plaintext-passwords")
.username("Admin")
.build())
.build());
}
}
resources:
example:
type: aws:storagegateway:Gateway
properties:
gatewayIpAddress: 1.2.3.4
gatewayName: example
gatewayTimezone: GMT
gatewayType: FILE_FSX_SMB
smbActiveDirectorySettings:
domainName: corp.example.com
password: avoid-plaintext-passwords
username: Admin
The gatewayType of FILE_FSX_SMB enables FSx integration. The smbActiveDirectorySettings block joins the gateway to your Active Directory domain, allowing Windows authentication for file share access. The gateway caches frequently accessed files locally while storing the full dataset in FSx.
Archive to virtual tape library for backup software
Backup applications that expect tape infrastructure can write to virtual tape libraries instead, with Storage Gateway handling the translation to S3 and Glacier storage.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.Gateway("example", {
gatewayIpAddress: "1.2.3.4",
gatewayName: "example",
gatewayTimezone: "GMT",
gatewayType: "VTL",
mediumChangerType: "AWS-Gateway-VTL",
tapeDriveType: "IBM-ULT3580-TD5",
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.Gateway("example",
gateway_ip_address="1.2.3.4",
gateway_name="example",
gateway_timezone="GMT",
gateway_type="VTL",
medium_changer_type="AWS-Gateway-VTL",
tape_drive_type="IBM-ULT3580-TD5")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/storagegateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := storagegateway.NewGateway(ctx, "example", &storagegateway.GatewayArgs{
GatewayIpAddress: pulumi.String("1.2.3.4"),
GatewayName: pulumi.String("example"),
GatewayTimezone: pulumi.String("GMT"),
GatewayType: pulumi.String("VTL"),
MediumChangerType: pulumi.String("AWS-Gateway-VTL"),
TapeDriveType: pulumi.String("IBM-ULT3580-TD5"),
})
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.StorageGateway.Gateway("example", new()
{
GatewayIpAddress = "1.2.3.4",
GatewayName = "example",
GatewayTimezone = "GMT",
GatewayType = "VTL",
MediumChangerType = "AWS-Gateway-VTL",
TapeDriveType = "IBM-ULT3580-TD5",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.Gateway;
import com.pulumi.aws.storagegateway.GatewayArgs;
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 Gateway("example", GatewayArgs.builder()
.gatewayIpAddress("1.2.3.4")
.gatewayName("example")
.gatewayTimezone("GMT")
.gatewayType("VTL")
.mediumChangerType("AWS-Gateway-VTL")
.tapeDriveType("IBM-ULT3580-TD5")
.build());
}
}
resources:
example:
type: aws:storagegateway:Gateway
properties:
gatewayIpAddress: 1.2.3.4
gatewayName: example
gatewayTimezone: GMT
gatewayType: VTL
mediumChangerType: AWS-Gateway-VTL
tapeDriveType: IBM-ULT3580-TD5
The gatewayType of VTL (Virtual Tape Library) presents iSCSI tape targets to backup software. The mediumChangerType and tapeDriveType properties define the virtual tape hardware that backup applications see. Storage Gateway stores tapes in S3 and archives them to Glacier automatically.
Present cached iSCSI volumes with S3 backing
Applications needing block storage can use cached volume gateways to present iSCSI targets while storing the full dataset in S3, keeping only frequently accessed data local.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.Gateway("example", {
gatewayIpAddress: "1.2.3.4",
gatewayName: "example",
gatewayTimezone: "GMT",
gatewayType: "CACHED",
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.Gateway("example",
gateway_ip_address="1.2.3.4",
gateway_name="example",
gateway_timezone="GMT",
gateway_type="CACHED")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/storagegateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := storagegateway.NewGateway(ctx, "example", &storagegateway.GatewayArgs{
GatewayIpAddress: pulumi.String("1.2.3.4"),
GatewayName: pulumi.String("example"),
GatewayTimezone: pulumi.String("GMT"),
GatewayType: pulumi.String("CACHED"),
})
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.StorageGateway.Gateway("example", new()
{
GatewayIpAddress = "1.2.3.4",
GatewayName = "example",
GatewayTimezone = "GMT",
GatewayType = "CACHED",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.Gateway;
import com.pulumi.aws.storagegateway.GatewayArgs;
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 Gateway("example", GatewayArgs.builder()
.gatewayIpAddress("1.2.3.4")
.gatewayName("example")
.gatewayTimezone("GMT")
.gatewayType("CACHED")
.build());
}
}
resources:
example:
type: aws:storagegateway:Gateway
properties:
gatewayIpAddress: 1.2.3.4
gatewayName: example
gatewayTimezone: GMT
gatewayType: CACHED
The gatewayType of CACHED creates a volume gateway that stores all data in S3 but caches frequently accessed blocks locally. Applications connect via iSCSI and see standard block devices. This configuration requires local cache storage, configured separately.
Configure local disk as cache storage
Cached and stored volume gateways require local disk space for caching frequently accessed data. This configuration attaches an EBS volume to the gateway instance and registers it as cache storage.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const testVolumeAttachment = new aws.ec2.VolumeAttachment("test", {
deviceName: "/dev/xvdb",
volumeId: testAwsEbsVolume.id,
instanceId: testAwsInstance.id,
});
const test = aws.storagegateway.getLocalDisk({
diskNode: testAwsVolumeAttachment.deviceName,
gatewayArn: testAwsStoragegatewayGateway.arn,
});
const testCache = new aws.storagegateway.Cache("test", {
diskId: test.then(test => test.diskId),
gatewayArn: testAwsStoragegatewayGateway.arn,
});
import pulumi
import pulumi_aws as aws
test_volume_attachment = aws.ec2.VolumeAttachment("test",
device_name="/dev/xvdb",
volume_id=test_aws_ebs_volume["id"],
instance_id=test_aws_instance["id"])
test = aws.storagegateway.get_local_disk(disk_node=test_aws_volume_attachment["deviceName"],
gateway_arn=test_aws_storagegateway_gateway["arn"])
test_cache = aws.storagegateway.Cache("test",
disk_id=test.disk_id,
gateway_arn=test_aws_storagegateway_gateway["arn"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/storagegateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := ec2.NewVolumeAttachment(ctx, "test", &ec2.VolumeAttachmentArgs{
DeviceName: pulumi.String("/dev/xvdb"),
VolumeId: pulumi.Any(testAwsEbsVolume.Id),
InstanceId: pulumi.Any(testAwsInstance.Id),
})
if err != nil {
return err
}
test, err := storagegateway.GetLocalDisk(ctx, &storagegateway.GetLocalDiskArgs{
DiskNode: pulumi.StringRef(testAwsVolumeAttachment.DeviceName),
GatewayArn: testAwsStoragegatewayGateway.Arn,
}, nil)
if err != nil {
return err
}
_, err = storagegateway.NewCache(ctx, "test", &storagegateway.CacheArgs{
DiskId: pulumi.String(test.DiskId),
GatewayArn: pulumi.Any(testAwsStoragegatewayGateway.Arn),
})
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 testVolumeAttachment = new Aws.Ec2.VolumeAttachment("test", new()
{
DeviceName = "/dev/xvdb",
VolumeId = testAwsEbsVolume.Id,
InstanceId = testAwsInstance.Id,
});
var test = Aws.StorageGateway.GetLocalDisk.Invoke(new()
{
DiskNode = testAwsVolumeAttachment.DeviceName,
GatewayArn = testAwsStoragegatewayGateway.Arn,
});
var testCache = new Aws.StorageGateway.Cache("test", new()
{
DiskId = test.Apply(getLocalDiskResult => getLocalDiskResult.DiskId),
GatewayArn = testAwsStoragegatewayGateway.Arn,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.VolumeAttachment;
import com.pulumi.aws.ec2.VolumeAttachmentArgs;
import com.pulumi.aws.storagegateway.StoragegatewayFunctions;
import com.pulumi.aws.storagegateway.inputs.GetLocalDiskArgs;
import com.pulumi.aws.storagegateway.Cache;
import com.pulumi.aws.storagegateway.CacheArgs;
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 testVolumeAttachment = new VolumeAttachment("testVolumeAttachment", VolumeAttachmentArgs.builder()
.deviceName("/dev/xvdb")
.volumeId(testAwsEbsVolume.id())
.instanceId(testAwsInstance.id())
.build());
final var test = StoragegatewayFunctions.getLocalDisk(GetLocalDiskArgs.builder()
.diskNode(testAwsVolumeAttachment.deviceName())
.gatewayArn(testAwsStoragegatewayGateway.arn())
.build());
var testCache = new Cache("testCache", CacheArgs.builder()
.diskId(test.diskId())
.gatewayArn(testAwsStoragegatewayGateway.arn())
.build());
}
}
resources:
testVolumeAttachment:
type: aws:ec2:VolumeAttachment
name: test
properties:
deviceName: /dev/xvdb
volumeId: ${testAwsEbsVolume.id}
instanceId: ${testAwsInstance.id}
testCache:
type: aws:storagegateway:Cache
name: test
properties:
diskId: ${test.diskId}
gatewayArn: ${testAwsStoragegatewayGateway.arn}
variables:
test:
fn::invoke:
function: aws:storagegateway:getLocalDisk
arguments:
diskNode: ${testAwsVolumeAttachment.deviceName}
gatewayArn: ${testAwsStoragegatewayGateway.arn}
The getLocalDisk function identifies the attached EBS volume by its device node path. The Cache resource registers this disk with the gateway for caching. This is a prerequisite for cached volume gateways; the gateway must have cache storage before you can create cached volumes.
Beyond these examples
These snippets focus on specific gateway-level features: gateway type selection (S3, FSx, tape, cached/stored volumes), Active Directory integration for SMB, and local cache configuration. They’re intentionally minimal rather than full hybrid storage deployments.
The examples assume pre-existing infrastructure such as Storage Gateway VM deployed on-premises or in EC2, Active Directory domain for FSx gateways, and EBS volumes for cache storage. They focus on configuring the gateway rather than provisioning the underlying VM or network infrastructure.
To keep things focused, common gateway patterns are omitted, including:
- CloudWatch logging (cloudwatchLogGroupArn)
- Bandwidth throttling (averageUploadRateLimitInBitsPerSec, averageDownloadRateLimitInBitsPerSec)
- SMB security strategy and guest passwords
- Maintenance windows (maintenanceStartTime)
These omissions are intentional: the goal is to illustrate how each gateway type is wired, not provide drop-in hybrid storage modules. See the Storage Gateway Gateway resource reference for all available configuration options.
Let's deploy AWS Storage Gateway
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Gateway Activation & Connectivity
activationKey if you’ve already obtained an activation key, or gatewayIpAddress to have Pulumi retrieve the key automatically. With gatewayIpAddress, Pulumi makes an HTTP request to port 80 on the specified IP.gatewayVpcEndpoint to specify the VPC endpoint address. Pulumi must have HTTP access to this endpoint.Gateway Types & Configuration
CACHED (cached volume), STORED (stored volume), FILE_S3 (S3 file gateway), FILE_FSX_SMB (FSx file gateway), and VTL (tape gateway). The default is STORED.gatewayType to VTL and specify both mediumChangerType (e.g., AWS-Gateway-VTL) and tapeDriveType (e.g., IBM-ULT3580-TD5).GMT, GMT-hr:mm, or GMT+hr:mm format. For example, GMT-4:00 indicates 4 hours behind GMT. This timezone is used for scheduling snapshots and maintenance.SMB File Shares
FILE_S3 and FILE_FSX_SMB gateways: set smbActiveDirectorySettings before creating ActiveDirectory authentication shares, and set smbGuestPassword before creating GuestAccess authentication shares.Immutability & Lifecycle
activationKey, gatewayIpAddress, gatewayType, gatewayVpcEndpoint, mediumChangerType, and tapeDriveType. Changing them requires recreating the gateway.gateway_ip_address after creation. Either omit this argument from your program or use ignore_changes to suppress the diff.mediumChangerType and tapeDriveType. You must manually verify these match your desired state.Bandwidth & Performance
averageDownloadRateLimitInBitsPerSec and averageUploadRateLimitInBitsPerSec to set rate limits. These are supported for CACHED, STORED, and VTL gateway types.