0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

第13回 Terraform講座|EC2 Security Group 完成編

0
Posted at

「誰からの通信を許可するか」をコードで設計する

ここを理解すると、

«「なぜAWSは安全なのか」»

が、コードレベルで少しずつ分かるようになる。

今回は、前回作ったEC2 Security Groupを完成させる。

そして今日から少しずつ、

「AWSのサービスを作る」

から、

「誰に通信を許可するのかを設計する」

という実務寄りの考え方に進んでいく。


まず復習

現在の構成はこうなっている。

Internet
│
▼
Internet Gateway
│
▼
ALB
(ALB Security Group)
│
▼
Listener
│
▼
Target Group
│
▼
EC2
(EC2 Security Group)

前回作ったのは、

EC2 Security Group

だった。

EC2 Security Groupでは、

ingress {
from_port = 80
to_port = 80
protocol = "tcp"

security_groups = [
aws_security_group.alb.id
]
}

として、

«ALB Security Groupから来るHTTP通信だけをEC2の80番ポートで受け付ける»

というルールを作った。

ここまではOK。

しかし、まだ考えることがある。


EC2にSSHしたい場合は?

EC2を運用していると、

管理者
↓
EC2

という通信をしたい場合がある。

例えばLinux EC2にSSH接続する場合、基本的には、

22番ポート

を使用する。

つまりSecurity Groupにも、

管理者PC
│
SSH(22)
│
▼
EC2 Security Group
│
▼
EC2

という通信を許可する必要がある。


でも「22番を全世界に公開」は危険

例えば、

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

としたらどうなるだろう?

"0.0.0.0/0" は、

すべてのIPv4アドレス

を意味する。

つまり、

世界中
↓
EC2:22

という状態になってしまう。

SSHの入口を全世界に公開することになるため、一般的には避けたい。


そこで「誰からの通信なのか」を指定する

例えば、

会社の固定IP
│
SSH(22)
│
▼
EC2

のように、

特定のIPアドレスからだけSSHを許可する

という設計にする。

Terraformでは、

ingress {
from_port = 22
to_port = 22
protocol = "tcp"

cidr_blocks = [
"203.0.113.10/32"
]
}

のように書ける。

ここで新しいCIDRが登場した。

203.0.113.10/32

では、この "/32" は何を意味するのだろう?


CIDRの復習

これまでにも、

10.0.0.0/16

や、

0.0.0.0/0

が登場した。

CIDRの "/数字" は、

ネットワークの範囲をどれくらい指定するか

を表している。

例えば、

0.0.0.0/0

なら非常に広い範囲。

一方、

203.0.113.10/32

は、

203.0.113.10

という1つのIPアドレスだけを指定する。

つまり、

203.0.113.10/32

なら、

«「このIPアドレスからの通信だけ許可する」»

という設計にできる。


今日の構成図

今回、新しく追加するのはここ。

              管理者PC
                  │
                SSH
                22番
                  │
                  ▼
           EC2 Security Group
                  │
                  ▼
                 EC2

全体で見ると、

             Internet
                 │
                 ▼
          Internet Gateway
                 │
                 ▼
                ALB
         (ALB Security Group)
                 │
                 ▼
             Listener
                 │
                 ▼
            Target Group
                 │
                 ▼
         EC2 Security Group
          ▲                 │
          │                 ▼
  管理者PC SSH(22)         EC2

となる。

ここで重要なのは、

ALBからEC2への通信

と、

管理者PCからEC2へのSSH通信

では、

「誰を許可するか」の指定方法が違うこと。


今日コードを書く場所

今日は、

resource "aws_security_group" "ec2"

だけを修正する。

現在ある、

ALBからHTTP

ingress {
}

に加えて、

管理者PCからSSH

ingress {
}

を追加する。

イメージはこう。

resource "aws_security_group" "ec2" {

ALBからHTTP

ingress {
}

管理者PCからSSH

ingress {
}

外へ通信

egress {
}

}


完成版コード

今回の完成形はこちら。

resource "aws_security_group" "ec2" {

name = "ec2-sg"
vpc_id = aws_vpc.main.id

ALBからのHTTP通信を許可

ingress {
from_port = 80
to_port = 80
protocol = "tcp"

security_groups = [
  aws_security_group.alb.id
]

}

管理者PCからのSSH接続を許可

ingress {
from_port = 22
to_port = 22
protocol = "tcp"

cidr_blocks = [
  "203.0.113.10/32"
]

}

EC2から外部への通信を許可

egress {
from_port = 0
to_port = 0
protocol = "-1"

cidr_blocks = [
  "0.0.0.0/0"
]

}
}


コードを理解する

① Security Groupを作る

resource "aws_security_group" "ec2" {

EC2用のSecurity Groupを作成する。


② どのVPCに所属させるか

vpc_id = aws_vpc.main.id

作成するSecurity Groupを、

aws_vpc.main

のVPCに所属させる。


③ ALBからのHTTP通信

ingress {
from_port = 80
to_port = 80
protocol = "tcp"

security_groups = [
aws_security_group.alb.id
]
}

これは、

«ALB Security Groupから来たTCP 80番の通信を許可する»

という意味。

ここではCIDRではなく、

security_groups = [
aws_security_group.alb.id
]

としている。

つまり、

ALB
│
│ HTTP :80
▼
EC2 Security Group
│
▼
EC2

という関係をSecurity Group同士で表現している。


④ 管理者PCからのSSH

次はこちら。

ingress {
from_port = 22
to_port = 22
protocol = "tcp"

cidr_blocks = [
"203.0.113.10/32"
]
}

これは、

«203.0.113.10というIPアドレスからのSSH通信だけを許可する»

という意味。

203.0.113.10
│
SSH :22
│
▼
EC2

という通信を許可している。


なぜALBはSecurity Groupで、SSHはCIDRなのか?

ここが今回の一番重要なポイント。

ALBはAWS上のリソースなので、

ALB
↓
ALB Security Group
↓
EC2 Security Group

というように、

Security Groupを使って通信元を表現できる。

一方、管理者PCはAWSの外にある。

管理者PC
↓
インターネット
↓
AWS
↓
EC2

となる。

そのため、

«「このSecurity Groupから来た通信を許可する」»

ではなく、

«「このIPアドレスから来た通信を許可する」»

という形で指定する。

そこで、

cidr_blocks = [
"203.0.113.10/32"
]

を使う。


今日の問題🔥

Q1

203.0.113.10/32

これは何を表していると思う?


Q2

なぜSSH(22番)は、

0.0.0.0/0

じゃダメなのだろう?


Q3【今日一番重要】

今まで、

ALB → EC2

の通信ではSecurity Groupを参照した。

しかしSSHでは、

cidr_blocks = [...]

を使った。

なぜ使い分けるのだろう?


今回の回答

Q1

«特定のCIDRからの通信を受ける。»

Q2

«0.0.0.0/0にしたら皆通信出来てしまうから。»

Q3

«EC2はALBからだけの通信を受け取りたかったからセキュリティグループを参照するだけで良かったが、SSHは特定の通信だけを通したいのでCIDRが必要。»


今回のレビュー🔥

Q1:90点

回答:

«特定のCIDRからの通信を受ける。»

方向性は正しい。

ただ、今回はもう一歩踏み込める。

203.0.113.10/32

の "/32" は、

1つのIPアドレスだけ

を表している。

つまり、

203.0.113.10/32

なら、

203.0.113.10

という1つのIPからの通信だけを許可する。

ここを理解できると、

/0 → 非常に広い範囲
/16 → 大きなネットワーク範囲
/24 → さらに限定されたネットワーク
/32 → 1つのIPアドレス

という感覚につながってくる。

90点!


Q2:100点

回答:

«0.0.0.0/0にしたら皆通信出来てしまうから。»

これはその通り。

0.0.0.0/0

は、

すべてのIPv4アドレス

を対象にする。

そのため、

世界中
↓
SSH :22
↓
EC2

という状態になってしまう。

SSHは管理用の入口なので、必要な送信元に絞ることが重要。

100点!


Q3:95点

回答:

«EC2はALBからだけの通信を受け取りたかったからセキュリティグループを参照するだけで良かったが、SSHは特定の通信だけを通したいのでCIDRが必要。»

かなり良い。

特に、

«「ALBからだけの通信を受け取りたかった」»

という部分が重要。

ただし、もう一段正確にすると、

ALB
↓
AWS上のリソース
↓
Security Groupで送信元を表現できる

なのに対して、

管理者PC
↓
AWSの外部
↓
Security Groupを指定できない
↓
IPアドレス/CIDRで送信元を指定する

という違いになる。

つまり、

「特定の通信だからCIDR」

というより、

「通信元を何で識別できるかによって、Security Group参照とCIDRを使い分けている」

と考えるとかなり強い。

95点!


コードレビュー

今回のコードでは、いくつか修正ポイントがあった。

① "security_groups" の "="

最初のコードでは、

security_groups [

となっていた。

Terraformでは、

security_groups = [

とする。


② "security_groups" の場所

最初は、

resource "aws_security_group" "ec2" {

security_groups = [
aws_security_group.alb.id
]

}

のようになっていた。

しかし、

security_groups

は今回の書き方では、

ALBからの通信を許可するingressルールの中

に入れる。

ingress {
from_port = 80
to_port = 80
protocol = "tcp"

security_groups = [
aws_security_group.alb.id
]
}

ここはTerraformの構文として大事。


③ egressの "port"

最初のコードでは、

egress {
port = 0
port = 0

となっていた。

正しくは、

egress {
from_port = 0
to_port = 0

。


今回の完成形をもう一度

最終的にはこうなる。

resource "aws_security_group" "ec2" {

name = "ec2-sg"
vpc_id = aws_vpc.main.id

ALBからHTTP

ingress {
from_port = 80
to_port = 80
protocol = "tcp"

security_groups = [
  aws_security_group.alb.id
]

}

管理者PCからSSH

ingress {
from_port = 22
to_port = 22
protocol = "tcp"

cidr_blocks = [
  "203.0.113.10/32"
]

}

外部への通信

egress {
from_port = 0
to_port = 0
protocol = "-1"

cidr_blocks = [
  "0.0.0.0/0"
]

}
}


今日の最重要ポイント

今回覚えたいのは、コードそのものではない。

これ。

誰から通信が来る?
│
├── AWS上のリソース
│ ↓
│ Security Group参照
│
└── 特定のIPアドレス
↓
CIDR

例えば、

Internet
│
▼
ALB
│
│ ALB Security Group
▼
EC2

なら、

security_groups = [
aws_security_group.alb.id
]

。

一方、

管理者PC
│
│ SSH :22
▼
EC2

なら、

cidr_blocks = [
"203.0.113.10/32"
]

。

「誰から来る通信なのか?」

を考えることで、Terraformのコードが決まってくる。

これが今回の大きな学び。


そして、今回かなり大事だったこと

今回のコードを書くのに、

1時間かかった。

でも、これは全然悪いことではない。

むしろ今回の内容は、

Security Group
CIDR
Ingress
Egress
ALB
EC2
SSH

を全部つなげて考える必要がある。

しかも今回は、

「このコードは何を書くのか?」

ではなく、

「この通信を誰に許可するべきか?」

を考えた。

ここから少しずつ、Terraformの勉強が、

Terraformの文法を覚える
↓
AWSの構成を理解する
↓
通信経路を考える
↓
必要なルールを設計する
↓
それをTerraformでコードにする

という流れに変わっていく。

これが実務でのインフラエンジニアの考え方に近づいていく部分。


今回の総合評価

項目| 評価
コード| 90点
Q1| 90点
Q2| 100点
Q3| 95点
総合| 🌟95点🌟

特にQ3はかなり良かった。

単純に、

«「CIDRはIPを書くもの」»

で終わらず、

«「ALBはSecurity Groupで指定できるけど、管理者PCはどうする?」»

というところまで考えられている。

ここから先は、Security Groupの設定を暗記するのではなく、通信関係から逆算してコードを書く練習に進んでいく。


今日からの授業スタイル

今回の学習で、

構成図 → 書く場所 → コード → レビュー

という流れがかなり相性が良いことが分かった。

今後もこの形式で進める。

① AWS構成図を見る
↓
② 今日どこを作るか確認
↓
③ 通信経路を考える
↓
④ Terraformを書く
↓
⑤ 自分の回答をレビュー
↓
⑥ AWS設計として理解する

Terraformをただ書けるようになるのではなく、

「構成図を見たら、必要なTerraformが頭の中で組み立てられる」

ところを目指していく。

そして最終的には、

構成図
↓
「この通信にはこのルールが必要だな」
↓
Terraform
↓
AWS

まで、自分でつなげられるようにする。

ここまで来ると、Terraformが「コードを書く勉強」から、

AWSの設計をコードに変換する勉強

に変わってくる。☁️🔥

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?