The azure-native:compute:Image resource, part of the Pulumi Azure Native provider, defines a managed VM image that captures OS and data disk configurations for reuse across VM deployments. This guide focuses on four capabilities: capturing images from running VMs, converting VHD blobs and managed disks to images, including data disks in multi-volume images, and applying customer-managed encryption.
Images reference existing VMs, VHD blobs, managed disks, or snapshots. They may require DiskEncryptionSets for customer-managed encryption. The examples are intentionally small. Combine them with your own VM preparation workflows and encryption policies.
Capture an image from a running VM
Teams often need to replicate VM configurations across environments or create golden images from customized VMs. Azure allows you to capture a generalized VM as an image.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const image = new azure_native.compute.Image("image", {
imageName: "myImage",
location: "West US",
resourceGroupName: "myResourceGroup",
sourceVirtualMachine: {
id: "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM",
},
});
import pulumi
import pulumi_azure_native as azure_native
image = azure_native.compute.Image("image",
image_name="myImage",
location="West US",
resource_group_name="myResourceGroup",
source_virtual_machine={
"id": "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM",
})
package main
import (
compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewImage(ctx, "image", &compute.ImageArgs{
ImageName: pulumi.String("myImage"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
SourceVirtualMachine: &compute.SubResourceArgs{
Id: pulumi.String("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var image = new AzureNative.Compute.Image("image", new()
{
ImageName = "myImage",
Location = "West US",
ResourceGroupName = "myResourceGroup",
SourceVirtualMachine = new AzureNative.Compute.Inputs.SubResourceArgs
{
Id = "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Image;
import com.pulumi.azurenative.compute.ImageArgs;
import com.pulumi.azurenative.compute.inputs.SubResourceArgs;
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 image = new Image("image", ImageArgs.builder()
.imageName("myImage")
.location("West US")
.resourceGroupName("myResourceGroup")
.sourceVirtualMachine(SubResourceArgs.builder()
.id("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM")
.build())
.build());
}
}
resources:
image:
type: azure-native:compute:Image
properties:
imageName: myImage
location: West US
resourceGroupName: myResourceGroup
sourceVirtualMachine:
id: /subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM
The sourceVirtualMachine property points to an existing VM by its resource ID. The VM must be in a generalized state before capture: run sysprep on Windows or waagent deprovision on Linux. Once captured, the image can deploy identical VMs across regions or subscriptions.
Create an image from a VHD blob
Organizations migrating from on-premises or other clouds often have VHD files stored in Azure Blob Storage. These VHDs can be converted into managed images for VM deployment.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const image = new azure_native.compute.Image("image", {
imageName: "myImage",
location: "West US",
resourceGroupName: "myResourceGroup",
storageProfile: {
osDisk: {
blobUri: "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
osState: azure_native.compute.OperatingSystemStateTypes.Generalized,
osType: azure_native.compute.OperatingSystemTypes.Linux,
},
zoneResilient: true,
},
});
import pulumi
import pulumi_azure_native as azure_native
image = azure_native.compute.Image("image",
image_name="myImage",
location="West US",
resource_group_name="myResourceGroup",
storage_profile={
"os_disk": {
"blob_uri": "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
"os_state": azure_native.compute.OperatingSystemStateTypes.GENERALIZED,
"os_type": azure_native.compute.OperatingSystemTypes.LINUX,
},
"zone_resilient": True,
})
package main
import (
compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewImage(ctx, "image", &compute.ImageArgs{
ImageName: pulumi.String("myImage"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
StorageProfile: &compute.ImageStorageProfileArgs{
OsDisk: &compute.ImageOSDiskArgs{
BlobUri: pulumi.String("https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd"),
OsState: compute.OperatingSystemStateTypesGeneralized,
OsType: compute.OperatingSystemTypesLinux,
},
ZoneResilient: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var image = new AzureNative.Compute.Image("image", new()
{
ImageName = "myImage",
Location = "West US",
ResourceGroupName = "myResourceGroup",
StorageProfile = new AzureNative.Compute.Inputs.ImageStorageProfileArgs
{
OsDisk = new AzureNative.Compute.Inputs.ImageOSDiskArgs
{
BlobUri = "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
OsState = AzureNative.Compute.OperatingSystemStateTypes.Generalized,
OsType = AzureNative.Compute.OperatingSystemTypes.Linux,
},
ZoneResilient = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Image;
import com.pulumi.azurenative.compute.ImageArgs;
import com.pulumi.azurenative.compute.inputs.ImageStorageProfileArgs;
import com.pulumi.azurenative.compute.inputs.ImageOSDiskArgs;
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 image = new Image("image", ImageArgs.builder()
.imageName("myImage")
.location("West US")
.resourceGroupName("myResourceGroup")
.storageProfile(ImageStorageProfileArgs.builder()
.osDisk(ImageOSDiskArgs.builder()
.blobUri("https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd")
.osState("Generalized")
.osType("Linux")
.build())
.zoneResilient(true)
.build())
.build());
}
}
resources:
image:
type: azure-native:compute:Image
properties:
imageName: myImage
location: West US
resourceGroupName: myResourceGroup
storageProfile:
osDisk:
blobUri: https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd
osState: Generalized
osType: Linux
zoneResilient: true
The storageProfile defines the OS disk source. The blobUri points to your VHD file in blob storage. The osState must be Generalized, and osType specifies Linux or Windows. The zoneResilient property enables zone-redundant storage for higher availability.
Create an image from a managed disk
When you have a managed disk containing a generalized OS, you can create an image directly from it without needing intermediate blob storage.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const image = new azure_native.compute.Image("image", {
imageName: "myImage",
location: "West US",
resourceGroupName: "myResourceGroup",
storageProfile: {
osDisk: {
managedDisk: {
id: "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
osState: azure_native.compute.OperatingSystemStateTypes.Generalized,
osType: azure_native.compute.OperatingSystemTypes.Linux,
},
zoneResilient: true,
},
});
import pulumi
import pulumi_azure_native as azure_native
image = azure_native.compute.Image("image",
image_name="myImage",
location="West US",
resource_group_name="myResourceGroup",
storage_profile={
"os_disk": {
"managed_disk": {
"id": "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
"os_state": azure_native.compute.OperatingSystemStateTypes.GENERALIZED,
"os_type": azure_native.compute.OperatingSystemTypes.LINUX,
},
"zone_resilient": True,
})
package main
import (
compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewImage(ctx, "image", &compute.ImageArgs{
ImageName: pulumi.String("myImage"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
StorageProfile: &compute.ImageStorageProfileArgs{
OsDisk: &compute.ImageOSDiskArgs{
ManagedDisk: &compute.SubResourceArgs{
Id: pulumi.String("subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk"),
},
OsState: compute.OperatingSystemStateTypesGeneralized,
OsType: compute.OperatingSystemTypesLinux,
},
ZoneResilient: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var image = new AzureNative.Compute.Image("image", new()
{
ImageName = "myImage",
Location = "West US",
ResourceGroupName = "myResourceGroup",
StorageProfile = new AzureNative.Compute.Inputs.ImageStorageProfileArgs
{
OsDisk = new AzureNative.Compute.Inputs.ImageOSDiskArgs
{
ManagedDisk = new AzureNative.Compute.Inputs.SubResourceArgs
{
Id = "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
OsState = AzureNative.Compute.OperatingSystemStateTypes.Generalized,
OsType = AzureNative.Compute.OperatingSystemTypes.Linux,
},
ZoneResilient = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Image;
import com.pulumi.azurenative.compute.ImageArgs;
import com.pulumi.azurenative.compute.inputs.ImageStorageProfileArgs;
import com.pulumi.azurenative.compute.inputs.ImageOSDiskArgs;
import com.pulumi.azurenative.compute.inputs.SubResourceArgs;
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 image = new Image("image", ImageArgs.builder()
.imageName("myImage")
.location("West US")
.resourceGroupName("myResourceGroup")
.storageProfile(ImageStorageProfileArgs.builder()
.osDisk(ImageOSDiskArgs.builder()
.managedDisk(SubResourceArgs.builder()
.id("subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk")
.build())
.osState("Generalized")
.osType("Linux")
.build())
.zoneResilient(true)
.build())
.build());
}
}
resources:
image:
type: azure-native:compute:Image
properties:
imageName: myImage
location: West US
resourceGroupName: myResourceGroup
storageProfile:
osDisk:
managedDisk:
id: subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk
osState: Generalized
osType: Linux
zoneResilient: true
The managedDisk property references an existing disk by ID. This approach is faster than blob-based images because the disk is already in Azure’s managed storage. The disk must contain a generalized OS; specialized disks retain machine-specific configuration and won’t work for multi-VM deployments.
Include data disks in an image
Applications often require both OS and data disks. Images can include multiple disks, allowing you to deploy VMs with pre-configured data volumes.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const image = new azure_native.compute.Image("image", {
imageName: "myImage",
location: "West US",
resourceGroupName: "myResourceGroup",
storageProfile: {
dataDisks: [{
lun: 1,
managedDisk: {
id: "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2",
},
}],
osDisk: {
managedDisk: {
id: "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
osState: azure_native.compute.OperatingSystemStateTypes.Generalized,
osType: azure_native.compute.OperatingSystemTypes.Linux,
},
zoneResilient: false,
},
});
import pulumi
import pulumi_azure_native as azure_native
image = azure_native.compute.Image("image",
image_name="myImage",
location="West US",
resource_group_name="myResourceGroup",
storage_profile={
"data_disks": [{
"lun": 1,
"managed_disk": {
"id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2",
},
}],
"os_disk": {
"managed_disk": {
"id": "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
"os_state": azure_native.compute.OperatingSystemStateTypes.GENERALIZED,
"os_type": azure_native.compute.OperatingSystemTypes.LINUX,
},
"zone_resilient": False,
})
package main
import (
compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewImage(ctx, "image", &compute.ImageArgs{
ImageName: pulumi.String("myImage"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
StorageProfile: &compute.ImageStorageProfileArgs{
DataDisks: compute.ImageDataDiskArray{
&compute.ImageDataDiskArgs{
Lun: pulumi.Int(1),
ManagedDisk: &compute.SubResourceArgs{
Id: pulumi.String("subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2"),
},
},
},
OsDisk: &compute.ImageOSDiskArgs{
ManagedDisk: &compute.SubResourceArgs{
Id: pulumi.String("subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk"),
},
OsState: compute.OperatingSystemStateTypesGeneralized,
OsType: compute.OperatingSystemTypesLinux,
},
ZoneResilient: pulumi.Bool(false),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var image = new AzureNative.Compute.Image("image", new()
{
ImageName = "myImage",
Location = "West US",
ResourceGroupName = "myResourceGroup",
StorageProfile = new AzureNative.Compute.Inputs.ImageStorageProfileArgs
{
DataDisks = new[]
{
new AzureNative.Compute.Inputs.ImageDataDiskArgs
{
Lun = 1,
ManagedDisk = new AzureNative.Compute.Inputs.SubResourceArgs
{
Id = "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2",
},
},
},
OsDisk = new AzureNative.Compute.Inputs.ImageOSDiskArgs
{
ManagedDisk = new AzureNative.Compute.Inputs.SubResourceArgs
{
Id = "subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk",
},
OsState = AzureNative.Compute.OperatingSystemStateTypes.Generalized,
OsType = AzureNative.Compute.OperatingSystemTypes.Linux,
},
ZoneResilient = false,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Image;
import com.pulumi.azurenative.compute.ImageArgs;
import com.pulumi.azurenative.compute.inputs.ImageStorageProfileArgs;
import com.pulumi.azurenative.compute.inputs.ImageOSDiskArgs;
import com.pulumi.azurenative.compute.inputs.SubResourceArgs;
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 image = new Image("image", ImageArgs.builder()
.imageName("myImage")
.location("West US")
.resourceGroupName("myResourceGroup")
.storageProfile(ImageStorageProfileArgs.builder()
.dataDisks(ImageDataDiskArgs.builder()
.lun(1)
.managedDisk(SubResourceArgs.builder()
.id("subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2")
.build())
.build())
.osDisk(ImageOSDiskArgs.builder()
.managedDisk(SubResourceArgs.builder()
.id("subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk")
.build())
.osState("Generalized")
.osType("Linux")
.build())
.zoneResilient(false)
.build())
.build());
}
}
resources:
image:
type: azure-native:compute:Image
properties:
imageName: myImage
location: West US
resourceGroupName: myResourceGroup
storageProfile:
dataDisks:
- lun: 1
managedDisk:
id: subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2
osDisk:
managedDisk:
id: subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk
osState: Generalized
osType: Linux
zoneResilient: false
The dataDisks array adds additional volumes to the image. Each data disk requires a lun (Logical Unit Number) that identifies its attachment point. When you deploy a VM from this image, both OS and data disks are created automatically, preserving your application’s storage layout.
Encrypt an image with DiskEncryptionSet
Compliance requirements often mandate encryption at rest using customer-managed keys. DiskEncryptionSet allows you to encrypt images with keys from Azure Key Vault.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const image = new azure_native.compute.Image("image", {
imageName: "myImage",
location: "West US",
resourceGroupName: "myResourceGroup",
storageProfile: {
osDisk: {
blobUri: "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
diskEncryptionSet: {
id: "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
},
osState: azure_native.compute.OperatingSystemStateTypes.Generalized,
osType: azure_native.compute.OperatingSystemTypes.Linux,
},
},
});
import pulumi
import pulumi_azure_native as azure_native
image = azure_native.compute.Image("image",
image_name="myImage",
location="West US",
resource_group_name="myResourceGroup",
storage_profile={
"os_disk": {
"blob_uri": "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
"disk_encryption_set": {
"id": "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
},
"os_state": azure_native.compute.OperatingSystemStateTypes.GENERALIZED,
"os_type": azure_native.compute.OperatingSystemTypes.LINUX,
},
})
package main
import (
compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewImage(ctx, "image", &compute.ImageArgs{
ImageName: pulumi.String("myImage"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
StorageProfile: &compute.ImageStorageProfileArgs{
OsDisk: &compute.ImageOSDiskArgs{
BlobUri: pulumi.String("https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd"),
DiskEncryptionSet: &compute.DiskEncryptionSetParametersArgs{
Id: pulumi.String("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}"),
},
OsState: compute.OperatingSystemStateTypesGeneralized,
OsType: compute.OperatingSystemTypesLinux,
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var image = new AzureNative.Compute.Image("image", new()
{
ImageName = "myImage",
Location = "West US",
ResourceGroupName = "myResourceGroup",
StorageProfile = new AzureNative.Compute.Inputs.ImageStorageProfileArgs
{
OsDisk = new AzureNative.Compute.Inputs.ImageOSDiskArgs
{
BlobUri = "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd",
DiskEncryptionSet = new AzureNative.Compute.Inputs.DiskEncryptionSetParametersArgs
{
Id = "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
},
OsState = AzureNative.Compute.OperatingSystemStateTypes.Generalized,
OsType = AzureNative.Compute.OperatingSystemTypes.Linux,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Image;
import com.pulumi.azurenative.compute.ImageArgs;
import com.pulumi.azurenative.compute.inputs.ImageStorageProfileArgs;
import com.pulumi.azurenative.compute.inputs.ImageOSDiskArgs;
import com.pulumi.azurenative.compute.inputs.DiskEncryptionSetParametersArgs;
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 image = new Image("image", ImageArgs.builder()
.imageName("myImage")
.location("West US")
.resourceGroupName("myResourceGroup")
.storageProfile(ImageStorageProfileArgs.builder()
.osDisk(ImageOSDiskArgs.builder()
.blobUri("https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd")
.diskEncryptionSet(DiskEncryptionSetParametersArgs.builder()
.id("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}")
.build())
.osState("Generalized")
.osType("Linux")
.build())
.build())
.build());
}
}
resources:
image:
type: azure-native:compute:Image
properties:
imageName: myImage
location: West US
resourceGroupName: myResourceGroup
storageProfile:
osDisk:
blobUri: https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd
diskEncryptionSet:
id: /subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}
osState: Generalized
osType: Linux
The diskEncryptionSet property references a DiskEncryptionSet resource that wraps your Key Vault key. When VMs are deployed from this image, their disks inherit the encryption configuration. The DiskEncryptionSet must exist before image creation and requires permissions to access your Key Vault.
Beyond these examples
These snippets focus on specific image-level features: image sources (VMs, blobs, managed disks, snapshots), multi-disk images with data volumes, and customer-managed encryption with DiskEncryptionSet. They’re intentionally minimal rather than full VM deployment workflows.
The examples may reference pre-existing infrastructure such as VMs in generalized state, VHD blobs in storage accounts, managed disks and snapshots, and DiskEncryptionSets with Key Vault access. They focus on configuring the image rather than provisioning the source resources.
To keep things focused, common image patterns are omitted, including:
- HyperV generation specification (hyperVGeneration)
- Extended location for edge deployments
- Resource tagging for organization
- Zone-resilient storage configuration details
These omissions are intentional: the goal is to illustrate how each image source is wired, not provide drop-in VM templates. See the Image resource reference for all available configuration options.
Let's create Azure VM Images
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Image Sources & Creation
blobUri), managed disks (using managedDisk), snapshots (using snapshot), or existing virtual machines (using sourceVirtualMachine).sourceVirtualMachine property with the VM’s resource ID instead of configuring storageProfile. This captures the entire VM configuration as an image.storageProfile.dataDisks with an array of disks, specifying the source (blobUri, managedDisk, or snapshot) and the lun (logical unit number) for each disk.Configuration & Requirements
hyperVGeneration when creating an image from a blob source. For managed resources like disks or snapshots, you may need to specify it if Azure cannot deduce the value from the source.Generalized for images that have been prepared with sysprep (Windows) or waagent (Linux) to remove machine-specific information. All provided examples use Generalized.diskEncryptionSet in the osDisk configuration with the resource ID of an existing DiskEncryptionSet. This applies to images created from blobs, managed disks, or snapshots.Limitations & Properties
location, imageName, and resourceGroupName properties are immutable and cannot be changed after the image is created.zoneResilient to true makes the image available across availability zones in the region. Use this for high-availability scenarios where VMs may be deployed across multiple zones.pulumi package add azure-native compute [ApiVersion]. Available versions include 2022-08-01, 2022-11-01, 2023-03-01, 2023-07-01, 2023-09-01, 2024-03-01, 2024-07-01, and 2025-04-01.