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 configured cache and upload buffer. The gateway must have cache added (via aws.storagegateway.Cache) before volume creation. Without an upload buffer (via aws.storagegateway.UploadBuffer), volumes will be created but remain in UPLOAD BUFFER NOT CONFIGURED status and won’t be operational to clients. The examples are intentionally small. Combine them with your own gateway infrastructure and iSCSI client configuration.
Create an empty cached iSCSI volume
Most deployments start by creating a new empty volume that applications can mount and use immediately.
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
When you create the volume, Storage Gateway exposes it as an iSCSI target on the specified network interface. The targetName becomes part of the iSCSI Qualified Name (IQN) that clients use to connect. The volumeSizeInBytes sets the total capacity; frequently accessed data stays in the gateway’s local cache while all data backs up to S3. The gatewayArn references the gateway that must already have cache configured.
Restore a volume from an EBS snapshot
Teams migrating existing EBS volumes to Storage Gateway or recovering from backups can restore cached volumes directly from 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());
}
}
The snapshotId property points to an existing EBS snapshot, and Storage Gateway restores its contents into the new cached volume. The volumeSizeInBytes must match or exceed the original snapshot size. This approach works well for migrating on-premises workloads that were previously backed up to EBS, or for disaster recovery scenarios where you need to restore data to a gateway location.
Clone an existing Storage Gateway volume
When you need to duplicate a volume for testing or create a point-in-time copy, you can clone from an existing volume’s latest 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 references an existing Storage Gateway volume, and the new volume becomes an exact copy of that volume’s latest recovery point. Unlike snapshot restore, this works directly with Storage Gateway volumes without requiring an intermediate EBS snapshot. 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 and snapshot and volume cloning. They’re intentionally minimal rather than full storage deployments.
The examples require pre-existing infrastructure such as Storage Gateway with configured cache (aws.storagegateway.Cache), upload buffer configuration (aws.storagegateway.UploadBuffer), gateway ARN and network interface references, 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)
- Volume tagging for organization
- CHAP authentication setup
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 before creating volumes, otherwise the Storage Gateway API will return an error.aws.storagegateway.UploadBuffer.aws.storagegateway.Cache resource’s gatewayArn attribute in your volume configuration, or use explicit dependsOn to declare the dependency (e.g., dependsOn: [exampleCache]).Volume Creation & Configuration
You can create a volume in three ways:
- Empty volume - Specify
volumeSizeInBytesandtargetName - From snapshot - Use
snapshotIdwith a snapshot ID - From existing volume - Use
sourceVolumeArnto clone a volume
snapshotId to the snapshot ID (e.g., snap-1122aabb) and calculate volumeSizeInBytes as the snapshot’s volume size in bytes: snapshotVolumeSize * 1024 * 1024 * 1024.sourceVolumeArn with the existing volume’s ARN. The new volume’s volumeSizeInBytes must be equal to or larger than the source volume’s size in bytes.kmsEncrypted to true and provide kmsKey with the ARN of your AWS KMS key. If kmsEncrypted is false or omitted, Amazon S3-managed encryption is used.Constraints & Limitations
gatewayArn, networkInterfaceId, targetName, volumeSizeInBytes, kmsEncrypted, kmsKey, snapshotId, and sourceVolumeArn. Note that networkInterfaceId only accepts IPv4 addresses.targetName must be unique across all volumes of a gateway. Using a duplicate name will cause an error.