The azure-native:compute:Gallery resource, part of the Pulumi Azure Native provider, defines a Shared Image Gallery container for storing and versioning custom VM images. This guide focuses on four capabilities: private gallery creation, cross-subscription sharing, community publishing, and soft deletion protection.
Galleries belong to a resource group and require a subscription. Image definitions and versions are created as separate child resources. The examples are intentionally small. Combine them with your own image definitions, RBAC policies, and tagging strategy.
Create a private gallery for custom images
Most organizations start by creating a private gallery to store and version custom VM images within their subscription.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const gallery = new azure_native.compute.Gallery("gallery", {
description: "This is the gallery description.",
galleryName: "myGalleryName",
location: "West US",
resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native
gallery = azure_native.compute.Gallery("gallery",
description="This is the gallery description.",
gallery_name="myGalleryName",
location="West US",
resource_group_name="myResourceGroup")
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.NewGallery(ctx, "gallery", &compute.GalleryArgs{
Description: pulumi.String("This is the gallery description."),
GalleryName: pulumi.String("myGalleryName"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
})
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 gallery = new AzureNative.Compute.Gallery("gallery", new()
{
Description = "This is the gallery description.",
GalleryName = "myGalleryName",
Location = "West US",
ResourceGroupName = "myResourceGroup",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Gallery;
import com.pulumi.azurenative.compute.GalleryArgs;
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 gallery = new Gallery("gallery", GalleryArgs.builder()
.description("This is the gallery description.")
.galleryName("myGalleryName")
.location("West US")
.resourceGroupName("myResourceGroup")
.build());
}
}
resources:
gallery:
type: azure-native:compute:Gallery
properties:
description: This is the gallery description.
galleryName: myGalleryName
location: West US
resourceGroupName: myResourceGroup
The galleryName provides a unique identifier within the resource group. The location determines where gallery metadata is stored. By default, galleries are private to the subscription unless you configure a sharingProfile.
Share gallery images across subscriptions
Teams managing multiple subscriptions often need to share images across organizational boundaries without duplicating storage.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const gallery = new azure_native.compute.Gallery("gallery", {
description: "This is the gallery description.",
galleryName: "myGalleryName",
location: "West US",
resourceGroupName: "myResourceGroup",
sharingProfile: {
permissions: azure_native.compute.GallerySharingPermissionTypes.Groups,
},
});
import pulumi
import pulumi_azure_native as azure_native
gallery = azure_native.compute.Gallery("gallery",
description="This is the gallery description.",
gallery_name="myGalleryName",
location="West US",
resource_group_name="myResourceGroup",
sharing_profile={
"permissions": azure_native.compute.GallerySharingPermissionTypes.GROUPS,
})
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.NewGallery(ctx, "gallery", &compute.GalleryArgs{
Description: pulumi.String("This is the gallery description."),
GalleryName: pulumi.String("myGalleryName"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
SharingProfile: &compute.SharingProfileArgs{
Permissions: pulumi.String(compute.GallerySharingPermissionTypesGroups),
},
})
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 gallery = new AzureNative.Compute.Gallery("gallery", new()
{
Description = "This is the gallery description.",
GalleryName = "myGalleryName",
Location = "West US",
ResourceGroupName = "myResourceGroup",
SharingProfile = new AzureNative.Compute.Inputs.SharingProfileArgs
{
Permissions = AzureNative.Compute.GallerySharingPermissionTypes.Groups,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Gallery;
import com.pulumi.azurenative.compute.GalleryArgs;
import com.pulumi.azurenative.compute.inputs.SharingProfileArgs;
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 gallery = new Gallery("gallery", GalleryArgs.builder()
.description("This is the gallery description.")
.galleryName("myGalleryName")
.location("West US")
.resourceGroupName("myResourceGroup")
.sharingProfile(SharingProfileArgs.builder()
.permissions("Groups")
.build())
.build());
}
}
resources:
gallery:
type: azure-native:compute:Gallery
properties:
description: This is the gallery description.
galleryName: myGalleryName
location: West US
resourceGroupName: myResourceGroup
sharingProfile:
permissions: Groups
The sharingProfile property controls access scope. Setting permissions to “Groups” enables sharing with specific Azure AD groups or subscriptions within your organization. This allows centralized image management while maintaining access control.
Publish images to the Azure community
Organizations that want to share images publicly with the broader Azure community can configure community gallery settings with licensing and contact information.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const gallery = new azure_native.compute.Gallery("gallery", {
description: "This is the gallery description.",
galleryName: "myGalleryName",
location: "West US",
resourceGroupName: "myResourceGroup",
sharingProfile: {
communityGalleryInfo: {
eula: "eula",
publicNamePrefix: "PirPublic",
publisherContact: "pir@microsoft.com",
publisherUri: "uri",
},
permissions: azure_native.compute.GallerySharingPermissionTypes.Community,
},
});
import pulumi
import pulumi_azure_native as azure_native
gallery = azure_native.compute.Gallery("gallery",
description="This is the gallery description.",
gallery_name="myGalleryName",
location="West US",
resource_group_name="myResourceGroup",
sharing_profile={
"community_gallery_info": {
"eula": "eula",
"public_name_prefix": "PirPublic",
"publisher_contact": "pir@microsoft.com",
"publisher_uri": "uri",
},
"permissions": azure_native.compute.GallerySharingPermissionTypes.COMMUNITY,
})
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.NewGallery(ctx, "gallery", &compute.GalleryArgs{
Description: pulumi.String("This is the gallery description."),
GalleryName: pulumi.String("myGalleryName"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
SharingProfile: &compute.SharingProfileArgs{
CommunityGalleryInfo: &compute.CommunityGalleryInfoArgs{
Eula: pulumi.String("eula"),
PublicNamePrefix: pulumi.String("PirPublic"),
PublisherContact: pulumi.String("pir@microsoft.com"),
PublisherUri: pulumi.String("uri"),
},
Permissions: pulumi.String(compute.GallerySharingPermissionTypesCommunity),
},
})
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 gallery = new AzureNative.Compute.Gallery("gallery", new()
{
Description = "This is the gallery description.",
GalleryName = "myGalleryName",
Location = "West US",
ResourceGroupName = "myResourceGroup",
SharingProfile = new AzureNative.Compute.Inputs.SharingProfileArgs
{
CommunityGalleryInfo = new AzureNative.Compute.Inputs.CommunityGalleryInfoArgs
{
Eula = "eula",
PublicNamePrefix = "PirPublic",
PublisherContact = "pir@microsoft.com",
PublisherUri = "uri",
},
Permissions = AzureNative.Compute.GallerySharingPermissionTypes.Community,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Gallery;
import com.pulumi.azurenative.compute.GalleryArgs;
import com.pulumi.azurenative.compute.inputs.SharingProfileArgs;
import com.pulumi.azurenative.compute.inputs.CommunityGalleryInfoArgs;
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 gallery = new Gallery("gallery", GalleryArgs.builder()
.description("This is the gallery description.")
.galleryName("myGalleryName")
.location("West US")
.resourceGroupName("myResourceGroup")
.sharingProfile(SharingProfileArgs.builder()
.communityGalleryInfo(CommunityGalleryInfoArgs.builder()
.eula("eula")
.publicNamePrefix("PirPublic")
.publisherContact("pir@microsoft.com")
.publisherUri("uri")
.build())
.permissions("Community")
.build())
.build());
}
}
resources:
gallery:
type: azure-native:compute:Gallery
properties:
description: This is the gallery description.
galleryName: myGalleryName
location: West US
resourceGroupName: myResourceGroup
sharingProfile:
communityGalleryInfo:
eula: eula
publicNamePrefix: PirPublic
publisherContact: pir@microsoft.com
publisherUri: uri
permissions: Community
Community galleries require additional metadata in the communityGalleryInfo block. The eula property specifies licensing terms, publicNamePrefix creates a discoverable name, and publisherContact provides support information. Setting permissions to “Community” makes the gallery publicly accessible.
Enable soft deletion for accidental removal protection
Production galleries benefit from soft deletion to prevent permanent data loss from accidental deletions or automation errors.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const gallery = new azure_native.compute.Gallery("gallery", {
description: "This is the gallery description.",
galleryName: "myGalleryName",
location: "West US",
resourceGroupName: "myResourceGroup",
softDeletePolicy: {
isSoftDeleteEnabled: true,
},
});
import pulumi
import pulumi_azure_native as azure_native
gallery = azure_native.compute.Gallery("gallery",
description="This is the gallery description.",
gallery_name="myGalleryName",
location="West US",
resource_group_name="myResourceGroup",
soft_delete_policy={
"is_soft_delete_enabled": 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.NewGallery(ctx, "gallery", &compute.GalleryArgs{
Description: pulumi.String("This is the gallery description."),
GalleryName: pulumi.String("myGalleryName"),
Location: pulumi.String("West US"),
ResourceGroupName: pulumi.String("myResourceGroup"),
SoftDeletePolicy: &compute.SoftDeletePolicyArgs{
IsSoftDeleteEnabled: 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 gallery = new AzureNative.Compute.Gallery("gallery", new()
{
Description = "This is the gallery description.",
GalleryName = "myGalleryName",
Location = "West US",
ResourceGroupName = "myResourceGroup",
SoftDeletePolicy = new AzureNative.Compute.Inputs.SoftDeletePolicyArgs
{
IsSoftDeleteEnabled = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Gallery;
import com.pulumi.azurenative.compute.GalleryArgs;
import com.pulumi.azurenative.compute.inputs.SoftDeletePolicyArgs;
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 gallery = new Gallery("gallery", GalleryArgs.builder()
.description("This is the gallery description.")
.galleryName("myGalleryName")
.location("West US")
.resourceGroupName("myResourceGroup")
.softDeletePolicy(SoftDeletePolicyArgs.builder()
.isSoftDeleteEnabled(true)
.build())
.build());
}
}
resources:
gallery:
type: azure-native:compute:Gallery
properties:
description: This is the gallery description.
galleryName: myGalleryName
location: West US
resourceGroupName: myResourceGroup
softDeletePolicy:
isSoftDeleteEnabled: true
The softDeletePolicy property controls deletion behavior. When isSoftDeleteEnabled is true, deleted gallery resources enter a soft-deleted state rather than being permanently removed, allowing recovery within a retention period.
Beyond these examples
These snippets focus on specific gallery-level features: private and shared gallery creation, community publishing with metadata, and soft deletion protection. They’re intentionally minimal rather than full image management solutions.
The examples may reference pre-existing infrastructure such as Azure resource groups and Azure subscriptions. They focus on configuring the gallery rather than provisioning everything around it.
To keep things focused, common gallery patterns are omitted, including:
- Gallery identity configuration (managed identity)
- Resource tagging for organization and cost tracking
- Gallery image definitions and versions (separate resources)
- RBAC permissions for gallery access control
These omissions are intentional: the goal is to illustrate how each gallery feature is wired, not provide drop-in image management modules. See the Gallery resource reference for all available configuration options.
Let's create Azure Shared Image Galleries
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Sharing & Permissions
Community or Groups permissions via the sharingProfile property.sharingProfile.permissions to Community and provide communityGalleryInfo with eula, publicNamePrefix, publisherContact, and publisherUri fields.eula (end-user license agreement), publicNamePrefix (public name for the gallery), publisherContact (contact email), and publisherUri (publisher website).Configuration & Properties
location, galleryName, and resourceGroupName properties are immutable and cannot be changed after creation.description property is updatable and can be changed at any time.softDeletePolicy with isSoftDeleteEnabled set to true to enable soft deletion protection.pulumi package add azure-native compute [ApiVersion].