CloudFormation templates for setting up AWS permissions for the CCA collector.
| Template | Purpose |
|---|---|
| aws-iam-role.yaml | IAM role for single account or management account |
| aws-stackset-member-role.yaml | StackSet template for organization-wide deployment (100+ accounts) |
Deploy the stack in your AWS account:
aws cloudformation create-stack \
--stack-name cca-collector \
--template-body file://setup/aws-iam-role.yaml \
--capabilities CAPABILITY_NAMED_IAMThen run the collector:
python3 aws_collect.pyDeploy with Organizations access enabled:
aws cloudformation create-stack \
--stack-name cca-collector \
--template-body file://setup/aws-iam-role.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters \
ParameterKey=EnableOrganizationsAccess,ParameterValue=trueDeploy to each member account with cross-account trust:
# Get your management account ID
MGMT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
# Deploy to member account (using profile or assumed role)
aws cloudformation create-stack \
--stack-name cca-collector \
--template-body file://setup/aws-iam-role.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters \
ParameterKey=TrustedAccountId,ParameterValue=$MGMT_ACCOUNT \
ParameterKey=ExternalId,ParameterValue=your-secret-external-id# Auto-discover accounts via Organizations
python3 aws_collect.py --org-role CCACollectorRole --external-id your-secret-external-id
# Or specify explicit role ARNs
python3 aws_collect.py --role-arns \
arn:aws:iam::111111111111:role/CCACollectorRole,\
arn:aws:iam::222222222222:role/CCACollectorRole| Parameter | Default | Description |
|---|---|---|
RoleName |
CCACollectorRole |
Name for the IAM role |
ExternalId |
(empty) | External ID for cross-account security |
TrustedAccountId |
(empty) | AWS account ID allowed to assume this role |
TrustedRoleArn |
(empty) | Specific role ARN allowed to assume (more restrictive) |
EnableOrganizationsAccess |
false |
Enable Organizations API access |
EnableCostExplorerAccess |
true |
Enable Cost Explorer API for cost_collect.py |
For organizations with many accounts, use our dedicated StackSet template for simplified deployment.
| Template | Purpose |
|---|---|
| aws-stackset-member-role.yaml | StackSet deployment - Optimized for member accounts |
| aws-iam-role.yaml | Single account or management account with Organizations access |
Deploy to your management account with Organizations access enabled:
aws cloudformation create-stack \
--stack-name cca-collector \
--template-body file://setup/aws-iam-role.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters \
ParameterKey=EnableOrganizationsAccess,ParameterValue=true# Get your management account ID
MGMT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
# Generate a unique external ID (or use your own)
EXTERNAL_ID="cca-$(date +%Y%m%d)-$(openssl rand -hex 4)"
echo "External ID: $EXTERNAL_ID" # Save this!
# Create the StackSet
aws cloudformation create-stack-set \
--stack-set-name cca-collector-roles \
--template-body file://setup/aws-stackset-member-role.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
--parameters \
ParameterKey=TrustedAccountId,ParameterValue=$MGMT_ACCOUNT \
ParameterKey=ExternalId,ParameterValue=$EXTERNAL_ID# Get your organization root ID
ORG_ROOT=$(aws organizations list-roots --query 'Roots[0].Id' --output text)
# Deploy to all accounts in the organization
aws cloudformation create-stack-instances \
--stack-set-name cca-collector-roles \
--deployment-targets OrganizationalUnitIds=$ORG_ROOT \
--regions us-east-1
# Monitor deployment progress
aws cloudformation list-stack-instances \
--stack-set-name cca-collector-roles \
--query 'Summaries[].{Account:Account,Status:Status,Reason:StatusReason}'# Using the unified collector (recommended)
python3 collect.py --cloud aws -- \
--org-role CCACollectorRole \
--external-id $EXTERNAL_ID
# Or directly with aws_collect.py
python3 aws_collect.py \
--org-role CCACollectorRole \
--external-id $EXTERNAL_ID| Parameter | Required | Description |
|---|---|---|
TrustedAccountId |
Yes | Your management account ID (12 digits) |
ExternalId |
Yes | Unique external ID for secure cross-account access |
RoleName |
No | IAM role name (default: CCACollectorRole) |
EnableCostExplorerAccess |
No | Enable Cost Explorer API (default: true) |
For 1000+ accounts, deployment may take 15-30 minutes:
# Check overall status
aws cloudformation describe-stack-set \
--stack-set-name cca-collector-roles \
--query 'StackSet.Status'
# Count by status
aws cloudformation list-stack-instances \
--stack-set-name cca-collector-roles \
--query 'Summaries[].Status' | sort | uniq -c
# View failed deployments
aws cloudformation list-stack-instances \
--stack-set-name cca-collector-roles \
--filters Name=STATUS,Values=FAILED \
--query 'Summaries[].{Account:Account,Reason:StatusReason}'To remove the stack:
aws cloudformation delete-stack --stack-name cca-collectorThe template grants these read-only permissions:
| Service | Permissions |
|---|---|
| EC2 | DescribeRegions, DescribeInstances, DescribeVolumes, DescribeSnapshots |
| RDS | DescribeDBInstances, DescribeDBClusters, DescribeDBSnapshots, DescribeDBClusterSnapshots |
| S3 | ListAllMyBuckets, GetBucketLocation, GetBucketTagging |
| EFS | DescribeFileSystems |
| FSx | DescribeFileSystems |
| EKS | ListClusters, DescribeCluster, ListNodegroups, DescribeNodegroup |
| Lambda | ListFunctions |
| DynamoDB | ListTables, DescribeTable |
| ElastiCache | DescribeCacheClusters |
| AWS Backup | ListBackupVaults, ListRecoveryPointsByBackupVault, ListBackupPlans, GetBackupPlan, ListBackupSelections, GetBackupSelection, ListProtectedResources |
| Organizations | ListAccounts, DescribeOrganization, DescribeAccount (optional) |
| Cost Explorer | GetCostAndUsage, GetCostForecast (optional) |
For the complete policy, see PERMISSIONS.md.