vagrant sshで接続時に自動でSecurityGroupを作り，切断時にSecurityGroupを消す

# 前提
固定IPがないので，SecurityGroupをうまく設定できない．でも`0.0.0.0/0`を許可したくない．

# 方針
## [vagrant-triggers](https://github.com/emyl/vagrant-triggers)でがんばってみる
[vagrant-triggers](https://github.com/emyl/vagrant-triggers)を使うと，vagrantの任意のサブコマンドの前後に処理を挟みこめます．

しかし，`vagrant ssh`時においては，接続前のトリガーはうまく動いたものの，切断したときはトリガーが発動せず，断念しました．

## `config.ssh.ssh_command`を設定する
[ドキュメント](https://www.vagrantup.com/docs/vagrantfile/ssh_settings.html)には見当らなかったのですが，`config.ssh.ssh_command`を設定することで，`vagrant ssh`時に使用されるsshプログラムを指定することができる模様．ソースだと[このあたり](https://github.com/mitchellh/vagrant/blob/master/plugins/kernel_v2/config/ssh.rb#L15)

そこで，sshする前に現在のIPからSSHを許可するSecurityGroupを作り，ssh切れたらSecurityGroupを消滅させるシェルを書き，それを`vagrant ssh`で勝手に使ってくれるようにしました．

# ソース
Vagrantfileに1つしかVM定義がない前提です．また，VM名を指定してる場合はinstance-idが書かれたファイルのパスが変わるはずです．

あと，awscliをインストールしておく必要があります．

```bash:ec2ssh
#!/bin/bash

# 事前にaws configureで設定は済ませておく
export AWS_DEFAULT_PROFILE=sample
set -e

# vagrant upは終わっている前提
# ファイルに書かれているinstance-idを読みとる
test -e .vagrant/machines/default/aws/id
INSTANCE_ID=$(cat .vagrant/machines/default/aws/id)
test -n $INSTANCE_ID

# SecurityGroupを作るために当該インスタンスが属しているVPCを調べる
VPC_ID=$(aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    --query "Reservations[0].Instances[0].VpcId" \
    --output text)
test -n $VPC_ID

# デフォルトのSecurityGroupを用意しておく
# EC2インスタンスには最低1つSecurityGroup付ける必要があるため．
# どこからも接続できないようなSecurityGroupでOK
DEFAULT_SECURITY_GROUP=$(aws ec2 describe-security-groups \
    --filter "Name=group-name,Values=default" \
    --query "SecurityGroups[0].GroupId" \
    --output text)
test -n $DEFAULT_SECURITY_GROUP

# 新しいSecurityGroupを作成
SECURITY_GROUP=$(aws ec2 create-security-group \
    --group-name "ec2ssh-$(date +%Y%m%d-%H%M%S)" \
    --description "SSH from CURRENT_IP" \
    --vpc-id $VPC_ID \
    --output text)
test -n $SECURITY_GROUP && echo "security-group $SECURITY_GROUP created successfully."

# 現在のIPを調べる
CURRENT_IP=$(curl -s https://api.ipify.org)
# 作ったSecurityGroupに，現在のIPからのSSHを許可するようなルールを作成する
aws ec2 authorize-security-group-ingress \
    --group-id $SECURITY_GROUP --ip-protocol tcp \
    --from-port 22 --to-port 22 --cidr-ip "$CURRENT_IP/32"
aws ec2 modify-instance-attribute \
    --instance-id $INSTANCE_ID \
    --groups $SECURITY_GROUP
echo "SSH connection would be authorized from $CURRENT_IP/32"

# sshが異常終了した場合でも処理を継続するように．
set +e
ssh $*
set -e

# 当該インスタンスのSecurityGroupをデフォルトのみに戻す
aws ec2 modify-instance-attribute \
    --instance-id $INSTANCE_ID \
    --groups $DEFAULT_SECURITY_GROUP
# 作ったSecurityGroupを削除する
aws ec2 delete-security-group \
    --group-id $SECURITY_GROUP
echo "security-group $SECURITY_GROUP deleted successfully."
echo "SSH connection would be revoked from $CURRENT_IP/32"

exit 0
```
こんなシェルをVagrantfileと同じ場所に置いておく

あとは，Vagrantfile内のsshの設定をやってるところで`ssh_command`に設定する．

```rb:Vagrantfile
    override.ssh.username         = "ec2-user"
    override.ssh.private_key_path = "~/.ssh/private.pem"
    override.ssh.ssh_command      = './ec2ssh' # <-これ
```

# 結果
```shell-session
uraura@rosemary $ vagrant ssh
security-group sg-xxxxxxxx created successfully.
SSH connection would be authorized from xxx.xxx.xxx.xxx/32
Last login: Fri Jan 22 11:15:01 2016 from xxx.xxx.xxx.xxx

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

https://aws.amazon.com/amazon-linux-ami/2015.09-release-notes/
1 package(s) needed for security, out of 1 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-172-31-8-18 ~]$

[ec2-user@ip-172-31-8-18 ~]$ exit
Connection to ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com closed.
security-group sg-xxxxxxxx deleted successfully.
SSH connection would be revoked from xxx.xxx.xxx.xxx/32
```

SSHがタイムアウトしたとか，SSH中にインスタンスが停止した場合でも，ちゃんとSecurityGroupが消えます．