みち草

Azure中心にまとめる技術情報ブログ

Template Spec と Automation を用いてユーザーに NW 権限を与えずにストレージ アカウントとプライベート エンドポイントをデプロイさせる

はじめに

Azure 環境を使わせるにあたり、PaaS サービスは必ずプライベート エンドポイントで使わせたい、ユーザーに NW 周りを操作する権限は与えなくない、といった制限をかけたい場合があると思います。

完全にクローズドな環境とするのは難しいため、可能な範囲で通信や権限を許可して使いやすくしたいところですが、ポリシー上どうしても許容できない場合もあるでしょう。

ポリシーを活用してプライベート エンドポイント必須にすることはできますが、サービスによっては、ポータルでのデプロイと同時にプライベート エンドポイントを有効化できなかったり、 NW 関連の権限をすべて奪ってしまうとプライベート エンドポイントができなくなったりと、細かい調整が難しかったりします。

それを解決できそうな方法として、テンプレート スペックと Automation を使う方法を試してみました。

こちらの別バージョンとして、Microsoft Forms + Azure Logic Apps + Template Spec で構成したものを技術書典で販売した同人本でまとめています。 ご興味があればこちらもご覧ください。

techbookfest.org

目次

構成

構成を図示するとこんな感じです。

やりたいことはこれ

  • ユーザーは、サブスクリプションの閲覧者ロールと Automation オペレーター ロールを持つ
  • Azure Automation のマネージド ID は、サブスクリプションの共同作成者ロールを持つ
  • PaaS サービス (Storage Account) + プライベート エンドポイントをデプロイする bicep テンプレートを作成し、テンプレート スペックとして登録しておく
  • ユーザー自身にリソース作成権限はないが、 Automation Runbook を実行するとテンプレート スペックがデプロイされリソースが作成される

Automation Runbook に権限を与えてテンプレートスペックをデプロイさせることで、 ユーザーに直接リソースを操作する権限を与えないけどデプロイができる状況を作ろう、という感じです。

※よくよく考えたら、この構成だとユーザーは Template Spec の読み取り権限すらなくても OK でした。

テンプレート スペック作成

ARM テンプレートもしくは Bicep を登録しておくことができ、Azure ポータルからデプロイに利用することができます。
簡単なバージョン管理もできます。

docs.microsoft.com

テンプレート スペックをデプロイするには、テンプレート スペック自体の読み取り権限と、テンプレートでデプロイするリソースの操作権限が必要です。

今回のテンプレートではストレージ アカウントや、プライベート エンドポイントの権限が必要になりますが、ユーザーには権限を付与しません。

今回の構成で使用したテンプレートはこちら

github.com

既存の VNet 、サブネットに対してプライベート エンドポイントと、それと関連付けたストレージ アカウントをデプロイします。
ストレージ アカウントはパブリック アクセスを完全に無効にしています。

本来であれば Azure DNS プライベート ゾーンにレコードをデプロイまで含めると思いますが、今回想定していたシナリオ的にそこまでは入れていません。

テンプレート スペックの作成はポータルからもできますが、現状、bicep の場合は次のようなコマンドから作成する必要があります。

az ts create --name StorageWithPE --version "1.0" --resource-group pe-bicep-spoke --location japaneast --template-file ".\Storage\StorageWithPrivateEndpoint.bicep"

Azure Automation

Runbook 作成

Azure Automation の PowerShell Runbook を作成します。
今回作成したのはこれ (コメントはデバッグ用)

param(
    [string] $location,
    [string] $ResourceGroup_Name,
    [string] $VNet_Name,
    [string] $Subnet_Name,
    [string] $Storage_Name,
    [string] $Storage_SKU
)

$TemplateSpec_Name = "StorageWithPE"
$TemplateSpec_ResourceGroup = "pe-bicep-spoke"

Connect-AzAccount -identity

# Write-Output "Input"
# Write-Output "Location:"$location
# Write-Output "RG Name:"$ResourceGroup_Name
# Write-Output "VNet Name:"$VNet_Name
# Write-Output "Subnet Name:"$Subnet_Name
# Write-Output "Storage Name:"$Storage_Name
# Write-Output "Storage SKU:"$Storage_SKU

$TemplateSpec = Get-AzTemplateSpec -ResourceGroupName $TemplateSpec_ResourceGroup -Name $TemplateSpec_Name
$LatestVersionId = "init"

if ($TemplateSpec.Versions.ID.GetType().FullName -eq "System.String"){
    $LatestVersionId = $TemplateSpec.Versions.ID
}elseif($TemplateSpec.Versions.ID.GetType().FullName -eq "System.Object[]"){
    $LatestVersionId = $TepmlateSpec.Versions.ID[$TepmlateSpec.Versions.length - 1]
}

# Write-Output "Get Template Spec"
# Write-Output "Spec ID:"$LatestVersionId

New-AzResourceGroupDeployment `
    -ResourceGroupName $ResourceGroup_Name `
    -TemplateSpecId $LatestVersionId `
    -location $location `
    -VNetName $VNet_Name `
    -SubnetName $Subnet_Name `
    -Storage_Name $Storage_Name `
    -Storage_SKU $Storage_SKU

スクリプトでは、以下のことを行います。

  • bicep テンプレートに必要なパラメータを受ける
  • 実行するテンプレート スペックのリソース ID を取得する (RG 名と名前はハードコーディング)
  • 入力されたパラメータを使ってテンプレート スペックをデプロイする

テンプレート スペックのリソース ID を取得するとき、バージョンが 1 つか複数かで取得結果が異なるため、if 文で処理しています。

マネージド ID 有効化

システム マネージド ID を有効化し、サブスクリプションの共同作成者権限を与えておきます。

ストレージ アカウント、プライベート エンドポイントのデプロイだけであれば強めではありますが、ストレージ アカウント以外のサービスも同様に実装していくことを考えると、最終的には共同作成者でもよいかと思います。

ユーザー作成

最後に、テスト用のユーザーを作成してロールを付与します。

ユーザーはサブスクリプションをスコープに、閲覧者と Automation オペレーターのロールを付与します。

Automation のマネージド ID が共同作成者を持つため何でもできてしまいますが、ユーザーには Automation オペレーターロールを用いて Runbook の実行権限しか与えないようにします。

テスト

最後にテスト ユーザーでログインして、Runbook の実行と期待したリソースがデプロイできることを確認します。

デプロイ前のリソース グループ

Runbook 実行時のパラメータ指定

Runbook の実行成功

リソース グループのデプロイ履歴でも成功確認

リソース グループに、指定したストレージ アカウントとプライベート エンドポイントができている
※デプロイはできているけど、本来必要な Azure DNS プライベート ゾーンを設定してないのでこのままだと繋がらない

終わりに

ユーザーに権限を与えないけどリソースのデプロイができる、という状況を作ってみました。
これなら最低限の権限で実現できるのではないでしょうか。
ただ、ユーザーが多い場合、 Runbook の同時実行数とかは制限になるかと思います。

本当は Logic Apps で手動実行するときにパラメータ指定させるつもりでしたが、Power Automate と違ってプルダウンのパラメータ指定を作れるトリガーがなかったので Automation にしました。
ストレージの SKU とか手打するものではないと思うのでいい方法がないか検討中…

Azure Functions で NSG を疑似的に FQDN に対応させる

はじめに

Azure IaaS を使う際にまず間違いなく使用する、 L4 ACL の NSG について、送信元や宛先 IP アドレスを指定できるものの、現状は FQDN を指定することができません。

  • 送信元または宛先 IP が変動するため FQDN で指定したい
  • NSG で FQDN が使えないから Any 宛て、だと許可範囲が広すぎる
  • FQDN のためだけに FW を入れるなどコストがかかるようなことはしたくない

そんな時に使える解決策として、 Azure Functions を用いた NSG ルール更新を実装したのでまとめます。

目次

構成

今回のポイントはタイトルのとおり、Azure Functions です。

Azure Functions で指定 FQDN の名前解決を行い、解決結果の IP アドレスを取得、それを NSG ルールの送信元または宛先 IP アドレスとして、ルールを更新します。

これをタイマー トリガー関数として定期実行させることで NSG ルールを定期的に更新し、FQDN 解決結果の変化にも対応することで、NSG を疑似的に FQDN に対応させます。

図にすると、以下のようなイメージです。 (送信ルールの場合)

Azure Functions はサーバーレス ソリューションであるため VM のデプロイや管理は不要です。

また、従量課金プランであれば実行時間 (正確には、メモリ使用量と時間) により課金され、ある程度の無料枠も提供されています。 docs.microsoft.com

今回のように 1, 2 分で完了するような処理であれば、実行頻度やリソース使用量にもよりますが、VM と比較して安価に使用することができるため、Functions の活躍できるパターンでしょう。

では実際の作り方

環境構築

NSG

まずは、更新対象の NSG と NSG ルールをデプロイしておきます。
ここでは例として、以下のような送信ルールを作成しています。

宛先 IP アドレスは後に Functions に書き換えられるので、何でもいいです。

Functions

Functions のデプロイ
試したときは PowerShell Core 7.2 がプレビューだったので、 7.0 で動作確認してます。
現在は 7.2 も GA

マネージド ID

Azure Functions から NSG ルールを操作するため、Functions のマネージド ID を有効化して、RBAC での権限を付与

ここでは前述の NSG リソースをスコープに、 "ネットワーク共同作成者" ロールを付与

アプリケーション設定

"構成" から、スクリプト中で必要な環境変数を設定

今回はパラメータをすべて環境変数として、スクリプトを編集せずに使いまわせるようにしています
追加する変数と値の例は以下

名前
NSG_NAME 対象ルールを持つ NSG 名 FQDN-NSG
NSG_RESOURCEGROUP NSG のリソース グループ名 FQDN-NSG-RG
NSG_RULE_ACCESS NSG ルールのアクション Allow
NSG_RULE_DEST_PORTRANGE NSG ルールの宛先ポート範囲 587
NSG_RULE_DIRECTION NSG ルールの通信の方向 Outbound
NSG_RULE_NAME NSG ルール名 Outbound-to-FQDN
NSG_RULE_PRIORITY ルールの優先度 100
NSG_RULE_PROTOCOL 通信のプロトコル *
NSG_RULE_SOURCE_ADDRESSPREFIX NSG ルールの発信元アドレス範囲 *
NSG_RULE_SOURCE_PORTRANGE NSG ルールの発信元ポート範囲 *
TARGET_FQDN 宛先として許可したい FQDN smtp.sendgrid.net

インストールするパッケージの指定

docs.microsoft.com

上記の Docs にも記載がありますが、Functions の初回実行時、requirements.psd1 を参照して、スクリプト中で必要なモジュールが PowerShell ギャラリー から自動的にダウンロードされます。
正確には "host.json の managedDependency が true であれば" ですが、作成時にデフォルトで有効 (true) です。

デフォルトだと以下のようになっています

requirements.psd1 の 7 行目の # (コメント) を外せば実行時に Az モジュールが必要であれば 8.x バージョンを自動でインストールしてくれるんですが、ここで 1 つ注意です。

PowerShell ギャラリーで Az モジュールを検索し、最新 8.1 の Package Details を見ると、Dependencies に大量の Az.xxx パッケージが記載されています。

デフォルトの設定だとこれらがすべてインストールされるため、Azure Functions の連続実行時間上限に引っ掛かる可能性があります。
というか、従量課金プランのデフォルト 5 分だと引っ掛かります。

対処としては以下の 2 つですが、無駄なパッケージをインストールする意味もないので、必要なものを指定するのがよいでしょう。

  1. タイムアウトを延ばす (上限あり)
  2. インストールするパッケージを指定する

タイムアウトとその変更方法については以下を参照

docs.microsoft.com

特定のパッケージを指定する場合は以下のように記述します。
今回は、(記述不要なためコード中には登場しませんが) マネージド ID でのログインに Az.Accounts が、 NSG ルールの変更に Az.Network が必要なのでその 2 つを記載

Az モジュール自体のバージョンと、その中のパッケージのバージョンは異なる、という点にも注意です。

www.powershellgallery.com

www.powershellgallery.com

関数の作成

最後に、タイマートリガーで定期実行する関数を作成します。

時間指定の方法は NCRONTAB 式というもので、6 種類のフィールドがそれぞれ秒や時間、月に対応しているものです。
ここでは "0 0 0 * * *" 、つまり毎日午前 0 時 (UTC) に設定

NCRONTAB の指定サンプルやタイムゾーンの変え方は Docs を参照

docs.microsoft.com

コードは以下の GitHub にあるので貼り付けます。

github.com

コードについて簡単に補足すると、

  • 2 行目の param は、関数自体は引数を受ける作りではないけど消すと怒られるので残すことに
  • 5 行目は、.NET のライブラリを用いた FQDN の名前解決
    PowerShell の Resolve-DnsName だと余計な出力がついてきて加工が面倒だったのでこちらを採用
  • 8 行目以降は NSG ルールのアップデート処理

これで準備は OK

動作テスト

動作テストはコード画面の上部の "テストと実行" から

Application Insights と連携していない場合は、"Filesystem ログ" に変更しないとログが見えない

"接続されました" になったら "実行"

正しくできれいれば、初回実行時のみパッケージのインストールが始まる
※パッケージインストール後、パラメータミスでエラーが出て修正、再実行したため、次の画像と繋がってません

"Executed" まで表示されれば、実行は終了
エラーがなければ、NSG ルールの宛先 IP アドレスが更新されているはず。

名前解決の結果と一致しているか、nsookup などで確認してみてください。

これで、FQDN の名前解決をし、解決結果を用いて NSG ルールを更新する関数を定期実行させることができました。

関数実行の合間に IP アドレス (名前解決の結果) が変わってしまう可能性はあるため完全に対応できるものではありませんが、 Functions の実行頻度を上げることである程度対応できるはず。
疑似的に FQDN 対応させる、という点ではあまりコストもかからず、十分かと思います。

終わりに

名前解決部分やそもそもの構想など、かなりアドバイスをいただきながら作成した初 Functions でしたが、触ってみてかなり便利だと思いました。
モジュールのインストールも Automation より簡単だし、言語の対応範囲も広いし、基本 Functions でいいかなという印象

コードそんなかけないしなぁ、と思っていたけど PowerShell が使えるならいろいろできそう

今回のは使い方としてなかなか面白かったので、他にも Functions でうまく解決できるようなことがあればいろいろ作りたいなー

Logic Apps で Azure Monitor のアラート メールをカスタマイズする

はじめに

Azure Monitor でアラートを設定すると、予め決められたフォーマットでメールが送られてきます。

補足の文章やアラート内の別の情報を入れたいと思っても、Monitor の機能のみではメールの内容を変更できないため、 Logic Apps と組み合わせることでメールの内容をカスタマイズします。

Azure サポート チームのブログでも紹介されています。

jpazmon-integ.github.io

本記事ではメールのカスタマイズとしてまとめていますが、ほぼ同じやり方でアクションを変えれば、アラートが発砲された際に Teams などに通知することも可能です。

目次

Logic Apps 作成

仮作成

まずは Logic Apps のデプロイ。アラート メールを送るだけなのでコンサンプション プランでちゃちゃっと作成。

"ロジック アプリ デザイナー" から "HTTP 要求の受信時" を選択

"サンプルペイロードを使用してスキーマを生成する" から、カスタマイズしたいアラートの種類に合わせたペイロードのサンプルを貼り付けます。

アラートの種類に応じて連携されるデータ構造が異なるため、Activity Log アラートのカスタマイズだったら "管理" 、 Advisor アラートだったら "推奨"、サービス正常性なら "Service Health" のスキーマと、自分がカスタマイズしたいものに合わせて貼ります。

スキーマは以下の Docs からコピペでもいいのですが、ここでは別の方法を紹介します。

docs.microsoft.com

ということで、ここでは何も貼り付けずに"保存" を選択します。

アクショングループの作成、テスト

一旦 Logics Apps の作成をやめ、アラート発生時に Logic Apps を呼び出すアクション グループを作成します。

"モニター" - "アラート" の "アクション グループ" から、"作成" を選択します。

名前を付け、"アクション" タブに進みます。

"アクションの種類" でロジック アプリを選択します。

右側に別のブレードが出てくるので、先ほど作成した Logic Apps を選択し OK

"確認と作成" を選択すると、"テスト アクション グループ (プレビュー)" ボタンが表示されるため選択します。

これはプレビュー機能ですが、実際のアラートと同じペイロードを送信し、アクション グループのテストを実施できます。
カスタマイズしたいアラートの種類に応じてサンプルを選択し、テストを実行します。

この記事では、"アクティビティ ログ アラート" を選択します。

テストが成功したら "作成" を選択して、中断していたアクション グループの作成を完了させます。

本作成

Logic Apps 作成の続きを行います。

Logic Apps を見ると、先ほどのテスト実行の履歴があるため選択。

この履歴の、"HTTP 要求の受信時" を選択すると、"出力" 本文に値が入っています。
これをコピーして、一番最初の "サンプルペイロードを使用してスキーマを生成する" に貼り付けることでスキーマを指定します。

最初に挙げたように Docs でスキーマを探してコピペでもできるのですが、SubscriptionId がなかったりするので何が正解かイマイチわからず、 多少の手間はありますが "アクション グループのテスト" を用いたこの方法が確実かと思います。

コピーしたら "ロジック アプリ デザイナー" に戻り、サンプルとして貼り付けましょう。

続いてはメールのカスタマイズ部分
"新しいステップ" から、"メールの送信(v2)" を選択します。

注意点として、このアクションは Microsoft 365 と連系してメールを送信するため、M365 が使用できるアカウントでの認証が必要です。
ここで認証したアカウントを送信元としてアラート メールが送信されるため、自分からアラートメールが飛んだように見えるのが嫌な場合、アラート用のアカウント作成などが必要です。

メールの宛先、件名、本文を設定していきます。
本文中では、アラートとして送信された値を参照することができます。
ペイロードの値をそのまま参照したいのであれば "動的なコンテンツ" に対象の名前を入力してクリックするだけなので簡単です。

例として Subscription ID を参照するとこんな感じ
動的コンテンツで subscriptionid を検索して選択

本文に緑色の値が挿入されれば OK

完成版はこんな感じ

リソース名だけは動的なコンテンツとして参照できないので、"式" の方に関数を入れてアラート内の情報から取り出してくる必要があります。
ここではこんな式にしてます。

split(triggerBody()?['data']?['context']?['ActivityLog']?['resourceId'],'/')[8]

リソース ID は以下の形式なので、"/" で split してリソース名の部分を取り出してます。

/subscriptions/サブスクリプションID/resourceGroups/リソースグループ名/providers/Microsoft.Compute/virtualMachines/リソース名

関数の参考 Docs はこちら docs.microsoft.com

これで Logic Apps は完成なので保存。

アラート設定

最後は、Logic Apps を起動するアラートを設定すれば完成です。

モニターのアラート作成から、サブスクリプション対象のアラートを作成

Activity Log アラートのスキーマを使用しているので、条件は Create or Update Virtual Network (Microsoft.Network/virtualNetworks) にしてます。

アクション グループは、既に作成しテストに使用したものを選択

作成時にアラート有効化、以外は好きに設定してアラート完成

動作確認

実際に NW を作成して、アラートを発砲させてみます。

適当な VNet を作成します。

実際に届いたアラートメールがこちら

認証に使用した自分のメールアドレスから届いています。

本文中には Logic Apps で指定した内容や値が記載されており、caller には Azure AD のユーザープリンシパル名が表示されています。
split で作成したリソース名も OK です。

このようにして、カスタマイズしたアラート メールを送信することができます。

終わりに

今回はアラート メールのカスタマイズとしましたが、最初にも書いたとおりアクションを変えれば Teams に連携したり、他の処理を行ったりもできるので、Logic Apps を使えばいろいろと自動化ができます。

ここでは Microsoft 365 との連携でメール送信をしていますが、アカウント認証が必要なのが少し面倒かなぁと思います。
実際の運用では個人にするわけにはいかないので専用アカウントを作成することになると思いますが、社内的にその申請やアカウント管理が手間になることは多々あるのかなと。

その点では SendGrid などを使用して、API で連携させる方が楽でよさそう。

診断ログによる Azure Table Storage のエンティティを定期削除する

はじめに

Azure VM イベントログやパフォーマンス カウンターを診断ログとしてストレージ アカウントに保存できますが、Blob ストレージではなくテーブル ストレージに保存されるため、 ライフサイクル管理機能が使えず、古いエンティティが自動的に削除されません。

そこで、Azure Automation の Runbook を用いて定期的に削除するようにしてみました。

一部画像が荒いですが、クリックすれば綺麗に見えます。

目次

対象テーブル

対象は、診断ログにより生成されるこれらのテーブルです。
Linux の Syslog テーブルもありますが、ここでは "WAD" がついたテーブルを対象にします。

削除実行前に、古いものがいつぐらいか確認しておきます。
ストレージ エクスプローラーを使うのが簡単

削除用スクリプト

削除用に作成した、Automation 向け PowerShell スクリプトはこちら

github.com

こちらの記事のスクリプトを参考にし、Az モジュール、マネージド ID を使用するようしています。 qiita.com

対象のストレージ アカウント、リソース グループの指定が必須
テーブル名はの指定は任意で、指定する場合はそのテーブルのみ、指定しない場合は "WAD" がついたすべてのテーブルが対象です。

ログの保持日数は、何日以上古いエンティティを削除するかの指定です。
365 を指定した場合は、1 年以上古いエンティティを削除対象とします。

ただ、はじめは指定日数より古いエンティティすべてを対象としていたのですが、自分の環境で試した限りでは、 エンティティ数が多くなると時間がかかり過ぎ、Automation のジョブが制限時間内 (3 時間) に終わらないことがありました。

なので 70 行目にて、最大 5000 件の制限をかけています。
ここは実際に動かしてみて、状況を見て調整してください。

Automation アカウント作成

Automation アカウントを作成する際は、マネージド ID を有効にした状態で作成します。

作成されたマネージド ID に対して、対象ストレージ アカウントの "ストレージ アカウント共同作成者" ロールを付与します。

今回のスクリプトを動かすために AzTable モジュールが必要なため、それを追加します。

Runbook、スケジュール作成

Runbook に先ほどのスクリプトを登録します。

コードを貼り付けた後は、"公開" を選択することを忘れずに。

パラメータはこんな感じで指定

実行結果

あとは時間になる or 手動で実行すれば、こんな感じで各テーブルのエンティティを削除してくれます。
Target : 0 は指定日数を超えるエンティティがない場合です。

実行前に確認したテーブルを再度見ると、綺麗になってます。

終わりに

途中でも記載しましたが、エンティティ量が増えると処理に時間がかかり 3 時間以内に終わらない場合があるため、試してみて数を減らしたり、別のジョブに分けるなど調整してください。
時間がかからずいい感じにできる方法が見つけられなかったので、そこは改善の余地あり。

エンティティ削除スクリプトを作成したものの、現状はイベント ログもパフォーマンス カウンタも Log Analytics に入れてしまう方が多いと思うので、あまり役立つ機会はないかも…
料金は Log Analytics の方が高いけど、最近は Basic Logs とかアーカイブとか出始めたし、Log Analytics なら自動で削除されるし、クエリもできるし、そっちの方が使い勝手はいいと思います。

あとは単純に、エンティティが結構なスピードで増えていくのでこれだと消すのが追い付かなさそう、というのが率直な感想です。

Azure Blob Storage を NFS 3.0 で Linux VM にマウントする

はじめに

タイトルのとおり、Azure Blob Storage にコンテナーを作成して、Linux VM (RHEL) 上から NFS 3.0 でマウントを試したので、備忘的なもの。

目次

環境

構成はシンプルに、VM と同一サブネット上にプライベート エンドポイントで接続可能なストレージ アカウントを置いて、 VM からマウントする感じです。

手順は以下の Docs を参考にしてます。

docs.microsoft.com

Blob ストレージの準備

ストレージ アカウントのデプロイ

Blob Storage デプロイ時の注意点は以下

  1. NFS 3.0 は Data Lake Storage Gen2 の機能であるため、階層型名前空間を有効にする
  2. LRS か ZRS しか選べない

NFS 3.0 は通常の Blob Storage ではなく、Data Lake Storage Gen2 でないと使えないため、以下のオプションを有効にします。

また、NFS 3.0 を使う場合の制限として、冗長性は LRS か ZRS しか選べません。
GRS を選んだ状態だと、こんな感じで押せません。

その他、機能制限など既知の問題ページで挙げられているため注意。

docs.microsoft.com

コンテナーの作成

RHEL でマウントするための、適当なコンテナーを作成しておきます。
今回は testnfs で作成

VM からのマウント

パッケージ インストール

以下のコマンドを実行して、NFS 接続に必要なパッケージをインストール

yum install -y nfs-utils

名前解決の確認

ストレージ アカウントへプライベート エンドポイントを用いて接続できるか、nslookup で確認

以下はプライベート IP 172.21.0.5 に解決できているので OK

マウント

以下のコマンドを実行してマウント用マウントポイントを作成

mkdir -p /mnt/test

以下のコマンドの <storage-account-name> ストレージ アカウント名に、<container-name> をコンテナー名に変更したうえで実行して、 マウントポイントにコンテナーをマウント

mount -o sec=sys,vers=3,nolock,proto=tcp <storage-account-name>.blob.core.windows.net:/<storage-account-name>/<container-name>  /mnt/test

今回の例だと以下のコマンドを実行

mount -o sec=sys,vers=3,nolock,proto=tcp kknfsstorage.blob.core.windows.net:/kknfsstorage/testnfs /mnt/test

マウントできたので、いくつかファイルを作成してみる
これで Blob Storage の NFS マウントができました。

fstab

fstab はこんな感じで追記して設定できました。

kknfsstorage.blob.core.windows.net:/kknfsstorage/testnfs        /mnt/test       nfs     sec=sys,vers=3,nolock,proto=tcp 0       0

終わりに

NFS でマウントしたり、fstab を書いたりしたことがあまりないので、試してみました。

ストレージの作成時に階層構造かつ LRS or ZRS にする、ということさえわかっていれば、後はそんなに難しいところはないと思います。
(個人的には Linux に慣れてなくて、nfs のパッケージとか fstab の書き方調べるのにちょっと手間取った)

Data Lake Storage は通常のストレージよりもできることが少ない (機能が対応してない) 場合があるので、その点は注意が必要です。

Azure VM のサイズ選択を助ける、VM セレクターが登場

はじめに

今回は小ネタ的に、Azure VM の VM セレクターを紹介。

これは、Azure VM のサイズ選択を手伝ってくれる Web ツールです。

目次

Azure VM セレクター

Azure VM のスペックを選択するのがサイズですが、最近は新しいものもたくさん出てきて、どれがいいのか悩むことは多々あります。

そんなとき、必要な情報を入れていくことでお勧めサイズを教えてくれるのが VM セレクターです。

リンクはこちら

azure.microsoft.com

使ってみる

最初の選択

最初に、以下のどれから始めるかを選択し、"ここから開始" をクリックします。
ちなみにこれ、どれを選んでも最終的に入力が必要なものは同じなので、最初の問いが違うだけです。

  • ワークロードの種類で VM を検索する
  • OS とソフトウェアで VM を検索する
  • デプロイ リージョンで VM を検索する

OS とソフトウェア

今回は "OS とソフトウェアで VM を検索する" を選択してみました。
OS とソフトウェアを選ぶ画面になるので、Windows で SQL Server Enterprise を動かす体で選択。

右のほうに、現在選択した値とその結果何台が当てはまるかが表示されています。

ワークロードの種類

続いて、VM 上で稼働させるワークロードの種類を選択します。
"+" をクリックすれば例が表示されるので、それを参考に選びます。

ここでは大規模なリレーショナル DB 想定で、"メモリ集中型" にしてみます。 (この選択が実質シリーズの選択なので、ここで何を選ぶかで大体何が出てくるか決まると思います)

VM の技術仕様 (要求スペック)

続いては、VM に必要な CPU とメモリの幅を選択します。
また、追加の機能を展開すると、CPU ブランドや GPU の要否、必要なデータ ディスクの本数などを指定する枠があります。

こんな感じでざっくりと指定。

ディスク ストレージ (SKU)

次は、必要なディスクのスペック (SKU) を指定します。

今回は DB 想定なので Premium にします。
これで s のついたシリーズしか表示されないはず。

ディスク ストレージ (SKU とサイズ)

次もディスク ストレージで、今度はデータディスクの種類とサイズを指定します。

ちょっとわかり辛いのですが、左から Ultra ディスクの枠、Premium SSD の枠、Standard SSD の枠、Standard HDD の枠になってます。
なので、Premium SSD * 3 本付けても左から 2 番目の枠内にまとめられています。
(偶然にもデータ ディスクを 4 と指定していたので 4 枠あるのかと思いましたがそうではない)

図では、Premium SSD * 3、Standard HDD * 1 の計 4 本を選択しています。

リージョン

最後に、リージョンを選択して入力は完了です!

結果画面

結果はこんな感じで、推奨されたサイズは "E16s v5" でした。
指定した CPU とメモリは当然クリアしてます。

下の方には、似たようなスペックのサイズも表示してくれるようです。

デフォルトで "Azure ハイブリッド特典の価格を表示" が有効なことには注意

"詳細の表示" をクリックすると、サイズの詳細や予約の価格を教えてくれます。

"選択されたデータ ディスク" 画面はこんな感じ。

終わりに

VM のサイズが増え、どう選んだらいいのか、どこから考えればいいのか、みたいに迷うことは増えたと思うので、 どの辺りがいいのか目星をつけることができるのはよいところだと思います。

Web で使えて、お金がかかるものでもないので、気軽に使っていきましょう。

Azure Lighthouse を設定してみる

はじめに

今回は、Azure Lighthouse にて別テナントユーザーへのサブスクリプション権限の委任を設定してみました。 ポータルでテンプレートを作成することができ、思ったよりは楽にできました。

目次

Azure Lighthouse 概要

docs.microsoft.com

ざっくり言えば Azure サブスクリプションやリソース グループの権限を別 AAD のユーザーに与えることができる、という機能であり、 AAD に招待して権限つけるのと同じじゃないの?と思いますが、Lighthouse ならではのメリットがあります。

個人的に Lighthouse のメリットだと感じたのはこの辺

  1. ユーザーだけでなくグループに対して委任を行うことができる
  2. Azure ポータルで委任された環境を管理する際、テナントの切り替えが不要

個人的メリット 1

1 点目について、例として作業を依頼したベンダーに権限を与える場合、作業メンバーを連携するから招待して権限を付与してください、とベンダーから依頼され対応する、 担当者の増減があれば連絡を受け、また実施してもらう、というパターンが多いと思います。

この場合、ベンダー側は依頼してから顧客側の対応を待たないといけなかったり、顧客側も度々変更依頼があると手間だったりということがあります。

※共有ユーザーを作成して招待し、複数人で使いまわすことも可能ではありますが、アクティビティログから誰がどの操作をしたのか確認できず、セキュリティ的にはよろしくないので考慮しない。

Lighthouse でグループに対して委任を行うことで、このやり取りが不要になります。

Lighthouse では前述のとおり、AAD ユーザーだけでなく AAD グループに対してもサブスクリプションやリソース グループの権限を委任することができます。

サブスクリプションやリソース グループ権限の委任ですので、AAD グループの管理自体は元々の持ち主 (先の例だと作業ベンダー) が行えます。

つまり、顧客側としては 1 回 だけ Azure Lighthouse の設定を行い、ベンダー側 AAD のグループに対して権限を委任してしまえば、 あとはベンダー側が自分たちで AAD グループのメンバー変更を行うことで、環境の権限を持つユーザーを変更する、ということができます。

これにより、管理をする側、される側の双方にとってやりやすい状態が作れるかと思います。

個人的メリット 2

2 点目の前に、これまでどおり招待した場合どうなるかをおさらいします。

招待されている場合、招待先の AAD およびサブスクリプションの操作を行うためには、Azure ポータルでテナントを切り替える必要があります。

右上の歯車アイコンを選択して

設定画面から見ることのできる "現在のディレクトリ"
"切り替え" ボタンで AAD を切り替えることで、そのディレクトリに紐づくサブスクリプションが見えるようになります。

別 AAD のサブスクリプションを見るときには切り替えて、ロードが発生して、終わったらまた自分のディレクトリに戻して、ロードが発生して、 というこの操作は結構面倒だと思っています。

これについても、Lighthouse を使うと解決することができます。

"現在のディレクトリ" と同じページの少し上を見てもらうと、"現在のディレクトリ + 委任されたディレクトリ" という部分があると思います。

Lighthouse で委任した場合、ここでチェックボックスにチェックを入れれば、ディレクトリを切り替えずともサブスクリプションの閲覧、リソース作成が可能になります。

リソースを閲覧するためには、 Lighthouse で委任されたディレクトリとサブスクリプションにチェックを入れます。
※kkdev が委任したもの

何かしらのリソース一覧にてフィルターを見てもらうと、別ディレクトリのサブスクリプションも選択できるようになっています。

リソース作成画面でも、別ディレクトリのサブスクリプションが選択できます。

というように、Lighthouse の委任を行うと、ディレクトリを切り替えずとも他のサブスクリプションを操作することができるようになります。

切り替えを繰り返す必要がなくなることで、利便性が上がる部分はあるかと思います。

Azure Lighthouse の構成

ここからは Azure Lighthouse の構成方法について紹介します。

サブスクリプションやリソース グループを委任してもらう側 (前述のベンダー側) と、 サブスクリプションやリソース グループを委任する側 (前述の顧客側) のそれぞれで作業が必要です。

スタートはサブスクリプションを委任してもらう側です。

委任してもらう側の作業

委任してもらう側の作業としては、Azure Lighthouse を有効にしてもらうための ARM テンプレート作成が必要です。

以下は Azure ポータルから作成する流れです。

まずは Azure Lighthouse の画面を開いて、[顧客の管理] を選択

[ARM テンプレートを作成] を選択

以下の画面では主に、委任するスコープを指定します。

サブスクリプション全体で委任してもらうのか、特定のリソース グループを委任してもらうかの選択です。

リソース グループを選択した場合は、委任してもらうリソース グループの名前を直接入力します。

今回はサブスクリプションのまま [認可の追加] へ

認可の追加画面では、誰にどんな権限を与えるか、与える際は永続か一時的か、といったことを指定します。

一時的な場合は、権限が与えられる時間、多要素認証、承認の有無が指定できます。

なお、グループに権限を委任したい場合は、[プリンシパルの種類] でグループを選択しましょう。

1 プリンシパル分の登録ができたので、複数のユーザーやグループ、サービス プリンシパルに委任してもらいたい場合は繰り返して追加しましょう。

追加できたら [テンプレートの表示] を選択します。

テンプレートが表示されるので、[ダウンロード] を選択して保存します。

これで委任してもらう側の作業は完了です。

ダウンロードしたテンプレートを顧客に渡し、以下の手順でテンプレートをデプロイしてもらいましょう。

委任する側の作業

委任する側の作業としては、前の流れで作成された ARM テンプレートを受け取りデプロイすることです。

以下は Azure ポータルからデプロイする流れです。

ポータル上部の検索ボックスに "テンプレート" と入力し、[カスタムテンプレートのデプロイ] を選択します。

[エディターで独自のテンプレートを作成する] を選択します。

[ファイルの読み込み] から先ほどの ARM テンプレートを読み込み、下部の [保存] を選択します。

そうするとパラメータ指定画面になりますが、テンプレートにデフォルト値が組み込まれているため、 委任するサブスクリプションとリージョンだけ指定して下部の [確認と作成] を選択します。

次のページで [作成] を選択します。

デプロイが完了後に反映されるまで少し時間はありますが、委任する側の作業は完了です。

委任後の管理

Azure Lighthouse の構成後、それぞれの画面ではどのように見えるかの紹介です。

委任してもらう側

委任してもらう側 (ベンダー側) は、[顧客の管理] から確認します。

[顧客] や [委任] の画面から、どこの AAD のどのサブスクリプションやリソース グループが、どう委任されているかを確認することができます。

[ロールの割り当て] に表示されている青文字を選択すると、詳細を見ることができます。

委任してもらう側でできることは特にないです。

委任する側

委任してもらう側 (顧客側) は、[サービス プロバイダー プランの表示] から確認します。

[サービス プロバイダーのオファー] や [委任] の画面から、先ほどと同様にどこの AAD のどのサブスクリプションやリソース グループが、どう委任されているかを確認することができます。

[ロールの割り当て] 下の青文字から見られる詳細情報も同じのためここでは省略します。

委任する側は、ここ以下の 2 つの操作を行うことが可能です。

  1. 委任するサブスクリプション、リソース グループの追加
  2. 委任の削除
委任の追加

[サービス プロバイダーのオファー] の右端の方に + ボタンがあり、ここから委任を追加することができます。

最初に委任した範囲から追加したいものが出てきた場合には活用しましょう。

チェックボックスを使って委任を追加すると、こんな感じで見えるようになります。

委任の削除

[サービス プロバイダーのオファー] や [委任] 画面の右端の方にゴミ箱ボタンがあり、ここから委任を削除することができます。

違いとしては、[委任] 画面ではサブスクリプションやリソース グループ単位での委任削除ができ、[サービス プロバイダーのオファー] 画面では委任丸ごとの削除ができます。

細かくコントロールしたいときは [委任] 画面から、完全に委任を削除したい場合には [サービス プロバイダーのオファー] 画面から、という使い分けです。

ちなみに、削除前には確認のポップアップが表示されます。

終わりに

今回は Azure Lighthouse での委任について紹介しました。
構築ベンダーと顧客の例で紹介しましたが、Lighthouse で委任してもらって、そこに対する監視やサポートなどのマネージドサービス的な使いかともできると思います。

また、AAD 招待の場合は条件付きアクセスでの MFA 強制や認証元 IP の制御が適用でき、Azure Lighthouse で全部 OK というものでもないと思いので、選択肢の 1 つとして抑えていただくのがいいかと思います。

コピペで使える Azure Resource Graph サンプル クエリ

はじめに

今回は、Azure のリソース検索に便利な Resource Graph のクエリについてです。

Resource Graph は特定のリソースを検出するうえで非常に便利ですが、 KQL を扱う必要があり、最初のうちはとっつきにくいところがあります。

ということで、コピペでそのまま使えるものをいくつかサンプルとして挙げてみます。

IaaS 系中心ですが、そのまま使用する、ちょっと手を加える、書き方を知るなど、何かしらの参考になれば幸いです。

目次

KQL リファレンス

関数の説明までは載せていないので、KQL のリファレンスを貼っておきます。

以下を参照してもらったり、コメント(先頭にダブルスラッシュでコメント化) したり、値を変えたりして。

docs.microsoft.com

もしくはこっちを参照すれば大体載っていると思います。
※左の縦メニューの中に型とか演算子とかいろいろ

docs.microsoft.com

SQL がわかる方はここを見ると KQL の理解が早いかもしれません。

docs.microsoft.com

Resource Graph クエリ サンプル

Compute 系

OS 種類別の VM 台数

OS 別の集計

Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| summarize count() by tostring(properties.storageProfile.osDisk.osType)

実行結果

ResourceGraph1

VM の情報と、使用している Dedicated Host 名
Resources
| where type =~ "Microsoft.Compute/virtualmachines"
| project name, resourceGroup, subscriptionId,  dedicatedHost=split(properties.host.id,"/")[8]

実行結果

サイズ別 VM 台数を、降順で表示

サイズ別の集計

resources
| where type =~ "Microsoft.Compute/VirtualMachines"
| summarize count() by tostring(properties.hardwareProfile.vmSize)
| sort by count_ desc 

実行結果

Storage 系

古いスナップショットの上位 10 個

使われず置いたままのスナップショット検索に。

Resources
| where type =~ "Microsoft.Compute/snapshots"
| project name, resourceGroup,properties.timeCreated
| sort by tostring(properties_timeCreated) asc
| take 10

実行結果

ResourceGraph2

未接続の管理ディスク

使われず置いたままの管理ディスク検索に。

Resources
| where type =~ "Microsoft.Compute/disks"
| where properties.diskState == "Unattached"

実行結果

ResourceGraph3

"Blob パブリック アクセスを許可" 設定が有効のストレージ アカウント

ストレージアカウント側の "パブリック アクセス許可" が有効なだけで、 実際にパブリック公開しているかどうかはコンテナー側の設定によります。

Resources
| where type =~ "Microsoft.Storage/storageaccounts"
| where properties.allowBlobPublicAccess == true

実行結果

ResourceGraph5

各ストレージ アカウントの "安全な転送が必要" と "Blob パブリックアクセスを許可"、"TLS の最小バージョン" の設定値

原因がわかりませんが、稀に設定値が空欄となり表示されないリソースがあります。
※作成時期が古いものだとなるかも?

Resources
| where type =~ "Microsoft.Storage/storageaccounts"
| project name, resourceGroup, properties.supportsHttpsTrafficOnly, properties.allowBlobPublicAccess, properties.minimumTlsVersion

実行結果

ResourceGraph6

Network 系

未接続のパブリック IP アドレス

使われず置いたままのパブリック IP アドレス検索に。

Resources
| where type =~ "Microsoft.Network/publicipaddresses"
| where isnull(properties.ipConfiguration)

実行結果

ResourceGraph4

Small もしくはインスタンスが 1 台以下の Application Gateway

Small 、もしくはインスタンスが 1 台以下の場合、Application Gateway の SLA 対象外です。

Resources
| where type =~ "Microsoft.Network/applicationgateways"
| where properties.sku.name == "Standard_Small" or properties.sku.capacity <= 1
| project name, properties.sku.name, properties.sku.capacity
| sort by tostring(properties_sku_name), tostring(properties_sku_capacity) asc

実行結果

ResourceGraph7

"高速ネットワーク" が無効なネットワーク インターフェイス

これだと NIC の設定値を見ているだけなので、どの VM かがわかりづらいです。
次に VM テーブルとの join 版を掲載しています。

Resources
| where type =~ "Microsoft.Network/NetworkInterfaces"
| where properties.enableAcceleratedNetworking == "false"
| project name, subscriptionId, properties.enableAcceleratedNetworking

実行結果

ResourceGraph8

各 VM のネットワーク インターフェイス名と "高速ネットワーク" の設定値 (join 版)

VM のテーブルと NIC のテーブルを join することで、どの VM のどの NIC かがわかりやすくなります。 ※複数 NIC の場合は考慮していません。

resources
| where type =~ "Microsoft.Compute/virtualmachines"
| project name, resourceGroup, size=tostring(properties.hardwareProfile.vmSize), subscriptionId, nic=tostring(split(properties.networkProfile.networkInterfaces[0].id, "/")[8])
| join kind = leftouter ( resources| where type =~ "Microsoft.Network/NetworkInterfaces") on $left.nic == $right.name
| project vm=name,subscriptionId, resourceGroup, nic, size, enableAcceleratedNetworking=properties.enableAcceleratedNetworking

実行結果

ResourceGraph9

Basic ロードバランサー

リタイアする Basic ロードバランサーの発見用に

Resources
| where type =~ "Microsoft.Network/Loadbalancers"
| where sku.name == "Basic"

実行結果

バックエンド プールが空の Application Gateway

使われず置いたままの Application Gateway 検索に。

resources
| where type =~ "Microsoft.Network/applicationGateways"
| where properties.backendAddressPools.properties.backendAddresses == ""

実行結果

Basic SKU のパブリック IP アドレス、ロードバランサー

リタイアに向けての検出用

resources
| where type == "microsoft.network/publicipaddresses" or type == "microsoft.network/loadbalancers"
| where sku.name == "Basic"

実行結果

ネットワーク インターフェースごとの、DNS 設定

個別設定の把握用

resources
| where type =~ "Microsoft.Network/networkinterfaces"
| project id, name, resourceGroup, DNS=properties.dnsSettings.dnsServers

実行結果

送信元を Any で許可している受信規則を持つ NSG とそのルール情報

広く許可し過ぎなルールを発見したいときに

resources
| where type =~ "Microsoft.Network/networksecuritygroups"
| mv-expand rule = properties.securityRules
| where tostring(rule.properties.sourceAddressPrefix) == "*" and tostring(rule.properties.access) == "Allow" and tostring(rule.properties.direction) == "Inbound"
| project id, name, resourceGroup, subscriptionId, ruleName = rule.name, rule

実行結果

Azure FW とそのプライベート IP アドレス

Azure FW 毎にプライベート IP アドレスを確認するのが面倒なときに

resources
| where type =~ "Microsoft.Network/azurefirewalls"
| mv-expand  ipCnof = properties.ipConfigurations
| extend fwIp = ipCnof.properties.privateIPAddress
| project id, name, resourceGroup, fwIp

実行結果

Application Gateway と、そのバックエンドに指定されている IP アドレス

どんな IP が指定されていたっけ?というのをまとめて確認したいときに

resources
| where type =~ "Microsoft.Network/applicationgateways"
| where location == "japaneast"
| mv-expand backendPool = properties.backendAddressPools
| mv-expand backendAddresses = backendPool.properties.backendAddresses
| extend backendAddress = tostring(backendAddresses.ipAddress)
| project id, name, resourceGroup, backendAddress

実行結果

その他

Notification Id 毎の Azure リソースのメンテナンス情報
maintenanceresources
| extend p = parse_json(properties)
| mvexpand d = p.value
| project  notificationId=properties.value[0].notificationId, id=substring(id, 0, indexof(id, "/providers/Microsoft.Maintenance")), resourceGroup, subscriptionId, status=d.status, detail=d

実行結果
メンテナンス対象リソースがないため取れたら追加

メンテナンス対象のリソースとその日時など

メンテナンス対象とその状況取得用

maintenanceresources
| mv-expand properties.value
| project notificationId=properties_value.notificationId, resourceId=properties_value.properties.resourceId ,resourceGroup, location, subscriptionId, Status=properties_value.status, StartTimeUtc=properties_value.startTimeUtc, endTimeUtc=properties_value.endTimeUtc, impactType=properties_value.impactType
| where Status != "Completed"

実行結果

こっちのサポート チームブログを見た方がいろいろ載ってていいかも

jpaztech.github.io

終わりに

今回はサンプル集としての記事でした。
クエリについては習うより慣れろで実際に動かしてみるのが一番かと思いますので、リファレンスを見つつ実際に動かしてみてください。

関数を使いこなせればもっといろいろできて楽しそうなのですが、自分でもまだそこまで扱えておらず join をちょっと試したくらい…
同じような、使ってみたいけどよーわからん、という方の参考になれば嬉しいです。
また、今後新しいクエリを作成できたら、更新していきたいと思います。