一覧SP-13-1 · ITDR:アイデンティティの脅威検知

IDとグループの権限分析

表示名ではなく出所付きのIDで主体を特定し、権限が届く経路を示します。

説明

ITDRでは認証や権限変更の記録を結び、アイデンティティを使った行動を調べます。同じ表示名でも別の組織やテナントの主体である場合があります。

固定の主体台帳を正規化し、グループやロールを経由する権限のつながりをSQLで検索します。サービスIDも含め、直接付与だけでは見えない関係を調べます。

表示名ではなく出所付きのIDで主体を特定し、権限が届く経路を示します。

1出所を含めて主体を列挙する

realmはIDの発行元を表す教材用の区分です。

from sp13 import * from sp02 import show出所を含めて主体を列挙する db=connect() show(db,"SELECT realm,id,name,kind FROM identity ORDER BY realm,id")

corpとlabのu7は、IDと名前が同じでも別主体です。svc7は人のアカウントではなくサービスIDです。

2同名の主体を検索する

aliceという表示名だけで検索します。

show同名の主体を検索する(db,"SELECT realm,id FROM identity WHERE name='alice'")

2件残ります。表示名は調査の入口には使えますが、一つの主体を確定するキーには不足しています。

3直接の関係を開く

srcからdstへ、member・grant・readという関係があります。

show直接の関係を開く(db,"SELECT * FROM edge ORDER BY src,dst")

corp:u7はgroup:opsへ所属し、グループはrole:readerを付与されています。サービスIDには別の経路があります。

4グループ経由の到達先を求める

再帰CTEで次の関係を繰り返したどります。

query="WITH RECURSIVEグループ経由の到達先を求める reach(node) AS (VALUES(?) UNION SELECT e.dst FROM edge e JOIN reach r ON e.src=r.node) SELECT node FROM reach ORDER BY node" show(db,query,('corp:u7',))

group:opsとrole:readerに到達します。この関係表は権限経路の資料で、denyや期限などの条件は別に照合します。

5サービスIDの経路を比較する

同じ検索をsvc7から始めます。

showサービスIDの経路を比較する(db,query,('corp:svc7',))

role:deploy経由でsecret:releaseへ到達します。利用者だけの棚卸しではサービスIDの経路を見落とします。

6新しい付与による到達範囲の変化を確認する

opsグループにdeployロールへの関係を追加します。

db.execute("INSERT INTO edge VALUES ('group:ops','role:deploy','grant')") show新しい付与による到達範囲の変化を確認する(db,query,('corp:u7',))

u7からもsecret:releaseへの経路ができました。変更した1行だけでなく、継承先を含めて影響を確認します。

7別の発行元の同名主体へ波及しないことを確認する

lab:u7からの到達先を検索します。

show別の発行元の同名主体へ波及しないことを確認する(db,query,('lab:u7',))

出発点だけです。表示名で関係を結んでいたら、本来関係のない主体へ権限を誤って対応付けるところでした。

まとめ

発行元とIDを組にして主体を特定します。

グループやロールを経由する関係もたどります。

権限変更の影響は継承先まで確認します。

操作履歴と解説を振り返れます。

Python 3.15 / SQLite / 固定の主体・権限・操作記録

1
from sp13 import * from sp02 import show db=connect() show(db,"SELECT realm,id,name,kind FROM identity ORDER BY realm,id")
realm | id | name | kind
corp | svc7 | builder | service
corp | u7 | alice | human
lab | u7 | alice | human
2
show(db,"SELECT realm,id FROM identity WHERE name='alice'")
realm | id
corp | u7
lab | u7
3
show(db,"SELECT * FROM edge ORDER BY src,dst")
src | dst | kind
corp:svc7 | role:deploy | grant
corp:u7 | group:ops | member
group:ops | role:reader | grant
role:deploy | secret:release | read
4
query="WITH RECURSIVE reach(node) AS (VALUES(?) UNION SELECT e.dst FROM edge e JOIN reach r ON e.src=r.node) SELECT node FROM reach ORDER BY node" show(db,query,('corp:u7',))
node
corp:u7
group:ops
role:reader
5
show(db,query,('corp:svc7',))
node
corp:svc7
role:deploy
secret:release
6
db.execute("INSERT INTO edge VALUES ('group:ops','role:deploy','grant')") show(db,query,('corp:u7',))
node
corp:u7
group:ops
role:deploy
role:reader
secret:release
7
show(db,query,('lab:u7',))
node
lab:u7

演習完了