Azureの学習用環境(サンドボックス)を自動で作成・管理する処理作ってみた

# はじめに
この記事は[NTTコムウェア Advent Calendar 2024](https://qiita.com/advent-calendar/2024/nttcomware) 17日目の記事です。

NTTコムウェアの八城と申します！
普段は社内の[IPAのDSSを活用したエンジニアの育成及び組織文化の醸成](https://www.ipa.go.jp/jinzai/skill-standard/dss/case.html#nttcomware)活動の一環として、
クラウドエンジニア(Azure&AWS)の育成コミュニティの運営などを行っております。
私自身はAzure歴が7年くらい？の人間です。

本記事ではクラウドエンジニア育成の一環として、より気軽にAzureを実際に触りながら学習や検証ができるような環境(サンドボックス)を自動で作成・管理してくれる処理を作成し自分の所属する組織に展開したので、"それ"について記載します！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/64288dcc-43a8-1c6e-0ef5-8a2f150fae92.png)
# 作成の経緯
### クラウドを学習する上でのよくある悩み
どんなクラウドであっても初学者がまず直面しがちなのは、
<b>"ドキュメント等を読んで基礎概念は理解したけど実際に環境を触ってみるのはなんかコワイ"</b>
という点です。
実際、自分が運営を行っているコミュニティの中で行われたインタビューでも「リソースを作ることが怖い」という意見がありました。

プライベートな環境の場合は自身のお財布に直結しますし、案件の環境の場合は予期せぬ操作で既存のリソースに何か問題を生じさせそうで怖い…と感じてしまうのは十分に理解できます。
自組織では検証&学習用のクラウド環境も持っていますが、初学者にいきなりアカウントだけ作ってはいどうぞと渡すのも酷です。ある程度は準備した環境を渡してあげたいです。

…上記を加味したうえで、育成コミュニティ運営として<b>初学者がより恐怖心を感じずに気軽にクラウドについて学習したり遊べる場所=サンドボックスを提供したい</b>と考えました。
### なぜAzureに作ったのか
育成コミュニティではAWSとAzureを主な育成対象のクラウドサービスとして扱っていますが、以下のような理由で今回はまずAzureでの作成としました。
* 組織内ではAzure OpenAIが出始めたことでAzureの利用率が上がってきた段階であり初学者が多かった（AWSはある程度浸透していた）
* 組織としてある程度自由に検証や学習で使っていい環境をAzure・AWSそれぞれで持っていたが、Azureはあまり使われてなくて比較的環境がきれいな状態だったので手を加えやすかった（~~AWS環境は色々とカオスな状態だった~~）
* 筆者がAzureメインのエンジニアだったため、大体の実装方法がなんとなく検討ついていた

### Microsoft公式が提供しているAzureサンドボックスではだめなのか
ここまで読んだ方の中には、Microsoft Learnのトレーニング演習などで利用するAzureサンドボックス環境使えば良いのでは？と考えた方もいるかもしれません。
（参考：[手軽に利用できるMicrosoft Azureサンドボックス環境の活用](https://ops.jig-saw.com/tech-cate/azure-sandbox))

確かにMicrosoftが公式的に提供しているサンドボックス環境も非常に有用であり、Microsoft Learnで提供されている学習コンテンツの為に使うには十分だと思われます。
ただ、初学者が様々な学習を行いたい場合には、もう少し長期的&簡易&柔軟に利用できる環境を組織として設けても良いのではないかという判断になり、公式のAzureサンドボックスも参考にしながら組織用のサンドボックスを提供する処理を自作をしました。
もっと言えば、こういったものを提供することで運営している育成コミュニティの活性化やコミュニティへの興味関心を高めたいとも考えていました。
# 作ってみた
### 前提条件
#### 提供環境について
サンドボックスは組織で利用している検証&学習用のものを利用します。
本環境は組織内で管理がなされており、環境を使いたい場合は管理者にアカウントの発行を依頼したり、用途を告げてリソースグループの作成や権限付与を行ってもらっていました。
（使いたいと思ってから利用申請を行い、人手で払い出しされるのを待つような運用でした）
そのため、サンドボックス提供の際には管理者の負担が増加しないようにするとともに、利用申請者により早くサンドボックスを提供できるようにする工夫を考える必要があります。
また、サブスクリプションには月単位で予算が設定されています。そのため、サンドボックスとサンドボックスを提供する処理もその範囲内で運用を行えるように配慮をするがありました。
#### 提供対象者について
コミュニティ運営の基となっている[IPAのDSSを活用したエンジニアの育成及び組織文化の醸成](https://www.ipa.go.jp/jinzai/skill-standard/dss/case.html#nttcomware)活動では、専門分野毎に以下のような区分によるレベル認定を行っています。
* Level0 ：まだこれから該当分野の学習をする段階（ほぼ知識なし）
* Level1 ：該当分野の基本的な知識を座学レベルで有している
* Level2 ：複数のサービスを組み合わせて活用し、自ら手を動かしてアプリケーションを開発できる
* Level3 ：商用案件を1人称で牽引できるテクニカルリーダ

コミュニティに参加している人達はAzureにおける上記のレベル情報を持っているのでその情報を活用し提供範囲を定めます。
今回は、最低限の知識は有した状態で実際に手を動かして欲しいという期待から、AzureにおけるスキルレベルがLv1以上の人をサンドボックスの提供ターゲットに据えました。

#### 具体的に何を提供するのか
サンドボックスと称してはいるものの、実際に何を提供するのか？ですが、簡単に言うと<b>"様々な制約のかけられた個人的に使っていいリソースグループ"</b>を提供します。
（学習用とは銘打ってますが、ちょっとした検証や設計の際の確認等にも気軽&自由に利用できるリソースグループを提供します。）
設定する制約は以下のようなものになります。
* 有効期限：デフォルトは１週間(最短1日~最長１ヵ月）
* 作成できるリソースの制限
* リソースで利用できる料金プランや設定の制限
* コスト制約（サンドボックスあたり4500円)
    * 予算を超えた場合でも特に制約は設けず継続利用を可能とするが、環境全体の予算実績に大きく影響を与える可能性がある場合には利用者に声がけを行う

### ざっくり構成
上記前提を加味したうえで、実際どうやってサンドボックスの提供処理を実現するかを整理すると以下のような構成になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/0e709025-5c38-f735-6608-97f63aa4a1ee.png)
処理の実現のために主に以下の3つを実装しました。
* サンドボックスに制限をかけるために必要なポリシーとそれをまとめたイニシアチブ
* 3種の関数処理
    * サンドボックス作成処理
    * サンドボックス削除処理
    * コスト監視処理
* Slack側からAzure Functionを呼び出すためのカスタムステップ

### サンドボックスを利用してもらう&運用する為の工夫
本構成では、より柔軟かつ様々な前提条件に配慮してサンドボックスを利用できるようにする工夫を行っています。それら工夫について幾つか紹介します。
#### 期間設定
サンドボックスの利用期限はリソースグループに付けられた専用のタグで管理されます。
払い出しされた段階の設定では期限を１週間に設定していますが、必要に応じて期限を短縮したり最大30日まで延長して利用することが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/b2fbbb0d-f0ca-a908-6034-d740de89c62e.png)
<font color="#808080">Microsoft Corporation 「Azure portal」(2024.12.11) スクリーンショット</font>

上記はサンドボックスに設定されているタグの一覧です。利用者はサンドボックスに設定されたタグの内、using-limitの値だけを書き換え可能です。
設定された期限を変更することで、利用者の必要に応じた期間だけサンドボックスを利用することができます。
ただし、仮にusing-limitに30日より先の日程を設定したとしても30日を経過すると削除されます。
（別途のマスタで最大有効期限が管理されているため、そちらを変更すると特例的に30日を経過しても利用することができる仕組みにはなっています）
また、using-limitタグの値以外は書き換えても修復されます。タグ自体の削除やキーの変更もできないようになっています。

#### ガードレール
Azure Policyを用いてサンドボックス用のイニシアチブを作成し割り当てることで、リソースグループに対してガードレールを設置しています。
基本的には利用できるリソースの絞り込みと、該当リソースで利用できる料金プランや設定に制約を設けています。

利用できるリソースについては、Azureを用いている案件の情報や組織の勉強&検証用サブスクリプションに作られているリソースの情報を加味したうえで、標準的に使われるリソースのみデプロイできるようにポリシーで制限をかけています。
リソースプロバイダーレベルでいうと、約300種あるうちの70種程度を利用可能な対象としています。
そのうえで、リソースタイプのレベルでも標準的には使わない&高額であったりするもの(例. Azure Key Vault Managed HSM)は利用対象外となるように調整を行っています。

利用可能としたリソースに対してもSKUの制限などが割り当てられています。
例えば、仮想マシンに対しては以下のような制限が設定されています。
* 仮想マシンで利用可能なサイズを制限する
* 仮想マシンで利用可能なディスクを制限する
* 仮想マシンの更新/障害ドメインの数を制限する

各ポリシーについては、設定値をパラメーター化しており、利用者からの要望などがあった場合には必要に応じて制限を緩められるようにする運用となっています。

また、その他にもそれぞれのサンドボックス上での操作履歴(アクティビティログ）は保存するので、あとから操作を確認することで利用者が実施したいことを現ガードレールで満たせているのかを分析することも可能です。(また、問題のある操作やあえてガードレール回避のためになにかしていないかなども必要に応じて確認することができます。)

#### 運用・管理について
現在は環境管理の人員もコミュニティ運営の人員も限られているため、定常的な処理は自動化し効率的な運用をしようという方針になりました。
その為以下のような対応を実施し、基本的にはコストやその他アラートが通知された場合にのみ対応を実施すればいいようにしました。
##### サンドボックスの自動作成
サンドボックスはSlackのワークフローから利用を申請でき、利用を申請すると以下をチェックし作成処理を実施します。問題がなければ利用申請をしてから2-3分程度で利用を開始できます。

* <INS>サブスクリプション自体の予算上限確認</INS>
    * 現行の環境全体の利用料が、サブスクリプションとして設けられている予算の上限に近いあるいは超過している場合は新規のサンドボックスは作成不可
* <INS>利用申請者の情報確認</INS>
    * メールアドレスやAzureアカウントの情報に間違いがあったり、申請者がAzureにおけるスキルレベルがLv1未満の場合は作成不可
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/972e8517-8a1c-c24c-febb-ade7a36a223d.png)
* <INS>利用中のサンドボックスが他にないかの確認</INS>
    * 現状は１人で複数個併用することはしない方針となっているため、他に利用中のものがあった場合は利用不可
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/f33f6499-4df3-2d71-a687-a83ea39f5425.png)

正常に作成処理が完了した場合は、以下のようなメッセージが利用者のSlackに送られ利用が開始できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/45cd3363-3e76-2391-d698-51de30fa02a7.png)
##### サンドボックスの自動削除
日周期で期限の切れたサンドボックスがないかを確認し、対象があった場合には削除を実施しSlackのコミュニティ運営のチャンネルと利用者のDMにそれぞれメッセージを送ります。
* <INS>運営チャンネルに送られるメッセージ</INS>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/b1dde252-eaad-8cea-3fca-b2273a22128a.png)
* <INS>利用者に送られるメッセージ</INS>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/87f61789-accb-1e7a-322c-9c03885f7a14.png)
アンケートに回答が行われるとそれについても別途運営側のTeamsに通知が行われます。
##### コスト監視
サンドボックスとなるリソースグループには必ず「project:sandbox」のタグがつけられており、該当タグを対象とした予算が設定され、予測・実測のコストが予算に近づくと運営に通知が飛ぶように設定されています。
また、各サンドボックスに対しても払い出す際に予算が設定され、予測・実測のコストが予算に近づくと利用者に通知が飛ぶようになっています。
上記で標準的なコストのアラート設定はなされている認識ではあったのですが、予算の評価周期を確認したところ、以下のような記載がなされていました。
>予算は 24 時間ごとにこれらのコストに対して評価されます。 コストと使用状況データの更新の詳細を把握するようにしてください。 予算のしきい値が満たされたとき、通常、評価後、1 時間以内に電子メールの通知が届きます。

(参考：[チュートリアル: 予算を作成して管理する](https://learn.microsoft.com/ja-jp/azure/cost-management-billing/costs/tutorial-acm-create-budgets?tabs=psbudget))

サンドボックスはガードレールが設定されているとはいえある程度自由に利用できる為、なにかあってコストが急上昇した場合に迅速に対応するためには上記の周期だとやや遅いと判断し、別途５分周期で各サンドボックスの実コストをチェックする処理を組み込みました。
（以下はサンドボックスあたりの予算を125円として、アラート通知を発生させた場合のメッセージ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941318/f4f61511-6fd8-83ef-3651-f6fea3dbf158.png)


# 運用開始してから…
### ポリシー管理の難しさ
カスタムポリシーはメンテナンスが大変という話は、[Azureポリシーは「組み込みポリシー」を使うべきか、「カスタムポリシー」を書くべきか](https://zenn.dev/tomot/articles/e65770773b2213)という記事などを読んで理解はしていました。しかしSKUに対して制限をかけるようなポリシーは組み込みとしてあまり用意されておらず、[AzAdvertizer](https://www.azadvertizer.net/index.html)などでも探してみたもののよいものが見つけられなかったため、今回のサンドボックス対応では約30のカスタムポリシーを作成し適用しています。

その結果運用始めてから何度か、Azure側の仕様変更等の影響で以前は正常動作していたポリシーが想定通り動かない事象に遭遇しています。（SKUの名称が変更されたり等）
ポリシーが正常動作しているかの検出処理までは今回作り切れなかったため現状は見つけたら手直しするような運用になってしまっています。
今後改善を検討していきたいとは考えておりますが、しばらくはカスタムポリシーのお世話が必要であり、なかなかに難しい代物だなと日々痛感させられています。

### あまり使われない…:sob:
10月末にサンドボックスについて組織へ展開しましたが、現在までの利用数は芳しくなくまだあまり使われていない状態です…。
現状、利用者はサンドボックスと称したガードレールの効いた空っぽのリソースグループだけが自由に使える状態なので、合わせてそこで利用できるコンテンツの提供などがないと学習用としては使い辛いのだろうと思われます。
そのため今後、環境で使える学習コンテンツの提供や、ハンズオンを交えた勉強会を行おうという計画を立てています。

# おわりに
一連の処理を実装してみて、ある程度Azureを触ってきたつもりでも自分自身まだまだ勉強が足りてないなと痛感しました。(特にAzure Policy周り…）
今後は自己研鑽を行うと共に、今回は時間が足りず組み込みきれなかったサンドボックスの保存・復元や、IaC生成、ポリシー周りの整理・改善などの処理追加にも取り組んでいきたいと考えています。
またそれとは別に、コミュニティ運営としてクラウドエンジニアを目指す方々の学習ハードルを下げる取り組みを実施していきたいと思います！

---
記載されている会社名、製品名、サービス名は、各社の商標または登録商標です。