Automating Arpio StackSets Adoption at Scale
This guide describes how to automate StackSets deployment using the Arpio API and AWS CloudFormation CLI.
The docs here illustrate how to Deploy Access with AWS StackSets through the Arpio console.
Jump to:
- Prerequisities
- Management Account Toplogy
- Summary
- Variables
- Step 1 - Create Administration Role
- Step 2 - Create Execution Roles
- Step 3 - Create an Arpio Application
- Step 4 - Fetch Access Templates
- Step 5 - Create Primary and Recovery StackSets
- Step 6 - Create Stack Instances
- Automating Template Updates
Prerequisites
- StackSets capability enabled on your Arpio tenant (contact Arpio support)
- StackSets is enabled as a capability on your Arpio tenant—there is no per-app flag. The backend detects StackSet management by reading the ArpioStackSet tag from the deployed Stack and exposes this information to the Arpio UI and API.
- Arpio API credentials with appropriate permissions
Management Account Topology
Before you begin, decide which topology matches your AWS setup:
- Single management account: one AWS management account owns both the Primary and the RecoveryStackSets. Use this if the same account administers deployments into your primary-region member accounts and your recovery-region member accounts.
- Separate management accounts (recommended): two AWS management accounts, one owning each StackSet. Use this if your Primary-side member accounts are administered from one account and your Recovery-side member accounts from another (common in larger AWS Organizations).
In the steps below, PRIMARY_MANAGEMENT_ACCOUNT_ID and RECOVERY_MANAGEMENT_ACCOUNT_ID may be the same value (single-management-account topology) or different values (separate management accounts).
"Member account" refers to the AWS account where a StackSet deploys a stack instance: your primary-region or recovery-region AWS account. We use "member" rather than "target" to avoid confusion with Arpio's "target endpoint" terminology, which refers to the recovery side of a sync pair.
Summary
|
Step |
Frequency |
Where |
|---|---|---|
|
1. Create Administration Role |
Once per management account |
Each management account in AWS |
|
2. Create Execution Roles |
Once per member account |
Each primary/recovery member account in AWS |
|
3. Create Arpio Application |
Per app |
Arpio API |
|
4. Fetch Access Templates |
Per app |
Arpio API |
|
5. Create StackSets |
Once per management account (skip per side if exists) |
Primary management account (Primary StackSet) in AWS / Recovery management account (Recovery StackSet) in AWS |
|
6. Create Stack Instances |
Per app (2 calls) |
Primary management account in AWS / Recovery management account in AWS |
Variables
Replace these placeholders throughout the guide:
|
Placeholder |
Description |
|---|---|
|
|
AWS account ID of the management account that owns the Primary StackSet |
|
|
AWS account ID of the management account that owns the Recovery StackSet (same as PRIMARY_MANAGEMENT_ACCOUNT_ID in the single-management-account topology) |
|
|
AWS account ID of your primary (source) member account |
|
|
AWS account ID of your recovery member account |
|
|
e.g. us-east-1 |
|
|
e.g. us-west-2 |
|
|
StackSet name for primary access, e.g. ArpioPrimaryAccess |
|
|
StackSet name for recovery access, e.g. ArpioRecoveryAccess |
|
|
Your Arpio account ID |
|
|
Your Arpio API bearer token |
Step 1 — Create Administration Role (once per management account)
Run the command below in your Primary management account. If you use separate management accounts for Primary and Recovery, run it again in your Recovery management account.
aws cloudformation create-stack \
--stack-name ArpioStackSetAdministrationRole \
--capabilities CAPABILITY_NAMED_IAM \
--template-body file://admin-role.yml
Save the following as admin-role.yml:
AWSTemplateFormatVersion: '2010-09-09'
Description: StackSet Administration Role for Arpio
Parameters:
ExecutionRoleName:
Type: String
Default: ArpioStackSetExecutionRole
Resources:
AdministrationRole:
Type: AWS::IAM::Role
Properties:
RoleName: ArpioStackSetAdministrationRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: AssumeExecutionRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: !Sub 'arn:aws:iam::*:role/${ExecutionRoleName}'
Wait for completion:
aws cloudformation wait stack-create-complete \
--stack-name ArpioStackSetAdministrationRole
Step 2 — Create Execution Roles (once per member account)
Run in each AWS account that participates as a primary or recovery member.
The Execution Role's trust policy must point at the management account that owns the StackSet for that side:
- A Primary member account's Execution Role must trust the Primary management account.
- A Recovery member account's Execution Role must trust the Recovery management account.
In the single-management-account topology, both sides tryst the same account.
Option A: Deploy via CloudFormation CLI
Run this command from the member account (or use cross-account role assumption). Set AdministrationAccountId to the management account ID for the side this member belongs to:
aws cloudformation create-stack \
--stack-name ArpioStackSetExecutionRole \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=AdministrationAccountId,ParameterValue=PRIMARY_MANAGEMENT_ACCOUNT_ID \
--template-body file://execution-role.yml
# For a Recovery member account, replace PRIMARY_MANAGEMENT_ACCOUNT_ID with RECOVERY_MANAGEMENT_ACCOUNT_ID.
Save the following as execution-role.yml:
AWSTemplateFormatVersion: '2010-09-09'
Description: StackSet Execution Role for Arpio
Parameters:
AdministrationAccountId:
Type: String
Description: AWS Account ID of the Administration Account
AdministrationRoleName:
Type: String
Default: ArpioStackSetAdministrationRole
Resources:
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: ArpioStackSetExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AdministrationAccountId}:role/${AdministrationRoleName}'
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
Wait for completion:
aws cloudformation wait stack-create-complete \
--stack-name ArpioStackSetExecutionRole
Option B: Deploy via CloudShell in Target Account
The Arpio console provides a ready-to-run command. Copy it from the UI and paste into CloudShell:
# From Arpio Console: App Settings > AWS Access > Step 1b
# Copy the provided command and run in CloudShell
aws cloudformation create-stack \
--stack-name ArpioStackSetExecutionRole \
--template-url <url-from-arpio-console> \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=AdministrationAccountId,ParameterValue=<mgmt-acct-id>
Option C: Batch Deployment via Automation
For bulk onboarding of multiple accounts, you can script the deployment using cross-account role assumption:
This will require the API key created earlier
#!/bin/bash
# deploy_execution_roles.sh
# Deploys Execution Role to multiple member accounts.
# Primary members trust the Primary management account.
# Recovery members trust the Recovery management account.
PRIMARY_MGMT_ACCOUNT_ID="123456789012"
RECOVERY_MGMT_ACCOUNT_ID="123456789012" # same as primary if single-management-account topology
PRIMARY_MEMBER_ACCOUNTS=("111111111111" "222222222222")
RECOVERY_MEMBER_ACCOUNTS=("333333333333" "444444444444")
CROSS_ACCOUNT_ROLE="OrganizationAccountAccessRole" # or your role name
TEMPLATE_URL="https://arpio-cloudformation-templates.s3.amazonaws.com/stacksets/ArpioStackSetExecutionRole.yml"
deploy_for_side() {
local ADMIN_ACCT_ID=$1
shift
local ACCOUNTS=("$@")
for ACCOUNT_ID in "${ACCOUNTS[@]}"; do
echo "Deploying to member account: $ACCOUNT_ID (trusting $ADMIN_ACCT_ID)"
CREDS=$(aws sts assume-role \
--role-arn arn:aws:iam::${ACCOUNT_ID}:role/${CROSS_ACCOUNT_ROLE} \
--role-session-name ArpioExecRoleDeploy \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text)
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | awk '{print $1}')
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | awk '{print $2}')
export AWS_SESSION_TOKEN=$(echo "$CREDS" | awk '{print $3}')
aws cloudformation create-stack \
--stack-name ArpioStackSetExecutionRole \
--template-url "$TEMPLATE_URL" \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=AdministrationAccountId,ParameterValue=$ADMIN_ACCT_ID
aws cloudformation wait stack-create-complete \
--stack-name ArpioStackSetExecutionRole
echo "Completed: $ACCOUNT_ID"
done
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
}
deploy_for_side "$PRIMARY_MGMT_ACCOUNT_ID" "${PRIMARY_MEMBER_ACCOUNTS[@]}"
deploy_for_side "$RECOVERY_MGMT_ACCOUNT_ID" "${RECOVERY_MEMBER_ACCOUNTS[@]}"
Verify Execution Role Deployment
Confirm the role exists in the target account:
# Verify the role was created (run in target account)
aws iam get-role --role-name ArpioStackSetExecutionRole
# Check the trust policy allows the Administration Role
aws iam get-role --role-name ArpioStackSetExecutionRole \
--query 'Role.AssumeRolePolicyDocument'
Expected trust:
-
In a Primary member account the Principal.AWS should be
arn:aws:iam::PRIMARY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole. -
In a Recovery member account the Principal.AWS should be
arn:aws:iam::RECOVERY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole.
Step 3 — Create an Arpio Application (per app)
curl -X POST "https://app.arpio.io/api/accounts/ARPIO_ACCOUNT_ID/applications" \
-H "X-Api-Key: <apiKeyID>:<secret>" \
-H "Content-Type: application/json" \
-d '{
"accountId": "ARPIO_ACCOUNT_ID",
"name": "APP_NAME",
"type": "aws",
"rpo": RPO_SECONDS,
"notificationEmails": ["team@example.com"],
"sourceEndpointUri": "aws:PRIMARY_ACCOUNT_ID:PRIMARY_REGION",
"targetEndpointUri": "aws:RECOVERY_ACCOUNT_ID:RECOVERY_REGION",
"selectionRules": [
{ "type": "tag", "tagKey": "TAG_KEY", "tagValue": "TAG_VALUE" }
],
"syncPhase": "STANDBY"
}'
Save the appId from the response.
Step 4 — Fetch Access Templates (per app)
Template S3 URLs are stable and remain constant even when Arpio releases updates. The template content is refreshed in place at the same URL. This means you can store the URL in your automation scripts and CI/CD pipelines without needing to re-query for each update.
curl -s "https://app.arpio.io/api/accounts/ARPIO_ACCOUNT_ID/syncPairs/aws:PRIMARY_ACCOUNT_ID:PRIMARY_REGION/aws:RECOVERY_ACCOUNT_ID:RECOVERY_REGION/accessTemplates" \
-H "X-Api-Key: <apiKeyID>:<secret>"
From the response, extract these fields:
|
Response field |
Use in |
|---|---|
|
|
Step 5 — |
|
|
Step 5 — |
|
|
Step 6 — |
|
|
Step 6 — |
|
|
Step 6 — |
|
|
Step 6 — |
Step 5 — Create Two StackSets (once per management account — skip per side if exists)
This step only needs to run once per management account. If you already have the StackSet that owns access for a given side, skip that side and go to Step 6.
PRIMARY_STACKSET_NAME and RECOVERY_STACKSET_NAME default to ArpioPrimaryAccess and ArpioRecoveryAccess. Choose your own names if you prefer, just be consistent across steps.
Create Primary Access StackSet:
# Location: Primary management account in AWS.
aws cloudformation create-stack-set \
--stack-set-name PRIMARY_STACKSET_NAME \
--template-url SOURCE_STACKSET_TEMPLATE_URL \
--permission-model SELF_MANAGED \
--administration-role-arn arn:aws:iam::PRIMARY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole \
--execution-role-name ArpioStackSetExecutionRole \
--capabilities CAPABILITY_NAMED_IAM
Create Recovery Access StackSet:
# Location: Recovery management account in AWS.
aws cloudformation create-stack-set \
--stack-set-name RECOVERY_STACKSET_NAME \
--template-url TARGET_STACKSET_TEMPLATE_URL \
--permission-model SELF_MANAGED \
--administration-role-arn arn:aws:iam::RECOVERY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole \
--execution-role-name ArpioStackSetExecutionRole \
--capabilities CAPABILITY_NAMED_IAM
If you use a single management account, PRIMARY_MANAGEMENT_ACCOUNT_ID and RECOVERY_MANAGEMENT_ACCOUNT_ID are the same value, and both commands run from that same account.
Step 6 — Create Stack Instances (per app)
Run each command from its matching management account:
Primary Access — deploys into the primary member account/region:
aws cloudformation create-stack-instances \
--stack-set-name PRIMARY_STACKSET_NAME \
--accounts PRIMARY_ACCOUNT_ID \
--regions PRIMARY_REGION \
--parameter-overrides \
ParameterKey=SourceAwsAccountId,ParameterValue=PRIMARY_ACCOUNT_ID \
ParameterKey=SourceRegion,ParameterValue=PRIMARY_REGION \
ParameterKey=TargetAwsAccountId,ParameterValue=RECOVERY_ACCOUNT_ID \
ParameterKey=TargetRegion,ParameterValue=RECOVERY_REGION \
ParameterKey=TemplateS3Bucket,ParameterValue=SOURCE_TEMPLATE_BUCKET \
ParameterKey=TemplateS3Key,ParameterValue=SOURCE_TEMPLATE_KEY
Recovery Access — deploys into the member recovery account/region:
Location: Recovery management account in AWS.
aws cloudformation create-stack-instances \
--stack-set-name RECOVERY_STACKSET_NAME \
--accounts RECOVERY_ACCOUNT_ID \
--regions RECOVERY_REGION \
--parameter-overrides \
ParameterKey=SourceAwsAccountId,ParameterValue=PRIMARY_ACCOUNT_ID \
ParameterKey=SourceRegion,ParameterValue=PRIMARY_REGION \
ParameterKey=TargetAwsAccountId,ParameterValue=RECOVERY_ACCOUNT_ID \
ParameterKey=TargetRegion,ParameterValue=RECOVERY_REGION \
ParameterKey=TemplateS3Bucket,ParameterValue=TARGET_TEMPLATE_BUCKET \
ParameterKey=TemplateS3Key,ParameterValue=TARGET_TEMPLATE_KEY
Automating Template Updates
Key Benefit: Single Command Updates
When Arpio releases new template versions, you can automate the update process by comparing template versions and running update-stack-set.
Running update-stack-set once per StackSet automatically propagates the update to ALL stack instances. For 50 applications, you run 2 commands instead of 100.
Compare Current vs. Latest Template Version
Query the application to get the current templateVersion:
# Get current template version
curl -X GET "https://api.arpio.io/api/accounts/{account_id}/applications/{app_id}" \
-H "X-Api-Key: <apiKeyID>:<secret>"
# Parse the templateVersion field from the response
Query the access templates endpoint to get the latest template version:
# Get latest template version from accessTemplates endpoint
curl -X GET "https://api.arpio.io/api/accounts/{account_id}/syncPairs/\
{src_account}/{src_region}/{tgt_account}/{tgt_region}/accessTemplates" \
-H "X-Api-Key: <apiKeyID>:<secret>"
# Compare templateVersion with current application version
Apply Updates
If versions differ, run update-stack-set on each StackSet from its matching management account:
# Update Primary StackSet (run from Primary management account; propagates to ALL primary stack instances)
aws cloudformation update-stack-set \
--stack-set-name PRIMARY_STACKSET_NAME \
--template-url {sourceStackSetTemplateS3Url} \
--administration-role-arn arn:aws:iam::PRIMARY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole \
--capabilities CAPABILITY_NAMED_IAM
# Update Recovery StackSet (run from Recovery management account; propagates to ALL recovery stack instances)
aws cloudformation update-stack-set \
--stack-set-name RECOVERY_STACKSET_NAME \
--template-url {targetStackSetTemplateS3Url} \
--administration-role-arn arn:aws:iam::RECOVERY_MANAGEMENT_ACCOUNT_ID:role/ArpioStackSetAdministrationRole \
--capabilities CAPABILITY_NAMED_IAM
Verify Update Success
After running the update, verify success using one of these methods:
- Check templateVersion: Query the application API and verify the templateVersion field matches the expected version.
- Check Sync Access: Call the access endpoint to confirm Arpio can reach the sync endpoint.
# Verify access after update
curl -X GET "https://api.arpio.io/api/accounts/{account_id}/syncPairs/\
{src_account}/{src_region}/{tgt_account}/{tgt_region}/access" \
-H "X-Api-Key: <apiKeyID>:<secret>"