주요업무 4번

공통 어드민 · 이네이블먼트

효율과 통제의 긴장을 설계로 푼다

화면 권한을 아무리 잘 걸어도, 운영 DB 직접 접속이 열려 있으면 통제는 없는 것과 같다.

티빙 현행을 진단한 문서가 아니라 “제가 만든다면”의 목표 설계 초안이며, 기간·목표치는 전부 가정입니다.

§0. 용어 풀이

약어원어
백오피스Back Office시청자가 아닌 내부 구성원이 쓰는 운영 도구 전체
이네이블먼트Enablement남들이 스스로 일할 수 있게 도구·가이드·권한을 갖춰주는 것
RBACRole-Based Access Control역할에 권한을 붙이고, 사람에게 역할을 부여하는 방식
ABACAttribute-Based Access Control속성(부서·지역·시간·데이터 등급)으로 접근을 판단하는 방식
PDPPolicy Decision Point정책 결정 지점. "이 요청을 허용할까"를 판단하는 컴포넌트
SSOSingle Sign-On한 번 로그인으로 여러 시스템을 쓰는 것
MFAMulti-Factor Authentication비밀번호 외에 추가 인증 수단을 요구하는 것
최소권한Least Privilege필요한 만큼만, 필요한 기간만 권한을 준다
JIT 권한Just-In-Time Access평소엔 권한이 없고, 필요할 때 승인받아 일시적으로 얻는 것
SoDSegregation of Duties직무 분리. 요청자와 승인자가 같은 사람이면 안 된다
PIIPersonally Identifiable Information개인식별정보. 이름·연락처·결제수단 등
마스킹Masking화면에 010-****-1234처럼 일부를 가려 보여주는 것
감사로그Audit Log누가·언제·무엇을·왜 했는지 남기는 변경 불가 기록
셀프서비스Self-service개발팀에 티켓을 넣지 않고 운영자가 스스로 처리하는 것
BFFBackend for Frontend화면 전용 API 계층. 여러 도메인 API를 화면 맞춤으로 조합
Admin Shell화면마다 안 바뀌는 공통 프레임. 공통 레이아웃(헤더·사이드바)·인증 가드·공통 컴포넌트·API 인터셉터 묶음. 도메인 화면들이 이 안에 꽂힌다
도메인 모듈셸 안에 꽂히는 업무별 화면 (CMS 운영·결제·CS 등)
로우코드Low-code코드를 거의 안 짜고 드래그로 화면을 조립하는 방식 (Retool 등)
마이크로프런트엔드Micro Frontend (MFE)여러 팀이 각자 만든 화면(모듈)을 하나의 셸에 꽂아 합치는 프런트엔드 구조
피처 플래그Feature Flag배포와 노출을 분리해, 기능을 켜고 끄는 스위치
z-score어떤 값이 평균에서 표준편차의 몇 배만큼 떨어져 있는지

§1. 도메인 정의 — 공통 어드민은 CRUD 화면 모음이 아니다

1-1. 두 개의 목적, 하나의 시스템

공통 어드민의 존재 이유는 두 가지이고, 이 둘은 자주 충돌합니다.

① 효율 — 운영자가 개발팀 없이 스스로 일하게 한다 (셀프서비스).

② 통제 — 아무나 아무 데이터에나 접근하지 못하게 한다 (거버넌스).

효율만 좇으면 권한이 헐거워지고, 통제만 좇으면 아무도 일을 못 합니다. 이 긴장을 설계로 푸는 것이 이 도메인의 본질입니다.

도식을 탭하면 확대해서 볼 수 있습니다

1-2. 내부 고객 페르소나

페르소나주 업무필요 권한위험도
콘텐츠 운영자(MD)메타 등록·검수·카탈로그 배치CMS 쓰기, PII 불필요낮음
편성 담당EPG·FAST 채널 편성CMS 편성 쓰기낮음
마케터프로모션·쿠폰·요금제결제 설정 쓰기, 집계 지표 읽기 (매출 영향)
CS결제 문의·환불개인 결제 이력 읽기, 환불 실행높음 (PII 접근)
정산 담당마감·대사·지급원장 읽기, 조정전표 쓰기높음 (금액 변경)
데이터 분석가지표·실험 분석집계 데이터 읽기 (원본 PII 불필요)
개발자장애 대응·데이터 수정운영 DB 접근최상 (사실상 무제한)

가장 위험한 페르소나는 개발자입니다. 그리고 대부분의 조직에서 개발자 권한이 가장 느슨합니다.

"장애 대응 때문에" 상시 운영 DB 접근권을 갖고 있는 구조는, 사고가 나면 누가 무엇을 봤는지 아무도 모릅니다.

해법은 권한을 뺏는 게 아니라 JIT로 바꾸는 것입니다 — 평소엔 없고, 필요할 때 사유와 함께 승인받아 2시간짜리 권한을 얻습니다.

1-3. 내부 도구가 반드시 푸는 여섯 가지 난제

티빙 현행에 대한 진단이 아닙니다. 규모가 커진 조직이라면 어디서나 마주치는 보편의 난제입니다.

#난제왜 어려운가이 문서의 답
N1계정·권한의 분산시스템마다 계정이 따로면 온·오프보딩이 수작업§2-1 원칙 1, SSO
N2권한 팽창권한을 주기만 하고 회수하지 않으면 모두가 모든 권한을 갖는다§3-2 결정 ①·②
N3뒷문(운영 DB 직접 접속)화면 권한을 아무리 잘 걸어도 우회 경로가 남는다§2-1 원칙 5, JIT + 세션 녹화
N4정상 권한 내의 이상 행위대량 유출은 권한 있는 사람이 너무 많이 조회하는 형태로 일어난다§3-2 결정 ④, §4-1
N5직무 분리의 부재요청자와 승인자가 같으면 통제가 없는 것과 같다§3-2 결정 ③
N6셀프서비스의 부재요금제 하나 바꾸려면 개발 티켓. 사업 속도 저하§2-1 원칙 3

N3와 N4는 함께 봐야 합니다.

화면에 권한을 아무리 잘 걸어도 운영 DB 직접 접속 경로가 열려 있으면 통제는 없는 것과 같습니다. 어드민 개선은 반드시 뒷문을 닫는 일과 함께 가야 합니다.

그리고 뒷문을 닫아도, 권한 범위 안에서 비정상적으로 많이 조회하는 행위는 권한 검사를 통과합니다. 건수와 패턴만이 이상을 드러냅니다.


§2. To-Be 목표 아키텍처

2-1. 설계 원칙 여섯 가지

#원칙구체적으로답하는 난제
1하나의 문(門)모든 어드민은 SSO 단일 진입. 계정은 하나, 권한은 역할로N1
2권한은 데이터, 코드가 아니다역할·권한 변경이 배포를 요구하지 않는다N2
3일상은 빠르게, 위험은 느리게저위험 작업은 마찰 0. 고위험 작업만 승인 게이트N5·N6
4PII는 기본 마스킹, 해제는 사유와 함께해제 자체가 감사 이벤트N4
5뒷문을 닫는다운영 DB 직접 접속을 JIT + 세션 기록으로 대체N3
6감사로그는 append-only지울 수 없는 별도 저장소. 어드민 자신도 못 지운다N4

2-2. 목표 구성도

도식을 탭하면 확대해서 볼 수 있습니다

2-3. 이 구성도를 한 문장으로

"모든 요청이 하나의 문을 지나 정책 엔진의 판단을 받고, BFF에서 마스킹된 뒤, 지울 수 없는 감사로그를 남긴다."

되돌리기 어려운 결정은 둘입니다 — 권한 모델의 형태(§3)와 감사로그를 어디에서 발행할 것인가(§2-2의 B3).

감사를 각 화면이 알아서 하게 두면 반드시 한 화면이 빠뜨립니다. BFF 한 곳에서 발행해야 빠질 수 없습니다.


§3. 데이터 모델 (ERD)

도식을 탭하면 확대해서 볼 수 있습니다

3-2. 설계 결정 네 가지

USER_ROLE.expires_at — 상시 권한에도 만료를 둔다 (난제 N2)

권한은 주기만 하고 회수하지 않으면 시간이 지날수록 모두가 모든 권한을 갖게 된다(권한 팽창, privilege creep). 만료를 기본값으로 두면, 갱신하지 않은 권한은 자동으로 사라진다. 갱신은 관리자가 "이 사람에게 아직 필요한가"를 재확인하는 순간이 된다.

ROLE.requires_jit — 어떤 역할은 상시 부여 자체를 금지한다 (난제 N3)

운영 DB 접근, PII 대량 조회, 정산 조정전표 같은 최고위험 권한은 평소에 아무도 갖고 있지 않아야 한다. 필요할 때 사유와 함께 요청하고, 2시간짜리로 받는다.

SOD_CONFLICT — 겸직 금지 조합을 데이터로 명시 (난제 N5)

"환불을 요청하는 사람과 승인하는 사람은 달라야 한다"는 규칙을 코드에 숨기지 않고 테이블에 둔다. 감사 대응 시 "우리는 이런 직무분리 규칙을 갖고 있습니다" 를 즉시 보여줄 수 있다.

PII_UNMASK.record_count — 몇 건을 열람했는지 센다 (난제 N4)

CS가 한 고객 문의를 처리하며 1건을 열람하는 것과, 누군가 하루에 5만 건을 열람하는 것은 완전히 다른 사건이다. 건수를 세지 않으면 그 차이를 발견할 수 없다.

④번이 대량 유출을 조기에 잡는 거의 유일한 신호입니다.

대부분의 대량 유출은 "권한이 있는 사람이 권한 범위 안에서 비정상적으로 많이 조회"하는 형태로 일어납니다. 권한 검사는 통과합니다. 건수와 패턴만이 이상을 드러냅니다.


§4. DB 샘플 쿼리

4-1. PII 대량 조회 탐지 (난제 N4)

-- 무엇을 답하는가: "평소보다 비정상적으로 많이 개인정보를 열람한 사람이 있는가"
-- 개인별 30일 평균과 비교해 이상치를 찾는다. 권한 검사는 통과한 접근들이다.
WITH daily AS (
    SELECT
        a.actor_user_id,
        DATE(a.occurred_at)          AS 일자,
        SUM(u.record_count)          AS 일_열람건수
    FROM audit_log a
    JOIN pii_unmask u ON u.audit_id = a.audit_id
    WHERE a.occurred_at >= NOW() - INTERVAL '30 days'
    GROUP BY 1, 2
),
stats AS (
    SELECT
        actor_user_id,
        AVG(일_열람건수)             AS 평균,
        STDDEV_POP(일_열람건수)      AS 표준편차
    FROM daily
    GROUP BY 1
)
SELECT
    au.email,
    d.일자,
    d.일_열람건수,
    ROUND(s.평균::numeric, 1)        AS 개인_평균,
    ROUND(((d.일_열람건수 - s.평균) / NULLIF(s.표준편차, 0))::numeric, 2) AS z_score
FROM daily d
JOIN stats s       ON s.actor_user_id = d.actor_user_id
JOIN admin_user au ON au.user_id      = d.actor_user_id
WHERE s.표준편차 > 0
  AND (d.일_열람건수 - s.평균) / s.표준편차 > 3   -- 평균 대비 3시그마 초과
ORDER BY z_score DESC;

z-score 3 초과는 "이 사람의 평소 패턴에서 통계적으로 매우 이례적"이라는 뜻입니다.

절대 건수 임계값(예: 1000건)만 쓰면, 평소 5000건 보는 사람의 1000건은 못 잡고 평소 10건 보는 사람의 200건도 못 잡습니다. 개인별 기준선이 필요합니다.

4-2. 권한 팽창 탐지 (난제 N2)

-- 무엇을 답하는가: "회수되지 않고 방치된 고위험 권한이 있는가"
SELECT
    au.email,
    d.name                                      AS 부서,
    r.code                                      AS 역할,
    r.risk_tier                                 AS 위험등급,
    ur.granted_at,
    ur.expires_at,
    CASE WHEN ur.expires_at IS NULL THEN '무기한'
         ELSE (ur.expires_at - NOW())::text END AS 잔여,
    au.last_login_at,
    NOW() - au.last_login_at                    AS 미사용_기간
FROM user_role ur
JOIN admin_user au ON au.user_id = ur.user_id
JOIN department d  ON d.department_id = au.department_id
JOIN role r        ON r.role_id = ur.role_id
WHERE r.risk_tier = 'HIGH'
  AND (
        ur.expires_at IS NULL                              -- 만료 없음
     OR au.last_login_at < NOW() - INTERVAL '60 days'      -- 60일 미사용
     OR au.employment_state <> 'ACTIVE'                    -- 퇴사·휴직자
  )
ORDER BY r.risk_tier, ur.granted_at;

4-3. 퇴사자 잔존 계정 (Quick Win)

-- 무엇을 답하는가: "퇴사했는데 아직 권한이 살아 있는 계정은?"
-- HR 동기화가 돌면 이 쿼리 결과는 항상 비어 있어야 한다.
SELECT
    au.email,
    au.employment_state,
    au.hr_synced_at,
    COUNT(ur.user_role_id)                      AS 잔존_역할수,
    ARRAY_AGG(r.code ORDER BY r.risk_tier DESC) AS 역할_목록,
    MAX(au.last_login_at)                       AS 마지막_로그인
FROM admin_user au
JOIN user_role ur ON ur.user_id = au.user_id
JOIN role r       ON r.role_id  = ur.role_id
WHERE au.employment_state = 'TERMINATED'
  AND (ur.expires_at IS NULL OR ur.expires_at > NOW())
GROUP BY au.email, au.employment_state, au.hr_synced_at
ORDER BY 잔존_역할수 DESC;

4-4. SoD 위반 — 겸직 금지 조합을 동시에 가진 사람 (난제 N5)

-- 무엇을 답하는가: "요청과 승인을 혼자 할 수 있는 사람이 있는가"
-- 감사에서 반드시 물어보는 질문. 답을 즉시 제시할 수 있어야 한다.
SELECT
    au.email,
    ra.code                     AS 역할_A,
    rb.code                     AS 역할_B,
    c.rationale                 AS 겸직금지_사유
FROM sod_conflict c
JOIN role ra ON ra.role_id = c.role_a_id
JOIN role rb ON rb.role_id = c.role_b_id
JOIN user_role ura ON ura.role_id = ra.role_id
JOIN user_role urb ON urb.role_id = rb.role_id
                  AND urb.user_id = ura.user_id      -- 같은 사람이 둘 다 보유
JOIN admin_user au ON au.user_id = ura.user_id
WHERE (ura.expires_at IS NULL OR ura.expires_at > NOW())
  AND (urb.expires_at IS NULL OR urb.expires_at > NOW())
ORDER BY au.email;

4-5. 셀프서비스 비율 — 어드민의 존재 이유를 재는 지표 (난제 N6)

-- 무엇을 답하는가: "운영 작업 중 개발팀 티켓 없이 처리된 비율은?"
-- 분모: 전체 운영 작업 / 분자: 어드민에서 완결된 작업
-- 티켓 시스템(Jira 등)에서 적재한 ops_ticket 테이블과 감사로그를 함께 본다.
WITH admin_ops AS (
    SELECT DATE_TRUNC('month', occurred_at) AS 월, COUNT(*) AS 어드민_처리
    FROM audit_log
    WHERE action IN ('WRITE', 'DELETE')
      AND outcome = 'ALLOW'
      AND occurred_at >= NOW() - INTERVAL '6 months'
    GROUP BY 1
),
dev_tickets AS (
    SELECT DATE_TRUNC('month', created_at) AS 월, COUNT(*) AS 개발_티켓
    FROM ops_ticket
    WHERE category = 'OPERATIONAL_DATA_CHANGE'
      AND created_at >= NOW() - INTERVAL '6 months'
    GROUP BY 1
)
SELECT
    a.월,
    a.어드민_처리,
    COALESCE(t.개발_티켓, 0)                AS 개발_티켓,
    ROUND(
        100.0 * a.어드민_처리 / NULLIF(a.어드민_처리 + COALESCE(t.개발_티켓, 0), 0)
    , 1)                                    AS 셀프서비스_비율_pct
FROM admin_ops a
LEFT JOIN dev_tickets t ON t.월 = a.월
ORDER BY a.월;

4-6. JIT 권한 사용 실태 — 뒷문이 닫혔는가 (난제 N3)

-- 무엇을 답하는가: "운영 DB 직접 접속이 JIT로 전환되고 있는가, 세션은 다 기록되는가"
SELECT
    DATE_TRUNC('month', s.started_at)                    AS 월,
    COUNT(*)                                             AS 접속_세션수,
    COUNT(*) FILTER (WHERE s.grant_id IS NOT NULL)       AS jit_승인_세션,
    COUNT(*) FILTER (WHERE s.grant_id IS NULL)           AS 상시권한_세션,
    COUNT(*) FILTER (WHERE s.recorded_uri IS NULL)       AS 미녹화_세션,
    ROUND(AVG(EXTRACT(EPOCH FROM (s.ended_at - s.started_at)) / 60)::numeric, 1) AS 평균_분
FROM db_session s
WHERE s.started_at >= NOW() - INTERVAL '6 months'
GROUP BY 1
ORDER BY 1;

상시권한_세션미녹화_세션이 0으로 수렴하는 것이 이 로드맵의 성공 조건입니다.

두 컬럼이 0이 아니면, 화면 권한을 아무리 정교하게 만들어도 뒷문이 열려 있는 것입니다.


§5. 서비스 흐름도 (시퀀스)

5-1. 시나리오 A — JIT 권한 요청과 2인 승인 (SoD)

도식을 탭하면 확대해서 볼 수 있습니다

5-2. 시나리오 B — CS의 PII 조회 (마스킹 해제)

도식을 탭하면 확대해서 볼 수 있습니다

CS는 권한이 있습니다. 그래도 사유를 적습니다.

사유 입력은 CS를 의심해서가 아니라, 사고가 났을 때 정당한 조회와 부당한 조회를 구분하기 위해서입니다.

그리고 그 마찰은 1건 조회에서는 몇 초지만, 5만 건 조회를 시도하는 사람에게는 5만 번의 마찰이 됩니다. 정직한 사용자에게 싸고, 악의적 사용자에게 비싼 설계입니다.


§6. 상태 전이

6-1. JIT 권한 요청

도식을 탭하면 확대해서 볼 수 있습니다

6-2. 계정 생명주기 (HR 연동)

도식을 탭하면 확대해서 볼 수 있습니다

§7. 동선 — 목표 상태

7-1. CS 담당자의 문의 처리 (To-Be)

도식을 탭하면 확대해서 볼 수 있습니다

"마스킹 해제 - 사유 입력"이 4점(5점이 아님)인 것이 의도입니다.

통제는 마찰을 만듭니다. 그 마찰을 0으로 만들려 해서는 안 됩니다. 최소화하되 없애지 않는 것이 설계 목표입니다.

7-2. 어드민 정보구조 (IA) — 권한에 따라 보이는 것이 달라진다

도식을 탭하면 확대해서 볼 수 있습니다

역할별로 아예 다른 홈을 본다는 게 핵심입니다.

흔한 실수는 모두에게 같은 메뉴를 보여주고 클릭하면 "권한 없음"을 띄우는 것입니다. 그건 통제가 아니라 좌절입니다.

보이지 않으면 시도하지 않습니다. 그리고 감사 로그에 DENY가 잔뜩 쌓이지 않아, 진짜 이상 신호가 묻히지 않습니다.


§8. 솔루션 후보 비교

8-1. 인증·권한 (IdP + PDP)

후보강점약점판단
Keycloak (OSS)셀프호스팅, OIDC·SAML 완비, 무료운영 부담, ABAC은 별도 설계 필요채택 후보
AWS Cognito관리형, AWS 통합커스텀 클레임·조직 계층 표현이 빈약
Okta / Auth0성숙도 최고, 관리 편의사용자당 과금 — 내부 직원 수백 명이면 부담
자체 SSO완전 통제보안 취약점 리스크를 우리가 짊어짐
정책 엔진: OPA (Open Policy Agent)정책을 코드/데이터로 분리, ABAC 표현력러닝커브PDP로 채택

인증(누구인가)은 사고, 인가(무엇을 할 수 있나)는 만든다.

인증은 표준(OIDC)이고 취약점 리스크가 크니 검증된 제품을 씁니다. 반면 인가 정책은 우리 도메인 지식입니다 — "정산 조정전표는 2인 승인", "CS는 1건 단위 마스킹 해제". 이건 아무도 대신 만들어주지 않습니다.

그래서 Keycloak(인증) + OPA(정책 평가) + 자체 권한 모델(도메인) 조합을 봅니다.

8-2. 어드민 UI

이 표는 "제품 A vs 제품 B" 비교가 아닙니다.

"조립식 어드민 UI 제품을 사느냐(바이) vs React로 직접 만드느냐(빌드)" 의 비교입니다. Retool·Forest Admin이 화면을 블록 쌓듯 만드는 조립식 어드민 제품이고, 아래에서 ✅로 고른 것은 그 제품들을 쓰지 않고 직접 만드는 선택지입니다. 그래서 마지막 행만 유독 제품 이름이 아닌 것입니다.

후보정체적합성판단
Retool / Appsmith / Budibase로우코드 어드민 빌더 (제품)빠른 프로토타입엔 최고. 마스킹·감사 같은 공통 통제를 강제하기 어려움△ (탐색·분석용 한정)
Forest Admin / DirectusDB 스키마 기반 자동 어드민 (제품)CRUD엔 좋으나 도메인 워크플로우 표현 한계
react-admin / RefineReact 어드민 뼈대 (라이브러리)목록·폼·인증의 기본 틀 제공. 자체 셸의 출발 뼈대로 활용 가능○ (셸 뼈대 후보)
Backstage플러그인 포털 프레임워크여러 팀이 모듈을 꽂는 구조가 참고 가치○ (아키텍처 참조)
자체 개발 — React 기반 공통 셸 + 도메인 모듈제품이 아니라 직접 빌드초기 비용 있으나 공통 통제를 구조로 보장채택

"셸"이 무엇인가 — 낯선 제품명이 아니다

셸(shell)은 화면마다 안 바뀌는 공통 프레임입니다.

공통 레이아웃(헤더·사이드바) + 로그인 처리(인증 가드) + 공통 컴포넌트(공용 표·마스킹 필드) + API 공통 처리(인터셉터)를 묶은 것입니다. React 앱에서 흔히 "공통 프레임 먼저 잡고 화면 붙이기"로 하던 바로 그 부분입니다.

건물에 비유하면 — 셸 = 1층 로비의 보안 게이트(누구든 여기를 지나야 하고, 지나면 자동으로 기록된다), 도메인 모듈 = 각 층 사무실(CMS·결제·CS 화면). 모두가 게이트를 반드시 지나므로, 개인정보 가리기·접근 기록을 화면이 깜빡할 수 없습니다.

왜 제품을 사지 않고 직접 만드나 — 이유는 UI가 아니라 정책

마스킹·감사·권한 검사를 각 화면이 알아서 하게 두면 반드시 한 화면이 빠뜨립니다.

셸이 공통 컴포넌트로 이걸 강제해야 합니다. 조립식 제품(Retool 등)은 화면은 빨리 만들지만, 이 공통 통제를 구조로 강제하기 어렵습니다.

"자체 개발"은 처음부터 전부 만든다는 뜻이 아니다 — 3분할

무엇을어떻게
공통 셸 + 도메인 모듈빌드 (React. react-admin·Backstage를 뼈대로 가능)마스킹·감사·권한을 구조로 강제
UI 프레임워크·컴포넌트바이 / OSS (React·표·차트 라이브러리)바퀴를 재발명하지 않음
PII 없는 분석·탐색 화면로우코드 (Retool 등)샐 것이 없으니 빠른 게 이득

즉 직접 만드는 것은 "공통 통제를 강제하는 껍데기(셸) 한 겹"뿐입니다.

React·컴포넌트 라이브러리는 사다 쓰고, react-admin·Backstage를 뼈대로 깔 수 있으며, 저위험 화면은 Retool로 빠르게 만듭니다. 빠르게 만들 수 있다는 게 통제를 우회할 이유는 아니라는 것 — 그 하나가 자체/로우코드를 가르는 기준입니다.

8-3. 감사·데이터 접근 통제

영역후보판단
감사로그 저장append-only 테이블 + S3 Object Lock 아카이브빌드 + 바이
DB 접근 프록시Teleport / StrongDM / AWS SSM Session Manager바이 (세션 녹화가 핵심)
이상 탐지자체 z-score 룰 + SIEM 연동하이브리드
DB 감사PostgreSQL pgaudit 확장바이
PII 마스킹BFF 계층 자체 필터빌드 (도메인 지식)
비밀 관리HashiCorp Vault / AWS Secrets Manager바이

8-4. 빌드/바이 한눈에

도식을 탭하면 확대해서 볼 수 있습니다

§9. 실행 로드맵

9-1. Phase 0 — 첫 30일에 반드시 물어볼 질문 세 개

① "지난 90일간 회원 PII 테이블을 조회한 사람의 목록을 뽑아주실 수 있나요?"

답이 "뽑을 수 없다"면, 그게 첫 번째 과제입니다.

② "지금 운영 DB에 직접 붙을 수 있는 계정이 몇 개인가요?"

숫자가 두 자리를 넘으면 뒷문이 열려 있는 것입니다.

③ "지난 분기 개발 티켓 중 운영자가 스스로 처리할 수 있었어야 하는 건 몇 %인가요?"

이 비율이 셀프서비스 로드맵의 크기를 결정합니다.

도식을 탭하면 확대해서 볼 수 있습니다

9-2. 순서의 논리

뒷문부터 닫습니다.

화면 권한을 정교하게 만들어도 운영 DB 직접 접속이 열려 있으면 아무 의미가 없습니다. 그래서 감사·JIT가 셀프서비스보다 먼저입니다.

다만 통제만 조이면 조직이 반발합니다. 그래서 Quick Win(퇴사자 계정 회수)으로 신뢰를 얻고, 통제와 편의를 같은 분기에 함께 내놓습니다.

도식을 탭하면 확대해서 볼 수 있습니다

§10. 성과지표

10-1. 지표 트리

도식을 탭하면 확대해서 볼 수 있습니다

10-2. 지표 정의표

지표유형정의쿼리
셀프서비스 비율북극성어드민 처리 ÷ (어드민 처리 + 운영 개발티켓)§4-5
작업당 소요시간입력감사로그 세션 기준 작업 완결 시간감사로그
어드민 커버리지입력화면으로 가능한 작업 종류 ÷ 전체 운영 작업 종류수기 인벤토리
온보딩 리드타임입력HR 입사일 → 첫 정상 업무 수행계정 생명주기
운영 DB 상시접속가드레일JIT 없이 접속 가능한 계정 수 (목표 0)§4-6
퇴사자 잔존 권한가드레일TERMINATED인데 유효 역할 보유 (목표 0)§4-3
SoD 위반가드레일겸직 금지 조합 보유자 (목표 0)§4-4
PII 이상접근 MTTR가드레일탐지 → 조치 완료 시간§4-1 + 인시던트

10-3. 중단 기준

조건조치
셀프서비스 확대 후 감사로그 누락 발견해당 모듈 즉시 롤백. 감사 없는 편의는 없다
어드민 셸 이관 후 DENY 로그 급증역할 설계 오류. 이관 중단하고 권한 매핑 재검토
JIT 도입 후 장애 대응 MTTR 악화승인 SLA(예: 15분) 도입. 통제가 사고를 키우면 안 됨
PII 이상접근 알림의 오탐률 50% 초과임계값 재조정. 양치기 소년이 되면 아무도 안 본다

세 번째 조건이 중요합니다.

보안 통제가 장애 대응을 막으면, 조직은 반드시 우회로를 만듭니다. JIT는 빨라야 합니다. 승인 SLA가 없는 JIT는 곧 무력화됩니다.