NGINX Ingress Controller Keycloak 활용 API 인증 구현 가이드

이 포스트는 NGINX Ingress Controller 와 Keycloak 을 활용하여 API 인증을 구현하는 방법에 관해 다룹니다. NGINX Ingress Controller와 Keycloak은 OIDC 인증을 통해 발급되는 ID 토큰을 통해 API 인증을 구현하며, NGINX Ingress Controller의 OIDC 인증 기능은 NGINX Ingress Controller의 상업 구독 버전인 NGINX Plus Ingress Controller 전용 기능입니다.

Kubernetes 클러스터에 Keycloak과 데이터 저장에 필요한 DB를 구성하고, NGINX Ingress Controller의 OIDC 인증을 활용하여 백엔드 애플리케이션 연결에 Keycloak을 사용한 인증 과정을 추가하도록 구성하겠습니다.

전체 과정은 NGINX Ingress Controller가 사전 배포된 Kuberenetes 클러스터 환경에서 진행합니다.

목차

1. Keycloak이란?
 1-1. Keycloak과 NGINX Ingress Controller의 인증 흐름

2. 버전 정보
3. Keycloak 구성
 3-1. PostgreSQL 구성
 3-2. Keycloak 구성
4. NGINX Ingress Controller Keycloak 연동
 4-1. NGINX Ingress Controller Keycloak 연동 전 사전 구성
 4-2. NGINX Ingress Controller Keycloak 연동 구성 – Keycloak
 4-3. NGINX Ingress Controller Keycloak 연동 구성 – NGINX Ingress Controller
5. NGINX Ingress Controller Keycloak API 인증 확인
6. 결론

1. Keycloack이란?

Keycloak은 오픈소스 인증 및 권한 관리 솔루션으로, 애플리케이션에서 사용자 인증 및 SSO(Single Sign-On)를 구현할 수 있는 소프트웨어입니다.

Keyclaok은 OAuth 2.0, OpenID Connect, SAML과 같은 다양한 인증 프로토콜을 지원하고 사용자 관리, MFA(다중 인증), 권한 및 역할 관리, 토큰 서비스 생성과 같은 기능을 제공합니다. 또한 LDAP 및 Google, Facebook, GitHub 등 소셜 로그인 연동 기능도 제공합니다.

NGINX Ingress Controller와 Keycloak을 연동하면 클러스터 내 여러 서비스에 대해 단일화된 인증을 구현할 수 있습니다. 하나의 인증 서버(Keycloak)에서 인증을 처리하고, NGINX Ingress Controller를 통해 연결되는 다양한 서비스에 대한 인증을 통합하여, 인증 프로세스를 중앙에서 관리하고, 안전하고 효율적인 인증 시스템을 구축할 수 있습니다.

1-1. Keycloak과 NGINX Ingress Controller의 인증 흐름

https://github.com/nginxinc/nginx-openid-connect

사진과 같이 NGINX Ingress Controller는 OIDC의 Authorization Code Flow를 사용하여 Keycloak과 연동해 인증을 수행합니다. Keycloak을 통해 발급되는 ID 토큰은 사용자 인증에 활용됩니다.

Authorization Code는 한 번만 사용되며, 이를 통해 탈취 위험을 최소화할 수 있습니다. 또한, ID 토큰은 브라우저를 거치지 않고 NGINX Ingress Controller와 Keycloak 서버 간에 직접 교환되어 보안이 강화됩니다

2. 버전 정보

  • Kubernetes: v1.30.3
  • NGINX Plus Ingress Controller: 4.0.0
  • Keycloak: 26.1.0
  • PostgreSQL: 17.2

3. Keycloak 구성

Keycloak을 구성하기 전에, Keycloak에 저장되는 사용자 정보, 클라이언트(애플리케이션) 설정, 역할 및 정책 등 데이터를 영구적으로 저장하기 위해 DB를 클러스터에 배포하고, 해당 DB에 데이터를 저장하도록 Keycloak을 구성하겠습니다.

이 포스트에서는 PostgreSQL을 사용해 DB를 구성했으며, Keycloak이 지원하는 다른 DB와 관련 구성 방법은 Keycloak DB문서를 참고하세요.

포스트의 구성에 사용한 yaml 파일은 NGINX STORE GitHub에서 확인하실 수 있습니다.

3-1. PostgreSQL 구성

Keycloack의 데이터를 저장할 PostgreSQL DB를 keycloak 네임스페이스에 구성합니다.
PostgreSQL DB의 데이터를 저장하기 위한 PersistentVolume을 생성하고 StatefulSet, Headless Service를 통해 배포하도록 하겠습니다.

프로덕션 환경을 위한 DB의 확장, 고가용성 구성이 필요하다면 postgresql-ha Helm 차트를 통해 배포하는 것을 권장합니다.

postgres-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: postgres-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  local:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker            # 노드 이름
  storageClassName: postgres  # 임의의 이름 지정

PV 구성은 예시를 위해 간단하게 워커 노드의 hostPath를 활용했습니다.
spec.storageClassName의 값은 StatefulSet에서 구성할 값과 동일해야합니다.

$ kubectl apply -f postgres-pv.yaml

persistentvolume/postgres-pv created

$ kubectl get pv postgres-pv

NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
postgres-pv   1Gi        RWO            Retain           Available           postgres       <unset>                          4s
postgres-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: postgres-secret
  namespace: keycloak
type: Opaque
stringData:
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: mysecretpassword
  POSTGRES_DB: keycloak

PostgreSQL DB 구성을 위한 민감한 환경 변수 정보를 Secret 리소스로 생성합니다.
사용자 이름, 비밀번호, DB 이름을 설정합니다.

$ kubectl apply -f postgres-secret.yaml

secret/postgres-secret created

$ kubectl get secret -n keycloak postgres-secret

NAME              TYPE     DATA   AGE
postgres-secret   Opaque   3      20s
postgres.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: keycloak
spec:
  serviceName: "postgres-svc-headless"  # PostgreSQL Pod와 연결될 Service 이름을 명시합니다
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - image: postgres:latest
        name: postgres
        envFrom:                        # 앞서 구성한 Secret을 통해 환경 변수를 설정합니다
          - secretRef:
              name: postgres-secret
        ports:
        - containerPort: 5432
          name: postgres
        securityContext:                # 컨테이너의 호스트 시스템의 커널 기능 접근 제한
          privileged: false
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:                               # 각 값은 PV의 값과 동일하게 구성
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: postgres        # PV에서 구성한 값과 동일하게 설정합니다
      resources:
        requests:
          storage: 1Gi

PostgreSQL Pod 구성을 위한 SatefulSet 구성입니다. DB의 경우 데이터의 지속성이 보장되어야 하며, 안정적인 네트워크 ID(Pod 이름)를 유지해야 하기 때문에 StatefulSet으로 구성합니다.
spec.serviceName을 통해 연결될 Service를 지정하며, spce.volumeClaimTemplates 설정에 따라 spec이 일치하는 PV와 연결됩니다.

$ kubectl apply -f postgres.yaml

statefulset.apps/postgres created

$ kubectl get pvc -n keycloak

NAME                          STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
postgres-storage-postgres-0   Bound    postgres-pv   1Gi        RWO            postgres       <unset>                 5s

$ kubectl get po -n keycloak

NAME         READY   STATUS    RESTARTS   AGE
postgres-0   1/1     Running   0          9s

StatefulSet을 배포 후 확인해 보면 volumeClaimTemplates 구성에 따라 PersistentVolumeClaim이 자동으로 생성되며, Pod의 이름은 StatefulSet 리소스의 이름 뒤에 숫자가 추가된 이름이 됩니다.

postgres-svc-hl.yaml
apiVersion: v1
kind: Service
metadata:
  name: postgres-svc-headless
  namespace: keycloak
spec:
  ports:
  - name: pgql
    port: 5432
    targetPort: 5432
    protocol: TCP
  selector:
    app: postgres
  clusterIP: None # Headless svc 구성을 위해 필요

Headless Service를 구성합니다. StatefulSet의 각 Pod가 개별 DNS 이름을 가질 수 있도록 설정하며, 로드 밸런싱 없이 클라이언트가 직접 특정 Pod에 연결할 수 있습니다.

$ kubectl apply -f postgres-svc-hl.yaml -n keycloak

service/postgres-svc-headless created

$ kubectl get svc postgres-svc-headless -n keycloak

NAME                    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
postgres-svc-headless   ClusterIP   None         <none>        5432/TCP   12s

$ kubectl get endpoints -n keycloak

NAME                    ENDPOINTS           AGE
postgres-svc-headless   10.244.4.111:5432   26s

Headless Service의 이름인 postgres-svc-headless(.<namespace>.svc.cluster.local)로 연결 시 StatefulSet의 Pod 목록 중 랜덤하게 하나로 연결되며, postgres-0.postgres-svc-headless와 같이 HeadlessService 이름 앞에 Pod의 이름을 추가하여 해당 Pod로 직접 연결할 수 있습니다.

3-2. Keycloak 구성

Keycloak Deployment를 배포하기 전에, 환경 변수를 통해 구성할 초기 admin 계정의 값을 Secret으로 설정합니다.

keycloak-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: keycloak-secrets
  namespace: keycloak
type: Opaque
stringData:
  KEYCLOAK_ADMIN: admin
  KEYCLOAK_ADMIN_PASSWORD: keypassword

Keycloak의 설정을 환경 변수로 구성하여 Deployment로 배포합니다. 강조된 항목은 실제 구성에 맞게 변경하세요.
Keycloak의 설정에 사용할 수 있는 모든 환경 변수는 Keycloak 설정 문서에서 확인하실 수 있습니다.

keycloak.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: keycloak
  labels:
    app: keycloak
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:26.1.0
          args: ["start-dev"]
          env:
            - name: KEYCLOAK_ADMIN                # 관리자 계정 정보 설정
              valueFrom:                        
                secretKeyRef:
                  name: keycloak-secrets          # 앞서 구성한 Secret 리소스 이름 지정
                  key: KEYCLOAK_ADMIN
            - name: KEYCLOAK_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: keycloak-secrets
                  key: KEYCLOAK_ADMIN_PASSWORD
            - name: KC_HEALTH_ENABLED             # Health check 엔드포인트 활성화
              value: "true"
            - name: KC_HOSTNAME                   # Keycloak 접속 도메인 설정
              value: "https://devopssong2.nginxstore.kr" # 이후 VirtualServer 구성에 사용
            - name: KC_PROXY_HEADERS              # 사용자 IP 확인을 위한 프록시 헤더 설정
              value: "xforwarded"   
            - name: KC_DB                         # DB 설정
              value: postgres
            - name: POSTGRES_DB
              valueFrom:
                secretKeyRef:
                  name: postgres-secret           # PostgreSL 구성에 사용한 Secret 이름 명시
                  key: POSTGRES_DB
            - name: KC_DB_URL                     # 구성한 Headless Service에 맞춰 명시
              value: jdbc:postgresql://postgres-0.postgres-svc-headless/$(POSTGRES_DB)
            - name: KC_DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: postgres-secret
                  key: POSTGRES_USER
            - name: KC_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-secret
                  key: POSTGRES_PASSWORD
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:                       # KC_HEALTH_ENABLED로 활성화된 엔드포인트를 통한 헬스 체크 설정
            httpGet:
              path: /health/ready
              port: 9000

KC_DB_URL 값은 구성한 StatefulSet, Headless Service에 맞춰서 설정하고, KC_HOSTNAME의 경우 NGINX Ingress Controller를 통해 Keycloak 서비스에 연결할 도메인으로 설정합니다. 이 예시에서는 devopssong2.nginxstore.kr을 사용했습니다.

Keycloak Service를 배포하고, NGINX Ingress Controller를 통한 HTTPS 연결을 위해 TLS 인증서를 Secret 리소스로 생성합니다.

keycloak-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: keycloak-svc
  namespace: keycloak
  labels:
    app: keycloak
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app: keycloak
  type: ClusterIP
$ kubectl create secret tls devopssong2-nginxstore --cert=cert-file.crt --key=key-file.crt

secret/devopssong2-nginxstore  created

devopssong2-nginxstore 이름으로 tls 타입의 Secret 리소스를 생성했습니다. cert, key 파일 및 리소스 이름은 구성 환경에 맞춰 변경해서 사용합니다.

NGINX Ingress Controller를 통해 연결하기 위해 VirtualServer 리소스를 배포합니다.

keycloak-vs.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: keycloak-vs
  namespace: keycloak
spec:
  host: devopssong2.nginxstore.kr   # 도메인 설정. Keycloak 환경 변수의 KC_HOSTNAME와 동일하게 설정
  tls:
    secret: devopssong2-nginxstore  # 앞서 구성한 Secret 이름 설정
    redirect:                       # HTTP 요청을 HTTPS로 리다이렉트
      enable: true 
  upstreams:
    - name: keycloak                # Keycloak Service 설정
      service: keycloak-svc
      port: 8080
  routes:
    - path: /
      action:
        pass: keycloak

구성한 도메인을 통해 웹 브라우저에서 접속할 수 있습니다.

NGINX Ingress Controller Keycloak - 로그인

keycloak-secrets에 설정한 ID/PW를 통해 최초 admin 계정으로 접속할 수 있습니다.

NGINX Ingress Controller Keycloak - admin 페이지 화면

Users 메뉴에서 새로운 사용자를 추가하여 admin 사용자로 설정할 수 있습니다.

NGINX Ingress Controller Keycloak - 사용자 추가
NGINX Ingress Controller Keycloak - 사용자 역할 추가

4. NGINX Ingress Controller Keycloak 연동 구성

NGINX Ingress Controller를 Keycloack과 연동하여 API 인증을 구현하기 전에, 인증을 통해 연결될 백엔드 Pod, Service 및 VirtualServer를 구성하고, NGINX Ingress Controller의 OIDC 인증 기능을 위해 필요한 설정을 알아보겠습니다.

4-1. NGINX Ingress Controller Keycloak 연동 전 사전 구성

백엔드 구성

app 네임스페이스에 백엔드 리소스를 구성했습니다. 간단하게 NGINX Pod와 연결될 Service를 배포합니다.

$ kubectl run nginx --image=nginx -n app

pod/nginx created

$ kubectl expose pod nginx --name=nginx-svc --port=80 -n app

service/nginx-svc exposed

$ kubectl get po,svc -n app

NAME        READY   STATUS    RESTARTS   AGE
pod/nginx   1/1     Running   0          58s

NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/nginx-svc   ClusterIP   10.96.170.87   <none>        80/TCP    23s

NGINX Ingress Controller를 통한 HTTPS 연결을 위해 Secret을 생성합니다.

$ kubectl create secret tls devopssong-nginxstore --cert=cert-file.crt --key=key-file.crt -n app

secret/devopssong-nginxstore  created

devopssong-nginxstore 이름으로 tls 타입의 Secret 리소스를 생성했습니다. cert, key 파일 및 리소스 이름은 구성 환경에 맞춰 변경해서 사용합니다.

VirtualServer 리소스를 생성하고 연결을 확인합니다.

nginx-vs.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: nginx-vs
  namespace: app
spec:
  host: devopssong.nginxstore.kr
  tls:
    secret: devopssong-nginxstore
  upstreams:
    - name: nginx
      service: nginx-svc
      port: 80
  routes:
    - path: /
      action:
        pass: nginx
NGINX Ingress Controller Keycloak - 백엔드 NGINX
NGINX Ingress Controller 구성

NGINX Ingress Controller의 OIDC 인증 기능을 사용하기 위해서는 Deployment 구성에서 활성화가 필요합니다.

......

        args:
          - -nginx-plus
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -mgmt-configmap=$(POD_NAMESPACE)/nginx-config-mgmt
          - -report-ingress-status
          - -external-service=nginx-ingress
          - -enable-oidc

OIDC 인증 기능은 NGINX의 상업 구독 버전인 NGINX Plus 전용 기능이며, NGINX의 OIDC 인증에 관한 자세한 내용은 nginx-openid-connect GitHub 리포지토리에서 확인하실 수 있습니다.

443 포트를 통한 HTTPS 통신을 위해 NGINX Ingress Controller의 Service를 LoadBalancer 타입으로 구성합니다.

$ kubectl get svc -n nginx-ingress

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
nginx-ingress-lb   LoadBalancer   10.104.142.51   175.196.***.***   80:32169/TCP,443:32643/TCP   25h

NGINX Ingress Controller의 kube-dns 설정을 ConfigMap으로 추가합니다.

nginx-config.yaml
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:
  resolver-addresses: kube-dns.kube-system.svc.cluster.local
  resolver-valid: 5s

4-2. NGINX Ingress Controller Keycloak 연동 구성 – Keycloak

앞서 admin 사용자로 접속한 Keycloak UI 좌측 상단의 박스를 클릭하여, Create realm 버튼을 통해 realm을 생성합니다. 이 포스트에서는 nginx 이름으로 생성했습니다.

realm은 Keycloak에서 사용자, 인증, 권한 등을 관리하는 독립적인 영역으로, 서로 다른 realm은 격리된 설정과 사용자가 적용됩니다.

NGINX Ingress Controller Keycloak - realm 생성
Client(애플리케이션) 구성

생성한 realm으로 변경하고, Clients 메뉴의 Create client 버튼을 클릭합니다.

NGINX Ingress Controller Keycloak - client 생성

Client(NGINX Ingress Controller)의 설정을 작성합니다. Client ID(nginx-ingress)의 경우 이후 생성할 Policy 리소스에 사용됩니다.

NGINX Ingress Controller Keycloak - client 생성

Client의 인증 설정을 활성화하고, Standard flow(Authorization Code Flow)를 체크합니다.

NGINX Ingress Controller Keycloak - client 인증 설정
Standard flow (Authorization Code Flow)

NGINX Ingress Controller의 OIDC 인증에 사용되는 방식이며, 웹 애플리케이션에서 주로 사용되는 인증 방식입니다.

사용자가 Keycloak의 로그인 페이지를 통해 인증을 진행하면 Keycloak이 클라이언트(애플리케이션)로 Authorization Code를 발급하고, 클라이언트가 발급받은 Code를 통해 Keycloak으로 토큰을 요청하여 발급받는 방식입니다. 자세한 인증 과정은 이 포스트의 1-1 섹션을 참고하세요.

이 방식은 토큰이 브라우저를 통하지 않고 백엔드 서버 간에 직접 교환되어 토큰을 노출하지 않고 보안을 강화할 수 있는 방식입니다.

Direct access grants

사용자가 직접 ID와 비밀번호를 클라이언트(애플리케이션)에 입력하고, 클라이언트가 이를 Keycloak으로 전송하여 인증을 처리하는 방식입니다. 신뢰할 수 있는 클라이언트에서만 사용해야 하며, 보안상 권장되지 않는 방식입니다.

Implicit flow

Authorization Code Flow와 유사하지만, 인증 코드(Authorization Code)를 거치지 않고, 바로 액세스 토큰을 발급받는 방식입니다. 토큰이 URL을 통해 노출되는 보안상의 취약점 때문에 Authorization Code Flow 사용이 권장됩니다.

Service accounts roles

사용자 개입 없이, 클라이언트(애플리케이션)가 Keycloak에 인증하여 액세스 토큰을 발급받는 방식입니다. 마이크로서비스 간 통신, 백엔드 서비스에서 API 호출 시 사용할 수 있습니다.

OAuth 2.0 Device Authorization Grant

UI가 없어 입력이 제한되는 장치(예: 스마트 TV, IoT 기기 등)에서 인증을 수행하는 방식입니다.

OIDC CIBA(Client Initiated Backchannel Authentication) Grant

사용자가 브라우저를 통해 리다이렉트 되어 인증을 수행하는 방식과 달리, 클라이언트(애플리케이션)가 Backchannel 요청을 통해 Keycloak을 직접 호출하고, 사용자는 브라우저가 아닌 별도 디바이스를 통해 인증을 진행하게 됩니다.

Client의 로그인 설정을 합니다.

NGINX Ingress Controller Keycloak - 로그인 URL 설정

앞서 구성한 애플리케이션의 도메인을 포트 번호와 함께 작성합니다. redirect URI는 /_codexch, logout redirect URI는 /_logout으로 설정합니다.

User(사용자) 구성

Keycloak을 통해 인증을 진행할 사용자를 생성합니다.

NGINX Ingress Controller Keycloak - realm 사용자 생성
NGINX Ingress Controller Keycloak - realm 사용자 생성
NGINX Ingress Controller Keycloak - realm 사용자 생성

필수 입력 항목은 사용자 이름이며, 첫 로그인 시 사용자가 수행해야 할 작업을 설정할 수 있습니다.
예시의 경우 별도 설정을 적용하지 않았습니다.

사용자 생성 후 Credentials 메뉴에서 해당 사용자의 비밀번호를 생성할 수 있습니다.

NGINX Ingress Controller Keycloak - realm 사용자 비밀번호 생성
NGINX Ingress Controller Keycloak - realm 사용자 비밀번호 생성

4-3. NGINX Ingress Controller Keycloak 연동 구성 – NGINX Ingress Controller

NGINX Ingress Controller의 OIDC 인증을 위해 Policy 리소스를 생성하고, 해당 리소스를 이전에 구성한 VirtualServer 리소스에 명시해야 합니다.

먼저 Policy 리소스에 사용될 Secret을 생성해야 합니다. Secret 생성에 필요한 값은 앞서 생성한 Client의 Credentials에서 확인할 수 있습니다.

해당 값을 복사하여, Kubernetes Secret으로 사용하기 위해 Base64 형식으로 인코딩합니다.

$ echo -n "8AjMzi7pfY9WzR93W6nlWT0l********" | base64 

OEFqTXppN3BmWTlXelI5M1c2bmxXVDBsUnl*******=

인코딩한 값을 사용해 Secret을 생성합니다.

oidc-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: oidc-secret
  namespace: app
type: nginx.org/oidc  # type 주의
data:
  client-secret: OEFqTXppN3BmWTlXelI5M1c2bmxXVDBsUnl*******=

애플리케이션이 배포된 app 네임스페이스에 생성합니다.

Policy 리소스 생성에 필요한 값을 확인합니다.

생성한 NGINX Ingress Controller client 정보에서 clientID 값을 확인합니다.

Realm settings 메뉴 하단의 OpenID Endpoint 링크를 클릭합니다.
혹은 <도메인>/realms/<realm 이름>/.well-know/openid-configuration에 연결하여 확인합니다.

구성에 필요한 엔드포인트 값을 확인할 수 있습니다.
엔드포인트의 구성은 <DOMAIN>/realms/<YOUR-REALM>/protocol/openid-connct/*** 형식입니다.

확인한 값과 앞서 생성한 Secret 이름을 사용하여 Policy 리소스를 app 네임스페이스에 생성합니다.

oidc-policy.yaml
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: oidc-policy
  namespace: app
spec:
  oidc:
    clientID: nginx-ingress
    clientSecret: oidc-secret   # 생성한 Secret 이름
    authEndpoint: https://devopssong2.nginxstore.kr/realms/nginx/protocol/openid-connect/auth
    tokenEndpoint: https://devopssong2.nginxstore.kr/realms/nginx/protocol/openid-connect/token
    jwksURI: https://devopssong2.nginxstore.kr/realms/nginx/protocol/openid-connect/certs
    endSessionEndpoint: https://devopssong2.nginxstore.kr/realms/nginx/protocol/openid-connect/logout

NGINX Pod로 연결되는 VirtualServer를 수정하여 Policy 설정을 추가합니다.

nginx-vs.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: nginx-vs
  namespace: app
spec:
  host: devopssong.nginxstore.kr
  tls:
    secret: devopssong-nginxstore
  upstreams:
    - name: nginx
      service: nginx-svc
      port: 80
  routes:
    - path: /
      policies:
        - name: oidc-policy
      action:
        pass: nginx

5. NGINX Ingress Controller Keycloak API 인증 확인

애플리케이션 도메인인 devopssong.nginxstore.kr로 브라우저에서 접속 시 아래와 같이 리다이렉트되며 로그인 페이지가 나타납니다. Realm 이름인 NGINX를 확인할 수 있습니다.

로그인에 성공하면 백엔드 애플리케이션인 NGINX로 연결됩니다.

Client(NGINX Ingress Controller)가 구성된 nginx realm의 Sessions 메뉴에서 접속한 사용자 정보를 확인할 수 있습니다.

6. 결론

이번 포스트에서는 Kubernetes 클러스터에 Keycloak을 구성하고, NGINX Ingress Controller의 OIDC 인증 기능을 연동하여 API 인증을 구현하는 방법을 알아봤습니다.

먼저 Keycloak의 데이터를 저장할 DB와 함께 Keycloak을 구성하고, NGINX Ingress Controller의 OIDC 인증 기능 활성화 방법을 알아보고, 마지막으로 NGINX Ingress Controller와 Keycloak 연동을 통한 인증 구현 방법을 알아봤습니다.

Keycloak과 NGINX Ingress Controller를 연동하면, 인증이 필요한 애플리케이션을 효과적으로 보호할 수 있습니다. 또한, 클러스터 내 여러 애플리케이션의 인증 정보를 통합하여 중앙에서 관리할 수 있어 운영 효율성이 향상되고, SSO(Single Sign-On)를 통해 사용자 경험을 개선할 수 있습니다.

Keycloak과 연동하여 OIDC 인증을 통해 API 인증을 구현할 수 있는 NGINX Ingress Controller를 체험해 보고 싶으시다면, NGINX STORE를 통해 문의해 무료로 NGINX의 상업 구독을 체험해 보세요.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required