The aws:cloudformation/stackInstances:StackInstances resource, part of the Pulumi AWS provider, deploys CloudFormation stack instances from a StackSet to target accounts and regions. This guide focuses on three capabilities: account-specific targeting, organizational unit deployment, and cross-account IAM configuration.
Stack instances depend on an existing StackSet and require IAM execution roles in each target account. The examples are intentionally small. Combine them with your own StackSet definitions and IAM infrastructure.
Deploy stack instances to specific accounts and regions
Most StackSet deployments target specific AWS accounts and regions where you want identical infrastructure.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.cloudformation.StackInstances("example", {
accounts: [
"123456789012",
"234567890123",
],
regions: [
"us-east-1",
"us-west-2",
],
stackSetName: exampleAwsCloudformationStackSet.name,
});
import pulumi
import pulumi_aws as aws
example = aws.cloudformation.StackInstances("example",
accounts=[
"123456789012",
"234567890123",
],
regions=[
"us-east-1",
"us-west-2",
],
stack_set_name=example_aws_cloudformation_stack_set["name"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudformation"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudformation.NewStackInstances(ctx, "example", &cloudformation.StackInstancesArgs{
Accounts: pulumi.StringArray{
pulumi.String("123456789012"),
pulumi.String("234567890123"),
},
Regions: pulumi.StringArray{
pulumi.String("us-east-1"),
pulumi.String("us-west-2"),
},
StackSetName: pulumi.Any(exampleAwsCloudformationStackSet.Name),
})
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.CloudFormation.StackInstances("example", new()
{
Accounts = new[]
{
"123456789012",
"234567890123",
},
Regions = new[]
{
"us-east-1",
"us-west-2",
},
StackSetName = exampleAwsCloudformationStackSet.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudformation.StackInstances;
import com.pulumi.aws.cloudformation.StackInstancesArgs;
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 StackInstances("example", StackInstancesArgs.builder()
.accounts(
"123456789012",
"234567890123")
.regions(
"us-east-1",
"us-west-2")
.stackSetName(exampleAwsCloudformationStackSet.name())
.build());
}
}
resources:
example:
type: aws:cloudformation:StackInstances
properties:
accounts:
- '123456789012'
- '234567890123'
regions:
- us-east-1
- us-west-2
stackSetName: ${exampleAwsCloudformationStackSet.name}
The accounts property lists AWS account IDs where stack instances will be created. The regions property specifies which regions receive instances in each account. CloudFormation creates one stack instance per account-region pair, deploying the StackSet’s template to all combinations.
Configure execution roles in target accounts
Before StackSets can deploy to target accounts, those accounts need an execution role that trusts the administrator account.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy = aws.iam.getPolicyDocument({
statements: [{
actions: ["sts:AssumeRole"],
effect: "Allow",
principals: [{
identifiers: [aWSCloudFormationStackSetAdministrationRole.arn],
type: "AWS",
}],
}],
});
const aWSCloudFormationStackSetExecutionRole = new aws.iam.Role("AWSCloudFormationStackSetExecutionRole", {
assumeRolePolicy: aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.then(aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy => aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.json),
name: "AWSCloudFormationStackSetExecutionRole",
});
// Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
// Additional IAM permissions necessary depend on the resources defined in the StackSet template
const aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy = aws.iam.getPolicyDocument({
statements: [{
actions: [
"cloudformation:*",
"s3:*",
"sns:*",
],
effect: "Allow",
resources: ["*"],
}],
});
const aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicyRolePolicy = new aws.iam.RolePolicy("AWSCloudFormationStackSetExecutionRole_MinimumExecutionPolicy", {
name: "MinimumExecutionPolicy",
policy: aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.then(aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy => aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.json),
role: aWSCloudFormationStackSetExecutionRole.name,
});
import pulumi
import pulumi_aws as aws
a_ws_cloud_formation_stack_set_execution_role_assume_role_policy = aws.iam.get_policy_document(statements=[{
"actions": ["sts:AssumeRole"],
"effect": "Allow",
"principals": [{
"identifiers": [a_ws_cloud_formation_stack_set_administration_role["arn"]],
"type": "AWS",
}],
}])
a_ws_cloud_formation_stack_set_execution_role = aws.iam.Role("AWSCloudFormationStackSetExecutionRole",
assume_role_policy=a_ws_cloud_formation_stack_set_execution_role_assume_role_policy.json,
name="AWSCloudFormationStackSetExecutionRole")
# Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
# Additional IAM permissions necessary depend on the resources defined in the StackSet template
a_ws_cloud_formation_stack_set_execution_role_minimum_execution_policy = aws.iam.get_policy_document(statements=[{
"actions": [
"cloudformation:*",
"s3:*",
"sns:*",
],
"effect": "Allow",
"resources": ["*"],
}])
a_ws_cloud_formation_stack_set_execution_role_minimum_execution_policy_role_policy = aws.iam.RolePolicy("AWSCloudFormationStackSetExecutionRole_MinimumExecutionPolicy",
name="MinimumExecutionPolicy",
policy=a_ws_cloud_formation_stack_set_execution_role_minimum_execution_policy.json,
role=a_ws_cloud_formation_stack_set_execution_role.name)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Actions: []string{
"sts:AssumeRole",
},
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Identifiers: interface{}{
aWSCloudFormationStackSetAdministrationRole.Arn,
},
Type: "AWS",
},
},
},
},
}, nil);
if err != nil {
return err
}
aWSCloudFormationStackSetExecutionRole, err := iam.NewRole(ctx, "AWSCloudFormationStackSetExecutionRole", &iam.RoleArgs{
AssumeRolePolicy: pulumi.String(aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.Json),
Name: pulumi.String("AWSCloudFormationStackSetExecutionRole"),
})
if err != nil {
return err
}
// Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
// Additional IAM permissions necessary depend on the resources defined in the StackSet template
aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Actions: []string{
"cloudformation:*",
"s3:*",
"sns:*",
},
Effect: pulumi.StringRef("Allow"),
Resources: []string{
"*",
},
},
},
}, nil);
if err != nil {
return err
}
_, err = iam.NewRolePolicy(ctx, "AWSCloudFormationStackSetExecutionRole_MinimumExecutionPolicy", &iam.RolePolicyArgs{
Name: pulumi.String("MinimumExecutionPolicy"),
Policy: pulumi.String(aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.Json),
Role: aWSCloudFormationStackSetExecutionRole.Name,
})
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 aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Actions = new[]
{
"sts:AssumeRole",
},
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Identifiers = new[]
{
aWSCloudFormationStackSetAdministrationRole.Arn,
},
Type = "AWS",
},
},
},
},
});
var aWSCloudFormationStackSetExecutionRole = new Aws.Iam.Role("AWSCloudFormationStackSetExecutionRole", new()
{
AssumeRolePolicy = aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
Name = "AWSCloudFormationStackSetExecutionRole",
});
// Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
// Additional IAM permissions necessary depend on the resources defined in the StackSet template
var aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Actions = new[]
{
"cloudformation:*",
"s3:*",
"sns:*",
},
Effect = "Allow",
Resources = new[]
{
"*",
},
},
},
});
var aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicyRolePolicy = new Aws.Iam.RolePolicy("AWSCloudFormationStackSetExecutionRole_MinimumExecutionPolicy", new()
{
Name = "MinimumExecutionPolicy",
Policy = aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
Role = aWSCloudFormationStackSetExecutionRole.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.iam.RolePolicy;
import com.pulumi.aws.iam.RolePolicyArgs;
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) {
final var aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.actions("sts:AssumeRole")
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.identifiers(aWSCloudFormationStackSetAdministrationRole.arn())
.type("AWS")
.build())
.build())
.build());
var aWSCloudFormationStackSetExecutionRole = new Role("aWSCloudFormationStackSetExecutionRole", RoleArgs.builder()
.assumeRolePolicy(aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.json())
.name("AWSCloudFormationStackSetExecutionRole")
.build());
// Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
// Additional IAM permissions necessary depend on the resources defined in the StackSet template
final var aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.actions(
"cloudformation:*",
"s3:*",
"sns:*")
.effect("Allow")
.resources("*")
.build())
.build());
var aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicyRolePolicy = new RolePolicy("aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicyRolePolicy", RolePolicyArgs.builder()
.name("MinimumExecutionPolicy")
.policy(aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.json())
.role(aWSCloudFormationStackSetExecutionRole.name())
.build());
}
}
resources:
aWSCloudFormationStackSetExecutionRole:
type: aws:iam:Role
name: AWSCloudFormationStackSetExecutionRole
properties:
assumeRolePolicy: ${aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy.json}
name: AWSCloudFormationStackSetExecutionRole
aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicyRolePolicy:
type: aws:iam:RolePolicy
name: AWSCloudFormationStackSetExecutionRole_MinimumExecutionPolicy
properties:
name: MinimumExecutionPolicy
policy: ${aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy.json}
role: ${aWSCloudFormationStackSetExecutionRole.name}
variables:
aWSCloudFormationStackSetExecutionRoleAssumeRolePolicy:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- actions:
- sts:AssumeRole
effect: Allow
principals:
- identifiers:
- ${aWSCloudFormationStackSetAdministrationRole.arn}
type: AWS
# Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html
# Additional IAM permissions necessary depend on the resources defined in the StackSet template
aWSCloudFormationStackSetExecutionRoleMinimumExecutionPolicy:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- actions:
- cloudformation:*
- s3:*
- sns:*
effect: Allow
resources:
- '*'
The execution role’s assumeRolePolicy grants the administrator account’s StackSet role permission to assume it via sts:AssumeRole. The role policy grants CloudFormation permissions to create resources defined in the StackSet template. This role must exist in each target account before stack instances deploy.
Deploy to organizational units automatically
Organizations with many accounts often deploy to entire OUs rather than maintaining explicit account lists.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.cloudformation.StackInstances("example", {
deploymentTargets: {
organizationalUnitIds: [exampleAwsOrganizationsOrganization.roots[0].id],
},
regions: [
"us-west-2",
"us-east-1",
],
stackSetName: exampleAwsCloudformationStackSet.name,
});
import pulumi
import pulumi_aws as aws
example = aws.cloudformation.StackInstances("example",
deployment_targets={
"organizational_unit_ids": [example_aws_organizations_organization["roots"][0]["id"]],
},
regions=[
"us-west-2",
"us-east-1",
],
stack_set_name=example_aws_cloudformation_stack_set["name"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudformation"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudformation.NewStackInstances(ctx, "example", &cloudformation.StackInstancesArgs{
DeploymentTargets: &cloudformation.StackInstancesDeploymentTargetsArgs{
OrganizationalUnitIds: pulumi.StringArray{
exampleAwsOrganizationsOrganization.Roots[0].Id,
},
},
Regions: pulumi.StringArray{
pulumi.String("us-west-2"),
pulumi.String("us-east-1"),
},
StackSetName: pulumi.Any(exampleAwsCloudformationStackSet.Name),
})
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.CloudFormation.StackInstances("example", new()
{
DeploymentTargets = new Aws.CloudFormation.Inputs.StackInstancesDeploymentTargetsArgs
{
OrganizationalUnitIds = new[]
{
exampleAwsOrganizationsOrganization.Roots[0].Id,
},
},
Regions = new[]
{
"us-west-2",
"us-east-1",
},
StackSetName = exampleAwsCloudformationStackSet.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudformation.StackInstances;
import com.pulumi.aws.cloudformation.StackInstancesArgs;
import com.pulumi.aws.cloudformation.inputs.StackInstancesDeploymentTargetsArgs;
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 StackInstances("example", StackInstancesArgs.builder()
.deploymentTargets(StackInstancesDeploymentTargetsArgs.builder()
.organizationalUnitIds(exampleAwsOrganizationsOrganization.roots()[0].id())
.build())
.regions(
"us-west-2",
"us-east-1")
.stackSetName(exampleAwsCloudformationStackSet.name())
.build());
}
}
resources:
example:
type: aws:cloudformation:StackInstances
properties:
deploymentTargets:
organizationalUnitIds:
- ${exampleAwsOrganizationsOrganization.roots[0].id}
regions:
- us-west-2
- us-east-1
stackSetName: ${exampleAwsCloudformationStackSet.name}
The deploymentTargets property replaces the accounts list with organizationalUnitIds, targeting all accounts in those OUs. New accounts added to the OU automatically receive stack instances. StackSets never deploy to the organization management account, even if it’s in the targeted OU.
Beyond these examples
These snippets focus on specific stack instance features: account-specific and OU-based targeting, and cross-account IAM trust configuration. They’re intentionally minimal rather than full multi-account deployment solutions.
The examples reference pre-existing infrastructure such as CloudFormation StackSets, AWS Organizations structure for OU deployments, and IAM administration roles in the source account. They focus on deploying stack instances rather than creating the StackSet or organization structure.
To keep things focused, common stack instance patterns are omitted, including:
- Parameter overrides per instance (parameterOverrides)
- Operation preferences for deployment control (operationPreferences)
- Stack retention on deletion (retainStacks)
- Delegated administrator mode (callAs)
These omissions are intentional: the goal is to illustrate how stack instance deployment is wired, not provide drop-in multi-account modules. See the CloudFormation StackInstances resource reference for all available configuration options.
Let's deploy AWS CloudFormation Stack Instances
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Deployment Targets & Scope
accounts to target specific AWS account IDs, or deploymentTargets to target organizational units. You can’t use both in the same configuration.accounts property with its account ID.accounts property and list the desired regions. For example: accounts: ["123456789012", "234567890123"] and regions: ["us-east-1", "us-west-2"].deploymentTargets with organizationalUnitIds pointing to your organization’s root or specific OUs, instead of listing individual accounts.IAM & Permissions
AWSCloudFormationStackSetExecutionRole with permissions for CloudFormation, S3, SNS, and any resources defined in your stack set template. The role must trust the administrator account’s role.SELF (default) when acting as an account administrator in the organization’s management account, or DELEGATED_ADMIN when acting as a delegated administrator in a member account.Drift Detection & State Management
deploymentTargets configuration, and for parameterOverrides it only works for the first account and region.retainStacks = true and apply it successfully before running the destroy operation. You can’t reassociate retained stacks or add them to a new stack set later.Configuration & Immutability
stackSetName is immutable and can’t be changed after creation. You’ll need to create new stack instances with a different stack set.Using a different cloud?
Explore integration guides for other cloud providers: