The aws:storagegateway/cachesIscsiVolume:CachesIscsiVolume resource, part of the Pulumi AWS provider, provisions cached iSCSI volumes that store frequently accessed data locally on the gateway while backing all data to S3. This guide focuses on three capabilities: creating empty volumes, restoring from EBS snapshots, and cloning existing volumes.
Cached iSCSI volumes require a Storage Gateway with cache and upload buffer already configured. The gateway must have cache added (via aws.storagegateway.Cache) before creating volumes, and an upload buffer (via aws.storagegateway.UploadBuffer) before volumes become operational to clients. The examples are intentionally small. Combine them with your own gateway infrastructure and encryption configuration.
Create an empty cached iSCSI volume
Most deployments start by creating a new empty volume that applications can mount and use immediately, with frequently accessed data cached locally.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.CachesIscsiVolume("example", {
gatewayArn: exampleAwsStoragegatewayCache.gatewayArn,
networkInterfaceId: exampleAwsInstance.privateIp,
targetName: "example",
volumeSizeInBytes: 5368709120,
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.CachesIscsiVolume("example",
gateway_arn=example_aws_storagegateway_cache["gatewayArn"],
network_interface_id=example_aws_instance["privateIp"],
target_name="example",
volume_size_in_bytes=5368709120)
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.NewCachesIscsiVolume(ctx, "example", &storagegateway.CachesIscsiVolumeArgs{
GatewayArn: pulumi.Any(exampleAwsStoragegatewayCache.GatewayArn),
NetworkInterfaceId: pulumi.Any(exampleAwsInstance.PrivateIp),
TargetName: pulumi.String("example"),
VolumeSizeInBytes: pulumi.Int(5368709120),
})
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.CachesIscsiVolume("example", new()
{
GatewayArn = exampleAwsStoragegatewayCache.GatewayArn,
NetworkInterfaceId = exampleAwsInstance.PrivateIp,
TargetName = "example",
VolumeSizeInBytes = 5368709120,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.CachesIscsiVolume;
import com.pulumi.aws.storagegateway.CachesIscsiVolumeArgs;
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 CachesIscsiVolume("example", CachesIscsiVolumeArgs.builder()
.gatewayArn(exampleAwsStoragegatewayCache.gatewayArn())
.networkInterfaceId(exampleAwsInstance.privateIp())
.targetName("example")
.volumeSizeInBytes(5368709120)
.build());
}
}
resources:
example:
type: aws:storagegateway:CachesIscsiVolume
properties:
gatewayArn: ${exampleAwsStoragegatewayCache.gatewayArn}
networkInterfaceId: ${exampleAwsInstance.privateIp}
targetName: example
volumeSizeInBytes: 5.36870912e+09 # 5 GB
The volume exposes an iSCSI target on the gateway’s network interface. The targetName identifies the iSCSI target for initiator connections and must be unique across all volumes on the gateway. The volumeSizeInBytes sets the total capacity in bytes. The gatewayArn references the Storage Gateway that hosts this volume.
Restore a volume from an EBS snapshot
Teams migrating existing EBS volumes to Storage Gateway or recovering from backups can restore volumes from EBS snapshots.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.CachesIscsiVolume("example", {
gatewayArn: exampleAwsStoragegatewayCache.gatewayArn,
networkInterfaceId: exampleAwsInstance.privateIp,
snapshotId: exampleAwsEbsSnapshot.id,
targetName: "example",
volumeSizeInBytes: exampleAwsEbsSnapshot.volumeSize * 1024 * 1024 * 1024,
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.CachesIscsiVolume("example",
gateway_arn=example_aws_storagegateway_cache["gatewayArn"],
network_interface_id=example_aws_instance["privateIp"],
snapshot_id=example_aws_ebs_snapshot["id"],
target_name="example",
volume_size_in_bytes=example_aws_ebs_snapshot["volumeSize"] * 1024 * 1024 * 1024)
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.NewCachesIscsiVolume(ctx, "example", &storagegateway.CachesIscsiVolumeArgs{
GatewayArn: pulumi.Any(exampleAwsStoragegatewayCache.GatewayArn),
NetworkInterfaceId: pulumi.Any(exampleAwsInstance.PrivateIp),
SnapshotId: pulumi.Any(exampleAwsEbsSnapshot.Id),
TargetName: pulumi.String("example"),
VolumeSizeInBytes: int(exampleAwsEbsSnapshot.VolumeSize * 1024 * 1024 * 1024),
})
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.CachesIscsiVolume("example", new()
{
GatewayArn = exampleAwsStoragegatewayCache.GatewayArn,
NetworkInterfaceId = exampleAwsInstance.PrivateIp,
SnapshotId = exampleAwsEbsSnapshot.Id,
TargetName = "example",
VolumeSizeInBytes = exampleAwsEbsSnapshot.VolumeSize * 1024 * 1024 * 1024,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.CachesIscsiVolume;
import com.pulumi.aws.storagegateway.CachesIscsiVolumeArgs;
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 CachesIscsiVolume("example", CachesIscsiVolumeArgs.builder()
.gatewayArn(exampleAwsStoragegatewayCache.gatewayArn())
.networkInterfaceId(exampleAwsInstance.privateIp())
.snapshotId(exampleAwsEbsSnapshot.id())
.targetName("example")
.volumeSizeInBytes(exampleAwsEbsSnapshot.volumeSize() * 1024 * 1024 * 1024)
.build());
}
}
When you specify a snapshotId, the volume restores data from that EBS snapshot. The volumeSizeInBytes must match or exceed the snapshot’s original volume size. This approach lets you migrate existing EBS data to Storage Gateway’s hybrid storage model.
Clone an existing Storage Gateway volume
Applications that need test environments or data replication can clone existing Storage Gateway volumes to create exact copies at a specific recovery point.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.storagegateway.CachesIscsiVolume("example", {
gatewayArn: exampleAwsStoragegatewayCache.gatewayArn,
networkInterfaceId: exampleAwsInstance.privateIp,
sourceVolumeArn: existing.arn,
targetName: "example",
volumeSizeInBytes: existing.volumeSizeInBytes,
});
import pulumi
import pulumi_aws as aws
example = aws.storagegateway.CachesIscsiVolume("example",
gateway_arn=example_aws_storagegateway_cache["gatewayArn"],
network_interface_id=example_aws_instance["privateIp"],
source_volume_arn=existing["arn"],
target_name="example",
volume_size_in_bytes=existing["volumeSizeInBytes"])
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.NewCachesIscsiVolume(ctx, "example", &storagegateway.CachesIscsiVolumeArgs{
GatewayArn: pulumi.Any(exampleAwsStoragegatewayCache.GatewayArn),
NetworkInterfaceId: pulumi.Any(exampleAwsInstance.PrivateIp),
SourceVolumeArn: pulumi.Any(existing.Arn),
TargetName: pulumi.String("example"),
VolumeSizeInBytes: pulumi.Any(existing.VolumeSizeInBytes),
})
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.CachesIscsiVolume("example", new()
{
GatewayArn = exampleAwsStoragegatewayCache.GatewayArn,
NetworkInterfaceId = exampleAwsInstance.PrivateIp,
SourceVolumeArn = existing.Arn,
TargetName = "example",
VolumeSizeInBytes = existing.VolumeSizeInBytes,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.storagegateway.CachesIscsiVolume;
import com.pulumi.aws.storagegateway.CachesIscsiVolumeArgs;
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 CachesIscsiVolume("example", CachesIscsiVolumeArgs.builder()
.gatewayArn(exampleAwsStoragegatewayCache.gatewayArn())
.networkInterfaceId(exampleAwsInstance.privateIp())
.sourceVolumeArn(existing.arn())
.targetName("example")
.volumeSizeInBytes(existing.volumeSizeInBytes())
.build());
}
}
resources:
example:
type: aws:storagegateway:CachesIscsiVolume
properties:
gatewayArn: ${exampleAwsStoragegatewayCache.gatewayArn}
networkInterfaceId: ${exampleAwsInstance.privateIp}
sourceVolumeArn: ${existing.arn}
targetName: example
volumeSizeInBytes: ${existing.volumeSizeInBytes}
The sourceVolumeArn points to an existing Storage Gateway volume. The new volume becomes an exact copy of the source volume’s latest recovery point. The volumeSizeInBytes must equal or exceed the source volume’s size.
Beyond these examples
These snippets focus on specific volume-level features: empty volume creation, snapshot and volume cloning, and iSCSI target configuration. They’re intentionally minimal rather than full storage deployments.
The examples rely on pre-existing infrastructure such as Storage Gateway with cache and upload buffer configured, gateway network interfaces (private IPs), and EBS snapshots or existing volumes for restore/clone scenarios. They focus on configuring the volume rather than provisioning the gateway infrastructure.
To keep things focused, common volume patterns are omitted, including:
- KMS encryption configuration (kmsEncrypted, kmsKey)
- Resource tagging (tags)
- CHAP authentication setup
- Volume resizing or modification
These omissions are intentional: the goal is to illustrate how each volume feature is wired, not provide drop-in storage modules. See the Storage Gateway Cached iSCSI Volume resource reference for all available configuration options.
Let's configure AWS Storage Gateway Cached iSCSI Volumes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Prerequisites & Dependencies
aws.storagegateway.Cache resource, or the Storage Gateway API will return an error.aws.storagegateway.UploadBuffer for the volume to be operational to clients. The API allows volume creation without it, but the volume won’t function until the buffer is configured.aws.storagegateway.Cache resource’s gatewayArn attribute in your volume configuration, or use an explicit dependsOn dependency to ensure proper ordering.Volume Creation Options
volumeSizeInBytes), restore from an EBS snapshot (using snapshotId), or clone an existing volume (using sourceVolumeArn).volumeSizeInBytes parameter.volumeSizeInBytes must be equal to or larger than the source volume’s size in bytes.Configuration & Constraints
gatewayArn, networkInterfaceId, targetName, volumeSizeInBytes, kmsEncrypted, kmsKey, snapshotId, and sourceVolumeArn. Only region and tags can be modified after creation.kmsEncrypted to true and provide the KMS key ARN in kmsKey. Both properties are required together and cannot be changed after creation.targetName must be unique across all volumes of a gateway, and networkInterfaceId only accepts IPv4 addresses.