oauth2-proxy와 keycloak 연동해보기 ( ingress nginx 사용 )

2025. 2. 25. 00:44Devops/Opensource

728x90
반응형

opensource를 이용하다보면 로그인 Page가 없는경우가 있다. 그런경우는 추가 개발을 해주던가 해야하는데 이런부분을 쉽게 리버스프록시를 사용하여 해 줄 수 있는 opensource가 있는데 그게 바로 oauth2-proxy이다 또한 keycloak을 연동하면 로그인페이지를 사용하여 페이지 이동전에 로그인을하여 이동할 수 있다. 물론.. 단점은 로그아웃이 없다는 점이다..(URL을 수동으로 넣으면 로그아웃은 가능!) 아키텍쳐는 이렇다.

oauth2-proxy 이미지

 

우리는 이번에 인증 middleware로 사용하기 위해 ingress nginx을 사용하여 oauth-proxy와 keycloak 사용해보고자한다

그리고 keycloak은 20버전 위, oauth2-proxy는 7버전 위를 사용하는것을 추천한다.

  • keycloak version : 23.0.6
  • oauth2-proxy : 7.8.1

이 글은 Keycloak이 설치되어있음을 가정하에 진행합니다.. 그리고 oauth2-proxy는 helm chart로 설치하며, 순서는 keycloak에 client를 생성 후 oauth2-proxy를 설치 후 application ingress에 auth annotation 삽입과 노출 순서로 진행됩니다.

 

1. Keycloak 설정

먼저 keycloak에서는 client를 설정해줘야합니다. 저는 oauth2-proxy라는 이름의 client를 생성했습니다.

 

clientName은 oauth2-proxy

 

client Secret은 꼭 필수!!

이후 사용하고자하는 URL주소의 callback주소를 입력해줘야합니다.

예를 들어 접속하고자하는 주소가 swlee.test.com 이라면 http://swlee.test.com/oauth2/callback 을 넣어줘야합니다. 

그리고 추가도 가능합니다. 저는 아래와 로그인 페이지 없는 URL을 넣었습니다.

 

 

그리고 client를 위한 전용 audience mapper를 구성해줘야 합니다. 할당된 클라이언트 범위에 있는 'oauth2-proxy-dedicated'를 클릭하여 전용 Mapper창에 들어가서 추가를 해줍니다.

추가적으로 권한 관리를 위해 User Mapper나 Group Mapper를 추가해도 됩니다

 

 

  • Name은 aud라고 명시했습니다. 
  • Included Client Audience는 oauth2-proxy를 선택해줍니다
  • Included Custom Audience는 입력을 해도되고 안해도되지만 aud로 추가줍니다.
  • Add to ID Token, Add to access Token, Add to instrospection은 로그인 후 어플리케이션에도 JWT 토큰을 upstream 해야하기에 On으로 해줍니다.

 

설정이 완료되면 이후에는 oauth2-proxy에 해당 client와 clientSecret을 사용하여 oauth2-proxy를 구성합니다.

 

 

 

2. Oauth2-proxy 설치

설치는 helm chart로 설치하며 value.yaml은 custom으로 구성해서 설치합니다. 저는 prometheus 대시보드를 인증후 들어가도록 하기위해 promeheus와 연동하여 진행했습니다.

  • helm add repository & update

먼저 helm repo를 등록해주고 update를 진행합니다.

$ helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
$ helm repo update

 

  • Create Namespace
$ k create ns oauth2-proxy
namespace/oauth2-proxy created

 

  • oauth2-proxy의 value.yaml 다운로드
$ wget https://raw.githubusercontent.com/oauth2-proxy/manifests/refs/heads/main/helm/oauth2-proxy/values.yaml
$ ls
value.yaml

 

  • value.yaml 수정

수정은 config와 ingress 쪽만 수정해줍니다.

ingress의 주소는 내가 로그인 페이지를 띄울 주소를 넣어줘야합니다.

config:
  # Add config annotations
  annotations: {}
  # OAuth client ID
  # Follow instructions to configure Keycloak client
  # https://oauth2-proxy.github.io/oauth2-proxy/configuration/providers/keycloak_oidc

  # Oauth2 client configuration. From Keycloak configuration
  clientID: "oauth2-proxy"
  clientSecret: "keycloak에서 만든 clientSecret을 입력해주세요"
    
  # Cookie secret
  # Create a new secret with the following command
  # openssl rand -base64 32 | head -c 32 | base64
  cookieSecret: "bG5pRDBvL0VaWis3dksrZ05vYnJLclRFb2VNcVZJYkg="
  # The name of the cookie that oauth2-proxy will create
  # If left empty, it will default to the release name
  cookieName: "oauth2-proxy"

  # Config file
  configFile: |-
    # Provider config
    provider="keycloak-oidc"
    provider_display_name="Keycloak"
    redirect_url="http://prometheus.test.com/oauth2/callback"
    oidc_issuer_url="http://keycloak.test.com/realms/master"
    code_challenge_method="S256"
    ssl_insecure_skip_verify=true
    # Upstream config
    http_address="0.0.0.0:4180"
    upstreams="file:///dev/null"
    email_domains=["*"]
    cookie_domains=["test.com"]
    cookie_secure=false
    scope="openid"
    whitelist_domains=[".test.com"]
    insecure_oidc_allow_unverified_email="true"

ingress:
  enabled: true
  className: "nginx"
  pathType: Prefix
  path: /oauth2
  annotations:
    # Enable cert-manager to create automatically the SSL certificate and store in Secret
    # Possible Cluster-Issuer values:
    #   * 'letsencrypt-issuer' (valid TLS certificate using IONOS API)
    #   * 'ca-issuer' (CA-signed certificate, not valid)
    nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
  hosts:
    - prometheus.test.com

 

여기서 email_domains=["*] 이부분과 insecure_oidc_allow_unverified_email="true" 은 꼭 넣어주셔야합니다...( 안넣으면 Email 확인 해달라는 에러가 나옴 해당부분은 아래에 에러 부분에 나옵니다...)

 

  • Install helm chart 

 설정이 완료되었다면 oauth2-proxy를 설치해줍니다. 내가 노출하고자하는 application과 같은 namespace에 배포를 해주는게 좋습니다.. svc를 공유하기때문에 만약에 같은 namespace가아니라면 해당 oauth2-proxy service를 externalName으로 지정해야 공유가 됩니다.

$ helm install oauth2-proxy oauth2-proxy/oauth2-proxy -f values.yaml --namespace oauth2-proxy

 

  • application을 노출하기

프로메테우스를 노출시키려고 했었기에.. kube-prometheus을 설치하고 dashboard를 노출시킬려면 ingress를 수정해야한다. 수정시 annotation에만 해당 내용만 넣어주면 된다.

아래의 3가지를 넣어주고 저장하면 된다.

nginx.ingress.kubernetes.io/auth-response-headers: Authorization
nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri
nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth

 

완성된 yaml은 아래와 같다..

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-response-headers: Authorization
    nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri
    nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth
  creationTimestamp: "2024-12-27T00:12:19Z"
  generation: 4
  labels:
    app: kube-prometheus-stack-prometheus
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/part-of: kube-prometheus-stack
    app.kubernetes.io/version: 59.0.0
    chart: kube-prometheus-stack-59.0.0
    heritage: Helm
  name: kube-prometheus-stack-prometheus
  namespace: oauth2-proxy
spec:
  ingressClassName: nginx
  rules:
  - host: prometheus.test.com
    http:
      paths:
      - backend:
          service:
            name: kube-prometheus-stack-prometheus
            port:
              number: 9090
        path: /
        pathType: ImplementationSpecific

 

 

 

2-1. oauth2-proxy 구성중 에러 해결 

  • Error redeeming code during OAuth2 callback: email in id_token (admin@admin.com) isn't verified

 

접속시 500 Error를 내뱉는경우가 있다.. 해당부분이 무슨에러인지 해서 oauth2-proxy 로그를 보니

 Error redeeming code during OAuth2 callback: email in id_token (admin@admin.com) isn't verified 이러한 에러다 한마디로 email 인증이 안되어서 생긴문제라는 것이다... 

고생좀 함...

이부분은  email_domains=["*] 이부분과 insecure_oidc_allow_unverified_email="true" 을 안넣어서 생긴문제이기에 꼭 넣고 다시 배포해줍니다.

 

  • 무한 Redirect ,504 Gateway, 403 Forbided 등등...

처음에는 application 에 /oauth2인증에 대한 부분을 같이 넣어서 진행했다. 근데 문제가 계속 해결이 안되었다 ㅠㅠ..그리고 엄청찾아봤다.oauth2-proxy redirect , oauth2-proxy 403 forbid 등등 검색해서.. 찾아봐도 결과는 잘나오지 않았다. 그리고 chatgpt도 잘 알려주지 않았다.. 

그러다보니 여러가지를 해결해보고자 ingress를 고치고 수정하고 하다보니 504도나오고 무한 리다이렉트도 나오고 403도 나오고 정말 힘들었음.. 근데 그 이유는 아래의  yaml에 있었다. (결국 내잘못..)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-response-headers: Authorization
    nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri
    nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth
  creationTimestamp: "2024-12-27T00:12:19Z"
  generation: 4
  labels:
    app: kube-prometheus-stack-prometheus
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/part-of: kube-prometheus-stack
    app.kubernetes.io/version: 59.0.0
    chart: kube-prometheus-stack-59.0.0
    heritage: Helm
  name: kube-prometheus-stack-prometheus
  namespace: oauth2-proxy
spec:
  ingressClassName: nginx
  rules:
  - host: prometheus.test.com
    http:
      paths:
      - backend:
          service:
            name: oauth2-proxy
            port:
              number: 80
        path: /oauth2
        pathType: Prefix
      - backend:
          service:
            name: kube-prometheus-stack-prometheus
            port:
              number: 9090
        path: /
        pathType: ImplementationSpecific

 

ingress 호스트 prometheus.test.com 안에 nginx auth에대한 annotaion을 사용한다면 prometheus.test.com 에 대한 ingress를 하나 더 만들어줘야한다.. 그래서 oauth2-proxy 를 배포하기 위해 설정한 ingress을 꼭 만들어야 한다는것이다..

만들게되면  prometheus.test.com 의 배포된 ingress는 꼭 2개가 되어야한다는  점이다.. (1개는 auth인증을 위한 app yaml 1개는 oauth2-proxy )이다. 그래서분기가 되면 아래와 같이 나오는 것이다.

 

  • prometheus-ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-response-headers: Authorization
    nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri
    nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth
  creationTimestamp: "2024-12-27T00:12:19Z"
  generation: 4
  labels:
    app: kube-prometheus-stack-prometheus
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/part-of: kube-prometheus-stack
    app.kubernetes.io/version: 59.0.0
    chart: kube-prometheus-stack-59.0.0
    heritage: Helm
  name: kube-prometheus-stack-prometheus
  namespace: oauth2-proxy
spec:
  ingressClassName: nginx
  rules:
  - host: prometheus.test.com
    http:
      paths:
      - backend:
          service:
            name: kube-prometheus-stack-prometheus
            port:
              number: 9090
        path: /
        pathType: ImplementationSpecific

 

  • oauth2-proxy ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    meta.helm.sh/release-name: oauth2-proxy
    meta.helm.sh/release-namespace:oauth2-proxy
    nginx.ingress.kubernetes.io/proxy-buffer-size: 16k
  creationTimestamp: "2025-02-25T06:10:02Z"
  generation: 1
  labels:
    app: oauth2-proxy
    app.kubernetes.io/component: authentication-proxy
    app.kubernetes.io/instance: oauth2-proxy
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: oauth2-proxy
    app.kubernetes.io/part-of: oauth2-proxy
    app.kubernetes.io/version: 7.8.1
    helm.sh/chart: oauth2-proxy-7.11.1
  name: oauth2-proxy
  namespace: oauth2-proxy
  resourceVersion: "634840087"
  uid: f2343b5a-7512-49c2-a454-80b130e31169
spec:
  ingressClassName: nginx
  rules:
  - host: prometheus.test.com
    http:
      paths:
      - backend:
          service:
            name: oauth2-proxy
            port:
              number: 80
        path: /oauth2
        pathType: Prefix

 

 

3. 결과

prometheus.test.com을 접속하게되면 아래와 같은 redirect 즉 keycloak 로그인 페이지가 뜹니다. 로그인하게되면...

 

로그인완료..

로그인하게 되면 한번 개발자 도구를 봐보자..

 

 

Cookie에 oauth2-proxy가 들어간것을 알수있다... 

 

4. 정리

원래는 istio를 통해 oauth2-proxy를 연동했었었다. 그때는 쉽게 쉽게 했는데 nginx는 생각보다 연동이 잘안되어서 애를 좀 먹었다. 이유는 뭐.. 흐름을 이해 못해서였을지도 모르지만.. 결론은 잘되서 기분좋았다

아직 문제를 다 해결한건 아니지만 (로그아웃도 문제고 cookie에 대한부분) 추후에 시간이 있다면 관련글을 또 올려야겠습니다. 그리고 session도 redis에 넣어서 관리가 가능하던데.. 근데 keycloak을 사용하면 infinitspan 으로 session을 관리하기에 안해도 되지않을까한다.. 

현재 istio도 글을 올리고있으니 다음은 istio와 연동하는 방법이나 올려야겠다..

728x90
반응형