説明を始める前に
説明を始める前に、まず簡単に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として、
name
とvalue
が必要 - 例(python形式):
[{name:"foo", value:100},{name:"bar", value:"hello world"}]
- keyとして、
script
:実行するコマンド- オプション:省略可
- データ型:文字列の配列。配列のエレメントがコマンドになるため、一連のコマンドの指定も可能
- 例(python形式):
["sudo su -","az login --identity"]
- この値を指定すると、指定したスクリプトによってコマンドの既定のスクリプトがオーバーライドされます。
- 例(python形式):
この部分はイメージが湧かないと思いますが、記事の最後のサンプルの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の使い方を例を使って、簡単に紹介します。
# 変数の定義
$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認証のみでよいです。
ここまで読んでいただいて、お疲れ様でした。
コメント