(dev301) automating aws with the aws cli

67
© 2015, Amazon Web Services, Inc. or its Affiliates. All rights reserved. James Saryerwinnie October 2015 Automating AWS with the AWS CLI DEV301

Upload: amazon-web-services

Post on 14-Apr-2017

12.907 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: (DEV301) Automating AWS with the AWS CLI

© 2015, Amazon Web Services, Inc. or its Affiliates. All rights reserved.

James Saryerwinnie

October 2015

Automating AWS with the AWS CLI

DEV301

Page 2: (DEV301) Automating AWS with the AWS CLI

AWS Command Line Interface

Unified tool to manage your AWS services

Page 3: (DEV301) Automating AWS with the AWS CLI

$ git show 1.0.0tag 1.0.0Tagger: James Saryerwinnie <[email protected]>Date: Mon Sep 2 18:38:51 2013 -0700

Tagging 1.0.0 release.

commit 7fbdac0b19ea9dcc0380242068af20ef425ac5c3Merge: 6f76721 469bab6Author: James Saryerwinnie <[email protected]>Date: Mon Sep 2 18:38:51 2013 -0700

Merge branch 'release-1.0.0'

* release-1.0.0:Bumping version to 1.0.0

Page 4: (DEV301) Automating AWS with the AWS CLI

Interactive

Page 5: (DEV301) Automating AWS with the AWS CLI

Shell scripts#!/bin/bash

import_key_pair() {echo -n "Would you like to import ~/.ssh/id_rsa.pub? [y/N]: "read confirmationif [[ "$confirmation" != "y" ]]then

return

fi

aws ec2 import-key-pair \

--key-name id_rsa \

--public-key-material file://~/.ssh/id_rsa.pub}

create_instance_profile() {echo -n "Would you like to create an IAM instance profile? [y/N]: "read confirmationif [[ "$confirmation" != "y" ]]; then

return

fi

aws iam create-role --role-name dev-ec2-instance \

--assume-role-policy-document "$TRUST_POLICY" || errexit "Could not create Role"

# Use a managed policy

policies=$(aws iam list-policies --scope AWS)

admin_policy_arn=$(jp -u \

"Policies[?PolicyName=='AdministratorAccess'].Arn | [0]" <<< "$policies")

aws iam attach-role-policy \

--role-name dev-ec2-instance \

--policy-arn "$admin_policy_arn" || errexit "Could not attach role policy"

# Then we need to create an instance profile from the role.

aws iam create-instance-profile \

--instance-profile-name dev-ec2-instance || \

errexit "Could not create instance profile."# And add it to the role

aws iam add-role-to-instance-profile \

--role-name dev-ec2-instance \

--instance-profile-name dev-ec2-instance || \

errexit "Could not add role to instance profile."}

compute_key_fingerprint() {# Computes the fingerprint of a public SSH key given a private

# RSA key. This can be used to compare against the output given

# from aws ec2 describe-key-pair.

openssl pkey -in ~/.ssh/id_rsa -pubout -outform DER | \

openssl md5 -c | \

cut -d = -f 2 | \

tr -d '[:space:]'}

do_setup() {echo "Checking for required resources..."echo ""# 1. Check if a security group is found for

# both windows and non-windows tags.

# If not, we'll eventually give the option to

# configure this.

if resource_exists "aws ec2 describe-security-groups \--filter Name=tag:dev-ec2-instance,Values=non-windows"; then

echo "Security groups exists."else

echo "Security group not found."fi

echo ""

# 2. Make sure the keypair is imported.

if [[ ! -f ~/.ssh/id_rsa ]]; then

echo "Missing ~/.ssh/id_rsa key pair."elif has_new_enough_openssl; then

fingerprint=$(compute_key_fingerprint ~/.ssh/id_rsa)

if resource_exists "aws ec2 describe-key-pairs \--filter Name=fingerprint,Values=$fingerprint"; then

echo "Key pair exists."else

echo "~/.ssh/id_rsa key pair does not appear to be imported."import_key_pair

fi

else

echo "Can't check if SSH key has been imported."echo "You need at least openssl 1.0.0 that has a \"pkey\" command."echo "Please upgrade your version of openssl."

fi

echo ""

# 3. Check that they have an IAM role called dev-ec2-instance.

# There is no server side filter for this like we have with the EC2

# APIs, so we have to manually use a --query option for us.

if resource_exists "aws iam list-instance-profiles" \

"length(InstanceProfiles[?InstanceProfileName=='dev-ec2-instance'])"; then

echo "Instance profile exists."else

echo "Missing IAM instance profile 'dev-ec2-instance'"create_instance_profile

fi

echo ""}

do_setup

Page 6: (DEV301) Automating AWS with the AWS CLI

aws s3 lsApplicationwith an AWS SDK

Page 7: (DEV301) Automating AWS with the AWS CLI

aws s3 lsApplicationwith an AWS SDK

Shell Scripts – what we’ll cover

Page 8: (DEV301) Automating AWS with the AWS CLI

A good shell script

• < 100 SLOC

• Commands in sequence

• Piping input/output

• Simple domain logic

Page 9: (DEV301) Automating AWS with the AWS CLI

• Familiar with AWS CLI

• Familiar with bash

• Familiar with AWS

Prerequisites

Page 10: (DEV301) Automating AWS with the AWS CLI

$ aws ec2 describe-instances --filters Name=architecture,Values=x86_64

$ du $(ls | grep cli) | sort -nr | tail -2

Amazon S3Amazon EC2

Prerequisites

Page 11: (DEV301) Automating AWS with the AWS CLI

Getting up to speed

• Becoming a Command Line Expert with the AWS CLI

• Advanced Usage of the AWS CLI

• Installation

• Configuration

Page 12: (DEV301) Automating AWS with the AWS CLI

$

We will be in the terminal…

Page 13: (DEV301) Automating AWS with the AWS CLI

$

We will be in the terminal…a lot

Page 14: (DEV301) Automating AWS with the AWS CLI

Common patterns

Page 15: (DEV301) Automating AWS with the AWS CLI

Main patterns

• Single output to a single command

• Map list output to N AWS CLI commands

• Storing JSON documents and querying later

• Resource exists check

Page 16: (DEV301) Automating AWS with the AWS CLI

Main patterns

• Single output to a single command

• Map list output to N AWS CLI commands

• Storing JSON documents and querying later

• Resource exists check

Page 17: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

Page 18: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

$ aws ec2 describe…

{

"Reservations": [

{

"Groups": [

{

"GroupId": "sg-abc",

"GroupName": "Windows"

}

],

"Instances": [

{

"AmiLaunchIndex": 0,

"Architecture": "x86_64",

"BlockDeviceMappings": [

{

"DeviceName": "/dev/sda1",

"Ebs": {

"AttachTime": "2015-01-29T21:22:17.000Z",

"DeleteOnTermination": true,

"Status": "attached",

$ aws ec2 run… --foo <here>

Page 19: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

aws ec2 create-tags --tags Key=purpose,Value=dev \

--resources $(aws ec2 run-instances \

--image-id ami-12345 \

--query Instances[].InstanceId \

--output text)

Page 20: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

aws ec2 create-tags --tags Key=purpose,Value=dev \

--resources $(aws ec2 run-instances \

--image-id ami-12345 \

--query Instances[].InstanceId \

--output text)

Error handling

Page 21: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

instance_ids=$(aws ec2 run-instances \

--image-id ami-12345 \

--query Instances[].InstanceId \

--output text) || errexit "Could not run instance"aws ec2 create-tags \

--tags Key=purpose,Value=dev \

--resources "$(instance_ids)" || errexit "<errmsg>"

Page 22: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

instance_ids=$(aws ec2 run-instances \

--image-id ami-12345 \

--query Instances[].InstanceId \

--output text) || errexit "Could not run instance"aws ec2 create-tags \

--tags Key=purpose,Value=dev \

--resources "$(instance_ids)" || errexit "<errmsg>"

Page 23: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

instance_ids=$(aws ec2 run-instances \

--image-id ami-12345 \

--query Instances[].InstanceId \

--output text) || errexit "Could not run instance"aws ec2 create-tags \

--tags Key=purpose,Value=dev \

--resources "$(instance_ids)" || errexit "<errmsg>"

Page 24: (DEV301) Automating AWS with the AWS CLI

Output to a single parameter

• Used to map one part of the output to one part of the input

• Use --query and --output text

• Make sure to handle the error case before using the value

Page 25: (DEV301) Automating AWS with the AWS CLI

Main Patterns

• Single output to a single command

• Map list output to N AWS CLI commands

• Storing JSON documents and querying later

• Resource exists check

Page 26: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

Page 27: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

$ aws iam list…

[

"a",

"b",

”c",

"d",

"e"

]

$ aws iam … --foo <here>

$ aws iam … --foo <here>

$ aws iam … --foo <here>

$ aws iam … --foo <here>

$ aws iam … --foo <here>

Page 28: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

for name in $(aws iam list-users \

--query "Users[].[UserName]" --output text); do

aws iam delete-user --user-name "$name"done

Page 29: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

for name in $(aws iam list-users \

--query "Users[].[UserName]" --output text); do

aws iam delete-user --user-name "$name"done

User1User2User3User4User5

Page 30: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

for name in $(aws iam list-users \

--query "Users[].[UserName]" --output text); do

aws iam delete-user --user-name "$name"done

Page 31: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

aws iam list-users --query "Users[].[UserName]" --output text |xargs -I {} -P 10 aws iam delete-user --user-name "{}"

Page 32: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

aws iam list-users --query "Users[].[UserName]" --output text |xargs -I {} -P 10 aws iam delete-user --user-name "{}"

Page 33: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

aws iam list-users --query "Users[].[UserName]" --output text |xargs -I {} -P 10 aws iam delete-user --user-name "{}"

Parallel

Page 34: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

\-+= 72730 james -bash\-+- 76343 james xargs -I {} –P 9 aws iam delete-user --user-name {}

|--- 76348 james aws iam delete-user --user-name user1|--- 76349 james aws iam delete-user --user-name user2|--- 76350 james aws iam delete-user --user-name user3|--- 76351 james aws iam delete-user --user-name user4|--- 76352 james aws iam delete-user --user-name user5|--- 76353 james aws iam delete-user --user-name user6|--- 76354 james aws iam delete-user --user-name user7|--- 76355 james aws iam delete-user --user-name user8\--- 76356 james aws iam delete-user --user-name user9

Page 35: (DEV301) Automating AWS with the AWS CLI

Mapping one output to N AWS calls

• Use a for loop for functions

• If you’re using xargs, use -I {}

• Use xargs –P N parallel execution

• Use “.[UserName]” instead of “.UserName” to get

newline separated output..

• This works because nothing is written to stdout on error

Page 36: (DEV301) Automating AWS with the AWS CLI

Demo

Page 37: (DEV301) Automating AWS with the AWS CLI

Main patterns

Single output to a single command

Map list output to N AWS CLI commands

• Storing JSON documents and querying later

• Resource exists check

Page 38: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

{"AmiLaunchIndex": 0,"Architecture": "x86_64","BlockDeviceMappings": [{"DeviceName": "/dev/sda1","Ebs": {"AttachTime": "2015-01-29T21:22:17.000Z","DeleteOnTermination": true,"Status": "attached","VolumeId": "vol-12345"

}},{"DeviceName": "xvdg","Ebs": {"AttachTime": "2015-09-17T19:14:27.000Z","DeleteOnTermination": false,"Status": "attached","VolumeId": "vol-12345"

}}

],"ClientToken": "12345","EbsOptimized": false,"Hypervisor": "xen","IamInstanceProfile": {"Arn": "arn:aws:iam::12345","Id": "12345"

},"ImageId": "ami-12345","InstanceId": "i-12345","InstanceType": "m3.large","KeyName": "id_rsa","LaunchTime": "2015-09-17T17:24:13.000Z","Monitoring": {"State": "disabled"

},}

instance =

Page 39: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

{"AmiLaunchIndex": 0,"Architecture": "x86_64","BlockDeviceMappings": [{"DeviceName": "/dev/sda1","Ebs": {"AttachTime": "2015-01-29T21:22:17.000Z","DeleteOnTermination": true,"Status": "attached","VolumeId": "vol-12345"

}},{"DeviceName": "xvdg","Ebs": {"AttachTime": "2015-09-17T19:14:27.000Z","DeleteOnTermination": false,"Status": "attached","VolumeId": "vol-12345"

}}

],"ClientToken": "12345","EbsOptimized": false,"Hypervisor": "xen","IamInstanceProfile": {"Arn": "arn:aws:iam::12345","Id": "12345"

},"ImageId": "ami-12345","InstanceId": "i-12345","InstanceType": "m3.large","KeyName": "id_rsa","LaunchTime": "2015-09-17T17:24:13.000Z","Monitoring": {"State": "disabled"

},}

instance = query $instance \BlockDeviceMappings[0].VolumeId

Page 40: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

{"AmiLaunchIndex": 0,"Architecture": "x86_64","BlockDeviceMappings": [{"DeviceName": "/dev/sda1","Ebs": {"AttachTime": "2015-01-29T21:22:17.000Z","DeleteOnTermination": true,"Status": "attached","VolumeId": "vol-12345"

}},{"DeviceName": "xvdg","Ebs": {"AttachTime": "2015-09-17T19:14:27.000Z","DeleteOnTermination": false,"Status": "attached","VolumeId": "vol-12345"

}}

],"ClientToken": "12345","EbsOptimized": false,"Hypervisor": "xen","IamInstanceProfile": {"Arn": "arn:aws:iam::12345","Id": "12345"

},"ImageId": "ami-12345","InstanceId": "i-12345","InstanceType": "m3.large","KeyName": "id_rsa","LaunchTime": "2015-09-17T17:24:13.000Z","Monitoring": {"State": "disabled"

},}

instance =

query $instance ImageId

query $instance \BlockDeviceMappings[0].VolumeId

Page 41: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

{"AmiLaunchIndex": 0,"Architecture": "x86_64","BlockDeviceMappings": [{"DeviceName": "/dev/sda1","Ebs": {"AttachTime": "2015-01-29T21:22:17.000Z","DeleteOnTermination": true,"Status": "attached","VolumeId": "vol-12345"

}},{"DeviceName": "xvdg","Ebs": {"AttachTime": "2015-09-17T19:14:27.000Z","DeleteOnTermination": false,"Status": "attached","VolumeId": "vol-12345"

}}

],"ClientToken": "12345","EbsOptimized": false,"Hypervisor": "xen","IamInstanceProfile": {"Arn": "arn:aws:iam::12345","Id": "12345"

},"ImageId": "ami-12345","InstanceId": "i-12345","InstanceType": "m3.large","KeyName": "id_rsa","LaunchTime": "2015-09-17T17:24:13.000Z","Monitoring": {"State": "disabled"

},}

instance =

query $instance InstanceId

query $instance ImageId

query $instance \BlockDeviceMappings[0].VolumeId

Page 42: (DEV301) Automating AWS with the AWS CLI

jp – The JMESPath CLI

• Same language as --query

• Cross platform executable

• https://github.com/jmespath/jp

Page 43: (DEV301) Automating AWS with the AWS CLI

jp – The JMESPath CLI

• Same language as --query

• Cross platform executable

• https://github.com/jmespath/jp

Mac OS Xbrew tap jmespath/jmespathbrew install jp

Page 44: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

instance=$(aws run-instance --image-id ami-1234 \

--query Instances[0])

query() {jp -u "$2" <<<"$1"

}

instance_id=$(query "$instance" InstanceId)

state_name=$(query "$instance" State.Name)

instance_name=$(query "$instance" "Tags[?Key=='Name'].Value | [0]")

Page 45: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

instance=$(aws run-instance --image-id ami-1234 \

--query Instances[0])

query() {jp -u "$2" <<<"$1"

}

instance_id=$(query "$instance" InstanceId)

state_name=$(query "$instance" State.Name)

instance_name=$(query "$instance" "Tags[?Key=='Name'].Value | [0]")

instance=

{"InstanceId": ”i-12345", ... }

Page 46: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

instance=$(aws run-instance --image-id ami-1234 \

--query Instances[0])

query() {jp -u "$2" <<<"$1"

}

instance_id=$(query "$instance" InstanceId)

state_name=$(query "$instance" State.Name)

instance_name=$(query "$instance" "Tags[?Key=='Name'].Value | [0]")

Page 47: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

instance=$(aws run-instance --image-id ami-1234 \

--query Instances[0])

query() {jp -u "$2" <<<"$1"

}

instance_id=$(query "$instance" InstanceId)

state_name=$(query "$instance" State.Name)

instance_name=$(query "$instance" "Tags[?Key=='Name'].Value | [0]")

Page 48: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

instance=$(aws run-instance --image-id ami-1234 \

--query Instances[0])

query() {jp -u "$2" <<<"$1"

}

instance_id=$(query "$instance" InstanceId)

state_name=$(query "$instance" State.Name)

instance_name=$(query "$instance" "Tags[?Key=='Name'].Value | [0]")

Page 49: (DEV301) Automating AWS with the AWS CLI

Saving the entire output for querying later

1. Use JSON output, not text, --output json

2. Store the entire thing as a variable, or write to a temp

file if output size is a concern.

3. Use the “jp” command to filter down results as needed.

Page 50: (DEV301) Automating AWS with the AWS CLI

Main Patterns

Single output to a single command

Map list output to N AWS CLI commands

Storing JSON documents and querying later

• Resource exists check

Page 51: (DEV301) Automating AWS with the AWS CLI

resource_exists() {

}

1. Determine command to run with query

2. Run command and check errors

3. Check length of query result

Page 52: (DEV301) Automating AWS with the AWS CLI

resource_exists() {local cmdlocal num_matches

if [[ -z "$2" ]]; then

cmd="$1 --query length(*[0])"else

cmd="$1 --query $2"fi

}

2. Run command and check errors

3. Check length of query result

Page 53: (DEV301) Automating AWS with the AWS CLI

resource_exists() {

num_matches=$($command)

if [[ "$?" -ne 0 ]]; then

echo "Could not check if resource exists, exiting."exit 2

fi

}

3. Check length of query result

1. Determine command to run with query

Page 54: (DEV301) Automating AWS with the AWS CLI

resource_exists() {

if [[ "$num_matches" -gt 0 ]]; then

# RC of 0 mean the resource exists, success.

return 0else

return 1fi

}

1. Determine command to run with query

2. Run command and check errors

Page 55: (DEV301) Automating AWS with the AWS CLI

Usage: Server-side filtering

describe_groups="aws ec2 describe-security-groups"if resource_exists "$describe_groups \--filter Name=tag:dev-ec2-instance,Values=linux"; then

echo "Security groups exists."else

echo "Security group not found."fi

Page 56: (DEV301) Automating AWS with the AWS CLI

Usage: Client-side filtering

list_profiles="aws iam list-instance-profiles"if resource_exists "$list_profiles" \

"InstanceProfiles[?InstanceProfileName=='dev-ec2-instance']" then

echo "Instance profile exists."else

echo "Missing IAM instance profile 'dev-ec2-instance'"create_instance_profile

fi

Page 57: (DEV301) Automating AWS with the AWS CLI

Resource exists

• Check if a resource exists by filtering down a list and

checking if the length is greater than 0.

• Use server side filtering when possible

• Use JMESPath query for client side filtering

Page 58: (DEV301) Automating AWS with the AWS CLI

Demo

Page 59: (DEV301) Automating AWS with the AWS CLI

Common Patterns

Single output to a single command

Map list output to N AWS CLI commands

Storing JSON documents and querying later

Resource exists check

Page 60: (DEV301) Automating AWS with the AWS CLI

Deployment tips

Page 61: (DEV301) Automating AWS with the AWS CLI

# * * * * * command to execute# │ │ │ │ │# │ │ │ │ │# │ │ │ │ └───── day of week (0 – 6)# │ │ │ └────────── month (1 - 12)# │ │ └─────────────── day of month (1 - 31)# │ └──────────────────── hour (0 - 23)# └───────────────────────── min (0 - 59)

Cron

Page 62: (DEV301) Automating AWS with the AWS CLI

$ whoami

$HOME/.aws/config

$HOME/.aws/credentials

export AWS_CONFIG_FILE

export AWS_SHARED_CREDENTIALS_FILE

Page 63: (DEV301) Automating AWS with the AWS CLI

$ whoami

$HOME/.aws/config

$HOME/.aws/credentials

export AWS_CONFIG_FILE

export AWS_SHARED_CREDENTIALS_FILE

• Explicitly set AWS_CONFIG_FILE/AWS_SHARED_CREDENTIALS_FILE• Ensure user running cron job has ~/.aws/config ~/.aws/credentials

Page 64: (DEV301) Automating AWS with the AWS CLI

aws configure set region \$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document \| jp -u 'region')

Configure a region

Page 65: (DEV301) Automating AWS with the AWS CLI

Summary

• Common patterns

• Shell script examples

• Deployment

• Tools

Page 66: (DEV301) Automating AWS with the AWS CLI

Remember to complete

your evaluations!

Page 67: (DEV301) Automating AWS with the AWS CLI

Thank you!• User guide: http://docs.aws.amazon.com/cli/latest/userguide/

• Reference docs: http://docs.aws.amazon.com/cli/latest/reference/

• JMESPath: http://jmespath.org/

• re:Invent 2014 - https://www.youtube.com/watch?v=vP56l7qThNs

• re:Invent 2013 - https://www.youtube.com/watch?v=qiPt1NoyZm0