PKI 시크릿 엔진 고려 사항
PKI 시크릿 엔진 고려 사항
이 시크릿 엔진을 성공적으로 배포하려면 알아 둬야 할 중요한 고려 사항이 여러 가지 있고, 사전에 해 둬야 할 준비 단계도 있어요. 이 시크릿 엔진을 사용하거나 이 시크릿 엔진에 쓸 CA를 생성하기 전에 이 내용을 모두 읽어 주세요.
출처: 문서
본문
목차
- 루트 CA 조심히 다루기
- CA 인증서 하나, 시크릿 엔진 하나
- 키 유형이 중요하다
- CA 계층 구조 사용하기
- 클러스터 URL이 중요하다
- ACME로 회전 자동화하기
- CRL을 위해 인증서 수명을 짧게 유지하기
- 발급/CRL/OCSP 정보를 사전에 구성해야 한다
- CRL과 OCSP의 배포
- CRL 구축과 정리 자동화하기
- 폐기 지원의 스펙트럼
- 발급자 주체(subject)와 CRL
- 리프 인증서 갱신 자동화하기
- 안전한 최소값
- 토큰 수명과 폐기
- 역할의 안전한 사용
- 키 용도(Key Usage)
- 텔레메트리
- 감사(Auditing)
- 역할 기반 접근
- 복제 데이터셋(Replicated DataSets)
- 클러스터 확장성
- PSS 지원
- 발급자 스토리지 마이그레이션 문제
- 발급자 제약 시행(Issuer Constraints Enforcement)
- 튜토리얼
- API
루트 CA 조심히 다루기
Vault 스토리지는 안전하지만, 은행 금고 안의 종이만큼 안전하지는 않아요. 어쨌든 네트워크에 연결된 소프트웨어니까요. 루트 CA를 Vault 외부에 호스팅한다면, 그걸 Vault에도 넣지 마세요. 대신 수명이 더 짧은 중간 CA 인증서를 발급해 Vault에 넣는 게 좋아요. 이는 업계 모범 사례와도 일치해요.
0.4 이후부터 이 시크릿 엔진은 자체 서명된 루트 CA 생성과 중간 CA용 CSR 생성·서명을 지원해요. 보안상 이유로 개인 키는 생성 시점에만 내보낼 수 있으며, 그렇게 하는 능력 자체가 명령 경로의 일부로 취급돼요 (그래서 ACL 정책에 넣을 수 있어요).
Vault와 함께 중간 CA를 사용할 계획이라면, Vault가 CSR을 만들게 하고 개인 키를 내보내지 않은 다음, 루트 CA(pki 시크릿 엔진의 두 번째 마운트일 수 있음)로 그 CSR에 서명하는 것을 권장해요.
관리 키 (Managed keys)
1.10 이후 Vault Enterprise는 관리 키(managed key) 안의 개인 키 자료에 접근할 수 있어요. 이 경우 Vault는 개인 키를 절대 보지 못하고, 외부 KMS나 HSM이 인증서 서명 작업을 수행해요. 관리 키는 루트나 중간을 생성할 때 kms 유형을 선택해 구성해요.
CA 인증서 하나, 시크릿 엔진 하나
Vault 1.11.0부터 PKI 시크릿 엔진은 단일 마운트에서 여러 발급자(issuer)를 지원해요. 그러나 구성을 단순화하기 위해 운영자는 마운트를 단일 발급자로 제한하는 것을 강력히 권장해요. 서로 다른 여러 CA에서 인증서를 발급하고 싶다면, 각각에 별도의 CA 인증서를 둔 여러 마운트 지점에 PKI 시크릿 엔진을 마운트하세요.
마운트를 분리하는 이유는 권한 관리를 단순화하기 위해서예요. 루트로 작업을 수행할 접근이 필요한 사람은 극히 적지만, 리프를 만들 접근이 필요한 사람은 많아요. 루트에 대한 작업은 일반적으로 중간 CA의 발급과 폐기로 제한되어야 해요. 이는 매우 높은 권한의 작업이에요. 일상적인 리프 발급과 섞여 있을 때보다 별도 마운트에 있을 때 이런 작업을 감사하기가 훨씬 쉬워집니다.
일반적인 패턴은 한 마운트가 루트 CA 역할을 하고, 이 CA로 다른 PKI 시크릿 엔진의 중간 CA CSR에만 서명하는 것이에요.
기존 CA를 활성 상태로 유지하면서 회전(rotation)을 달성하는 방법은 두 가지가 있어요.
-
여러 시크릿 엔진 사용하기. 이렇게 하면 이전 발급자와 CRL을 보존하면서 새로 시작할 수 있어요. Vault ACL 정책을 갱신해 이전 마운트 지점 아래의 새 발급을 거부하고, 역할은 새 마운트 지점으로 가져오기 전에 재평가할 수 있어요.
-
같은 마운트 지점에서 여러 발급자 사용하기. 이전 발급자의 사용을 CRL 서명으로 제한할 수 있고, 기존 역할과 ACL 정책은 그대로 유지할 수 있어요. 이렇게 하면 같은 마운트 안에서 교차 서명(cross-signing)이 가능하고, 마운트의 사용자는 구성을 갱신할 필요가 없어요. 이 회전의 전환 기간이 끝나고 과거 발급 인증서가 모두 만료되면, 마운트 지점에서 이전 발급자와 불필요한 교차 서명 발급자를 완전히 제거하는 것이 좋아요.
같은 마운트에서 여러 발급자를 사용하는 또 하나의 제안된 사용 사례는 TTL 수명으로 발급을 나누는 것이에요. 단기 인증서의 경우 Vault에 저장된 중간 발급자가 HSM 기반 중간 발급자보다 성능이 좋은 경우가 많아요. 반면 장기 인증서는 종단 엔티티 인증서의 전체 수명 동안 중간 키 자료를 확보하는 것이 중요할 때가 많아요. 즉, 같은 마운트의 두 중간 발급자(하나는 HSM 백업, 하나는 Vault 백업)가 두 사용 사례를 모두 충족할 수 있어요. 운영자는 각 발급자에 최대 TTL을 설정하는 역할을 만들 수 있고, 마운트 소비자는 어느 것을 사용할지 결정할 수 있어요.
항상 기본 발급자(default issuer) 구성하기
하위 호환성을 위해 기본 발급자는 명시적 발급자 없이(경로 선택 또는 역할 기반 선택을 통해) PKI 엔드포인트를 서비스하는 데 사용돼요. 인증서가 폐기되고 그 발급자가 더 이상 이 PKI 마운트의 일부가 아니면, Vault는 그 인증서를 기본 발급자의 CRL에 올려요. 즉, 인증서 발급의 하위 호환성과 폐기된 인증서가 CRL에 들어가는 것을 보장하기 위해 기본 발급자를 유지하는 것이 중요해요.
키 유형이 중요하다
특정 키 유형은 성능에 영향을 미쳐요. RSA 키에서 인증서에 서명하는 것은 ECDSA나 Ed25519 키에서 발급하는 것보다 느려요. RSA 키를 사용한 키 생성(/issue/:role 엔드포인트)도 느려요: RSA 키 생성은 적절한 무작위 소수를 찾는 작업을 수반하지만, Ed25519 키는 무작위 데이터일 수 있어요. 비트 수가 올라갈수록(RSA 2048 → 4096 또는 ECDSA P-256 → P-521) 서명 시간도 늘어납니다.
이것은 양방향으로 중요해요: 발급이 더 비싸질 뿐 아니라, (예: TLS 핸드셰이크에서의) 해당 서명 검증도 더 비싸져요. 발급자와 발급된 키 유형을 신중히 고려하면 Vault뿐 아니라 이 인증서를 사용하는 시스템의 성능에도 의미 있는 영향을 미칠 수 있어요.
클러스터 성능과 키 유형
benchmark-vault 프로젝트를 사용해 Vault PKI 인스턴스의 성능을 측정할 수 있어요. 일반적으로 알아 둬야 할 몇 가지 고려 사항이 있어요.
- RSA 키 생성은 EC 키 생성보다 훨씬 느리고 변동성이 커요. 성능과 처리량이 필수라면 RSA 대신 EC 키(NIST P-curve와 Ed25519 포함)를 고려하세요.
- (
/pki/sign을 통한) 키 서명 요청은 (/pki/issue보다) 더 빨라요. 특히 RSA 키의 경우요: 이렇게 하면 Vault가 키 자료를 생성할 필요가 없어지고 클라이언트가 제공한 키 자료에 서명할 수 있어요. 이 서명 단계는 두 엔드포인트에 공통이므로, 클라이언트가 충분히 안전한 엔트로피 원천을 가진다면 키 생성은 순수 오버헤드예요. - CA의 키 유형도 중요해요: RSA CA를 사용하면 RSA 서명이 되고 ECDSA나 Ed25519 CA보다 시간이 더 걸려요.
- 스토리지는 중요한 요소예요: BYOC 폐기를 사용하면
no_store=true여도 인증서를 폐기할 수 있고, 감사 로그로 발급을 추적할 수 있어요. 느린 네트워크에서 원격 스토리지(Consul 같은)를 사용하고no_store=false또는no_store_cert_metadata=false로 발급 시 메타데이터를 지정하는 클러스터는 발급에 추가 지연이 생겨요. 발급된 모든 인증서에 리스를 추가하면 문제가 더 커집니다.- 너무 많은 인증서를 저장하면
LIST /pki/certs시간이 길어지고 인스턴스 정리 시간도 길어져요. 그래서 대규모 배포(활성 인증서 ≥250k)에서는 감사 로그를 사용해 Vault 외부에서 인증서를 추적하는 것을 권장해요.
- 너무 많은 인증서를 저장하면
구체화되지 않은 하드웨어의 일반적인 비교로, 로컬 단일 노드 raft 백업 Vault 인스턴스에서 benchmark-vault를 30s 동안 실행하면:
- Vault는 CA와 리프 키에 EC P-256을 사용하고 스토리지 없이 30만 개의 인증서를 발급할 수 있어요.
- 하지만 이 리프들을 저장하도록 바꾸면 그 숫자는 6.5만으로 떨어지고, 리스와 함께라면 2만 개뿐이에요.
- 크고 비싼 RSA-4096 비트 키를 사용하면, 스토리지나 리스 사용 여부와 무관하게 Vault는 160개의 리프만 발급할 수 있어요. 95% 키 생성 시간은 10초 이상이에요.
- 비교로 P-521 키를 사용하면 Vault는 리스 없이 3만 개, 리스와 함께 1.8만 개의 리프를 발급할 수 있어요.
이 숫자는 서로 다른 키 유형이 PKI 클러스터 성능에 미칠 수 있는 영향을 보여 주기 위한 예시일 뿐이에요.
ACME를 사용하면 인증서를 저장해야 하고 챌린지 검증을 수행해야 하기 때문에 이 숫자에 추가 지연이 더해져요.
CA 계층 구조 사용하기
일반적으로 계층적 CA 설정을 권장해요. 루트 인증서가 (용도에 따라) 하나 이상의 중간 인증서를 발급하고, 그 중간 인증서가 리프 인증서를 발급하는 구조예요.
이렇게 하면 Vault가 중간 CA와 리프 발급을 관리하면서도 루트 CA 보호에 더 강력한 스토리지나 정책 보증을 제공할 수 있어요. 서로 다른 중간 인증서를 서로 다른 용도로 발급할 수 있어요(예: VPN 서명, 이메일 서명, 테스트 대비 프로덕션 TLS 서비스). 이렇게 하면 CRL을 특정 목적으로 제한할 수 있어요: 예를 들어 VPN 서비스는 별도 인증서와 다른 중간을 사용한다면 이메일 서명 인증서의 폐기 집합을 신경 쓸 필요가 없고, 따라서 두 CRL 내용이 모두 필요하지 않아요. 추가로 이렇게 하면 더 높은 위험의 중간(예: 더 긴 수명의 이메일 서명 인증서를 발급하는 것)이 회전이 쉬운 중간과 인증서(예: TLS 중간)의 성능에 영향을 주지 않고 HSM 백업을 가질 수 있어요.
Vault는 역할의 allowed_domains 파라미터와 허용·제외 DNS 도메인, IP 범위, 이메일 주소, URI 도메인을 위한 파라미터 집합을 모두 지원해 루트 및 중간 생성 시 Name Constraints 확장을 설정할 수 있어요. 이렇게 하면 TLS 기반 서비스 사이에서 여러 관심사의 분리를 달성할 수 있어요.
교차 서명된 중간 (Cross-Signed intermediates)
두 개의 별도 루트에서 중간을 교차 서명할 때, Vault PKI 마운트 안에는 두 개의 별도 중간 발급자가 존재해요. 발급 요청에서 교차 서명된 체인을 올바르게 서비스하려면 두 중간 중 하나 또는 둘 다에 manual_chain 오버라이드가 필요해요. 이는 다음 순서로 구성할 수 있어요.
- 이 발급자 (
self) - 이 루트
- 이 중간의 다른 복사본
- 다른 루트
이 발급자에 대한 모든 서명 요청은 이제 전체 교차 서명 체인을 제시해요.
클러스터 URL이 중요하다
Vault 1.13에서 템플레이팅된 AIA URL 지원이 추가됐어요. 이 Performance Replication 클러스터를 가리키는 클러스터별 URL 구성을 사용하면, AIA 정보가 이 인증서를 발급한 클러스터를 자동으로 가리키게 돼요.
Vault 1.14에서 ACME 지원과 함께, 같은 구성이 ACME 클라이언트가 이 클러스터의 URL을 발견하도록 허용하는 데 사용돼요.
경고: 이 구성이 최신 상태로 올바르게 유지되어 항상 노드의 PR 클러스터 주소(로드 밸런싱 또는 DNS 라운드로빈 주소일 수 있음)를 가리키도록 보장하는 것이 중요해요. 이 구성을 모든 Performance Replication 클러스터에 설정하지 않으면 (REST 및/또는 ACME를 통한) 인증서 발급이 실패할 겁니다.
ACME로 회전 자동화하기
Vault 1.14에서 PKI 엔진에 자동 인증서 관리 환경(ACME) 프로토콜 지원이 추가됐어요. 이는 서버 인증서의 검증, 발급, 회전, 폐기를 처리하는 표준화된 방법이에요.
Caddy, Nginx, Apache 같은 웹 서버부터 cert-manager를 통한 Kubernetes 같은 오케스트레이션 환경까지 많은 생태계가 ACME 프로토콜을 통한 발급을 기본 지원해요. 기본 지원이 없는 배포에서는 certbot 같은 독립 도구가 소비자를 대신해 인증서를 가져오고 갱신하는 것을 지원해요. Vault의 PKI 엔진은 ACME의 서버 지원만 포함하며 클라이언트 기능은 포함되지 않았어요.
참고: Vault의 PKI ACME 서버는 기본적으로 인증서 유효 기간을 최대 90일로 제한하며, ACME 구성의
max_ttl파라미터로 재정의할 수 있어요. 더 짧은 유효 기간은 역할의 TTL을 전역 ACME 구성 한도 아래로 제한해 설정할 수 있어요. Let's Encrypt와 일치하게, 선택적NotBefore와NotAfter주문 요청 파라미터는 지원하지 않아요.
ACME는 인증서를 저장한다
ACME는 동작하려면 저장된 인증서가 필요하므로, 아래의 정리(tidy) 자동화에 대한 참고는 PKI 클러스터의 장기적 건강에 특히 중요해요. ACME는 또한 정리되어야 할 추가 리소스 유형(계정, 주문, 인증, 챌린지)을 도입하는데, 이는 tidy_acme=true 옵션으로 정리돼요. 주문, 인증, 챌린지는 safety_buffer 파라미터를 기준으로 정리되지만, 계정은 acme_account_safety_buffer 파라미터를 제어해 마지막으로 발급한 인증서 이후 더 오래 살 수 있어요.
위의 결과로, 그리고 클러스터 확장성 섹션의 논의처럼, 이 역할들은 no_store=false가 설정되어 있으므로 ACME는 PR 클러스터의 활성 노드에서만 인증서를 발급할 수 있어요. 스탠바이 노드에 접촉하면 모든 요청을 활성 노드로 투명하게 전달할 겁니다.
ACME 역할 제한에는 EAB가 필요하다
ACME는 기본적으로 외부 인증 엔진이 없고 Vault 관점에서 인증되지 않기 때문에, 기본 구성에서 역할과 함께 ACME를 사용하는 것은 제한된 가치가 있어요. 어떤 ACME 클라이언트든 요청된 인증서 식별자의 소유를 증명함으로써 어떤 역할 아래에서든 인증서를 요청할 수 있기 때문이에요.
이 문제를 해결하려면 두 가지 접근 방식이 있어요.
- 제한적인
allowed_roles,allowed_issuers,default_directory_policyACME 구성을 사용해 단일 역할과 발급자만 사용되게 하기. 이렇게 하면 사용자 선택을 막고 발급에 일부 전역 제한을 둘 수 있으며, ACME 클라이언트가 (초기 설정 시) Vault EAB ACME 토큰을 얻는 다른 메커니즘의 Vault 토큰에 접근할 필요가 없게 해요. eab_policy=always-required구성으로 더 관대한 구성을 사용해 더 많은 역할과 사용자에게 역할 선택을 허용하되, ACME 클라이언트를 적절히 ACL된 승인된 ACME 디렉토리 집합에 바인딩할 수 있는 Vault 토큰에 결합하기.
접근 방식의 선택은 ACME를 사용하려는 조직의 정책에 달려 있어요.
ACME 요청이 Vault 관점에서 인증되지 않는다는 또 하나의 결과로, 엔티티 정보에 기반한 역할 템플레이팅은 사용할 수 없어요. 요청과 연결된 토큰이 없으므로(EAB 바인딩을 사용해도) 엔티티가 없기 때문이에요.
ACME와 공개 인터넷
공개 인터넷에서 ACME를 사용하는 것이 가능해요. Let's Encrypt 같은 공개 CA가 이를 서비스로 제공해요. 마찬가지로 내부 PKI 인프라를 운영하는 조직은 내부 네트워크 경계 밖의 인프라 조각에 공개적으로 접근 가능한 Vault 인스턴스에서 서버 인증서를 발급하고 싶을 수 있어요. 기본적으로 제한적인 eab_policy를 시행하지 않으면 이는 복잡한 위협 모델을 만듭니다: 도메인 소유를 증명할 수 있는 모든 외부 클라이언트가 이 CA 아래에서 인증서를 발급할 수 있는데, 이는 조직이 더 신뢰할 수 있다고 여길 수 있기 때문이에요.
따라서 (HCP Vault 같은) 공개적으로 노출된 Vault 인스턴스는 PKI 마운트 운영자가 제한적인 eab_policy=always-required 구성을 요구하도록 시행하는 것을 강력히 권장해요. Vault 인스턴스의 시스템 관리자는 VAULT_DISABLE_PUBLIC_ACME=true 환경 변수를 설정해 이를 시행할 수 있어요.
ACME 오류는 서버 로그에 있다
ACME 클라이언트가 반드시 신뢰할 수 있는 것은 아니므로(EAB를 사용하지 않으면 계정 등록이 유효한 Vault 토큰과 연결되지 않을 수 있으므로), 많은 오류 메시지가 보안상의 필요로 Vault 서버 로그에 남아요. 인증서를 요청하는 클라이언트의 문제를 해결할 때는 먼저 클라이언트의 로그(있다면)를 확인하고(예: certbot은 오류 시 로그 위치를 알려 줘요), 그다음 Vault 서버 로그와 대조해 실패 원인을 식별하세요.
ACME 보안 고려 사항
ACME는 모든 클라이언트가 Vault를 사용해 어떤 종류의 외부 호출을 하게 허용해요. ACME의 설계가 이 범위를 최소화하려 하고 잘못된 서버에 접촉하면 발급을 금지하지만, 가능한 모든 원격 서버 구현을 설명할 수는 없어요. Vault의 ACME 서버는 세 가지 유형의 요청을 만들어요.
_acme-challenge.<domain>에 대한 DNS 요청 — 가장 침습적이지 않고 가장 안전해야 해요.acme-tls/1프로토콜에 대한 TLS ALPN 요청 — 애플리케이션 코드가 호출되기 전에 TLS가 안전하게 처리해야 해요.http://<domain>/.well-known/acme-challenge/<token>에 대한 HTTP 요청 — 서버 설계에 따라 문제가 될 수 있어요. 경로와 무관하게 모든 요청을 동일하게 처리하고 신뢰한다고 가정하면, Vault가 (유효하지 않은) 요청을 만드는 데 사용될 수 있어요. 이상적으로는 그러한 서버 구현을 갱신해 그러한 ACME 검증 요청을 무시하거나 이 서비스에 대한 Vault 출신 접근을 차단해야 해요.
모든 경우에 원격 서버가 제시한 응답에 대한 정보는 ACME 클라이언트에게 반환되지 않아요.
여러 네트워크에서 Vault를 실행할 때, Vault의 ACME 서버는 요청 클라이언트/대상 식별자 검증 경로에 아무 제한을 두지 않는다는 점을 기억하세요. 클라이언트가 HTTP 챌린지를 사용해 Vault가 다른 방법으로는 접근할 수 없는 네트워크의 서버에 접촉하도록 강제할 수 있어요.
ACME와 클라이언트 카운팅
Vault 1.14에서 ACME는 PKI 시크릿 엔진과의 다른 상호작용과 다르게 사용 지표에 기여해요. 인증되지 않은 요청(Vault 토큰을 생성하지 않는)을 사용하기 때문에 전통적인 활동 로그 API에 카운트되지 않아요. 대신 ACME를 통해 발급된 인증서는 고유 인증서 식별자(CN, DNS SAN, IP SAN의 조합)로 카운트됩니다. 이는 갱신, 다른 ACME 클라이언트, 마운트, 네임스페이스에 걸쳐 일관된 안정적 식별자를 만들어, 현재 활동 로그에서 해당 요청을 만든 첫 마운트에 귀속된 비엔티티 토큰으로 기여해요.
CRL을 위해 인증서 수명을 짧게 유지하기
이 시크릿 엔진은 Vault의 짧은 수명 시크릿 철학과 일치해요. 그래서 CRL이 커질 것으로 기대하지 않아요. 개인 키가 반환되는 유일한 곳은 요청한 클라이언트에게예요 (이 시크릿 엔진은 CA 인증서를 제외하고 생성된 개인 키를 저장하지 않아요). 대부분의 경우 키를 잃어버리면 인증서는 곧 만료되므로 그냥 무시하면 돼요.
인증서를 정말로 폐기해야 한다면 일반 Vault 폐기 기능을 사용할 수 있고, 어떤 폐기 작업이든 CRL을 재생성하게 돼요. CRL이 재생성되면 만료된 인증서는 CRL에서 제거되고(폐기·만료된 인증서는 시크릿 엔진 스토리지에서 제거돼요). 이는 비싼 작업이에요! CRL 표준의 구조 때문에 Vault는 CRL을 재구축하기 위해 모든 폐기 인증서를 메모리로 읽어야 하고, 클라이언트는 재생성된 CRL을 가져와야 해요.
이 시크릿 엔진은 슬라이딩 날짜 창이 있는 여러 CRL 엔드포인트를 지원하지 않아요. 종종 그러한 메커니즘은 몇 일 간격으로 전환 지점을 갖지만, 이는 이 시크릿 엔진에서 발급된 실제 인증서 유효 기간의 예상 범위에 들어가요. 이 시크릿 엔진의 좋은 경험 법칙은 단순히 편안한 CRL 수명보다 큰 유효 기간의 인증서를 발급하지 않는 것이에요. 또는 클라이언트의 CRL 캐싱 동작을 제어해 확인을 더 자주 하게 할 수 있어요.
종종 단일 CRL 엔드포인트가 다운됐을 때 여러 엔드포인트가 사용돼 클라이언트가 응답 부재를 어떻게 처리할지 고민하지 않게 해요. Vault를 HA 모드로 실행하면 특정 노드가 다운돼도 CRL 엔드포인트를 사용할 수 있어야 해요.
참고: Vault 1.11.0부터 같은 마운트 지점의 여러 발급자는 (주체와 키 자료에 따라) 서로 다른 CRL을 가질 수 있어요. 즉 Vault가 여러 CRL을 재생성해야 할 수 있어요. 이는 다시 TTL을 짧게 유지하고 가능하면 폐기를 피해야 하는 근거가 돼요.
참고: Vault 1.12.0부터 두 가지 보완적인 폐기 메커니즘을 지원해요: 마지막 완전 CRL에 대한 더 작고 점진적인 추가분의 재구축을 허용하는 델타 CRL(Delta CRLs)과, 개별 인증서에 대한 폐기 상태 요청에 응답할 수 있는 OCSP예요. 새로운 CRL 자동 재구축 기능과 결합하면, (CRL이 매 폐기마다 항상 재구축되지는 않으므로) 스토리지 고려 사항을 제외하면 폐기 단계가 그렇게 비싸지 않아요. 그러나 많은 인증서가 있을 때 재구축 작업은 여전히 비쌀 수 있지만, 온디맨드가 아니라 스케줄에 따라 수행될 겁니다.
리프 인증서의 NotAfter 동작
Vault 1.11.0에서 PKI 시크릿 엔진은 발급자에 새 leaf_not_after_behavior 파라미터를 도입했어요. 이는 발급 동작을 수정할 수 있게 해요: Vault가 err(발급자보다 더 긴 수명의 리프 인증서 발급을 방지), 발급자의 NotAfter 값으로 조용히 truncate, 또는 더 긴 만료를 permit 해야 하는지요.
중간 발급자에는 err 또는 truncate를 사용할 것을 강력히 권장해요. permit는 루트 인증서에만 유용한데, 제시된 체인을 검증할 때 중간의 NotAfter 만료가 확인되기 때문이에요.
더 긴 수명의 루트(아마 210년 범위), 더 짧은 수명의 중간(아마 6개월2년), 짧은 수명의 리프 인증서(30~90일 범위)의 계단식 만료와 결합하면, 그리고 다른 섹션에서 논의한 회전 전략과 함께 CRL을 적절히 작게 유지할 수 있어요.
클러스터 성능과 리프 인증서 수량
위에서 언급했듯이, TTL을 짧게 유지하거나(no_store=true와 no_store_cert_metadata=true 사용) 리스를 피하는 것은 건강한 클러스터에 중요해요. 그러나 이는 규모의 문제라는 점을 기억하는 것이 중요해요: 101000개의 장기 수명의 저장된 인증서는 아마 괜찮지만, 5만10만 개는 문제가 되고 50만 개 이상의 저장·미만료 인증서는 짧은 TTL임에도 불구하고 큰 Vault 클러스터에도 부정적 영향을 줄 수 있어요!
그러나 이 인증서들이 만료되면 정리(tidy) 작업이 CRL과 Vault 클러스터 스토리지의 정리를 수행해요.
인증서 손상에 대한 조직 위험 평가 때문에 특정 인증서 유형은 항상 no_store=false로 발급해야 할 수 있다는 점을 기억하세요. 심지어 짧은 수명의 광범위한 와일드카드 인증서(예: *.example.com)도 폐기를 정밀하게 제어할 만큼 중요할 수 있어요. 그러나 범위가 잘 지정된 인증서를 가진 내부 서비스(예: service.example.com)는 위험이 충분히 낮아 no_store=true로 90일 TTL을 발급해 손상의 드문 경우에 폐기할 필요를 막을 수 있어요.
TTL을 더 짧게 하면 인증서를 폐기해야 할 가능성은 줄어들지만(완전히 막지는 못함) 그러한 손상의 영향을 줄여요.
참고: Vault 1.12부터 PKI 시크릿 엔진의 Bring-Your-Own-Cert (BYOC) 기능은 이전에 저장되지 않은(예:
no_store=true역할로 발급된) 인증서의 폐기를 허용해요. 즉, 발급된 인증서의 중요성(및 폐기 가능성)과 무관하게no_store=true설정이 이제 안전하게 전역으로 사용될 수 있어요.
발급/CRL/OCSP 정보를 사전에 구성해야 한다
이 시크릿 엔진은 예측 가능한 위치에서 CRL을 서비스하지만, 시크릿 엔진이 어디서 실행 중인지 알 수는 없어요. 따라서 발급 인증서, CRL 배포 지점, OCSP 서버에 대한 원하는 URL을 config/urls 엔드포인트를 사용해 수동으로 구성해야 해요. 여러 URL을 쉼표로 구분된 문자열 파라미터로 전달해 각각을 하나 이상 가질 수 있어요.
참고: PKI 시크릿 엔진 마운트와 함께 Vault Enterprise의 Performance Replication 기능을 사용할 때, 각 클러스터는 자체 CRL을 가져요. 즉 각 클러스터의 고유 CRL 주소를 AIA 정보 필드에 별도로 포함시키거나, CRL을 통합해 Vault 외부에서 서비스해야 해요.
참고: 같은 마운트에서 여러 발급자를 사용할 때는 전역(
/config/urls) 변형보다 발급자별 AIA 필드를 사용하는 것을 권장해요. 정확성 때문이에요: 이 필드는 특정 애플리케이션의 체인 구축과 자동 CRL 감지에 사용돼요. 잘못된 발급자의 정보를 가리키면 애플리케이션이 깨질 수 있어요.
CRL과 OCSP의 배포
CRL과 OCSP 모두 인증서의 폐기 상태를 조회할 수 있게 해요. 두 방법 모두 내부 보안과 진위성(CRL과 OCSP 응답 모두 Vault 안의 발급 CA가 서명)을 포함해요. 즉 둘 다 HTTP 같은 비보안·비인증 채널로 배포해도 괜찮아요.
참고: GET 요청의 OCSP 구현은 인코딩된 OCSP 요청에 연속된 '/' 문자가 포함되면 간헐적 400 오류를 일으킬 수 있어요. 이 문제가 해결될 때까지는 POST 기반 OCSP 요청을 사용하는 것을 권장해요.
CRL 구축과 정리 자동화하기
Vault 1.12부터 PKI 시크릿 엔진은 /config/crl 엔드포인트를 통해 자동 CRL 재구축(완전 CRL보다 더 자주 구축할 수 있는 선택적 델타 CRL 포함)을 지원해요. 또한 /config/auto-tidy 엔드포인트를 통해 폐기·만료 인증서의 정리를 자동 구성할 수 있어요. 더 넓은 PKIX 생태계와의 호환성과 클러스터 성능을 보장하려면 둘 다 활성화해야 해요.
폐기 지원의 스펙트럼
Vault 1.13부터 PKI 시크릿 엔진은 다양한 클러스터 크기와 인증서 폐기 수량의 스펙트럼을 지원할 수 있어요.
폐기가 적거나 통합된 보기를 원하고 이를 지원할 인터클러스터 대역폭이 있는 사용자는 CRL 자동 재구축, 크로스 클러스터 폐기 큐, 크로스 클러스터 CRL을 켜는 것을 권장해요. 이렇게 하면 CRL의 모든 소비자가 어느 클러스터에 말하든 폐기에 대한 가장 정확한 그림을 가질 수 있어요.
통합 CRL이 기본 스토리지 메커니즘에 너무 커지거나 단일 호스트가 구축하기에 너무 커지면, CRL 대신 OCSP에 의존하는 것을 권장해요. OCSP는 스토리지 항목이 훨씬 작고, CRL disabled 플래그는 unified_crls와 독립적이라 통합 OCSP를 유지할 수 있어요.
그러나 크로스 클러스터 트래픽이 너무 높아지면(또는 OCSP 외에 여전히 CRL이 필요하면), 서로 다른 클러스터 간에 CRL을 샤딩하는 것을 권장해요. 이는 Vault의 기본 동작이었지만, 클러스터별 템플레이팅된 AIA 정보의 도입으로 리프 인증서의 Authority Information Access (AIA) 정보가 발급한 클러스터를 직접 가리켜 애플리케이션이 이 인증서의 올바른 CRL을 식별할 수 있게 됐어요. 이는 Let's Encrypt의 CRL 샤딩 동작을 더 정확히 모방해요.
폐기 항목의 크로스 클러스터 트래픽이 너무 높아지면 이 샤딩 동작을 OCSP에도 사용할 수 있어요.
폐기를 수동으로 관리하려는 사용자는 감사 로그로 인증서 발급을 추적해 외부 시스템이 어떤 인증서가 발급됐는지 식별하게 할 수 있어요. 이들은 폐기를 수동으로 추적할 수 있고, 외부에서 추적된 폐기를 사용해 사용자 정의 CRL을 구축할 수 있어요. 이렇게 하면 no_store=true로 설정된 역할을 사용할 수 있어 Vault는 엄격히 발급 기관으로만 사용되고 발급·폐기된 어떤 인증서도 저장하지 않아요. 가장 높은 폐기 규모에는 이 옵션이 최선일 수 있어요.
특히 이 마지막 접근 방식은 외부 저장된 통합 또는 샤딩된 CRL 생성에 사용될 수 있어요. 단일 외부 통합 CRL이 비합리적으로 커지면, 각 클러스터의 인증서 AIA 정보가 외부에 저장·유지되는 샤딩된 CRL을 가리킬 수 있어요. 그러나 Vault는 현재 OCSP 요청에 서명할 메커니즘이 없어요.
크로스 클러스터 CRL이란?
Vault Enterprise는 Performance Replication이라는 클러스터링 모드를 지원해요. 복제된 PKI 시크릿 엔진 마운트에서 발급자와 역할 정보는 Performance Primary와 모든 Performance Secondary 클러스터 간에 동기화돼요. 그러나 각 Performance Secondary 클러스터는 동기화되지 않는 발급된 인증서와 폐기의 자체 로컬 스토리지를 가져요. Vault 1.13 이전 버전에서는 이로 인해 각 클러스터가 자체 CRL과 OCSP 데이터를 가졌고, 폐기 요청은 발급한 클러스터에서 처리되어야 했어요(또는 BYOC를 사용).
Vault 1.13부터 이 설정을 더 정확하고 쉽게 관리하도록 두 가지 기능을 Vault Enterprise에 추가했어요: 폐기 요청 큐(config/crl의 cross_cluster_revocation=true)와 통합 폐기 항목(config/crl의 unified_crl=true).
전자는 운영자가(시리얼 번호로 폐기) 어느 클러스터에서 발급됐는지와 무관하게 인증서가 폐기되도록 요청할 수 있게 해요. 예를 들어 요청이 Performance Primary에 들어갔는데 그곳에서 인증서를 발급하지 않았다면, 크로스 클러스터 폐기 요청을 쓰고 결과를 pending으로 표시해요. 다른 클러스터가 이 인증서를 이미 스토리지에 갖고 있으면 폐기하고 메인 클러스터로 폐기를 확인해요. 운영자는 pending 폐기 목록을 통해 이 요청들의 상태를 볼 수 있어요. 유효하지 않은 요청(예: 그 인증서가 있던 클러스터가 사라졌거나, 그 인증서가 역할에 no_store=true로 발급됐거나, 유효하지 않은 시리얼 번호라면)을 정리하기 위해 운영자는 tidy_revocation_queue=true로 tidy를 사용하고, 선택적으로 revocation_queue_safety_buffer를 줄여 더 빨리 제거할 수 있어요.
후자는 모든 클러스터가 폐기의 통합된 보기를 갖게 해요. 즉 다른 클러스터가 수행한 폐기 목록에 접근할 수 있게 해요. 구성 파라미터 설명에 crl이 포함되어 있지만, 이는 CRL과 OCSP 응답자 모두에 적용돼요. 이 폐기 복제가 발생하면, 어느 클러스터가 인증서를 폐기된 것으로 간주하는데(예: no_store=false 인증서의 BYOC 폐기로) 다른 클러스터가 그렇지 않다면, 모든 클러스터가 만료되지 않았다면 이제 모든 클러스터가 그 인증서를 폐기된 것으로 간주해요. 특히 프라이머리 클러스터의 활성 노드가 CRL을 재구축하는 데 사용돼요. 많은 클러스터에 많은 폐기 인증서가 있으면 커질 수 있으므로, 운영자는 CRL 구축을 비활성화하거나(config/crl의 disabled=true) 스토리지 크기를 늘려야 할 수 있어요.
덧붙여, 모든 새 크로스 클러스터 쓰기(Performance Secondary에서 Performance Primary로)는 동기적으로 수행돼요. 이렇게 하면 호출자에게 요청이 실제로 통과했다는 확신을 주지만, 인증서 폐기의 오버헤드가 조금 더 높아져요. 노드가 GRPC 연결을 잃으면(예: 리더십 선거 중이거나 활성 프라이머리에 연락할 수 없을 때) 로컬 부분의 쓰기(있다면)는 여전히 성공하지만 오류가 발생할 겁니다. 크로스 클러스터 폐기 요청의 경우 로컬 쓰기가 없으므로 작업을 재시도해야 하지만, 인증서가 로컬에 존재할 때 크로스 클러스터 폐기 항목을 쓰는 데 문제가 있으면 연결이 복구될 때 폐기가 결국 클러스터 전체에 동기화될 겁니다.
발급자 주체(subject)와 CRL
여러 GitHub 이슈에 언급된 대로, Go의 x509 라이브러리는 인증서 주체에 대해 의견이 있는(opinionated) 파싱과 구조화 메커니즘을 가지고 있어요. Vault 안에서 생성된 발급자는 괜찮지만, 외부에서 생성된 CA 인증서를 사용할 때 PKI의 모든 부분에서 올바르게 파싱되지 않을 수 있어요. 특히 CRL은 발급자 이름의 (수정된) 복사본을 포함해요. 폐기를 추적하려면 OCSP를 사용해 이를 피할 수 있지만, OCSP와 CRL의 성능 특성은 다르다는 점을 기억하세요.
참고: Go 1.20과 Vault 1.13부터 Go는 CRL의 발급자 이름을 올바르게 형식화하며 이 공지는 적용되지 않아요.
리프 인증서 갱신 자동화하기
규모에 맞게 서비스 인증서를 관리하려면 인증서 갱신을 최대한 자동화하는 것이 가장 좋아요. Vault Agent는 validTo 필드에 기반해 요청된 인증서를 자동으로 갱신하는 것을 지원해요. 다른 해결책으로는 Vault CA 기반의 Kubernetes나 OpenShift에서 cert-manager를 사용하는 것이 있어요.
안전한 최소값 (Safe minimums)
이 시크릿 엔진은 시작부터 SHA1이 아니라 서명 해시에 SHA256을 시행했어요. 0.5.1부터 RSA 키에 최소 2048비트도 시행돼요. SHA256 서명을 처리할 수 있는 소프트웨어는 2048비트 키도 처리할 수 있어야 하고, 1024비트 키는 안전하지 않은 것으로 간주되어 인터넷 PKI에서 허용되지 않아요.
토큰 수명과 폐기
토큰이 만료되면 그와 연결된 모든 리스가 폐기돼요. 즉 수명이 긴 CA 인증서는 그에 상응하는 수명이 긴 토큰이 필요하며, 이는 잊기 쉬운 점이에요. 0.6부터 루트와 중간 CA 인증서는 더 이상 연결된 리스가 없어, 충분히 긴 수명의 토큰을 사용하지 않을 때 의도치 않은 폐기를 막아요. 이 인증서들을 폐기하려면 pki/revoke 엔드포인트를 사용하세요.
역할의 안전한 사용
Vault PKI 시크릿 엔진은 역할(Roles)을 통해 발급을 제한하는 많은 옵션을 지원해요. 필요한 것보다 더 많은 권한이 주어지지 않도록 구성을 신중히 고려해야 해요. 또한 역할은 일반적으로 한 가지 일을 해야 해요. 임의 발급을 허용하는 너무 관대한 역할(예: allow_any_name은 보통 아껴서 사용해야 함)보다 여러 역할이 바람직해요.
allow_any_name은 일반적으로false로 설정해야 해요. 이것이 기본값이에요.- 프로덕션 서비스에서는
localhost에서 수신할 것이 기대되지 않는 한,allow_localhost을 일반적으로false로 설정해야 해요. - 필요하지 않으면
allow_wildcard_certificates를 일반적으로false로 설정해야 해요. 하위 호환성 문제 때문에 이것은 기본값이 아닙니다.- 특히
allow_subdomains또는allow_glob_domains가 활성화될 때 필요해요.
- 특히
enforce_hostnames은 TLS 서비스에 일반적으로 활성화해야 해요. 이것이 기본값이에요.- IP 인증서가 명시적으로 필요하지 않은 한,
allow_ip_sans을 일반적으로false로 설정해야 해요 (기본값은true예요). - 짧은 TTL(<30일)을 사용하거나 발급량이 많을 때는
no_store를true로 설정하는 것이 일반적으로 권장돼요 (기본값은false). 이렇게 하면 시리얼 번호 기반 폐기를 막지만, Vault가 더 이상 모든 발급 인증서를 저장할 필요가 없으므로 더 높은 처리량을 허용해요. 이에 대한 자세한 논의는 아래 복제 데이터셋 섹션에서 해요. - 루트 인증서(
issuer_ref)와 함께 역할을 사용하지 마세요. 루트 인증서는 일반적으로 역할에 의존하지 않는 중간 인증서만 발급해야 해요 (위의 CA 계층 구조 섹션 참고). key_usage와ext_key_usage를 제한하세요. 모든 목적에 모든 용도를 허용하려 하지 마세요. 일반적으로 기본값은 클라이언트와 서버 TLS 인증에 유용해요.
키 용도 (Key Usage)
key_usage와 ext_key_usage 필드는 인증서 사용을 특정 목적으로 제한하는 데 사용돼요. 예를 들어 인증서를 클라이언트 인증, 서버 인증, 코드 서명에만 사용하도록 제한할 수 있어요. Vault는 RFC #5280을 구현하며, 이는 생성된 키 용도 확장이 critical로 표시되고 무시할 수 없음을 의미해요.
텔레메트리 (Telemetry)
Vault의 요청 처리에 대한 기본 텔레메트리 외에, PKI는 issue, sign, sign-verbatim, revoke 호출에 대한 카운트와 지속 시간 지표를 노출해요. 지표 키는 mount-path,operation,[failure] 형태를 가지며 네임스페이스와 역할 이름 라벨을 가져요.
이 지표들은 노드별이므로 노드와 클러스터 전체에 걸쳐 집계해야 한다는 점을 기억하세요.
감사 (Auditing)
Vault는 기본적으로 감사 문자열 키를 HMAC하므로, 이 마운트 아래에서 발생하는 발급을 정확히 보려면 PKI 시크릿 마운트를 튜닝해야 해요.
참고: Vault 사용에 따라 CRL(그리고 드물게 CA 체인)이 꽤 커질 수 있어요. 이런 이유로
crl필드의 un-HMAC을 권장하지 않지만, 아래 권장 사항은/pki/cert/crlAPI 엔드포인트를 통해 CRL이 서비스될 수 있는certificate응답 파라미터의 un-HMAC을 제안한다는 점을 기억하세요. 또한http_raw_body는 CRL을 PEM과 원시 바이너리 DER 두 형태로 반환할 수 있으므로, 그 필드는 로그 형식을 손상시키지 않도록 un-HMAC 하지 않는 것이 좋아요.
이것을 syslog 감사 디바이스로만 하면, Vault는 서버에서 작업을 수행한 후 메시지를 로그할 수 없어 (불투명한 500 Internal Error 메시지와 함께) 요청을 거부할 수 있어요.
제안된 해결책은 certificate와 crl 응답 필드를 HMAC된 채로 두거나, file 감사 로그 유형도 활성화하는 것이에요.
요청에 대해 un-HMAC 하도록 제안된 몇 가지 키는 다음과 같아요.
csr— 서명할 요청된 CSRcertificate— 다시 서명할 요청된 자체 서명 인증서 또는 발급자 가져올 때- 다양한 발급 관련 재정의 파라미터. 예:
issuer_ref— 이 인증서에 서명하도록 요청된 발급자common_name— 요청된 공통 이름alt_names— 이 인증서에 대한 대체 요청 DNS 유형 SANother_sans— 이 인증서에 대한 기타(비-DNS, 비-이메일, 비-IP, 비-URI) 요청 SANip_sans— 이 인증서에 대한 요청 IP 유형 SANuri_sans— 이 인증서에 대한 요청 URI 유형 SANttl— 이 인증서의 요청 만료 날짜not_after— 이 인증서의 요청 만료 날짜serial_number— 주체의 요청 시리얼 번호key_type— 요청 키 유형private_key_format— 요청 키 형식 (공개 인증서 형식에도 사용됨)
- 다양한 역할·발급자 관련 생성 파라미터. 예:
managed_key_name— 발급자 생성 시 요청 관리 키 이름managed_key_id— 발급자 생성 시 요청 관리 키 식별자ou— 주체의 조직 단위organization— 주체의 조직country— 주체의 국가 코드locality— 주체의 지역province— 주체의 주/도street_address— 주체의 거리 주소postal_code— 주체의 우편번호permitted_dns_domains— 허용 DNS 도메인permitted_ip_ranges— 허용 IP 범위permitted_email_addresses— 허용 이메일 주소permitted_uri_domains— 허용 URI 도메인excluded_dns_domains— 제외 DNS 도메인excluded_email_addresses— 제외 이메일 주소excluded_ip_ranges— 제외 IP 범위excluded_uri_domains— 제외 URI 도메인policy_identifiers— 역할 생성 시 요청 정책 식별자ext_key_usage_oids— 요청 인증서의 확장 키 용도 OID
응답에 대해 un-HMAC 하도록 제안된 몇 가지 키는 다음과 같아요.
certificate— 발급된 인증서issuing_ca— 요청 인증서를 발급한 CA의 인증서serial_number— 발급된 인증서의 시리얼 번호error— 요청과 관련된 오류 표시ca_chain— 노이즈 때문에 선택적; 요청 인증서 발급자의 전체 CA 체인
참고: un-HMAC 할 파라미터 목록은 제안일 뿐이며 완전하지 않을 수 있어요.
다음 키는 민감한 특성 때문에 un-HMAC 하지 않는 것이 좋아요.
private_key— 이 응답 파라미터는 발급 중 Vault가 생성한 개인 키를 포함해요pem_bundle— 이 요청 파라미터는 발급자 가져오기 경로에서만 사용되며 민감한 개인 키 자료를 포함할 수 있어요
역할 기반 접근 (Role-Based access)
Vault는 Vault 안의 다양한 경로에 대한 접근 제한을 위해 경로 기반 ACL 정책을 지원해요.
다음은 PKI 시크릿 엔진을 ACL 하는 방법의 간결한 예시 참조예요. 이는 제안일 뿐이며, 다른 페르소나와 정책 접근 방식도 유효할 수 있어요.
다음 페르소나를 제안해요.
- Operator — PKI 하위 시스템의 건강을 관리하는 특권 사용자; 발급자와 키 자료를 관리해요.
- Agent — 운영자를 대신해 역할을 관리하고 폐기를 처리하는 반특권 사용자; 위임 발급도 처리할 수 있어요. administrator 또는 role manager라고도 불릴 수 있어요.
- Advanced — 추가 발급 API에 접근할 수 있는 파워유저 또는 서비스일 수 있어요.
- Requester — 단순히 인증서를 요청하는 낮은 수준의 사용자 또는 서비스.
- Unauthed — Vault 토큰이 없는 임의 사용자 또는 서비스.
이 페르소나들에 대해 다음 ACL을 간결한 표 형식으로 제안해요. (표의 열은 경로 / 작업 / Operator / Agent / Advanced / Requester / Unauthd 순서예요.)
| 경로 | 작업 | Operator | Agent | Advanced | Requester | Unauthd |
|---|---|---|---|---|---|---|
/ca(/pem)? |
Read | 예 | 예 | 예 | 예 | 예 |
/ca_chain |
Read | 예 | 예 | 예 | 예 | 예 |
/crl(/pem)? |
Read | 예 | 예 | 예 | 예 | 예 |
/crl/delta(/pem)? |
Read | 예 | 예 | 예 | 예 | 예 |
/cert/:serial(/raw(/pem)?)? |
Read | 예 | 예 | 예 | 예 | 예 |
/issuers |
List | 예 | 예 | 예 | 예 | 예 |
/issuer/:issuer_ref/(json|der|pem) |
Read | 예 | 예 | 예 | 예 | 예 |
/issuer/:issuer_ref/crl(/der|/pem)? |
Read | 예 | 예 | 예 | 예 | 예 |
/issuer/:issuer_ref/crl/delta(/der|/pem)? |
Read | 예 | 예 | 예 | 예 | 예 |
/ocsp/<request> |
Read | 예 | 예 | 예 | 예 | 예 |
/ocsp |
Write | 예 | 예 | 예 | 예 | 예 |
/certs |
List | 예 | 예 | 예 | 예 | |
/revoke-with-key |
Write | 예 | 예 | 예 | 예 | |
/roles |
List | 예 | 예 | 예 | 예 | |
/roles/:role |
Read | 예 | 예 | 예 | 예 | |
/(issue|sign)/:role |
Write | 예 | 예 | 예 | 예 | |
/issuer/:issuer_ref/(issue|sign)/:role |
Write | 예 | 예 | 예 | ||
/config/auto-tidy |
Read | 예 | 예 | |||
/config/ca |
Read | 예 | 예 | |||
/config/crl |
Read | 예 | 예 | |||
/config/issuers |
Read | 예 | 예 | |||
/crl/rotate |
Read | 예 | 예 | |||
/crl/rotate-delta |
Read | 예 | 예 | |||
/roles/:role |
Write | 예 | 예 | |||
/issuer/:issuer_ref |
Read | 예 | 예 | |||
/sign-verbatim(/:role)? |
Write | 예 | 예 | |||
/issuer/:issuer_ref/sign-verbatim(/:role)? |
Write | 예 | 예 | |||
/revoke |
Write | 예 | 예 | |||
/tidy |
Write | 예 | 예 | |||
/tidy-cancel |
Write | 예 | 예 | |||
/tidy-status |
Read | 예 | 예 | |||
/config/auto-tidy |
Write | 예 | ||||
/config/ca |
Write | 예 | ||||
/config/crl |
Write | 예 | ||||
/config/issuers |
Write | 예 | ||||
/config/keys |
Read, Write | 예 | ||||
/config/urls |
Read, Write | 예 | ||||
/issuer/:issuer_ref |
Write | 예 | ||||
/issuer/:issuer_ref/revoke |
Write | 예 | ||||
/issuer/:issuer_ref/sign-intermediate |
Write | 예 | ||||
/issuer/issuer_ref/sign-self-issued |
Write | 예 | ||||
/issuers/generate/+/+ |
Write | 예 | ||||
/issuers/import/+ |
Write | 예 | ||||
/intermediate/generate/+ |
Write | 예 | ||||
/intermediate/cross-sign |
Write | 예 | ||||
/intermediate/set-signed |
Write | 예 | ||||
/keys |
List | 예 | ||||
/key/:key_ref |
Read, Write | 예 | ||||
/keys/generate/+ |
Write | 예 | ||||
/keys/import |
Write | 예 | ||||
/root/generate/+ |
Write | 예 | ||||
/root/sign-intermediate |
Write | 예 | ||||
/root/sign-self-issued |
Write | 예 | ||||
/root/rotate/+ |
Write | 예 | ||||
/root/replace |
Write | 예 |
참고: 관리 키를 사용하면 운영자는 마운트 지점의 튜너블 데이터를 읽을 접근(
/sys/mounts에 대한 Read)과 관리 키를 사용하거나 관리할 접근이 필요할 수 있어요.
복제 데이터셋 (Replicated DataSets)
Performance Secondary 클러스터로 운영할 때, 일부 데이터셋은 모든 클러스터에 걸쳐 유지되고 다른 것은 성능과 확장성 이유로 주어진 클러스터 안에 유지돼요.
다음 표는 어떤 데이터셋이 클러스터 경계를 넘을지 데이터 유형별로 나눠요. 클러스터 경계를 넘지 않는 데이터 유형의 경우, 해당 데이터에 대한 읽기 요청은 데이터가 생성된 적절한 클러스터로 보내야 해요.
| 데이터셋 | 클러스터 간 복제 |
|---|---|
| 발급자 & 키 (Issuers & Keys) | 예 |
| 역할 (Roles) | 예 |
| CRL 구성 (CRL Config) | 예 |
| URL 구성 (URL Config) | 예 |
| 발급자 구성 (Issuer Config) | 예 |
| 키 구성 (Key Config) | 예 |
| CRL | 아니요 |
| 폐기 인증서 (Revoked Certificates) | 아니요 |
| 리프/발급 인증서 (Leaf/Issued Certificates) | 아니요 |
| 인증서 메타데이터 (Certificate Metadata) | 아니요 |
주요 효과는 PKI 시크릿 엔진 안에서 no_store가 false로 설정되어 발급된 리프 인증서가 발급한 클러스터에 로컬로 저장된다는 것이에요. 이는 프라이머리와 Performance Secondary 클러스터의 활성 노드 모두 인증서를 발급해 더 큰 확장성을 얻을 수 있게 해요. 결과적으로 이 인증서들, 메타데이터, 폐기 내용은 발급 클러스터에서만 보여요. 이는 또한 각 클러스터가 다른 클러스터와 구별되는 자체 CRL 집합을 가짐을 의미해요. 이 CRL들은 단일 URI에서 배포하기 위해 단일 CRL로 통합하거나, 서버 운영자가 모든 클러스터의 모든 CRL을 가져와야 한다는 것을 알아야 해요.
클러스터 확장성 (Cluster scalability)
PKI 시크릿 엔진의 대부분의 비-인트로스펙션 작업은 스토리지에 쓰기가 필요하므로 실행을 위해 클러스터의 활성 노드로 전달돼요. 이 표는 어떤 작업이 performance standby 노드에서 실행될 수 있어 클러스터 안의 모든 노드에 걸쳐 수평 확장되는지 설명해요.
| 경로 | 작업 |
|---|---|
ca[/pem] |
Read |
cert/*serial-number* |
Read |
cert/ca_chain |
Read |
config/crl |
Read |
certs |
List |
ca_chain |
Read |
crl[/pem] |
Read |
issue |
Update * |
revoke/*serial-number* |
Read |
sign |
Update * |
sign-verbatim |
Update * |
- 해당 역할에
no_store가 true로 설정되고,generate_lease가 false이고, 기록되는 메타데이터가 없을 때만.generate_lease가 true면 리스 생성은 활성 노드로 전달되고,no_store가 false면 전체 요청이 활성 노드로 전달돼요.no_store_cert_metadata=false이고metadata인자가 제공되면 전체 요청이 활성 노드로 전달돼요.
PSS 지원
Go는 rsaPSS OID(1.2.840.113549.1.1.10)를 사용하는 PSS 인증서, 키, CSR을 지원하지 않아요. 모든 RSA 인증서, 키, CSR이 대체 rsaEncryption OID(1.2.840.113549.1.1.1)를 사용하도록 요구해요.
OpenSSL로 PKCS8 인코딩된 PSS 키에서 CA나 CSR을 생성하면 결과 CA와 CSR은 rsaPSS OID를 가져요. Go와 Vault는 이를 거부해요. 대신 OpenSSL을 사용해 PKCS#1v1.5 개인 키 파일을 생성하거나 변환하고, 이를 사용해 CSR을 생성하세요. Vault는 역할과 서명 메커니즘에 따라 요청의 SubjectPublicKeyInfo와 SignatureAlgorithm 필드가 직교하므로 요청의 rsaEncryption OID에도 불구하고 여전히 PSS 서명을 사용할 수 있어요. 외부 CA를 만들어 Vault로 가져올 때는 SignatureAlgorithm이 PSS 기반이더라도 SubjectPublicKeyInfo 필드에 rsaEncryption OID가 있는지 확인하세요.
Go가 생성한 이 인증서들(rsaEncryption OID이지만 PSS 기반 서명)은 그 외에는 완전한 PSS 기반 인증서와 호환돼요. OpenSSL과 NSS는 이 유형의 인증서를 사용한 체인 파싱과 검증을 지원해요. 일부 TLS 구현은 rsa_pss_rsae_* 서명 체계를 지원하지 않으면 이 유형의 인증서를 지원하지 않을 수 있다는 점을 기억하세요. 또한 일부 구현은 rsaPSS OID 인증서가 이 인증서가 허용하는 서명 파라미터에 대한 제한을 포함하게 허용하지만, Go와 Vault는 그러한 제한 추가를 지원하지 않아요.
현재 Go는 PSS 서명 알고리즘으로 CSR에 서명하는 것을 지원하지 않아요. 중간 CA 키의 백업으로 RSA PSS 알고리즘을 요구하는 관리 키(GCP나 PKCS#11 HSM 같은)를 사용한다면, (pki/intermediate/generate/kms를 통한) CSR 생성 시도는 서명 검증에 실패할 겁니다. 이 경우 CSR은 Vault 외부에서 생성해야 하고, 서명된 최종 인증서는 마운트로 가져올 수 있어요.
Go는 또한 PSS 서명 알고리즘으로 OCSP 응답 생성을 지원하지 않아요. Vault는 PSS 기반 폐기 서명 알고리즘을 가진 발급자를 PKCS#1v1.5로 자동 다운그레이드하지만, 일부 KMS 디바이스(HSM과 GCP 같은)는 같은 키로 이를 지원하지 않을 수 있다는 점을 기억하세요. 결과적으로 OCSP 응답자는 응답 서명에 실패해 내부 오류를 반환할 수 있어요.
발급자 스토리지 마이그레이션 문제
Vault가 1.11.6, 1.12.2, 1.13 이전 릴리스의 새 다중 발급자 스토리지 레이아웃으로 마이그레이션할 때, 마운트 초기화와 스토리지 마이그레이션 과정 중 스토리지 쓰기 오류가 발생하면 기본 발급자가 올바른 ca_chain 값을 갖지 못하고 자체 참조만 가질 수 있어요. 이런 쓰기 오류는 로그에서 failed to persist issuer ... chain to disk: <cause> 같은 메시지로 가장 흔히 나타나며, 마이그레이션 당시 Vault가 안정적이지 않았다는 것을 나타내요. 이는 마운트 안에 (루트가 있는 중간 같은) 발급자가 하나 이상 있을 때만 발생한다는 점을 기억하세요.
(새 버전의 Vault가 발급자 체인을 자동 재구축할 때까지) 수동으로 고치려면 체인 재구축을 수행할 수 있어요.
curl -X PATCH -H "Content-Type: application/merge-patch+json" -H "X-Vault-Request: true" -H "X-Vault-Token: $(vault print token)" -d '{"manual_chain":"self"}' https://.../issuer/default
curl -X PATCH -H "Content-Type: application/merge-patch+json" -H "X-Vault-Request: true" -H "X-Vault-Token: $(vault print token)" -d '{"manual_chain":""}' https://.../issuer/default
이렇게 하면 기본 발급자의 manual chain을 잠시 자체 체인만으로 설정한 다음 다시 자동 체인 구축으로 되돌려요. 이는 발급자의 ca_chain 필드의 새로고침을 트리거하며, 다음으로 확인할 수 있어요.
vault read pki/issuer/default
발급자 제약 시행 (Issuer Constraints Enforcement)
1.18.3, 1.18.3+ent, 1.17.10+ent, 1.16.14+ent 버전부터 Vault는 제약 확장(constraints extensions)을 가진 발급자의 리프 인증서 생성 또는 서명 시 추가 검증을 수행해요. 이 검증에는 확장 키 용도, 이름 제약 검증, 그리고 발급자 이름을 인증서에 올바르게 복사하는 것이 포함돼요. 이 검증 없이 발급된 인증서는 최종 사용자 애플리케이션이 수락하지 않을 수 있어요.
이 검증에서 발생하는 발급 문제는 더 아래에서 문제가 생기지 않도록 발급자 인증서 자체를 변경해 고쳐야 해요.
VAULT_DISABLE_PKI_CONSTRAINTS_VERIFICATION 환경 변수를 true로 설정해 검증을 완전히 비활성화하는 것도 가능해요.
경고:
VAULT_DISABLE_PKI_CONSTRAINTS_VERIFICATION환경 변수 사용은 최후의 수단으로 간주해야 해요.
튜토리얼 (Tutorial)
나만의 인증 기관(CA) 구축하기 가이드를 참고하면 단계별 튜토리얼을 볼 수 있어요.
PKI에 외부 관리 키를 사용하는 방법이 궁금하다면 관리 키를 사용한 PKI 시크릿 엔진도 함께 살펴보세요.
API
PKI 시크릿 엔진은 완전한 HTTP API를 제공해요. 자세한 내용은 PKI 시크릿 엔진 API 문서를 참고해 주세요.
더 알아보기 (Learn more)
- Vault PKI 시크릿 엔진의 전체 API 목록은 PKI API 문서에서 확인하세요.
- PKI 튜토리얼은 Build Your Own CA와 관리 키 튜토리얼을 참고하세요.