기업 인증 연동 · 인증 방식 지형도 · 이론
신분증과 카드키 — 인증 방식의 지형도
한 줄 요약
SI 에서 인증이 어려운 이유는 인증이 어려워서가 아니라 이미 인증 체계가 있기 때문이고, 우리 시스템은 그 사이에 끼어들어야 한다.
왜 SI 에서 인증이 어려운가
신규 시스템 하나를 만들 때 인증은 어렵지 않다. 아이디/비밀번호를 DB 에 넣고 끝이다.
SI 에서 어려운 이유는 이미 인증 체계가 있기 때문이다.
고객사에는 대개 이런 것들이 이미 있다.
- 인사 시스템 (사람의 원천 데이터. 입사·퇴사·부서이동이 여기서 시작된다)
- Active Directory 또는 LDAP (PC 로그인, 파일 서버, 메일)
- 그룹웨어 / 포털 (사내 SSO 의 실질적 관문)
- 오래된 WebSSO 제품 (SiteMinder 같은 것. 15년째 돌고 있다)
- 그리고 최근에 붙인 Keycloak 이나 클라우드 IdP
당신이 만들 시스템은 이 사이에 끼어야 한다. 그래서 "로그인 붙여 주세요"라는
한 줄짜리 요구사항이 실제로는 두 달짜리 일이 된다.
네 가지를 헷갈리지 말 것
| 이름 | 무엇인가 | 한 줄 비유 |
| --- | --- | --- |
| LDAP | 사용자·조직 정보를 담는 디렉터리 프로토콜 | 전화번호부 |
| SAML 2.0 | XML 기반 인증 연동(SSO) 프로토콜 | 종이 신분증 |
| OIDC | OAuth 2.0 위에 올린 인증 연동 프로토콜 | 디지털 신분증 |
| OAuth 2.0 | 인가(권한 위임) 프레임워크 | 호텔 카드키 |
가장 중요한 구분은 마지막 둘이다.
> OIDC / SAML 은 신분증 발급이고, OAuth 2.0 은 호텔 카드키다.
> 카드키는 "이 카드로 305호와 헬스장 문을 열 수 있다"고 말할 뿐,
> 소지자가 누구인지는 말해 주지 않는다.
여기서 유명한 안티패턴이 나온다. 액세스 토큰으로 로그인을 판단하는 것.
액세스 토큰에는 "누구에게 발급했는가"의 검증 근거(aud)가 없거나 느슨하다.
다른 앱용으로 발급된 토큰을 가져다 붙이면 통과해 버리는 토큰 치환 공격이 가능하다.
로그인 판단은 ID 토큰으로 해야 한다.
LDAP 은 인증 프로토콜인가
절반만 맞다. LDAP 은 디렉터리 조회 프로토콜이고, bind 연산으로 비밀번호 검증을
할 수 있다. 그래서 "LDAP 인증"이라는 말이 성립한다. 하지만 그건
애플리케이션이 비밀번호를 직접 받아서 LDAP 에 물어보는 방식이다.
즉 SSO 가 아니다. 앱마다 로그인 화면이 따로 있다.
실무에서는 이렇게 조합한다.
[사용자] --로그인--> [IdP(Keycloak 등)] --bind/조회--> [AD / LDAP] | | |<---- ID 토큰 --------| v[우리 시스템] ← 토큰만 검증. 비밀번호를 절대 보지 않는다우리 시스템이 비밀번호를 보지 않는 것이 핵심 이득이다.
비밀번호를 안 보면 유출 사고의 당사자가 되지 않는다.
레거시 헤더 인증 — 국내 대기업/금융 인트라넷의 현실
15년 된 WebSSO 제품(SiteMinder 계열)은 이렇게 동작한다.
웹 서버에 에이전트를 깔고, 인증이 끝나면 HTTP 헤더에 사용자 정보를 꽂아서
백엔드 애플리케이션에 넘긴다.
SM_USER: jdoeSM_USERDN: uid=jdoe,ou=people,dc=example,dc=comSM_USERGROUPS: hr-staff^payroll-admin백엔드 자바 앱은 필터에서 request.getHeader("SM_USER") 를 읽어 로그인 처리한다.
간단하고, 앱 수정이 거의 없고, 그래서 수백 개 앱이 이 방식으로 붙어 있다.
문제는 명확하다. **앱이 헤더를 무조건 신뢰한다는 것은,
에이전트를 우회해 앱에 직접 도달할 수 있는 경로가 하나라도 있으면
즉시 인증 우회가 된다는 뜻이다.**
curl -H "SM_USER: ceo" -H "SM_USERGROUPS: payroll-admin" \ http://hr-app.internal:8080/hr/payroll/list이 한 줄이 통하는 시스템이 실제로 존재한다. 그래서 필요한 통제가 셋이다.
1. 네트워크 격리 — 앱 포트에 게이트웨이 외에는 접근 불가
2. 엣지에서 헤더 제거 — 외부에서 들어온 SM_* 헤더를 무조건 지우고 새로 채운다
3. 게이트웨이-앱 간 상호 인증 — mTLS 또는 공유 비밀
그리고 이건 옛날 이야기가 아니다. **현대의 리버스프록시 인증(oauth2-proxy 등)도
정확히 같은 구조**다. 헤더로 신원을 전달하는 모든 구성에 같은 요구가 붙는다.
부록으로, 헤더 방식에는 파싱 함정도 있다.SM_USERGROUPS 의 구분자는 캐럿(^) 이다. 콤마로 가정하고 파싱하는 코드가
그룹 하나로 인식해 권한이 통째로 날아간다. 마이그레이션 인벤토리를 만들 때는
헤더 이름뿐 아니라 값의 형식까지 조사해야 한다.
무엇을 언제 쓰는가
| 상황 | 선택 |
| --- | --- |
| 신규 웹/모바일, 우리가 IdP 를 통제할 수 있음 | OIDC (Authorization Code + PKCE) |
| 상대가 대기업/공공이고 이미 SAML IdP 가 있음 | SAML 2.0 |
| 사내 계정 정보 조회·그룹 판정만 필요 | LDAP 조회 (인증은 IdP 에 위임) |
| 서버 간 통신(배치, 연동) | OAuth 2.0 client_credentials |
| 15년 된 앱 100개를 당장 못 고침 | 프록시 기반 헤더 주입 + 위의 통제 3종 |
마지막 줄이 SI 의 현실이다. 이상적인 답은 전부 OIDC 지만,
앱을 못 고치는 상황에서 실제로 굴러가는 답이 필요하다.
그럴 때 프록시가 SSO 를 대신 처리하고 앱에는 헤더로 넘기는 구성을 쓴다.
단, 위의 통제 세 가지를 반드시 함께 건다.
마지막으로, 배치와 서비스 계정을 잊지 마라
SSO 전환 프로젝트에서 반복적으로 터지는 사고가 있다.
월말/분기말에만 발생하는 인증 실패다.
원인은 대개 이것이다: 야간 배치나 연동 프로그램이
사람처럼 로그인 화면을 흉내 내어 인증을 통과하고 있었다.
사람 계정만 마이그레이션 대상으로 잡으면 이걸 놓친다.
그리고 월말에만 도는 배치라서 전환 후 3주 동안 아무 문제가 없다가 터진다.
인벤토리 조사에 반드시 넣어야 할 질문이 있다.
> "사람이 아닌 것 중에 이 인증을 통과하는 것이 있습니까?"
답이 "없다"면 십중팔구 아직 못 찾은 것이다.
현장에서 만나는 모습
"로그인 붙여 주세요" 라는 한 줄짜리 요구사항이 두 달짜리 일이 되는 과정은 대개 이렇게 흘러간다.
먼저 어디에 붙일지가 안 정해져 있다. 인사 시스템이 사람의 원천이지만 로그인은 AD 가 받고, 실질적인 관문은 그룹웨어이며, 최근에 붙인 IdP 도 따로 있다. "우리 회사 계정" 이 무엇을 가리키는지 담당자마다 다르게 답한다.
다음으로 레거시 헤더 인증을 만난다. 앞단 WebSSO 제품이 사용자 ID 를 HTTP 헤더에 실어 넘겨 주는 방식인데, 15 년째 돌고 있어 바꿀 수 없다. 이때 반드시 확인할 것이 하나 있다 — 그 헤더를 외부에서 직접 넣을 수 있는가. 프록시가 헤더를 덮어쓰지 않으면 누구나 남의 ID 로 들어올 수 있다.
마지막으로 배치와 서비스 계정이 빠진다. 사람 계정만 설계하고 오픈한 뒤, 야간 배치가 무슨 자격으로 붙을지를 그때 정하게 된다.