AWS 기술 블로그
당근이 AWS CloudHSM으로 대규모 서명키 관리 시스템을 구축한 방법– 2부: CloudHSM 아키텍처와 다계층 접근 제어
해당 포스트는 당근의 최용환님, 조승환님, 오현준님과 함께 작성했으며, AWS Summit Seoul 2026에서 발표한 세션 내용을 기반으로 합니다.
이 시리즈의 1부에서는 서명키 보안의 중요성과 당근이 AWS CloudHSM과 AWS KMS를 비교하여 하이브리드 전략을 선택한 과정을 다루었습니다. 이번 글에서는 CloudHSM 아키텍처를 어떻게 설계했는지, 그리고 서명키에 대한 접근을 어떻게 다계층으로 보호했는지 공유합니다.
CloudHSM 아키텍처 개요
다음 다이어그램은 당근이 구성한 CloudHSM 기반 서명 시스템의 전체 아키텍처를 보여줍니다.

아키텍처는 크게 다음 구성 요소로 이루어져 있습니다:
- 서명 애플리케이션(Token Issuer) — Amazon EKS 클러스터 내에 위치한 Pod으로, JWT 토큰 서명을 담당합니다.
- HSM 접근 NodeGroup — CloudHSM에 접근이 허용된 전용 노드 그룹입니다.
- AWS CloudHSM 클러스터 — 다중 AZ에 걸쳐 배포된 HSM 인스턴스들입니다.
- HSM 관리 인스턴스 — HSM 담당자가 키 생성 및 관리를 위해 접속하는 전용 인스턴스입니다.
- Istio Service Mesh — 서비스 간 통신을 사이드카 프록시로 가로채 제어/관찰하는 서비스 메시로, 서명 애플리케이션에 대한 트래픽 제어를 담당합니다.
- AWS Secrets Manager — CloudHSM 접속 정보를 안전하게 보관합니다.
- Certbot CronJob — mTLS 클라이언트 인증서를 주기적으로 자동 갱신합니다.
이 아키텍처에서 접근 제어는 네트워크, 애플리케이션, HSM 내부의 세 계층에 걸쳐 설계되어 있습니다. 각 계층을 하나씩 살펴보겠습니다.
1계층: 네트워크 레벨 접근 제어
Istio를 활용한 서명 애플리케이션 접근 제어
EKS 클러스터 내에서 서명 애플리케이션(Token Issuer)에 접근하는 워크로드를 제어하기 위해 Istio의 AuthorizationPolicy를 활용했습니다. 허용 목록(allowlist) 기반으로 접근을 통제하여, Identity 관련 서버 등 당근이 명시적으로 허용한 워크로드만 Token Issuer에 요청할 수 있습니다. 허용되지 않은 워크로드는 연결 자체가 차단되며, 외부에서 위장 요청을 시도하더라도 Istio의 mTLS 기반 워크로드 인증을 통해 걸러집니다.

Security Group을 통한 CloudHSM 접근 제어
서명 애플리케이션에서 CloudHSM으로의 네트워크 접근도 별도로 제어합니다. CloudHSM 전용 보안 그룹(Security Group)을 생성하고, 이를 CloudHSM 접근이 허용된 NodeGroup과 HSM 관리 인스턴스에만 부착했습니다. 그 외 워크로드는 CloudHSM 포트(2223)에 대한 접근 자체가 불가능합니다.

mTLS 활성화
네트워크 레벨 보안을 한층 더 강화하기 위해 CloudHSM 클러스터에 mTLS(mutual TLS)를 활성화했습니다. 이를 통해 애플리케이션과 HSM 사이의 통신이 양방향 인증으로 보호됩니다. 일반적인 TLS(HTTPS) 통신에서는 클라이언트가 서버의 인증서를 검증하는 단방향 인증만 수행합니다. 즉, “내가 접속한 서버가 진짜 맞는지”만 확인하는 것이죠. mTLS는 여기서 한 단계 더 나아가, 서버도 클라이언트의 인증서를 검증합니다.
mTLS에 사용하는 클라이언트 인증서는 별도의 CronJob으로 주기적으로 자동 갱신하고 있습니다. 갱신된 인증서는 Secrets Manager에 보관하여 애플리케이션이 안전하게 가져다 쓸 수 있도록 구성했습니다.
인증서 갱신은 자동화하되, 갱신 실패가 곧 서명 장애로 이어지지 않도록 대비하는 것이 중요합니다. 인증서는 만료 전 충분한 여유를 두고 갱신하고, 남은 유효기간을 지표로 모니터링하여 임계치에 도달하면 알림을 받도록 했습니다. 갱신에 한 번 실패하더라도 기존 인증서가 만료되기 전까지는 서명이 정상 동작하므로, 그 사이에 원인을 파악하고 수동 갱신이나 롤백으로 복구할 수 있습니다. 인증서 자동 갱신이 자칫 숨은 SPOF가 되지 않도록 하는 장치입니다.

2계층: 애플리케이션 레벨 접근 제어
CloudHSM 접근 주체 분리
CloudHSM에 접근하는 주체를 세 가지로 명확히 분리하여 설계했습니다:
- HSM 담당자 — HSM 관리 인스턴스의 CLI를 통해 직접 접속합니다. 키 생성과 속성 변경이 필요할 때 ID와 Password를 stdin으로 입력하는 방식입니다.
- 일반 개발자 — CloudHSM에 접근할 수 없도록 차단합니다.
- Token Issuer(서명 애플리케이션) — Secrets Manager에 보관된 접속 정보를 가져와서, PKCS#11 규격으로 CloudHSM에 연결합니다.
CloudHSM User 설계
이 접근 주체 분리에 맞게 CloudHSM 내에 세 가지 유저를 구성했습니다. CloudHSM에는 Admin과 Crypto User라는 두 가지 Role이 있습니다. Admin은 유저를 관리하는 역할이고, Crypto User는 키를 관리하는 역할입니다.
| 유저 | Role | 역할 |
|---|---|---|
| User 관리 유저 | Admin | 키 권한 없이 유저들을 관리 |
| Key 관리 유저 | Crypto User | 키를 생성하고 키 설정을 관리 |
| Read-only 유저 | Crypto User | 키를 이용해 Signing만 수행 (Token Issuer용) |
이 세 유저에 대한 접근 권한은 다음과 같이 분리되어 있습니다:
| 유저 유형 | HSM 담당자 | 개발자 | 애플리케이션 |
|---|---|---|---|
| User 관리 유저 | O | X | X |
| Key 관리 유저 | O | X | X |
| Read-only 유저 | O | X | O |
HSM 담당자는 세 유저 모두에 접근할 수 있고, Secrets Manager에 Token Issuer 계정 정보를 넣는 권한도 갖고 있습니다. 일반 개발자는 어떤 유저에도 접근 권한이 없습니다. Token Issuer 애플리케이션은 서명 전용 Read-only Crypto User 정보만 받아서 사용합니다.
Kyverno를 활용한 Pod 레벨 보호
여기서 추가적인 보안 질문이 생깁니다. “허용되지 않은 Pod가 서명 전용 ServiceAccount Token을 탈취하거나, HSM 접근 NodeGroup에 스케줄링을 시도하면 어떻게 될까?”
당근은 Kyverno 정책을 통해 이런 시도를 Kubernetes API Server의 Validation 단계에서 사전 차단하고 있습니다. 허용된 Token Issuer Pod 이외에서는 관련 ServiceAccount Token을 요청하거나 특정 NodeGroup에 스케줄링하는 것 자체가 불가능합니다.

3계층: HSM 내부 키 레벨 접근 제어
유저 분리 외에도 키 자체의 보안 설정에 세 가지 원칙을 적용했습니다:
- Disable Extraction — Extractable 속성을 비활성화하여 Private Key가 HSM 밖으로 추출되지 않도록 했습니다. 이 설정이 적용되면 키를 외부로 내보낼 수 없습니다.
- Prevent Destruction — Destroyable 속성을 비활성화하여 키가 임의로 삭제되는 것을 방지했습니다. 키를 관리하는 유저도 함부로 해당 키를 삭제하거나 핵심 속성을 변경할 수 없습니다.
- Separate Read User with Key Owner — Key 관리 유저가 Read-only 유저에게 키를 공유(share)하는 형태로 권한을 부여했습니다. 이를 통해 Token Issuer 계정은 서명만 할 수 있고 키 설정은 변경할 수 없는 최소 권한을 보장합니다.
한 가지 주의할 점은, 이러한 키 속성과 소유권/공유 설정이 키를 생성하는 시점에 정해지며 이후 되돌리기가 어렵다는 것입니다. 예를 들어 Extractable을 비활성화한 키는 나중에 추출 가능하도록 바꿀 수 없습니다. 그래서 키를 만들기 전에 “이 키를 추출할 일이 있는가”, “누가 소유하고 누구에게 공유할 것인가”, “삭제를 허용할 것인가”를 확정하는 생성 전 체크리스트를 두는 것이 좋습니다. 잘못 설정하면 키를 폐기하고 다시 만들어야 할 수 있기 때문입니다.

접근 제어 흐름
실제로 Token Issuer가 CloudHSM에 접근하여 서명을 수행하는 전체 흐름은 다음과 같습니다:
- Token Issuer는 AWS Secrets Manager에서 CloudHSM 접속 정보를 조회합니다. 이 Secret은 HSM 접근 정보 전용 KMS 키로 암호화되어 있습니다.
- 접근 권한이 확인됩니다. SRE팀이나 Token Issuer Role이 아닌 경우에는 접근 자체가 차단됩니다.
- 조건을 통과하면 해당 Secret을 이용해 PKCS#11으로 CloudHSM에 접속합니다.

중요한 점은, 이 모든 흐름이 다음 조건을 동시에 만족해야만 동작한다는 것입니다:
- CloudHSM 접근 허용 NodeGroup에 스케줄링된 Pod여야 합니다.
- 허용된 ServiceAccount를 사용해야 합니다.
- IRSA(IAM Roles for Service Accounts; Pod가 정적 키 없이 IAM 역할 권한을 발급받는 방식)를 통해 Secrets Manager에서 접근 정보를 조회할 수 있어야 합니다.
보안 감사: AWS CloudTrail
접근 차단만으로는 충분하지 않습니다. 비정상적인 접근 시도를 탐지하고 추적하는 것도 중요합니다. AWS CloudTrail을 통해 HSM 및 HSM 관리 인스턴스에 대한 접근 기록을 지속적으로 추적하여, 키의 안전한 보관뿐만 아니라 사용 이력에 대해서도 감사를 수행하고 있습니다. 이를 통해 비정상적인 접근 시도를 사후에 추적하고, 분석 결과를 바탕으로 접근 제어 정책을 지속적으로 개선하고 있습니다.

접근 제어 전략 요약
지금까지 설명한 다계층 접근 제어 전략을 요약하면 다음과 같습니다:
| 계층 | 기술 | 목적 |
|---|---|---|
| 네트워크 | Security Group | CloudHSM 포트 접근을 허용된 NodeGroup/인스턴스로 제한 |
| 네트워크 | mTLS | 애플리케이션-HSM 간 양방향 인증 |
| 애플리케이션 | Istio AuthorizationPolicy | Token Issuer에 접근 가능한 워크로드를 허용 목록으로 제한 |
| 애플리케이션 | Kyverno Policy | 비인가 Pod의 ServiceAccount 탈취/NodeGroup 스케줄링 차단 |
| 애플리케이션 | IRSA + Secrets Manager | HSM 접속 정보를 허용된 Role에만 제공 |
| HSM 내부 | PKCS#11 User 분리 | Admin, Key 관리, Read-only 유저를 역할별로 분리 |
| HSM 내부 | Key 속성 설정 | Extractable/Destroyable 비활성화, Key 공유를 통한 최소 권한 |
| 감사 | CloudTrail | HSM 접근 기록의 지속적 추적 및 비정상 접근 탐지 |
이 다계층 구조를 통해 당근은 “Private Key가 HSM 밖으로 나오지 않도록 보장하면서, 담당자도 임의로 서명할 수 없는” 시스템을 구현했습니다.
Lessons Learned: Istio와 PKCS#11 연동
CloudHSM 도입 과정에서 중요한 교훈도 얻었습니다.
Istio Egress Gateway 연동 이슈
처음에는 Istio Egress Gateway(클러스터 외부로 나가는 트래픽을 한 곳에 모아 통제하는 관문)를 통해 HSM으로 향하는 트래픽이 Forward Proxy(요청을 대신 중계하는 서버)를 거치도록 설정했습니다. 그런데 PKCS#11 클라이언트 초기화 시 대량의 커넥션 에러가 발생했습니다. 원인은 HSM이 자체적인 TLS 방식을 사용하고 End-to-End 연결이 명확하게 관리되도록 설계되어 있어, Proxy를 경유하는 방식과 호환되지 않았기 때문입니다.

도메인 기반 HSM 목록 관리 시도와 포기
Istio에서 최소한의 메트릭을 수집하기 위해 CloudHSM의 HSM 인스턴스 목록을 도메인으로 관리하는 방식을 시도했습니다. Amazon Route 53에 CloudHSM 클러스터의 ENI IP 목록을 등록하고 CronJob으로 주기적으로 갱신하는 구조였습니다.
그러나 도메인으로 연결 시 세션이 불안정해지는 문제가 발생하여 이 방식을 포기했습니다. 현재는 AWS가 권장하는 방식인 configure-pkcs11 명령으로 cloudhsm-v2:DescribeClusters API를 호출하여 IP 목록을 확보하고 있습니다.
실제로 configure-pkcs11에 HSM IP를 하나만 등록해도 클라이언트 SDK가 클러스터 토폴로지를 통해 나머지 HSM을 자동으로 발견했고, HSM을 새로 추가했을 때도 약 1~2분 안에 자동 인식되어 별도의 Pod 변경이나 DNS 갱신이 필요하지 않았습니다. 결국 HSM 목록 관리는 SDK에 맡기는 편이 안정적이었습니다.

교훈: PKCS#11 기반의 CloudHSM 연동은 일반적인 HTTP 기반 서비스와 다른 특성이 있습니다. 프록시나 도메인 기반 라우팅 같은 일반적인 네트워크 패턴이 그대로 적용되지 않을 수 있으므로, AWS의 권장 방식을 우선적으로 따르는 것이 안정적입니다.
마무리
2부에서는 CloudHSM 아키텍처의 전체 구조와 네트워크·애플리케이션·HSM 내부의 세 계층에 걸친 접근 제어 전략을 살펴보았습니다. 특히 Istio·Kyverno·PKCS#11 User 분리·키 속성 설정 등을 조합하여 “키가 HSM 밖으로 나오지 않도록 보장하면서, 허용된 경로에서만 서명이 수행되는” 구조를 구현한 과정을 공유했습니다.
3부에서는 이 인프라 위에서 애플리케이션 레벨의 서명 시스템을 어떻게 구현했는지, 그리고 도입 과정에서 겪은 트러블슈팅과 무중단 키 전환 경험을 공유하겠습니다.