Skip to content

A reverse proxy that provides authentication with Google, Azure, OpenID Connect and many more identity providers.

Notifications You must be signed in to change notification settings

Jing-ze/oauth2-proxy

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OIDC Wasm 插件

简介

本仓库提供了一个高度可集成的Wasm插件支持OpenID Connect(OIDC)身份认证,同时强化了对跨站请求伪造(CSRF)攻击的防御能力,支持OpenID Connect协议中的Logout Endpoint。在通过Wasm插件OIDC验证后的请求会携带 Authorization的标头对应ID Token。

OIDC 流程图

oidc_process

OIDC 流程解析

  1. 模拟用户访问对应服务api

    curl --url "foo.bar.com/headers"
  2. Higress重定向到OIDC Provider登录页同时携带client_id、response_type、scope等OIDC认证的参数并设置csrf cookie防御CSRF攻击

    curl --url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/authorize"\
      --url-query "approval_prompt=force" \
      --url-query "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \
      --url-query "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \
      --url-query "response_type=code" \
      --url-query "scope=openid+email+offline_access" \
      --url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \
      --header "Set-Cookie: _oauth2_proxy_csrf=LPruATEDgcdmelr8zScD_ObhsbP4zSzvcgmPlcNDcJpFJ0OvhxP2hFotsU-kZnYxd5KsIjzeIXGTOjf8TKcbTHbDIt-aQoZORXI_0id3qeY0Jt78223DPeJ1xBqa8VO0UiEOUFOR53FGxirJOdKFxaAvxDFb1Ok=|1718962455|V1QGWyjQ4hMNOQ4Jtf17HeQJdVqHdt5d65uraFduMIU=; Path=/; Expires=Fri, 21 Jun 2024 08:06:20 GMT; HttpOnly"
  3. 用户在登录页进行登录

keycloak_login

  1. 携带授权重定向到Higress并携带了state参数用于验证CSRF Cookie,授权code用于交换Token

    curl --url "http://foo.bar.com/oauth2/callback" \
      --url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \
      --url-query "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm"
  2. 利用授权交换id_token和access_token

    curl -X POST \
      --url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/oauth/token" \
      --data "grant_type=authorization_code" \
      --data "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \
      --data "client_secret=ekqv5XoZuMFtYms1NszEqRx03qct6BPvGeJUeptNG4y09PrY16BKT9IWezTrrhJJ" \
      --data "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \
      --data "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm" \

    返回的请求里包含了id_token, access_token,refresh_token用于后续刷新access_token

    {
        "access_token": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtbzQzeGIxbXo3eWE3YWNoNC51cy5hdXRoMC5jb20vIn0..WP_WRVM-y3fM1sN4.fAQqtKoKZNG9Wj0OhtrMgtsjTJ2J72M2klDRd9SvUKGbiYsZNPmIl_qJUf81D3VIjD59o9xrOOJIzXTgsfFVA2x15g-jBlNh68N7dyhXu9237Tbplweu1jA25IZDSnjitQ3pbf7xJVIfPnWcrzl6uT8G1EP-omFcl6AQprV2FoKFMCGFCgeafuttppKe1a8mpJDj7AFLPs-344tT9mvCWmI4DuoLFh0PiqMMJBByoijRSxcSdXLPxZng84j8JVF7H6mFa-dj-icP-KLy6yvzEaRKz_uwBzQCzgYK434LIpqw_PRuN3ClEsenwRgIsNdVjvKcoAysfoZhmRy9BQaE0I7qTohSBFNX6A.mgGGeeWgugfXcUcsX4T5dQ",
        "refresh_token": "GrZ1f2JvzjAZQzSXmyr1ScWbv8aMFBvzAXHBUSiILcDEG",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imc1Z1ExSF9ZbTY0WUlvVkQwSVpXTCJ9.eyJlbWFpbCI6IjE2MDExNTYyNjhAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2Rldi1vNDN4YjFtejd5YTdhY2g0LnVzLmF1dGgwLmNvbS8iLCJhdWQiOiJZYWdGcVJEOXRmTklhYWM1QmFtamhzU2F0anJBbnNuWiIsImlhdCI6MTcxOTE5ODYzOCwiZXhwIjoxNzE5MjM0NjM4LCJzdWIiOiJhdXRoMHw2NjVkNzFlNzRjMTMxMTc3YmU2NmU2MDciLCJzaWQiOiJjdDJVOF9ZUS16VDdFOGkwRTNNeUstejc5ZGlWUWhhVSJ9.gfzXKJ0FeqzYqOUDLQHWcUG19IOLqkpLN09xTmIat0umrlGV5VNSumgWH3XJmmwnhdb8AThH3Jf-7kbRJzu4rM-BbGbFTRBTzNHeUajFOFrIgld5VENQ_M_sXHkTp0psWKSr9vF24kmilCfSbvC5lBKjt878ljZ7-xteWuaUYOMUdcJb4DSv0-zjX01sonJxYamTlhji3M4TAW7VwhwqyZt8dBhVSNaRw1wUKj-M1JrBDLyx65sroZtSqVA0udIrqMHEbWYb2de7JjzlqG003HRMzwOm7OXgEd5ZVFqgmBLosgixOU5DJ4A26nlqK92Sp6VqDMRvA-3ym8W_m-wJ_A",
        "scope": "openid email offline_access",
        "expires_in": 86400,
        "token_type": "Bearer"
    }
  3. 将获得的id_token和access_token加密存储在Cookie _oauth2_proxy中,用于后续用户登录状态的验证,同时清除Cookie _oauth2_proxy_csrf

    "Set-Cookie": [
        "_oauth2_proxy_csrf=; Path=/; Expires=Mon, 24 Jun 2024 02:17:39 GMT; HttpOnly",
        "_oauth2_proxy=8zM_Pcfpp_gesKFe4SMg08o5Iv0A8WAOQOmG1-vZBbQ56UggYVC0Cu-gFMEoxJZU5q1O5vqRlVBizlLetgVjRCksGVbttwl8tQ7h5YiyIubbbtvF1T4JzLh3QfzUUrwbB-VznOkh8qLbjAhddocecjBt4rMiDyceKXqMr4eO5TUEMx4vHtJYnTYalMeTYhGXk5MNSyrdZX9NnQnkdrCjiOQM13ggwob2nYwhGWaAlgzFSWkgkdtBy2Cl_YMWZ8_gKk9rDX289-JrJyGpr5k9O9RzRhZoY2iE3Mcr8-Q37RTji1Ga22QO-XkAcSaGqY1Qo7jLdmgZTYKC5JvtdLc4rj3vcbveYxU7R3Pt2vEribQjKTh4Sqb0aA03p4cxXyZN4SUfBW1NAOm4JLPUhKJy8frqC9_E0nVqPvpvnacaoQs8WkX2zp75xHoMa3SD6KZhQ5JUiPEiNkOaUsyafLvht6lLkNDhgzW3BP2czoe0DCDBLnsot0jH-qQpMZYkaGr-ZnRKI1OPl1vHls3mao5juOAW1VB2A9aughgc8SJ55IFZpMfFMdHdTDdMqPODkItX2PK44GX-pHeLxkOqrzp3GHtMInpL5QIQlTuux3erm3CG-ntlUE7JBtN2T9LEb8XfIFu58X9_vzMun4JQlje2Thi9_taI_z1DSaTtvNNb54wJfSPwYCCl4OsH-BacVmPQhH6TTZ6gP2Qsm5TR2o1U2D9fuVkSM-OPCG9l3tILambIQwC3vofMW6X8SIFSmhJUDvN7NbwxowBiZ6Y7GJRZlAk_GKDkpsdrdIvC67QqczZFphRVnm6qi-gPO41APCbcO6fgTwyOhbP3RrZZKWSIqWJYhNE3_Sfkf0565H7sC7Hc8XUUjJvP3WnjKS9x7KwzWa-dsUjV3-Q-VNl-rXTguVNAIirYK-qrMNMZGCRcJqcLnUF0V_J2lVmFyVsSlE3t0sDw2xmbkOwDptXFOjQL5Rb4esUMYdCBWFajBfvUtcZEFtYhD0kb6VcbjXO3NCVW5qKh_l9C9SRCc7TG1vcRAqUQlRXHacTGWfcWsuQkCJ3Mp_oWaDxs1GRDykQYxAn5sTICovThWEU2C6o75grWaNrkj5NU-0eHh3ryvxLmGLBOXZV9OQhtKShWmUgywSWMxOHOuZAqdAPULc8KheuGFjXYp-RnCbFYWePJmwzfQw89kSkj1KUZgMYwKEjSz62z2qc9KLczomv76ortQzvo4Hv9kaW6xVuQj5R5Oq6_WMBOqsmUMzcXpxCIOGjcdcZRBc0Fm09Uy9oV1PRqvAE4PGtfyrCaoqILBix8UIww63B07YGwzQ-hAXDysBK-Vca2x7GmGdXsNXXcTgu00bdsjtHZPDBBWGfL3g_rMAXr2vWyvK4CwNjcaPAmrlF3geHPwbIePT0hskBboX1v1bsuhzsai7rGM4r53pnb1ZEoTQDa1B-HyokFgo14XiwME0zE1ifpNzefjpkz1YY2krJlqfCydNwoKaTit4tD2yHlnxAeFF9iIrxzSKErNUFpmyLa7ge7V33vhEH-6k5oBTLE2Q2BrC6aAkLCcPwU9xv_SzBDQPRY0MEYv3kGF03Swo1crRbGh-aifYX9NiHDsmG6r1vAnx0MAOw2Jzuz2x6SSdfBrzlcoWBlrwiZzd9kAKq75n1Uy9uzZ8SRnkBrEZySHBwEbu196VklkRE0jqwC-e3wWNNuviSOfwkVeX-7QdOoO10yw9VK2sW52lFvIEf4chv_ta7bGfAZOWBjpktG6ZLD81SE6A88zpqG2SysSyNMp9hl-umG-5sFsjCn_c9E8bDvwkUOUVb9bNqhBDsZgR0BNPawiOZjmyfhzmwmWf-zgFzfFSV6BvOwNRi3sCOHTsWcuk9NBQ_YK8CpNkVl3WeIBSDfidimuC_QV9UWKs1GPk35ZRkM4zKtLY2JsBFWKaDy_P80TcOzcMBoP8gIBClXZ-WUqfE8s1yyc4jrq-qL1_wJ24ef1O9FktsbyZiDKXw2vnqsT8-g_hCeG-unrT1ZFscf8oNdqczARHX-K4vKH2k3uIqEx1M=|1719199056|2rsgdUIClHNEpxBLlHOVRYup6e4oKensQfljtmn4B80=; Path=/; Expires=Mon, 01 Jul 2024 03:17:36 GMT; HttpOnly"
    ]
  4. 携带 Authorization的标头对应id_token访问对应api

    curl --url "foo.bar.com/headers"
      --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imc1Z1ExSF9ZbTY0WUlvVkQwSVpXTCJ9.eyJlbWFpbCI6IjE2MDExNTYyNjhAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2Rldi1vNDN4YjFtejd5YTdhY2g0LnVzLmF1dGgwLmNvbS8iLCJhdWQiOiJZYWdGcVJEOXRmTklhYWM1QmFtamhzU2F0anJBbnNuWiIsImlhdCI6MTcxOTE5ODYzOCwiZXhwIjoxNzE5MjM0NjM4LCJzdWIiOiJhdXRoMHw2NjVkNzFlNzRjMTMxMTc3YmU2NmU2MDciLCJzaWQiOiJjdDJVOF9ZUS16VDdFOGkwRTNNeUstejc5ZGlWUWhhVSJ9.gfzXKJ0FeqzYqOUDLQHWcUG19IOLqkpLN09xTmIat0umrlGV5VNSumgWH3XJmmwnhdb8AThH3Jf-7kbRJzu4rM-BbGbFTRBTzNHeUajFOFrIgld5VENQ_M_sXHkTp0psWKSr9vF24kmilCfSbvC5lBKjt878ljZ7-xteWuaUYOMUdcJb4DSv0-zjX01sonJxYamTlhji3M4TAW7VwhwqyZt8dBhVSNaRw1wUKj-M1JrBDLyx65sroZtSqVA0udIrqMHEbWYb2de7JjzlqG003HRMzwOm7OXgEd5ZVFqgmBLosgixOU5DJ4A26nlqK92Sp6VqDMRvA-3ym8W_m-wJ_A"
  5. 后端服务根据id_token获取用户信息并返回对应的Http响应

    {
        "email": "******",
        "email_verified": false,
        "iss": "https://dev-o43xb1mz7ya7ach4.us.auth0.com/",
        "aud": "YagFqRD9tfNIaac5BamjhsSatjrAnsnZ",
        "iat": 1719198638,
        "exp": 1719234638,
        "sub": "auth0|665d71e74c131177be66e607",
        "sid": "ct2U8_YQ-zT7E8i0E3MyK-z79diVQhaU"
    }

配置

配置项

Option Type Description Default
cookie_name string the name of the cookie that the oauth_proxy creates. Should be changed to use a cookie prefix (__Host- or __Secure-) if --cookie-secure is set. "_oauth2_proxy"
cookie_secret string the seed string for secure cookies (optionally base64 encoded)
cookie_domains string|list Optional cookie domains to force cookies to (e.g. .yourcompany.com). The longest domain matching the request's host will be used (or the shortest cookie domain if there is no match).
cookie_path string an optional cookie path to force cookies to (e.g. /poc/) "/"
cookie_expire duration expire timeframe for cookie. If set to 0, cookie becomes a session-cookie which will expire when the browser is closed. 168h0m0s
cookie_refresh duration refresh the cookie after this duration; 0 to disable
cookie_secure bool set secure (HTTPS only) cookie flag true
cookie_httponly bool set HttpOnly cookie flag true
cookie_samesite string set SameSite cookie attribute ("lax", "strict", "none", or ""). ""
cookie_csrf_per_request bool Enable having different CSRF cookies per request, making it possible to have parallel requests. false
cookie_csrf_expire duration expire timeframe for CSRF cookie 15m
client_id string the OAuth Client ID
client_secret string the OAuth Client Secret
provider string OAuth provider oidc
pass_authorization_header bool pass OIDC IDToken to upstream via Authorization Bearer header true
oidc_issuer_url string the OpenID Connect issuer URL, e.g. "https://dev-o43xb1mz7ya7ach4.us.auth0.com"
oidc_verifier_request_timeout uint32 OIDC verifier discovery request timeout 2000(ms)
scope string OAuth scope specification
redirect_url string the OAuth Redirect URL, e.g. "https://internalapp.yourcompany.com/oauth2/callback"
service_name string registered name of the OIDC service, e.g. auth.dns, keycloak.static
service_port int64 service port of the OIDC service
service_host string host of the OIDC service when type is static ip
match_type string match type (whitelist or blacklist) "whitelist"
match_list rule|list a list of (match_rule_domain, match_rule_path, and match_rule_type).
match_rule_domain string match rule domain, support wildcard pattern such as *.bar.com
match_rule_path string match rule path such as /headers
match_rule_type string match rule type can be exact or prefix or regex

生成 Cookie 密钥

python -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'

参考:Oauth2-proxy Generating a Cookie Secret

黑白名单模式

支持黑白名单模式配置,默认为白名单模式,白名单为空,即所有请求都需要经过验证,匹配域名支持泛域名例如*.bar.com,匹配规则支持精确匹配exact,前缀匹配prefix,正则匹配regex

  • 白名单模式
match_type: 'whitelist'
match_list:
    - match_rule_domain: '*.bar.com'
      match_rule_path: '/foo'
      match_rule_type: 'prefix'

泛域名*.bar.com下前缀匹配/foo的请求无需验证

  • 黑名单模式
match_type: 'blacklist'
match_list:
    - match_rule_domain: '*.bar.com'
      match_rule_path: '/headers'
      match_rule_type: 'prefix'

只有泛域名*.bar.com下前缀匹配/header的请求需要验证

注销用户

注销用户需重定向到/oauth2/sign_out这个端点。这个端点仅移除oauth2-proxy自己设置的cookie,也就是说,用户仍然在OIDC Provider处保持登录状态,并且在再次访问应用时可能会自动重新登录。因此还需要使用rd查询参数将用户重定向到认证提供商的注销页面,即重定向用户到类似如下地址(注意URL编码!):

/oauth2/sign_out?rd=https%3A%2F%2Fmy-oidc-provider.example.com%2Fsign_out_page

或者,可以在X-Auth-Request-Redirect头部中包含重定向URL:

GET /oauth2/sign_out HTTP/1.1
X-Auth-Request-Redirect: https://my-oidc-provider.example.com/sign_out_page
...

重定向URL中可以包含post_logout_redirect_uri参数指定OIDC Provider登出后跳转到的页面,例如后端服务的登出页面,不携带该参数则默认跳转到OIDC Provider的登出页面,详情见下方auth0和keycloak的示例(如果OIDC Provider支持会话管理和发现,那么"sign_out_page"应该是从metadata中获取的end_session_endpoint

OIDC 服务 HTTPS 协议

如果 OIDC Provider 为 HTTPS 协议,参考Higress中配置后端服务协议:HTTPS的说明需要通过使用注解higress.io/backend-protocol: "HTTPS"配置请求转发至后端服务使用HTTPS协议,参考Auth0示例中Ingress配置

配置示例

Auth0 配置示例

Step 1: 配置 Auth0 账户

:需填写Allowed Callback URLs, Allowed Logout URLs, Allowed Web Origins等配置项,否则 OIDC Provider 会认为用户跳转的重定向 URL 或登出 URL 无效

Step 2: Higress 配置服务来源

  • 在Higress服务来源中创建auth0 DNS来源

auth0 create

Step 3: OIDC 服务 HTTPS 配置

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auth0-ingress
  annotations:
    higress.io/destination: auth.dns
    higress.io/backend-protocol: "HTTPS"
    higress.io/ignore-path-case: "false"
spec:
  ingressClassName: higress
  rules:
    - host: foo.bar.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              resource:
                apiGroup: networking.higress.io
                kind: McpBridge
                name: default

Step 4: Wasm 插件配置

redirect_url: 'http://foo.bar.com/oauth2/callback'
oidc_issuer_url: 'https://dev-o43xb1mz7ya7ach4.us.auth0.com/'
client_id: 'YagFqRD9tfNIaac5BamjhsSatjrAnsnZ'
client_secret: 'ekqv5XoZuMFtYms1NszEqRx03qct6BPvGeJUeptNG4y09PrY16BKT9IWezTrrhJJ'
scope: 'openid email offline_access'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'auth.dns'
service_port: 443
match_type: 'whitelist'
match_list:
    - match_rule_domain: '*.bar.com'
      match_rule_path: '/foo'
      match_rule_type: 'prefix'

:必须先配置服务来源,wasm插件在初始化时需要访问配置的服务获取openid-configuration

访问服务页面,未登陆的话进行跳转

auth0_login

登陆成功跳转到服务页面

headers中可以看到携带了_oauth2_proxy 的cookie用于下次登陆访问,Authorization对应IDToken用于后端服务获得用户信息

auth0 service

访问登出跳转到登出页面

http://foo.bar.com/oauth2/sign_out?rd=https%3A%2F%2Fdev-o43xb1mz7ya7ach4.us.auth0.com%2Foidc%2Flogout

auth0 logout

访问登出跳转到登出页面(携带post_logout_redirect_uri参数跳转指定uri)

http://foo.bar.com/oauth2/sign_out?rd=https%3A%2F%2Fdev-o43xb1mz7ya7ach4.us.auth0.com%2Foidc%2Flogout%3Fpost_logout_redirect_uri%3Dhttp%3A%2F%2Ffoo.bar.com%2Ffoo

注:post_logout_redirect_uri跳转的uri需要在OIDC Provider Allowed URLs处配置才可以正常跳转

auth0 logout redirect

keycloak 配置示例

Step 1: Get started with keycloak on docker

https://www.keycloak.org/getting-started/getting-started-docker

:需填写Valid redirect URIs, Valid post logout URIs, Web origins配置项,否则 OIDC Provider 会认为用户跳转的重定向 URL 或登出 URL 无效

Step 2: Higress 配置服务来源

  • 在Higress服务来源中创建Keycloak固定地址服务

keycloak create

Step 3: Wasm 插件配置

redirect_url: 'http://foo.bar.com/oauth2/callback'
oidc_issuer_url: 'http://127.0.0.1:9090/realms/myrealm'
client_id: 'myclient'
client_secret: 'PgSvuK7M4GYMPUaO0naQteKhpWYDpBYE'
scope: 'openid email'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'keycloak.static'
service_port: 80
service_host: '127.0.0.1:9090'
match_type: 'blacklist'
match_list:
    - match_rule_domain: '*.bar.com'
      match_rule_path: '/headers'
      match_rule_type: 'prefix'

访问服务页面,未登陆的话进行跳转

keycloak_login

登陆成功跳转到服务页面

keycloak service

访问登出跳转到登出页面

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout

keycloak logout

访问登出跳转到登出页面(携带post_logout_redirect_uri参数跳转指定uri)

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout%3Fpost_logout_redirect_uri%3Dhttp%3A%2F%2Ffoo.bar.com%2Ffoo

keycloak logout redirect

About

A reverse proxy that provides authentication with Google, Azure, OpenID Connect and many more identity providers.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%