Ext Auth with Istio 1.9.1 and Oauth-proxy redirect issue once authenticated

Hi,

I have setup a test environment with oauth2-proxy ,dex and istio 1.9.1 to test the ext_authz functionality.

All code can be found here : istio-on-kind/mesh.yaml at 4178bad9614de33d1b215d7c0cb7fe32ad08b839 · primeroz/istio-on-kind · GitHub

This is almost working other than the final redirect to the original URL Requested

  • setup the cluster as described in README.md
  • visit http://podinfo.127.0.0.1.nip.io
  • get redirected to dex by istio ingress due to oauth2-proxy and the request no having the cookie
  • authenticate with admin@example.com and password
  • client get redirected to oauth2-proxy.127.0.0.1/oauth2/callback and the client is presented an authenticated page
  • here i would expect to get redirected to the original url http://podinfo.127.0.0.1.nip.io but instead you only get the oauth2-proxy Authenticated Page
  • visit the URL http://podinfo.127.0.0.1.nip.io again
  • client has the cookie, oauth2-proxy return 200 to istio and the request is forwarded to the usptream workload

Is it actually possible to get it to work all in one shot ?

Configuration Snippets

MeshConfig

    extensionProviders: 
    - name: "oauth2-proxy"
      envoyExtAuthzHttp:
        service: "oauth2-proxy.dex.svc.cluster.local"
        port: "4180" # The default port used by oauth2-proxy.
        #includeHeadersInCheck: ["authorization", "cookie"]  # headers sent to the oauth2-proxy in the check request.
        includeHeadersInCheck: # headers sent to the oauth2-proxy in the check request.
            # https://github.com/oauth2-proxy/oauth2-proxy/issues/350#issuecomment-576949334
            - "cookie"
            - "x-forwarded-access-token"
            - "x-forwarded-user"
            - "x-forwarded-email"
            - "authorization"
            - "x-forwarded-proto"
            - "proxy-authorization"
            - "user-agent"
            - "x-forwarded-host"
            - "from"
            - "x-forwarded-for"
            - "accept"
        headersToUpstreamOnAllow: ["authorization", "path", "x-auth-request-user", "x-auth-request-email", "x-auth-request-access-token", "x-auth-request-user-groups"] # headers sent to backend application when request is allowed.
        headersToDownstreamOnDeny: ["content-type", "set-cookie"] # headers sent back to the client when request is denied.

OAUTH proxy is configured as

          - --http-address=0.0.0.0:4180
          - --email-domain="example.com"
          - --cookie-refresh=1h
          - --cookie-secure=false # Set to false for test environment only
          - --set-xauthrequest=true # X-Auth-Request-User, X-Auth-Request-Email, X-Auth-Request-Preferred-Username, X-Auth-Request-Groups
          - --pass-access-token=true # X-Auth-Request-Access-Token, must first enable --set-xauthrequest
          - --set-authorization-header=true # Authorization: Bearer <JWT>
          - --pass-authorization-header=true # pass OIDC IDToken to upstream via Authorization Bearer header
          - --pass-host-header=true # pass the request Host Header to upstream
          - --pass-access-token=true # pass OAuth access_token to upstream via X-Forwarded-Access-Token header. When used with --set-xauthrequest this adds the X-Auth-Request-Access-Token header to the response
          - --upstream=static://200
          - --reverse-proxy
          #- --whitelist-domain=".127.0.0.1.nip.io"
          - --whitelist-domain=".127.0.0.1.nip.io"
          - --cookie-domain=".127.0.0.1.nip.io"
          - --cookie-name=_oauth2_proxy
          - --cookie-samesite=lax
          #- --scope="openid groups profile email"
          - --provider=oidc
          - --oidc-issuer-url=http://dex.127.0.0.1.nip.io
          - --redirect-url=http://oauth2-proxy.127.0.0.1.nip.io/oauth2/callback
          - --skip-provider-button=true

and the AuthPolicy

---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: podinfo
  #namespace: dev
  # Does it need to be in the ingrassgateway namespace?
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: CUSTOM
  provider:
    name: "oauth2-proxy"
  rules:
    - to:
      - operation:
          hosts:
          - "podinfo.127.0.0.1.nip.io"
1 Like

For reference:

The issue was with setting - --redirect-url=http://oauth2-proxy.127.0.0.1.nip.io/oauth2/callback

without that the callback will be to the original HOST/oauth2/callback which envoy will forward to oauth2-proxy for validation and then back to the original HOST

cc @YangminZhu regarding to external authz.

@YangminZhu I’m seeing a similar issue attempting to configure oauth2-proxy as an external authorization provider: The original request to an authaurizationpolicy-protected service gets successfully redirected to the oauth2-proxy, I’m able to authenticate, and the redirect goes back to the oauth2-proxy.

The problem is, oauth2-proxy requires one of the following to be configured on the request in order to correctly redirect the original request back to the original host:

  • rd querysting parameter
  • X-Auth-Request-Redirect header
  • X-Forwarded-(Proto|Host|Uri) headers (when ReverseProxy mode is enabled)
  • X-Forwarded-(Proto|Host) if Uri has the ProxyPath (i.e. /oauth2/*)
  • X-Forwarded-Uri direct URI path (when ReverseProxy mode is enabled)
  • req.URL.RequestURI if not under the ProxyPath (i.e. /oauth2/*)

Clearly these headers do not exist on the ext_authz initiated requests to the oauth2-proxy, and therefore the oauth2-proxy does not redirect. Are you aware of any solutions to configure the redirect correctly?

oauth2-proxy config:

provider = "oidc"
whitelist_domain = ".internal.com"
cookie_domain = ".internal.com"
redirect_url = "https://oauth2-proxy-url.com/oauth2/callback"
oidc_issuer_url = "https://x.okta.com/oauth2/default"
email_domains = [
    "*"
]
upstreams = [ "static://200" ]
pass_access_token = true
skip_provider_button = true
set_authorization_header = true
pass_authorization_header = true
pass_host_header = true
set_xauthrequest = true
skip_jwt_bearer_tokens = false
reverse_proxy = true
cookie_name = "_oauth2_proxy"
cookie_samesite = "lax"

standard_logging = true
auth_logging = true
request_logging = true
session-cookie-minimal = true

Mesh config:

  meshConfig:
# Add the following content to define the external authorizers.
extensionProviders:
  - name: "oauth2-proxy"
    envoyExtAuthzHttp:
      service: "oauth2-proxy.auth.svc.cluster.local"
      port: "80" # The default port used by oauth2-proxy.
      includeHeadersInCheck: # headers sent to the oauth2-proxy in the check request.  https://github.com/oauth2-proxy/oauth2-proxy/issues/350#issuecomment-576949334
        - "cookie"
        - "x-forwarded-access-token"
        - "x-forwarded-user"
        - "x-forwarded-email"
        - "authorization"
        - "x-forwarded-proto"
        - "proxy-authorization"
        - "user-agent"
        - "x-forwarded-host"
        - "from"
        - "x-forwarded-for"
        - "x-forwarded-uri"
        - "x-auth-request-redirect"
        - "accept"
      headersToUpstreamOnAllow: ["authorization", "path", "x-auth-request-user", "x-forwarded-uri", "x-auth-request-redirect", "x-auth-request-email", "x-auth-request-access-token", "x-auth-request-user-groups"] # headers sent to backend application when request is allowed.
      headersToDownstreamOnDeny: ["content-type", "set-cookie"] # headers sent back to the client when request is denied.

The following did the trick for me (note the includeAdditionalHeadersInCheck entry):

    extensionProviders:
    - envoyExtAuthzHttp:
        headersToDownstreamOnDeny:
        - content-type
        - set-cookie
        headersToUpstreamOnAllow:
        - authorization
        - cookie
        includeAdditionalHeadersInCheck:
          X-Auth-Request-Redirect: 'https://%REQ(Host)%'
        includeHeadersInCheck:
        - authorization
        - cookie
        port: 4180
        service: oauth2-proxy.istio-system.svc.cluster.local
      name: oauth2-proxy

This effectively adds another header, X-Auth-Request-Redirect, to the request that gets forwarded to oauth2-proxy. The value of this header is extracted from the pre-existing Host header.

@djfinnoy thanks for the pointer - I’ve tried updating to istio 1.10 and configuring includeAdditionalHeadersInCheck as you’ve suggested. I’m seeing that the X-Auth-Request-Redirect header does get attached on authentication, but the HOST is set to the oauth2-proxy url, not the original HOST.

If possible, would you mind sharing your oauth2-proxy deployment configuration and istio AuthorizationPolicy?

I posted my setup in a separate thread: Adding headers for oauth2-proxy redirect

Check the oauth2-proxy logs now that you’ve got a redirect header, if there are any issues with your redirect URL it will be posted there (note that protocol and quotation marks are required, eg 'https://%REQ(Host)%').

Out of curiosity, how are you seeing the headers sent to oauth2-proxy? They don’t show up in my in my browser.

@djfinnoy Thanks for sharing your config! I’ve ensured I’m using quotes in my Istio Operator definition (as you’ve suggested).

One thing I noticed is that you’re not configuring oauth2-proxy’s redirect_url (which I am currently doing in my config). Is this intentional? If so, how do you define the accepted redirect_urls on your Oauth application (looks like you’re using github)?

Ok - I finally have this working - it seems to have been an issue with the version of oauth2-proxy I was using (originally v5.x). Since updating to v7, the redirect works correctly with istio 1.10

glad you got it working.

I am in fact using --redirect-url, but it appears I accidentally cropped that out of my code example.
without it, the auth flow fails; tested this with both GitHub and Google as the oauth provider.

Thanks for this tip. I noticed the redirect was still landing at the root, for example starting the flow by visiting https://bookinfo.example.com/productpage results in being redirected to https://bookinfo.example.com after authentication.

The following configuration includes the scheme, authority (host:port), path and query parameters. I don’t think it includes anchor fragments though.

includeAdditionalHeadersInCheck:
  X-Auth-Request-Redirect: '%REQ(x-forwarded-proto)%://%REQ(:authority)%%REQ(:path)%'
2 Likes