korean-docs
관리
SSO 설정 (OIDC)

SSO 설정 (OIDC)

Wave 3.2.2부터 웹 콘솔에 OpenID Connect(OIDC) 싱글 사인온이 추가되었습니다. 이 문서는 운영자를 위한 실전 런북으로, IdP에서 설정할 항목, Helm에서 지정할 값, 사용자를 미리 등록하는 방법, IdP별로 주의해야 할 함정을 다룹니다.

이 방식을 선택한 이유

Kubernetes는 대시보드 인증 문제를 해결해주지 않습니다. 콘솔형 도구는 대부분 인증 없이 배포되거나, kubectl proxy와 공유 kubeconfig에 의존하거나, 공유 admin 계정 하나만 제공합니다. 이런 방식은 SRE 팀의 컴플라이언스 심사를 통과하지 못합니다. Wave SSO는 조직이 이미 운영 중인 IdP와 연동하므로, 모든 엔지니어가 자신의 계정으로 로그인하고 실제로 의미 있는 감사 기록이 남습니다. 기존 로컬 admin 계정은 비상 접근 경로(break-glass)로 그대로 남아 있어서 IdP 장애가 나도 접속이 막히지 않습니다.

SSO 미사용: 공유 로컬 admin 계정AliceSREBobSRECarolSREadmin공유 비밀번호인당 감사 기록이 없습니다. 오프보딩은 결국 비밀번호 교체뿐입니다.Wave SSO 사용: OIDC 연동AliceSREBobSRECarolSREOIDC IdPOkta / Entra 등Wave 콘솔엔지니어 개개인이 자신의 ID, 역할, 감사 기록을 갖습니다.

사전 요구사항

  • Wave 3.2.2 이상
  • 표준을 준수하는 OIDC identity provider (Okta, Microsoft Entra ID(Azure AD), Google Workspace, Keycloak에서 테스트 완료)
  • SSO 관련 values가 적용된 Wave Autoscale Helm 차트. Helm 설정은 핵심 코드 저장소가 아니라 wave-autoscale-helm 컴패니언 저장소에 있습니다.
  • IdP에 새 OIDC 클라이언트를 등록할 권한

쿠키 키 생성

OIDC의 state, nonce, PKCE verifier는 브라우저와 Wave 사이를 하나의 암호화된 쿠키로 오갑니다. 이 쿠키는 32바이트 키를 사용한 AES-256-GCM으로 봉인됩니다.

환경마다 한 번씩 생성하세요:

openssl rand -base64 32

이 출력값을 다음 단계에서 WA_SSO_COOKIE_KEY로 사용하세요. 비밀 값으로 취급해야 합니다.

IdP에 OIDC 클라이언트 등록

일반 OIDC 설정 (모든 IdP 공통):

설정
FlowAuthorization Code with PKCE
Scopesopenid email profile
Redirect URIhttps://<your-wave-public-host>/api/auth/sso/oidc/callback

redirect URI는 WA_SSO_OIDC_REDIRECT_URI정확히 일치해야 합니다. 프로토콜, 호스트, 포트, 경로, 트레일링 슬래시까지 모두 같아야 합니다. "redirect URI mismatch" 오류의 흔한 원인은 HTTPS 종단 장비가 트레일링 슬래시를 추가하거나 제거하는 경우입니다.

Wave 설정 (WA_SSO_* 환경 변수)

Wave는 다음 환경 변수를 읽습니다. Helm 차트는 이 값들을 wave-sso Secret과 Deployment의 env로 매핑합니다 (자세한 내용은 helm 저장소의 companion PR을 참고하세요).

변수유형기본값설명
WA_SSO_OIDC_ENABLEDboolfalse마스터 스위치입니다.
WA_SSO_OIDC_ISSUERURL-활성화 시 필수입니다. IdP의 issuer URL로, Wave가 /.well-known/openid-configuration 문서를 가져올 때 사용하는 것과 같은 URL입니다.
WA_SSO_OIDC_CLIENT_IDstring-필수입니다.
WA_SSO_OIDC_CLIENT_SECRETsecret-confidential client에는 필수입니다.
WA_SSO_OIDC_REDIRECT_URIURL-위에서 등록한 공개 콜백 URL입니다.
WA_SSO_OIDC_SCOPEScsvopenid,email,profileIdP가 그룹 클레임을 별도 scope 뒤에 두는 경우에만 groups를 추가하세요.
WA_SSO_OIDC_EMAIL_CLAIMstringemailKeycloak 전용 환경에서만 재정의하세요 (IdP별 참고 사항 참조).
WA_SSO_OIDC_REQUIRE_VERIFIED_EMAILbooltrueemail_verified=false인 토큰을 거부합니다. IdP를 완전히 신뢰하지 않는 한 켜둔 상태를 유지하세요.
WA_SSO_OIDC_CLOCK_SKEW_SECONDSu6460토큰 iat/exp 검증 시 허용 오차입니다.
WA_SSO_OIDC_DISPLAY_NAMEstring-로그인 버튼에 표시할 선택적 라벨입니다 (예: "Sign in with Okta").
WA_SSO_COOKIE_KEYbase64-32B-필수입니다. 앞서 실행한 openssl rand -base64 32의 출력값입니다.
WA_SSO_DEV_INSECURE_COOKIESboolfalse개발 환경 전용입니다. Secure 쿠키 속성을 제거해 http://localhost에서도 동작하게 합니다. 운영 환경에서는 절대 설정하지 마세요.

사용자 사전 등록

SSO 사용자는 첫 로그인 시 자동으로 생성되지 않습니다. 관리자가 먼저 계정을 등록해야 합니다:

  1. 웹 콘솔에서 Admin → Users → Add user로 이동합니다.
  2. Auth source = SSO로 설정합니다.
  3. Email을 IdP가 WA_SSO_OIDC_EMAIL_CLAIM(기본값: email)이 가리키는 클레임으로 반환할 값과 정확히 동일하게 입력합니다.
  4. 역할을 지정합니다: Viewer / Operator / Manager / Admin.

이후 IdP로 처음 로그인하면 이메일이 일치하는 이 계정에 연결됩니다. SSO 사용자에게는 Reset Password 버튼이 표시되지 않으며, SSO 계정에 대해 POST /api/auth/change-password를 호출하면 에러 코드 E00051과 함께 400 Bad Request가 반환됩니다 ("This account is managed via SSO; password change is not supported.").

이후 IdP에서 사용자의 이메일이 변경되면 Wave의 계정 정보도 수동으로 업데이트해야 합니다. 이유는 아래 "identity가 sub가 아니라 email과 매칭되는 이유" 절을 참고하세요.

로그인 경험

  • 로그인 페이지에는 기본으로 **"Sign in with <WA_SSO_OIDC_DISPLAY_NAME>"**가 표시됩니다 (값이 없으면 "SSO"로 표시됩니다).
  • "Use local admin account" 토글을 켜면 기존 사용자 이름/비밀번호 입력 폼이 펼쳐집니다. 이 토글은 SSO가 활성화된 상태에서도 계속 표시되며, IdP 장애 시 사용하는 비상 접근 경로입니다.
  • OIDC 핸드셰이크가 성공하면 Wave는 표준 opaque wau_… 세션 토큰을 발급합니다. 이 시점부터는 로컬 admin 로그인과 세션 모델이 완전히 동일합니다.

클레임 매핑 참고

Wave 필드OIDC 클레임 (기본값)누락 시 동작
Identity 매칭email (또는 WA_SSO_OIDC_EMAIL_CLAIM이 가리키는 값)sso_not_authorized로 거부합니다.
Email 인증 여부email_verifiedfalse이고 WA_SSO_OIDC_REQUIRE_VERIFIED_EMAIL=true이면 거부합니다.
Display namename, 없으면 preferred_username둘 다 없으면 이메일의 local-part를 사용합니다.

IdP별 참고 사항

Okta

  • "OIDC - Web App" 애플리케이션 템플릿을 사용하세요.
  • Issuer URL: https://<your-okta-domain>/oauth2/default (또는 커스텀 Authorization Server)
  • 그룹 클레임은 별도의 groups scope 뒤에 있습니다. 나중에 그룹 정보를 노출할 계획이 있을 때만 추가하세요. Wave 3.2.2는 아직 그룹 정보를 사용하지 않습니다.

Microsoft Entra ID (Azure AD)

  • 싱글 테넌트에서도 redirect URI는 반드시 HTTPS여야 합니다.
  • 개인 Microsoft 계정의 경우 email 클레임이 비어 있을 수 있습니다. 이를 막으려면 Supported account types 설정에서 앱 등록 범위를 조직 테넌트로 제한하세요.
  • Issuer: https://login.microsoftonline.com/<tenant-id>/v2.0

Google Workspace

  • hd(hosted domain) 클레임은 로그인을 여러분의 Workspace 도메인으로 제한합니다. 이 제약은 Wave가 아니라 Google 앱 설정에서 적용하세요. Google이 토큰을 여러분에게 전달하기 전에 먼저 거부합니다.
  • Issuer: https://accounts.google.com

Keycloak

  • Realm 설정 Login → Edit username = OFF(기본값)는 preferred_username의 고유성과 불변성을 강제합니다. Keycloak만 사용하는 환경이라면 WA_SSO_OIDC_EMAIL_CLAIM=preferred_username으로 전환해 이메일 변경에도 identity를 안정적으로 유지할 수 있습니다.
  • 나중에 IdP를 바꿀 가능성이 조금이라도 있다면 이렇게 하지 마세요. preferred_username의 이식성은 OIDC 스펙에서 보장하지 않습니다.

identity가 sub가 아니라 email과 매칭되는 이유

OpenID Connect Core 1.0 §5.7에는 (iss, sub) 쌍만 안정적이고 고유함이 보장된다고 명시되어 있습니다. email은 그렇지 않습니다. 그럼에도 저희는 안전장치로 WA_SSO_OIDC_REQUIRE_VERIFIED_EMAIL=true를 두고 email 매칭 방식을 선택했습니다. 이유는 다음과 같습니다:

  • 온보딩 UX가 더 단순합니다. 관리자는 이미 알고 있는 이메일로 계정을 미리 등록하면 됩니다.
  • IdP에서 이메일이 바뀌는 일은 실제로 일어나지만 드뭅니다. 이때 실패 모드는 "관리자가 계정 정보를 갱신할 때까지 사용자가 로그인하지 못한다"이지, "다른 사람의 계정으로 로그인된다"가 아닙니다.
  • verified email 요구 조건이 주요 IdP에서 발생할 수 있는 고유성 문제를 막아줍니다.

문제 해결

  • sso_not_authorized: 이메일 클레임과 일치하는 Wave 사용자 계정이 없습니다. 사용자를 미리 등록하고 이메일이 IdP 클레임과 정확히 일치하는지 확인하세요.
  • E00051 (400 Bad Request): SSO 사용자가 POST /api/auth/change-password를 호출하면 정상적으로 발생하는 에러입니다. 메시지: "This account is managed via SSO; password change is not supported." UI에서는 SSO 사용자에게 Reset Password 버튼을 숨기므로 평소에는 이 상황이 노출되지 않습니다.
  • IdP에서 "redirect URI mismatch"가 발생하는 경우: WA_SSO_OIDC_REDIRECT_URI의 프로토콜, 호스트, 포트, 경로가 IdP에 등록된 값과 정확히 일치해야 합니다. 트레일링 슬래시를 다시 확인하세요.
  • 개발 중 localhost에서 쿠키가 설정되지 않는 경우: WA_SSO_DEV_INSECURE_COOKIES=true로 설정하세요. 운영 환경에서는 절대 설정하지 마세요. 쿠키의 Secure 플래그가 사라집니다.
  • OIDC 핸드셰이크는 성공하지만 email_not_verified로 로그인이 실패하는 경우: IdP가 email_verified=false를 반환하고 있습니다. IdP 쪽 인증 설정을 고치거나, 위험을 감수할 수 있다면 WA_SSO_OIDC_REQUIRE_VERIFIED_EMAIL=false로 기준을 낮추세요.
  • IdP 장애로 접속할 수 없는 경우: 로그인 화면의 "Use local admin account" 토글을 사용하세요. 기존 로컬 admin 계정은 계속 유효합니다.