5 minute read

전편에서 Okta가 SCIM 커넥터로 보내는 요청을 전부 로그로 받아 확인했다. 이번에는 그 파이프라인 위에서 계정 수명주기의 왕복을 실측한다. 질문은 단순하다.

  1. AD에서 계정을 끄면(Disable) — Okta 계정은, 그리고 앱 쪽 계정은 어떻게 되는가
  2. 다시 켜면(Enable) — 같은 경로를 거슬러 원상복구되는가

Import 다이얼로그에는 “Users disabled in Active Directory will be deactivated in Okta”라고 적혀 있다. 문서가 말해주는 것은 여기까지다. 앱까지의 전파 타이밍, 그리고 반대 방향(재활성화)이 어떻게 동작하는지는 화면으로 확인해야 했다. 결론부터 말하면 끄는 길과 켜는 길은 대칭이 아니다.

1. 랩 구성

항목 값
Okta org Integrator Free Plan
디렉토리 AD — 랩 4에서 구성한 AD Agent 연동 (도메인은 마스킹)
대상 계정 AD-sourced 테스트 계정 1명 — 이하 <username>으로 표기
앱 SCIM-SAML-sp — 랩 6의 커스텀 SAML 앱 + SCIM 프로비저닝
SCIM 서버 자체 Flask 서버(scim_server.py) + cloudflared quick tunnel

시작 시점의 People 목록이다. AD-sourced 계정들과 Okta-sourced 동명 계정이 섞여 9명, 전원 Active 상태다.

시작 상태 — People 목록 9명 전원 Active

2. 환경 재가동 — quick tunnel의 함정

전편의 뒷정리로 SCIM 서버와 터널을 내렸었기 때문에, 실측 전에 환경부터 되살렸다. 서버는 토큰을 환경변수로 주입해 그대로 재기동하면 된다.

SCIM 서버 재기동 — 토큰은 환경변수 주입

문제는 터널이다. cloudflared quick tunnel은 재기동할 때마다 무작위 호스트명이 새로 발급된다. 어제의 URL은 오늘 존재하지 않는다.

cloudflared 재기동 — 새 quick tunnel URL 발급

Okta의 SCIM 커넥터는 여전히 죽은 URL을 바라보고 있으므로, 이 상태에서 프로비저닝이 트리거되면 사용자 상세에 빨간 배너가 뜬다.

Automatic provisioning of user <username> to app SCIM-SAML-sp failed:
Error while verifying if user exists: null

죽은 터널 URL 상태의 프로비저닝 오류 — verifying if user exists: null

에러 문구가 정확하다. 전편 5절에서 봤듯 Okta의 쓰기는 항상 GET /Users?filter=…로 존재 확인부터 시작하는데, 그 첫 단계(verify if user exists)가 연결 실패로 null을 받고 중단된 것이다. 커넥터의 base URL을 새 터널 호스트로 갱신하면 해소된다.

SCIM Connection — base URL을 새 터널 호스트로 수정

부수 관찰 하나. 랩 VM들을 다시 켜자 Okta가 AD Agent 재접속 알림 메일을 보내왔다. Agent의 연결 상태를 org 차원에서 감시하고 있다는 뜻이다 — 실무에서는 이 메일이 Agent 서버 장애의 첫 신호가 된다.

AD Agent 재접속 알림 메일

교훈은 명확하다. quick tunnel은 데모용이지 지속 환경용이 아니다. 실습을 이어갈 계획이라면 named tunnel(고정 호스트)을 쓰는 편이 커넥터 수정을 반복하지 않는 길이다.

3. 기준 상태 만들기 — 대상 계정 할당

커넥터를 복구한 뒤 대상 계정을 앱에 할당해 기준 상태를 만들었다. 서버 로그에 찍힌 요청은 전편과 동일한 패턴이다.

GET /Users?filter=userName eq "…"   → 0건
POST /Users                          → 201  (active: true)

할당 시 서버 로그 — filter 조회 후 POST 201

POST 본문의 구조도 전편 그대로다 — core + enterprise 두 스키마, externalId에 Okta 사용자 ID(00u…), 그리고 Sync Password를 끈 상태에서도 실리는 무작위 password(<masked len=8>). 이 시점에 앱 store에는 세 계정이 전부 active: true로 존재한다.

4. 계정 비활성화 — AD에서 끄면

이제 본론이다. DC에서 계정을 끈다.

Disable-ADAccount <username>
Get-ADUser <username> | Select-Object SamAccountName, Enabled   # → False

DC에서 Disable-ADAccount 실행 — Enabled False 확인

AD Agent 연동은 스케줄 Import 기반이므로, 기다리는 대신 Directory Integrations에서 Import Now로 Incremental Import를 수동 실행했다.

Directory Integrations — AD 연동 진입

Import Now 실행

Import 다이얼로그가 이번 랩의 전제를 명시하고 있다 — “Users disabled in Active Directory will be deactivated in Okta.” 그리고 full import에만 해당하는 예외(AD에서 삭제된 그룹 제거)도 함께 적혀 있다.

Incremental Import 다이얼로그 — disabled 사용자는 Okta에서 deactivate된다는 문구

Import가 끝나자 Okta의 대상 계정은 Deactivated로 바뀌었다. 주목할 점은 이 방향에는 확인 절차가 없다는 것이다 — Import 결과는 “0 need review”였고, 비활성화는 관리자 개입 없이 곧바로 적용됐다.

Import 직후 People — 대상 계정 Deactivated

5. 앱까지의 전파는 동기가 아니다

Okta가 Deactivated라면 앱 쪽도 active: false가 되어 있어야 한다. 그런데 Deactivated 확인 직후 store를 열어보니 세 계정 모두 여전히 active: true였다.

Okta는 Deactivated인데 store는 전원 active true

잠시 뒤 다시 확인하자 대상 계정만 False로 바뀌어 있었다 — 전편 6절에서 본 GET /Users/{id} → PUT active:false가 뒤늦게 도착한 것이다.

재확인 — 대상 계정 active False

정리하면: Okta 콘솔의 상태 변화와 다운스트림 앱의 상태 변화 사이에는 지연이 있다. Okta 화면이 Deactivated라고 해서 그 순간 앱 접근이 차단된 것은 아니다. 퇴사자 처리처럼 시간이 중요한 시나리오라면, Okta 상태가 아니라 앱 쪽 상태를 기준으로 완료를 판정해야 한다.

6. 재활성화 — Import는 계정을 되살리지 않는다

이제 반대 방향이다. DC에서 계정을 다시 켜고,

Enable-ADAccount <username>
Get-ADUser <username> | Select-Object SamAccountName, Enabled   # → True

DC에서 Enable-ADAccount — Enabled True

같은 방식으로 Incremental Import를 돌렸다. 비활성화 때와 달리 이번에는 결과가 “1 imported user needs review” — 자동 적용이 아니라 검토 대상으로 올라온다.

Enable 후 Import — 1 need review, EXACT match

검토 항목을 열어보면 기존 Okta 계정과의 EXACT match가 잡혀 있고, 매칭 방식(EXACT / NEW / EXISTING 지정 / IGNORE)을 고르게 되어 있다. 비활성화됐던 AD-sourced 계정이 다시 살아나면, Okta는 이를 기존 계정에 자동 연결하지 않고 신규 Import처럼 재확인을 요구하는 것이다.

매칭 선택지 — EXACT match / NEW user / EXISTING 지정 / IGNORE

EXACT match를 선택하고 Confirm Assignments를 눌렀다.

Confirm Assignments 1건 실행

결과는 오류다.

App assignment attempted for user 00u15qfinqqbDoVti698
but user is in inactive status INACTIVE

Confirm 결과 — 앱 할당이 INACTIVE 오류로 실패

여기가 이번 랩의 핵심 발견이다. AD에서 Enable + Import를 해도 Okta 계정은 Deactivated에서 돌아오지 않는다. Import는 매칭 확인까지만 해주고, 매칭에 딸린 앱 할당은 계정이 INACTIVE라서 실패한다. 끄는 방향은 Import 한 번에 자동으로 끝났지만, 켜는 방향은 여기서 멈춘다.

7. 수동 Activate — 그리고 Pending user action

복구 경로는 관리자가 콘솔에서 직접 여는 수밖에 없었다. People에서 대상 계정을 열면 Deactivated 상태에 Activate 버튼이 보인다.

Deactivated 사용자 상세 — Activate 버튼

Activate를 누르자 System Log에 앱 멤버십 재부여 이벤트가 찍혔다 — 계정이 되살아나면서 끊겼던 앱 할당이 다시 연결되는 것이다.

System Log — Add user to application membership SUCCESS

그런데 People 목록의 상태는 Active가 아니라 Pending user action이다. 재활성화된 계정은 사용자가 로그인(활성화 절차)을 마치기 전까지 이 중간 상태에 머문다.

Activate 후 상태 — Active가 아니라 Pending user action

그럼 Pending 상태에서는 로그인이 안 되는가? 됐다. 대상 계정으로 대시보드에 로그인하자 System Log에 SSO 성공과 OIDC 토큰 발급이 기록됐다. 인증의 실체가 AD 위임 인증이기 때문이다 — AD 계정이 살아 있고 비밀번호가 맞으면, Okta 쪽 상태 표시가 Pending이어도 인증은 통과한다.

Pending 상태에서 로그인 성공 — SSO + OIDC 토큰 발급

Pending user action은 “로그인 불가”가 아니라 “사용자의 첫 활성화 행동 대기”라는 표시에 가깝다. 상태 이름만 보고 접근이 막혀 있다고 판단하면 틀린다.

8. 실습 중 확인한 자잘한 것들

  • Import 다이얼로그의 문구는 방향별 동작 차이를 이미 암시하고 있다 — deactivate는 both import types의 동작으로 명시돼 있지만, 재활성화에 대한 문구는 없다
  • 프로비저닝 오류 배너는 커넥터 URL을 고쳐도 저절로 사라지지 않는다. 다음 프로비저닝 트리거가 성공해야 정리된다
  • quick tunnel URL 갱신 후 Test Connector Configuration의 요청은 전편과 동일하게 GET /Users?startIndex=1&count=2 하나였다

정리

이번 실측으로 확인된 비대칭을 한 줄씩 정리하면:

  1. AD Disable → Okta Deactivated는 자동이다. Incremental Import 한 번, 확인 절차 없이 적용된다
  2. Okta Deactivated → 앱 active:false는 비동기다. 확인 시점에 따라 앱 계정이 아직 살아 있을 수 있다. 완료 판정은 앱 쪽 상태로 해야 한다
  3. AD Enable → Import는 Okta 계정을 되살리지 않는다. EXACT match 재확인을 요구하고, 딸린 앱 할당은 INACTIVE 오류로 실패한다
  4. 복구에는 관리자의 수동 Activate가 필요하다. Activate 시점에 앱 멤버십이 재부여된다
  5. 재활성화된 계정은 Pending user action 상태다. 그러나 AD 위임 인증이므로 이 상태에서도 로그인은 성공한다
  6. quick tunnel은 재기동마다 URL이 바뀐다. 커넥터가 죽은 URL을 바라보면 “Error while verifying if user exists: null”로 프로비저닝이 멈춘다

Leaver 방향은 자동화가 잘 깔려 있지만, 복귀(rehire) 방향은 관리자 개입 지점이 두 곳(Import 확인, 수동 Activate) 숨어 있다. 계정 수명주기 운영 절차를 설계한다면 이 비대칭을 절차서에 그대로 반영해야 한다.

미실측 항목

  • Full Import에서의 동작 차이 — 특히 “Users not present in the data will be deactivated”가 만드는 대량 비활성화 시나리오
  • Deactivate 대신 Suspend를 썼을 때 앱 전파가 어떻게 달라지는지
  • Okta Deactivated → 앱 PUT active:false의 지연 시간 정밀 측정 — 이번에는 “즉시는 아니다”까지만 확인했다
  • Pending user action이 Active로 전환되는 정확한 조건

Comments