fix: save/restore policies with correct scope (global vs project-level)
- Disable now saves both global and project-level policies with scope info - Restore puts policies back in original scope (global or project) - Project list view now syncs policies from Volcengine in real-time - Fixes: policies incorrectly restored as global after disable/enable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a2a822a889
commit
23ec78e83d
@ -569,6 +569,8 @@ def iam_user_disable_view(request, pk):
|
|||||||
# 2. 移除所有权限策略并保存快照(恢复时加回)
|
# 2. 移除所有权限策略并保存快照(恢复时加回)
|
||||||
saved_policies = []
|
saved_policies = []
|
||||||
detach_errors = []
|
detach_errors = []
|
||||||
|
|
||||||
|
# 2a. 全局策略
|
||||||
try:
|
try:
|
||||||
resp = svc.list_attached_user_policies(user.username)
|
resp = svc.list_attached_user_policies(user.username)
|
||||||
policies = resp.get("Result", {}).get("AttachedPolicyMetadata", [])
|
policies = resp.get("Result", {}).get("AttachedPolicyMetadata", [])
|
||||||
@ -577,12 +579,31 @@ def iam_user_disable_view(request, pk):
|
|||||||
ptype = p.get("PolicyType", "")
|
ptype = p.get("PolicyType", "")
|
||||||
try:
|
try:
|
||||||
svc.detach_user_policy(user.username, pname, ptype)
|
svc.detach_user_policy(user.username, pname, ptype)
|
||||||
saved_policies.append({"name": pname, "type": ptype})
|
saved_policies.append({"name": pname, "type": ptype, "scope": "global"})
|
||||||
except VolcengineAPIError as detach_err:
|
except VolcengineAPIError as detach_err:
|
||||||
detach_errors.append(f"{pname}: {detach_err}")
|
detach_errors.append(f"{pname}(global): {detach_err}")
|
||||||
except VolcengineAPIError:
|
except VolcengineAPIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 2b. 项目级策略
|
||||||
|
for proj in user.projects.all():
|
||||||
|
try:
|
||||||
|
resp = svc.client.call('ListAttachedUserPolicies', {
|
||||||
|
'UserName': user.username,
|
||||||
|
'ProjectName': proj.project_name,
|
||||||
|
})
|
||||||
|
proj_policies = resp.get("Result", {}).get("AttachedPolicyMetadata", [])
|
||||||
|
for p in proj_policies:
|
||||||
|
pname = p.get("PolicyName", "")
|
||||||
|
ptype = p.get("PolicyType", "")
|
||||||
|
try:
|
||||||
|
svc.detach_policy_in_project(user.username, pname, proj.project_name, ptype)
|
||||||
|
saved_policies.append({"name": pname, "type": ptype, "scope": "project", "project": proj.project_name})
|
||||||
|
except VolcengineAPIError as detach_err:
|
||||||
|
detach_errors.append(f"{pname}({proj.project_name}): {detach_err}")
|
||||||
|
except VolcengineAPIError:
|
||||||
|
pass
|
||||||
|
|
||||||
user.status = IAMUser.Status.DISABLED
|
user.status = IAMUser.Status.DISABLED
|
||||||
# 在策略快照里记住停用前的火山登录状态
|
# 在策略快照里记住停用前的火山登录状态
|
||||||
saved_policies.append({"_volc_login_was": user.volc_login_allowed})
|
saved_policies.append({"_volc_login_was": user.volc_login_allowed})
|
||||||
@ -635,12 +656,15 @@ def iam_user_enable_view(request, pk):
|
|||||||
# 1. 恢复 API 密钥 + 控制台(按停用前状态)
|
# 1. 恢复 API 密钥 + 控制台(按停用前状态)
|
||||||
svc.enable_user(user.username, restore_login=restore_login)
|
svc.enable_user(user.username, restore_login=restore_login)
|
||||||
|
|
||||||
# 2. 重新附加停用时保存的策略
|
# 2. 重新附加停用时保存的策略(按原始位置:全局或项目级)
|
||||||
restored_count = 0
|
restored_count = 0
|
||||||
restore_errors = []
|
restore_errors = []
|
||||||
for p in actual_policies:
|
for p in actual_policies:
|
||||||
try:
|
try:
|
||||||
svc.attach_user_policy(user.username, p["name"], p["type"])
|
if p.get("scope") == "project" and p.get("project"):
|
||||||
|
svc.attach_policy_in_project(user.username, p["name"], p["project"], p["type"])
|
||||||
|
else:
|
||||||
|
svc.attach_user_policy(user.username, p["name"], p["type"])
|
||||||
restored_count += 1
|
restored_count += 1
|
||||||
except VolcengineAPIError as restore_err:
|
except VolcengineAPIError as restore_err:
|
||||||
restore_errors.append(f"{p['name']}: {restore_err}")
|
restore_errors.append(f"{p['name']}: {restore_err}")
|
||||||
@ -762,12 +786,34 @@ def iam_user_detach_policy_view(request, pk):
|
|||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def iam_user_project_list_view(request, pk):
|
def iam_user_project_list_view(request, pk):
|
||||||
"""查看子账号关联的项目列表"""
|
"""查看子账号关联的项目列表(实时从火山同步项目级策略)"""
|
||||||
try:
|
try:
|
||||||
user = IAMUser.objects.get(pk=pk)
|
user = IAMUser.objects.get(pk=pk)
|
||||||
except IAMUser.DoesNotExist:
|
except IAMUser.DoesNotExist:
|
||||||
return Response({'error': 'not_found'}, status=status.HTTP_404_NOT_FOUND)
|
return Response({'error': 'not_found'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
projects = user.projects.all()
|
projects = user.projects.all()
|
||||||
|
|
||||||
|
# 实时从火山查询每个项目的策略,同步到本地
|
||||||
|
account, ak, sk = _get_volc_account(user.volc_account_id)
|
||||||
|
if ak:
|
||||||
|
svc = IAMService(ak, sk)
|
||||||
|
for proj in projects:
|
||||||
|
try:
|
||||||
|
resp = svc.client.call('ListAttachedUserPolicies', {
|
||||||
|
'UserName': user.username,
|
||||||
|
'ProjectName': proj.project_name,
|
||||||
|
})
|
||||||
|
volc_policies = [
|
||||||
|
p.get('PolicyName', '')
|
||||||
|
for p in resp.get('Result', {}).get('AttachedPolicyMetadata', [])
|
||||||
|
]
|
||||||
|
if set(volc_policies) != set(proj.attached_policies or []):
|
||||||
|
proj.attached_policies = volc_policies
|
||||||
|
proj.save(update_fields=['attached_policies'])
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return Response(IAMUserProjectSerializer(projects, many=True).data)
|
return Response(IAMUserProjectSerializer(projects, many=True).data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user