リソースロックの罠

## はじめに
Azureには __リソースロック__ という機能があります。
リソースロックには『読み取り専用ロック』と『削除ロック』という2種類のロックレベルあり、サブスクリプション、リソースグループ、リソースの単位でロックを付与することができます。Azureのベストプラクティスでも「誤ってリソースを削除しないためにリソースロックを使うべし！」と書かれていますが、実はリソースロックは注意して使わないと痛い目を見ることがあります。今日はそんなリソースロックの罠について書いてみたいと思います。

なお、リソースロックに関するMicrosoftの公式ドキュメントは下記のとおりです。

https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/management/lock-resources?tabs=json


## リソースロックを知る

Azureのリソースロックには『読み取り専用ロック』と『削除ロック』があリますが、端的に言えば以下のような違いがあります。
* 削除ロック（CanNotDelete）・・・そのリソースを削除することを抑止する
* 読み取り専用ロック（ReadOnly）・・・そのリソースを変更することを抑止する

もう少し詳細に説明すると、これはRBACに関係します。RBACはAzureリソースに対する権限コントロールの仕組みになりますが、どのリソース種別に対してどのようなアクションを許可（拒否）するかという構造になっています。
```
Microsoft.Network/*/read
```
上記は、Azureの全てのネットワークサービスに対して「閲覧権限」を与える定義になります。リソースロックに大きく影響するのは末尾のアクションの部分です。ここには、"read"、"write"、"delete"、"action"の4つのアクションを書くルールになっています。（厳密には"*"(オールOK)もあります。）つまり、リソースロックは、このアクション群をRBACの外側から抑止する機能であるといえます。各リソースロックとRBACのアクションの関係を示すと以下になります。

* 削除ロック→"delete"のアクションのみを抑止する
* 読み取り専用ロック→"read"以外のアクションを抑止する

また、リソースロックは、サブスクリプション→リソースグループ→リソースでロックの継承関係があります。リソースグループのレイヤで『削除ロック』をつけた場合、その配下のリソースに対しても『削除ロック』が適用されます。また、その継承関係には、より強いロックが有効になります。例えば、リソースグループに対して『削除ロック』、配下のリソースに対して『読み取り専用ロック』をつけた場合、そのリソースには『読み取り専用ロック』が適用されます。リソースグループに対して『読み取り専用ロック』、配下のリソースに対して『削除ロック』をつけた場合、そのリソースには『読み取り専用ロック』が適用されます。

この場合、VMには『読み取り専用ロック』が適用されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/888f51cc-6802-c5c3-ddf6-2164d02a8b72.png)

この場合も、VMには『読み取り専用ロック』が適用されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/672a3483-472f-caff-ad31-3999114391d3.png)

また、リソースロックはその名の通りAzureのリソースに対するロック制御機能ですが、この有効範囲はコントロールプレーン（Azureの操作を行うレイヤ）のみで、データプレーン（ユーザデータの操作を行うレイヤ）は範囲外になります。例えば、Azure Storageの構成に対する操作はリソースロックが有効ですが、Azure Storageに格納されているBLOB等のデータに対する操作はリソースロック対象外となります。


## リソースロックの使いどころ

よく使われるのは『削除ロック』です。リソースの削除操作は、Azureポータルをポチポチするだけで実行できてしまう結構危険な操作です。そのため、例えば本番環境メンテ中に誤ってVMを削除してしまうといった事故が起きてしまう可能性もあります。本番環境においてはリソースグループに対して『削除ロック』をかけることを推奨します。そうしておけば、誤ってVMの削除操作を行ったとしても、以下のようなエラーとなりリソース削除を防ぐことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/b2e5340a-f55e-6021-713d-e09e45e733a1.png)

同様に、誤って設定変更されると致命的にマズいリソースには、より安全を期して『読み取り専用ロック』を付与しておきましょう。環境に対して強い統制をかけたい場合にも『読み取り専用ロック』を使う場合もあります。実はリソースロックを操作できるロールは「Microsoft.Authorization/locks/*」という極めて高い権限になります。組み込みロールでいうと「所有者」のみが有しており「共同作成者」にも付与されていません。そのため、通常、読み取り専用ロックをかけておいて、変更が必要な場合にのみ「所有者」権限を持つ人が一時的にロックを解除する、という運用を行うことも可能です。
以下のように『読み取り専用ロック』を付けていれば、VMの停止さえできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/24b70458-48fd-d68b-d6bc-5e67e7d33789.png)


## リソースロックの罠

ここが一番伝えたかったことなのですが、特に『読み取り専用ロック』については、適用することでAzureが正しく動かなくなることがあります。先ほど説明した通り『読み取り専用ロック』は"read"以外のアクションを抑止する機能ですが、Azureが通常動作する中で内部的に"write"や"action"を行っていることがあり、こういった内部動作も抑止してしまうからです。私も本番ワークロードの中で『読み取り専用ロック』を多用しているのですが、その中で『読み取り専用ロック』でハマったことが数多くあります。ここではそんなハマった経験を元に『読み取り専用ロック』の注意点を挙げていきたいと思います。特に★マークを付けたものは致命的にハマったものです。

##### ★AppServicePlanのロックの影響でAppServiceのオートスケールができない
AppServicePlanでWebAppsなどを動かしている場合、スケールアウト・インはAppServicePlanの役目になります。そのためAppServicePlanに『読み取り専用ロック』を付けてしまうと、オートスケールも効かなくなりアクティビティログにシレっと以下のエラーが出力されます。AppServicePlanに『読み取り専用ロック』を付けるのは避けましょう。

> "The scope'/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/(rg-name)/providers/Microsoft.Web/serverfarms/(AppServicePlan-name)'cannot perform write operation because following scope(s) are locked:'/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/(rg-name)/providers/Microsoft.Web/serverfarms/(AppServicePlan-name)'.Please remove the lock and try again."

##### AppServiceのアプリケーション構成が参照できない
AppServiceのアプリケーション構成は参照するだけでもreadアクション以外のロールが必要なようです。そのため『読み取り専用ロック』を付けると下記のような表示になってしまいます。アプリケーション構成の中身（例えば他リソースへの接続文字列）を見られたくないならむしろ好都合ですが、多少保守性が落ちますので注意してください。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/5971665d-4087-2be5-086e-0367bf591bae.png)

##### ★Log Analyticsのロックの影響でAKSの起動に失敗する
これが最近一番ハマったことです。これはAKS自体にロックをかけていたのではなくAKSと紐づけているLog Analyticsに『読み取り専用ロック』を掛けていました。AKS起動の際にはLogAnalyticsの共有プライマリキーを読み込む処理が実施されるのですが、これにwriteアクションが必要でした。読み込み処理になのにwriteやactionが必要というのは”Azureあるある”ではありますが、直感的ではないので変えてほしいところです。。ちなみにこの場合は下記のようなエラーが出ます。AKS起動エラーなのにLogAnalyticsのロックによるものというのが分かります。

> "The scope '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/(rg-name)/providers/Microsoft.OperationalInsights/workspaces/(LogAnalytics workspace-name)' cannot perform write operation because following scope(s) are locked: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/(rg-name)/providers/microsoft. operationalinsights/workspaces/(LogAnalytics workspace-name)'. Please remove the lock and try again."

##### Azure Container Registoryのpushができなくなる
これはなんとなく分かっていましたが、ACRに『読み取り専用ロック』を付けるとイメージのPullはできますがPushができなくなります。ACRで管理するイメージを固定化したり厳しい統制を掛けたい場合は、Push時に一時的にロックを解除するという運用もアリかもしれませんが、開発スピードが低下しますので要件次第といったところです。

##### ★Azure Container Registoryのレプリケーション設定ができない
こちらも最近コンテナ基盤の案件でハマりました。ACRにはレポジトリを他リージョンにレプリケーションし可用性を高める機能がついています。これを有効化しようとしたのですが、他リージョンのレプリケーション設定が”Creating”で固まり、一向に”Suceeded”にならない現象が発生しました。こちらはMSサポートに問い合わせた結果、ACRに設定しているプライベートエンドポイントおよびプライベートDNSゾーンの『読み取り専用ロック』が原因でした。これが厄介だったのはAzure側でエラーとならずステータスが変わらなかったことです。レプリケーションに時間がかかってるのか、処理が止まっているのか判断できなかったのが辛かったです。Azureでは時々そういった罠がありますのでご注意ください。
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/50a90371-6336-0d68-6811-90fa033bbb3f.png)

##### Application Gatewayのバックエンド正常性が参照できない
これも参照系なのにreadアクション以外を使っている系です。『読み取り専用ロック』を付けている状態でバックエンド正常性を開くと以下の画面となります。そもそも閲覧者権限でも参照できないのもどうかと思いますが、このあたりも改善していただきたいところです。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/36aade4c-a8e6-1ad3-68d2-815a6c91ebb3.png)

他にも色々あったと思いますが、一旦思いつくところでは以上です。その他冒頭に紹介したMicrosoftサイトにもリソースロックにより影響を受けるリソースの説明がありますのでご参考ください。__[ロック適用前の考慮事項]__ の章が参考になります。

https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/management/lock-resources?tabs=json#considerations-before-applying-your-locks

## リソースロックの罠にハマらないようにするために

リソースロックを使う場合は予め以下のようなことを心がけておくとよいと思います。

##### 『削除ロック』はリソースグループに適用する

『削除ロック』がリソースに与える影響は、あくまで削除の抑止のみです。そのため比較的軽く適用を進めていただいて問題ありません。適用のスコープとしてはサブスクリプションもアリですが、リソース削除したくなった場合に、サブスクリプションスコープだと削除対象でないリソースにも少なからず影響が出てしまうので、あまりよろしくありません。かと言ってリソーススコープだと細かすぎます。リソースグループスコープで適用するのが一番運用しやすいかと思います。

##### 『読み取り専用ロック』の適用は限定的に

これまで説明してきたように『読み取り専用ロック』はとても強力なロックで、Azureの内部動作でさえ抑止してしまうことがあります。通常時から『読み取り専用ロック』を付けてリソースを守りたい気持ちもありますが、やはり『読み取り専用ロック』の多用は控えた方がよいと思います。当然のことながら、サブスクリプションやリソースグループの単位では『読み取り専用ロック』を適用することは止めて、本当に守る必要があるリソースを狙って『読み取り専用ロック』を使うようにしましょう。

##### リソースロックは早期に適用を

よくリリース直前になり「本番稼働後のリソースを守るため」という名目でリソースロックを適用することがありますが、リソースロックはシステム構築時のテストフェーズで有効にしておくことが大事です。特に『読み取り専用ロック』については、リソースにどんな影響があるか分かりませんので、できるだけ早めに適用してロックが有効な状態でシステムテストを実施することをお勧めします。

##### とは言えリソースロックを活用しましょう

色々ハマりどころはありますが、各ロックレベルに対する適用範囲をしっかり見定め、十分なテストを行い、リソースロックをモノにしてしまいましょう。環境を守るための手段としてリソースロックは極めて有効です。

## おわりに

今回は、Azureのリソースロックについて語らせていただきました。使いどころをきちんと押さえておけば強力なツールになりますので、みなさんも是非活用してみてください。それでは。