跳到正文
Træfɪk

<span class="nav-link-with-icon">OIDC <img src="https://doc.traefik.io/traefik-hub/img/ps-traefik-hub-logo-light.svg" class="menu-icon" alt="Traefik Hub API Gateway"></span>

Traefik Hub 功能

此中间件仅在 Traefik Hub 中提供。了解更多 Traefik Hub 高级功能。

OIDC 认证中间件将认证委托给外部提供商,从而保护应用。


配置示例

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oidc
  namespace: whoami
spec:
  plugin:
    oidc:
      issuer: "https://tenant.auth0.com/realms/myrealm"
      redirectUrl: "/callback"
      clientId: "urn:k8s:secret:my-secret:clientId"
      clientSecret: "urn:k8s:secret:my-secret:clientSecret"
      session:
        name: customsessioncookiename
        sliding: false
        refresh: false
        expiry: 10
        sameSite: none
        httpOnly: false
        secure: true
      stateCookie:
        name: customstatecookiename
        maxAge: 10
        sameSite: none
        httpOnly: true
        secure: true
      forwardHeaders:
        Group: grp
        Expires-At: exp
      claims: Equals(`grp`, `admin`)
      csrf: {}
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
stringData:
  clientID: my-oidc-client-name
  clientSecret: mysecret

配置选项

字段 说明 默认值 必填
issuer 定义 OpenID Connect 提供商的 URL(例如 https://accounts.google.com)。
应指向提供 OpenID Connect 配置的服务器。
"" 是
trustedIssuer 定义另一个可信签发者 URL,除了从 OpenID Connect 提供商发现的签发者之外,也接受此 URL 进行验证。 "" 否
disableIssuerCheck 在令牌验证期间禁用签发者验证检查。 false 否
redirectUrl 定义授权完成后 OpenID Connect 提供商重定向回中间件时使用的 URL。(更多信息见此处) "" 是
clientId 定义 OpenID Connect 提供商中某个账户的唯一客户端标识符;设置 clientSecret 时必须设置。(更多信息见此处) "" 是
clientSecret 定义 OpenID Connect 提供商中某个账户的唯一客户端密钥;设置 clientId 时必须设置。(更多信息见此处) "" 是
claims 定义为授权请求而需要验证的声明。
claims 选项仅可用于 JWT 格式的令牌。(更多信息见此处)
"" 否
usernameClaim 定义需要求值的声明,以填充访问日志中的 clientusername。
usernameClaim 选项仅可用于 JWT 格式的令牌。
"" 否
forwardHeaders 定义要添加到请求中的 HTTP 头,并使用从授权服务器返回的访问令牌声明中提取的值填充。
如果 JWT 中找不到要转发的声明,相应头的值为空。
forwardHeaders 选项仅可用于 JWT 格式的令牌。
[] 否
clientConfig.tls.ca PEM 编码的证书包,或引用包含此证书包的 Secret 的 URN;该证书包用于与授权服务器建立 TLS 连接。(更多信息见此处) "" 否
clientConfig.tls.cert PEM 编码的证书,或引用包含此证书的 Secret 的 URN;该证书用于与 Vault 服务器建立 TLS 连接。(更多信息见此处) "" 否
clientConfig.tls.key PEM 编码的密钥,或引用包含此密钥的 Secret 的 URN;该密钥用于与 Vault 服务器建立 TLS 连接。(更多信息见此处) "" 否
clientConfig.tls.insecureSkipVerify 与授权服务器通信时禁用 TLS 证书验证。
可用于测试,但强烈不建议在生产环境使用。(更多信息见此处)
"" 否
clientConfig.timeoutSeconds 定义向授权服务器发出请求后,放弃等待之前的时长。 5 否
clientConfig.maxRetries 定义向授权服务器发送请求失败时的重试次数。 3 否
pkce 定义 RFC 7636 中描述的代码交换证明密钥(Proof Key for Code Exchange)。 false 否
discoveryParams 任意查询参数的映射,将在发现机制执行期间添加到 openid-configuration 的 well-known URI。 "" 否
scopes 要请求的作用域,必须包含 openid。 openid 否
authParams 要传给认证提供商的任意查询参数映射。
当 AuthParams 中的 prompt 键设置为空字符串时,OAuth2 授权 URL 不会添加 prompt 参数,这意味着不会提示用户同意授权。
"" 否
disableLogin 禁用到认证提供商的重定向。
保护 API 时,如果不希望重定向到登录页面,此选项很有用。
false 否
loginUrl 定义需要时用于启动授权的 URL。
其他尚未授权的请求均返回 401 Unauthorized。留空时,所有请求都可以启动授权。
可以是路径(例如 /login)、主机加路径(example.com/login),或完整 URL(https://example.com/login)。
仅支持 http 和 https 协议方案。
"" 否
logoutUrl 定义用于删除会话、使用户退出登录的 URL。
可以是路径(例如 /logout)、主机加路径(example.com/logout),或完整 URL(https://example.com/logout)。
仅支持 http 和 https 协议方案。
"" 否
postLoginRedirectUrl 如果设置并与 loginUrl 配合使用,中间件将在登录成功后重定向到此 URL。
可以是路径(例如 /after/login)、主机加路径(example.com/after/login),或完整 URL(https://example.com/after/login)。
仅支持 http 和 https 协议方案。
"" 否
postLogoutRedirectUrl 如果设置并与 logoutUrl 配合使用,中间件将在退出登录后重定向到此 URL。
可以是路径(例如 /after/logout)、主机加路径(example.com/after/logout),或完整 URL(https://example.com/after/logout)。
仅支持 http 和 https 协议方案。
"" 否
backchannelLogoutUrl 定义用户退出登录时 OIDC 提供商调用的 URL(参见 https://openid.net/specs/openid-connect-rpinitiated-1_0.html#OpenID.BackChannel)。
可以是路径(例如 /backchannel-logout)、主机加路径(example.com/backchannel-logout),或完整 URL(https://example.com/backchannel-logout)。
仅支持 http 和 https 协议方案。
此功能目前处于实验阶段,且仅使用 Keycloak OIDC 提供商进行过测试。
"" 否
backchannelLogoutSessionsRequired 指定 OIDC 提供商是否在 Logout Token 中包含 sid(会话 ID)声明,用于识别用户会话(参见 https://openid.net/specs/openid-connect-backchannel-1_0.html#BCRegistration)。
省略时默认为 false。
此功能目前处于实验阶段,且仅使用 Keycloak OIDC 提供商进行过测试。
false 否
stateCookie.name 定义状态 Cookie 的名称。 "MIDDLEWARE_NAME-state" 否
stateCookie.path 定义请求 URL 中必须存在的 URL 路径,只有满足时才发送 Cookie 头。
%x2F('/')字符被视为目录分隔符,子目录也会匹配。
例如,stateCookie.path 设置为 /docs 时,这些路径均匹配:/docs、/docs/web/、/docs/web/http。
"/" 否
stateCookie.domain 定义允许接收 Cookie 的主机。
如果指定此项,始终包含其子域名。
例如,设为 example.com 时,Cookie 也会发送到 api.example.com 等子域名。
"" 否
stateCookie.maxAge 定义状态 Cookie 多少秒后过期。
零或负数会使 Cookie 立即过期。
600 否
stateCookie.sameSite 告知浏览器如何在跨站请求中处理状态 Cookie。
设为 lax 或 strict 可提供一定的跨站请求伪造(CSRF)攻击防护。
更多信息见此处。
lax 否
stateCookie.httpOnly 禁止 JavaScript 访问 Cookie。
例如,通过 Document.cookie 属性、XMLHttpRequest API 或 Request API。
这有助于缓解跨站脚本(XSS)攻击。
true 否
stateCookie.secure 定义是否仅在使用 https 协议方案发出请求时,才将状态 Cookie 发送给服务器。 false 否
session.name 会话 Cookie 的名称。 "MIDDLEWARE_NAME-session" 否
session.path 定义请求 URL 中必须存在的 URL 路径,只有满足时才发送 Cookie 头。
%x2F('/')字符被视为目录分隔符,子目录也会匹配。
例如,stateCookie.path 设置为 /docs 时,这些路径均匹配:/docs、/docs/web/、/docs/web/http。
"/" 否
session.domain 指定允许接收 Cookie 的主机。如果指定此项,始终包含其子域名。如果指定此项,始终包含其子域名。
例如,设为 example.com 时,Cookie 也会发送到 api.example.com 等子域名。
"" 否
session.expiry 会话多少秒后过期。禁止使用零或负数。 86400 (24h) 否
session.sliding 强制中间件在每次收到已认证的请求时续期会话 Cookie。 true 否
session.refresh 启用访问令牌到期时的刷新功能。 true 否
session.sameSite 告知浏览器如何在跨站请求中处理会话 Cookie。
设为 lax 或 strict 可提供一定的跨站请求伪造(CSRF)攻击防护。
更多信息见此处。
lax 否
session.httpOnly 禁止 JavaScript 访问 Cookie。
例如,通过 Document.cookie 属性、XMLHttpRequest API 或 Request API。
这有助于缓解跨站脚本(XSS)攻击。
true 否
session.secure 定义是否仅在使用 https 协议方案发出请求时,才将会话 Cookie 发送给服务器。 false 否
session.store.redis.endpoints 要连接的 Redis 实例端点(例如 redis.traefik-hub.svc.cluster.local:6379)。 "" 是
session.store.redis.username Traefik Hub 连接 Redis 时使用的用户名。 "" 否
session.store.redis.password Traefik Hub 连接 Redis 时使用的 password。 "" 否
session.store.redis.database Traefik Hub 用于存储信息的数据库(默认值:0)。 "" 否
session.store.redis.cluster 启用 Redis Cluster。 "" 否
session.store.redis.tls.caBundle 自定义 CA 证书包。 "" 否
session.store.redis.tls.cert TLS 证书。 "" 否
session.store.redis.tls.key TLS 密钥。 "" 否
session.store.redis.tls.insecureSkipVerify 允许跳过 TLS 验证。 "" 否
session.store.redis.sentinel.masterSet 用于主节点选择的主节点集合名称。使用 Sentinel 时必填。 "" 否
session.store.redis.sentinel.username Sentinel 认证使用的用户名(可以与 username 不同)。 "" 否
session.store.redis.sentinel.password Sentinel 认证使用的密码(可以与 password 不同)。 "" 否
session.store.keyPrefix 定义用于存储会话的条目的键前缀。 "" 否
csrf 启用后,将名为 hub-csrf-token 的 CSRF Cookie 绑定到 OIDC 会话,以保护服务免受 CSRF 攻击。
此功能基于 OWASP 基金会定义的签名双重提交 Cookie实现。
更多信息见此处。
"" 否
csrf.secure 定义是否仅在使用 https 协议方案发出请求时,才将 CSRF Cookie 发送给服务器。 false 否
csrf.headerName 定义用于发送 CSRF 令牌值的请求头名称,该令牌值来自先前收到的 CSRF Cookie。 Hub-Csrf-Token 否

redirectUrl 重定向 URL

在 IngressRoute 上添加特定规则

此 URL 告知 OpenID Connect 提供商如何返回中间件。 如果路由器规则接受某个域名下的所有路径,则无需额外操作。 如果路由器规则对允许的路径有限制,则应将此选项设置的路径包含在规则中。

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: whoami
spec:
  entryPoints:
    - web
    - websecure
  routes:
      # Rules to match the loginUrl and redirectUrl can be added into
      # your current router.
    - match: Path(`/myapi`) || Path(`/login`) || Path(`/callback`)
      kind: Rule
      middlewares:
        - name: test-oidc

此 URL 不会传递给上游应用,而由中间件自身处理。 因此,所选 URL 不应与上游应用需要使用的任何 URL 冲突。

有时还需要在 OpenID Connect 提供商的配置中设置此 URL,例如 Google Accounts。

它可以是绝对 URL、相对于协议的 URL(继承请求协议),或相对于域名的 URL(继承请求域名和协议)。 参阅以下示例。

继承请求的协议与域名,使用 Redirecturl 的路径

请求 URL RedirectURL 结果
http://expl.co /cback http://expl.co/cback

继承请求的协议,使用 Redirecturl 的域名与路径

请求 URL RedirectURL 结果
https://scur.co expl.co/cback https://expl.co/cback

使用绝对重定向 URL 替换请求 URL

请求 URL RedirectURL 结果
https://scur.co http://expl.co/cback http://expl.co/cback

支持的协议方案

仅支持 http 和 https 协议方案。

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oidc
spec:
  plugin:
    oidc:
      issuer: "https://tenant.auth0.com/realms/myrealm"
      redirectUrl: "/callback"
      clientId: my-oidc-client-name
      clientSecret: mysecret

clientId 与 clientSecret

在 Kubernetes Secret 中存储机密值

配置 clientId 和 clientSecret 时,可以引用与 Middleware 位于同一命名空间中的 Kubernetes Secret。 Kubernetes Secret 的引用采用 URN 格式:

urn:k8s:secret:[name]:[valueKey]

claims 声明

语法

claims 支持以下函数:

函数 说明 示例
Equals 验证 key 中的值是否等于 value。 Equals(`grp`, `admin`)
Prefix 验证 key 中的值是否以 value 为前缀。 Prefix(`referrer`, `http://example.com`)
Contains(字符串) 验证 key 中的值是否包含 value。 Contains(`referrer`, `/foo/`)
Contains(数组) 验证 key 数组是否包含 value。 Contains(`areas`, `home`)
SplitContains 验证 key 中的值按分隔符拆分后是否包含 value。 SplitContains(`scope`, ` `, `writer`)
OneOf 验证 key 数组是否包含 values 中的任意一个值。 OneOf(`areas`, `office`, `lab`)

所有函数都可以通过布尔运算符连接。支持以下运算符:

运算符 说明 示例
&& 比较两个函数,仅当二者都求值为 true 时返回 true。 Equals(`grp`, `admin`) && Equals(`active`, `true`)
|| 比较两个函数,只要任意一个求值为 true 就返回 true。 Equals(`grp`, `admin`) || Equals(`active`, `true`)
! 函数为 true 时返回 false,否则返回 true。 !Equals(`grp`, `testers`)

对于以下数据结构,所有示例都会返回 true:

{
  "active": true,
  "grp": "admin",
  "scope": "reader writer deploy",
  "referrer": "http://example.com/foo/bar",
  "areas": [
    "office",
    "home"
  ]
}

嵌套声明

在键之间使用 . 可以支持嵌套声明。例如:

user.name
{
  "active": true,
  "grp": "admin",
  "scope": "reader writer deploy",
  "referrer": "http://example.com/foo/bar",
  "areas": [
    "office",
    "home"
  ],
  "user" {
    "name": "John Snow",
    "status": "undead"
  }
}
John Snow

处理包含 '.' 的键

如果 key 包含点号,可以使用 \. 转义。

处理包含 '\' 的键

如果 key 包含 \,则需要写成两个:\\。

访问令牌与 ID 令牌的声明

函数的第一个参数表示要在令牌声明中查找的键,可以通过前缀指定要检查两种令牌中的哪一种。 可用前缀为 id_token. 和 access_token.。不指定前缀时,默认检查 ID 令牌。

示例 说明
Equals(`id_token.grp`, `admin`) 检查 ID 令牌中 grp 声明的值是否为 admin。
Prefix(`access_token.referrer`, `http://example.com`) 检查访问令牌中 referrer 声明的值是否以 http://example.com\ 为前缀。
OneOf(`areas`, `office`, `lab`) 检查 ID 令牌中 areas 声明的值是否为 office 或 labs。

clientConfig 客户端配置

定义 API 网关连接身份提供商等第三方软件时使用的配置。

clientConfig.tls TLS 配置

在 Kubernetes Secret 中存储机密值

配置 tls.ca、tls.cert、tls.key 时,可以引用与 Middleware 位于同一命名空间中的 Kubernetes Secret。 Kubernetes Secret 的引用采用 URN 格式:

urn:k8s:secret:[name]:[valueKey]
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oidc
spec:
  plugin:
    oidc:
      clientConfig:
        tls:
          ca: "urn:k8s:secret:tls:ca"
          cert: "urn:k8s:secret:tls:cert"
          key: "urn:k8s:secret:tls:key"
          insecureSkipVerify: true
apiVersion: v1
kind: Secret
metadata:
  name: tls
stringData:
  ca: |-
    -----BEGIN CERTIFICATE-----
    MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
    BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
    Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
    aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
    DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
    EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
    RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
    apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
    Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
    ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
    98TwDIK/39WEB/V607As+KoYazQG8drorw==
    -----END CERTIFICATE-----
  cert: |-
    -----BEGIN CERTIFICATE-----
    MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
    BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
    Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
    aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
    DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
    EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
    RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
    apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
    Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
    ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
    98TwDIK/39WEB/V607As+KoYazQG8drorw==
    -----END CERTIFICATE-----
  key: |-
    -----BEGIN EC PRIVATE KEY-----
    MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49
    AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu
    KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ==
    -----END EC PRIVATE KEY-----

sameSite 可接受的值

  • none:浏览器会在跨站请求和同站请求中都发送 Cookie。
  • strict:浏览器仅在同站请求(源自设置该 Cookie 的站点的请求)中发送 Cookie。 如果请求来自与当前位置 URL 不同的 URL,则不会包含任何标记为 strict 的 Cookie。
  • lax:同站 Cookie 不会随跨站子请求(例如加载图片或框架的调用)发送,但用户从外部站点导航到该 URL 时会发送,例如点击链接。

session.store 会话存储

OpenID Connect 认证中间件可以使用持久化 KV 存储保存 HTTP 会话数据, 而不是将所有状态都保存在 Cookie 中。 这能避免 Cookie 变得过大而引发延迟问题。

参阅 Redis 选项来配置 Redis 连接。

Redis 服务器的连接参数配置在 Middleware 部署中。

支持以下 Redis 模式:

提示

如果使用 Redis 单实例模式或 Redis Sentinel,可以配置 database 字段。 如果使用 Redis Cluster,此值不会生效(仅可使用数据库 0)。

此时将显示一条警告,并忽略该值。

更多 Redis 信息,建议参阅 Redis 官方文档。

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oidc
spec:
  plugin:
    oidc:
      issuer: "https://tenant.auth0.com/realms/myrealm"
      redirectUrl: "/callback"
      clientId: my-oidc-client-name
      clientSecret: mysecret
      session:
        store:
          redis:
            endpoints:
              - redis-master.traefik-hub.svc.cluster.local:6379
            password: "urn:k8s:secret:oidc:redisPass"
apiVersion: v1
kind: Secret
metadata:
  name: oidc
stringData:
  redisPass: mysecret12345678

csrf 跨站请求伪造防护

CSRF 内部行为

OIDC 会话过期时,对应的 CSRF Cookie 会被删除。 这意味着,每当会话刷新或重建时,都会生成新的 CSRF 令牌并发送给客户端。

当请求使用非安全方法时(参见 RFC7231#section-4.2.1), 必须通过 headerName 选项配置的请求头,将 CSRF 令牌值(从 Cookie 提取)发送给服务器。


在生产环境使用 Traefik OSS?

如果你在工作中使用 Traefik,可以考虑为 Traefik OSS 增加企业级 API 网关能力或商业支持。

为 Traefik OSS 增加 API 网关能力快捷且平滑,无需推倒重来,现有配置也会完整保留。请通过这个简短视频了解实际效果。


版权所有 © 头文件软件工作室

文档由 HeadFile Studio 翻译。

Traefik v3.7 中文快照 · 原文版权归 Traefik Labs 及贡献者所有 · MIT 许可证