広告

RestAPIでAzure仮想マシンにコマンド実行

Azure

説明を始める前に

説明を始める前に、まず簡単にRestAPIについて、軽く触れていこうと思います。
開発者の方でしたらすごく詳しいと思いますが、私みたいなインフラエンジニアにとっては「?」しか浮かないかもしれません。

RestAPIはRESTful APIの略称で、簡単にいうと、事前に決めたURI(URL)にPOSTやGETなどリクエストを出すことで、このURLに紐づく動作を実行させる仕組みです。
※動作の内容は、リクエストを受け付けているWEBサーバのプログラムで事前に定義している

要するに、実行したい動作のURIにリクエストを出すだけで、操作が実施させることができる仕組みです。

で、リクエストについてですが、基本HEADERとBODYの部分がありまして、それぞれ必要なデータを書くわけですが、これはサーバ側のプログラムで定義するので、開発の話になってしまうため、ここでは割愛いたします。
本記事では、RestAPIを使って仮想マシンのOSにコマンド実行させるための内容をまとめるので、そのHEADERやBODYはサンプルとして上げていきます。

仮想マシンにコマンド実行

仮想マシンにコマンドをリモートで実行させるには、様々な方法があります。
例えば以下の方法(ツール)があります。

  • ssh
  • openssh
  • rsh

Azureの場合、上記のツール以外に、RestAPIでコマンドを実行させることを可能になっています。

Azure仮想マシンにはRestAPIを提供しています。
POSTリクエストを仮想マシンに送信することで、コマンドを実行させることが可能です。

この記事では、以下の記事を参考に、検証などを行ってから、書いたものとなります。
公式ドキュメント

仮想マシンのPOSTのURI

仮想マシンにコマンドを実行させるためのURIは以下となっています。
※バージョン変更する可能性があるので、仕様する前に上記公式ドキュメントを確認してください。

https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/runCommand?api-version=2020-06-01

また、上記URIの以下の部分は自分の環境に合わせて、置き換えてください。

  • {subscriptionId}:サブスクリプションID
  • {resourceGroupName}:リソースグループ名
  • {vmName}:仮想マシン名

仮想マシンのPOSTの本体(body)

POST内容は事前に定義されているので、正しくPOSTするには、定められた内容でPOSTする必要があります。
※RestAPIの一般的な話ですが、POSTの本体(body)は基本JSON形式(key-value)のデータです。他の形式はできるものの、汎用性が低いです。

Bodyは以下の三つの情報(key)が入れられます。

  • commandId:コマンドの種類を指定する文字列
    • オプション:必須
    • データ型:文字列
    • 指定可能な値:
      • RunPowerShellScript:powershellで実行する(Windows)
      • RunShellScript:Shellスクリプトで実行する(linux)
  • parameters:コマンドのパラメータの指定
    • オプション:省略可
    • データ型:key-value(連想配列、dictとも言います)の配列
      • keyとして、namevalueが必要
      • 例(python形式):[{name:"foo", value:100},{name:"bar", value:"hello world"}]
  • script:実行するコマンド
    • オプション:省略可
    • データ型:文字列の配列。配列のエレメントがコマンドになるため、一連のコマンドの指定も可能
      • 例(python形式):["sudo su -","az login --identity"]
      • この値を指定すると、指定したスクリプトによってコマンドの既定のスクリプトがオーバーライドされます。

この部分はイメージが湧かないと思いますが、記事の最後のサンプルのbodyを確認していただくと、どんな風に書くかが分かっていただけると思います。

restAPI送信するためのツール

現時点、簡単にrestAPIを送信できるツールは以下の2つあります。

  • curl(linux)
  • Invoke-webrequest(Windows-Powershell 5.0以降)

今回はpowershellをベースに説明していきます。
※curl が慣れている方は、内容をcurlに変換すれば、うまくいくはずです。

powershellデータ型の簡単紹介

Invoke-webrequestをご紹介する前に、前提知識として、簡単にPowershellのハッシュテーブル(jsonみたいなkey-value形式)とArray(配列)のデータ型の定義の仕方をご紹介します。

# powershellのArrayは@()で定義する
arr1 = @(1,"a",4)

# powershellのハッシュテーブルは@{'key1'='value1', 'key2'='value2'}で定義する
hash1 = @{
    'key1'='value1',
    'key2'='value2',
    'key3'=@(1,"a",4)
}

認証 header

Azureのリソースを操作するために、認証が必要です。
認証情報は基本Headerに記載するので、POSTリクエストにHeaderに認証情報を付けて、認証させる必要があります。
※Headerの本質もkey-valueとなります。

ちなみに、認証に必要なヘッダーのkeyは@{ Authorization = "Bearer <access token>" }のみです。

ヘッダーの作成例:

# まず、はコマンドでログインする必要がある

# アクセストークンを取得する
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)

# ヘッダーの定義
$authHeader = @{
    'Content-Type'='application/json'
    'Authorization'='Bearer ' + $token.AccessToken
}

ヘッダー取得参考

※ ヘッダーのvalue部分にあるBearerは固定の文字列で、"token_type"というものの指定となっています。
::は静的メンバにアクセスする演算子です。

Invoke-webrequestで送信

参考:Invoke-webrequest

Invoke-webrequestの使い方を例を使って、簡単に紹介します。

# 変数の定義
$restUri = https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/runCommand?api-version=2020-06-01
$body = @{
    'commandId' = 'RunShellScript',  # commandIdの定義は必須、ここはShellコマンドのためRunShellScriptにしている
    # scriptに実行する一連のコマンドを配列に入れる
    'script' = @(
        'sudo su -',
        'mkdir TestDir',
        'date > ./TestDir/now',
    )
}

# Invoke-webrequestはアクセス結果を返してくれるので$response変数で受け取っている。
# -Body に入れる内容はJson形式に変換する必要があるので、$($body | ConvertTo-Json)で変換して渡している
# -Headers はヘッダーの部分で定義したのものを使用する、こちらもJSON形式に変換する必要がある
$response = Invoke-webrequest -Uri $restUri -Method Post -Body $($body | ConvertTo-Json)

Write-Output "response:" $response  # 結果を出力する

※Invoke-RestMethodというコマンドもありますが、出力内容が違いみたいなので、基本curlと対等なのがInvoke-webrequestです。

VMコマンド実行サンプル

前提知識を以上ご紹介しました。
それでは、VMコマンド実行するためのサンプルコードを以下に置きます。多分前提知識が理解していればすぐわかると思います。
※実はそのまま少し修正して、使ってもいいです (笑


# まずは以下のコマンドでAzureにログインする(ここは割愛します)
# Connect-AzureAD
# Connect-AzAccount

# アクセストークンを取得する
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)

# Headerの定義
$authHeader = @{
    'Content-Type'='application/json'
    'Authorization'='Bearer ' + $token.AccessToken
}

# RestAPIのURIとBodyの定義
$restUri = https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/runCommand?api-version=2020-06-01
$body = @{
    'commandId' = 'RunShellScript',  # commandIdの定義は必須。Shellコマンドを実行する
    # scriptに実行する一連のコマンドを配列に入れる
    'script' = @(
        'sudo su -',
        'mkdir TestDir',
        'date > ./TestDir/now',
    )
}

# Invoke-webrequestはアクセス結果を返してくれるので$response変数で受け取っている。
# -Body に入れる内容はJson形式に変換する必要があるので、$($body | ConvertTo-Json)で変換して渡している
# -Headers はヘッダーの部分で定義したのものを使用する、こちらもJSON形式に変換する必要がある
$response = Invoke-webrequest -Uri $restUri -Method Post -Headers $authHeader -Body $($body | ConvertTo-Json)

Write-Output "response:" $response  # 結果を出力する

サンプルの参考サイト

最後に

クラウドサービスはホント便利ですね、こんなこともできるなんて、と感心しました。
Azureを使う場合のみ、仮想マシンにコマンドを実行させる手法が一つ増えていますね。
これでツールを導入せずとも、リモートからコマンドを実行させることが可能になるし、認証もAzure認証のみでよいです。

ここまで読んでいただいて、お疲れ様でした。

コメント

タイトルとURLをコピーしました