Authentik 接管 Atlassian Data Center 全家桶

动机
公司的 Atlassian 全家桶(Jira / Confluence / Bitbucket / Bamboo,全是 Data Center 版)一直挂在 Crowd 上做用户中心。Crowd 的角色很简单:把 Windows AD 当后端,自己再同步一份用户/组到下游各个 app 里去。单论 Atlassian 这一摊事儿,跑得也算稳,本来没什么动它的理由。
真正想动它,是因为 Authentik 这条新线。Authentik 是不久前刚搭起来的统一身份入口,长期目标是把公司里越来越多的新业务(自建工具、内部看板、第三方 SaaS、新上的开源服务)都收到一个 SSO 入口下面——新业务要么走 SAML、要么走 OIDC,统一接到 Authentik 就完事,不再需要每上一个新服务都重新写一遍 AD 集成、也不再需要把 LDAP 凭据发出去给一堆服务各自持有。
Atlassian 这一摊老资格自然该并进来。从「Atlassian → Crowd → AD」改成「Atlassian → Authentik → AD」之后:
- 公司里所有服务的登录入口长一个样,不会出现「这套走 Crowd、那套走 Authentik、新业务又是另一套」的割裂
- 直接跟 AD 说话的服务从一堆收敛到「只有 Authentik」,AD 那边的攻击面和暴露的 bind 凭据数都跟着收
- 以后想给 Atlassian 加任何额外的访问策略(按 IP、按设备、按角色),在 Authentik 一处加完即可,不用挨个 app 改
- Crowd 这一层可以一并退役,少一个 Java + Postgres 实例要养
折腾下来发现:只要先做 SAML、再换用户目录、最后退役 Crowd,整条链路可以平滑切。下游已有用户的 issue 分配、权限、关注者一个都不会丢。这篇把每一步、踩过的坑、最终配置都写下来,下次再切别的 app 直接抄。
名词速览
文章里频繁出现的几个缩写和概念,怕第一次接触的读者懵,先过一下:
- SSO(Single Sign-On)—— 单点登录。一次登录,下游多个系统通用,登录这件事统一收到一个身份服务来做。
- IdP / SP —— SSO 里的两个角色。IdP(Identity Provider,身份提供方)负责验证用户、签发凭证,本文就是 Authentik;SP(Service Provider,服务提供方)是消费这份凭证的业务系统,本文就是 Jira / Confluence / Bitbucket / Bamboo。
- SAML(Security Assertion Markup Language)—— 上一代主流 SSO 协议,基于 XML,2005 年定型。Atlassian / Salesforce / 各种企业 SaaS 这类老牌产品基本都支持,本文用的就是它。
- OIDC(OpenID Connect)—— 新一代 SSO 协议,构建在 OAuth 2.0 之上,基于 JSON / JWT,对 Web 和移动 App 友好。Atlassian Data Center 这一侧,Jira / Confluence / Bitbucket 已经原生支持 OIDC,只有 Bamboo 还得靠第三方插件。本文统一走 SAML 主要是为了四个 app 走同一套配置路径、模板可复用,并不是 OIDC 跑不了——如果改走 OIDC,Bamboo 那一档就要单独引入第三方插件来维护。
- LDAP / AD —— LDAP 是用户/组目录的查询协议;AD(Active Directory)是微软自家的 LDAP 实现。本文里 AD 是「事实源」,所有用户身份最终都从这里来。
- NameID / Audience / ACS URL —— SAML 协议里的几个关键字段。NameID 是 IdP 告诉 SP「这个登录的人是谁」用的标识;Audience 是 SP 自报的接收方身份(IdP 用来判断这份断言该发给谁);ACS URL(Assertion Consumer Service)是 SP 用来接收 SAML 断言的入口。后面填配置时反复见到。
- JIT provisioning(Just-In-Time provisioning)—— 用户第一次 SSO 登录时,SP 在本地数据库自动给 ta 建一个账号。本文没启用,理由后面「迁移思路」里说。
- Crowd —— Atlassian 自家的用户中心 / SSO 中转层产品,跑在 Server / Data Center 模式下。本文要退役的就是它。
整体架构
切换前:
flowchart LR
AD[Active Directory
dc.example.com]
Crowd[Crowd
crowd.example.com]
Jira[Jira]
Conf[Confluence]
Bit[Bitbucket]
Bam[Bamboo]
User[User Browser]
AD -->|LDAP sync| Crowd
Crowd -->|user directory| Jira
Crowd -->|user directory| Conf
Crowd -->|user directory| Bit
Crowd -->|user directory| Bam
User -->|login| Crowd
切换后:
flowchart LR
AD[Active Directory
dc.example.com]
Auth[Authentik
auth.example.com]
Jira[Jira]
Conf[Confluence]
Bit[Bitbucket]
Bam[Bamboo]
User[User Browser]
AD -->|LDAP sync
authentik-bind| Auth
AD -->|user directory
atlassian-bind read-only| Jira
AD -->|user directory
atlassian-bind read-only| Conf
AD -->|user directory
atlassian-bind read-only| Bit
AD -->|user directory
atlassian-bind read-only| Bam
User -->|SAML SSO| Auth
Auth -.assertion.-> Jira
Auth -.assertion.-> Conf
Auth -.assertion.-> Bit
Auth -.assertion.-> Bam
迁移思路
两个原则定下来后剩下的就好拆:
- AD 是唯一事实源,所有用户和组都从 AD 来
- 只允许 Authentik 拿特权 bind(带 Reset Password 那种),别的服务一律用只读 bind
按这两条,主线分三步:
第一步:先上 SAML,用户目录不动 —— 每个 app 加一个 Authentik 的 SAML 配置,登录走 Authentik,但用户依然落在 Crowd 那个目录上。SAML NameID 用 sAMAccountName,恰好就是 Crowd 同步过来的 username key,登录时不会建新账号、也不会有重复。回滚成本极低——一个 REST PATCH 就能把本地登录框打开。
第二步:把用户目录从 Crowd 换成 AD 直连 —— 每个 app 加一个新的「Microsoft Active Directory」目录,bind 用一个新的只读账号 atlassian-bind,base DN 限定 OU=People,group 限定 OU=Atlassian,OU=Groups。用户/组数和 Crowd 那边对齐了,再把 Crowd 那个目录关掉(不删,留底)。
第三步:退役 Crowd —— 先备份整个 Crowd 实例,停掉,观察一个月没人来抱怨,再彻底销毁 + 删 DNS + 删 AD 里的 crowd-administrators 组。
主线之外还有两件配套的事,跟主线穿插着做:第二步完事之后顺手把 REST 的 Basic Auth 关掉收紧攻击面、第三步退役 Crowd 之后调整新员工开通流程。下面按时间顺序一段段写。
JIT provisioning 我没用。理由:JIT 之后组同步是滞后的(首次登录才创建),用户选择器里搜不到没登录过的人,预先建账号也做不了。AD 直连同步的话这些都是顺带就有的。
准备工作
涉及到的服务版本和域名:
| 服务 | 版本 | 域名 |
|---|---|---|
| Authentik | 2026.2.2 | auth.example.com |
| Jira Software Data Center | 11.3.1 | jira.example.com |
| Confluence Data Center | 10.2.2 | wiki.example.com |
| Bitbucket Data Center | 9.4.16 | git.example.com |
| Bamboo Data Center | 12.1.1 | ci.example.com |
| Crowd Data Center(待退役) | 7.1.3 | crowd.example.com |
部署上,所有服务都跑在 Docker 里,Docker 又跑在 PVE 的 LXC 容器中。这套基础设施跟本文 SAML 配置没关系,下文不展开——但能解释为什么后面看到 ssh root@auth.example.com 接着 docker exec authentik-server ... 这种写法。
⚠️ 前提:SAML SSO 是 Atlassian Data Center 限定功能。Server 版(已 EOL)和早期 Cloud Standard 都不带。Data Center 自带的「SSO 2.0 / Authentication methods」模块够用,完全不需要装 Resolution / miniorange / Kantega 之类的第三方插件。
AD 这边事先把组建好:
confluence-users/bitbucket-users/jira-software-users/bamboo-users- 注意 Jira 那个组是
jira-software-users,不是jira-users - 全部放在
OU=Atlassian,OU=Groups下面
每个组里把要给访问权限的人加进去(一开始我同步过来 ~67 人)。
把 SAML 接进来
这一段是登录入口的切换:在 Authentik 上建好四个 SAML provider 和对应的 application,每个 Atlassian app 里再把 SAML 配置填进去。这一阶段 Crowd 还在原位继续做用户目录,登录入口先切走、用户库不动,回滚成本压到最低。
Authentik 侧
共享签名证书
四个 SAML provider 共用一张自签证书,方便统一管理。不要复用通配 TLS 证书——下次 TLS 轮替时四个 SP 全炸。也不要复用 Authentik 自己的 authentik Self-signed Certificate,它有效期只有两年,太短。
直接 Web UI 也能建,但用 ak shell 几行就出来:
1 | ssh root@auth.example.com |
1 | from authentik.crypto.builder import CertificateBuilder |
之后在 System → Certificates 里能看到 atlassian-saml,subject 是 CN=atlassian-saml,O=authentik,OU=Self-signed。
Property mappings
NameID 用 username(sAMAccountName),下游各个 app 的本地用户 key 就是这个,对得上。三个 default mapping 直接复用:
| Mapping 名 | SAML attribute | 取值 |
|---|---|---|
| Username | http://schemas.goauthentik.io/2021/02/saml/username |
request.user.username(= sAMAccountName) |
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress |
request.user.email(= AD mail) |
|
| Name | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name |
request.user.name |
再加一个自定义 Groups mapping 过滤一下:AD 里我有 ~16 个组,但只有 10 个跟 Atlassian 相关,其它的(部门组、内部工具组等)不该塞进 SAML 里。
Customisation → Property Mappings → Create → SAML Provider Property Mapping:
| 字段 | 值 |
|---|---|
| Name | atlassian-groups |
| SAML Attribute Name | http://schemas.xmlsoap.org/claims/Group |
| Friendly Name | Group |
Expression:
1 | for group in request.user.groups.all(): |
Confluence / Bitbucket / Bamboo 的 SAML 配置里没有 Groups 字段可填——它们读组靠 user directory,不靠 SAML。但发出去无害,留个口子万一以后想用 group attribute 决策。
SAML Provider — 一份模板套四次
每个 app 一个 provider。Web UI 点一遍可以,但 ak shell 跑脚本更不容易出错。下面这份是 Bitbucket 的,其它三个改名字、改 ACS、改 audience 就行:
1 | from authentik.providers.saml.models import SAMLProvider, SAMLPropertyMapping |
几个非默认值要留意:
sp_binding="post":ACS 走 HTTP-POST,不是 Redirect。Atlassian Data Center 这边吃 POST。sign_assertion=True且sign_response=True:内层<saml:Assertion>必须签,外层<samlp:Response>也签上做纵深防御。Atlassian 两个都接受。第一遍漏了 sign_response,回头补的。verification_kp留空:Atlassian 默认不签 AuthnRequest,Authentik 也不强制要验。encryption_kp留空:TLS 已经把信道加密了,再做 SAML payload 加密性价比不高。- 时钟容差是 Authentik 默认(前后各 5 分钟),别忘了 NTP。
四个 provider 创建完,记下来每个的 ID(在 Applications → Providers 里能看到,比如 5/6/7/8),后面取 IdP metadata 用得到:
1 | https://auth.example.com/api/v3/providers/saml/<id>/metadata/?download |
每个 application 在 Applications → Applications 里再绑一个 Group policy binding,限定只有 <app>-users 这个 AD 组的成员能 SSO 进来。组外用户在 IdP 这一层就被拒了,根本到不了 Atlassian。
不需要 Outpost
四个 app 都直接说 SAML,跟 Authentik 之间不走 LDAP outpost,也不走 proxy outpost。Outpost 那一套这里完全用不上。
Atlassian 侧
四个 app 的 SAML 配置长得几乎一样,最大差异是各自的 break-glass URL 不一样——下面单独列表。
共通字段
| 字段 | 值 |
|---|---|
| Configuration name | Authentik |
| Login button text | Sign in with Authentik |
| Single sign-on issuer | https://auth.example.com |
| Identity provider single sign-on URL | https://auth.example.com/application/saml/<slug>/sso/binding/redirect/ |
| X.509 Certificate | atlassian-saml 的完整 PEM |
| Username mapping | ${NameID} |
| JIT provisioning | OFF |
| Update users on login | OFF |
| Encrypt assertions | OFF |
| Show IdP on the login page | ON |
| Remember user logins | ON |
关于
Username mapping—— Atlassian 这个字段既能填 SAML 属性 URI(比如http://schemas.goauthentik.io/2021/02/saml/username),也能填占位符${NameID}。优先用${NameID}:URI 形式在不同版本的 Atlassian SAML 里支持度参差,${NameID}永远 work,少一层映射。
关键步骤顺序
四个 app 的操作我都按这个顺序走,最重要的是先开 fallback 再保存 SAML。否则 SAML 一保存出问题,自己也进不去:
REST PATCH 打开 fallback(先做这一步):
1
2
3curl -u <admin> -X PATCH "https://<app>/rest/authconfig/1.0/sso" \
-H "Content-Type: application/json" \
-d '{"enable-authentication-fallback": true}'UI 进
Authentication methods → Add configuration → SAML single sign-on共通字段照上表填,证书 PEM 用「SSH 拿出来 → pbcopy」的办法贴(见后面踩坑 #2)
保存,开无痕窗口测:浏览器到
https://<app>→ 跳 Authentik → AD 密码 → 落到原来那个用户(不应该是新建账号)测 break-glass URL(每个 app 不一样,下一节列表)能进本地登录框
一切 OK 后,再 PATCH 一次把本地登录框藏起来,让 SAML 成默认入口:
1
2
3curl -u <admin> -X PATCH "https://<app>/rest/authconfig/1.0/sso" \
-H "Content-Type: application/json" \
-d '{"show-login-form": false}'下一个 app
Confluence
UI 路径:Confluence Administration → General Configuration → Authentication methods(在「USERS & SECURITY」组里)。
Break-glass URL:https://wiki.example.com/login.action?auth_fallback
Confluence 的 SAML 表单没有 Groups attribute 字段,也没有 Sign requests 字段(那是 Jira-only)。
Bitbucket
UI 路径:Bitbucket Administration → Accounts → Authentication methods → Add configuration → SAML single sign-on
Break-glass URL:https://git.example.com/login?auth_fallback(注意是 /login,不是 /login.action)
Git over SSH / git over HTTPS 都不走 SAML——SSH 用 key,HTTPS 用 HTTP access token(前缀 BBDC- 那种)。SAML 切完不影响 git 操作。后面要禁 Basic Auth 时记得 /scm/* 加白名单,否则 git push/pull 直接挂。
Jira
UI 路径:Jira Administration → System → Authentication methods → Add configuration → SAML single sign-on
Break-glass URL:https://jira.example.com/login.jsp?auth_fallback
Jira 11.1+ 的表单比其它三个多两栏:
- NameID Policy:选
Unspecified(跟 Authentik 默认对齐) - Sign requests:OFF(Authentik 这边没要求 SP 签 AuthnRequest)
还有一个 Jira-only 的开关 Include customer logins (JSM)——我把它关掉,让 JSM 的客户门户继续走本地登录:
1 | {"show-login-form-for-jsm": true} |
⚠️ Jira 还有个「匿名用户能看到 dashboard 骨架」的坑,跟 SAML 没关系但是切完 SSO 一定会注意到。详见后面踩坑 #5。
Bamboo
UI 路径:Bamboo Administration → Security → Authentication methods → Add configuration → SAML single sign-on
Break-glass URL:https://ci.example.com/userlogin.action?auth_fallback(注意是 userlogin.action)
Bamboo 12.1.1 没有原生 OIDC 支持(要 OIDC 得装 Kantega / miniorange 之类的第三方插件),SAML 是 Atlassian 自带方案的唯一选项。Remote agent(比如 agent-win)走 agent token 鉴权,不受 SAML 影响。
让 SAML 成为默认
四个 app 都没有「Set as default」按钮。机制是:把 Username/password 那一行的 Show on login page 关掉。关掉之后匿名用户访问 https://<app> 直接重定向到 Authentik;?auth_fallback URL 仍然能用,因为它走的是另一条 servlet。
REST 等价:{"show-login-form": false}。
Break-glass URL 大表
四个 app 的 break-glass 全都不一样,单独存一份留着:
| App | URL |
|---|---|
| Confluence | https://wiki.example.com/login.action?auth_fallback |
| Bitbucket | https://git.example.com/login?auth_fallback |
| Jira | https://jira.example.com/login.jsp?auth_fallback |
| Bamboo | https://ci.example.com/userlogin.action?auth_fallback |
前提是 enable-authentication-fallback: true 已经 PATCH 过。
踩过的坑
坑 1 — 第一遍漏了 sign_response
Authentik 的 SAML provider 默认 sign_response=False、sign_assertion=True。第一遍创建 Confluence 的时候直接保存了,后来回头补。理论上 sign_assertion 已经够 Atlassian 验证完整性了,但同时签 response 没坏处,做纵深防御:
1 | p = SAMLProvider.objects.get(name="confluence-saml") |
后面 Bitbucket / Jira / Bamboo 一开始就两个都开。
坑 2 — 证书 PEM 贴进去每行第一个字符被吞了
把 atlassian-saml 的 PEM 从 Authentik UI 复制出来贴到 Confluence 的 X.509 字段,结果 -----BEGIN CERTIFICATE----- 变成了 ----BEGIN CERTIFICATE----,每行 base64 也都丢了第一个字符。SAML 这种是直接签名校验失败。
不是证书的问题,是渲染层吃字符——某些 UI 控件对每行第一个字节的处理有 bug。绕开:
1 | # 在 Authentik 容器里把证书导出到 /tmp |
然后 ⌘V 贴进去,零字符丢失。
坑 3 — ?auth_fallback 也跳 Authentik
第一次配完 Confluence,访问 https://wiki.example.com/login.action?auth_fallback,结果也跳了 Authentik。意味着 fallback 没生效。
原因是 enable-authentication-fallback 默认是 false,UI 里没那个开关,必须走 REST:
1 | curl -u <admin> -X PATCH "https://wiki.example.com/rest/authconfig/1.0/sso" \ |
PATCH 完再访问 ?auth_fallback,本地登录框就回来了。所以这一步必须放在保存 SAML 之前——否则 SAML 一旦配错,自己也进不去。
坑 4 — UI 路径已经改名了
网上很多老教程写「User Management → SSO 2.0 → Add SAML configuration」,Data Center 10.x 现在的路径是「General Configuration → Authentication methods」。SSO 2.0 这个老名字基本只在文档里能见到。四个 app 的菜单都重命名过,照新的找。
坑 5 — Jira 匿名页面绕开 SAML
切完 SAML 后,开无痕窗口访问 https://jira.example.com/secure/Dashboard.jspa,直接 200 返回 dashboard 骨架——虽然没有真实数据(只有 “Loading…” 占位),但页面能渲染、URL 不跳登录。/browse/ 倒是正常 302 到登录。
试过两条路:
- 把全局
Use Jira/Browse Projects权限里的Anyone摘掉——没用,dashboard 骨架照样出来 - Jira mode 切 Private——我已经是 Private 了
最后是开 Jira 的 dark feature:
1 | https://jira.example.com/secure/SiteDarkFeatures!default.jspa |
里面输 public.access.disabled,Enable。这个 dark feature 从 Jira 7.2.10 就有了,全局把所有匿名 URL 都重定向到 /login.jsp,再也没有骨架可看。
⚠️ 副作用:监控的健康检查 不能再打
/,要打/status。后者永远匿名访问,返回{"state":"RUNNING"}。LB 那边记得改。
坑 6 — Confluence 的 SAML 表单没有 “Sign requests” 字段
UI 上确实没有,因为「Sign requests」是 Jira 11.1+ 才加的,其它三个 app 都不暴露这个开关。Authentik 这边 verification_kp=None,本来就不要求 SP 签 AuthnRequest,所以表单上有没有都无所谓,不用纠结。
验证
每个 app 切完之后这套都跑一遍:
- 无痕窗口 →
https://<app>→ 跳 Authentik → AD 密码 → 落到已有用户(不是新建) ?auth_fallbackURL → 本地登录框出来- 把测试账号从
<app>-users组里临时拿掉 → 重新登录 → Authentik 直接拒绝(”You do not have access to this application”) - 跨 app SSO:登完 Confluence 再访问 Jira,无须重新输密码
- App link / 各种集成(Confluence 引 Jira issue、Bitbucket commit 关联 Jira ticket)依然能用——这些走 OAuth 不走 SAML
- Bitbucket 的 git push/pull、Bamboo 的 remote agent 也都正常
Authentik 这边查事件日志确认登录成功:
1 | ssh root@auth.example.com "docker exec authentik-server ak shell -c ' |
正常情况会看到 login 后面跟着 authorize_application,application 字段就是 confluence / jira 之类。
把用户目录从 Crowd 换成 AD 直连
SAML 跑稳一周以后,开始换用户目录。整体思路:每个 app 加一个新的 AD 目录,bind 用一个新的只读账号 atlassian-bind,等同步完毕、用户/组数对上、user key 也对上,再把 Crowd 那个目录 disable(不删)。
创建 atlassian-bind AD 账号
在 AD 域控上 PowerShell:
1 | $pw = Read-Host -AsSecureString "Password for atlassian-bind" |
不要给它 Reset Password 之类的特权 ACL——只用默认 Domain Users 在 OU=People/OU=Groups 上的读权限就够了。Atlassian 这边只读模式不会写回 AD。
在每个 Atlassian app 里加 AD 用户目录
User Management → User Directories → Add Directory → Microsoft Active Directory:
| 字段 | 值 |
|---|---|
| Name | AD - example.com |
| Directory type | Microsoft Active Directory |
| Permissions | Read Only, with Local Groups ← 必须这个,atlassian-bind 没写权限 |
| Hostname | dc.example.com |
| Use SSL | ✅ |
| Port | 636 |
| Username | CN=atlassian-bind,OU=Services,DC=example,DC=com |
| Password | 上面建的密码 |
| Base DN | DC=example,DC=com |
| Additional User DN | OU=People |
| Additional Group DN | OU=Atlassian,OU=Groups ← 注意限定到 Atlassian 子 OU,不要拉整个 OU=Groups |
| User name attribute | sAMAccountName |
| User unique ID | objectSid |
| User RDN | cn |
| User object filter | (&(objectCategory=person)(objectClass=user)) |
| Group object filter | (objectCategory=group) |
| Group membership attribute | member |
| User membership attribute | distinguishedName |
| Synchronisation interval | 60 minutes |
保存 → Test → Sync。Sync 完成后把新目录的优先级拉到 Crowd 上面,然后访问用户选择器搜几个人,确认拿到的是新目录里的副本(看 Directory 列)。
验数
直接到每个 app 的 Postgres 里查:
1 | -- Confluence / Jira / Bitbucket / Bamboo 都是 cwd_* 这套表 |
新旧两个目录的活跃用户数应该一致(我这里两边都是 67~68)。Confluence/Jira 的 user key(比如 JIRAUSER10101、2c9280828f99ac2a018f99b208a90003)是按 username 落进 cwd_user 的,目录切换不会重发新 key——这就是为什么前面坚持 NameID = sAMAccountName 的原因,整条链路 user identity 都用 username 串起来,issue 分配、权限、关注者全部稳如老狗。
关掉 Crowd 那个目录
每个 app 的 Crowd 目录 Disable,不要 Delete。Disable 之后用户不会消失(key 还在),只是不再从 Crowd 拉新数据。万一 AD 这边出问题,Crowd 一键回滚。
关 Basic Auth on REST
第二步切完用户目录之后,顺手把 REST 接口的 Basic Auth 关了。四个 app 健康检查里都会有一条「Basic Authentication Disabled」的告警,Atlassian 推荐切 SSO 后把 REST API 的 Basic Auth 关掉,逼大家用 PAT(personal access token)。
1 | PUT /rest/basicauth/1.0/config |
| App | body | 备注 |
|---|---|---|
| Confluence | {"block-requests": true, "allowed-paths": [], "allowed-users": []} |
没东西用 Basic |
| Jira | 同上 | 同上 |
| Bamboo | 同上 | 同上 |
| Bitbucket | {"block-requests": true, "allowed-paths": ["/scm/*"], "allowed-users": []} |
/scm/* 必须放过,git over HTTPS 还得用 HTTP access token 走 Basic |
验证:
1 | # 匿名 Basic → 应该 403 |
退役 Crowd
跑了一两个月,没人来抱怨「我登不进 Jira」「我看不到 Confluence 空间」之后,可以彻底干掉 Crowd 了:
- 给 Crowd 实例做一份完整备份,单独存档并标记为受保护,免得被保留策略误删
- 停服务,关掉开机自启
- 观察一个月,期间没人哭就继续
- 彻底销毁实例
收尾:
- DNS 里删掉
crowd.example.com的 A 记录 - AD 里
Remove-ADGroup -Identity "crowd-administrators"那个组也清掉
Crowd 退役后的新员工开通流程
Crowd 还在的时候有个隐藏作用:「Group memberships when creating accounts」会在新账号第一次登录时自动塞进 confluence-users 等几个组。Crowd 没了之后,新员工进 AD 但没自动加 Atlassian 组,Authentik 这一层就直接拒了,根本登不进任何 Atlassian app。
替代方案两条:
- 在 AD 域控上跑
Sync-AtlassianGroups.ps1这种定时任务,根据 OU 自动把 Employees 加到对应*-users组里 - 在「新员工建账号」流程里直接加上四个组——我后来改的是这条,写了个
New-EmployeeUser.ps1,建账号时Add-ADGroupMember一并搞定,省得再起一个定时任务
任选一种。外包之类的临时账号要走人工审核,别塞默认。
一些零碎经验
- AD bind 严格分两份:
authentik-bind有 Reset Password ACL(密码 writeback 用),只给 Authentik 用;atlassian-bind只读,给四个 app。其它服务想接 AD 都各自再开只读账号,不要互相串。 - Audience / Issuer / ACS URL 必须严丝合缝:差一个
/都会在 Atlassian 这边被拒。Authentik 的 audience 写https://jira.example.com,Atlassian 这边的 base URL 也得是同样的、不带末尾斜杠。 - NTP:Authentik 和四个 Atlassian 实例都要走同一台 NTP,时钟差超过 5 分钟 SAML 直接拒。
- 不要拿通配 TLS 证书签 SAML:TLS 证书每年/每两年一轮替,每次都得重新分发 IdP 元数据给四个 SP。专门一张 10 年自签
atlassian-saml。 - App link 不动:四个 app 之间的 OAuth 互信不依赖 SAML,切了不用动。
- SP-initiated only:我没配 IdP-initiated 流程,从 Authentik My Apps 里点 tile 是 IdP-initiated,会走得通但不是主用法。
小结
切下来回头看,整条链路其实没那么吓人——把节奏拆成「先 SAML、再换用户目录、再退 Crowd」三段,每一段都能独立回滚。最容易踩的反而不是 SAML 本身,是这些边边角角:回退开关没开、UI 路径改名、Jira 匿名页面、证书贴歪。把这些列出来记一份,下次再切别的 app 就轻车熟路。
Crowd 服役这么多年也算尽职尽责,但一个十多年没换 UI、还要单独跑 Java 实例的 SSO 中转层,确实可以光荣退役了。Authentik 这边除了少了一跳,多端 SSO、MFA、未来想加什么社交登录也都顺手。
References
Atlassian Data Center 官方文档
- OpenID Connect for Atlassian Data Center applications —— 用来确认 Jira / Confluence / Bitbucket 已经原生支持 OIDC(Bamboo 例外)
- Authentication, simplified: OpenID Connect for Data Center —— Atlassian 官方关于 OIDC for Data Center 的公告
- Configuring OIDC using the Atlassian SSO for Data Center App in Jira —— 想走 OIDC 路线时的配置入口
- Single sign-on for Confluence Data Center —— Confluence 这一侧 SSO 配置文档
- Enable default login page to bypass SAML in Confluence Data Center —— 踩坑 #3
?auth_fallback不生效的官方说明
Authentik
- authentik documentation —— SAML Provider、Property Mapping、Application、Policy Binding 等概念都在这
- authentik on GitHub —— 源码、Issue、Discussion
第三方扩展(Bamboo OIDC 替代方案)
- Kantega SSO — SSO in Jira and Confluence with OpenID Connect —— 给 Bamboo 加 OIDC 时可用的第三方插件之一