AWS EC2にインスタンス一覧から選択してSSHできるスクリプトを作った

EC2 に SSH する度に AWS コンソールからインスタンスの詳細選んで Elastic IP をコピペしてキーファイルを指定して実行というのが怠いので便利スクリプトを作ってみた。

単に SSH

第1引数にプロファイル名を指定します。 ~/.aws/credentials に定義されている中から選択します(引数なしで実行するとプロファイルがわかります)。

$ ec2ssh profile1
0) server-dev   60.100.45.XXX  i-abcdefgx  keypair-dev
1) server-stg   60.100.45.YYY  i-abcdefgy  keypair-stg
2) server-prod  60.100.45.ZZZ  i-abcdefgz  keypair-prod
Input target EC2 number> 2
Last login: Wed Jan 20 15:19:00 2016 from xxxx.xxxx.xxx.xxx

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2015.09-release-notes/
[ec2-user@ip-10-0-0-1 ~]$

ファイルをEC2からローカルにコピー

EC2 の /tmp/log.tgz をローカルの ~/work/ にコピーする。 引数に get, EC2内ファイルパス, ローカルコピー先パス の順に指定する。 コピー先が未指定ならカレントディレクトリになる。

$ ec2ssh profile1 get /tmp/log.tgz ~/work/

ファイルをローカルからEC2にコピー

カレントディレクトリの batch.sh を EC2 の /tmp にコピーする 引数に put, ローカルファイルパス, EC2内コピー先パス の順に指定する。 コピー先が未指定なら ec2-user のホームディレクトリになる。

$ ec2ssh profile1 put batch.sh /tmp

スクリプト

https://gist.github.com/tilfin/4cdca4311b2585ed91e8

  • AWS CLIjq に依存しています。
  • 各キーペアpemファイルは、AWSコンソールから取得したときのファイル名のまま ~/.ssh/ に置く。
  • ~/.ec2ssh-pre を置くと ssh, scp 前に任意のコマンドを実行できます。
  • ~/.ec2ssh-post を置くと ssh, scp 後に任意のコマンドを実行できます。
#!/bin/bash
#---------------------------------------------
# EC2 SSH
#
# select target from instace list
#---------------------------------------------
#
#  ssh example) $ ec2ssh profile1
#
#  download file example)
#  $ ec2ssh profile1 get /tmp/log.tgz ~/work/
#
#  upload file example)
#  $ ec2ssh profile1 put batch.sh /tmp
#
#
#  If you want to hook pre and post command,
#  put ~/.ec2ssh-pre or ~/.ec2ssh-post
#  pre|post script is called with arguments:
#     $1 = EC2 IP Address
#     $2 = profile
#     $3 = action
#     $4 = source path
#     $5 = destination path
#
#---------------------------------------------

EC2USER=ec2-user
ALIVEINTERVAL=30


profile=$1
action=$2
src=$3
dest=$4
if [ "$profile" == "" ]; then
  name=`basename $0`
  echo "Usage: $name <aws profile> [action] [src] [dest]"
  echo -n "  aws profiles)"
  for pf in `grep -e "\[[a-z\-]*\]" ~/.aws/credentials | sed 's/\[//;s/\]//'`
  do
    echo -n " $pf"
  done
  echo -e "\n  action) get put"
  exit 1
fi


iplist=()
keylist=()
index=0

IFS=$'\n'
for line in `aws ec2 describe-instances --profile $profile \
  | jq '.Reservations[].Instances[] | {InstanceId, PublicIpAddress, PrivateIpAddress, KeyName, InstanceName: (.Tags[] | select(.Key=="Name").Value)}' 2> /dev/null \
  | jq 'sort_by(.InstanceName) | .[]' --slurp \
  | jq -r '[.PublicIpAddress, .InstanceId, .InstanceName, .KeyName] | @tsv'`
do
  IFS=$'\t'
  item=( $line )
  IFS=$'\n'

  iplist+=( ${item[0]} )
  keylist+=( ${item[3]} )
  echo -e "$index) ${item[2]}\t${item[0]}\t${item[1]}\t${item[3]}"

  index=$((index + 1))
  count=$index
done

if [ $count -eq 0 ]; then
  echo "Not found EC2 instances"
  exit 1
fi

echo -n "Input target EC2 number> "
read INPUT
index=$INPUT

if [ "$index" != "" ] && [ $index -lt $count ]; then
  hostip=${iplist[$index]}
  pemfile=${keylist[${index}]}

  if [ -f ~/.ec2ssh-pre ]; then
    . ~/.ec2ssh-pre $hostip $profile $action $src $dest
  fi

  if [ "$action" == "get" ]; then
    if [ "$dest" == "" ]; then
      dest="."
    fi

    scp -o StrictHostKeyChecking=no -i ~/.ssh/${pemfile}.pem $EC2USER@$hostip:$src $dest
  elif [ "$action" == "put" ]; then
    if [ "$dest" == "" ]; then
      dest="~"
    fi

    scp -o StrictHostKeyChecking=no -i ~/.ssh/${pemfile}.pem $src $EC2USER@$hostip:$dest
  else
    ssh -o ServerAliveInterval=$ALIVEINTERVAL \
        -o StrictHostKeyChecking=no \
        -l $EC2USER -i ~/.ssh/${pemfile}.pem $hostip
  fi

  if [ -f ~/.ec2ssh-post ]; then
    . ~/.ec2ssh-post $hostip $profile $action $src $dest
  fi
fi

Qiitaにクロスポストしてみるか。