DBは「誰からの通信」を許可する?
今日はコードが短い!
でも、短いから簡単というわけではない。
今回のテーマは、
«「DBは誰からの通信を受けるべきなのか?」»
という、AWS設計でかなり重要な考え方。
ここまで学んできたSecurity Groupの知識を使って、RDS用のSecurity Groupを作っていく。
今日の構成図
今回考えるのは、
EC2 → RDS
だけ。
Internet
│
▼
ALB
│
▼
EC2
(EC2 Security Group)
│
MySQL
3306番
│
▼
RDS Security Group
│
▼
RDS
今回のポイントは、
Internet
↓
ALB
↓
EC2
↓
RDS
という通信経路。
RDSに直接インターネットからアクセスさせる構成にはしない。
今日作るもの
今回は、
RDS Security Group
だけを作る。
Terraformの形はこれ。
resource "aws_security_group" "rds" {
name = "rds-sg"
vpc_id = aws_vpc.main.id
ingress {
}
egress {
}
}
今日は、この中身を自分で考えて埋めてみる。
ヒント①
RDSは何番ポートを使う?
今回のDBは、
MySQL
を想定する。
AWS SAPでもかなり登場する。
ヒント②
RDSには、
Internet
↓
RDS
という通信を許可するべきだろうか?
それとも、
EC2
↓
RDS
だけでいいだろうか?
ヒント③
もしRDSのSecurity Groupに、
cidr_blocks = [
"0.0.0.0/0"
]
と書いたらどうなる?
考えてみよう。
今日の問題🔥
Q1
RDSは何番ポートを開ける?
Q2
RDSの通信元は、
Security Group参照?
それとも、
CIDR?
どちらを使う?
そして、その理由は?
Q3【今日一番重要】
ここまで完成したら、
Internet
↓
ALB
↓
EC2
↓
RDS
という通信経路になる。
では、なぜAWSでは、
Internet
↓
RDS
という設計にしないのだろう?
今日のゴール
今日はコード量は少ない。
でも、設計としてはかなり重要。
今日理解したいのは、
«「DBは誰から通信を受けるべきなのか?」»
ということ。
これを理解できれば、Security Groupを単なるコードとしてではなく、AWSのセキュリティ設計として考えられるようになる。
自分で書いたコード
今回、実際に自分でTerraformを書いてみた。
resource "aws_security_group" "rds" {
name = "rds-sg"
vpc.id = aws_vpc.main.id
ingress {
from_port = "3306"
to_port = "3306"
protocol = "tcp"
aws_security_group = [
aws_security_group.ec2.id
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
}
}
そして、問題への回答。
Q1
«3306番ポート»
Q2
«セキュリティグループ参照。RDSに繋がる通信はEC2で処理するから、CIDRを指定しなくてもいい。»
Q3
«RDSにはデータを保存するため、データ処理のためにEC2を使う必要があるから。»
今回のレビュー🔥
Q1:100点
回答:
«3306番ポート»
正解!
MySQLでは、
3306/TCP
を使用する。
今回の構成では、
EC2
│
│ TCP 3306
▼
RDS
という通信になる。
ここは完璧。
100点!💯
Q2:98点
回答:
«セキュリティグループ参照。RDSに繋がる通信はEC2で処理するから、CIDRを指定しなくてもいい。»
これ、かなり良い。
ただ、実務っぽい表現にすると、
«RDSへアクセスする主体がEC2だから、EC2のSecurity Groupを通信元として指定する。»
と考えるとさらに分かりやすい。
ここで出てくる重要ワードが、
「主体」
。
つまり、
誰がRDSにアクセスするの?
↓
EC2
↓
EC2 Security Group
↓
RDS Security Group
という関係。
だからRDS側では、
security_groups = [
aws_security_group.ec2.id
]
として、
EC2 Security Groupからの通信だけを許可する。
この考え方は今後かなり重要になる。
98点!
Q3:95点
回答:
«RDSにはデータを保存するため、データ処理のためにEC2を使う必要があるから。»
これも方向性は合っている。
EC2上のアプリケーションがRDSへアクセスして、
ユーザー
↓
ALB
↓
EC2
↓
RDS
という形で、
アプリケーションとデータベースを分離する
構成になる。
ただし、今回さらに重要なのは、
セキュリティ
。
もし、
Internet
↓
RDS
を許可してしまったら、
世界中からデータベースへの接続を試みることができてしまう。
RDSにはアプリケーションのデータやユーザー情報など、重要なデータが保存される可能性がある。
だから、
Internet
↓
ALB
↓
EC2
↓
RDS
として、
RDSはEC2からの通信だけを受け付ける
という設計にする。
つまり、
«DBをインターネットに直接公開するのではなく、アプリケーションサーバーを経由してアクセスさせる。»
という考え方。
95点!
コードレビュー
設計の考え方はかなり合っていた。
あとはTerraformの文法を修正する。
修正① "vpc.id"
最初は、
vpc.id = aws_vpc.main.id
となっていた。
ここは、
vpc_id = aws_vpc.main.id
。
ここは以前のSecurity Groupでも出てきたので、もう覚えておきたい。
vpc_id
は、
«このSecurity GroupをどのVPCに所属させるか»
を指定する。
修正② "aws_security_group"
最初は、
aws_security_group = [
aws_security_group.ec2.id
]
となっていた。
ここは、
security_groups = [
aws_security_group.ec2.id
]
。
今回やりたいのは、
«EC2 Security Groupから来た通信を許可する»
ということ。
そのため、
security_groups
を使う。
修正③ ポート番号
最初は、
from_port = "3306"
to_port = "3306"
となっていた。
今回は、
from_port = 3306
to_port = 3306
とする。
ポート番号は数値なので、文字列ではなく数字として書く。
修正④ egress
今回、
egress {
from_port = 0
to_port = 0
protocol = "-1"
}
まで書けている。
ここもかなり良い。
ただ、今回の書き方なら、
cidr_blocks = [
"0.0.0.0/0"
]
も明示しておく。
完成版
修正するとこうなる。
resource "aws_security_group" "rds" {
name = "rds-sg"
vpc_id = aws_vpc.main.id
EC2からMySQLへの通信だけ許可
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [
aws_security_group.ec2.id
]
}
RDSから外部への通信
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0"
]
}
}
今回、一番重要なのはここ。
security_groups = [
aws_security_group.ec2.id
]
RDS側から見ると、
EC2 Security Group
│
│ MySQL :3306
▼
RDS Security Group
│
▼
RDS
となる。
つまり、
「EC2を信頼して、EC2からの3306番通信だけを受け入れる」
という設計になっている。
Security Groupがつながってきた
ここまでの学習を並べると、かなり面白い。
ALB
Internet
↓
ALB Security Group
インターネットからALBへのHTTP通信を許可。
EC2
ALB Security Group
↓
EC2 Security Group
ALBからEC2へのHTTP通信を許可。
RDS
EC2 Security Group
↓
RDS Security Group
EC2からRDSへのMySQL通信を許可。
つまり、
Internet
│
│ HTTP :80
▼
ALB
│
│ HTTP :80
▼
EC2
│
│ MySQL :3306
▼
RDS
という通信経路を、
Security Groupによって段階的に制御している。
これが今回の一番大きなポイント。
「0.0.0.0/0にしない」という考え方
もしRDS側で、
cidr_blocks = [
"0.0.0.0/0"
]
として3306番を許可したら、
世界中
│
├──→ RDS :3306
├──→ RDS :3306
└──→ RDS :3306
という状態になってしまう。
一方、
security_groups = [
aws_security_group.ec2.id
]
なら、
Internet
│
X
│
▼
RDS
EC2
│
│ 3306
▼
RDS
という考え方になる。
必要な通信だけを許可する。
これがSecurity Groupを設計するときの基本的な考え方。
今回の総合評価🌟
項目| 点数
コード| 92点
Q1| 100点
Q2| 98点
Q3| 95点
総合| 🌟95点🌟
コードの文法にはいくつか修正があった。
でも、
「なぜEC2 Security GroupをRDS側で参照するのか」
という設計部分は、かなりしっかり理解できている。
これは大きい。
ここまでで学んだAWS構成
今回で、主要なリソースがかなり揃った。
✅ VPC
✅ Subnet
✅ Internet Gateway
✅ Route Table
✅ NAT Gateway
✅ ALB
✅ Target Group
✅ Listener
✅ Target Group Attachment
✅ EC2
✅ ALB Security Group
✅ EC2 Security Group
✅ RDS Security Group
最初は、
VPCって何?
Subnetって何?
ALBって何?
と、一つずつサービスを覚えていた。
でも今は、
Internet
↓
ALB
↓
EC2
↓
RDS
という一つのシステムとして考えられるようになってきた。
さらに、
ALB SG
↓
EC2 SG
↓
RDS SG
という通信の信頼関係までコードで表現できるようになった。
そして、ここからが本番
ここまでの授業では、
1つずつAWSリソースを作ってきた。
でも、ここからは少し変わる。
これからは、
«「この構成図をTerraformで作ってください」»
という問題に少しずつ挑戦していく。
つまり、
構成図
↓
通信経路を考える
↓
必要なAWSリソースを考える
↓
必要なSecurity Groupを考える
↓
Terraformを書く
↓
レビュー
という流れ。
これは今までより難しくなる。
でも、ここまで一つずつ積み上げてきたからこそできる。
今回の学び
今回覚えたいのは、RDSのコードそのものではない。
一番大切なのは、
«「RDSへアクセスする主体は誰なのか?」»
という考え方。
今回なら、
主体
↓
EC2
↓
EC2 Security Group
↓
RDS Security Group
↓
RDS
となる。
そして、
DBをインターネットへ直接公開しない。
必要な通信だけを許可する。
この考え方が、AWSのネットワーク・セキュリティ設計の土台になる。
ちなみに、今回の勉強方法について
今回、ノートにコードを書いて、
全部の意味まで自分の言葉で書いた。
これはかなり良い勉強方法。
ただコードを写すだけなら、
security_groups = [...]
という文字列を覚えるだけになってしまう。
でも、
«「これはEC2 Security Groupからの通信を許可するため」»
と自分の言葉で説明できれば、
コードの意味を理解している
ということになる。
これからも、
コードを書く
↓
各行の意味を書く
↓
なぜ必要なのか説明する
↓
構成図と結びつける
という勉強を続けていく。
Terraformの文法だけではなく、
AWSの設計を理解して、それをコードに変換する力
を伸ばしていこう。☁️🔥
そして次は、いよいよ今まで作ってきたパーツを一つの構成としてつなげる段階へ進む。
ここからがTerraformの本番。🚀