<!-- canonical: https://docs.axelabs.ai/ops/runbook/employee-offboarding -->
<!-- source: content/ops/runbook/employee-offboarding.mdx -->

---
title: 직원 퇴사
description: 퇴사한 직원의 모든 access 차단 절차.
playbook: true
---

# 직원 퇴사 (운영자 측)

## AI 요청 프롬프트

```
https://docs.axelabs.ai/ops/runbook/employee-offboarding 따라 퇴사 직원 access 차단해줘.

진행:
1. 퇴사 정보 확인 (email + 퇴사일 + 즉시 차단 여부)
2. 페이지 step 1 — customer IT 측 Microsoft 365 사용자 비활성 (Entra ID OAuth 차단, 토큰 60-90분 내 자동 만료)
3. 페이지 step 2 — `customers.yaml` 의 `user_entity_map` 에서 해당 email 제거 또는 주석, 사용자 확인 후 적용
4. 페이지 step 3 — customer macmini 측 frame 재기동, 매 step 결과 받고 다음. 함정 — 토큰 캐시 60-90분 미만료 / customers.yaml comment 처리 vs 삭제
5. 페이지 step 4 (선택) — 직원이 client_secret 알고 있던 정황 시 [secret-rotation](/ops/runbook/secret-rotation) playbook 으로 분기
```

본인 AI session = Claude Code / Cursor / ChatGPT 데스크탑 / Claude.app / 기타.

페이지 본문 = 사람이 직접 read 도 가능, AI 도 참고. AI 가 본 페이지 fetch 후 위 진행 순서대로 사용자와 step-by-step interactive 풀어나감.

customer admin 으로부터 퇴사 알림:

```
퇴사: kim.minsoo@axellc.com
퇴사일: 2026-06-30
요청: access 즉시 차단
```

## 즉시 (퇴사일 ≤24h 전)

### 1. customer 측 Microsoft 365 사용자 비활성

customer IT 가 처리. 이거 하나만 해도 Microsoft Entra ID OAuth 가 차단 — 즉, frame 도 자동 차단.

직원 본인의 access_token 이 캐시되어 있더라도 60-90분 내 만료.

### 2. customers.yaml 에서 entity 매핑 제거

```yaml
axe:
  user_entity_map:
    "ai@axellc.com": ["axec", "axev"]
    "cfo@axellc.com": ["axec", "axev"]
    # "kim.minsoo@axellc.com": ["axec"]    # ← 제거 (또는 주석 처리)
```

### 3. frame 재기동

```bash
ssh axe-macmini "
  cd /Users/axe/frame &&
  set -a && source .env.local && set +a &&
  docker compose restart frame-mcp-blue frame-mcp-green
"
```

이후 그 직원의 토큰이 frame 에 도달해도 `EntityNotAuthorizedError` 로 거부.

### 4. claude.ai 측 secret 회전 (선택)

만약 그 직원이 회사 client_secret 값을 알고 있던 상황 (Vaultwarden 등) → 의심 시 회전:

→ [Secret rotation](/ops/runbook/secret-rotation) 절차 (응급).

악의 없는 정상 퇴사면 회전 안 해도 무방 (직원의 Microsoft 계정이 비활성화되어 secret 으로도 OAuth 시작 못 함).

## 24h 후

### 5. Audit (직원 마지막 활동 기록)

```bash
ssh axe-macmini "docker exec frame-postgres psql -U frame -d frame -c \"
  SELECT actor, op, table_name, ts
  FROM axec.audit_log
  WHERE actor = 'kim.minsoo@axellc.com'
  ORDER BY ts DESC
  LIMIT 30;
\""
```

- 마지막 활동 timestamp 확인 (정상 종료 vs 의심 패턴)
- 이상 활동 있으면 customer admin 에게 통지

### 6. 보관

audit_log 는 자동으로 영구 보관 (append-only). 별도 export 불필요. 향후 감사 필요 시 actor 로 조회.

## 1 주일 후

### 7. (선택) Vaultwarden organization 에서 제거

만약 Vaultwarden 멤버였으면 organization 에서 제거:

```bash
# Vaultwarden admin UI
# Organizations → axe → Members → kim.minsoo@axellc.com → Remove
```

또는 `bw` CLI 로:
```bash
bw config server https://axe.axelabs.ai/vault
bw login
# (subcommand 로 organization member remove)
```

> **주의 — vault 의 trust boundary**: vault item delete 는 **그 secret 의 저장 위치에서만** 차단. 외부 service (Microsoft / GitHub / KB / 홈택스 등) 의 계정·2FA·OAuth client_secret 은 별 절차 필요. 상세: [/architecture/vault-policies#vault-scope--무엇을-보호하는가-trust-boundary](/architecture/vault-policies). 다음 step 8 표를 vault remove 와 **반드시 병행**.

### 8. 외부 service 권한 회수 (vault scope 외)

vault item 을 지웠다고 그 secret 이 가리키는 외부 service 측 access 가 자동 차단되지 않음. service 마다 별도 admin 절차 필요. 회수 누락 시 그 service 의 access 잔존 + 데이터 export risk.

| 외부 service | 회수 작업 | 책임자 |
|---|---|---|
| Microsoft 365 / Entra ID | 계정 비활성 (= step 1 그대로) | customer IT admin |
| GitHub `axelabs-ai` org | org member 제거 + 본인 PAT 의 server 측 revoke 요청 | 운영자 |
| KB / 홈택스 / 회계법인 portal | 해당 portal admin 의 계정 비활성/삭제 + TOTP secret regenerate (잔존 device 차단) | customer admin |
| Cloudflare Access | user 를 Access policy 에서 remove | 운영자 |
| Anthropic / OpenAI / 기타 API key | 해당 console 에서 API key revoke (vault item 삭제와 별개) | 운영자 |
| OAuth client_secret (직원이 알던 정황) | Azure / Google 측 client_secret 재발급 → 옛값 폐기 | 운영자 (→ [secret-rotation](/ops/runbook/secret-rotation)) |

→ 각 row 를 vault item 삭제와 **쌍으로 처리**. 둘 다 끝나야 회수 완료.

## 함정

| 함정 | 결과 | 회피 |
|---|---|---|
| Microsoft 비활성만 하고 customers.yaml 안 건드림 | 그 직원의 토큰이 만료 후 OAuth 재시도하면 frame 가 entity 매핑 발견 후 통과 가능성 | 둘 다 처리 |
| frame 재기동 잊음 | YAML 변경 안 반영 | 매번 restart |
| 마지막 activity audit 안 함 | 의심 활동 놓침 | 24h 후 확인 |
| vault 만 처리하고 외부 service 안 건드림 | 그 service 측 access 잔존 (KB/홈택스/GitHub/Anthropic 등) + 데이터 export risk | step 8 표 row 별 외부 service 회수 동반 — vault item delete 는 "저장소 차단" 일 뿐. trust boundary = [/architecture/vault-policies#vault-scope--무엇을-보호하는가-trust-boundary](/architecture/vault-policies) |

## 응급 — 의심 활동 발견 시

만약 audit_log 에서 의심 활동 (대량 export, write 폭주 등) 발견:

1. customer admin 에게 즉시 통지
2. 그 직원의 모든 활동 추출 (audit_log 전체)
3. 영향 받은 entity 의 daily integrity check 결과 재확인
4. 필요 시 백업으로 복원 검토
5. customer 요청 시 외부 감사인에게 audit_log 인도

audit_log 는 모든 write 의 old_data + new_data 를 JSONB 로 기록 → 정확한 변경 내용 복원 가능.
