はじめに
Azure にて異なる Tenant (Azure AD), Subscription 間で VNET Peering を
Terraform (サービスプリンシパル利用) で実施した内容を記載する
実施内容
マルチテナントでの Subscription 間 VNET Peering を Terraform で実施するために、下記を実施した
- User Access Administrator 権限設定
- Terraform で使用するサービスプリンシパルのマルチテナント化
- spoke での Terraform サービスプリンシパルのアクセス許可
- spoke でのサービスプリンシパルへの IAM での権限追加
- Terraform でのマルチテナント操作での VNet Peering
1. User Access Administrator 権限設定
ロールの割り当ての追加をするには、Microsoft.Authorization/roleAssignments/write
が必要で、
組み込みロールで言うと Owner
もしくは User Access Administrator
(ユーザー アクセス管理者
) のロールを持っている必要がある
(Azure ドキュメントの Terraform サービス プリンシパルの作成で例に記載されているContributor
/共同作成者
では無理なので注意)
User Access Administrator
(ユーザー アクセス管理者
) のロールを割り当てる
サブスクリプションやリソースグループのアクセス制御(IAM)
で設定する
ユーザー アクセス管理者
をクリックして次へ
+メンバーを選択する
で選択するユーザをクリックして、選択
してクリック
(ここではユーザにしているが、サービスプリンシパルで実施している場合は、サービスプリンシパルを選択)
レビューと割り当て
を実施して割り当てる
2. Terraform サービスプリンシパルのマルチテナント化
サポートされているアカウントの種類:
が所属する組織のみ
になっている場合は、マルチテナント対応をする必要がある
所属する組織のみ
をクリックする
下記を選択して、変更する
任意の組織ディレクトリ内のアカウント (任意の Azure AD ディレクトリ - マルチテナント)
サポートされているアカウントの種類:
が 複数の組織
となっていることを確認
API のアクセス許可
で Microsoft Graph
の User.Read
権限を追加 (最初からマルチテナントでサービスプリンシパル作成しているとデフォルトで設定済)
3. spoke への Hub Terraform サービスプリンシパルのアクセス許可
マルチテナント化した Hub 側のサービスプリンシパルのアプリケーション ID (Application(client) ID) を参照する
spoke のディレクトリ(テナント)ID
(Service Tenant ID
) を取得する
https://login.microsoftonline.com/<Service Tenant ID>/oauth2/authorize?client_id=<Application (client) ID>&response_type=code&redirect_uri=https%3A%2F%2Fwww.microsoft.com%2F
ブラウザでアクセスして承認
する
サインイン
でエラー
となるが気にせずこのタブは閉じて良い
spoke 側の エンタープライズ アプリケーション
に追加したアプリケーション ID
でサービスプリンシパルが追加されていることが確認できる
4. spoke でのサービスプリンシパルへの IAM での権限追加
ひとつ前で追加した、Hubのアプリケーションのサービスプリンシパルへ spoke の VNET のネットワーク共同作成者
権限を付与する
GUI (Azure Portal) で実施する場合
spoke の VNET からアクセス制御 (IAM)
へ移動してロールの割り当ての追加
を実施する
ネットワーク共同作成者
を選択する
+メンバーを選択する
をクリックして、追加したサービスプリンシパルをクリックして、選択
をクリックして、
最後に次へ
をクリック
レビューと割り当て
をクリックして割り当てる
CLI (az-cli) で実施する場合
Spoke VNET のプロパティ
でリソース ID
を取得する
下記コマンドをユーザー アクセス管理者
ロールを持つユーザでログインした状態で実施
az role assignment create --role "Network Contributor" --assignee-object-id <サービスプリンシパルのオブジェクトID> --scope <Spoke VNET リソース ID> --assignee-principal-type ServicePrincipal
下記実行出力例
5. Terraform での VNet Peering 作成
Terraform で VNet Peering を作成する
サービスプリンシパルの ID/Password は環境変数に設定してから実施する
(パスワードは作成時を参照)
export ARM_CLIENT_ID=81XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX9
export ARM_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
下記、Terraform コード例
マルチテナント操作のため、provider を alias で複数定義して、auxiliary_tenant_ids
を使用する
# Spoke との Peering
module "spoke-peering-infratest2" {
source = "../../../../../../modules/hub/vnet/spoke-peering-different-subscription"
hub_resource_group_name = var.resource_group_name
hub_virtual_network_name = var.virtual_network_name
hub_tenant_id = "ceXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX1"
hub_subscription_id = "38XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX7"
spoke_resource_group_name = "rg-testinfra2-japaneast-001"
spoke_virtual_network_name = "vnet-testinfra2-japaneast-001"
spoke_tenant_id = "edXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX4"
spoke_subscription_id = "a4XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX9"
}
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
provider "azurerm" {
alias = "hub"
tenant_id = var.hub_tenant_id
subscription_id = var.hub_subscription_id
skip_provider_registration = true
auxiliary_tenant_ids = [var.spoke_tenant_id, ]
features {}
# client_id = var.client_id # ARM_CLIENT_ID
# client_secret = var.client_secret # ARM_CLIENT_SECRET
}
provider "azurerm" {
alias = "spoke"
tenant_id = var.spoke_tenant_id
subscription_id = var.spoke_subscription_id
skip_provider_registration = true
auxiliary_tenant_ids = [var.hub_tenant_id, ]
features {}
# client_id = var.client_id # ARM_CLIENT_ID
# client_secret = var.client_secret # ARM_CLIENT_SECRET
}
# https://registry.terraform.io/providers/hashicorp/azurerm/3.1.0/docs/data-sources/virtual_network
data "azurerm_virtual_network" "hub" {
name = var.hub_virtual_network_name
resource_group_name = var.hub_resource_group_name
provider = azurerm.hub
}
data "azurerm_virtual_network" "spoke" {
name = var.spoke_virtual_network_name
resource_group_name = var.spoke_resource_group_name
provider = azurerm.spoke
}
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering
resource "azurerm_virtual_network_peering" "hub-to-spoke" {
name = "peer-${data.azurerm_virtual_network.hub.name}-to-${data.azurerm_virtual_network.spoke.name}"
resource_group_name = data.azurerm_virtual_network.hub.resource_group_name
virtual_network_name = data.azurerm_virtual_network.hub.name
remote_virtual_network_id = data.azurerm_virtual_network.spoke.id
allow_virtual_network_access = true
allow_forwarded_traffic = true
allow_gateway_transit = true
use_remote_gateways = false
provider = azurerm.hub
}
resource "azurerm_virtual_network_peering" "spoke-to-hub" {
name = "peer-${data.azurerm_virtual_network.spoke.name}-to-${data.azurerm_virtual_network.hub.name}"
resource_group_name = data.azurerm_virtual_network.spoke.resource_group_name
virtual_network_name = data.azurerm_virtual_network.spoke.name
remote_virtual_network_id = data.azurerm_virtual_network.hub.id
allow_virtual_network_access = true
allow_forwarded_traffic = true
allow_gateway_transit = false
use_remote_gateways = true
provider = azurerm.spoke
}
# Local Param
variable "hub_resource_group_name" {}
variable "hub_virtual_network_name" {}
# spoke Param
variable "spoke_virtual_network_name" {}
variable "spoke_resource_group_name" {}
# hub SP Param
variable "hub_tenant_id" {}
variable "hub_subscription_id" {}
# spoke SP Param
variable "spoke_tenant_id" {}
variable "spoke_subscription_id" {}
terraform apply
を実行すると、Peering が完了する
下記は spoke 側で vnet の ピアリング
から今回作成のピアリング状態が接続済み
となっていることを確認した
おわりに
マルチテナントでの VNET Peeirng を実施した
サービスプリンシパルが複雑で、実施するのに非常に苦労した
記載内容も正規手順ではないかもしれないので、ご参考程度でお願いします
参考