vagrant-awsを使ってみた＆vagrant up --provider=aws で "Waiting for SSH to become available" で固まる現象を回避した話

[vagrant-aws](https://github.com/mitchellh/vagrant-aws) を使ったEC2インスタンスの立ち上げ・プロビジョニングに手を出してみたのだけれど、using VPC (+ Security Group)な環境下でタイトルのエラーが出て悩まされた
要は「`vagrant up`時にsshが繋がらない」という事象なのだけど、調べてみても解決策がイマイチはっきりしなかったので、自分が試した事＆解決までの道程をログっておく


## 先に結論
Vagrantfileで

* `aws.associate_public_ip = true`する
* `aws.security_groups = [外部からport=22を許可しているgroup ID]`する（含める）

## AWS VPCの設定
（ほぼ）[VPC Management Console](https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#vpcs:) のチュートリアル手順をベースにしている。VPCとは何ぞや？という話については省略

* CIDRが`10.0.0.0/16`のVPC
* このVPC内に CIDRが`10.0.0.0/24` なpublic subnetを作成
* このpublic subnetにpublic用途&private用途なroute tableを割り当てる
    * public用途 = `10.0.0.0/16(local)`, `0.0.0.0/0(gw経由で外部と通信)`
    * private用途 = `10.0.0.0/16(local)`
* 当然gatewayも作成してこのVPCに割り当て
* Network ACLはデフォルトのまま触らない
* __Security Groupsについては後述__


## vagrant-aws 準備・実行

* ec2のkey(pem)は ~/.ssh に置いてあること

```
$ ls -l ~/.ssh
8 -rw-------  1 aho  staff   1696  1 11  2014 [びゃー].pem
```

* AWSのaccess_key_id, secret_access_key, keypair_name 等を環境変数にexportしておく(`Vagrantfile`で適宜参照する、という前提で)

```
export AWS_ACCESS_KEY_ID=HOGEHOGE
export AWS_SECRET_ACCESS_KEY=HUGAHUGA
export AWS_KEYPAIR_NAME=ABABABA
:
```

* vagrant-awsのインストール, 実行

```
$ vagrant -v
Vagrant 1.7.2

# vagrant-awsプラグインのインストール
$ vagrant plugin install vagrant-aws

$ vagrant up --provider=aws  # で実行
```


## Vagrantfile

* `aws.private_ip_address`以下がVPC関連
    * `aws.private_ip_address` は`10.0.0.11`を設定した
* 今回設定を色々と変えつつ試行錯誤した部分には`#★`とコメントを付けた


```ruby:Varantfile
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "dummy"
  config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  config.vm.synced_folder "./", "/vagrant", disabled: true

  config.vm.provider :aws do |aws, override|
    aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
    aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
    aws.keypair_name = ENV['AWS_KEYPAIR_NAME']

    aws.region = ENV['AWS_REGION'] ||= "ap-northeast-1"
    aws.availability_zone = ENV['AWS_AVAILABILITY_ZONE'] ||= "ap-northeast-1c"
    aws.ami = ENV['AWS_AMI_ID'] ||= "ami-cbf90ecb" # amzn-ami-hvm-2015.03.0.x86_64-gp2
    aws.instance_type = ENV['AWS_INSTANCE_TYPE'] ||= "t2.micro"

    override.ssh.username = "ec2-user"
    override.ssh.private_key_path = "~/.ssh/#{ENV['AWS_PRIVATE_KEY_FILE']}"

    aws.private_ip_address = ENV['AWS_PRIVATE_IP'] if ENV['AWS_PRIVATE_IP']

    # public subnet のIDを設定
    aws.subnet_id = ENV['AWS_SUBNET_ID'] if ENV['AWS_SUBNET_ID']

    #★
    aws.associate_public_ip = false # or true
    #★ 
    aws.security_groups = ENV['AWS_SECURITY_GROUP_IDS'].split(',') if ENV['AWS_SECURITY_GROUP_IDS']
  end
```


## 試したパターン

この↓Security Groupsの設定に対して...

|security group | inbound               | outbound |
|:--------------|----------------------:|:------------:|
| (1)default    | Type=ALL Trafic       | Type=ALL Trafic  |
|               | Protocol=ALL          | Protocol=ALL    |
|               | Port Range=ALL        | Port Range=ALL  |
|               | Source=[このgroupのID]| Destination=0.0.0.0/0  |
|    |           |   |
| (2)for SSH    | Type=SSH(22)          | Type=ALL Trafic  |
|               | Protocol=TCP(6)       | Protocol=ALL    |
|               | Port Range=22         | Port Range=ALL  |
|               | Source=0.0.0.0/0      | Destination=0.0.0.0/0  |

Vagrantfile（と環境変数）をこのように組み合わせた

|aws.associate_public_ip | ENV['AWS_SECURITY_GROUP_IDS'] |case|
|:-----------------------|------------------------------:|---:|
| false                  | (1)                           |【1】|
|                        | (1),(2)                       |【2】|
| true                   | (1)                           |【3】|
|                        | (1),(2)                       |【4】|


## case【1】
vagrant, aws, vpc などでググってみると一番見かけた事例。
なのだが、試す前から「public ipを割り当てずにどうやって/どこからSSHするんだろ？」というのが引っ掛かってて、案の定タイトルの事象に遭遇した
ローカルPCから`10.0.0.11`宛にsshしても繋がらんだろ、と思うのだが。。。

```shell-session
$ VAGRANT_LOG=debug vagrant up --provider=aws

DEBUG ssh: Checking key permissions: /Users/aho/.ssh/[pemファイル]
 INFO ssh: Attempting SSH connection...
 INFO ssh: Attempting to connect to SSH...
 INFO ssh:   - Host: 10.0.0.11
 INFO ssh:   - Port: 22
 INFO ssh:   - Username: ec2-user
 INFO ssh:   - Password? false
 INFO ssh:   - Key Path: ["/Users/aho/.ssh/[pemファイル]"]
^C INFO interface: warn: Waiting for cleanup before exiting...
 INFO interface: warn: ==> default: Waiting for cleanup before exiting...
==> default: Waiting for cleanup before exiting...
DEBUG ssh: == Net-SSH connection debug-level log START ==
DEBUG ssh: D, [2015-04-25T21:00:56.067550 #70420] DEBUG -- net.ssh.transport.session[略]: establishing connection to 10.0.0.11:22
DEBUG ssh: == Net-SSH connection debug-level log END ==
 INFO retryable: Retryable exception raised: #<Errno::ECONNREFUSED: Connection refused - connect(2)>

（以下、これの繰り返し）
```

## case【2】
【1】と同事象
外からのsshを許可するSecurity Groupsを追加したとは言え、宛先が`10.0.0.11`だと意味無いよね
（ログは【1】と同じなので省略）

## case【3】
public IPを割り当てるようにしたので、外部からも見える。`vagrant up`時のssh試行ログにも`Host: 52.68.xxx.xxx`とpublic IPが出力されるようになった
とは言えSecurity Groupsをデフォルトのものしか割り当てていない（外部からのinboundは拒否）なので、sshしても繋がらない

```
DEBUG ssh: Checking key permissions: /Users/aho/.ssh/[pemファイル]
 INFO ssh: Attempting SSH connection...
 INFO ssh: Attempting to connect to SSH...
 INFO ssh:   - Host: 52.68.xxx.xxx
 INFO ssh:   - Port: 22
 INFO ssh:   - Username: ec2-user
 INFO ssh:   - Password? false
 INFO ssh:   - Key Path: ["/Users/aho/.ssh/[pemファイル]"]
DEBUG ssh: == Net-SSH connection debug-level log START ==
DEBUG ssh: D, [2015-04-25T21:14:57.477408 #72626] DEBUG -- net.ssh.transport.session[略]: establishing connection to 52.68.56.255:22

DEBUG ssh: == Net-SSH connection debug-level log END ==
 INFO retryable: Retryable exception raised: #<Errno::ECONNREFUSED: Connection refused - connect(2)>

（以下、これの繰り返し）
```

## case【4】 ※これで解決
public IPを割り当てて、外部からのport=22通信を許可するSecurity Groupsを使う
という、後になればそりゃそうだよな というパターンで解決した

```
DEBUG ssh: Checking key permissions: /Users/aho/.ssh/[pemファイル]
 INFO ssh: Attempting SSH connection...
 INFO ssh: Attempting to connect to SSH...
 INFO ssh:   - Host: 52.68.xxx.xxx
 INFO ssh:   - Port: 22
 INFO ssh:   - Username: ec2-user
 INFO ssh:   - Password? false
 INFO ssh:   - Key Path: ["/Users/aho/.ssh/[pemファイル]"]
DEBUG ssh: == Net-SSH connection debug-level log START ==
DEBUG ssh: D, [2015-04-25T22:14:43.906276 #79794] DEBUG -- net.ssh.transport.session[略]: establishing connection to 52.68.xxx.xxx:22
D, [2015-04-25T22:14:43.918466 #79794] DEBUG -- net.ssh.transport.session[略]: connection established
I, [2015-04-25T22:14:43.918693 #79794]  INFO -- net.ssh.transport.server_version[略]: negotiating protocol version
D, [2015-04-25T22:14:43.934849 #79794] DEBUG -- net.ssh.transport.server_version[略]: remote is `SSH-2.0-OpenSSH_6.2'
D, [2015-04-25T22:14:43.934999 #79794] DEBUG -- net.ssh.transport.server_version[略]: local is `SSH-2.0-Ruby/Net::SSH_2.9.2 universal.x86_64-darwin12.5.0'
```