みち草

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

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 でうまく解決できるようなことがあればいろいろ作りたいなー