やりたいこと
- サービスプロジェクトで外部IPが制限している制約下で、特定のサブネットのみインターネット通信を許可したい
- プロジェクトのサブネット内でのみ通信を許可し、プロジェクト外のサブネット間通信は拒否したい
- VPC内のインスタンスに対してIAP経由でのみsshを許可する
VPC
- awsではVPCでIP範囲を持つが、gcpではvpcにIP範囲を持たない
そのため、サブネット単位でIP範囲を指定するため、VPCのIP制約なく追加可能 - awsのVPCは特定のリージョンに存在するが、gcpのvpcはグローバルリソースである
gcpの場合はリージョン間通信に追加のリソースが必要ない
通信制御
- awsではセキュリティグループやACLがあるが、GCPではファイアウォールとなる
- ネットワークタグやIP範囲等を使用してフィルタできるステートレスなルールを設定できる
実装
構築するリソース
- Cloud RouterおよびNATの構成(外部IPを持ち、外向きインターネット通信を可能にする)
- 共有VPC(ネットワーク管理をプロジェクトで分離することができる)
- 権限付与(IAP経由でssh可能、共有VPC利用のためサービスプロジェクトでComputeネットワークユーザロール付与)
terraform
※countを使用するのでなく、set, each_forのほうがよさそう(stateファイルに保存される際、配列のキーがインデックスかリソース名の違い。インデックスだと何らかの変更を加えた際に別物だと認識し破壊と再作成の挙動が生じる)
※google_project_iam_bindingの使用は推奨されていない。複数のgoogle_project_iam_bindingを使用するとどれか一つしかプロビジョニングされない
ホストプロジェクトとして有効化するプロジェクトを指定する
resource "google_compute_shared_vpc_host_project" "hostpj" {
project = google_project.network_host_project.id
}
#サービスプロジェクトとして有効化するプロジェクトをループして指定する
resource "google_compute_shared_vpc_service_project" "servicepj" {
count = "var.number_of_project"
host_project = google_compute_shared_vpc_host_project.hostpj.project
service_project = "element(google_project.project, count.index).id}"
}
#共有VPCとするVPCを作成する
resource "google_compute_network" "shared_vpc" {
project = google_project.network_host_project.id
name = "shnw-prd-asne1-sharedvpc"
auto_create_subnetworks = false
mtu = 1460
}
#サービスプロジェクトごとに共有するサブネットをホストプロジェクト側で作成する
resource "google_compute_subnetwork" "shared_subnets" {
project = google_project.network_host_project.id
count = "var.number_of_project"
name = "shnw-prd-asne1-sbn${count.index}"
ip_cidr_range = "10.0.${count.index+1}.0/24"
region = var.gcp_region
network = google_compute_network.shared_vpc.id
}
# サービスプロジェクト側で共有VPCが利用可能なようにComputeネットワークユーザロールを付与する
resource "google_compute_subnetwork_iam_binding" "shared_subnet_iam_binding" {
count = "var.number_of_project"
project = google_project.project, count.index).id
region = element(google_compute_subnetwork.shared_subnets, count.index).region
subnetwork = element(google_compute_subnetwork.shared_subnets, count.index).id
role = "roles/compute.networkUser"
members = [
"user:XXXXXXXXX",
]
}
# CloudNATをホストプロジェクトで定義
resource "google_compute_router_nat" "nat" {
name = "shnw-prd-asne1-cnat"
project = replace(google_project.network_host_project.id
region = var.gcp_region
router = google_compute_router.router.name
source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"
nat_ip_allocate_option = "AUTO_ONLY"
# 共有VPC用のサブネット分だけループする
dynamic "subnetwork" {
for_each = google_compute_subnetwork.shared_subnets
content {
name = subnetwork.value.id
source_ip_ranges_to_nat = ["ALL_IP_RANGES"]
}
}
log_config {
enable = true
filter = "ALL"
}
depends_on = [google_compute_subnetwork.shared_subnets]
}
# NATを構成するルータの設定
resource "google_compute_router" "router" {
name = "router"
project = google_project.network_host_project.id
region = var.gcp_region
network = google_compute_network.shared_vpc.id
}
# 共有VPCで80,8080ポート通信を許可するようにFirewallを設定する。
resource "google_compute_firewall" "allow_internet" {
description = "共有VPCから外向けにhttp,https通信を許可します"
project = google_project.network_host_project.id
name = "shnw-prd-asne1-fwr01"
network = google_compute_network.shared_vpc.name
direction = "EGRESS"
priority = 1000
allow {
protocol = "icmp"
}
allow {
protocol = "tcp"
ports = ["80", "8080"]
}
}
resource "google_compute_firewall" "allow_ssh" {
description = "共有VPCに対するSSH接続を許可します"
project = google_project.network_host_project.id
name = "shnw-prd-asne1-fwr02"
network = google_compute_network.shared_vpc.name
priority = 1000
allow {
protocol = "tcp"
ports = ["22","3389"]
}
direction = "INGRESS"
source_ranges = ["35.235.240.0/20"]
}
# ターゲットタグを用いてインスタンスに特定のネットワークタグが付いた通信のみ許可する
resource "google_compute_firewall" "allow_between_only-my-subnets" {
count = "var.number_of_project"
description = "共有VPCの自分のプロジェクトのsubnet内で通信を許可します"
project = google_project.network_host_project.id
name = "shnw-prd-asne1-fwr-${element(google_project.project, count.index).number}}"
network = google_compute_network.shared_vpc.name
priority = 1000
allow {
protocol = "all"
}
direction = "INGRESS"
source_ranges = ["10.0.${count.index+1}.0/24"]
target_tags = ["${element(google_project.project, count.index).number}"]
}
#サービスプロジェクト側で共有VPC利用のためのIAMロールの付与
resource "google_project_iam_member" "project_iam_binding_networkuser" {
count = "var.number_of_project"
project = "${element(google_project.project, count.index).id}"
role = "roles/compute.networkUser"
member = "user:XXXXXXXX"
depends_on = [google_compute_subnetwork_iam_binding.shared_subnet_iam_binding]
}
#IAP経由でsshするためのロール付与
resource "google_project_iam_member" "project_iam_binding_iapsshuser" {
count = "var.number_of_project"
project = "${element(google_project.project, count.index).id}"
role = "roles/iap.tunnelResourceAccessor"
member = "user:XXXXXXXXXX"
depends_on = [google_compute_subnetwork_iam_binding.shared_subnet_iam_binding]
}