My Home NW Lab

逸般の誤家庭のネットワーク

Azure Cloud Shellでbashを用いてTerraformの実行環境を構築する

Terraformの実行環境をAzure Cloud Shellでbashを用いて準備する手順をまとめました。 できるだけコマンドをそのまま流し込めばセットアップが完了するように調整しております。

Azure Cloud Shellを用いたTerraform環境の構築イメージ

設定の方針

  • TerraformからAzureへのService Principalを介した接続は証明書による認証としています。

  • Azure Cloud Shellは検証用途で利用していて定期的に環境を破棄する想定とし、消し忘れたService Principalの不正利用を防ぐために証明書の有効期限を90日としています。

  • 検証時に権限周りの制約に悩まされないようにService Principalに割り当てるRoleは Contributor にしています。しかしながら権限の強さに比例して悪用時のリスクが高まるので適宜調整してください。

情報源

Microsoftのドキュメント

Terraformの環境構築自体はMicrosoftのドキュメントを参考にしています。 固有情報のような書き換えが必要な個所があったので、できるだけAzure Cloud Shellからコマンドを流し込めばよい状態に調整しております。

Configure Terraform in Azure Cloud Shell with Bash | Microsoft Learn
https://learn.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell-bash?tabs=bash

TerraformのAzure Providerのドキュメント

認証情報に関してはTerraformのAzure Providerのドキュメントを参考にして、証明書認証で設定しております。

Azure Provider: Authenticating via a Service Principal and a Client Certificate | Guides | hashicorp/azurerm | Terraform Registry
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_certificate.html

設定方法

Terraformの最新バージョンのダウンロード (任意)

  • Azure Cloud Shellで現在インストールされているTerraformのバージョンを確認します。
terraform version
  • 筆者が検証時のAzure Cloud ShellではTerraformのバージョンが v1.3.2 だったので、検証時の最新版をインストールする方針としました。
sysadmin [ ~ ]$ terraform version
Terraform v1.3.2
on linux_amd64

Your version of Terraform is out of date! The latest version
is 1.5.5. You can update by downloading from https://www.terraform.io/downloads.html
sysadmin [ ~ ]$ 
  • Terraformの最新バージョンを自動で判定して取得します。実行ファイルは ~/bin/ に格納しています。
LATEST_URL=$(curl -sL https://releases.hashicorp.com/terraform/index.json | jq -r '.versions[].builds[].url' | grep -E 'terraform_[0-9]\.[0-9]{1,2}\.[0-9]{1,2}_linux.*amd64' | sort -V | tail -n 1)

echo ${LATEST_URL}

curl -O ${LATEST_URL}

ls ~/terraform_*_linux_amd64.zip

unzip ~/terraform_*_linux_amd64.zip

mkdir ~/bin

mv ~/terraform ~/bin/
  • デフォルトで環境変数 ${PATH}~/bin/ が通っていますが、新しい実行ファイルが優先されないケースがありました。この場合はMicrosoftのドキュメントに従ってShellを開き直します。
sysadmin [ ~ ]$ echo ${PATH}
~/.local/bin:~/bin:~/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/istio-latest/bin:/usr/local/linkerd/bin:/usr/lib/golang/bin:/opt/mssql-tools18/bin:~/bundle/bin:~/bundle/gems/bin
sysadmin [ ~ ]$ 
sysadmin [ ~ ]$ which terraform
/home/sysadmin/bin/terraform
sysadmin [ ~ ]$ 
sysadmin [ ~ ]$ terraform version
Terraform v1.3.2
on linux_amd64

Your version of Terraform is out of date! The latest version
is 1.5.2. You can update by downloading from https://www.terraform.io/downloads.html
sysadmin [ ~ ]$ 
  • 新しくShellを開き直して最新のTerraformの実行ファイルが優先されるかを確認します。
exit

Shellの開き直し

terraform version

認証設定

  • Terraform向けのService Principalを作成していきます。Service Principal名を変数に格納します。
SP_NAME='sp_terraform'
  • Subscriptionの情報が必要になるので予め変数に格納しておきます。
SUBSCRIPTION=/subscriptions/`az account show | jq -r .id`

echo ${SUBSCRIPTION}
  • 証明書用のパスワードを変数に格納します。
    パスワードの複雑性に指定がある場合は適宜修正してください。後の手順でヒアドキュメントを用いてファイルに保存しているので、Shellによって変数展開される $$~ の扱いには注意してください。
CERT_PASSWORD=`openssl rand -base64 18`

echo ${CERT_PASSWORD}
  • Terraform用の証明書を事前作成した上で、Service Principalを作成しています。証明書の有効期間は openssl コマンドの -days オプションで90日としています。
mkdir ~/credentials

cd ~/credentials

pwd

openssl req -subj '/CN=myclientcertificate/O=MyCompany, Inc./ST=CA/C=US' -new -newkey rsa:4096 -sha256 -days 90 -nodes -x509 -keyout ./client.key -out ./client.crt

openssl pkcs12 -export -password pass:${CERT_PASSWORD} -out ./client.pfx -inkey ./client.key -in ./client.crt

az ad sp create-for-rbac --name ${SP_NAME} --role Contributor --scopes ${SUBSCRIPTION} --cert '@./client.crt'

Terraformのサンプル

動作確認用にResource Groupを作成するTerraformのサンプルを実行します。

事前準備

  • Terraformのサンプル ファイルを格納するディレクトリを作成して移動します。
mkdir ~/Sample

cd ~/Sample

pwd

変数の設定

  • TerraformからAzureへ接続する際の認証情報を格納する変数を定義します。
cat > ./variables.tf << EOF
variable "subscription_id" {
  description = "Subscription ID"
  type        = string
  sensitive   = true
}

variable "tenant_id" {
  description = "Tenant ID"
  type        = string
  sensitive   = true
}

variable "client_id" {
  description = "Client ID"
  type        = string
  sensitive   = true
}

variable "client_certificate_password" {
  description = "Client Certificate Password"
  type        = string
  sensitive   = true
}
EOF
cat ./variables.tf
  • 認証情報を格納します。機密情報を扱うファイルとなるため取り扱いに注意してください。
cat > ./secret.tfvars << EOF
subscription_id             = "`az account show | jq -r .id`"
tenant_id                   = "`az account show --subscription 'Pay-As-You-Go' | jq -r .tenantId`"
client_id                   = "`az ad sp list --display-name ${SP_NAME} | jq -r .[].appId`"
client_certificate_password = "${CERT_PASSWORD}"
EOF
cat ./secret.tfvars

メインの設定

  • Resource Groupを作成するためのサンプルです。
cat > ./main.tf << EOF
terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>3.44.1"

    }
  }
}

data "local_file" "client_certificate" {
  filename = pathexpand("~/credentials/client.pfx")
}

provider "azurerm" {
  features {}

  client_id = var.client_id
  client_certificate_path     = data.local_file.client_certificate.filename
  client_certificate_password = var.client_certificate_password

  tenant_id       = var.tenant_id
  subscription_id = var.subscription_id
}

resource "azurerm_resource_group" "rg-sample" {
  name     = "rg-sample"
  location = "japaneast"
}

output "OUTPUT_TEST" {
  description = "Test Message"
  value       = "Hello, World!"
}
EOF
cat ./main.tf

Terraformの実行コマンド

  • 現在の作業ディレクトリでTerraform環境の初期化処理を行います。
terraform init
  • 生成される設定情報を事前に確認します。TerraformからAzureへ接続する際の認証情報が含まれている変数定義ファイルを読み込んでいます。
terraform plan -var-file="./secret.tfvars"
  • 実際に実行します。変数定義ファイルの指定を忘れないようにしてください。
terraform apply -var-file="./secret.tfvars"
  • 検証作業が終わったら不要なリソースを削除します。検証時にShellを閉じているケースを考慮して、ディレクトリ移動を事前に行うようにしています。変数定義ファイルの指定を忘れないようにしてください。
cd ~/Sample

terraform destroy -var-file="./secret.tfvars"

後片付け: Service Principalの設定削除

検証作業を終えてTerraformからAzureへのデプロイ作業も不要になったら、不正アクセスの要因にならないようにService Principalの設定を削除しておきます。

az ad sp create-for-rbac コマンドを用いてService Principalを作成した際に、Enterprise ApplicationとApp Registrationの設定が作成されているので、2つ分の設定の削除が必要になります。

CLIからの作業だけだと、Enterprise ApplicationとApp Registrationの2つの設定個所を意識しにくいので、Web UIからの作業手順も用意しました。

CLIの手順

  • Service Principal名を変数に指定します。
SP_NAME='sp_terraform'
  • Enterprise Applicationの設定を削除します。事前と事後で設定が存在しているかの確認をしています。
az ad sp list --display-name ${SP_NAME}

az ad sp delete --id `az ad sp list --display-name ${SP_NAME} | jq -r .[].id`

az ad sp list --display-name ${SP_NAME}
  • App Registrationの設定を削除します。事前と事後で設定が存在しているかの確認をしています。
az ad app list --display-name ${SP_NAME} 

az ad app delete --id `az ad app list --display-name ${SP_NAME} | jq -r .[].id`

az ad app list --display-name ${SP_NAME} 

Web UIの手順

Enterprise applicationsの設定の削除
  • Azure Active Directoryから Enterprise applications に移動します。

    Enterprise applications への移動

  • Application type == Enterprise Applications の検索フィルタを削除して、sp_terraform の設定を探して移動します。

    Enterprise applicationのTerraform用設定への移動

  • sp_terraformManage セクションにある Properties を開いて、Delete ボタンから削除します。

    Enterprise ApplicationのTerraform用設定の削除

App Registrationの設定の削除
  • Azure Active Directoryから App Registrations に移動します。

    App Registrations への移動

  • All applications のタブに切り替えた後に sp_terraform の設定を探して移動します。

    App RegistrationのTerraform用設定への移動

  • Overview から Delete ボタンから削除します。

    App RegistrationのTerraform用設定の削除

関連記事

myhomenwlab.hatenablog.com