본문 바로가기
서버구축 (WEB,DB)

Kubernetes 서비스 보호를 위한 Google 인증 게이트 (oauth2-proxy)

by 날으는물고기 2026. 3. 23.

Kubernetes 서비스 보호를 위한 Google 인증 게이트 (oauth2-proxy)

728x90

oauth2-proxy는 Google 같은 인증 제공자와 연동해 기존 서비스 앞단에 인증을 얹는 reverse proxy이며, Nginx auth_request와 Kubernetes Ingress annotation 방식 모두를 지원합니다. 또한 Google provider를 사용할 때는 Google Cloud Console에 OAuth 클라이언트 ID를 만들고, oauth2-proxy의 callback 경로를 승인된 redirect URI로 등록하는 방식이 기본 흐름입니다.

oauth2-proxy로 Google 로그인 연동하기

Kubernetes Ingress 앞단 인증을 가장 깔끔하게 붙이는 방법

왜 oauth2-proxy인가

oauth2-proxy는 애플리케이션 자체에 로그인 로직을 넣지 않고도, 앞단에서 Google 계정 인증을 처리할 수 있게 해주는 도구입니다. 즉, 앱은 본래 기능에만 집중하고, 인증은 oauth2-proxy가 맡는 구조입니다. 이런 방식은 내부 서비스, 관리자 페이지, 운영 포털, DevOps 도구처럼 “로그인이 꼭 필요하지만 앱 자체에 인증 기능을 넣고 싶지 않은” 서비스에 특히 잘 맞습니다. 공식 문서도 이를 위해 Google, GitHub 등 다양한 provider를 사용한 인증 방식을 안내하고 있습니다.

이 구조의 장점은 단순합니다. 애플리케이션마다 따로 인증 코드를 개발하지 않아도 되고, Ingress 앞단에서 공통 인증을 강제할 수 있으며, Google Workspace 계정이나 그룹 정책을 활용해 내부 사용자만 허용하는 통제가 쉬워집니다. oauth2-proxy는 기본적으로 세션을 쿠키로 유지하고, 필요하면 Redis 같은 외부 저장소로 세션을 옮길 수도 있습니다.

전체 동작 흐름

흐름은 다음처럼 이해하면 쉽습니다.

  1. 사용자가 myapp.example.com에 접속합니다.
  2. Ingress가 /oauth2/auth로 인증 요청을 보냅니다.
  3. oauth2-proxy가 인증되지 않았다고 판단하면 Google 로그인으로 리다이렉트합니다.
  4. Google 로그인 후 /oauth2/callback으로 돌아오고, oauth2-proxy가 세션을 생성합니다.
  5. 이후부터는 쿠키를 기준으로 인증이 유지됩니다.

oauth2-proxy의 기본 엔드포인트는 /oauth2/auth, /oauth2/start, /oauth2/callback, /oauth2/sign_out 같은 경로로 구성되며, /oauth2 prefix는 설정으로 바꿀 수 있습니다. Nginx ingress-nginx 환경에서는 auth-urlauth-signin annotation을 써서 이 흐름을 연결하는 방식이 공식 문서에 제시되어 있습니다.

Google Cloud Console 설정

Google 연동의 첫 단계는 Google Cloud Console에서 OAuth 2.0 클라이언트를 만드는 것입니다. Google 공식 문서도 OAuth 2.0 client ID를 만들 때 Web application 유형을 선택하고, 승인된 redirect URI를 등록하라고 안내합니다. oauth2-proxy 문서 역시 Google provider 등록 시 Web application/oauth2/callback redirect URI를 쓰는 예시를 제공합니다.

실무적으로는 아래 순서로 진행하면 됩니다.

  1. Google Cloud Console에서 프로젝트를 선택합니다.
  2. APIs & Services → Credentials로 이동합니다.
  3. Create Credentials → OAuth client ID를 선택합니다.
  4. 애플리케이션 유형은 Web application으로 선택합니다.
  5. 승인된 redirect URI에 https://auth.example.com/oauth2/callback을 등록합니다.
  6. 생성 후 Client IDClient Secret을 확보합니다.

여기서 중요한 점은 redirect URI가 실제 서비스 도메인과 경로를 정확히 반영해야 한다는 점입니다. Google의 OAuth 2.0 정책 문서도 web app은 redirect URI와 JavaScript origin이 검증 규칙을 따라야 하며, HTTPS를 사용하는 것이 전제라고 안내합니다. 운영 환경에서는 반드시 서비스 도메인 기준으로 정확하게 등록하는 것이 좋습니다.

oauth2-proxy 설정의 핵심

oauth2-proxy는 config file, environment variable, command line option으로 설정할 수 있고, 우선순위는 command line → environment → config file 순입니다. 따라서 Helm이나 Kubernetes 환경에서는 Secret과 values.yaml, extraArgs를 함께 설계하는 것이 일반적입니다. 또한 공식 문서는 강한 cookie secret 생성을 위해 32바이트 URL-safe 값을 사용하라고 안내합니다.

cookie secret은 반드시 설정해야 합니다. 공식 세션 스토리지 문서에 따르면 cookie storage를 사용할 때 세션 정보는 클라이언트 쿠키에 저장되며, 이때 cookie-secret은 필수입니다. 즉, 이 값이 없으면 세션 보호가 성립하지 않습니다.

쿠키 비밀값은 아래처럼 생성할 수 있습니다. 공식 문서도 유사한 방식의 생성 예시를 제공합니다.

python3 -c "import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())"

또는 다음처럼 만들어도 됩니다.

openssl rand -base64 32 | tr '+/' '-_'

Helm 차트에서 Secret 분리하기

실무에서는 clientSecretcookieSecret을 values.yaml에 평문으로 두지 않고 Kubernetes Secret으로 분리하는 것이 좋습니다. 공식 Helm chart 문서도 config.existingSecret을 통해 OAuth2 자격 증명을 기존 Secret에서 사용하도록 지원하며, config.clientID, config.clientSecret, config.cookieSecret이 주요 값이라는 점을 명시합니다. Google 서비스 계정 JSON이 필요한 경우에는 config.google.existingConfig 또는 config.google.serviceAccountJson 같은 구조도 지원합니다.

공식 chart 기준으로는 대략 이런 형태로 생각하면 됩니다. 차트 버전에 따라 키 이름과 위치가 조금 다를 수 있으니, 실제 적용 전에는 현재 사용하는 chart의 README와 values를 한 번 더 확인하는 편이 안전합니다.

apiVersion: v1
kind: Secret
metadata:
  name: oauth2-proxy-secret
  namespace: your-namespace
type: Opaque
stringData:
  client-id: "123456789-xxxxxxxxxx.apps.googleusercontent.com"
  client-secret: "GOCSPX-xxxxxxxxxxxxxxxxxxxx"
  cookie-secret: "REPLACE_ME_WITH_32BYTE_URLSAFE_VALUE"
# values.yaml 예시
config:
  provider: google
  existingSecret: oauth2-proxy-secret
  cookieSecret: "REPLACE_ME_WITH_32BYTE_URLSAFE_VALUE"
  google:
    adminEmail: "admin@example.com"
    groups:
      - "security-team@example.com"
      - "devops@example.com"

extraArgs:
  cookie-secure: "true"
  cookie-samesite: "lax"
  cookie-expire: "24h"
  cookie-refresh: "1h"
  set-authorization-header: "true"
  pass-authorization-header: "true"
  pass-access-token: "true"
  proxy-prefix: "/oauth2"
  scope: "openid email profile"

scope는 provider별 기본값이 있으므로 항상 꼭 써야 하는 것은 아니지만, 공식 문서는 scope를 명시할 수 있고, provider 기본 scope가 없으면 기본 목록이 사용된다고 설명합니다. 운영 정책상 필요한 범위만 명시해 두는 습관이 좋습니다.

Ingress에서 보호 대상 서비스에 붙이기

Kubernetes에서 가장 흔한 구성은 oauth2-proxy를 별도 서비스로 두고, 보호할 애플리케이션 Ingress에 auth annotation을 거는 방식입니다. 공식 Nginx 가이드도 auth_request와 ingress-nginx annotation 방식 모두를 예시로 제공합니다. auth-url/oauth2/auth, auth-signin/oauth2/start?rd=$escaped_request_uri 형태가 기본입니다.

300x250

아래 예시는 가장 많이 쓰는 패턴입니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://auth.example.com/oauth2/start?rd=$escaped_request_uri"
    nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-Request-User,X-Auth-Request-Email,Authorization"
spec:
  ingressClassName: nginx
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myapp-svc
                port:
                  number: 80

oauth2-proxy는 Nginx auth_request에 대해 인증 성공 시 202, 실패 시 401을 반환하는 방식으로 동작합니다. 또한 --set-xauthrequest를 사용하면 X-Auth-Request-User, X-Auth-Request-Email, X-Auth-Request-Groups 같은 헤더를 넘길 수 있고, --pass-access-token이나 --set-authorization-header를 함께 쓰면 백엔드 전달 방식도 세밀하게 제어할 수 있습니다.

Google Workspace 그룹 기반 접근 제어

단순히 example.com 도메인만 허용하는 것보다 더 강하게 통제하려면 Google Workspace 그룹 기반 제어를 붙일 수 있습니다. 공식 문서에 따르면 이 기능은 service account를 만들고, Admin SDK를 활성화하고, domain-wide delegation을 설정한 뒤, google-admin-emailgoogle-group을 지정하는 방식으로 동작합니다.

특히 이 기능은 로그인이 처음 이뤄질 때와 토큰이 갱신될 때마다 그룹 멤버십을 다시 검사합니다. 공식 문서에는 약 1시간 주기로 refresh 시 재검증이 이루어진다고 설명되어 있어, 퇴사자나 권한 회수 대상자에 대한 통제를 더 촘촘히 가져갈 수 있습니다.

또한 Google provider 문서에는 google-use-application-default-credentials를 통해 GKE Workload Identity나 ADC를 활용할 수 있다고 되어 있습니다. 즉, 꼭 JSON 키 파일만 써야 하는 것은 아니고, GKE에서는 Workload Identity 기반으로 더 안전하게 운영할 수 있습니다.

세션과 쿠키를 어떻게 볼 것인가

oauth2-proxy의 세션 저장 방식은 기본적으로 cookie 기반입니다. 이 경우 세션 정보가 클라이언트 쿠키에 들어가므로 구성은 단순하지만, cookie secret 관리가 절대적으로 중요합니다. 공식 문서는 쿠키 저장소가 stateless하다는 점과, 쿠키가 서버에서 서명되고 암호화된다는 점을 함께 설명합니다.

큰 토큰이나 장기 세션이 필요한 환경에서는 Redis 세션 저장소를 고려할 수 있습니다. 공식 문서에 따르면 Redis 저장소는 암호화된 세션을 Redis에 보관하고, 브라우저에는 짧은 ticket만 전달합니다. 대형 조직이나 토큰이 커지는 환경에서는 이 방식이 훨씬 안정적일 수 있습니다.

쿠키 관련 옵션도 중요합니다. 공식 문서는 cookie-secure를 HTTPS 환경에서 쓰는 것을 전제로 설명하고, cookie-name을 Secure/Host prefix와 함께 설계하는 것이 바람직하다고 안내합니다. cookie-refresh는 세션을 일정 주기로 갱신해 권한이 아직 유효한지 재검증하는 데 쓰이며, Google provider 문서도 짧은 주기(예: 1시간) 갱신을 권장합니다.

배포와 검증

배포 전에는 설정을 검증하는 것이 좋습니다. 공식 문서의 --config-test는 시작하지 않고 설정의 유효성만 검사할 수 있어, CI/CD나 릴리스 전 검증에 유용합니다. required field, provider 설정, upstream 정의, Redis 연결 여부까지 점검 대상에 포함됩니다.

기본 배포는 Helm chart로 진행할 수 있습니다. 공식 chart는 Kubernetes용 deployment를 쉽게 올릴 수 있게 구성되어 있고, helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests 후 설치하는 흐름을 안내합니다. 배포 후에는 Pod 상태, 로그, /oauth2/auth 응답, Google callback 처리 여부를 순서대로 확인하면 됩니다.

예시:

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

helm upgrade --install oauth2-proxy oauth2-proxy/oauth2-proxy \
  -f oauth2-proxy-values.yaml \
  -n your-namespace

검증 단계에서는 다음을 확인하면 좋습니다.

kubectl get pods -n your-namespace
kubectl logs -f deploy/oauth2-proxy -n your-namespace

운영 관점 보안 점검 포인트

첫째, clientSecretcookieSecret은 반드시 Secret으로 분리해야 합니다. GitOps 환경이라면 Sealed Secrets나 External Secrets Operator처럼 암호화된 형태로 관리하는 것이 더 안전합니다. 공식 문서도 secrets를 파일이나 환경변수로 두는 방식을 권장하고 있습니다.

둘째, cookie-secure=true, auth-signin HTTPS, HSTS 적용을 기본 전제로 보아야 합니다. Nginx TLS 가이드는 SSL 종료를 제대로 구성하고, reverse proxy 앞단에서 안전하게 전달하는 구성을 예시로 보여줍니다.

셋째, 가능한 경우 도메인 제한보다 그룹 제한이 더 강합니다. email_domains는 손쉽지만, 실무에서는 조직 계정인지, 어떤 부서 그룹인지까지 확인하는 쪽이 더 좋습니다. Google Workspace 그룹 제어를 붙이면 그룹 멤버십을 기준으로 중앙 통제가 가능합니다.

넷째, 백엔드로 무엇을 넘길지도 정해야 합니다. 단순히 로그인만 시킬지, 아니면 X-Auth-Request-Email이나 Authorization까지 전달할지에 따라 set-xauthrequest, pass-access-token, pass-authorization-header 조합이 달라집니다. 이 부분은 나중에 앱별 권한 연동이나 감사 로그 품질에 큰 영향을 줍니다.

자주 헷갈리는 부분

가장 많이 헷갈리는 부분은 “Google provider인데 왜 OIDC issuer를 쓰지 않느냐”입니다. oauth2-proxy는 Google provider를 별도 provider로 지원하며, Google 전용 설정과 OIDC provider 설정이 분리되어 있습니다. 즉, 기존 OIDC 방식에서 Google provider로 전환할 때는 issuer URL을 그대로 옮기는 것이 아니라 provider 자체를 google로 바꾸는 것이 맞습니다.

또 하나는 Secret 위치입니다. 현재 공식 Helm chart 문서에서는 config.existingSecret이 OAuth2 자격 증명용이며, Google 서비스 계정 관련 값은 config.google.* 또는 config.google.existingConfig 구조를 사용합니다. 차트 버전과 예제에 따라 키가 조금 다를 수 있으니, “내 values.yaml이 아니라 차트 문서가 기준”이라는 점을 꼭 기억하는 편이 좋습니다.

마무리

정리하면, oauth2-proxy + Google 조합은 Kubernetes에서 가장 실용적인 인증 게이트웨이 패턴 중 하나입니다. Google Cloud Console에서 OAuth client를 만들고, oauth2-proxy에 Google provider를 지정한 뒤, Ingress 앞단에서 /oauth2/auth/oauth2/start를 연결하면 곧바로 쓸 수 있습니다. 여기에 Google Workspace 그룹 제한, Secret 분리, cookie-refresh, Redis 세션 저장소까지 더하면 운영 환경에 맞는 꽤 단단한 인증 계층이 됩니다.

728x90
그리드형(광고전용)

댓글