2025-10-23
One thing we are often asked is how to automate provisioning for new accounts, groups and users, under a partner’s Organization.
There are lots of ways to do this, but we’ve automated it ;-) and here’s how.
Given an existing AWS account within an Organization and with an operational IAM Identity Center instance in the Organization and Region:
*-workload-admin-group*-workload-adminNow to do this you need a few prerequisites like:
aws login.aws sso-admin, ie something like Admin Access for the user who is running the script.Here’s the full script.
Rename it something like setup-customer-aws.sh and run it with bash (works on Linux or Mac, or even Windows Subsystem for Linux).
Assumes you have aws-cli installed and can login with the appropriate permissions
Run it with:
bash setup-customer-aws.sh --slug SLUG --awsacct 1234567890 --email name@customer.com --region us-east-1
Replace the slug, AWS account, email address and region as appropriate.
#!/usr/bin/env bash
set -euo pipefail
# ── Parse named parameters ───────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
case "$1" in
--slug) SLUG="$2"; shift 2 ;;
--awsacct) AWSACCT="$2"; shift 2 ;;
--email) EMAIL="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
*) echo "Unknown parameter: $1"; exit 1 ;;
esac
done
# ── Validate all required params present ────────────────────────────────────
for var in SLUG AWSACCT EMAIL REGION; do
[ -z "${!var:-}" ] && { echo "Missing required parameter: --${var,,}"; exit 1; }
done
# ── Discover SSO instance ────────────────────────────────────────────────────
echo "Looking up IAM Identity Center instance in $REGION..."
INSTANCE_DATA=$(aws sso-admin list-instances --region "$REGION" --query 'Instances[0]' --output json)
INSTANCE_ARN=$(echo "$INSTANCE_DATA" | python3 -c "import sys,json; print(json.load(sys.stdin)['InstanceArn'])")
IDENTITY_STORE_ID=$(echo "$INSTANCE_DATA" | python3 -c "import sys,json; print(json.load(sys.stdin)['IdentityStoreId'])")
echo "Instance ARN: $INSTANCE_ARN"
echo "Identity Store ID: $IDENTITY_STORE_ID"
GROUP_NAME="${SLUG}-workload-group"
USER_NAME="${SLUG}-workload-admin"
# ── 1. Create group ──────────────────────────────────────────────────────────
echo "Creating group: $GROUP_NAME..."
GROUP_ID=$(aws identitystore create-group \
--identity-store-id "$IDENTITY_STORE_ID" \
--display-name "$GROUP_NAME" \
--region "$REGION" \
--query 'GroupId' --output text)
echo "Created group: $GROUP_NAME ($GROUP_ID)"
# ── 2. Find AdministratorAccess permission set ───────────────────────────────
echo "Looking up AdministratorAccess permission set..."
PERMISSION_SET_ARN=""
NEXT_TOKEN=""
while true; do
if [ -z "$NEXT_TOKEN" ]; then
PAGE=$(aws sso-admin list-permission-sets \
--instance-arn "$INSTANCE_ARN" \
--region "$REGION" \
--output json)
else
PAGE=$(aws sso-admin list-permission-sets \
--instance-arn "$INSTANCE_ARN" \
--region "$REGION" \
--next-token "$NEXT_TOKEN" \
--output json)
fi
for PSA in $(echo "$PAGE" | python3 -c "import sys,json; [print(p) for p in json.load(sys.stdin)['PermissionSets']]"); do
NAME=$(aws sso-admin describe-permission-set \
--instance-arn "$INSTANCE_ARN" \
--permission-set-arn "$PSA" \
--region "$REGION" \
--query 'PermissionSet.Name' --output text)
if [ "$NAME" = "AdministratorAccess" ]; then
PERMISSION_SET_ARN="$PSA"
break 2
fi
done
NEXT_TOKEN=$(echo "$PAGE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('NextToken',''))")
[ -z "$NEXT_TOKEN" ] && break
done
[ -z "$PERMISSION_SET_ARN" ] && { echo "AdministratorAccess permission set not found"; exit 1; }
echo "AdministratorAccess ARN: $PERMISSION_SET_ARN"
# ── 3. Assign group to account with AdministratorAccess (async + poll) ───────
echo "Assigning $GROUP_NAME to account $AWSACCT..."
ASSIGNMENT_REQUEST_ID=$(aws sso-admin create-account-assignment \
--instance-arn "$INSTANCE_ARN" \
--target-id "$AWSACCT" \
--target-type AWS_ACCOUNT \
--permission-set-arn "$PERMISSION_SET_ARN" \
--principal-type GROUP \
--principal-id "$GROUP_ID" \
--region "$REGION" \
--query 'AccountAssignmentCreationStatus.RequestId' --output text)
echo "Waiting for account existence confirmation (request: $ASSIGNMENT_REQUEST_ID)..."
while true; do
STATUS=$(aws sso-admin describe-account-assignment-creation-status \
--instance-arn "$INSTANCE_ARN" \
--account-assignment-creation-request-id "$ASSIGNMENT_REQUEST_ID" \
--region "$REGION" \
--query 'AccountAssignmentCreationStatus.Status' --output text)
echo " Status: $STATUS"
case "$STATUS" in
SUCCEEDED) echo "Account confirmed to exist."; break ;;
FAILED)
REASON=$(aws sso-admin describe-account-assignment-creation-status \
--instance-arn "$INSTANCE_ARN" \
--account-assignment-creation-request-id "$ASSIGNMENT_REQUEST_ID" \
--region "$REGION" \
--query 'AccountAssignmentCreationStatus.FailureReason' --output text)
echo "Account existence check FAILED: $REASON"; exit 1 ;;
*) sleep 10 ;;
esac
done
# ── 4. Create user ───────────────────────────────────────────────────────────
echo "Creating user: $USER_NAME..."
USER_ID=$(aws identitystore create-user \
--identity-store-id "$IDENTITY_STORE_ID" \
--user-name "$USER_NAME" \
--display-name "$USER_NAME" \
--emails "Value=${EMAIL},Type=work,Primary=true" \
--name "GivenName=${SLUG},FamilyName=Workload Admin" \
--region "$REGION" \
--query 'UserId' --output text)
echo "Created user: $USER_NAME ($USER_ID)"
# ── 5. Add user to group ─────────────────────────────────────────────────────
echo "Adding $USER_NAME to $GROUP_NAME..."
aws identitystore create-group-membership \
--identity-store-id "$IDENTITY_STORE_ID" \
--group-id "$GROUP_ID" \
--member-id "UserId=${USER_ID}" \
--region "$REGION"
echo ""
echo "Done. $USER_NAME is now a member of $GROUP_NAME, which is assigned AdministratorAccess via permissions on account $AWSACCT."
While automation is good, there are a couple of assumptions worth noting:
There’s lots of ways to do basic account provisioning for AWS for a new account ranging from DIY in the Console through to using various forms of automation. This is one simple example, which at least keeps things pretty organized in the absence of an overlay like Control Tower.