---
title: "마스터 키와 서명 키 로테이션, 브레이크글라스 접근"
description: "저장된 자격 증명을 보호하는 마스터 키를 로테이션하고 브레이크글라스 접근을 사용하기."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/ko/llms.txt
> Use this file to discover all available pages before exploring further.

# 마스터 키와 서명 키 로테이션, 브레이크글라스 접근

<span id="master-key-and-signing-key-rotation-and-break-glass-access"></span>

감사인이 이름을 대며 요구하는 21-compliance.md 14절의 통제들입니다. 이
페이지는 절차이며, 그 절차가 만들어내는 기록이 증거입니다.

## 키 <!--quire:the-keys-->

저장된 모든 자격 증명은 새로운 데이터 암호화 키(DEK)로 봉인됩니다. DEK는
마스터 키(KEK)로 감싸이며, 마스터 키의 참조는 그 옆에 저장됩니다(`key_ref`,
또는 패킹된 값 안의 참조). 마스터 키를 로테이션하면 DEK를 다시 감쌉니다.
자격 증명을 복호화하거나 다시 암호화하는 일은 결코 없습니다.

| 설정 | 의미 |
| --- | --- |
| `QUIRE_MASTER_KEY` | 현재 마스터 키: 32바이트, base64. 모든 새 시크릿은 이것으로 감싸입니다 |
| `QUIRE_MASTER_KEY_VERSION` | 그 버전 라벨. 미설정 시 `v1`. 키를 바꿀 때마다 올리세요 |
| `QUIRE_MASTER_KEY_RETIRED` | 시크릿을 저장했던 이전 키들. 여전히 아래에 있을 수 있습니다. 형식은 `v1=<base64>,v0=<base64>`. 읽기 전용, 쓰지 않습니다 |

웹 계층, 워커, `bun run kek:rotate` 명령은 같은 세 설정을 읽습니다. 값이
같아야 하며, 하나라도 다르면 한쪽이 봉인한 것을 다른 쪽이 열 수 없습니다.

`QUIRE_MASTER_KEY`가 없으면 각 하위 시스템은 `QUIRE_SECRET_KEY`에서 파생한
키를 유지합니다. 이것은 동작하지만 시스템 상태 페이지에는 성능 저하로
표시되고, 마스터 키를 설정한 뒤에도 읽을 수 있는 상태로 남습니다. 바로
그렇게 첫 로테이션이 모든 것을 그곳에서 옮기는 것입니다. 프로세스 환경을
읽을 수 있는 사람은 누구든 저장된 모든 자격 증명을 복호화할 수 있으므로,
프로덕션 설치에는 마스터 키가 있어야 하며, 시크릿 저장소에 두고 데이터베이스와
같은 백업에 두지 마세요.

## 로테이션 <!--quire:rotating-->

키 수명은 플랫폼 콘솔의 Security, Master key와 지표
`quire.secrets.master_key.age`(일 단위)에 표시됩니다. 매일의
`platform.key_age` 스케줄(03:41 UTC)은 키가 365일에 이르면 플랫폼 감사
체인에 알림 항목을 쓰고, 로테이션될 때까지 30일마다 다시 씁니다. 알림을
받을 때, 그리고 키가 노출되었을 수 있는 언제라도 로테이션하세요.

1. 새 키를 만드세요: `openssl rand -base64 32`.
2. `QUIRE_MASTER_KEY`에 그 키를, `QUIRE_MASTER_KEY_VERSION`에 다음 라벨
   (`v2`)을 설정하세요. 이전 키는 `QUIRE_MASTER_KEY_RETIRED`로
   `v1=<old base64>` 형식으로 옮기세요. 둘 다의 사본을 이 호스트가 아닌
   어딘가에 보관하세요.
3. 새 설정으로 웹 계층과 워커를 배포하세요. 이제 새 시크릿은
   `env:QUIRE_MASTER_KEY:v2` 아래로 감싸이고, 이전 시크릿은 은퇴한 키로
   여전히 열립니다.
4. 감사 추적에 남을 사유와 함께 로테이션을 요청하세요.
   - 콘솔에서: Security, Master key, Rotate the master key; 또는
   - 같은 환경의 셸에서: `bun run kek:rotate request --reason "Annual rotation, ticket SEC-114"`.
5. 워커는 분당 한 조각씩 다시 감싸고(스케줄러의 `platform.key_rotation`
   스케줄), 재시작 후에도 이어집니다. 한 번에 끝내려면:
   `bun run kek:rotate run`. 진행 상황은 `bun run kek:rotate status`로 지켜보세요.
6. 기록에 **미해결 0, 실패 0**으로 로테이션이 완료되었다고 표시되면,
   `QUIRE_MASTER_KEY_RETIRED`에서 은퇴 키를 제거하고 다시 배포하세요. 그전까지는
   유지하세요. 옮기지 못한 값은 여전히 이전 키 아래로 감싸여 있습니다.

### 작업이 순회하는 곳 <!--quire:what-the-job-walks-->

감싸인 DEK를 보관하는 모든 저장소. `SEALED_STORES`에 있는 것들
(`apps/worker/src/key-rotation.ts`)이 그렇습니다. 제어 데이터베이스 저장소는
제어 데이터베이스에서 순회하고, 조직 저장소는 조직이 있는 데이터베이스에서
행 수준 보안 아래에서 조직 하나씩 순회합니다. 전용 데이터베이스에 고정된
테넌트는 그 데이터베이스에서 로테이션됩니다. 스키마가 목록에 없는 감싸인 키
컬럼을 얻으면 테스트가 실패하고, 자격 증명 검토가 목록이 놓친 봉인 컬럼을
분류해도 실패합니다.

### 기록 <!--quire:the-record-->

- `ops.key_rotation`: 로테이션당 한 행. 사유, 요청자, 상태, 합계
  (다시 감쌈, 이미 최신, 미해결, 실패)가 담깁니다.
- `ops.key_rotation_progress`: 순회가 끝난 저장소·범위당 한 행. 읽지 못한 키
  참조와 각 참조 아래에 있던 값의 개수가 담깁니다. 재개된 로테이션은 이것을
  건너뜁니다.
- 플랫폼 감사 체인: 사유가 담긴 `platform/key_rotation_request`, 카운트가
  담긴 저장소별 `platform/key_rotation_store` 하나씩,
  `platform/key_rotation_complete` 또는 `platform/key_rotation_fail`, 알림용
  `platform/key_age_reminder`.
- 지표: `quire.secrets.master_key.age`와 `quire.secrets.rewrap.outstanding`
  (지난 로테이션이 옮기지 못한 값).

### 값이 미해결일 때 <!--quire:when-values-are-unresolved-->

미해결 값은 이 설치가 보유하지 않은 키 참조 아래로 감싸여 있거나, 그 컬럼이
약속한 형태가 아닙니다. 진행 기록에는 참조가 명시됩니다(예:
`env:QUIRE_MASTER_KEY:v0 (unreadable)`). 그 키를 `QUIRE_MASTER_KEY_RETIRED`에
복원하고 다시 로테이션하거나, 키가 영구히 사라졌다면 조직 관리자가 자격
증명을 다시 입력하게 하세요. 그러면 현재 키 아래에 봉인됩니다. 실패한
로테이션은 기록에 오류를 표시합니다. 원인을 고치고 다시 요청하세요.

## 서명 키 <!--quire:signing-keys-->

마스터 키와는 별개입니다. 각 조직은 자체 RSA 키로 OpenID Connect 토큰과
LTI 메시지에 서명하며, 그 키는 `/.well-known/jwks.json`에 게시됩니다. 여기서
운영자가 할 일은 없습니다. 시간당 `platform.signing_keys` 스케줄은 현재
키의 구십 일이 다 되기 칠 일 전에 후임을 게시하고, 일주일 뒤 후임이 서명을
시작하며 이전 키는 은퇴 단계로 넘어가고, 그로부터 구십 일 뒤 이전 키는
삭제되어 키셋에서 빠집니다. 모든 단계는 플랫폼 감사 체인의
`platform/signing_key_advance` 항목입니다.

노출 이후처럼 조직의 키를 일찍 교체하려면:

- 콘솔에서: Security, Master key, Publish a new signing key
  (`platform/keys_manage` 필요); 또는
- 워커 환경의 셸에서: `bun run kek:rotate signing-keys rotate
  --tenant <slug or id> --reason "Key exposed, INC-3310"`. `bun run kek:rotate
  signing-keys status`는 단계별로 모든 조직의 키를 나열합니다.

새 키는 즉시 게시되고 칠 일 뒤, 현재 키가 은퇴할 때 서명을 시작합니다. 일주일은
의도적입니다. 의존하는 쪽은 키셋을 캐시하므로, 겹침이 짧으면 모든 도구가
한 번에 실패합니다. 은퇴하는 키는 구십 일 동안 더 키셋에 남아 이미 서명한
토큰이 계속 검증됩니다. 노출로 더 일찍 신뢰를 멈춰야 한다면 행을 삭제하는
작업은 변경 기록 아래에서 운영자 자신의 데이터베이스 접근으로 하는
변경입니다(브레이크글라스 접근은 읽기 전용이며), 그 키로 서명된 토큰은
이후 검증에 실패합니다. 강제 로테이션은 사유와 함께 감사 체인의
`platform/signing_key_rotate`로 남습니다. 워커는 새 키를 감싸기 위해 웹 계층과
같은 `QUIRE_MASTER_KEY` 설정이 필요하며, 마스터 키용 `bun run kek:rotate`는
다른 것들과 함께 서명 키도 다시 감쌉니다(`oauth_signing_key`는
`SEALED_STORES`에 있습니다).

## 브레이크글라스 프로덕션 접근 <!--quire:break-glass-production-access-->

누구도 프로덕션에 대한 상시 접근을 보유하지 않습니다. 기다릴 수 없는 일이
생기면 담당자가 브레이크글라스 승인을 발급합니다. 플랫폼 콘솔, Security,
Break-glass access.

- 승인에는 범위(하나의 조직 또는 플랫폼 레지스트리), 사고나 티켓을 명시하는
  20자 이상의 사유, 5분에서 240분 사이의 기간이 필요합니다. 만료는
  자동입니다. 모든 진술마다 시계와 대조됩니다.
- 발급한 담당자 자신에게, 또는 다른 담당자에게(2인 형태) 발급할 수 있습니다.
  발급받은 사람만 사용할 수 있습니다. 발급에는 `platform/break_glass_issue`가,
  사용에는 `platform/break_glass_use`가 필요하며 둘 다 기본적으로 담당자
  전용입니다.
- 진술은 데이터베이스 로그인이 아니라 게이트웨이를 통해 실행됩니다. 읽기
  전용, 한 번에 하나, 조직 또는 제어 레지스트리로 한정, 5초 타임아웃,
  최대 500행. 바이너리 값은 크기로 표시됩니다.
- 플랫폼 감사 체인은 발급(사유 포함), 철회, 실행 전의 모든 진술
  (`platform/break_glass_statement`, 거부된 것은 결과 `denied`), 그리고 모든
  결과(`platform/break_glass_result`)를 기록합니다.
  `ops.break_glass_statement`는 감사 항목 ID를 보관하므로 발급 기록이 그 감사
  항목과 조인됩니다.
- 쓰기는 제공되지 않습니다. 릴리스를 기다릴 수 없는 변경은 이 제품 밖에서
  자체 변경 기록 아래의 운영자 데이터베이스 접근으로 하며, 그 기록은 여기서
  쓴 사고 참조를 인용해야 합니다.

데이터베이스 자격 증명을 발급하지 않는 이유: Postgres 로그인은 그것을 요청한
세션보다 오래 살아남고, 애플리케이션이 의존하는 행 수준 보안을 우회하며, 이
제품의 감사 체인에 쓸 수 없어 그 진술은 누가 서버 로그를 옮겼는지만큼만
감사됩니다. 게이트웨이는 감사 추적을 접근을 둘러싼 실무가 아니라 접근 자체의
속성으로 만듭니다.

감사 요청에 답하려면: 기간의 승인을 나열하고(Break-glass access), 승인의
이력을 열어 진술과 감사 항목 ID를 확인한 뒤, 플랫폼 감사 체인에서 그 항목을
읽으세요(`bun run audit:verify --platform`으로 체인이 온전함을 증명합니다).

Source: https://docs.quirelms.com/ko/ops/key-rotation/index.mdx
