fix: deny policy audit - detach before delete, fail on empty project list

- Fix: detach policy before deleting (avoids deletion error on referenced policy)
- Fix: fail explicitly if project list can't be fetched (prevent no-op Deny)
- Add _refresh_all_deny_policies helper for batch refresh after new project creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-03-28 20:34:19 +08:00
parent 0f034b7b26
commit ff0d0de8f8
2 changed files with 27 additions and 18 deletions

View File

@ -59,6 +59,14 @@ def _update_deny_policy(user):
logger.error(f"更新 Deny 策略失败 ({user.username}): {e}")
def _refresh_all_deny_policies():
"""刷新所有子账号的 Deny 策略(新建火山项目后调用)"""
users = IAMUser.objects.filter(status=IAMUser.Status.ACTIVE)
for user in users:
if user.projects.exists():
_update_deny_policy(user)
# ==================== Dashboard ====================
@api_view(['GET'])

View File

@ -122,17 +122,18 @@ class IAMService:
# Get all projects to build explicit deny list
from .volcengine_client import get_resource_client
try:
res_client = get_resource_client(
self.client.ak, self.client.sk
)
resp = res_client.call("ListProjects", {"Limit": "100"})
all_projects = [
p.get("ProjectName", "") for p in
resp.get("Result", {}).get("Projects", [])
]
except Exception:
all_projects = []
res_client = get_resource_client(
self.client.ak, self.client.sk
)
resp = res_client.call("ListProjects", {"Limit": "100"})
all_projects = [
p.get("ProjectName", "") for p in
resp.get("Result", {}).get("Projects", [])
]
if not all_projects:
logger.warning(f"无法获取项目列表,跳过 Deny 策略更新 ({username})")
return
if not allowed_projects:
# No projects, deny everything
@ -165,7 +166,12 @@ class IAMService:
}]
})
# Try to update existing, if not found create new
# Delete old policy (must detach first), then recreate
try:
self.detach_user_policy(username, policy_name, "Custom")
except VolcengineAPIError:
pass # Not attached or doesn't exist
try:
self.client.call("DeletePolicy", {"PolicyName": policy_name})
except VolcengineAPIError:
@ -177,12 +183,7 @@ class IAMService:
"Description": f"AirGate 自动生成:限制 {username} 只能访问授权项目",
})
# Ensure it's attached
try:
self.attach_user_policy(username, policy_name, "Custom")
except VolcengineAPIError as e:
if "PolicyAttachConflict" not in str(e):
raise
self.attach_user_policy(username, policy_name, "Custom")
def remove_deny_policy(self, username: str):
"""移除子账号的 Deny 策略"""