SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-16

自架軟體的 SSO 稅:安裝前必看的檢查清單

許多開放原始碼應用程式將 OIDC 與 SAML 放入付費方案。了解維護者的定價理由,並在安裝前確認支援、IdP 相容性與替代方案。

SSO 稅是什麼

自架軟體中的 SSO 稅,是指應用程式本身免費,但必須購買單一登入(SSO)才能使用。您可以在自己的 VPS 上執行完整系統,不需要授權金鑰,也不受席次數量限制。接著,您在文件中開啟驗證頁面,卻發現 OpenID Connect (OIDC) 或 SAML(security assertion markup language)被列在付費方案中。

這比一般的付費功能更值得注意,因為 SSO 能讓一組自架服務以單一系統的方式運作。身分識別提供者(IdP)可為每位使用者提供一個帳號、一套密碼政策、一個啟用多重要素驗證(MFA)的位置,以及一個停用使用者的位置。沒有 SSO 時,每個應用程式都會維護自己的小型使用者資料庫,而您必須逐一手動管理。

這種模式早已存在,甚至有公開的評比名單。sso.tax 上的 SSO Wall of Shame(https://sso.tax/)列出對單一登入收取高額溢價的供應商,最早的項目可追溯至 2018 年。其作者設定了合理的標準:「如果您的 SSO 支援只讓價格提高 10%,就不會列入這份名單。」名單中的大多數是閉源軟體。如今,採用相同定價邏輯的情況,也出現在由您自行託管的開放原始碼專案中。

維護者為何將單一登入列入付費方案

原因有兩個,而且都很實際。SSO 的支援成本很高,也是大型組織少數願意付費的功能之一。

支援成本確實存在,因為身分識別整合永遠不會真正完成。每個 IdP 的 claims 格式都有些差異。群組對應、工作階段存續時間、重新導向 URL 與時鐘偏差都可能造成登入錯誤;而登入錯誤會同時鎖住所有使用者,因此這類工單都很緊急。接著還會出現後續需求:巢狀群組、角色對應、使用 SCIM(system for cross-domain identity management)自動佈建,以及合規團隊會查閱的稽核日誌。

收入方面是算術問題,而不是惡意行為。無法將應用程式連接至自有 IdP 的公司,根本不會部署該應用程式。因此,SSO 能清楚區分付費使用者與非付費使用者。開放核心專案必須在某個功能上劃出這條界線。SSO 比幾乎任何其他功能都更適合,因此許多專案都選擇這樣做。

需要修正常見的一項抱怨:假設某項功能遭到移除前,先查看變更日誌,因為移除功能會出現在版本說明中。我查閱本文提到的專案後發現,付費 SSO 功能從一開始就是為付費方案建立的。我沒有找到原本可用的免費 SSO 後來遭到撤回的案例。Grafana 就是典型例子。其 SAML 頁面有一行簡短說明:「Available in Grafana Enterprise and Grafana Cloud」;但在開放原始碼版本中,針對自有 issuer 的一般 OAuth 仍可使用。

SSO 成本實際上有多高

金錢只是較小的一半。付費方案按使用者計費,因此團隊越大,帳單越高;代管與升級仍由你負責。

較大的成本是手動處理身分管理,主要會出現在以下四個方面。

  • 每個應用程式各自管理密碼,因此只要重複使用一組密碼,所有共用該密碼的應用程式都會出現安全漏洞。
  • 憑記憶執行離職停權。你必須記得某人使用過的每項服務,而遺漏的那一項往往最重要。
  • 必須逐一在各應用程式中設定 MFA,而且前提是該應用程式支援 MFA。
  • 共用登入帳號。在這種壓力下,小型團隊實際上往往會這麼做。

最後一點值得另行說明。當團隊在文件管理器中共用一個管理員帳號時,稽核軌跡會為所有操作記錄同一個名稱,因此你無法判斷是誰刪除了發票。每位使用者的權限也會失效,因為系統中只有一個使用者。這就是 SSO 成本造成的實際損害:它會把小型團隊推向共用單一帳號,而這比其他任何替代方案都更糟糕。

採用前應執行的檢查清單

請在 docker compose up 前執行這些檢查,不要等到應用程式已經保存 400 份文件後才處理。

  1. 開啟文件中的驗證頁面,閱讀頂端的方案說明。付費功能通常會有標章或一行可用性說明。
  2. 確認應用程式能透過 OIDC 或 SAML 連線到您自己的 issuer,而不是只能連線到固定的公開供應商清單。
  3. 檢查角色與群組對應。建立使用者只完成一半工作,另一半是處理權限;若要在 10 個應用程式中手動設定,這部分最容易造成負擔。
  4. 檢查應用程式是否接受受信任 proxy 在標頭中傳入的已驗證使用者名稱,以及是否能鎖定它所信任的 proxy。
  5. 閱讀 git 中的授權條款歷程,並確認貢獻者是否簽署 CLA (contributor licence agreement)。
  6. 檢查離職處理流程。確認 IdP 帳戶停用後,API (application programming interface) token 與現有工作階段會如何處理。

第 2 項最容易造成失望。Sign in with Google 按鈕不代表應用程式能透過您的 identity provider 使用 OIDC;它只是與單一供應商的固定整合。真正的支援會要求您提供 issuer URL,其餘資訊則透過 discovery 取得。您可以使用一個命令確認供應商端是否正確。

curl -s https://id.example.com/.well-known/openid-configuration \
  | jq '.issuer, .authorization_endpoint, .token_endpoint'

正常的供應商會回傳 3 個 URL。空白結果或 404 通常表示 discovery 路徑錯誤,而該路徑取決於供應商:Keycloak 會在 /realms/<realm>/.well-known/openid-configuration 發布這項資訊。如果應用程式完全沒有 issuer URL 欄位,無論功能清單如何描述,它都無法連線到您的 IdP。

第 6 項通常會在有人離職數週後才被注意到。在 IdP 中停用帳戶會阻止新的登入,但不會撤銷應用程式先前核發的 API token,因為應用程式會自行驗證該 token,且不會向 IdP 查詢。因此,離職處理包含兩個步驟:先在 IdP 中停用帳戶,再在每個應用程式內刪除使用者或其 token。

實際上各層級徽章代表什麼

以下內容是根據各專案截至 2026 年 8 月的官方文件核對而成。先從付費方案開始。

Grafana 將 SAML 標示為「Available in Grafana Enterprise and Grafana Cloud」,並同時提供 team sync 與 SCIM provisioning。Generic OAuth、GitHub OAuth、LDAP(lightweight directory access protocol)及 auth proxy 都包含在 open source build 中,因此小型自架環境仍可透過自己的身分提供者登入。付費功能的界線落在 SAML,而不是整體的 single sign-on;「SSO tax」這個說法通常會忽略這項細節。

Metabase 的說法更直接。其文件指出:「SAML authentication is only available on Pro and Enterprise plans (both self-hosted and on Metabase Cloud).」open source edition 仍保留密碼登入與 LDAP。

Passbolt 將 SSO 文件標示為 Pro 與 Cloud,因此 community edition 不提供此功能。文件列出的提供者包括 Keycloak 與 Entra ID。

接著看另一種情況,因為這種模式並不普遍。

  • GitLab Self-Managed 的 SAML 頁面標示「Tier: Free, Premium, Ultimate」,因此使用自有 GitLab 進行 SAML 驗證不需付費。
  • Paperless-ngx 透過 django-allauth 搭配 PAPERLESS_SOCIALACCOUNT_PROVIDERS 設定 OIDC,使用 PAPERLESS_DISABLE_REGULAR_LOGIN 隱藏本機登入表單,並使用 PAPERLESS_SOCIAL_ACCOUNT_SYNC_GROUPS 將 claims 對應到群組。
  • Planka 接受 OIDC_ISSUEROIDC_CLIENT_IDOIDC_CLIENT_SECRET,預設 scopes 為 openid profile email,並使用 OIDC_ADMIN_ROLES 將管理員提升為管理員角色。
  • BookStack 使用 AUTH_METHOD=oidc 切換至該功能,接著使用 OIDC_USER_TO_GROUPS=trueOIDC_GROUPS_CLAIM 將提供者群組對應到自身的角色。
  • Vaultwarden 在 2025 年 12 月 27 日的 1.35.0 版本中加入「support for SSO with OpenID Connect」,這項功能來自一名貢獻者提交的 pull request;該貢獻者先前曾在 fork 中維護此功能。
  • listmonk 自 v4.0.0 起,便在使用者角色之外提供 OIDC 登入。

請在做出選擇時使用這些資訊,而不是等到確定方案後才查看。Planka 看板與其他 自架 Trello 替代方案對身分驗證的處理方式並不相同,BookStack、Wiki.js 與 Outline也是如此。免費 OIDC 是可與儲存空間上限或行動用戶端一樣納入評估的功能。如果你仍在整理候選清單,2026 年適合自架的服務是合理的起點,而 Paperless-ngx 文件管理器Vaultwarden目前都提供免費 OIDC。

為什麼應用程式前的反向代理不等於單一登入

常見的替代做法是 forward auth。反向代理會暫停處理每個請求,詢問驗證服務此瀏覽器是否已登入,確認後才將請求傳給應用程式。authentik 將此功能稱為 proxy provider,提供適用於單一應用程式的 forward auth 模式,以及適用於整個網域的另一種模式。Authelia 和 oauth2-proxy 也能執行相同工作。

以下是依照 authentik 官方範例撰寫的 Caddy site block。

app.example.com {
  forward_auth http://authentik-outpost:9000 {
    uri /outpost.goauthentik.io/auth/caddy
    copy_headers X-Authentik-Username X-Authentik-Email X-Authentik-Groups
    trusted_proxies private_ranges
  }
  reverse_proxy app:8000
}

在 Caddy 中,這些標頭名稱的大小寫很重要,因為名稱不一致時,傳入的值會是空的。對每個通過核准的請求,outpost 都會設定 X-authentik-usernameX-authentik-emailX-authentik-groups 及其他幾個標頭。

這樣做可以帶來以下效果。任何人都必須先通過你的身分識別提供者,才能連到應用程式。因此,未修補的登入表單不再直接暴露於網際網路,MFA 也會一次套用到反向代理後方的所有服務。

但這樣做無法提供應用程式內的身分識別。應用程式仍有自己的帳號,也有自己判定登入者的方式。如果所有人都通過反向代理,最後使用同一個共用管理員帳號登入,你得到的是一道強固的入口,以及後方的一個匿名工作階段。稽核日誌仍只會顯示同一個名稱。不同使用者之間仍無法套用不同權限。將這種架構稱為 SSO 會造成安全判斷錯誤,因為離職處理只完成了一半:從你的 IdP 移除該使用者可以關閉入口,但只要有人能直接連到應用程式,該使用者在應用程式內建立的 API token 仍可繼續使用。

確保標頭驗證安全

部分應用程式接受由代理程式提供的使用者名稱,因此無須付費 SSO 即可識別個別使用者。每個專案對應的設定名稱都不同。

Grafana 將此功能稱為 auth proxy,預設停用。標頭名稱預設為 X-WEBAUTH-USER,也可以指定代理程式設定的其他標頭。

[auth.proxy]
enabled = true
header_name = X-authentik-username
header_property = username
auto_sign_up = true
whitelist = 10.0.0.5

whitelist 是使用者容易略過的設定。Grafana 文件明確說明,此設定用於防止使用者偽造標頭,因此其中只能填入代理程式的位址。Gitea 也提供相同功能,但使用不同的設定名稱,而且預設值較安全。

[security]
ENABLE_REVERSE_PROXY_AUTHENTICATION = true
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
REVERSE_PROXY_TRUSTED_PROXIES = 10.0.0.5/32
REVERSE_PROXY_LIMIT = 1

REVERSE_PROXY_TRUSTED_PROXIES 預設為 127.0.0.0/8,::1/128,而 REVERSE_PROXY_LIMIT 代表 Gitea 在代理鏈中信任的代理程式數量。將此限制設為零會完全停用標頭處理。

Paperless-ngx 透過 PAPERLESS_ENABLE_HTTP_REMOTE_USER 搭配 PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME 提供此功能,其文件也列出所有這類設定都應有的警告:

只要在請求中加入 Remote-User: <username> 標頭,即可進行驗證。請謹慎使用!

要確保標頭驗證安全,必須遵守兩項規則,兩者都與可連線性有關。第一,除了透過代理程式之外,應用程式不可從其他來源連線,因為任何能對其開啟 socket 的人,都能傳送該標頭並冒充任何使用者。在 Docker 中,ports: ["8000:8000"] 會在所有介面上發布連接埠,因此請使用 ports: ["127.0.0.1:8000:8000"] 將其繫結至 loopback 位址;或者移除發布的連接埠,並將代理程式放在相同的 Docker network。第二,代理程式必須刪除從用戶端收到的任何同名標頭,讓應用程式看見的唯一值,是代理程式完成驗證後設定的值。

請檢查這兩項。從 VPS 外部的機器執行第一個命令,並在伺服器本身執行第二個命令。

curl -si -H "Remote-User: admin" http://203.0.113.10:8000/ | head -n 1
ss -ltnp | grep 8000

curl 應無法建立連線,而 ss 應輸出 127.0.0.1:8000,而不是 0.0.0.0:8000。如果第一行是 HTTP/1.1 302 Found,表示應用程式可直接回應公開網際網路,因此任何人只要在標頭中指定使用者名稱,就能以該使用者身分登入。

沒有免費 SSO 時,請做決定,不要只抱怨

以下列出 4 個選項,順序是我會採用的優先順序。

  1. 選擇內建 OIDC 的應用程式。如果兩個專案功能相同,而其中一個能免費連接你的身分識別提供者,這就是實際的執行成本差異。
  2. 誠實使用 forward auth。對只有一個帳戶和一名操作人員的管理工具而言,前方的代理已經足夠;應用程式內的個別使用者身分不會帶來實質效益。
  3. 付費。如果應用程式是工作流程的核心,且按席次計費的價格符合團隊規模,這筆費用能維持專案持續維護;否則替代方案就是耗費你晚上的時間。
  4. 先搜尋 issue tracker,再向上游提出要求。Vaultwarden 的 OIDC 支援來自貢獻者的 fork 和長期維護的 pull request,因此,若功能請求後面有可運作的實作,有時確實能進入免費版本。

如果沒有自己的身分識別提供者,上述方法都無法運作;因此應先建立這個元件。在 VPS 上執行 authentik 會提供 OIDC 與 SAML provider,以及前文使用的 forward auth outpost;Keycloak、authentik 與 Zitadel 的比較 則說明各方案之間的取捨,供你在尚未決定前參考。

授權歷史,以及它為何列在檢查清單中

最後一項檢查清單是關於未來,因為今天的分層配置只是一個快照。有兩個記錄完整的案例,顯示情況變化得多快,而且可能朝兩個方向發展。HashiCorp 在 2023 年 8 月 10 日為所有未來版本採用 Business Source License 1.1,而較早的版本仍採用 MPL 2.0(Mozilla Public License)。Redis 在 2024 年 3 月改用 SSPL(server side public license),接著在 2025 年 5 月 1 日宣布 Redis 8 也採用 AGPLv3(GNU Affero General Public License)。

請將這兩個案例視為機制的證據,而不是動機的證據。你今天閱讀的授權條款適用於你今天安裝的版本;如果專案持有全部著作權,就能自行變更下一個版本的條款。因此,CLA 問題會列在檢查清單中,因為廣泛的著作權轉讓正是單方面重新授權成為可能的原因。

在以專案為基礎進行開發前,請自行檢查其歷史記錄。

git clone --filter=blob:none https://github.com/paperless-ngx/paperless-ngx.git
cd paperless-ngx
git log --follow --oneline -- LICENSE

提交記錄很短,而且大多來自第一次匯入,通常是良好跡象。如果授權檔案曾多次改寫,就應在依據目前條款規劃前,先閱讀每個提交訊息。

FAQ

什麼是 SSO 稅?

SSO 稅是指將 single sign-on 列為付費進階功能,而產品其餘部分免費或價格低廉的做法。在自架軟體中,這通常表示應用程式可在不需要 license key 的情況下執行,但 OIDC 或 SAML 登入功能被放在付費方案中。這個名稱源自 sso.tax 的 SSO Wall of Shame,該網站追蹤向此功能收取高額加價的供應商。對自架服務使用者而言,結果是每個應用程式都保留自己的使用者資料庫,因此必須手動建立及移除帳戶。

使用 forward auth 的反向代理等同於 SSO 嗎?

不等同。Forward auth 保護的是入口:代理伺服器會先向 identity provider 驗證,再讓請求送達應用程式。後端應用程式仍使用自己的帳戶,因此若所有人都進入同一個共用登入,系統只會產生一個匿名工作階段,稽核日誌也只會記錄同一個名稱。只有在應用程式讀取標頭中的使用者名稱時,才會成為真正的個別使用者識別;Grafana 的 auth proxy、Gitea 的 reverse proxy authentication,以及 Paperless-ngx 的 PAPERLESS_ENABLE_HTTP_REMOTE_USER 都能做到這點。只有在應用程式無法繞過代理伺服器直接連線時,這些設定才安全,因為該標頭只是純文字字串,任何用戶端都能送出。

哪些自架應用程式在免費版本中提供 OIDC?

截至 August 2026,根據各專案的文件確認:Paperless-ngx、Planka、BookStack、Gitea、listmonk 和 Vaultwarden 都在免費版本中支援 OIDC;GitLab Self-Managed 則將 SAML 列在 Tier: Free。Grafana 的 open source 版本可使用 generic OAuth,連線至自有的 issuer;其中的 SAML 則是 Enterprise 功能。安裝前請確認專案自己的 authentication 頁面,因為這些清單會隨版本發布而變更。

我應該付費購買解鎖 single sign-on 的方案嗎?

請用2個數字決定:需要帳戶的人數,以及原本必須手動維護的應用程式數量。若只有1或2位管理員,在本機帳戶前方使用 forward auth 通常已足夠,付費方案的價值有限。若是人員會加入及離開的團隊,停用帳戶時漏掉1個帳戶所造成的成本可能高於 license 費用,而這筆費用也支應你所依賴的維護工作。若價格不合適,實際做法是選擇原生提供 OIDC 的應用程式,而不是設法繞過不支援 OIDC 的應用程式限制。