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 Organizations Docs: https://docs.aws.amazon.com/organizations/ IAM Best Practices: https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html Identity Center: https://docs.aws.amazon.com/singlesignon/ Cost Management: https://docs.aws.amazon.com/cost-management/ Control Tower: https://docs.aws.amazon.com/controltower/ Security Hub: https://docs.aws.amazon.com/securityhub/