HMAC 키 배포 설계: 공유 비밀을 어디까지 노출할 것인가

반응형

HMAC은 같은 secret key로 message authentication code를 만들고 검증한다. 빠르고 단순하지만 중요한 성질이 하나 있다. 검증을 위해 raw key를 가진 주체는 유효한 HMAC도 새로 만들 수 있다.

따라서 HMAC 키를 어떻게 “공유할지”보다 먼저 누가 message를 만들 수 있어야 하고, 누가 검증만 해야 하는지 정해야 한다. 검증자까지 발행 권한을 가져서는 안 되는 구조라면 HMAC보다 공개키 서명을 선택하는 편이 맞다.

HMAC이 보장하는 것과 보장하지 않는 것

HMAC은 message와 secret key를 hash 기반 함수에 넣어 고정 길이 tag를 만든다. 수신자는 같은 key로 tag를 다시 계산해 message가 변조되지 않았고 key를 아는 주체가 만들었음을 확인한다.

sender:   message + shared key ──> HMAC tag
receiver: message + shared key ──> expected tag ──> compare

이 구조가 제공하는 것은 integrity와 shared-key authenticity다. 다음까지 자동으로 제공하지는 않는다.

  • confidentiality: message 본문은 별도로 암호화하지 않으면 보인다.
  • replay 방지: 같은 message와 tag를 다시 보내는 공격은 timestamp·nonce·sequence 정책이 필요하다.
  • non-repudiation: 양쪽이 같은 key를 가지므로 어느 쪽이 만들었는지 제3자에게 증명하기 어렵다.
  • 발행·검증 권한 분리: raw key를 가진 verifier도 tag를 만들 수 있다.

마지막 두 조건이 필요하면 digital signature처럼 private key와 public verification key가 분리되는 방식을 검토한다.

먼저 trust boundary를 그린다

key 배포 방식은 다음 질문에 답한 뒤 정한다.

  1. HMAC을 생성할 주체는 몇 개인가?
  2. 검증만 해야 하는 주체가 있는가?
  3. online central service를 호출할 수 있는가?
  4. latency·throughput·offline 요구가 있는가?
  5. key가 유출되면 어느 tenant·service·environment까지 영향받는가?
  6. 어느 시점 이전의 message를 계속 검증해야 하는가?

하나의 global key를 모든 service와 partner가 공유하면 한 곳의 침해가 전체 위조 권한으로 확대된다. 최소한 environment, purpose, tenant 또는 peer처럼 실제 격리 단위별로 key를 나눈다.

선택지 1: key를 내보내지 않는 중앙 HMAC service

AWS KMS HMAC key처럼 key material을 service 밖으로 내보내지 않고 GenerateMac, VerifyMac operation만 호출하는 방식이다. HashiCorp Vault Transit도 exportable을 활성화하지 않은 key로 HMAC 생성·검증과 key version 관리를 제공한다.

application ── authenticated API ──> KMS / Transit
                                      ├─ Generate MAC
                                      └─ Verify MAC
                         raw HMAC key ─┘ (외부로 내보내지 않음)

장점은 application memory와 배포 pipeline에 raw key가 나타나지 않고, 중앙 access policy와 audit log를 적용할 수 있다는 점이다. AWS KMS에서는 GenerateMacVerifyMac 권한도 분리할 수 있어 verifier에 생성 권한을 주지 않는 구조를 만들 수 있다.

대신 network dependency, service quota, latency, availability와 request size 제한을 설계해야 한다. 중앙 API를 호출할 수 없는 offline verifier에도 맞지 않는다. AWS KMS의 HMAC key는 자동 rotation을 지원하지 않으므로 새 key를 만들고 application의 key ID를 전환하는 절차가 필요하다. 제품별 rotation 기능이 같다고 가정하면 안 된다.

선택지 2: secret manager가 raw key를 workload에 전달

high-throughput local verification처럼 매 요청마다 중앙 cryptographic service를 부르기 어려우면 raw key가 application runtime에 필요할 수 있다.

이 경우 secret manager는 저장·인증·전달을 관리하지만, key가 process memory에 도달한다는 사실은 바뀌지 않는다.

  • source code, container image와 build argument에 key를 넣지 않는다.
  • workload identity로 필요한 secret path만 읽게 한다.
  • file mount, local agent, memory 전달 등 노출 면이 작은 방식을 선택한다.
  • log, error report, diagnostic endpoint와 crash dump에서 secret을 제외한다.
  • 같은 node·process의 debugging 권한과 memory read 권한을 제한한다.
  • application 종료·reload 때 더 이상 필요한 key를 참조하지 않게 한다.

환경 변수는 배포 도구가 값을 주입하는 한 통로일 뿐 key management system 자체가 아니다. process inspection, debug dump, child process 상속과 운영 도구 노출 가능성을 검토한 뒤 사용해야 한다.

선택지 3: envelope wrapping으로 exportable key를 전달

여러 endpoint가 local HMAC을 수행해야 한다면 random HMAC key를 key-encryption key(KEK)로 감싸 저장하는 envelope 방식도 가능하다.

random HMAC key
      │ encrypt with KEK in KMS
      ▼
wrapped key + key ID + version ── storage/distribution
      │
      └─ trusted workload unwraps ──> HMAC key in memory

저장소와 배포 channel에는 wrapped key만 두고, 허용된 workload만 unwrap한다. 하지만 unwrap 뒤에는 plaintext key가 memory에 존재한다. 이것은 key가 KMS 안에서만 사용되는 KMS HMAC key와 다른 모델이다.

envelope wrapping을 선택할 때는 다음 metadata가 함께 필요하다.

  • wrapping key와 HMAC key의 ID·version
  • algorithm과 key purpose
  • 생성·활성·retire 시각
  • 사용할 tenant·service·environment
  • unwrap 권한과 audit owner

wrapped blob만 바꾸면 rotation이 끝나는 것도 아니다. 모든 signer와 verifier가 어느 version을 언제부터 쓸지 합의해야 한다.

선택지 4: 외부 partner와 pre-shared key 교환

서로 다른 조직의 webhook처럼 raw HMAC key를 양쪽이 가져야 할 때는 key 하나가 하나의 partner 관계만 대표하도록 분리한다. email, ticket, chat message에 평문으로 붙이는 방식은 피하고, 인증된 관리 portal이나 별도의 승인된 out-of-band channel을 사용한다.

전달 절차에는 다음이 포함돼야 한다.

  • sender와 receiver identity 확인
  • key receipt 확인과 활성 시각 합의
  • algorithm, canonical message format과 encoding 합의
  • key ID와 rotation overlap 규칙
  • 유출·퇴사·계약 종료 때 revoke 연락 경로
  • test key와 production key의 완전한 분리

TLS는 전송 중 key를 보호할 수 있지만, endpoint 저장과 운영자 권한까지 해결하지 않는다. 인증되지 않은 Diffie-Hellman을 직접 조합하면 중간자 공격에 취약하다. 자체 key exchange protocol을 만들기보다 인증된 TLS와 검증된 key management product를 사용한다.

key 자체보다 protocol을 함께 설계한다

안전한 HMAC도 어느 byte를 인증하는지 합의하지 않으면 실패한다. 다음 항목의 순서, separator, character encoding, newline, JSON canonicalization과 body hash 방식을 정확히 정의해야 한다.

version=1
key_id=partner-a-2026-08
timestamp=...
nonce=...
method=POST
path=/events
body_sha256=...

예시는 field 목록을 보여 주기 위한 것이다. 실제 protocol에서는 byte-level canonical form을 문서화하고 standard library나 검증된 SDK로 HMAC을 계산한다. 단순 문자열 연결은 field ambiguity를 만들 수 있다.

verifier는 다음을 함께 확인한다.

  1. allowlist에 있는 algorithm과 key ID인가?
  2. tag 길이와 encoding이 예상과 맞는가?
  3. constant-time 비교를 제공하는 crypto library를 사용했는가?
  4. timestamp가 허용 window 안에 있는가?
  5. nonce나 event ID가 이미 처리된 값은 아닌가?
  6. body를 읽은 바로 그 byte로 tag를 검증했는가?

key ID는 secret이 아니라 version lookup hint다. client가 보낸 key ID를 file path, database query나 arbitrary URL에 그대로 넣지 않고, application이 가진 allowlist에서만 찾는다.

key 생성과 rotation 기준

HMAC key는 password나 사람이 기억할 문자열에서 만들지 않고 cryptographically secure random generator로 생성한다. HMAC-SHA-256처럼 256-bit security parameter를 전제로 한 protocol이라면 최소 256-bit random key를 사용하는 식으로 algorithm과 표준의 요구를 맞춘다.

rotation 주기는 모든 시스템에 같은 숫자를 적용하기보다 key의 cryptoperiod와 위험을 기준으로 정한다.

  • 보호하는 data와 message의 가치
  • key가 복제된 endpoint 수
  • message 유효 기간과 과거 검증 요구
  • algorithm·policy·인력·시스템 경계 변경
  • compromise 징후와 audit 결과

rotation은 보통 다음 상태 전이가 필요하다.

new key:      generate ─> verify-ready ─> active signer
old key:      active   ─> verify-only  ─> retired ─> revoked/deleted

signer는 한 시점에 하나의 active key로만 새 tag를 만든다. verifier는 bounded overlap 동안 현재 key와 직전 key를 key ID로 구분해 받아들이고, message 최대 수명 뒤 old key를 retire한다. unknown key ID를 모든 key로 차례로 검증하는 방식은 피한다.

유출이 의심되면 정기 일정까지 기다리지 않는다. 생성 권한을 차단하고, 새 key로 전환하며, compromised key로 만들어진 message의 수명과 replay 상태를 확인한다. HMAC key를 지웠다고 이미 처리된 위조 event가 자동으로 취소되지는 않는다.

어떤 방식을 선택할까

요구 우선 검토할 방식
online이고 raw key 노출을 최소화 KMS·Transit의 HMAC operation
매우 높은 local throughput workload identity + secret manager 또는 envelope-wrapped per-workload key
offline 검증 제한된 raw key 배포 또는 공개키 서명
검증자는 발행하면 안 됨 HMAC 대신 digital signature
외부 partner webhook partner별 PSK + 인증된 전달 + version·replay protocol

HMAC 키 배포의 핵심은 secret을 안전한 channel로 한 번 옮기는 일이 아니다. 누가 위조할 수 있는지 정하고, 그 권한을 최소 단위로 나누며, rotation과 replay까지 protocol로 관리하는 일이다.

JWT와 HMAC 검증 기준은 HS256에서 같은 shared key가 만드는 trust boundary를 구체적으로 다룬다. 중앙 secret 전달 방식이 필요하다면 HashiCorp Vault 시크릿 관리에서 identity·policy·injection 경계를 이어서 볼 수 있다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글