diff --git a/backend/apps/monitor/migrations/0010_iamuser_deny_policy_exempt.py b/backend/apps/monitor/migrations/0010_iamuser_deny_policy_exempt.py
new file mode 100644
index 0000000..c29ac6e
--- /dev/null
+++ b/backend/apps/monitor/migrations/0010_iamuser_deny_policy_exempt.py
@@ -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 策略'),
+ ),
+ ]
diff --git a/backend/apps/monitor/models.py b/backend/apps/monitor/models.py
index 6a1565a..58d036a 100644
--- a/backend/apps/monitor/models.py
+++ b/backend/apps/monitor/models.py
@@ -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='停用时自动移除的策略列表,恢复时加回')
diff --git a/backend/apps/monitor/serializers.py b/backend/apps/monitor/serializers.py
index f17bd80..bed8e2a 100644
--- a/backend/apps/monitor/serializers.py
+++ b/backend/apps/monitor/serializers.py
@@ -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):
diff --git a/backend/apps/monitor/views.py b/backend/apps/monitor/views.py
index be08cb0..200c889 100644
--- a/backend/apps/monitor/views.py
+++ b/backend/apps/monitor/views.py
@@ -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)
diff --git a/frontend/src/views/iam/IAMUserList.vue b/frontend/src/views/iam/IAMUserList.vue
index e5f1eda..401fd65 100644
--- a/frontend/src/views/iam/IAMUserList.vue
+++ b/frontend/src/views/iam/IAMUserList.vue
@@ -155,6 +155,10 @@
{{ configForm.auto_disable_enabled ? '消费达100%额度时自动停用' : '仅通知不停用' }}
+
+
+ {{ configForm.deny_policy_exempt ? '不限制项目访问(管理员账号)' : '按关联项目限制访问' }}
+
取消
@@ -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