Get the FREE Ultimate OpenClaw Setup Guide →

aws-account-management

Scanned
npx machina-cli add skill Makiya1202/ai-agents-skills/aws-account-management --openclaw
Files (1)
SKILL.md
13.7 KB

AWS Account Management

Manage AWS accounts, organizations, IAM, and billing effectively.

AWS Organizations

Organization Structure

Root
├── Production OU
│   ├── Prod Account A
│   └── Prod Account B
├── Development OU
│   ├── Dev Account
│   └── Staging Account
├── Security OU
│   ├── Security Account
│   └── Log Archive Account
└── Sandbox OU
    └── Sandbox Account

Create Organization

# Create organization (from management account)
aws organizations create-organization --feature-set ALL

# Create organizational unit
aws organizations create-organizational-unit \
  --parent-id r-xxxx \
  --name "Production"

# Create member account
aws organizations create-account \
  --email prod-aws@company.com \
  --account-name "Production Account"

# Move account to OU
aws organizations move-account \
  --account-id 123456789012 \
  --source-parent-id r-xxxx \
  --destination-parent-id ou-xxxx-xxxxxxxx

Service Control Policies (SCPs)

// Deny leaving organization
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyLeaveOrg",
      "Effect": "Deny",
      "Action": "organizations:LeaveOrganization",
      "Resource": "*"
    }
  ]
}

// Require IMDSv2 (instance metadata)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RequireIMDSv2",
      "Effect": "Deny",
      "Action": "ec2:RunInstances",
      "Resource": "arn:aws:ec2:*:*:instance/*",
      "Condition": {
        "StringNotEquals": {
          "ec2:MetadataHttpTokens": "required"
        }
      }
    }
  ]
}

// Region restriction
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyNonApprovedRegions",
      "Effect": "Deny",
      "NotAction": [
        "iam:*",
        "organizations:*",
        "support:*",
        "budgets:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": ["us-east-1", "us-west-2", "eu-west-1"]
        }
      }
    }
  ]
}

// Prevent root user access
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyRootUser",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:PrincipalArn": "arn:aws:iam::*:root"
        }
      }
    }
  ]
}

Attach SCP

# Create SCP
aws organizations create-policy \
  --name "DenyLeaveOrg" \
  --type SERVICE_CONTROL_POLICY \
  --content file://deny-leave-org.json

# Attach to OU
aws organizations attach-policy \
  --policy-id p-xxxxxxxxxxxx \
  --target-id ou-xxxx-xxxxxxxx

IAM Identity Center (AWS SSO)

Setup Identity Center

# Enable Identity Center
aws sso-admin create-instance

# Create permission set
aws sso-admin create-permission-set \
  --instance-arn arn:aws:sso:::instance/ssoins-xxxxxxxx \
  --name "AdministratorAccess" \
  --session-duration "PT8H"

# Attach managed policy
aws sso-admin attach-managed-policy-to-permission-set \
  --instance-arn arn:aws:sso:::instance/ssoins-xxxxxxxx \
  --permission-set-arn arn:aws:sso:::permissionSet/ssoins-xxxxxxxx/ps-xxxxxxxx \
  --managed-policy-arn arn:aws:iam::aws:policy/AdministratorAccess

Permission Sets

// Developer permission set (inline policy)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DeveloperAccess",
      "Effect": "Allow",
      "Action": [
        "ec2:*",
        "s3:*",
        "lambda:*",
        "dynamodb:*",
        "cloudwatch:*",
        "logs:*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenyBillingAndIAM",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:DeleteUser",
        "iam:CreateAccessKey",
        "aws-portal:*",
        "budgets:*"
      ],
      "Resource": "*"
    }
  ]
}

IAM Best Practices

IAM Policies

// Least privilege policy example
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3BucketAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "private"
        }
      }
    },
    {
      "Sid": "AllowListBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::my-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": ["${aws:username}/*"]
        }
      }
    }
  ]
}

// Cross-account role trust policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-external-id"
        },
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

IAM Roles for Services

// Lambda execution role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

// EC2 instance profile
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

IAM Security Tools

# Generate credential report
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content | base64 -d

# List unused access keys (last used > 90 days)
aws iam list-users --query 'Users[*].UserName' --output text | \
  xargs -I {} aws iam list-access-keys --user-name {} \
    --query 'AccessKeyMetadata[?Status==`Active`]'

# Get access key last used
aws iam get-access-key-last-used --access-key-id AKIAXXXXXXXX

# IAM Access Analyzer
aws accessanalyzer create-analyzer \
  --analyzer-name my-analyzer \
  --type ACCOUNT

Cost Management

AWS Budgets

# Create budget
aws budgets create-budget \
  --account-id 123456789012 \
  --budget '{
    "BudgetName": "Monthly-Budget",
    "BudgetLimit": {
      "Amount": "1000",
      "Unit": "USD"
    },
    "BudgetType": "COST",
    "TimeUnit": "MONTHLY"
  }' \
  --notifications-with-subscribers '[
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80
      },
      "Subscribers": [
        {
          "SubscriptionType": "EMAIL",
          "Address": "alerts@company.com"
        }
      ]
    }
  ]'

Cost Explorer API

import boto3
from datetime import datetime, timedelta

client = boto3.client('ce')

# Get cost and usage
response = client.get_cost_and_usage(
    TimePeriod={
        'Start': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),
        'End': datetime.now().strftime('%Y-%m-%d')
    },
    Granularity='MONTHLY',
    Metrics=['UnblendedCost'],
    GroupBy=[
        {'Type': 'DIMENSION', 'Key': 'SERVICE'},
        {'Type': 'DIMENSION', 'Key': 'LINKED_ACCOUNT'}
    ]
)

# Get cost forecast
forecast = client.get_cost_forecast(
    TimePeriod={
        'Start': datetime.now().strftime('%Y-%m-%d'),
        'End': (datetime.now() + timedelta(days=30)).strftime('%Y-%m-%d')
    },
    Metric='UNBLENDED_COST',
    Granularity='MONTHLY'
)

print(f"Forecasted cost: ${forecast['Total']['Amount']}")

Cost Allocation Tags

# Activate cost allocation tags
aws ce update-cost-allocation-tags-status \
  --cost-allocation-tags-status '[
    {"TagKey": "Environment", "Status": "Active"},
    {"TagKey": "Project", "Status": "Active"},
    {"TagKey": "CostCenter", "Status": "Active"}
  ]'

# Tag resources consistently
aws ec2 create-tags \
  --resources i-1234567890abcdef0 \
  --tags Key=Environment,Value=Production \
         Key=Project,Value=WebApp \
         Key=CostCenter,Value=Engineering

Savings Plans & Reserved Instances

# Get Savings Plans recommendations
aws savingsplans describe-savings-plans-offering-rates \
  --savings-plan-offering-ids xxxxxxxxx

# Get Reserved Instance recommendations
aws ce get-reservation-purchase-recommendation \
  --service "Amazon Elastic Compute Cloud - Compute" \
  --lookback-period-in-days THIRTY_DAYS \
  --term-in-years ONE_YEAR \
  --payment-option NO_UPFRONT

CloudTrail & Logging

Organization Trail

# Create organization trail
aws cloudtrail create-trail \
  --name organization-trail \
  --s3-bucket-name my-cloudtrail-bucket \
  --is-organization-trail \
  --is-multi-region-trail \
  --enable-log-file-validation \
  --kms-key-id alias/cloudtrail-key

# Start logging
aws cloudtrail start-logging --name organization-trail

CloudTrail Event Selectors

# Log management events and S3 data events
aws cloudtrail put-event-selectors \
  --trail-name organization-trail \
  --event-selectors '[
    {
      "ReadWriteType": "All",
      "IncludeManagementEvents": true,
      "DataResources": [
        {
          "Type": "AWS::S3::Object",
          "Values": ["arn:aws:s3:::sensitive-bucket/"]
        }
      ]
    }
  ]'

Config & Compliance

AWS Config Rules

# Enable Config
aws configservice put-configuration-recorder \
  --configuration-recorder name=default,roleARN=arn:aws:iam::123456789012:role/config-role

# Deploy managed rule
aws configservice put-config-rule \
  --config-rule '{
    "ConfigRuleName": "s3-bucket-public-read-prohibited",
    "Source": {
      "Owner": "AWS",
      "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
    }
  }'

# Organization Config rules
aws configservice put-organization-config-rule \
  --organization-config-rule-name "org-s3-bucket-public-read-prohibited" \
  --organization-managed-rule-metadata '{
    "RuleIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
  }'

Conformance Packs

# conformance-pack.yaml
Parameters:
  S3BucketName:
    Type: String
Resources:
  S3BucketPublicReadProhibited:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-public-read-prohibited
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
  IAMRootAccessKeyCheck:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-root-access-key-check
      Source:
        Owner: AWS
        SourceIdentifier: IAM_ROOT_ACCESS_KEY_CHECK
  MFAEnabledForIAMConsoleAccess:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: mfa-enabled-for-iam-console-access
      Source:
        Owner: AWS
        SourceIdentifier: MFA_ENABLED_FOR_IAM_CONSOLE_ACCESS

Terraform Multi-Account

# providers.tf
provider "aws" {
  alias  = "management"
  region = "us-east-1"
}

provider "aws" {
  alias  = "production"
  region = "us-east-1"
  assume_role {
    role_arn = "arn:aws:iam::${var.prod_account_id}:role/TerraformRole"
  }
}

provider "aws" {
  alias  = "development"
  region = "us-east-1"
  assume_role {
    role_arn = "arn:aws:iam::${var.dev_account_id}:role/TerraformRole"
  }
}

# Create resources in specific accounts
resource "aws_s3_bucket" "prod_bucket" {
  provider = aws.production
  bucket   = "my-prod-bucket"
}

resource "aws_s3_bucket" "dev_bucket" {
  provider = aws.development
  bucket   = "my-dev-bucket"
}

Account Factory (Control Tower Pattern)

# modules/account/main.tf
resource "aws_organizations_account" "account" {
  name  = var.account_name
  email = var.account_email
  
  parent_id = var.organizational_unit_id
  
  role_name = "OrganizationAccountAccessRole"
  
  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

resource "aws_iam_role" "terraform_role" {
  provider = aws.new_account
  name     = "TerraformRole"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${var.management_account_id}:root"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

Security Best Practices Checklist

## Account Security
- [ ] MFA enabled on root account
- [ ] Root account access keys deleted
- [ ] Root account email is distribution list
- [ ] Strong password policy configured
- [ ] CloudTrail enabled in all regions
- [ ] GuardDuty enabled
- [ ] Security Hub enabled
- [ ] Config enabled with rules

## Organization Security
- [ ] SCPs restrict dangerous actions
- [ ] SCPs enforce region restrictions
- [ ] SCPs require encryption
- [ ] Log archive account isolated
- [ ] Security account isolated
- [ ] Cross-account access uses roles (not users)

## IAM Security
- [ ] No long-lived access keys
- [ ] IAM Access Analyzer enabled
- [ ] Unused credentials rotated/removed
- [ ] Permission boundaries on delegated admins
- [ ] Service-linked roles used where possible

## Cost Management
- [ ] Budgets configured with alerts
- [ ] Cost allocation tags active
- [ ] Savings Plans evaluated
- [ ] Unused resources cleaned up
- [ ] Right-sizing recommendations reviewed

Resources

Source

git clone https://github.com/Makiya1202/ai-agents-skills/blob/master/skills/aws-account-management/SKILL.mdView on GitHub

Overview

This skill helps you set up and govern AWS Organizations, structure OUs, manage member accounts, enforce SCPs, and control costs via billing tools. It also covers IAM Identity Center setup and permissions to streamline multi-account operations.

How This Skill Works

It provides concrete commands, JSON snippets, and workflows for creating organizations and OUs, provisioning member accounts, moving accounts between OUs, and applying Service Control Policies. It also covers configuring IAM Identity Center (SSO), permission sets, and attaching managed policies to enable cross-account access control.

When to Use It

  • When starting a multi-account AWS strategy and creating an Organization.
  • When centralizing governance with SCPs and policy controls across accounts.
  • When provisioning new accounts and moving them into organizational units (OUs).
  • When configuring AWS IAM Identity Center (SSO) permissions and permission sets.
  • When enforcing security and cost controls across accounts using billing tools and Cost Explorer.

Quick Start

  1. Step 1: Create organization (from management account) using aws organizations create-organization --feature-set ALL
  2. Step 2: Create organizational unit(s) and member accounts, then move accounts into the correct OU with aws organizations create-organizational-unit and aws organizations move-account
  3. Step 3: Create and attach SCPs (e.g., DenyLeaveOrg, RequireIMDSv2, DenyNonApprovedRegions) and set up IAM Identity Center with permission sets and managed policies

Best Practices

  • Plan a scalable OU structure that maps to environments (Production, Development, Security, Sandbox).
  • Use Service Control Policies to enforce mandatory security baselines (e.g., IMDSv2, approved regions).
  • Deny root user access and minimize elevated IAM permissions across accounts.
  • Automate account provisioning and account migrations to reduce errors and onboarding time.
  • Regularly review billing, budgets, and Cost Explorer to optimize spend across the organization.

Example Use Cases

  • Create an Organization with Production, Development, Security, and Sandbox OUs and assign respective accounts.
  • Attach a DenyLeaveOrg SCP to prevent accounts from leaving the Organization.
  • Apply DenyNonApprovedRegions SCP to restrict resource creation to approved regions only.
  • Set up AWS IAM Identity Center and create an AdministratorAccess permission set for cross-account admin access.
  • Configure Identity Center permission sets (inline policies) to provide scoped access like DeveloperAccess while denying billing and IAM actions.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers