Alliance Auth 的 Discord 集成对账审计。将配置的 Discord 服务器中实际的角色分配与 Alliance Auth 中表达的状态(每个用户的 Groups + State)进行比较,并封堵管理员可以将 AA 命名的角色手动分配给 AA 未知用户的漏洞。
状态: alpha(
0.1.x)。公共 API 和设置可能在1.0之前仍会发生变化。
审计默认安全:
InitialAuditAcknowledgement(仅限管理员或 shell)。report——破坏性操作需主动选择加入。AuditRun、AuditFinding、AuditInvocation、ConfigChangeLog)在管理器层和实例层均为仅追加;批量 update() / bulk_update() 被阻止。每个服务器成员被分类到一个类别:
| 类别 | 含义 |
|---|---|
unknown_guest | AA 完全不了解的 Discord 成员 |
linked_no_perm | 身份已知于 AA 但缺少 discord.access_discord |
bot_filtered | 配置的机器人账户——永不处理 |
操作员将每个类别映射到一个操作:
| 操作 | 行为 |
|---|---|
report | 记录发现;不进行 Discord 端更改 |
strip | 移除 AA 管理的角色 |
strip_kick | 移除 AA 管理的角色,然后从服务器踢出 |
该映射是 AA_DISCORD_AUDIT_POLICY 设置;按组和按状态的覆盖嵌套在每个类别内。
allianceauth.services.modules.discord)已安装并配置
(机器人令牌 + 服务器)pip install aa-discord-audit
在你的 Auth local.py 中:
# `aa_discord_audit` must appear AFTER
# `allianceauth.services.modules.discord` so the discord module's
# models load first; `apps.ready()` raises `ImproperlyConfigured`
# otherwise.
INSTALLED_APPS += ["aa_discord_audit"]
MIDDLEWARE += [
"aa_discord_audit.current_user.CurrentUserMiddleware",
]
然后运行迁移:
python manage.py migrate aa_discord_audit
CurrentUserMiddleware 是必需的——如果缺少它,apps.ready() 会抛出
ImproperlyConfigured。正是它让 ConfigChangeLog 信号处理器能够将管理员编辑归因于真实用户,
而不是 <system>。
将 aa_discord_audit.run_audit 授予执行审计的运营角色。
运行一次试运行审计:
python manage.py audit_discord_roles --action report
在 Auth 仪表盘的 Discord Audit → Audit runs 下查看审计结果。
解除首次运行锁定——可以通过管理后台创建一行 InitialAuditAcknowledgement 记录,或运行
python manage.py audit_acknowledge_initial。两者都需要
aa_discord_audit.run_audit 和
aa_discord_audit.acknowledge_initial_audit 权限。
准备就绪后,使用你选择的破坏性操作重新运行。
| 权限代号 | 控制范围 |
|---|---|
aa_discord_audit.run_audit | 管理命令、beat 任务、删除运行记录 |
aa_discord_audit.run_audit_destructive | strip / strip_kick 的 Web 启动门控(与 run_audit 分开) |
aa_discord_audit.acknowledge_initial_audit | 解除首次运行试运行锁定 |
aa_discord_audit.manage_discord_identity | DiscordIdentity 管理后台 |
aa_discord_audit.manage_role_exception | ManagedRoleException 管理后台 |
aa_discord_audit.manage_protected_member | ProtectedDiscordMember 管理后台 |
aa_discord_audit.manage_bot_account_uid | BotAccountUid 管理后台 |
aa_discord_audit.manage_finding_override | FindingActionOverride 管理后台 |
aa_discord_audit.view_auditrun (及相关权限) | Auth 仪表盘中的只读审计追踪 |
manage_* 权限代号按影响范围拆分,因此拥有 manage_bot_account_uid 的初级用户无法通过编辑
ManagedRoleException 来削弱审计功能。
所有设置均为可选。默认值安全。
# Action policy. Bare-string form below is shorthand for
# {"default": "<action>"}; use the nested form for per-group / per-state
# overrides keyed by AA group name and state name.
AA_DISCORD_AUDIT_POLICY = {
"unknown_guest": "report",
"linked_no_perm": "report",
# "strip" is rejected at startup for linked_no_perm (it conflicts with
# AA's update_groups task); use "strip_kick" instead.
# "linked_no_perm": {
# "default": "strip_kick",
# "by_state": {"Guest": "report"},
# "by_group": {"Directors": "report"},
# },
}
# AA-notify fan-out to permission holders.
AA_DISCORD_AUDIT_NOTIFY_ADMINS = True
# Discord webhook for run summaries. Treat as a credential.
AA_DISCORD_AUDIT_WEBHOOK_URL = None
# uids skipped as bot accounts (in addition to the BotAccountUid admin
# table).
AA_DISCORD_AUDIT_BOT_UIDS = []
# Auto-discover bot accounts by Discord nickname heuristics. Reserved
# for v2; not implemented in the MVP. The startup validator raises
# ImproperlyConfigured if set to True — keep this False and use the
# explicit BotAccountUid admin table instead.
AA_DISCORD_AUDIT_AUTO_DISCOVER_BY_NICKNAME = False
# Retention. 0 disables pruning; the validator refuses 0 unless the
# acknowledged flag below is also set.
AA_DISCORD_AUDIT_RUN_RETENTION_DAYS = 180
AA_DISCORD_AUDIT_RETENTION_OPT_OUT_ACKNOWLEDGED = False
# Idempotency-key TTL. When positive, prune_audit_runs releases
# AuditRun.idempotency_key on rows older than the cutoff while the
# row itself stays for RUN_RETENTION_DAYS. 0 (default) disables the
# expiry; the key dies with the row.
AA_DISCORD_AUDIT_IDEMPOTENCY_KEY_TTL_DAYS = 0
# Per-run deadline. The Celery task's soft_time_limit follows.
AA_DISCORD_AUDIT_RUN_DEADLINE_MINUTES = 60
# Rolling 24h rate limit on accepted audit triggers per user.
# DISABLED is an opt-out gate; refuses to take effect unless
# explicitly toggled.
AA_DISCORD_AUDIT_RUN_RATE_LIMIT_PER_DAY = 5
AA_DISCORD_AUDIT_RUN_RATE_LIMIT_DISABLED = False
# Discord webhook delivery tuning.
AA_DISCORD_AUDIT_WEBHOOK_TIMEOUT = 10
AA_DISCORD_AUDIT_WEBHOOK_MAX_RETRIES = 3
# Opt-in: bulk PATCH role strip. Faster on large guilds; off by default
# while we collect operator feedback on Discord-side rate-limit shape.
AA_DISCORD_AUDIT_USE_BULK_ROLE_STRIP = False
# Periodic (Celery beat) audit. Destructive actions on the unattended
# beat require this explicit opt-in, independent of the one-shot
# first-run lock: a beat run carrying strip/kick is coerced to report
# otherwise, with a startup warning on mismatch.
AA_DISCORD_AUDIT_BEAT_ALLOW_DESTRUCTIVE = False
# Coarse global floor between beat runs, in minutes. 0 (default)
# disables it — the Celery beat schedule is the primary cadence
# control. A backstop against a misconfigured fast schedule
# (QueueOnce only dedupes concurrent ticks, not back-to-back ones).
AA_DISCORD_AUDIT_BEAT_MIN_INTERVAL_MINUTES = 0
# Pin the CLI acting user to a Django username (the "service principal"
# pattern). The management command has no HTTP request, so the actor is
# normally derived from the OS login; set this for clean, stable
# ConfigChangeLog attribution from cron and manual CLI alike. Resolved
# and permission-checked per invocation.
AA_DISCORD_AUDIT_CLI_ACTOR = None