들어가며 — 미루던 숙제를 꺼낼 시간
이전 글에서 SiteMinder(사이트마인더)의 아키텍처를 해부했습니다. 이번 글은 그 다음 질문, **"그래서 어떻게 빠져나오는가"** 를 다룹니다.
2026년 현재 이 숙제를 더는 미룰 수 없는 이유가 분명해졌습니다. [Keycloak 26.6](https://www.keycloak.org/docs/latest/release_notes/index.html)은 FAPI 2.0 Final, passkeys 로그인 통합, zero-downtime 롤링 업데이트, Workflows 기반 realm 관리 자동화까지 갖춰 엔터프라이즈 요구사항을 충분히 받아낼 수 있는 수준이 되었고, [OAuth 2.1 draft](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)와 [RFC 9700](https://datatracker.ietf.org/doc/html/rfc9700)으로 표준 측 베스트 프랙티스도 정리됐습니다. 반면 SiteMinder 측은 12.8.04 EOS(2023-12)가 보여주듯 버전 수명 관리 자체가 상시 리스크이고, Broadcom 인수 후 라이선스 정책 변화는 비용 예측을 어렵게 만들었습니다.
이 글은 컨설팅 장표가 아니라 실무 로드맵을 지향합니다. 인벤토리 작성법, SiteMinder 객체의 Keycloak 매핑, 공존 아키텍처 구성, 비밀번호 마이그레이션, 롤백 계획까지 — 실제 프로젝트에서 부딪히는 순서대로 정리합니다.
마이그레이션 동기 — 왜 떠나는가
조직마다 사정은 다르지만, 동기는 대체로 세 가지로 수렴합니다.
1. EOS와 지원 리스크
- 12.8.04는 2023년 12월에 EOS를 맞았습니다. 구버전에 머무는 환경은 보안 패치 공백에 노출됩니다.
- 12.9로의 업그레이드 자체도 작은 프로젝트가 아니므로, "어차피 큰 공사를 할 거라면 표준 스택으로"라는 판단이 자연스럽게 나옵니다.
2. 라이선스 비용
- 사용자 수 기반 라이선스와 유지보수 비용은 연 단위로 수억 원 규모가 되는 경우가 흔합니다.
- Keycloak은 오픈소스(Apache 2.0)이며, 상용 지원이 필요하면 Red Hat build of Keycloak 같은 선택지가 있습니다. 비용 구조가 "라이선스"에서 "운영 역량"으로 이동합니다.
3. 표준 부재와 생태계 단절
- SMSESSION은 비표준이라 모바일 앱, SPA, API, AI 에이전트(non-human identity) 같은 모던 워크로드와 통합이 어렵습니다.
- OIDC/SAML/SCIM 같은 표준 중심의 Keycloak은 신규 서비스와의 통합 비용이 구조적으로 낮습니다.
- 채용 시장에서 SiteMinder 운영 인력을 구하기는 갈수록 어렵고, Keycloak 경험자는 늘고 있습니다.
0단계: 인벤토리 — 모든 것은 분류에서 시작된다
마이그레이션 실패의 가장 흔한 원인은 기술이 아니라 **인벤토리 부실**입니다. XPSExport로 정책 스토어를 덤프하고, 앱을 다음 세 부류로 분류하는 것이 출발점입니다.
정책 스토어 전체 export
XPSExport sm-policy-export.xml -xb -vT
realm/response 개수 등 1차 통계 추출 (예시)
grep -c "<Realm" sm-policy-export.xml
grep -o 'SM_[A-Z_]*' sm-policy-export.xml | sort | uniq -c | sort -rn
앱 분류 체계
| 분류 | 특징 | 마이그레이션 난이도 | 전환 방법 |
| --- | --- | --- | --- |
| A. 표준 프로토콜 앱 | 이미 SAML/OIDC로 연동 (페더레이션 파트너) | 낮음 | IdP 엔드포인트만 Keycloak으로 교체 |
| B. 헤더 기반 앱 (수정 가능) | SM_USER 헤더 의존, 소스 수정 가능 | 중간 | OIDC 클라이언트로 재작성 또는 프록시 |
| C. 헤더 기반 앱 (수정 불가) | 벤더 폐업, 소스 없음, 변경 금지 | 높음 | 프록시 패턴으로 헤더 재현 (무수정) |
| D. 에이전트 API 의존 앱 | SiteMinder SDK/Agent API 직접 호출 | 최고 | 개별 분석 후 재설계 필요 |
분류와 함께 앱마다 다음 메타데이터를 수집합니다.
- 의존하는 헤더 목록 (SM_USER만? SM_USERGROUPS, 커스텀 response 헤더까지?)
- 세션 타임아웃 요구사항 (realm의 idle/max 값)
- 인증 스킴 (Forms? 인증서? Kerberos? step-up 여부)
- 사용자 스토어 (어느 LDAP/AD를 보는가, 사용자 속성 의존성)
- 트래픽 규모와 업무 중요도 (전환 순서 결정에 사용)
이 인벤토리는 엑셀이 아니라 **버전 관리되는 구조화 데이터**(YAML/JSON)로 만들어 두는 것을 권합니다. 전환 진행률 대시보드의 데이터 소스가 됩니다.
app-inventory.yaml (예시)
- appId: hr-payroll
category: C # 헤더 기반, 수정 불가
headers: [SM_USER, SM_USERGROUPS, X-Custom-Empno]
authScheme: forms
sessionIdle: 30m
owner: hr-it-team
criticality: high
wave: 3 # 전환 웨이브 배정
빅뱅 vs 단계적 전환
| 항목 | 빅뱅 | 단계적 (권장) |
| --- | --- | --- |
| 전환 기간 | 짧음 (이론상) | 길음 (1~3년) |
| 리스크 | 전사 동시 장애 가능성 | 웨이브 단위로 국지화 |
| 롤백 | 사실상 불가능 | 웨이브 단위 롤백 가능 |
| 공존 인프라 | 불필요 | SAML 브리지/프록시 필요 |
| 적합 환경 | 앱 30개 미만 소규모 | 금융권/대기업 수백 개 앱 |
앱이 수십 개를 넘는 환경에서 빅뱅은 도박입니다. 이하 내용은 단계적 전환을 전제로 합니다. 단계적 전환의 핵심 과제는 **전환 기간 동안 두 IdP가 공존하면서도 사용자는 한 번만 로그인하게 만드는 것**입니다.
공존(Coexistence) 아키텍처 — 두 세계의 다리
SAML 브로커링: Keycloak과 SiteMinder의 상호 연동
두 시스템 모두 SAML 2.0을 말할 수 있다는 점이 다리가 됩니다. 방향은 두 가지입니다.
**방향 1: Keycloak이 IdP, SiteMinder가 SP (목표 상태로 가는 권장 방향)**
신규/전환된 앱은 Keycloak으로 직접 로그인하고, 아직 SiteMinder 밑에 있는 레거시 앱에 접근하면 SiteMinder가 SAML SP로서 Keycloak에 인증을 위임합니다. 인증의 진실 공급원이 Keycloak으로 먼저 넘어오므로, passkeys 같은 모던 인증 수단을 전사에 먼저 적용할 수 있습니다.
사용자
|
| 1. 로그인 (passkey/OTP/비밀번호)
v
+------------------+ SAML assertion +--------------------+
| Keycloak | -------------------> | SiteMinder |
| (신규 IdP) | (SM이 SAML SP) | (레거시 WebSSO) |
+--------+---------+ +---------+----------+
| |
| OIDC/SAML | SMSESSION + SM_USER
v v
+------------------+ +--------------------+
| 전환 완료 앱들 | | 미전환 레거시 앱들 |
| (OIDC 클라이언트) | | (헤더 기반) |
+------------------+ +--------------------+
**방향 2: SiteMinder가 IdP, Keycloak이 브로커 (과도기 초기에 유용)**
기존 로그인 경험을 건드리지 않고 신규 앱부터 Keycloak에 붙이고 싶을 때, Keycloak의 Identity Brokering 기능으로 SiteMinder를 외부 IdP로 등록합니다. 사용자는 여전히 SiteMinder 로그인 화면을 보지만, 신규 앱은 표준 OIDC로 개발됩니다.
Keycloak에서 SAML Identity Provider를 등록하는 설정 예시는 다음과 같습니다.
kcadm으로 SiteMinder를 SAML IdP로 등록
/opt/keycloak/bin/kcadm.sh create identity-provider/instances -r enterprise \
-s alias=siteminder-idp \
-s providerId=saml \
-s enabled=true \
-s 'config.entityId=https://keycloak.example.com/realms/enterprise' \
-s 'config.singleSignOnServiceUrl=https://sso.example.com/affwebservices/public/saml2sso' \
-s 'config.nameIDPolicyFormat=urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified' \
-s 'config.postBindingResponse=true' \
-s 'config.wantAssertionsSigned=true'
세션 브리징의 현실
두 IdP의 세션은 별개입니다. SAML 브로커링은 "재인증 없이 다른 쪽 세션을 만들어 주는" 것이지 세션을 하나로 합치는 것이 아닙니다. 따라서 다음을 설계 단계에서 정해야 합니다.
- **세션 수명 정렬**: Keycloak SSO Session Idle/Max를 SiteMinder realm의 idle/max와 의도적으로 맞추거나, 더 짧은 쪽을 기준으로 통일합니다.
- **로그아웃 전파**: 한쪽에서 로그아웃하면 다른 쪽 세션이 살아남는 문제. SiteMinder 로그아웃 URL과 Keycloak의 front-channel logout을 체이닝하는 로그아웃 오케스트레이션 페이지를 두는 것이 현실적인 해법입니다.
- 이 주제는 다음 글(하이브리드 공존 패턴)에서 더 깊게 다룹니다.
헤더 기반 앱을 위한 프록시 패턴 — oauth2-proxy
분류 C(수정 불가 헤더 기반 앱)의 해법입니다. Web Agent가 하던 일 — 인증 확인 후 사용자 헤더 주입 — 을 [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy/)와 nginx로 재현합니다.
사용자 --> nginx (auth_request) --> oauth2-proxy --> Keycloak (OIDC)
| |
| 인증 OK + 헤더 수신 |
v |
레거시 앱 (SM_USER 헤더를 |
그대로 받음 — 코드 무수정) <-------+
oauth2-proxy 설정 핵심은 **Keycloak의 OIDC 클레임을 SiteMinder 헤더 이름으로 변환**하는 부분입니다.
oauth2-proxy.yaml (alpha config)
upstreamConfig:
upstreams:
- id: hr-payroll
path: /
uri: http://hr-payroll.internal:8080
providers:
- id: keycloak-oidc
provider: keycloak-oidc
clientID: legacy-bridge-proxy
clientSecretFile: /secrets/client-secret
oidcConfig:
issuerURL: https://keycloak.example.com/realms/enterprise
emailClaim: email
audienceClaims: [aud]
injectRequestHeaders:
- name: SM_USER # 레거시 앱이 기대하는 헤더 이름 그대로
values:
- claim: preferred_username
- name: SM_USERGROUPS
values:
- claim: groups # Keycloak mapper로 캐럿(^) 조인 형식 재현
- name: X-Custom-Empno
values:
- claim: employeeNumber
nginx 측은 auth_request 패턴으로 연결합니다.
server {
listen 443 ssl;
server_name hr-payroll.example.com;
location /oauth2/ {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header X-Forwarded-Uri $request_uri;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/start?rd=$scheme://$host$request_uri;
oauth2-proxy가 검증 후 내려준 헤더를 업스트림에 전달
auth_request_set $sm_user $upstream_http_sm_user;
auth_request_set $sm_groups $upstream_http_sm_usergroups;
proxy_set_header SM_USER $sm_user;
proxy_set_header SM_USERGROUPS $sm_groups;
외부에서 위조해 들어온 동명 헤더는 위에서 무조건 덮어써짐
proxy_pass http://hr-payroll.internal:8080;
}
}
**보안 주의**: 이전 글에서 강조한 header injection 원칙이 그대로 적용됩니다. 레거시 앱은 반드시 이 프록시를 통해서만 접근 가능하도록 네트워크를 격리해야 하고, 프록시는 클라이언트가 보낸 SM_USER 류 헤더를 덮어써야 합니다.
그룹 클레임을 SiteMinder 형식(캐럿 구분)으로 맞춰야 한다면 Keycloak Script Mapper 또는 커스텀 protocol mapper로 처리합니다.
// Keycloak 커스텀 ProtocolMapper 핵심 로직 (캐럿 구분 그룹 문자열)
@Override
protected void setClaim(IDToken token, ProtocolMapperModel model,
UserSessionModel userSession, KeycloakSession session,
ClientSessionContext ctx) {
String joined = userSession.getUser().getGroupsStream()
.map(GroupModel::getName)
.collect(Collectors.joining("^"));
token.getOtherClaims().put("smUserGroups", joined);
}
정책 마이그레이션 — 객체 매핑표
SiteMinder 객체 모델을 Keycloak 개념으로 옮길 때의 기준 매핑입니다.
| SiteMinder 객체 | Keycloak 대응 개념 | 비고 |
| --- | --- | --- |
| Policy Domain | Realm 또는 Client 그룹핑 | 조직 단위가 크면 realm 분리 검토 |
| Realm (URL 영역+스킴) | Client + 요구 인증 흐름 | URL 보호는 앱/프록시 책임으로 이동 |
| Rule (리소스+액션) | Authorization Services의 resource/scope | 또는 앱 레벨 인가로 이동 |
| Policy (rule+사용자) | Role/Group 매핑, AuthZ policy | LDAP 그룹은 group-ldap-mapper로 동기화 |
| Response (헤더 주입) | Protocol Mapper (클레임 주입) | 헤더 인벤토리가 매핑의 입력 |
| Auth Scheme | Authentication Flow | step-up은 ACR/LoA 조건 흐름으로 |
| Protection Level | ACR (Authentication Context Class) | step-up authentication 재현 |
| User Store (AD/LDAP) | User Federation (LDAP provider) | 초기엔 기존 LDAP 그대로 연결 |
| Session (idle/max) | SSO Session Idle / Max | realm 단위 통일 필요성 검토 |
| OnAuthAccept 이벤트 룰 | Event Listener SPI / Required Action | 커스텀 SPI 개발 영역 |
중요한 관점 전환이 하나 있습니다. SiteMinder는 **URL 중심**(이 URL은 누가 접근 가능한가)이고, Keycloak은 **클라이언트/토큰 중심**(이 앱에 어떤 클레임과 롤을 발급하는가)입니다. URL 단위 세밀 인가가 꼭 필요하면 Keycloak Authorization Services 또는 게이트웨이 레벨(예: 프록시의 경로별 그룹 검사)로 옮기되, 가능하면 앱 내부 인가로 내리는 것이 장기적으로 건강합니다.
LDAP User Federation은 초기 공존기의 핵심 장치입니다. 두 시스템이 **같은 사용자 스토어**를 바라보게 하면 계정 동기화 문제가 사라집니다.
Keycloak에 기존 AD/LDAP을 User Federation으로 연결
/opt/keycloak/bin/kcadm.sh create components -r enterprise \
-s name=corp-ldap \
-s providerId=ldap \
-s providerType=org.keycloak.storage.UserStorageProvider \
-s 'config.connectionUrl=["ldaps://ad.example.com:636"]' \
-s 'config.usersDn=["ou=people,dc=example,dc=com"]' \
-s 'config.bindDn=["cn=svc-keycloak,ou=svc,dc=example,dc=com"]' \
-s 'config.editMode=["READ_ONLY"]' \
-s 'config.syncRegistrations=["false"]'
사용자/비밀번호 마이그레이션 — 점진적 캡처
같은 LDAP을 공유한다면 비밀번호 문제는 없습니다. 그러나 SiteMinder가 자체 사용자 스토어를 쓰거나, 이 기회에 LDAP 자체를 폐기하려는 경우 비밀번호 해시를 옮길 수 없는 상황(독점 해시, 정책상 export 금지)이 생깁니다. 이때 쓰는 것이 **점진적 비밀번호 캡처(gradual password capture)** 입니다.
1. 사용자 프로필(ID, 이메일, 속성)은 SCIM([RFC 7644](https://datatracker.ietf.org/doc/html/rfc7644))이나 배치로 선 이관하되, 비밀번호는 비워 둡니다.
2. Keycloak에 **커스텀 User Storage SPI**를 배치합니다. 사용자가 처음 Keycloak에서 로그인하면, SPI가 입력된 비밀번호로 레거시 스토어(LDAP bind 또는 SiteMinder 인증 API)에 검증을 위임합니다.
3. 검증에 성공하면 그 비밀번호를 Keycloak 자체 크리덴셜(argon2 해시)로 저장하고, 이후부터는 로컬 검증으로 전환합니다.
4. 수개월 후 캡처율이 충분히 오르면(예: 95퍼센트), 잔여 사용자에게 비밀번호 재설정을 안내하고 레거시 스토어를 폐기합니다.
// User Storage SPI의 핵심: 최초 로그인 시 레거시 검증 + 캡처
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
String rawPassword = input.getChallengeResponse();
boolean legacyOk = legacyAuthClient.validate(user.getUsername(), rawPassword);
if (legacyOk) {
// 캡처: Keycloak 로컬 크리덴셜로 저장 → 다음부터 로컬 검증
user.credentialManager().updateCredential(
UserCredentialModel.password(rawPassword));
log.infof("Password captured for user=%s", user.getUsername());
}
return legacyOk;
}
이 패턴은 사용자에게 "비밀번호 재설정 대란"을 일으키지 않고 스토어를 갈아타는 검증된 방법입니다. 단, 캡처 기간 동안 레거시 인증 경로의 가용성이 Keycloak 로그인의 가용성에 영향을 주므로, 서킷 브레이커와 모니터링을 붙여야 합니다.
단계별 롤아웃과 롤백 계획
웨이브 설계
Wave 0 (파일럿) : 사내 IT팀용 저위험 앱 2~3개. 모든 패턴 검증.
Wave 1 (저위험) : 트래픽 적고 업무 영향 낮은 앱 10~20개.
Wave 2~N (본 이관) : 부서/도메인 단위 묶음. 웨이브당 2~6주.
Wave Final (심장부) : 핵심 업무 앱. 충분한 공존 운영 실적 후.
마지막: SiteMinder 디커미션 (정책 아카이브, 라이선스 종료)
웨이브마다 동일한 체크리스트를 반복합니다.
1. **사전**: 대상 앱 헤더/세션 요구사항 재확인, Keycloak 클라이언트/프록시 구성, 스테이징 검증
2. **전환**: DNS/로드밸런서 라우팅을 새 경로(프록시 또는 OIDC 직접)로 변경. 가능하면 카나리(트래픽 일부만 신규 경로) 적용
3. **관찰**: 인증 성공률, 로그인 소요 시간, 헬프데스크 티켓 양을 최소 1~2주 모니터링
4. **확정 또는 롤백**
롤백 계획
롤백이 쉬운 구조를 의도적으로 만들어야 합니다.
- 전환의 실체를 **라우팅 변경**으로 한정하면(앱도, SiteMinder 정책도 삭제하지 않음), 롤백은 라우팅 원복 한 번입니다.
- SiteMinder 정책은 웨이브 확정 후 N주가 지나기 전까지 삭제하지 않고 비활성화 상태로 보존합니다.
- 롤백 트리거를 사전에 수치로 합의합니다. 예: "인증 성공률이 베이스라인 대비 2퍼센트포인트 이상 하락이 30분 지속되면 자동 롤백".
라우팅 전환/원복을 스크립트화해 둔다 (예: nginx upstream 교체)
./switch-route.sh hr-payroll --to keycloak-proxy # 전환
./switch-route.sh hr-payroll --to siteminder # 롤백 (1분 내)
검증 시나리오 — 웨이브마다 돌리는 테스트
최소한 다음 시나리오를 자동화해 두기를 권합니다.
| 번호 | 시나리오 | 확인 포인트 |
| --- | --- | --- |
| T1 | 미인증 사용자가 보호 URL 접근 | 로그인 리다이렉트, 원래 URL 복귀 |
| T2 | 로그인 후 같은 웨이브의 다른 앱 접근 | SSO (재로그인 없음) |
| T3 | 레거시 앱과 신규 앱 교차 이동 | 브리지 경유 SSO, 이중 로그인 없음 |
| T4 | 헤더 값 정합성 | SM_USER 등 헤더가 레거시와 동일 형식 |
| T5 | 세션 idle 만료 | 만료 후 재인증 요구, 무한 리다이렉트 없음 |
| T6 | 로그아웃 | 양쪽 세션 모두 종료되는지 |
| T7 | 헤더 위조 시도 | 외부 주입 SM_USER가 무시/덮어쓰기되는지 |
| T8 | 그룹 기반 인가 | 권한 없는 그룹의 403 확인 |
| T9 | step-up 인증 | 고보호 앱 진입 시 재인증/2FA 요구 |
| T10 | 장애 주입 | Keycloak 1노드 다운 시 로그인 지속 |
T4(헤더 정합성)는 특히 중요합니다. 레거시 환경과 신규 프록시 환경에 같은 요청을 보내 헤더 덤프를 diff하는 하네스를 만들어 두면 웨이브마다 재사용할 수 있습니다.
헤더 정합성 diff 하네스 (개념 예시)
curl -s -b "$LEGACY_COOKIE" https://legacy.example.com/echo-headers > legacy.txt
curl -s -b "$KC_COOKIE" https://bridge.example.com/echo-headers > new.txt
diff <(grep '^SM_' legacy.txt | sort) <(grep '^SM_' new.txt | sort)
Identity Orchestration 도구라는 선택지
모든 것을 직접 구축하는 대신, 전환기 복잡도를 흡수해 주는 상용 레이어도 있습니다. [Strata Maverics](https://www.strata.io/) 같은 identity orchestration 제품은 SiteMinder와 모던 IdP 사이에 추상화 레이어를 두고, 앱별로 어느 IdP를 쓸지 정책으로 스위칭하며, 세션 변환과 헤더 주입을 대신 처리합니다.
- **장점**: 공존 인프라(프록시, 브리지, 로그아웃 동기화)를 직접 개발하지 않아도 됨. 멀티 IdP 환경(인수합병 등)에서 특히 강력.
- **단점**: 또 하나의 벤더 종속과 라이선스 비용. "SiteMinder에서 탈출했더니 오케스트레이션 벤더에 잠겼다"가 되지 않도록, 오케스트레이션 레이어는 한시적 도구로 계획하는 것이 좋습니다.
조직의 엔지니어링 역량이 충분하고 앱 패턴이 단순(대부분 헤더 기반)하다면 oauth2-proxy 기반 자체 구축이, 패턴이 복잡하고 일정이 빠듯하다면 오케스트레이션 도구 도입이 합리적입니다.
흔한 함정 모음
- **헤더 인벤토리 누락**: SM_USER만 옮기고 커스텀 response 헤더(X-Custom-Empno 류)를 빠뜨려, 전환 당일 앱이 빈 화면을 뿜는 사례가 가장 흔합니다.
- **그룹 구분자 불일치**: 캐럿(^) 구분 문자열을 기대하는 파서에 JSON 배열이나 콤마 구분 값을 넘겨 권한이 전부 사라지는 문제.
- **세션 수명 불일치로 인한 리다이렉트 루프**: 프록시 세션은 살아 있는데 Keycloak SSO 세션이 먼저 죽으면, 구성에 따라 무한 리다이렉트가 발생할 수 있습니다. 토큰 갱신과 세션 수명을 계층적으로 정렬해야 합니다.
- **인코딩**: 비ASCII 사용자 속성(한글 이름 등)의 인코딩이 레거시(RFC 2047)와 신규(UTF-8) 간에 달라 다운스트림 파서가 깨지는 문제. T4 하네스에 비ASCII 케이스를 반드시 포함하십시오.
- **시계열 없는 전환 판단**: 전환 직후가 아니라 월말 배치, 분기 결산 같은 주기 업무에서 터지는 문제가 있습니다. 웨이브 확정 전 관찰 기간에 업무 주기를 포함시키십시오.
- **"마지막 5퍼센트" 방치**: 어떤 앱은 끝까지 안 옮겨집니다. 디커미션 목표일을 정하고, 그날 이후 잔여 앱의 유지 비용을 해당 앱 오너 부서에 과금하는 거버넌스가 실제로 효과적입니다.
- **서비스 계정과 배치 잡 누락**: 사람 사용자만 인벤토리에 올리고, 헤더 인증을 흉내 내던 배치/모니터링 봇을 빠뜨리는 사례. non-human identity는 처음부터 별도 트랙으로 분리해 client credentials 플로우로 옮기십시오.
- **헬프데스크 준비 부족**: 웨이브 전환일의 문의 폭증은 예측 가능한 이벤트입니다. 전환 전 헬프데스크에 새 로그인 화면 캡처와 FAQ를 배포하는 것만으로 대응 시간이 크게 줄어듭니다.
- **감사 로그 보존 누락**: 규제 산업은 인증 감사 로그를 수년간 보존해야 합니다. SiteMinder 디커미션 전에 레거시 감사 로그의 보존 방안(아카이브 위치, 조회 절차)을 확정하지 않으면 감사 시즌에 곤란해집니다.
마치며
SiteMinder에서 Keycloak으로의 마이그레이션은 IdP 교체 프로젝트가 아니라 **앱 포트폴리오 현대화 프로그램**입니다. 성공의 8할은 인벤토리와 분류, 그리고 롤백 가능한 웨이브 설계에서 결정됩니다. 기술적으로는 SAML 브로커링과 oauth2-proxy 헤더 변환이라는 두 가지 다리만 견고하게 놓으면, 나머지는 반복 가능한 운영 프로세스의 문제입니다.
다음 글에서는 이 전환기가 수년간 지속된다는 현실을 받아들이고, **레거시 WebSSO와 모던 IAM의 공존 아키텍처 패턴** — 프로토콜 브리지, 리버스 프록시 헤더 주입, identity orchestration, strangler fig — 을 은행 인트라넷 200개 앱 가상 사례와 함께 깊이 다룹니다.
참고 자료
- [Keycloak 공식 문서](https://www.keycloak.org/documentation)
- [Keycloak 릴리스 노트](https://www.keycloak.org/docs/latest/release_notes/index.html)
- [Keycloak Server Administration — Identity Brokering](https://www.keycloak.org/docs/latest/server_admin/index.html)
- [Broadcom SiteMinder Tech Docs](https://techdocs.broadcom.com/siteminder)
- [oauth2-proxy 공식 문서](https://oauth2-proxy.github.io/oauth2-proxy/)
- [RFC 6749 — The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [RFC 7644 — SCIM Protocol](https://datatracker.ietf.org/doc/html/rfc7644)
- [RFC 8693 — OAuth 2.0 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693)
- [RFC 9700 — Best Current Practice for OAuth 2.0 Security](https://datatracker.ietf.org/doc/html/rfc9700)
- [OAuth 2.1 draft (draft-ietf-oauth-v2-1)](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)
- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)
- [SAML 2.0 Core 사양 (OASIS)](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf)
- [Strata — Identity Orchestration](https://www.strata.io/)
현재 단락 (1/244)
이전 글에서 SiteMinder(사이트마인더)의 아키텍처를 해부했습니다. 이번 글은 그 다음 질문, **"그래서 어떻게 빠져나오는가"** 를 다룹니다.