この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、大阪オフィスのかずえです。
前回お伝えした通り、Terraformを使い始めました。
今回は、初めてのTerraform案件にて私がやってしまった失敗をお話しします。
初歩的な内容で恐縮ですが、以後同じ轍を踏む方がいらっしゃらないよう。。
やりたかったこと
踏み台インスタンス経由でprivateサブネットにあるインスタンスにRDP接続をすることです。(Windowsインスタンスです)
- 踏み台インスタンス用のSecurity Groupを作成します。
- publicサブネットに踏み台インスタンスを作成し、上記Security Groupをアタッチします。
- privateサブネットインスタンス用のSecurity Groupを作成します。送信元は上記踏み台用Security Group(がアタッチされているリソース)のみ許可します。
- privateサブネット上にインスタンスを作成し、上記Security Groupをアタッチします。
コード
抜粋していますが、だいたいこんな感じです。(TerraformのVersionは0.12です)
resource "aws_security_group" "bastion" {
name = "bastion-sg"
description = "bastion-sg"
vpc_id = "(VPCのid)"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
cidr_blocks = [
"(自分のIP)",
]
}
}
resource "aws_security_group" "app" {
name = "app"
description = "app"
vpc_id = "(VPCのid)"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}
}
resource "aws_instance" "bastion" {
ami = "ami-04d0f44a3c739f093"
availability_zone = "ap-northeast-1a"
instance_type = "t2.micro"
tags = {
Name = "test-bastion"
}
vpc_security_group_ids = [aws_security_group.bastion.id]
subnet_id = "(public subnetのid)"
root_block_device {
volume_size = 30
volume_type = "gp2"
}
}
resource "aws_instance" "app" {
ami = "ami-04d0f44a3c739f093"
availability_zone = "ap-northeast-1a"
instance_type = "m5.large"
tags = {
Name = "test-app"
}
vpc_security_group_ids = [aws_security_group.app.id]
subnet_id = "(private subnetのid)"
root_block_device {
volume_size = 30
volume_type = "gp2"
}
}
…何がマズイかお分かりになりましたでしょうか?
起きた不具合
- オフィスから踏み台インスタンス(bastion)にはRDPできる(OK)
- 踏み台インスタンスからprivateサブネットのインスタンス(app)にRDP接続できない!
- appのSecurity Groupを全開放にしてみる → 接続できない!
- appと同じ構成のインスタンスをpublic subnetに作成してみて踏み台から接続 → できない!
- appのWindowsファイアウォールは停止しているので関係なさそう
- NACLも設定していないから関係なさそう
原因
セキュリティグループのアウトバウンドの記述をしていなかったから。
はい。Terraformはセキュリティグループを作成する時、アウトバウンドのルールも明記する必要があります。egress
という引数がそれです。
Terraform AWS provider Resource: aws_security_group
この設定が無い場合、作成されるSecurity Groupのアウトバウンドは全拒否になります。
実際に上記tfファイルで作成されたSecurity Groupをコンソールで確認してみましょう。
このように何もルールがありません。
ちなみに、コンソールで作った場合はどうなるかというと、
このようにデフォルトで全許可のルールが設定されます。
今回の場合、踏み台インスタンスのSecurity Groupのアウトバウンドルールのせいで、踏み台インスタンスからappにRDP接続する際に、踏み台インスタンスから外に通信が出れていなかったわけです。
普段アウトバウンドのルールを設定することが無い(デフォルトの全許可のまま)のことが多いので、この部分を意識せずappインスタンス側の問題点がないかというところばかり調査していました。。
対処法
Security Groupリソース欄にegress引数を追加します!
resource "aws_security_group" "bastion" {
name = "bastion-sg"
description = "bastion-sg"
vpc_id = "(VPCのid)"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
cidr_blocks = [
"(自分のIP)",
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "app" {
name = "app"
description = "app"
vpc_id = "(VPCのid)"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
まとめ
という訳で、Terraformでセキュリティグループを作成する場合は、アウトバウンド(egress)も明示的に定義しましょう。しましょう。します。