From ff0d0de8f8dbdf78df609326a666c09b1789cf35 Mon Sep 17 00:00:00 2001 From: seaislee1209 Date: Sat, 28 Mar 2026 20:34:19 +0800 Subject: [PATCH] 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) --- backend/apps/monitor/views.py | 8 ++++++++ backend/utils/iam_service.py | 37 ++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/backend/apps/monitor/views.py b/backend/apps/monitor/views.py index a062c5f..3799f00 100644 --- a/backend/apps/monitor/views.py +++ b/backend/apps/monitor/views.py @@ -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']) diff --git a/backend/utils/iam_service.py b/backend/utils/iam_service.py index f5c877e..f2858f1 100644 --- a/backend/utils/iam_service.py +++ b/backend/utils/iam_service.py @@ -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 策略"""