はじめに
今回は、前回に引き続きGCP入門ということで、Terraformで構築したGCEにSSHするところまで進めていきたいと思います。
GCPとTerraformの初期設定は以下を参考に完了しておきます。
Terraformコードの作成
以下を参考にTerraformコードを作成します。

任意のテキストエディタでmain.tfのようなファイルを作成しておきます。
mkdir test-project && cd test-project
touch main.tf
作成したファイルに以下のコードを記述します。
(サブネットは後続の記事で冗長構成を構築したく4つにしています)
provider "google" {
project = "your-project-id
region = "asia-northeast1" # 東京リージョン
}
# VPC作成
resource "google_compute_network" "vpc_network" {
name = "my-vpc-network"
# auto_create_subnetworks = false
}
# パブリックサブネット1作成
resource "google_compute_subnetwork" "public_subnet_1" {
name = "public-subnet-1"
ip_cidr_range = "10.0.1.0/24"
network = google_compute_network.vpc_network.self_link
region = "asia-northeast1"
}
# パブリックサブネット2作成
resource "google_compute_subnetwork" "public_subnet_2" {
name = "public-subnet-2"
ip_cidr_range = "10.0.2.0/24"
network = google_compute_network.vpc_network.self_link
region = "asia-northeast1"
}
# プライベートサブネット1作成
resource "google_compute_subnetwork" "private_subnet_1" {
name = "private-subnet-1"
ip_cidr_range = "10.0.3.0/24"
network = google_compute_network.vpc_network.self_link
region = "asia-northeast1"
}
# プライベートサブネット2作成
resource "google_compute_subnetwork" "private_subnet_2" {
name = "private-subnet-2"
ip_cidr_range = "10.0.4.0/24"
network = google_compute_network.vpc_network.self_link
region = "asia-northeast1"
}
# GCEインスタンス作成
resource "google_compute_instance" "example_instance" {
name = "example-instance"
machine_type = "f1-micro"
zone = "asia-northeast1-a"
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2004-lts"
}
}
network_interface {
subnetwork = google_compute_subnetwork.public_subnet_1.self_link
access_config {
// Ephemeral IP
}
}
}
# ファイアウォールルール作成
resource "google_compute_firewall" "ssh_http_firewall" {
name = "ssh-http-firewall"
network = google_compute_network.vpc_network.self_link
allow {
protocol = "tcp"
ports = ["22", "80","443"]
}
source_ranges = ["0.0.0.0/0"]
# target_tags = ["example-instance"]
}
リソースの構築
terraform planを実行してドライランを確認してterraform applyを実行します。
$ terraform plan
Terraform used the selected providers to generate the
following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_compute_firewall.ssh_http_firewall will be created
+ resource "google_compute_firewall" "ssh_http_firewall" {
+ creation_timestamp = (known after apply)
+ destination_ranges = (known after apply)
+ direction = (known after apply)
+ enable_logging = (known after apply)
+ id = (known after apply)
+ name = "ssh-http-firewall"
+ network = (known after apply)
+ priority = 1000
+ project = "your-project-id"
+ self_link = (known after apply)
+ source_ranges = [
+ "0.0.0.0/0",
]
+ target_tags = [
+ "example-instance",
]
+ allow {
+ ports = [
+ "22",
+ "80",
+ "443",
]
+ protocol = "tcp"
}
}
# google_compute_instance.example_instance will be created
+ resource "google_compute_instance" "example_instance" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ current_status = (known after apply)
+ deletion_protection = false
+ effective_labels = (known after apply)
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ machine_type = "f1-micro"
+ metadata_fingerprint = (known after apply)
+ min_cpu_platform = (known after apply)
+ name = "example-instance"
+ project = "your-project-id"
+ self_link = (known after apply)
+ tags_fingerprint = (known after apply)
+ terraform_labels = (known after apply)
+ zone = "asia-northeast1-a"
+ boot_disk {
+ auto_delete = true
+ device_name = (known after apply)
+ disk_encryption_key_sha256 = (known after apply)
+ kms_key_self_link = (known after apply)
+ mode = "READ_WRITE"
+ source = (known after apply)
+ initialize_params {
+ image = "ubuntu-os-cloud/ubuntu-2004-lts"
+ labels = (known after apply)
+ provisioned_iops = (known after apply)
+ provisioned_throughput = (known after apply)
+ size = (known after apply)
+ type = (known after apply)
}
}
+ confidential_instance_config {
+ enable_confidential_compute = (known after apply)
}
+ network_interface {
+ internal_ipv6_prefix_length = (known after apply)
+ ipv6_access_type = (known after apply)
+ ipv6_address = (known after apply)
+ name = (known after apply)
+ network = (known after apply)
+ network_ip = (known after apply)
+ stack_type = (known after apply)
+ subnetwork = (known after apply)
+ subnetwork_project = (known after apply)
+ access_config {
+ nat_ip = (known after apply)
+ network_tier = (known after apply)
}
}
+ reservation_affinity {
+ type = (known after apply)
+ specific_reservation {
+ key = (known after apply)
+ values = (known after apply)
}
}
+ scheduling {
+ automatic_restart = (known after apply)
+ instance_termination_action = (known after apply)
+ min_node_cpus = (known after apply)
+ on_host_maintenance = (known after apply)
+ preemptible = (known after apply)
+ provisioning_model = (known after apply)
+ local_ssd_recovery_timeout {
+ nanos = (known after apply)
+ seconds = (known after apply)
}
+ node_affinities {
+ key = (known after apply)
+ operator = (known after apply)
+ values = (known after apply)
}
}
}
# google_compute_network.vpc_network will be created
+ resource "google_compute_network" "vpc_network" {
+ auto_create_subnetworks = true
+ delete_default_routes_on_create = false
+ gateway_ipv4 = (known after apply)
+ id = (known after apply)
+ internal_ipv6_range = (known after apply)
+ mtu = (known after apply)
+ name = "my-vpc-network"
+ network_firewall_policy_enforcement_order = "AFTER_CLASSIC_FIREWALL"
+ numeric_id = (known after apply)
+ project = "your-project-id"
+ routing_mode = (known after apply)
+ self_link = (known after apply)
}
# google_compute_subnetwork.private_subnet_1 will be created
+ resource "google_compute_subnetwork" "private_subnet_1" {
+ creation_timestamp = (known after apply)
+ external_ipv6_prefix = (known after apply)
+ fingerprint = (known after apply)
+ gateway_address = (known after apply)
+ id = (known after apply)
+ internal_ipv6_prefix = (known after apply)
+ ip_cidr_range = "10.0.3.0/24"
+ ipv6_cidr_range = (known after apply)
+ name = "private-subnet-1"
+ network = (known after apply)
+ private_ip_google_access = (known after apply)
+ private_ipv6_google_access = (known after apply)
+ project = "your-project-id"
+ purpose = (known after apply)
+ region = "asia-northeast1"
+ secondary_ip_range = (known after apply)
+ self_link = (known after apply)
+ stack_type = (known after apply)
}
# google_compute_subnetwork.private_subnet_2 will be created
+ resource "google_compute_subnetwork" "private_subnet_2" {
+ creation_timestamp = (known after apply)
+ external_ipv6_prefix = (known after apply)
+ fingerprint = (known after apply)
+ gateway_address = (known after apply)
+ id = (known after apply)
+ internal_ipv6_prefix = (known after apply)
+ ip_cidr_range = "10.0.4.0/24"
+ ipv6_cidr_range = (known after apply)
+ name = "private-subnet-2"
+ network = (known after apply)
+ private_ip_google_access = (known after apply)
+ private_ipv6_google_access = (known after apply)
+ project = "your-project-id"
+ purpose = (known after apply)
+ region = "asia-northeast1"
+ secondary_ip_range = (known after apply)
+ self_link = (known after apply)
+ stack_type = (known after apply)
}
# google_compute_subnetwork.public_subnet_1 will be created
+ resource "google_compute_subnetwork" "public_subnet_1" {
+ creation_timestamp = (known after apply)
+ external_ipv6_prefix = (known after apply)
+ fingerprint = (known after apply)
+ gateway_address = (known after apply)
+ id = (known after apply)
+ internal_ipv6_prefix = (known after apply)
+ ip_cidr_range = "10.0.1.0/24"
+ ipv6_cidr_range = (known after apply)
+ name = "public-subnet-1"
+ network = (known after apply)
+ private_ip_google_access = (known after apply)
+ private_ipv6_google_access = (known after apply)
+ project = "your-project-id"
+ purpose = (known after apply)
+ region = "asia-northeast1"
+ secondary_ip_range = (known after apply)
+ self_link = (known after apply)
+ stack_type = (known after apply)
}
# google_compute_subnetwork.public_subnet_2 will be created
+ resource "google_compute_subnetwork" "public_subnet_2" {
+ creation_timestamp = (known after apply)
+ external_ipv6_prefix = (known after apply)
+ fingerprint = (known after apply)
+ gateway_address = (known after apply)
+ id = (known after apply)
+ internal_ipv6_prefix = (known after apply)
+ ip_cidr_range = "10.0.2.0/24"
+ ipv6_cidr_range = (known after apply)
+ name = "public-subnet-2"
+ network = (known after apply)
+ private_ip_google_access = (known after apply)
+ private_ipv6_google_access = (known after apply)
+ project = "your-project-id"
+ purpose = (known after apply)
+ region = "asia-northeast1"
+ secondary_ip_range = (known after apply)
+ self_link = (known after apply)
+ stack_type = (known after apply)
}
Plan: 7 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────
Note: You didn't use the -out option to save this
plan, so Terraform can't guarantee to take exactly
these actions if you run "terraform apply" now.
f1-microがasia-northeast1-aで使用できなかったため、e2-microに変更して再度terraform planを実行しました。
$ terraform plan
google_compute_network.vpc_network: Refreshing state... [id=projects/your-project-id/global/networks/my-vpc-network]
google_compute_subnetwork.private_subnet_2: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/private-subnet-2]
google_compute_subnetwork.public_subnet_1: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-1]
google_compute_subnetwork.public_subnet_2: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-2]
google_compute_subnetwork.private_subnet_1: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/private-subnet-1]
google_compute_firewall.ssh_http_firewall: Refreshing state... [id=projects/your-project-id/global/firewalls/ssh-http-firewall]
Terraform used the selected providers to generate the
following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_compute_instance.example_instance will be created
+ resource "google_compute_instance" "example_instance" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ current_status = (known after apply)
+ deletion_protection = false
+ effective_labels = (known after apply)
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ machine_type = "e2-micro"
+ metadata_fingerprint = (known after apply)
+ min_cpu_platform = (known after apply)
+ name = "example-instance"
+ project = "your-project-id"
+ self_link = (known after apply)
+ tags_fingerprint = (known after apply)
+ terraform_labels = (known after apply)
+ zone = "asia-northeast1-a"
+ boot_disk {
+ auto_delete = true
+ device_name = (known after apply)
+ disk_encryption_key_sha256 = (known after apply)
+ kms_key_self_link = (known after apply)
+ mode = "READ_WRITE"
+ source = (known after apply)
+ initialize_params {
+ image = "ubuntu-os-cloud/ubuntu-2004-lts"
+ labels = (known after apply)
+ provisioned_iops = (known after apply)
+ provisioned_throughput = (known after apply)
+ size = (known after apply)
+ type = (known after apply)
}
}
+ confidential_instance_config {
+ enable_confidential_compute = (known after apply)
}
+ network_interface {
+ internal_ipv6_prefix_length = (known after apply)
+ ipv6_access_type = (known after apply)
+ ipv6_address = (known after apply)
+ name = (known after apply)
+ network = (known after apply)
+ network_ip = (known after apply)
+ stack_type = (known after apply)
+ subnetwork = "<https://www.googleapis.com/compute/v1/projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-1>"
+ subnetwork_project = (known after apply)
+ access_config {
+ nat_ip = (known after apply)
+ network_tier = (known after apply)
}
}
+ reservation_affinity {
+ type = (known after apply)
+ specific_reservation {
+ key = (known after apply)
+ values = (known after apply)
}
}
+ scheduling {
+ automatic_restart = (known after apply)
+ instance_termination_action = (known after apply)
+ min_node_cpus = (known after apply)
+ on_host_maintenance = (known after apply)
+ preemptible = (known after apply)
+ provisioning_model = (known after apply)
+ local_ssd_recovery_timeout {
+ nanos = (known after apply)
+ seconds = (known after apply)
}
+ node_affinities {
+ key = (known after apply)
+ operator = (known after apply)
+ values = (known after apply)
}
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────
Note: You didn't use the -out option to save this
plan, so Terraform can't guarantee to take exactly
these actions if you run "terraform apply" now.
terraform applyを実行します。
$ terraform apply
google_compute_network.vpc_network: Refreshing state... [id=projects/your-project-id/global/networks/my-vpc-network]
google_compute_subnetwork.private_subnet_1: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/private-subnet-1]
google_compute_subnetwork.public_subnet_2: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-2]
google_compute_subnetwork.public_subnet_1: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-1]
google_compute_subnetwork.private_subnet_2: Refreshing state... [id=projects/your-project-id/regions/asia-northeast1/subnetworks/private-subnet-2]
google_compute_firewall.ssh_http_firewall: Refreshing state... [id=projects/your-project-id/global/firewalls/ssh-http-firewall]
Terraform used the selected providers to generate the
following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_compute_instance.example_instance will be created
+ resource "google_compute_instance" "example_instance" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ current_status = (known after apply)
+ deletion_protection = false
+ effective_labels = (known after apply)
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ machine_type = "e2-micro"
+ metadata_fingerprint = (known after apply)
+ min_cpu_platform = (known after apply)
+ name = "example-instance"
+ project = "your-project-id"
+ self_link = (known after apply)
+ tags_fingerprint = (known after apply)
+ terraform_labels = (known after apply)
+ zone = "asia-northeast1-a"
+ boot_disk {
+ auto_delete = true
+ device_name = (known after apply)
+ disk_encryption_key_sha256 = (known after apply)
+ kms_key_self_link = (known after apply)
+ mode = "READ_WRITE"
+ source = (known after apply)
+ initialize_params {
+ image = "ubuntu-os-cloud/ubuntu-2004-lts"
+ labels = (known after apply)
+ provisioned_iops = (known after apply)
+ provisioned_throughput = (known after apply)
+ size = (known after apply)
+ type = (known after apply)
}
}
+ confidential_instance_config {
+ enable_confidential_compute = (known after apply)
}
+ network_interface {
+ internal_ipv6_prefix_length = (known after apply)
+ ipv6_access_type = (known after apply)
+ ipv6_address = (known after apply)
+ name = (known after apply)
+ network = (known after apply)
+ network_ip = (known after apply)
+ stack_type = (known after apply)
+ subnetwork = "<https://www.googleapis.com/compute/v1/projects/your-project-id/regions/asia-northeast1/subnetworks/public-subnet-1>"
+ subnetwork_project = (known after apply)
+ access_config {
+ nat_ip = (known after apply)
+ network_tier = (known after apply)
}
}
+ reservation_affinity {
+ type = (known after apply)
+ specific_reservation {
+ key = (known after apply)
+ values = (known after apply)
}
}
+ scheduling {
+ automatic_restart = (known after apply)
+ instance_termination_action = (known after apply)
+ min_node_cpus = (known after apply)
+ on_host_maintenance = (known after apply)
+ preemptible = (known after apply)
+ provisioning_model = (known after apply)
+ local_ssd_recovery_timeout {
+ nanos = (known after apply)
+ seconds = (known after apply)
}
+ node_affinities {
+ key = (known after apply)
+ operator = (known after apply)
+ values = (known after apply)
}
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
google_compute_instance.example_instance: Creating...
google_compute_instance.example_instance: Still creating... [10s elapsed]
google_compute_instance.example_instance: Creation complete after 16s [id=projects/your-project-id/zones/asia-northeast1-a/instances/example-instance]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
VPC,FW,インスタンスが作成されました!
SSH接続
インスタンスにCLIコンソール接続する方法がいくつか用意されていますので、今回は2パターン試していきます。
ブラウザからのSSH接続
GCEコンソール上から接続する方法です。
- SSH>ブラウザウィンドウで開く
非常に手軽に実行できる点が魅力ですね。

以下のようなウィンドウが開かれてブラウザからコンソール接続できました。

ただし、VPCのファイアウォールで適切にアクセス許可を行う必要があります。
ブラウザでの SSH を使用するには、環境が次の要件を満たしている必要があります。
- Google Cloud コンソールは、サポート対象のウェブブラウザで実行されている必要があります。
- 接続先の VM には、ゲスト環境がインストールされ、実行されている必要があります。ゲスト環境は、Google 提供の公開イメージから作成した VM にプリインストールされています。
- ネットワークは以下の要件を満たしている必要があります。
- HTTPS プロキシとセキュリティ デバイスは、TLS インスペクションなどのために、独自の TLS 証明書を使用してトラフィックを復号、再暗号化してはなりません。
- ネットワークは、
google.com
、gstatic.com
、またはgoogleapis.com
で終わるホスト名との間のトラフィックを許可する必要があります。- ネットワークは、デフォルト ドメインの IP アドレスへのパケット送信を許可する必要があります。
- 外部 IP アドレスを使用して VM に接続するには、Virtual Private Cloud(VPC)で IP 範囲
0.0.0.0/0
の TCP 上り(内向き)トラフィックを許可する必要があります。- 内部 IP アドレスを使用して VM に接続するには、VPC で IAP を使用する必要があります。

外部IPでアクセスしたい場合は、0.0.0.0/0からのsshアクセスを許可します。
ただし、セキュリティ的によろしくないので、内部IPでアクセスしたいと思います。その場合は、35.235.240.0/20からのsshアクセスを許可することでコンソールアクセス可能です。これは、httpsでGCPのフルマネージドのリバースプロキシであるCloudIAP(35.235.240.0/20)を経由してSSHするためです。

ローカルのターミナルからgcloudSSH接続
ローカル端末で任意のターミナルを開き、以下のコマンドを実行します。
パスワードを2回聞かれるので、任意のパスワードを入力します。
/Users/username/.ssh/配下に秘密鍵が作成されるので、今後、パスワード認証でSSHアクセスできるようになります。
$ gcloud compute ssh --zone "asia-northeast1-a" "example-instance" --project "your-project-id"
WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
以下の条件を満たしている必要があります。
- インスタンスが外部IPを持っていること
- VPCのファイアウォールでローカル端末のIPアドレスからのsshを許可していること
内部IPのみのインスタンスにローカル端末からSSH接続
ロールを追加した上で、IAP経由する方法があるようです。
今回は実施しませんでしたが、今後はこちらも試していきたいと思います。

作成したリソースを削除
忘れずにリソースを削除しておきましょう。
$ terraform destroy
Destroy complete! Resources: 7 destroyed.
まとめ
今回は、TerraformでGCEインスタンスを作成してSSHしてみました。
次回以降で、Webサーバー構築なども試していきたと思います。
最後までご覧いただきありがとうございました
コメント