はじめに
Azure の操作を自動化するとき、みなさんどんなツール使うことが多いのかなと思い、先日こんなアンケートをとってみました。
(アンケートです)Azure リソース操作の自動化で主に使ってるもの(選択肢1/2)
— よこち (@akira6592) 2023年1月11日
(選択肢2/2)
— よこち (@akira6592) 2023年1月11日
Terraform が多いですね。
候補に上げてみたものの、触ってみたことが無いものもあったので、色々触ってみようと思いました。
今回は、ネットワークセキュリティグループとそのルールを定義する簡単な内容を以下の6個のツール類でやってみました。
ツールごとに別々のリソースグループを予め作成していた状態からはじめました。ツールのインストールや認証情報などの設定も済んでいる状態です。
かんたんなサンプルを掲載します。まだちょっと触っただけなので、うまく有効活用した書き方になっていないところもあると思います。また構文の説明も省略します。あくまで雰囲気、ということでご了承ください。
1. Azure CLI
まず、普段遣いとしてもとても便利な印象の Azure CLIでやってみます。
- 環境
- Azure CLI 2.43.0
NSG 自体の作成を az network nsg create
で、ルールの作成を az network nsg rule create
で行いました。
サンプルと実行
NSG の作成:
% az network nsg create -g sakana-cli -n testnsg01 { "NewNSG": { "defaultSecurityRules": [ { "access": "Allow", // ...(略)...
ルールの作成:
% az network nsg rule create -g sakana-cli --nsg-name testnsg01 \ --name "Allow 443" \ --direction Inbound \ --priority 110 \ --destination-port-ranges 443 \ --protocol Tcp \ --destination-address-prefixes "*" \ --source-address-prefixes 10.0.0.0/16 \ --access Allow { "access": "Allow", "destinationAddressPrefix": "*", // ...(略)... }
手軽に使えて、繰り返し実行もしやすくて便利です。
2. Bicep
ARM テンプレートより簡単に書ける構文で書けるもので、今回初めて書きました。
内部的には、一度 ARM テンプレートに変換されるようです。
サンプル
param location string = resourceGroup().location resource testnsg01 'Microsoft.Network/networkSecurityGroups@2022-07-01' = { name: 'testnsg01' location: location } resource Allow443 'Microsoft.Network/networkSecurityGroups/securityRules@2022-07-01' = { name: 'Allow443' parent: testnsg01 properties: { direction: 'Inbound' priority: 110 destinationPortRange: '443' protocol: 'Tcp' destinationAddressPrefix: '*' sourcePortRange: '*' sourceAddressPrefix: '10.0.0.0/16' access: 'Allow' } }
VS Code の拡張「Bicep」を利用して書きましたが、補完が効いてとても書きやすかったです。
実行
ARM テンプレートと同じく Azure CLI の az deployment group create
でデプロイします。Azure CLI の内部的には、指定したファイル名の拡張子が .bicep
だと ARM テンプレートに変換(az bicep build -f ファイル名.bicep --stdout
)する処理を挟むようでした。
% az deployment group create -f nsg.bicep -g sakana-bicep { "id": "/subscriptions/xxxx/resourceGroups/sakana-bicep/providers/Microsoft.Resources/deployments/nsg", "location": null, "name": "nsg", "properties": { ...(略)...
参考URL
- Microsoft.Network/networkSecurityGroups - Bicep, ARM template & Terraform AzAPI reference | Microsoft Learn
- Microsoft.Network/networkSecurityGroups/securityRules - Bicep, ARM template & Terraform AzAPI reference | Microsoft Learn
- 入門Azure Bicep 1 - APC 技術ブログ
3. ARM テンプレート
一番 Azure ネイティブな方法と言えるかなと思います。
サンプル
一から書くのが手間に感じたため、先程作成した Bicep のファイルから生成します。az bicep build -f nsg.bicep
コマンドで nsg.json
というファイル名の ARM テンテプレートができます。
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.13.1.58284", "templateHash": "4078294825981448537" } }, "parameters": { "location": { "type": "string", "defaultValue": "[resourceGroup().location]" } }, "resources": [ { "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2022-07-01", "name": "testnsg01", "location": "[parameters('location')]" }, { "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2022-07-01", "name": "[format('{0}/{1}', 'testnsg01', 'Allow443')]", "properties": { "direction": "Inbound", "priority": 110, "destinationPortRange": "443", "protocol": "Tcp", "destinationAddressPrefix": "*", "sourcePortRange": "*", "sourceAddressPrefix": "10.0.0.0/16", "access": "Allow" }, "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', 'testnsg01')]" ] } ] }
どうしても少し長くなります。Bicep の有り難みが分かりました。
実行
構文は、Bicep と同じです。今回はツールごとにリソースグループを分けているので -g
は異なります。
$ az deployment group create -f nsg.json -g sakana-arm { "id": "/subscriptions/xxxx/resourceGroups/sakana-arm/providers/Microsoft.Resources/deployments/nsg", "location": null, "name": "nsg", "properties": { ...(略)...
4. Ansible
azure.azcollection
というコレクションの中に、さまざまなリソースを操作するモジュールがあります。
NSG の作成自体も、ルールの作成も同じく azure/azcollection/azure_rm_securitygroup
モジュールを利用します。
- 環境
- ansible-core 2.12.1
- azure.azcollection 1.14.0
サンプル
--- - hosts: localhost gather_facts: false connection: local vars: resource_group: sakana-ansible ansible_python_interpreter: "{{ ansible_playbook_python }}" tasks: - name: Create NSG azure.azcollection.azure_rm_securitygroup: resource_group: "{{ resource_group }}" name: testnsg01 rules: - name: Allow 443 direction: Inbound priority: 110 destination_port_range: 443 protocol: Tcp source_address_prefix: 10.0.0.0/16 access: Allow
実行
% ansible-playbook -i localhost, nsg.yml PLAY [localhost] *********************************************************************************** TASK [Create NSG] ********************************************************************************** changed: [localhost] PLAY RECAP ***************************************************************************************** localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
5. Terraform
次は、今回のアンケートでは使っている人が多かった Terraform です。
- 環境
- Terraform v1.3.7
サンプル
provider "azurerm" { features {} } resource "azurerm_network_security_group" "testnsg01" { name = "testnsg01" location = "japaneast" resource_group_name = "sakana-tf" } resource "azurerm_network_security_rule" "Allow443" { name = "Allow 443" network_security_group_name = azurerm_network_security_group.testnsg01.name resource_group_name = "sakana-tf" direction = "Inbound" priority = 110 destination_port_range = "443" protocol = "Tcp" source_address_prefix = "10.0.0.0/16" source_port_range = "*" destination_address_prefix = "*" access = "Allow" }
実行
init:
% terraform init Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/azurerm... - Installing hashicorp/azurerm v3.39.1... - Installed hashicorp/azurerm v3.39.1 (signed by HashiCorp) ...(略)...
plan:
% 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: # azurerm_network_security_group.testnsg01 will be created + resource "azurerm_network_security_group" "testnsg01" { + id = (known after apply) + location = "japaneast" + name = "testnsg01" + resource_group_name = "sakana-tf" + security_rule = (known after apply) } # azurerm_network_security_rule.Allow443 will be created + resource "azurerm_network_security_rule" "Allow443" { + access = "Allow" + destination_address_prefix = "*" + destination_port_range = "443" + direction = "Inbound" + id = (known after apply) + name = "Allow 443" + network_security_group_name = "testnsg01" + priority = 110 + protocol = "Tcp" + resource_group_name = "sakana-tf" + source_address_prefix = "10.0.0.0/16" + source_port_range = "*" } Plan: 2 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.
apply:
% terraform apply 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: # azurerm_network_security_group.testnsg01 will be created + resource "azurerm_network_security_group" "testnsg01" { + id = (known after apply) + location = "japaneast" + name = "testnsg01" + resource_group_name = "sakana-tf" + security_rule = (known after apply) } # azurerm_network_security_rule.Allow443 will be created + resource "azurerm_network_security_rule" "Allow443" { + access = "Allow" + destination_address_prefix = "*" + destination_port_range = "443" + direction = "Inbound" + id = (known after apply) + name = "Allow 443" + network_security_group_name = "testnsg01" + priority = 110 + protocol = "Tcp" + resource_group_name = "sakana-tf" + source_address_prefix = "10.0.0.0/16" + source_port_range = "*" } Plan: 2 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 azurerm_network_security_group.testnsg01: Creating... azurerm_network_security_group.testnsg01: Creation complete after 4s [id=/subscriptions/xxxx/resourceGroups/sakana-tf/providers/Microsoft.Network/networkSecurityGroups/testnsg01] azurerm_network_security_rule.Allow443: Creating... azurerm_network_security_rule.Allow443: Still creating... [10s elapsed] azurerm_network_security_rule.Allow443: Creation complete after 10s [id=/subscriptions/xxxx/resourceGroups/sakana-tf/providers/Microsoft.Network/networkSecurityGroups/testnsg01/securityRules/Allow 443] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
ステートを持つのが特徴ですね、
6. CDKTF (CDK for Terraform)
CDK 経由で Terraform を書けるようなツールです。言語は一番サンプルが多そうな TypeScript にしました。
できるまで苦戦してしまいました。何か指摘があれば Twittter までご連絡いただけるとありがたいです。
- 環境
- cdktf 0.14.3
サンプル
main.ts
(cdktf init
で生成されたものに追記):
// Copyright (c) HashiCorp, Inc // SPDX-License-Identifier: MPL-2.0 import { Construct } from "constructs"; import { App, TerraformStack } from "cdktf"; import { AzurermProvider } from '@cdktf/provider-azurerm/lib/provider'; import { NetworkSecurityGroup } from '@cdktf/provider-azurerm/lib/network-security-group'; import { NetworkSecurityRule } from '@cdktf/provider-azurerm/lib/network-security-rule'; class MyStack extends TerraformStack { constructor(scope: Construct, id: string) { super(scope, id); // define resources here new AzurermProvider(this, "azure", { features: {} }) const nsg = new NetworkSecurityGroup(this, "nsg", { location: "japaneast", resourceGroupName: "sakana-cdktf", name: "sakana-cdktf" }) new NetworkSecurityRule(this, "rule", { name: "allow 443", networkSecurityGroupName: nsg.name, resourceGroupName: "sakana-cdktf", direction: "Inbound", priority: 110, destinationPortRange: "443", protocol: "Tcp", sourceAddressPrefix: "10.0.0.0/16", sourcePortRange: "*", destinationAddressPrefix: "*", access: "Allow" }) } } const app = new App(); new MyStack(app, "cdk"); app.synth();
実行
synth:
% cdktf synth Generated Terraform code for the stacks: cdk
deploy:
% cdktf deploy cdk Initializing the backend... cdk Successfully configured the backend "local"! Terraform will automatically use this backend unless the backend configuration changes. Initializing provider plugins... - Finding hashicorp/azurerm versions matching "3.39.1"... cdk - Using hashicorp/azurerm v3.39.1 from the shared cache directory cdk Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. cdk ╷ │ Warning: Incomplete lock file information for providers │ │ Due to your customized provider installation methods, Terraform was forced │ to calculate lock file checksums locally for the following providers: │ - hashicorp/azurerm │ │ The current .terraform.lock.hcl file only includes checksums for │ darwin_amd64, so Terraform running on another platform will fail to install │ these providers. │ │ To calculate additional checksums for another platform, run: │ terraform providers lock -platform=linux_amd64 │ (where linux_amd64 is the platform to generate) ╵ Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. cdk 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: cdk # azurerm_network_security_group.nsg (nsg) will be created + resource "azurerm_network_security_group" "nsg" { + id = (known after apply) + location = "japaneast" + name = "sakana-cdktf" + resource_group_name = "sakana-cdktf" + security_rule = (known after apply) } # azurerm_network_security_rule.rule (rule) will be created + resource "azurerm_network_security_rule" "rule" { + access = "Allow" + destination_address_prefix = "*" + destination_port_range = "443" + direction = "Inbound" + id = (known after apply) + name = "allow 443" + network_security_group_name = "sakana-cdktf" + priority = 110 + protocol = "Tcp" + resource_group_name = "sakana-cdktf" + source_address_prefix = "10.0.0.0/16" + source_port_range = "*" } Plan: 2 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" (ここで Approve を選択) To perform exactly these actions, run the following command to apply: terraform apply "plan" cdk azurerm_network_security_group.nsg (nsg): Creating... cdk azurerm_network_security_group.nsg (nsg): Creation complete after 4s [id=/subscriptions/xxxx/resourceGroups/sakana-cdktf/providers/Microsoft.Network/networkSecurityGroups/sakana-cdktf] cdk azurerm_network_security_rule.rule (rule): Creating... cdk azurerm_network_security_rule.rule (rule): Still creating... [10s elapsed] cdk azurerm_network_security_rule.rule (rule): Creation complete after 10s [id=/subscriptions/xxxx/resourceGroups/sakana-cdktf/providers/Microsoft.Network/networkSecurityGroups/sakana-cdktf/securityRules/allow 443] cdk Apply complete! Resources: 2 added, 0 changed, 0 destroyed. No outputs found.
参考URL
今回 CDKTF を触ったの初めてでした。以下のページを参考にさせていただきました。
- Install CDK for Terraform and run a quick start demo | Terraform | HashiCorp Developer
- Building Azure Resources with TypeScript Using the CDK for Terraform
- Object Oriented Your Azure Infrastructure with Cloud Development Kit for Terraform (CDKTF) - Microsoft Community Hub
- Terraform CDK for Azure. by Roman Galeev | by McKinsey Digital | McKinsey Digital Insights | Medium
- Provisioning Azure Cosmos DB, Blobstorage, and Appservice with CDKTF | by max.VCbhan | Medium
Terraform 直接の場合と同じくステートを持ちます。
おわりに
とても簡単ではありますが、一通り触ってみました。触ったことがないものも少しだけ雰囲気を感じることができました。
もちろんコード類の書きっぷりだけでは簡単に比較はできず、運用スタイルや課題、組織が持っているスキルるなどにもよるかと思います。
第一印象としては、Azure 限定でよいなら、Bicep は良いなと思いました。