Skip to Content

RBAC bootstrap / lockout 운영 매뉴얼 (D-hive-32)

hive 의 권한 모델은 verb-orthogonal RBAC (hive 서비스 페이지). 본 런북은 그 bootstrap / lockout 안전망의 운영 절차 — owner 가 모자라거나(quorum) 전부 사라졌을 때(lockout) 어떻게 권한을 회복하는가.

AI 요청 프롬프트

https://docs.axelabs.ai/ops/runbook/rbac-bootstrap 따라 hive RBAC lockout 복구해줘. 진행: 1. 상황 식별 — 단일 owner 위험(quorum) vs owner 0명(full lockout) vs 일반 role 부여 차단 2. 1차 = CLI break-glass (`hive role-assign`) — owner 1명 이상 남아있으면 이걸로 충분 3. owner 0명이면 DB break-glass (Layer 2) — 직접 SQL INSERT, 그 후 access_audit_log 수동 보강 4. 모든 step 결과를 받고 다음 — 특히 owner 신원 확인 후 grant 5. 복구 후 owner ≥2 재확인 (`hive role-list`) + (선택) /ops/updates Ship Log 한 줄

본인 AI session = Claude Code / Cursor / Claude.app / 기타. 본문은 사람이 직접 read 도 가능.

전제 — 실행 위치: 프로덕션 CLI 는 컨테이너 안에서 돈다. 모든 hive <cmd> 는 호스트에서 docker exec hive-mcp-blue hive <cmd> 로 감싼다 (active blue 기준 — green 이 active 면 컨테이너명만 교체). hive 는 bare console-script entrypoint (pyproject [project.scripts] hive = "hive.cli:main").

1. 모델 요약 — 무엇을 보호하는가

구성소스
owner role 이름owner (구 admin noun 대체)rbac.OWNER_ROLE
owner 최소 인원2 (quorum)rbac.OWNER_MIN_COUNT = 2
quorum 강제 시점revoke 시에만 — 마지막에서 2번째 owner 해지 차단rbac.revoke_roleOwnerQuorumError
assign 시점강제 없음 — idempotent, 무제한 grant 가능rbac.assign_role
역할 데이터shared.user_roles (human) / shared.system_actor_permissions (system)alembic 0006_rbac_shared

핵심: quorum 은 해지에서만 막힌다. owner 를 추가하는 길(assign)은 절대 막히지 않으므로, owner 가 1명이라도 남아 있으면 lockout 이 아니다 — CLI 로 2번째 owner 를 즉시 채워 quorum 을 복구하면 된다. lockout 은 owner 가 0명일 때만 발생하고, 그때만 Layer 2(DB break-glass)가 필요하다.

2. Layer 1 — owner quorum (≥2) 자동 안전망

revoke_role(role_name="owner") 은 해지 후 active owner 가 OWNER_MIN_COUNT 미만이 되면 OwnerQuorumError 를 던지고 트랜잭션을 롤백한다 (rbac.py revoke_role, active - 1 < OWNER_MIN_COUNT). 즉 마지막 1~2번째 owner 는 시스템이 스스로 보호한다.

확인:

docker exec hive-mcp-blue hive role-list --entity axec # members 배열에서 role=owner 의 active 인원 수 확인 — 2명 미만이면 즉시 보강(아래)

3. Break-glass — owner 보강 / lockout 복구

Layer 2a — CLI break-glass (hive role-assign) — owner 가 1명 이상 남아있을 때 1차 경로

docker exec hive-mcp-blue hive role-assign \ --entity axec --email [email protected] --role owner

assign_role 은 idempotent (이미 active 면 그대로 반환). 이 CLI 경로는 quorum 검사를 받지 않으므로 owner 1명만 남은 위험 상태에서도 즉시 2번째 owner 를 채울 수 있다.

⚠️ audit provenance — 정확히 이해할 것 (자주 오해되는 지점) CLI role-assign 의 grant 는 shared.access_audit_log 에 기록되지 않는다. assign_role (rbac.py) 은 오직 shared.user_roles 에 한 행을 INSERT 하고, 그 행의 granted_by = 'cli:role-assign' + granted_at = now()유일한 (row-level) audit provenance 다. access_audit_logMCP 도구 래퍼 rbac.audited_session 쓴다 (ok/denied/error INSERT) — CLI 는 이 래퍼를 거치지 않고 DB trigger 도 없다 (alembic 0006 에 trigger 없음). 따라서 CLI grant 는 access_audit_log 행을 남기지 않는다. 통합 break-glass audit trail 을 원하면 Layer 2b 와 동일하게 아래 access_audit_log INSERT 를 수동으로 추가하라 (권장).

확인 — grant 가 user_roles 에 남았는지 (row-level provenance):

docker exec hive-postgres psql -U hive -d hive -c \ "SELECT user_email, role_id, granted_by, granted_at FROM shared.user_roles WHERE entity_id='axec' AND revoked_at IS NULL ORDER BY granted_at DESC LIMIT 5;"

Layer 2b — DB break-glass (owner 0명 = full lockout)

owner 가 한 명도 남아 있지 않으면 grant hive.role 권한을 가진 주체가 없어 CLI/MCP grant 자체가 거부될 수 있다. 이때만 DB 에 직접 INSERT 한다.

# 1) owner role 의 id 확인 (entity 별로 seed 됨) docker exec hive-postgres psql -U hive -d hive -c \ "SELECT id, name FROM shared.roles WHERE entity_id='axec' AND name='owner';" # 2) owner 직접 부여 — partial unique index uq_user_roles_active # (entity_id, user_email, role_id) WHERE revoked_at IS NULL 가 중복 active 를 막음 docker exec hive-postgres psql -U hive -d hive -c \ "INSERT INTO shared.user_roles (entity_id, user_email, role_id, granted_by) SELECT 'axec', '[email protected]', r.id, 'break-glass:db' FROM shared.roles r WHERE r.entity_id='axec' AND r.name='owner' ON CONFLICT DO NOTHING;"

복구는 항상 owner ≥2 로 끝내라 (단일 owner 면 다시 같은 lockout 위험). 2명 채운 뒤 hive role-list 로 재확인.

DB break-glass 의 audit trail — 수동 보강 (필수 규율)

DB INSERT 도, CLI grant 와 마찬가지로 access_audit_log 에 자동 기록되지 않는다. row-level provenance 는 user_roles.granted_by = 'break-glass:db' 가 담당하지만, 통합 audit trail 을 위해 같은 트랜잭션 맥락에서 access_audit_log 에 수동 행을 남긴다:

docker exec hive-postgres psql -U hive -d hive -c \ "INSERT INTO shared.access_audit_log (entity_id, actor_kind, actor_id, verb, resource, tool_name, status, detail) VALUES ('axec','human','break-glass','grant','hive.role','break-glass:db','ok', '{\"reason\":\"owner lockout recovery\",\"granted_to\":\"[email protected]\"}'::jsonb);"

statusok|error|denied 만 허용 (CHECK 제약 ck_access_audit_status), verb 는 6 verb CHECK 를 따른다.

owner 신원·권한 회복을 DB 레벨로도 정당화할 수 없는 경우 (예: 회사 지배구조 분쟁, 운영자 전원 부재) → 회사 법무 절차. break-glass 는 어디까지나 신뢰된 운영자가 신원 확인된 owner 를 회복시키는 길이지, 권한 분쟁의 판정 수단이 아니다.

4. 복구 후 체크리스트

  1. hive role-list --entity <entity> → owner active 인원 ≥2 확인.
  2. break-glass 를 썼다면 granted_by (cli:role-assign / break-glass:db) 가 user_roles 에 남았는지 확인 + (DB break-glass 면) access_audit_log 수동 행 확인.
  3. quorum 이 정상화됐으면 임시 owner 는 정상 거버넌스로 revoke (단, 항상 ≥2 유지하며 단계적으로).
  4. (선택) /ops/updates Ship Log 또는 known-gaps 에 lockout 사건 한 줄 기록.

5. seed (참고) — 신규 entity 의 owner ≥2 보장

신규 entity onboarding 시 처음부터 owner 2명을 강제하면 lockout 자체가 잘 안 생긴다. seed_rolesOWNER_MIN_COUNT 미만의 distinct owner email 을 받으면 거부한다.

docker exec hive-mcp-blue hive seed-roles \ --entity axec --owner [email protected] --owner [email protected] # idempotent. customers.yaml user_entity_map 사용자에 member 자동 부여 (--no-members 로 끄기).