Skip to content

AWS CLI Profiles

You must always specify --profile with every AWS CLI command. There is no safe default profile.


Profile Setup

Credentials File

Add both profiles to ~/.aws/credentials:

[shared-services]
aws_access_key_id = YOUR_SHARED_SERVICES_KEY_ID
aws_secret_access_key = YOUR_SHARED_SERVICES_SECRET

[dev]
aws_access_key_id = YOUR_DEV_KEY_ID
aws_secret_access_key = YOUR_DEV_SECRET

Config File

Add the corresponding config entries to ~/.aws/config:

[profile shared-services]
region = us-west-2
output = json

[profile dev]
region = us-west-2
output = json

Do not set a default profile

Leaving [default] in your credentials file pointing at either account creates a footgun. If you forget --profile on a command, it silently targets the wrong account. Either remove [default] or point it to an account with no infrastructure (e.g., a read-only role).


Verifying Your Identity

Always run this before any AWS operation that modifies resources:

# Verify shared-services account
aws sts get-caller-identity --profile shared-services
# Expected output:
# {
#     "UserId": "...",
#     "Account": "308188966547",
#     "Arn": "arn:aws:iam::308188966547:user/your.name"
# }

# Verify dev account
aws sts get-caller-identity --profile dev
# Expected output:
# {
#     "UserId": "...",
#     "Account": "686123185567",
#     "Arn": "arn:aws:iam::686123185567:user/your.name"
# }

If the Account field does not match the expected account ID, stop. You are targeting the wrong account.


Common Operations

EC2

# List instances in the dev account
aws ec2 describe-instances \
  --profile dev \
  --query 'Reservations[].Instances[].{ID:InstanceId,Name:Tags[?Key==`Name`].Value|[0],State:State.Name,IP:PrivateIpAddress}' \
  --output table

# Describe a specific instance
aws ec2 describe-instances \
  --profile dev \
  --instance-ids i-0abc123def456789 \
  --output json

# List all security groups in shared-services
aws ec2 describe-security-groups \
  --profile shared-services \
  --query 'SecurityGroups[].{ID:GroupId,Name:GroupName}' \
  --output table

Route53

# List hosted zones (always in shared-services)
aws route53 list-hosted-zones --profile shared-services

# List records in a zone
aws route53 list-resource-record-sets \
  --profile shared-services \
  --hosted-zone-id Z1234567890ABCDEF \
  --output table

S3

# List all buckets in each account
aws s3 ls --profile shared-services
aws s3 ls --profile dev

# View Terraform state bucket (shared-services)
aws s3 ls s3://cwiq-terraform-states/ --profile shared-services --recursive

EKS

# Update kubeconfig for the dev EKS cluster
aws eks update-kubeconfig \
  --profile dev \
  --region us-west-2 \
  --name cwiq-dev-eks-cluster

# List nodes (after updating kubeconfig)
kubectl get nodes

kubectl runs on the ansible server

The kubectl context for cwiq-dev-eks-cluster is configured on the ansible server (ansible-shared-cwiq-io), not on your local machine or the dev server. To run kubectl commands, SSH to the ansible server first.


Getting Access Keys

Access keys are provisioned per-developer by the infrastructure team. Each developer gets individual IAM users in both accounts with appropriate permissions.

To request access:

  1. Contact the infrastructure team with your intended role (developer, read-only, etc.)
  2. They will create IAM users in both accounts and provide the key IDs and secrets
  3. Add the keys to ~/.aws/credentials as shown above
  4. Verify with aws sts get-caller-identity --profile shared-services and --profile dev

Use IAM roles for production access

For any operation in a production-equivalent environment, prefer assuming an IAM role rather than using long-lived access keys. This provides an audit trail and time-limited credentials. Ask the infrastructure team about the available IAM roles.


Shell Aliases

Optional convenience aliases to reduce the chance of forgetting --profile:

# Add to ~/.bashrc or ~/.zshrc
alias aws-ss='aws --profile shared-services'
alias aws-dev='aws --profile dev'

# Usage
aws-ss sts get-caller-identity
aws-dev ec2 describe-instances --output table

Even with aliases, the profile is explicit in every command — the aliases just save typing.