tech.guitarrapc.cóm

Technical updates

NTFS の ACL (アクセス許可) をPowerShell DSC で制御しよう

Windows において、特定のフォルダのアクセス制御をするのはいくつか手段があります。

原則としては *nux 系と同様、ファイルシステム(NTFS) のアクセス許可 (ACL) を制御するのが楽でしょう。

今回は、NFTS のアクセス許可という刺身タンポポを卒業しようというおすすめです。

目次

NFTS のアクセス許可とは

Microsoft TechNet と @IT の説明がわかりやすいでしょう。

What Are Permissions? | Microsoft Learn

www.atmarkit.co.jp

Windowsで制御したい対象のフォルダ/ファイルの プロパティ > セキュリティ > 詳細 をみてみてください。次のような画面になります。

Permissions一覧が、そのフォルダやファイルのNTFS制御を示しています。このアクセス許可の一覧をアクセスコントロールリスト (ACL) と称します。(Access control lists - Win32 apps | Microsoft Learn)

Inherit (日本語OS なら 継承) は、上位フォルダからそのアクセス許可を継承しているかどうかです。

対象のアクセス許可を上位から継承していない場合は、None として継承がないことが明示されます。(これが明示的なアクセス許可です)

ACLの制御

アクセス許可とその一覧は、各フォルダ/ファイルに設定していると、個別にユーザー/グループでの許可/拒否指定が必要になりすぐにカオスになります。

そのため、極力シンプルに保つには「上位フォルダでアクセス許可を設定して下位フォルダはACLを継承」することが大事です。

しかし、ACL制御にはいくつかの問題があります。

  • アクセス許可の不透明さ
  • 個別設定の手間
  • 設定時の影響

問題を順に見ていきましょう。

アクセス許可状態の不透明さ

どこに何が設定されたのか、設定が不透明になりやすいことです。

たとえば、D:\Hoge と D:\Fuga それぞれがどんなACLを持っているのかをTechNet で調べても、その設定変更点をフォルダを横断してみる方法には言及がありません。

View Effective Permissions on Files and Folders | Microsoft Learn

なかには 3rd Party に 簡易 GUI と エクセルでACL一覧をみるというのもあるぐらいで..。

ACLDump | 鉄飛テクノロジー

ACLのcsv書き出し程度ならワンライナーで書いてもいいんすが、求めるのは変更状態の透明性であって使い心地は良くないでしょう。

Get-ChildItem <対象のパス> -Recurse | Get-ACL |Export-Csv <書き出し先パス> -Encoding Default
個別設定の手間

設定したいフォルダを個別にプロパティ > セキュリティ > 詳細 とやっていく作業を、100フォルダに行いたいでしょうか?

サーバーを作りなおすたびに、サーバーのACLを都度設定したいでしょうか?

こういった各フォルダにACLを設定していくだけの作業は、「決まり決まった手順」でありプログラム化です。こんなことは人のやることではないと考えます。

設定時の影響

最大の問題はこれです。ファイル数が10000程度だったり、共有アクセスがないフォルダなら対した影響はありません。

しかしNAS や 実行ファイルがあるフォルダ(かつファイルを排他的にロックする場合) は、アクセス許可を変更した際に操作中のファイルへの処理が拒否されます。

ACL を PowerShell DSC で制御する

*nux でも chmode を使ったACL操作を、Chef で自動化するように、Windows でも PowerShell DSC で ACL 制御の自動化が可能です。これにより、先ほどの問題がある程度解消します。

今回必要があって、NTFS のアクセス許可の継承を制御する DSC Resource を作成しました。以前からACLを制御するリソースは作ってあったので、これで継承もアクセス許可も制御できるようになりました。

PowerShell DSC や Chef による、Configuration Manager にアクセス許可を任せることで、先ほどの問題がどう変わるのか見てみましょう。

アクセス許可状態の不透明さ

コードで記述するため、変更箇所が透明化されます。

ただし、「アクセス許可一覧を取るのではなく変更箇所をコードで指定する」だけなため、そのフォルダにどんなACLが設定されているかは、コードからだけで読み解くのは少し違うシーンがあるでしょう。

大事なのは、「ACL一覧を知ることが目的」ではなく「ACLを適切に制御できていること」というのが基本的な考えになります。*1

個別設定の手間

CI (継続的デリバリー)環境を構築してあれば、DSC の Configuration に落としこんで PULL モードで自動展開されます。

ACLに更新があったら、コンフィグレーションを更新して Commit > CI > Test > 展開でおしまいです。人の手がかかることなく、刺身タンポポ卒業です。

設定時の影響

ここは改善が困難な問題です。そもそもプロセスレベルでのファイルアクセス状態の制御は、副作用(プロセスやユーザーアクセス状態の変化)を伴うため好ましくないでしょう。

サービス環境で影響になることがないので、いったん見ないふり!していますが。

PowerShell DSC リソース

Github で公開しています。

github.com

この中の、cACL と cInheritACL がACLの制御に利用するリソースです。

cACL

cInheritACL

サンプル

例えば、D:\ACL フォルダ内部で以下の構成を作ってみましょう。

C:\ACL\hoge
  • 親フォルダからのACL継承を継承する
  • アクセス許可として、everyone ユーザーをフルコントロール許可する
C:\ACL\fuga
  • 親フォルダからのACL継承を破棄する
  • 継承破棄時に、親フォルダから継承していたアクセス許可を明示的なアクセス許可として持つ

コードです。

gist.github.com

実行してみて、

結果です。

継承を戻す

アクセス許可の継承は戻すこともできます。

とはいえ、ACL は状態が一意に定まらないパターンがあります。今回の「継承をやめる際に明示的なアクセス許可にして、再びアクセス許可の継承を行う。にACL継承設定を戻したりすると、明示的なアクセス許可が継承後も残る」が該当します。

そのため、この操作は副作用を伴うということは把握しておく必要があります。

gist.github.com

まとめ

ACL は DSC で制御しないと生きていけないですね。

cACL は必要な用途に限定しているので、まだ若干細かい操作に対応できないパターンがある気がします。PRお待ちしています。

*1:一覧が欲しいなら一覧をレポートするリソースなどを作ればいいでしょう。いらないけど。