銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Azure の Linux 仮想マシンを仮想マシンの内部からdeallocateする

このエントリはこちらのブログの日本語版になります。

developers.redhat.com

AzureにたてたLinux仮想マシンをdeallocateしたい場合、Azure Portalにログインできればそこからログインしたり、REST APIを実行する権限を作って適宜プログラムからdeallocateすることができます。しかし、そのLinuxにログインできる権限しか無い場合、OSのshutdownコマンドを実行してもdeallocateはされないため、仮想マシンの利用料金はかかり続けます。そこで仮想マシンの中からdeallocateするようにしてみたいと思います。

deallocateするにはREST APIを実行する必要があるので、Azure CLI 2.0をインストールして、Azure AD APPでService Principalを作成して認証を行います。もちろんService Principalのパスワードを指定してもいいのですが、パスワードを平文で保存することが懸念の場合は、Managed Service Identity (MSI)を利用してパスワードを利用せずに認証することができます。今回はその方法を紹介することにします。

対象となるLinux仮想マシンにAzure CLI 2.0がインストールされていない場合はインストールします。yum形式でのインストールは次のようにおこないます。

docs.microsoft.com

$ sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
$ sudo sh -c 'echo -e "[azure-cli]\nname=Azure CLI\nbaseurl=https://packages.microsoft.com/yumrepos/azure-cli\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azure-cli.repo'
$ sudo yum install azure-cli

次に仮想マシンに対しMSIを有効にします。Azure Cloud ShellなどAzure CLI 2.0を利用する場合は次のコマンドを実行します。

docs.microsoft.com

$ az vm identity assign -g <resrouce_group_name> -n <vm_name>

次にこの仮想マシンに実行できるIAM Roleを付与します。今回は同じ仮想マシンに対するVirtual Machine Contributor ロールを付与することにします。最初のコマンドで仮想マシンのリソースIDを取得し、次のコマンドで先程与えたMSIのサービスプリンシパルIDを取得します。取得いた値を3番目のコマンドに与えて、ロールを付与しています。

$ az vm show  -g <resrouce_group_name> -n <vm_name> --query id
$ az resource list -n <vm_name> --query [*].identity.principalId --out tsv
$ az role assignment create --assignee <vm_resource_id> --role 'Virtual Machine Contributor' --scope <sp_id>

これで準備は完了です。仮想マシン側でdeallocateするためのスクリプトを次のように作っておきます。MSIを利用したログインは--msiオプションで実行できます。また、deallocateするために自分自身のリソースグループ名と仮想マシン名が必要です。スクリプトにべた書きしてもいいですが、せっかくなのでインスタンスメタデータサービスを使って取得してみました。これで同一のスクリプトを好きな仮想マシンに配置するだけで実行できるようになります。このスクリプトであればcronでスケジュール実行することもできるでしょう。

#!/bin/bash

response=$(curl -H Metadata:true "http://169.254.169.254/metadata/instance/compute?api-version=2017-12-01" -s)
resource_group=$(echo $response | python -c 'import sys, json; print (json.load(sys.stdin)["resourceGroupName"])')
vm_name=$(echo $response | python -c 'import sys, json; print (json.load(sys.stdin)["name"])')

az login --msi
az vm deallocate -g $resource_group -n $vm_name

また、MSIを利用しない場合は、サービスプリンシパルを設定したAzure AD Appを作成し、パスワードを指定してAzure CLI 2.0のログインコマンドを実行するとよいでしょう。