본문으로 건너뛰기

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

저장된 자격 증명을 보호하는 마스터 키를 로테이션하고 브레이크글라스 접근을 사용하기.

Markdown으로 보기

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

키

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

로테이션

키 수명은 플랫폼 콘솔의 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에서 은퇴 키를 제거하고 다시 배포하세요. 그전까지는 유지하세요. 옮기지 못한 값은 여전히 이전 키 아래로 감싸여 있습니다.

작업이 순회하는 곳

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

기록

  • 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 (지난 로테이션이 옮기지 못한 값).

값이 미해결일 때

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

서명 키

마스터 키와는 별개입니다. 각 조직은 자체 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에 있습니다).

브레이크글라스 프로덕션 접근

누구도 프로덕션에 대한 상시 접근을 보유하지 않습니다. 기다릴 수 없는 일이 생기면 담당자가 브레이크글라스 승인을 발급합니다. 플랫폼 콘솔, 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으로 체인이 온전함을 증명합니다).

탐색

검색어를 입력하세요…

↑↓ 이동↵ 선택Esc 닫기