Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward access token from OIDC login as Authorization Bearer token. #843

Closed
carabj opened this issue Oct 14, 2020 · 25 comments
Closed

Forward access token from OIDC login as Authorization Bearer token. #843

carabj opened this issue Oct 14, 2020 · 25 comments

Comments

@carabj
Copy link

carabj commented Oct 14, 2020

Forward access token from OIDC login as Authorization Bearer token.

Expected Behavior

It should be possible to forward the access token gained from the OIDC provider in upstream calls as the Authorization Bearer token.

Current Behavior

It is only possible to forward the ID Token as Authorization Bearer token. The access token can only be forwarded in the X-Forwarded-Access-Token header (or X-Auth-Forwarded-Access-Token).

Possible Solution

Make it configurable to forward the Access Token as Authorization Bearer token.

Suggestion:
pass_access_token="true"
pass_access_token_as_bearer="true"

With the second option the oauthproxy can do:
if p.PassAccessToken { if p.PassAccessTokenAsBearer { if session.AccessToken != "" { req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", session.AccessToken)} } else { req.Header.Del("Authorization") } } else { if session.AccessToken != "" { req.Header["X-Forwarded-Access-Token"] = []string{session.AccessToken} } else { req.Header.Del("X-Forwarded-Access-Token") } } }

I have made this fix locally, and are willing to contribute with a PR, but need to discuss what needs to be checked/tested.

Also, if this option is enabled, it should not be possible to configure
pass_authorization_header="true"

I noticed there is requirements on the cookie secret if PassAccessToken is set to true. Therefor it feels most correct to extend that option with this new one. Rather than add an extra option to pass_authorization_header, which is based on id token.

Context

Our organization manage our own OAuth2 authorization service and OIDC provider. All our microservices expects the access token to be present in the Authorization header as Bearer token.

The access token can be both opaque or as JWT.

An ID Token is not an access token. It doesn't contain the scopes claim.

Your Environment

  • Version used: 6.1.1
@NickMeves
Copy link
Member

We are setting the stage for this in this PR: #826

At the moment we are just back porting the new header configuration libraries to legacy configurations. The end goal is to provide much more header customization power in a structured configs we are targeting for an upcoming major major release.

We are aiming to support features like this.

@kvaps
Copy link

kvaps commented Oct 26, 2020

Hi, I also faced this issue with Kubernetes and Keycloak, unlike louketo-proxy oauth2-proxy does not pass Authorization: Bearer token even if --pass-authorization-header option explicitly set, but Kubernetes rely on this header.

@NickMeves
Copy link
Member

@kvaps If you are using OAuth2-Proxy with a Kubernetes ingress using nginx subrequests (https://kubernetes.github.io/ingress-nginx/examples/auth/oauth-external-auth/) the data that comes back to nginx is actually an HTTP response, so you will need to use HTTP Response headers (the --pass-* options configure request headers to the upstream).

Try --set-authorization-header and then you need to use this annotation to have the Kubernetes take the subrequest response header and add it to the proxied request header: nginx.ingress.kubernetes.io/auth-response-headers

https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#external-authentication

@NickMeves
Copy link
Member

@JoelSpeed Might be worth revisiting our conversation on X-Forwarded-* and X-Auth-Request-* headers between the request and response respectively.

Having them as different header prefixes with different flags that configure them seems to be resulting in a lot of Issues/Questions lately -- Envoy/Nginx subrequest getting popular out of the blue lately.

@kvaps
Copy link

kvaps commented Oct 27, 2020

Hi @NickMeves my oauth2-proxy is running as a sidecar and proxying the requests to the application itself:

      - args:
        - --provider=keycloak
        - --client-id=kubernetes
        - --client-secret=7b412da4-548a-44af-a2c1-6b42a5c46431
        - --cookie-secret=x-1vrrMhC-886ITuz8ySNw==
        - --upstream=http://localhost:8080/
        - --http-address=0.0.0.0:3000
        - --email-domain=*
        - --pass-basic-auth=false
        - --pass-access-token=true
        - --set-xauthrequest=true
        - --skip-jwt-bearer-tokens=true
        - --set-authorization-header=true
        - --pass-authorization-header=true
        - --skip-auth-regex=^\/config\.json$
        - --skip-auth-regex=^\/favicon.*\.png$
        - --skip-auth-regex=^\/static\/
        - --skip-auth-regex=^\/$
        - --scope=openid email groups
        - --oidc-issuer-url=https://keycloak.example.org/auth/realms/kubernetes
        - --login-url=https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/auth
        - --redeem-url=https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/token
        - --validate-url=https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/userinfo
        - --keycloak-group=ipausers

But after the successful authentication my application see only these headers:

Hostname: kubeapps-84f7f5f7f6-v4hq4
IP: 127.0.0.1
IP: ::1
IP: 10.112.2.173
IP: fd00::2:f2c0
IP: fe80::8ce:b4ff:fe9e:10e7
RemoteAddr: [::1]:47192
GET /a HTTP/1.1
Host: kubeapps-stage.example.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Cache-Control: max-age=0
Cookie: < my cookies here >
Dnt: 1
Upgrade-Insecure-Requests: 1
X-Forwarded-Access-Token: < Bearer token here >
X-Forwarded-Email: andrei.kvapil@example.org
X-Forwarded-For: 10.31.2.82, 10.112.1.245
X-Forwarded-Host: kubeapps-stage.example.org
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Real-Ip: 10.31.2.82
X-Request-Id: 40aa3757f3387296d30fcad6b8a0b089
X-Scheme: https

However if I use louketo-proxy:

      - args:
        - --discovery-url=https://keycloak.example.org/auth/realms/kubernetes
        - --client-id=kubernetes
        - --client-secret=7b412da4-548a-44af-a2c1-6b42a5c46431
        - --encryption-key=oowuPaquoxe5ephaehah6aeb8ieweesu
        - --upstream-url=http://localhost:8080/
        - --listen=0.0.0.0:3000
        - --resources=uri=/config.json|white-listed=true
        - --resources=uri=/favicon*.png|white-listed=true
        - --resources=uri=/static/*|white-listed=true
        - --scopes=openid+email+groups
        - --enable-session-cookies=true
        - --enable-refresh-tokens=true
        - --enable-logout-redirect
        - --enable-logging=true
        - --verbose=true

I'm seeing more headers:

Hostname: kubeapps-654c8b8db4-m2vmf
IP: 127.0.0.1
IP: ::1
IP: 10.112.2.159
IP: fd00::2:7973
IP: fe80::e4:27ff:fe3b:702d
RemoteAddr: [::1]:60838
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Authorization: Bearer  < Bearer token here >
Cache-Control: max-age=0
Cookie: < My cookie here >
Dnt: 1
Upgrade-Insecure-Requests: 1
X-Auth-Audience: kubernetes
X-Auth-Email: andrei.kvapil@example.org
X-Auth-Expiresin: 2020-10-26 22:05:17 +0000 UTC
X-Auth-Groups: < My user groups here>
X-Auth-Roles: offline_access,uma_authorization,account:manage-account,account:manage-account-links,account:view-profile
X-Auth-Subject: 337a5e4b-ecce-4ef6-b28e-d89220ec0830
X-Auth-Token:  < Bearer token here >
X-Auth-Userid: kvaps
X-Auth-Username: kvaps
X-Forwarded-For: 127.0.0.1
X-Forwarded-Host: localhost:8080
X-Forwarded-Proto: 

In fact louketo-proxy is working, but with oauth2-proxy I'm getting, when I'm trying to access Kubernetes API:

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {
    
  },
  "code": 403
}

#826 does not solves this problem, should I open new issue?

@NickMeves
Copy link
Member

NickMeves commented Oct 27, 2020

At the moment, we only support the ID Token in the authorization header. We have a PR that aims to make this more configurable in the future: #826

Can you add some comments to that PR for @JoelSpeed if you think it doesn't cover your Access vs ID Token Authorization header concerns? I thought that PR was aiming to tackle that problem.

Structured configs that make this fully configurable currently targeted for v8. We are looking into adding alpha flags to give early access to these features in the codebase in v7.X

Weird that I don't see the Authorization header after you added the proper flag. Does the Keycloak provider not provide an ID Token, only and Access Token?

I'm not a Keycloak user, so I've lost track of the use cases. I've seen some people use the provider, others hook into it via OIDC -- so I don't fully know the tokens it gives back.

@kvaps
Copy link

kvaps commented Oct 27, 2020

Weird that I don't see the Authorization header after you added the proper flag. Does the Keycloak provider not provide an ID Token, only and Access Token?

Keycloak has an opportunity to request the ID token, eg kuberos is succefully doing that:

https://github.com/negz/kuberos/blob/ede40851585b5f11fb07242bea82a914e06db6b8/extractor/oidc.go#L89-L100

But all others: louketo-proxy, oauth2-proxy and kubelogin are requesting and using Bearer (Access token) for some reason

@JoelSpeed
Copy link
Member

If you try the oidc provider instead of the keycloak provider, does that give you an access token? As far as I remember the keycloak provider doesn't store an ID Token in the session, hence not getting an Authorization header

@JoelSpeed
Copy link
Member

@JoelSpeed Might be worth revisiting our conversation on X-Forwarded-* and X-Auth-Request-* headers between the request and response respectively.

@NickMeves Does this not go away when we introduce the structured configuration? Since users will just set request or response header injection?

@NickMeves
Copy link
Member

I more mean consolidating around a unified header prefix ie X-Forwarded-* on both upstream requests and downstream responses.

I think with the nginx or kubernetes ingress subrequest architecture, users get very confused about the need for X-Auth-Request-* since it isn't fully transparent that technically nginx/kubernetes is a client and gets back an HTTP Response.

(Then further confusing matters, they then likely want to forward the client's response headers to the upstream in the proxied request -- so in this architecture, the headers are X-Auth-Request-* headers instead of X-Forwarded-* that a parallel upstream app that is using an inline proxy architecture would get).

I support both the subrequest model for Kubernetes ingress resources to hook into as a central Access Proxy & deploying OAuth2-Proxy as an intercepting sidecar proxy with the apps. My backend app developers get very confused where to get the identity headers and which architecture they are using under the hood (since it is mostly transparent to them). They just confusingly get different sets of headers that do the same thing and they don't know why.

And then they come bug & blame me! 😅

@JoelSpeed
Copy link
Member

I think you could configure them to be the same needing the new configuration if you wanted to! The new configuration should be totally flexible so that you can do that.

I think normally if you were configuring nginx you would rename the response header from the OAuth2 Proxy before you copy it onto the request to the upstream

@kvaps
Copy link

kvaps commented Oct 27, 2020

If you try the oidc provider instead of the keycloak provider, does that give you an access token? As far as I remember the keycloak provider doesn't store an ID Token in the session, hence not getting an Authorization header

With --provider=oidc and port-forward on a service I'm getting correct ID token with Authorization Bearer <token> header set,
But through nginx-ingress I'm getting 502 error for some reason after successful identification, logs:

10.112.1.245:44644 - andrei.kvapil@example.org [2020/10/27 20:54:03] [AuthSuccess] Authenticated via OAuth2: Session{email:andrei.kvapil@example.org user:337a5e4b-ecce-4ef6-b28e-d89220ec0830 PreferredUsername:kvaps token:true id_token:true created:2020-10-27 20:54:03.305648569 +0000 UTC m=+436.246431873 expires:2020-10-27 20:59:03.305326464 +0000 UTC m=+736.246109762 refresh_token:true}
10.112.1.245:44644 - - [2020/10/27 20:54:03] kubeapps-stage.example.org GET - "/oauth2/callback?state=0894346b68f2132c41fbc6fe4387d7d1%3A%2F1&session_state=a80adf0d-a648-48bf-be00-ec6a3295ba9a&code=664f16c4-7030-42db-ba89-cbf97ec67b19.a80adf0d-a648-48bf-be00-ec6a3295ba9a.8e6a59a8-0c62-4418-9171-eb92e8c7794c" HTTP/1.1 "Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0" 302 25 0.148

@kvaps
Copy link

kvaps commented Oct 29, 2020

Fixed by setting the following annotations for nginx-ingress:

nginx.ingress.kubernetes.io/proxy-buffer-size: "64k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"

Thanks to https://stackoverflow.com/questions/58943111/nginx-ingress-returns-502-after-post-with-redirect

@github-actions
Copy link
Contributor

This issue has been inactive for 60 days. If the issue is still relevant please comment to re-activate the issue. If no action is taken within 7 days, the issue will be marked closed.

@tbabik
Copy link

tbabik commented Apr 12, 2021

Hi,

perhaps I missed it, but since 7.x is out - is it possible to configure the access token to be used as authorization bearer token?
From what I've seen in the configuration documentation of 7.1 it does not seem to be the case .. yet?

Currently I'm still on 6.x and I'm switching my Javascript Frontend to use MSAL v.2which sends the access token in the authorization bearer to my API calls, which unfortunately gives ma an unauthorized. Yet I would still like to keep the OAuth2 Proxy to protect my API and other endpoints.

Thanks

@JoelSpeed
Copy link
Member

If you are willing to use the alpha configuration that is largely undocumented, and potentially going to change in the future. Then yes you can do this, you'll need to do something like

injectRequestHeaders:
- name: Authorization
  values:
  - claim: access_token
    prefix: "Bearer"

@antibios
Copy link

When using keycloak we really need to get back more detail or the token otherwise we have to reimplement all this logic back into every service.

For example, when we're running traefik and oauth2-proxy I get back the following
X-Forwarded-User: user@example.org

But that doesn't give the microservice enough information to process the request, sure I've got a authenticated user, but does that user have group access or role access?

We really need oauth2-proxy adding enough information to the request for the microservice to make access decisions. I'd suggest at a minimum we'd need the following:

X-Auth-Email: andrei.kvapil@example.org
X-Auth-Expiresin: 2020-10-26 22:05:17 +0000 UTC
X-Auth-Groups: < My user groups here>
X-Auth-Roles: offline_access,uma_authorization,account:manage-account,account:manage-account-links,account:view-profile
X-Auth-Subject: 337a5e4b-ecce-4ef6-b28e-d89220ec0830
X-Auth-Token:  < Bearer token here >

@InfoSec812
Copy link

If you are willing to use the alpha configuration that is largely undocumented, and potentially going to change in the future. Then yes you can do this, you'll need to do something like

injectRequestHeaders:
- name: Authorization
  values:
  - claim: access_token
    prefix: "Bearer"

OMG! This is AMAZING!! It's exactly what I have always wanted out of oauth2-proxy!! THANK YOU SO MUCH! It works SO well in my environment!

@karatkep
Copy link

Hi All,
After almost 1 year, is there any reliable and simple way to pass access token to upstream via Authorization header?

@JoelSpeed
Copy link
Member

As per previous comments, if you want to do this, use the alpha config as others have

@siddharth201983
Copy link

Hi @InfoSec812 @JoelSpeed, I am trying to authenticate the request(istio-bookinfo demo productpage) using Keycloak.
Here is the oauth2-proxy config I am using with alpha config --


kubeVersion:
# Oauth client configuration specifics
config:
  clientID: "myclient"
  clientSecret: "g4KoGIPPQr8Q6NnXmZQsylOBKaHsfSe6"
  cookieSecret: "Mpbb4N8EpvVFeryFFfnXLuCKRsaKlOHutUEJWFGdpjI="
  provider: "keycloak-oidc"

  configFile: |-
      email_domains = ["*"]

alphaConfig:
  enabled: true
  providers:
  - provider: oidc
    clientID: myclient
    clientSecret: g4KoGIPPQr8Q6NnXmZQsylOBKaHsfSe6
    loginURL: http://<keycloak-url>:8080/realms/myrealm/protocol/openid-connect/auth
    redeemURL: http://<keycloak-url>:8080/realms/myrealm/protocol/openid-connect/token
    profileURL: http://<keycloak-url>:8080/realms/myrealm/protocol/openid-connect/userinfo
    validateURL: http://<keycloak-url>:8080/realms/myrealm/protocol/openid-connect/userinfo
  scope: "openid email profile groups istio"
  allowedGroups:
  - admins # List all groups managed at our your IdP which should be allowed access
  # - infrateam
  # - anothergroup
  oidcConfig:
    emailClaim: email.  # Name of the clain in JWT containing the E-Mail
    groupsClaim: groups # Name of the claim in JWT containing the Groups
    userIDClaim: email  # Name of the claim in JWT containing the User ID
    skipDiscovery: true # You can try using the well-knwon endpoint directly for auto discovery, here we won't use it
    oidcissuerURL: http://<keycloak-url>:8080/realms/myrealm
    jwksURL: http://<keycloak-url>:8080/realms/myrealm/protocol/openid-connect/certs
  upstreamConfig:
    upstreams:
      - id: static_200
        path: /
        static: true
        staticCode: 200
  # Headers that should be added to responses from the proxy
  injectResponseHeaders: # Send this headers in responses from oauth2-proxy
    - name: X-Auth-Request-Preferred-Username
      values:
        - claim: preferred_username
    - name: X-Auth-Request-Email
      values:
        - claim: email

image:
  repository: "quay.io/oauth2-proxy/oauth2-proxy"
  # appVersion is used by default
  tag: "v7.4.0"
  pullPolicy: "IfNotPresent"

extraArgs:
  cookie-secure: "false"
  cookie-domain: "*"    # Replace with your base domain
  cookie-samesite: lax
  cookie-expire: 12h               # How long our Cookie is valid
  auth-logging: true               # Enable / Disable auth logs
  request-logging: true            # Enable / Disable request logs
  standard-logging: true           # Enable / Disable the standart logs
  show-debug-on-error: true        # Disable in production setups
  skip-provider-button: true       # We only have one provider configured (Keycloak)
  silence-ping-logging: true       # Keeps our logs clean
  whitelist-domain: "*" # Replace with your base domain
extraEnv: []

# -- Custom labels to add into metadata
customLabels: {}

# To authorize individual email addresses
# That is part of extraArgs but since this needs special treatment we need to do a separate section
authenticatedEmailsFile:
  enabled: false
  # Defines how the email addresses file will be projected, via a configmap or secret
  persistence: configmap
  # template is the name of the configmap what contains the email user list but has been configured without this chart.
  # It's a simpler way to maintain only one configmap (user list) instead changing it for each oauth2-proxy service.
  # Be aware the value name in the extern config map in data needs to be named to "restricted_user_access" or to the
  # provided value in restrictedUserAccessKey field.
  template: ""
  # The configmap/secret key under which the list of email access is stored
  # Defaults to "restricted_user_access" if not filled-in, but can be overridden to allow flexibility
  restrictedUserAccessKey: ""
  # One email per line
  # example:
  # restricted_access: |-
  #   name1@domain
  #   name2@domain
  # If you override the config with restricted_access it will configure a user list within this chart what takes care of the
  # config map resource.
  restricted_access: ""
  annotations: {}
  # helm.sh/resource-policy: keep

service:
  type: NodePort
  # when service.type is ClusterIP ...
  # clusterIP: 192.0.2.20
  # when service.type is LoadBalancer ...
  # loadBalancerIP: 198.51.100.40
  # loadBalancerSourceRanges: 203.0.113.0/24
  # when service.type is NodePort ...
  # nodePort: 80
  portNumber: 4180
  # Protocol set on the service
  appProtocol: http
  annotations: {}
  # foo.io/bar: "true"

## Create or use ServiceAccount
serviceAccount:
  ## Specifies whether a ServiceAccount should be created
  enabled: true
  ## The name of the ServiceAccount to use.
  ## If not set and create is true, a name is generated using the fullname template
  name:
  automountServiceAccountToken: true
  annotations: {}

ingress:
  enabled: false
  # className: nginx
  path: /
  # Only used if API capabilities (networking.k8s.io/v1) allow it
  pathType: ImplementationSpecific
  # Used to create an Ingress record.
  # hosts:
    # - chart-example.local
  # Extra paths to prepend to every host configuration. This is useful when working with annotation based services.
  # Warning! The configuration is dependant on your current k8s API version capabilities (networking.k8s.io/v1)
  # extraPaths:
  # - path: /*
  #   pathType: ImplementationSpecific
  #   backend:
  #     service:
  #       name: ssl-redirect
  #       port:
  #         name: use-annotation
  # annotations:
  #   kubernetes.io/ingress.class: nginx
  #   kubernetes.io/tls-acme: "true"
  # tls:
    # Secrets must be manually created in the namespace.
    # - secretName: chart-example-tls
    #   hosts:
    #     - chart-example.local

resources: {}
  # limits:
  #   cpu: 100m
  #   memory: 300Mi
  # requests:
  #   cpu: 100m
  #   memory: 300Mi

extraVolumes: []
  # - name: ca-bundle-cert
  #   secret:
  #     secretName: <secret-name>

extraVolumeMounts: []
  # - mountPath: /etc/ssl/certs/
  #   name: ca-bundle-cert

priorityClassName: ""

# Host aliases, useful when working "on premise" where (public) DNS resolver does not know about my hosts.
hostAlias:
  enabled: false
  # ip: "10.xxx.xxx.xxx"
  # hostname: "auth.example.com"

# [TopologySpreadConstraints](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) configuration.
# Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
# topologySpreadConstraints: []

# Affinity for pod assignment
# Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
# affinity: {}

# Tolerations for pod assignment
# Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
tolerations: []

# Node labels for pod assignment
# Ref: https://kubernetes.io/docs/user-guide/node-selection/
nodeSelector: {}

# Whether to use secrets instead of environment values for setting up OAUTH2_PROXY variables
proxyVarsAsSecrets: true

# Configure Kubernetes liveness and readiness probes.
# Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
# Disable both when deploying with Istio 1.0 mTLS. https://istio.io/help/faq/security/#k8s-health-checks
livenessProbe:
  enabled: true
  initialDelaySeconds: 0
  timeoutSeconds: 1

readinessProbe:
  enabled: true
  initialDelaySeconds: 0
  timeoutSeconds: 5
  periodSeconds: 10
  successThreshold: 1

# Configure Kubernetes security context for container
# Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
securityContext:
  enabled: false
  runAsNonRoot: true
  # allowPrivilegeEscalation: false
  # runAsUser: 2000

deploymentAnnotations: {}
podAnnotations: {}
podLabels: {}
replicaCount: 1

## PodDisruptionBudget settings
## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
podDisruptionBudget:
  enabled: true
  minAvailable: 1

# Configure Kubernetes security context for pod
# Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
podSecurityContext: {}

# whether to use http or https
httpScheme: http

# Additionally authenticate against a htpasswd file. Entries must be created with "htpasswd -B" for bcrypt encryption.
# Alternatively supply an existing secret which contains the required information.
htpasswdFile:
  enabled: false
  existingSecret: ""
  entries: {}
  # One row for each user
  # example:
  # entries:
  #  - testuser:$2y$05$gY6dgXqjuzFhwdhsiFe7seM9q9Tile4Y3E.CBpAZJffkeiLaC21Gy

# Configure the session storage type, between cookie and redis
sessionStorage:
  # Can be one of the supported session storage cookie|redis
  type: cookie
  redis:
    # Name of the Kubernetes secret containing the redis & redis sentinel password values (see also `sessionStorage.redis.passwordKey`)
    existingSecret: ""
    # Redis password value. Applicable for all Redis configurations. Taken from redis subchart secret if not set. `sessionStorage.redis.existingSecret` takes precedence
    password: ""
    # Key of the Kubernetes secret data containing the redis password value
    passwordKey: "redis-password"
    # Can be one of standalone|cluster|sentinel
    clientType: "standalone"
    standalone:
      # URL of redis standalone server for redis session storage (e.g. `redis://HOST[:PORT]`). Automatically generated if not set
      connectionUrl: ""
    cluster:
      # List of Redis cluster connection URLs (e.g. `["redis://127.0.0.1:8000", "redis://127.0.0.1:8000"]`)
      connectionUrls: []
    sentinel:
      # Name of the Kubernetes secret containing the redis sentinel password value (see also `sessionStorage.redis.sentinel.passwordKey`). Default: `sessionStorage.redis.existingSecret`
      existingSecret: ""
      # Redis sentinel password. Used only for sentinel connection; any redis node passwords need to use `sessionStorage.redis.password`
      password: ""
      # Key of the Kubernetes secret data containing the redis sentinel password value
      passwordKey: "redis-sentinel-password"
      # Redis sentinel master name
      masterName: ""
      # List of Redis sentinel connection URLs (e.g. `["redis://127.0.0.1:8000", "redis://127.0.0.1:8000"]`)
      connectionUrls: []

# Enables and configure the automatic deployment of the redis subchart
redis:
  # provision an instance of the redis sub-chart
  enabled: false
  # Redis specific helm chart settings, please see:
  # https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters
  # redisPort: 6379
  # cluster:
  #   enabled: false
  #   slaveCount: 1

# Enables apiVersion deprecation checks
checkDeprecation: true

metrics:
  # Enable Prometheus metrics endpoint
  enabled: true
  # Serve Prometheus metrics on this port
  port: 44180
  # when service.type is NodePort ...
  # nodePort: 44180
  # Protocol set on the service for the metrics port
  service:
    appProtocol: http
  servicemonitor:
    # Enable Prometheus Operator ServiceMonitor
    enabled: false
    # Define the namespace where to deploy the ServiceMonitor resource
    namespace: ""
    # Prometheus Instance definition
    prometheusInstance: default
    # Prometheus scrape interval
    interval: 60s
    # Prometheus scrape timeout
    scrapeTimeout: 30s
    # Add custom labels to the ServiceMonitor resource
    labels: {}

# Extra K8s manifests to deploy
extraObjects: []
  # - apiVersion: secrets-store.csi.x-k8s.io/v1
  #   kind: SecretProviderClass
  #   metadata:
  #     name: oauth2-proxy-secrets-store
  #   spec:
  #     provider: aws
  #     parameters:
  #       objects: |
  #         - objectName: "oauth2-proxy"
  #           objectType: "secretsmanager"
  #           jmesPath:
  #               - path: "client_id"
  #                 objectAlias: "client-id"
  #               - path: "client_secret"
  #                 objectAlias: "client-secret"
  #               - path: "cookie_secret"
  #                 objectAlias: "cookie-secret"
  #     secretObjects:
  #     - data:
  #       - key: client-id
  #         objectName: client-id
  #         - key: client-secret
  #           objectName: client-secret
  #         - key: cookie-secret
  #         objectName: cookie-secret
  #       secretName: oauth2-proxy-secrets-store
  #       type: Opaque

but the POD is not coming UP and throwing error --

$ k logs oauth2-proxy-6d99fb74dc-nk9kg
[2023/03/06 04:50:08] [main.go:75] WARNING: You are using alpha configuration. The structure in this configuration file may change without notice. You MUST remove conflicting options from your existing configuration.
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation.Validate(0xc000189400)
        /go/src/github.com/oauth2-proxy/oauth2-proxy/pkg/validation/options.go:39 +0x13cf
main.main()
        /go/src/github.com/oauth2-proxy/oauth2-proxy/main.go:53 +0x35a

Any help is highly appreciated.

@InfoSec812
Copy link

2 issues which I noticed.

  1. You do not need to specify all of the OIDC urls for Keycloak. This is what I use:
providers:
- clientID: consultant360
  clientSecret: 7463e6ad-5e03-4855-877f-360cdc1ef9d6
  id: consultant360
  oidcConfig:
    emailClaim: email
    groupsClaim: groups
    insecureAllowUnverifiedEmail: true
    insecureSkipNonce: true
    userIDClaim: email
    issuerURL: http://keycloak:8080/auth/realms/consultant360
    audienceClaims: 
      - aud
  provider: oidc
  1. Istio/Envoy is going to be expecting the Authorization: Bearer <token> header and should be explicitly configured via the injectResponseHeaders:
  injectResponseHeaders: # Send this headers in responses from oauth2-proxy
    - name: X-Auth-Request-Preferred-Username
      values:
        - claim: preferred_username
    - name: X-Auth-Request-Email
      values:
        - claim: email
    - name: Authorization
      values:
        - claim: access_token
          prefix: "Bearer "

@siddharth201983
Copy link

siddharth201983 commented Mar 7, 2023

Hey @InfoSec812 , thanks for the quick reply. I applied the config you suggested. --

kubeVersion:
# Oauth client configuration specifics
config:
  clientID: myclient
  clientSecret: g4KoGIPPQr8Q6NnXmZQsylOBKaHsfSe6
  cookieSecret: Mpbb4N8EpvVFeryFFfnXLuCKRsaKlOHutUEJWFGdpjI=
  provider: oidc

  configFile: |-
      email_domains = ["*"]

alphaConfig:
  enabled: true
  providers:
  - provider: oidc
    clientID: myclient
    id: myclient
    clientSecret: g4KoGIPPQr8Q6NnXmZQsylOBKaHsfSe6
  oidcConfig:
    emailClaim: email
    groupsClaim: groups
    userIDClaim: email
    issuerURL: http://<keycloak-url>:8080/realms/myrealm
  upstreamConfig:
    upstreams:
      - id: static_200
        path: /
        static: true
        staticCode: 200
  injectResponseHeaders:
    - name: X-Auth-Request-Preferred-Username
      values:
        - claim: preferred_username
    - name: X-Auth-Request-Email
      values:
        - claim: email
    - name: Authorization
      values:
        - claim: access_token
          prefix: "Bearer"

image:
  repository: "quay.io/oauth2-proxy/oauth2-proxy"
  # appVersion is used by default
  tag: "v7.4.0"
  pullPolicy: "IfNotPresent"

extraArgs:
  cookie-secure: "false"
  cookie-domain: "*"    # Replace with your base domain
  cookie-samesite: lax
  cookie-expire: 12h               # How long our Cookie is valid
  auth-logging: true               # Enable / Disable auth logs
  request-logging: true            # Enable / Disable request logs
  standard-logging: true           # Enable / Disable the standart logs
  show-debug-on-error: true        # Disable in production setups
  skip-provider-button: true       # We only have one provider configured (Keycloak)
  silence-ping-logging: true       # Keeps our logs clean
  whitelist-domain: "*" # Replace with your base domain
extraEnv: []

But I dont know why I am still getting the same Index [0] error --

[2023/03/07 03:08:11] [main.go:75] WARNING: You are using alpha configuration. The structure in this configuration file may change without notice. You MUST remove conflicting options from your existing configuration.
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation.Validate(0xc0000fc000)
        /go/src/github.com/oauth2-proxy/oauth2-proxy/pkg/validation/options.go:39 +0x13cf
main.main()
        /go/src/github.com/oauth2-proxy/oauth2-proxy/main.go:53 +0x35a

As I checked the validation code, I guess this is related to Provider config but I am unable to figure out the missing/incorrect config here :(

@jdbranham
Copy link

I had the same error @siddharth201983
The helm chart is looking for different structure -
https://github.com/oauth2-proxy/manifests/blob/main/helm/oauth2-proxy/templates/secret-alpha.yaml#L33

It should be like this I think -

alphaConfig:
  enabled: true
  configData:
    providers: ... 
    oidcConfig: ...

@hvoss
Copy link

hvoss commented Dec 18, 2023

If you are willing to use the alpha configuration that is largely undocumented, and potentially going to change in the future. Then yes you can do this, you'll need to do something like

injectRequestHeaders:
- name: Authorization
  values:
  - claim: access_token
    prefix: "Bearer"

I had to add a whitespace after Bearer:

injectRequestHeaders:
- name: Authorization
  values:
  - claim: access_token
    prefix: "Bearer "

Took me while to find it. Maybe some helps that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.