terraformによるamazonVPCセキュリティグループのicmpルール作成

##はじめに

terraformを使ったセキュリティグループの管理はちょこっと癖がありますよね。
（terraformというよりAWSAPIの癖って気もしますが。。）
指定方法が特殊なICMPのルールについて自分自身の備忘も兼ねて纏めておこうと思います。

##terraform公式ドキュメントの記載内容

基本的な書式

```
resource "aws_security_group_rule" "allow_all" { 
  type = "ingress" 
  from_port = 0 
  to_port = 65535 
  protocol = "tcp" # Opening to 0.0.0.0/0 can lead to security vulnerabilities. 
  cidr_blocks = # add a CIDR block here 
  prefix_list_ids = [ 
    "pl-12c4e678" 
  ] 
  security_group_id = "sg-123456" 
}
```

icmpルールの場合、ポイントになるのは以下の部分です。

**protocol** （必須）プロトコル。 icmp、icmpv6、tcp、udp、またはすべてがプロトコル番号を使用しない場合
**from_port** （必須）開始ポート（または*プロトコルが「icmp」または「icmpv6」の場合はICMPタイプ番号*）
**to_port** （必須）エンドポート（または*プロトコルが「icmp」の場合はICMPコード*）

要約するとICMPルールの時は以下を指定しろって事のようですね。

* protocolに「icmpまたはicmpv6」
* from_portに「icmpタイプ番号」
* to_portに「icmpコード」

##ICMPタイプ番号

from_portに「ICMPタイプ番号」というのは少し違和感がありますが、
ICMPにはポート番号という概念が無いので、TYPEを代わりに指定するイメージですか。
ICMPには以下のTYPEがあります。
※v6の場合は番号が異なるので注意


| Type |           内容          | 意味                             |
|:-----|------------------------:|:---------------------------------|
| 0    | Echo Reply              | エコー応答                       |
| 3    | Destination Unreachable | 宛先到達不能                     |
| 4    | Source Quench           | 始点抑制                         |
| 5    | Redirect                | 最適経路への変更指示             |
| 8    | Echo Request            | エコー要求                       |
| 9    | Router Advertisement    | ルータ通知                       |
| 10   | Router Solicitation     | ルータ要求                       |
| 11   | Time Exceeded           | TTL超過によるパケット破棄の報告  |
| 12   | Parameter Problem       | パケットパラメータにおけるエラー |
| 13   | Timestamp               | タイムスタンプ                   |
| 14   | Timestamp Reply         | タイムスタンプ応答               |
| 15   | Information Request     | インフォメーション要求           |
| 16   | Information Reply       | インフォメーション応答           |
| 17   | Address Mask Request    | アドレスマスク要求               |
| 18   | Address Mask Reply      | アドレスマスク応答               |

よく使うのはPING=エコー要求の「8」でしょうか。

##ICMPコード

to_portに「icmpコード」
個人的に少し悩みどころだったのですが、**ICMPコードはICMPタイプによってあるものとないものがあります。**
調べた感じ、ICMPコードがあるのは「ICMP Type3」「ICMP Type5」「ICMP Type9」「ICMP Type11」「ICMP Type12」みたいですね。
※それぞれのcodeは後で時間があれば纏めるかも。ちなみに後述しますが全てのCODEを対象にする場合は「-1」です。

ICMPコードがあるものはその番号を指定すれば良いでしょうが、ここでの問題は**ICMPコードがないものは何を指定すりゃええねん！**って部分ですよね。（自分はすごく悩みました）
よく利用されるであろうエコー要求もICMPコードがない部類ですね。コンソールだと「該当なし」になりますが、CLIでそれをどう表現するんだ。。

で、一生懸命探したところ、terraformでは**icmpコードなし=「0」を指定せよ**ってことみたいです。
※AWSCLIのリファレンスでは「0」or「-1」がicmpコードなしとして有効な値らしいですが、terraformから実行する場合「-1」は無効な値と判定されるっぽい（実際には試してませんが）ただ、AWSAPI側では「0」を指定しても「-1」に値が変換されて設定されている可能性があるとのこと。う、うん？って感じ。そこは足並みを揃えて欲しいですね。

まあ纏めると以下になるかと。

* ICMPコードがあるものは、指定したいコードまたは「-1」 　※「-1」は「すべて」の意
* ICMPコードがないものは、「0」を指定

##すべてのICMP
ここまでの内容だけでは、まだ足りないものがあります。
そう、**「すべてのICMP」を許可するルールはどう作るねん**って話ですね。

まあ、これに関してはAWSCLIのリファレンスを信じて問題なさそうです。
https://docs.aws.amazon.com/cli/latest/reference/ec2/authorize-security-group-ingress.html

AWSCLIのリファレンスから重要な部分を抜粋すると以下です。
`ICMP/ICMPv6 の場合は、ICMP/ICMPv6 タイプおよびコードも指定する必要があります。-1 を使用すると、すべての種類またはすべてのコードを意味できます。`

要約すると以下ですかね。

* 全てのicmpタイプ = 「-1」を指定する
* 全てのicmpコード = 「-1」を指定する

なので、「すべてのICMP」を表すのは以下になります。

```
     protocol  = "icmp"
     from_port = -1
     to_port   = -1
```

##まとめ

terraformからPINGを許可するセキュリティルールはどう指定するん？

```
resource "aws_security_group_rule" "allow_ping" { 
  type = "ingress" 
  from_port = 8 
  to_port   = 0 
  protocol  = "icmp"
  cidr_blocks = "0.0.0.0/0"
  security_group_id = "sg-123456" 
}
```

terraformからすべてのICMPを許可するセキュリティルールはどう指定するん？

```
resource "aws_security_group_rule" "allow_icmp_all" { 
  type = "ingress" 
  from_port = -1 
  to_port   = -1 
  protocol  = "icmp"
  cidr_blocks = "0.0.0.0/0"
  security_group_id = "sg-123456" 
}
```

##簡単な調べ方
今回は正確な裏付け情報を得るためにリファレンスとかを漁りましたが、簡単に調べる方法もあります。

**コンソールから手でルールを作成して、それがどんな値で設定されているか調べる**という方法ですね。（こっちのが確実かも）

CLIで確認するなら`aws ec2 describe-security-groups`ですかね。
※ただ、ICMPコードの時みたいに「cliでは有効だけどterraformでは無効な値」とかあるかもしれないのが困りものですが。

terraformなら`terraform import`ですね。
> terraform import aws_security_group.<セキュリティグループ> 

上記方法は実際には試してないのですが、`terraform import`なら正確な設定値が返ってきそうな気がしますね。（時間がある時にエコー要求のルールでどんな値が返ってくるか検証してみようかなー。。）