GCP 環境をプロビジョニングするための Terraform の基本的な設定を記載します。
本ページで利用する terraform のバージョンは以下のとおりです。
[vagrant@localhost myrepo]$ terraform --version
Terraform v0.14.8
以下のような main.tf
ファイルを作成します。GCP のサービスアカウントの key ファイルのパスを指定します。サービスアカウントには必要なロールを割り当てておく必要があります。
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.60.0"
}
}
}
provider "google" {
credentials = file("./my-service-account-key.json")
project = "my-project-id"
}
resource "google_compute_network" "vpc_network" {
name = "terraform-network"
}
Terraform では対象とする環境に応じて provider
を指定します。GCP の場合は hashicorp/google という provider を利用します。
以下のコマンドで provider のバイナリのダウンロード等の初期化処理を行います。
terraform init
変更される内容を dry-run で確認します。
terraform plan
変更を適用します。
terraform apply
terraform が認識している状態を確認します。
terraform show
出力例
# google_compute_network.vpc_network:
resource "google_compute_network" "vpc_network" {
auto_create_subnetworks = true
delete_default_routes_on_create = false
id = "projects/my-project-id/global/networks/terraform-network"
mtu = 0
name = "terraform-network"
project = "my-project-id"
routing_mode = "REGIONAL"
self_link = "https://www.googleapis.com/compute/v1/projects/my-project-id/global/networks/terraform-network"
}
terraform の設定が期待通りに動かない場合に、local でビルドした google provider を利用できると検証時に便利です。
git clone https://github.com/hashicorp/terraform-provider-google.git
Go 言語でビルドします。
cd ./terraform-provider-google
go build
ビルド成果物
du -h ~/terraform-provider-google/terraform-provider-google
75M /home/vagrant/terraform-provider-google/terraform-provider-google
以下のようなディレクトリとシンボリックリンクを作成します。
mkdir -p ~/.terraform.d/plugin/registry.terraform.io/hashicorp/google/99.99.99/linux_amd64
mkdir -p ~/.terraform.d/plugin-cache
ln -s ~/terraform-provider-google/terraform-provider-google ~/.terraform.d/plugin/registry.terraform.io/hashicorp/google/99.99.99/linux_amd64/terraform-provider-google_v99.99.99
~/.terraformrc
を作成します。
provider_installation {
filesystem_mirror {
path = "/home/vagrant/.terraform.d/plugin"
}
direct {
exclude = []
}
}
plugin_cache_dir = "/home/vagrant/.terraform.d/plugin-cache"
main.tf の version を更新します。
terraform {
required_providers {
google = {
source = "hashicorp/google"
# version = "3.60.0"
version = "99.99.99"
}
}
}
ロックファイルを削除して init しなおします。
rm .terraform.lock.hcl
terraform init
以下のように .terraform/*
にインストールされました。
find .terraform/providers/ -name terraform-provider-google* -follow
.terraform/providers/registry.terraform.io/hashicorp/google/3.60.0/linux_amd64/terraform-provider-google_v3.60.0_x5
.terraform/providers/registry.terraform.io/hashicorp/google/99.99.99/linux_amd64/terraform-provider-google_v99.99.99
注意: BeyondCorp Enterprise の機能を使うため、以下の手順を試すためには GCP における「組織」の登録が必要となります。
サービスアカウントは、ある一つのプロジェクトに属します。「組織」にサービスアカウントを作成することはできないため、適当なプロジェクトでサービスアカウントを作成します。
mylab-308012
というプロジェクトで my-service-account-2
を作成すると、以下のようなメールアドレスになります。
my-service-account-2@mylab-308012.iam.gserviceaccount.com
JSON 形式の鍵ファイルをダウンロードしておきます。
「組織」の「IAM」において、「roles/browser(参照者)」ロールをサービスアカウントに付与します。
組織の階層構造を参照できるようになります。
gcloud auth activate-service-account --key-file ./my-service-account-2.json
gcloud organizations list
DISPLAY_NAME ID DIRECTORY_CUSTOMER_ID
qoosky.io 111111111111 XXXXXXXXX
作成したサービスアカウントを用いて Terraform でリソースを作成する必要があるため、更に「roles/editor(編集者)」ロールも付与します。
editor ロールがあると、組織のリソースを閲覧できるようになります。例えば以下のコマンドがエラーなく実行できます。
gcloud access-context-manager policies list --organization 111111111111
NAME ORGANIZATION TITLE ETAG
486212067009 111111111111 default policy 045d9af982e4e4fa
デフォルトのポリシーが既に作成されている「組織」の場合は上記のように表示されます。「組織」は一つのポリシーしか持てないため、デフォルトのポリシーが存在する場合は terraform でポリシーを作成しようとするとエラーになります。
「デフォルトのポリシー」が存在しない場合は、以下のように「組織」のポリシーも terraform で管理します。既にデフォルトのポリシーが存在する場合で terraform 管理しない場合は、以下の main.tf の ${google_access_context_manager_access_policy.my-access-policy.name}
をデフォルトポリシーのものでハードコーディングします。
main.tf
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.60.0"
}
}
}
provider "google" {
credentials = file("./my-service-account-2.json")
}
resource "google_access_context_manager_access_policy" "my-access-policy" {
parent = "organizations/111111111111"
title = "my-access-policy"
}
resource "google_access_context_manager_access_level" "access-level" {
parent = "accessPolicies/${google_access_context_manager_access_policy.my-access-policy.name}"
name = "accessPolicies/${google_access_context_manager_access_policy.my-access-policy.name}/accessLevels/my_ip_restriction"
title = "my_ip_restriction"
basic {
conditions {
ip_subnetworks = [
"123.123.123.123/32"
]
}
}
}
google_access_context_manager_access_level
リソースのドキュメントはこちらですが、terraform の google プロバイダは、内部的には GCP REST API を実行しているため、ドキュメントでは把握しづらい情報は、REST API のドキュメントを参照して設定します。
グループを作成します。これにユーザを所属させることで、アクセス制限を行います。サービスアカウントでグループを作成するためには、必要な権限を付与する必要があります。CloudIdentity の場合は「グループ管理者」を付与します。
Cloud Identity 管理コンソールで「管理者ロール」をクリックします。
「グループ管理者」をクリックします。
「サービスアカウントへの割り当て」をクリックします。
サービスアカウントのメールアドレスを入力して追加します。
また、CloudIdentity の顧客ID を確認しておきます。
gcloud organizations list
DISPLAY_NAME ID DIRECTORY_CUSTOMER_ID
qoosky.io 111111111111 CXXXXXXXX
main.tf に以下のリソース定義を追記します。
resource "google_cloud_identity_group" "my-group" {
display_name = "my-ip-restriction-group"
parent = "customers/CXXXXXXXX"
group_key {
id = "my-ip-restriction-group@qoosky.io"
}
labels = {
"cloudidentity.googleapis.com/groups.discussion_forum" = ""
}
}
アカウントタイプ | ドメイン | Organization Administrator (GCP IAM による cloudidentity.googleapis.com 利用の許可) | Groups Admin (Cloud Identity qoosky.io) |
mygroup@qoosky.io 作成 |
---|---|---|---|---|
ユーザアカウント | qoosky.io | X | X | X |
ユーザアカウント | qoosky.io | O | X | O |
ユーザアカウント | qoosky.io | X | O | O |
ユーザアカウント | qoosky.io | O | O | O |
ユーザアカウント | abc.com | O/X | X (権限付与はできません) | X |
サービスアカウント | xxx.iam.gserviceaccount.com | X | X | X |
サービスアカウント | xxx.iam.gserviceaccount.com | O | X | X |
サービスアカウント | xxx.iam.gserviceaccount.com | X | O | X |
サービスアカウント | xxx.iam.gserviceaccount.com | O | O | O |
作成した「アクセスレベル」と「グループ」の紐付けを設定します。
resource "google_access_context_manager_gcp_user_access_binding" "my-access-binding" {
organization_id = "111111111111"
group_key = trimprefix(google_cloud_identity_group.my-group.id, "groups/")
access_levels = [
google_access_context_manager_access_level.access-level.name,
]
}
最終的に以下のような main.tf となります。
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.60.0"
}
}
}
provider "google" {
credentials = file("./my-service-account-2.json")
}
resource "google_access_context_manager_access_policy" "my-access-policy" {
parent = "organizations/111111111111"
title = "my-access-policy"
}
resource "google_access_context_manager_access_level" "access-level" {
parent = "accessPolicies/${google_access_context_manager_access_policy.my-access-policy.name}"
name = "accessPolicies/${google_access_context_manager_access_policy.my-access-policy.name}/accessLevels/my_ip_restriction"
title = "my_ip_restriction"
basic {
conditions {
ip_subnetworks = [
"123.123.123.123/32"
]
}
}
}
resource "google_cloud_identity_group" "my-group" {
display_name = "my-ip-restriction-group"
parent = "customers/CXXXXXXXX"
group_key {
id = "my-ip-restriction-group@qoosky.io"
}
labels = {
"cloudidentity.googleapis.com/groups.discussion_forum" = ""
}
}
resource "google_access_context_manager_gcp_user_access_binding" "my-access-binding" {
organization_id = "111111111111"
group_key = trimprefix(google_cloud_identity_group.my-group.id, "groups/")
access_levels = [
google_access_context_manager_access_level.access-level.name,
]
}
また、アクセス制限できるのは、同じドメイン qoosky.io におけるユーザアカウントのみです。
@qoosky.io
以外のユーザは、グループに含めたとしても制限できません。
アクセス制限が有効になると cloud console が使えなくなります。
API も同様です。
期待通りに動作しない場合は、Cloud Logging のログを「組織」について確認します。
上記例では、callerIp が IPv6 となっており、IPv4 で設定した許可IP としてアクセスできておらず、Access Denied となっています。自宅や職場のネットワーク設定で IPv6 を利用している場合は注意します。
IPv4 の 0.0.0.0/0
に相当する ::/0 を許可 IP として設定して Access Denied とならなくなる場合は、これが原因です。
グループの情報を調査
gcloud identity groups describe my-ip-restriction-group@qoosky.io
グループ一覧の確認
gcloud identity groups search --organization 111111111111 --labels 'cloudidentity.googleapis.com/groups.discussion_forum'
gcloud は内部的に REST API を実行しています。上記と同様の処理を curl で行うためには以下のようにします。parent を URL エンコーディングする必要があることに注意します。
curl -sS -H "Authorization: Bearer $(gcloud auth print-access-token)" "https://cloudidentity.googleapis.com/v1/groups?parent=customers%2FCXXXXXXXX"
グループを作成できるアカウントであることを gcloud で確認
gcloud identity groups create my-group@qoosky.io --organization 111111111111 --labels 'cloudidentity.googleapis.com/groups.discussion_forum' --with-initial-owner empty
アクセスバインディングを gcloud で作成、削除 (group-key
の指定方法に注意)
gcloud access-context-manager cloud-bindings create \
--group-key "04k668n33mb28sl" \
--level accessPolicies/486212067009/accessLevels/my_ip_restriction \
--organization 111111111111
gcloud access-context-manager cloud-bindings delete --binding organizations/111111111111/gcpUserAccessBindings/aAQS-YRTcHRZ1IHJsBBe9kx0Tv1WHPqDpiA7yVtVZI55qrJpu