feat: add Deny policy exempt toggle for admin sub-accounts

- New deny_policy_exempt field on IAMUser model
- Toggle in monitoring config dialog
- Exempt accounts skip Deny policy creation
- Changing the toggle immediately updates/removes Deny policy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-03-29 00:01:35 +08:00
parent 5b997bc1a7
commit 9f00e6996b
5 changed files with 41 additions and 0 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.21 on 2026-03-28 16:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('monitor', '0009_iamuser_volc_login_allowed'),
]
operations = [
migrations.AddField(
model_name='iamuser',
name='deny_policy_exempt',
field=models.BooleanField(default=False, help_text='开启后不生成项目隔离 Deny 策略(适用于管理员自用账号)', verbose_name='免除 Deny 策略'),
),
]

View File

@ -62,6 +62,9 @@ class IAMUser(models.Model):
triggered_alerts = models.JSONField('已触发的告警阈值', default=list, blank=True,
help_text='记录已通知过的百分比,划拨新额度时自动重置')
deny_policy_exempt = models.BooleanField('免除 Deny 策略', default=False,
help_text='开启后不生成项目隔离 Deny 策略(适用于管理员自用账号)')
# --- 停用时保存的策略快照(恢复时自动加回) ---
saved_policies_on_disable = models.JSONField('停用时保存的策略', default=list, blank=True,
help_text='停用时自动移除的策略列表,恢复时加回')

View File

@ -42,6 +42,7 @@ class IAMUserSerializer(serializers.ModelSerializer):
'effective_alert_thresholds',
'projects', 'monitored_project_count',
'login_enabled', 'volc_login_allowed',
'deny_policy_exempt',
'remark', 'created_at', 'updated_at',
]
read_only_fields = ['user_id', 'access_key_ids', 'status',
@ -77,6 +78,7 @@ class IAMUserConfigSerializer(serializers.Serializer):
)
monitor_enabled = serializers.BooleanField(required=False)
auto_disable_enabled = serializers.BooleanField(required=False)
deny_policy_exempt = serializers.BooleanField(required=False)
class IAMUserProjectAddSerializer(serializers.Serializer):

View File

@ -50,6 +50,12 @@ def _update_deny_policy(user):
if not ak:
return
svc = IAMService(ak, sk)
if user.deny_policy_exempt:
# 免除 Deny 策略的账号,移除已有的 Deny 策略
svc.remove_deny_policy(user.username)
return
allowed_projects = list(
user.projects.values_list('project_name', flat=True)
)
@ -420,9 +426,16 @@ def iam_user_update_view(request, pk):
serializer = IAMUserConfigSerializer(data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
deny_changed = 'deny_policy_exempt' in serializer.validated_data and \
serializer.validated_data['deny_policy_exempt'] != user.deny_policy_exempt
for field, value in serializer.validated_data.items():
setattr(user, field, value)
user.save()
if deny_changed:
_update_deny_policy(user)
return Response(IAMUserSerializer(user).data)

View File

@ -155,6 +155,10 @@
<el-switch v-model="configForm.auto_disable_enabled" />
<span class="switch-hint">{{ configForm.auto_disable_enabled ? '消费达100%额度时自动停用' : '仅通知不停用' }}</span>
</el-form-item>
<el-form-item label="免除 Deny 策略">
<el-switch v-model="configForm.deny_policy_exempt" />
<span class="switch-hint">{{ configForm.deny_policy_exempt ? '不限制项目访问(管理员账号)' : '按关联项目限制访问' }}</span>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="configVisible = false">取消</el-button>
@ -488,6 +492,7 @@ function openConfig(row) {
alert_thresholds: [...(row.alert_thresholds?.length ? row.alert_thresholds : row.effective_alert_thresholds || [50, 80, 90])],
monitor_enabled: row.monitor_enabled,
auto_disable_enabled: row.auto_disable_enabled,
deny_policy_exempt: row.deny_policy_exempt || false,
}
newStep.value = null
configVisible.value = true