$ CloudsLink
/

Setup & configuration

Get credentials in place and control output before anything else.

Configure credentials

Interactive prompt for access key, secret key, default region, and output format. Add --profile to keep multiple accounts side by side.

$ aws configure
$ aws configure --profile staging

Check who you are

Confirms which account and identity your current credentials resolve to. The first command to run when something returns AccessDenied.

$ aws sts get-caller-identity

Control output per command

Any command accepts --output (json, table, text, yaml), --region, --profile, and a JMESPath --query to trim the response.

$ aws ec2 describe-instances --output table --region us-west-2 \
    --query 'Reservations[].Instances[].[InstanceId,State.Name]'

Built-in help

Every command and subcommand has a manual page.

$ aws s3 cp help

S3

Two command sets exist: high-level aws s3 (rsync-like) and low-level aws s3api.

List buckets and objects

No argument lists all buckets; a URI lists its contents. --recursive walks the whole prefix, --human-readable --summarize adds sizes and totals.

$ aws s3 ls
$ aws s3 ls s3://my-bucket/logs/ --recursive --human-readable --summarize

Copy files up or down

cp works in either direction and between buckets. Add --recursive for directories.

$ aws s3 cp ./report.pdf s3://my-bucket/reports/
$ aws s3 cp s3://my-bucket/reports/report.pdf .

Sync a directory

Copies only new or changed files. --delete removes remote files that no longer exist locally — the standard static-site deploy.

$ aws s3 sync ./dist s3://my-bucket --delete --exclude "*.map"

Delete objects or a bucket

rm --recursive empties a prefix; rb --force empties and removes the bucket itself.

$ aws s3 rm s3://my-bucket/logs/ --recursive
$ aws s3 rb s3://my-bucket --force

Generate a presigned URL

Creates a temporary link to a private object. --expires-in is in seconds (default 3600).

$ aws s3 presign s3://my-bucket/reports/report.pdf --expires-in 86400

Create a bucket

$ aws s3 mb s3://my-new-bucket --region us-west-2

EC2

List instances

Filter server-side with --filters, then trim client-side with --query.

$ aws ec2 describe-instances \
    --filters "Name=instance-state-name,Values=running" \
    --query 'Reservations[].Instances[].[InstanceId,InstanceType,PublicIpAddress,Tags[?Key==`Name`]|[0].Value]' \
    --output table

Launch an instance

$ aws ec2 run-instances \
    --image-id ami-0abcdef1234567890 \
    --instance-type t3.micro \
    --key-name my-key \
    --security-group-ids sg-0123456789abcdef0 \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-1}]'

Stop, start, terminate

Stopped instances keep their EBS volumes; terminate is permanent.

$ aws ec2 stop-instances --instance-ids i-0123456789abcdef0
$ aws ec2 start-instances --instance-ids i-0123456789abcdef0
$ aws ec2 terminate-instances --instance-ids i-0123456789abcdef0

Open a port on a security group

$ aws ec2 authorize-security-group-ingress \
    --group-id sg-0123456789abcdef0 \
    --protocol tcp --port 22 --cidr 203.0.113.0/24

Find the latest Amazon Linux AMI

Reads the public SSM parameter, so you never hardcode a stale AMI ID.

$ aws ssm get-parameter \
    --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
    --query 'Parameter.Value' --output text

IAM

List users, roles, policies

$ aws iam list-users --query 'Users[].UserName'
$ aws iam list-roles --query 'Roles[].RoleName'
$ aws iam list-attached-role-policies --role-name my-role

Create a user and access key

The secret key is shown once in the response — store it immediately.

$ aws iam create-user --user-name ci-deployer
$ aws iam create-access-key --user-name ci-deployer

Attach a managed policy

$ aws iam attach-user-policy \
    --user-name ci-deployer \
    --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Test whether an action is allowed

Simulates policy evaluation without actually calling the service.

$ aws iam simulate-principal-policy \
    --policy-source-arn arn:aws:iam::123456789012:user/ci-deployer \
    --action-names s3:PutObject

Lambda

List functions

$ aws lambda list-functions --query 'Functions[].[FunctionName,Runtime,LastModified]' --output table

Invoke a function

--cli-binary-format raw-in-base64-out lets you pass plain JSON on CLI v2. The response body lands in the output file.

$ aws lambda invoke \
    --function-name my-function \
    --cli-binary-format raw-in-base64-out \
    --payload '{"key": "value"}' \
    response.json && cat response.json

Deploy new code from a zip

$ zip -r function.zip . && aws lambda update-function-code \
    --function-name my-function \
    --zip-file fileb://function.zip

Update configuration

Note: --environment replaces the whole variable set, it doesn't merge.

$ aws lambda update-function-configuration \
    --function-name my-function \
    --timeout 30 --memory-size 512 \
    --environment 'Variables={STAGE=prod,LOG_LEVEL=info}'

DynamoDB

List and describe tables

$ aws dynamodb list-tables
$ aws dynamodb describe-table --table-name Users --query 'Table.ItemCount'

Put an item

Every value is wrapped in a type descriptor: S string, N number, BOOL, L list, M map.

$ aws dynamodb put-item \
    --table-name Users \
    --item '{"userId": {"S": "u-100"}, "name": {"S": "Ada"}, "age": {"N": "37"}}'

Get an item by key

$ aws dynamodb get-item \
    --table-name Users \
    --key '{"userId": {"S": "u-100"}}'

Query by partition key

Prefer query over scan — it reads only the matching partition.

$ aws dynamodb query \
    --table-name Orders \
    --key-condition-expression 'userId = :u' \
    --expression-attribute-values '{":u": {"S": "u-100"}}'

CloudFormation

Deploy a stack

deploy creates the stack if it's new and updates it via a change set if it exists — idempotent, so it's the CI-friendly choice.

$ aws cloudformation deploy \
    --stack-name my-app \
    --template-file template.yaml \
    --parameter-overrides Stage=prod \
    --capabilities CAPABILITY_NAMED_IAM

Inspect stacks and outputs

$ aws cloudformation describe-stacks --stack-name my-app \
    --query 'Stacks[0].Outputs' --output table

See why a deploy failed

Events are newest-first; filter to the failures.

$ aws cloudformation describe-stack-events --stack-name my-app \
    --query "StackEvents[?contains(ResourceStatus, 'FAILED')].[LogicalResourceId,ResourceStatusReason]" \
    --output table

Delete a stack

$ aws cloudformation delete-stack --stack-name my-app
$ aws cloudformation wait stack-delete-complete --stack-name my-app

CloudWatch Logs

Tail logs live

The closest thing to tail -f for AWS. --since accepts values like 10m, 2h, 1d.

$ aws logs tail /aws/lambda/my-function --follow --since 15m

Search for a pattern

$ aws logs filter-log-events \
    --log-group-name /aws/lambda/my-function \
    --filter-pattern 'ERROR' \
    --start-time $(date -d '1 hour ago' +%s000)

List log groups / set retention

$ aws logs describe-log-groups --query 'logGroups[].logGroupName'
$ aws logs put-retention-policy --log-group-name /aws/lambda/my-function --retention-in-days 30

ECR & ECS

Log Docker in to ECR

$ aws ecr get-login-password --region us-west-2 | \
    docker login --username AWS --password-stdin \
    123456789012.dkr.ecr.us-west-2.amazonaws.com

Tag and push an image

$ docker tag my-app:latest 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-app:latest
$ docker push 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-app:latest

Redeploy an ECS service

Forces new tasks with the same task definition — the standard "restart" after pushing a new :latest image.

$ aws ecs update-service --cluster prod --service web --force-new-deployment

List running tasks

$ aws ecs list-tasks --cluster prod --service-name web

SQS & SNS

Send a message

$ aws sqs send-message \
    --queue-url https://sqs.us-west-2.amazonaws.com/123456789012/my-queue \
    --message-body '{"orderId": 42}'

Receive and delete messages

Receiving doesn't remove a message — delete it with the receipt handle once processed.

$ aws sqs receive-message --queue-url $QUEUE_URL --wait-time-seconds 10
$ aws sqs delete-message --queue-url $QUEUE_URL --receipt-handle "$HANDLE"

Check queue depth

$ aws sqs get-queue-attributes --queue-url $QUEUE_URL \
    --attribute-names ApproximateNumberOfMessages

Publish to an SNS topic

$ aws sns publish \
    --topic-arn arn:aws:sns:us-west-2:123456789012:alerts \
    --subject "Deploy finished" --message "v2.4.1 is live"

STS

Assume a role

Returns temporary credentials — export the three values it prints as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN.

$ aws sts assume-role \
    --role-arn arn:aws:iam::123456789012:role/deploy-role \
    --role-session-name cli-session

Get the current account ID

Handy inside scripts for building ARNs.

$ aws sts get-caller-identity --query Account --output text

No commands match "" — try a service name or verb like sync, tail, invoke.