와일드카드 인증서는, 한 번 발급하면 같은 개인키가 당신이 소유한 줄도 잊은 서버들 위에 올라가게 되는 유일한 종류의 TLS 인증서다.
한 문장으로 끝나는 문제지만, 아무도 그걸 체감하지 못한다 — 어느 날 가치 없는 서버 하나가 털리기 전까지는. 어떤 스테이징 서버, 어떤 마케팅용 마이크로사이트, 2023년에 외주 개발자가 띄워놓고 아무도 내리지 않은 내부 대시보드. 공격자는 그 서버에 관심 없다. 관심 있는 건 거기 놓인 파일이다: STAR_example_com.key. 프로덕션에 있는 것과 똑같은 키. 지구상 모든 브라우저에게 당신이 *.example.com임을 증명하는 바로 그 키.
이제 그들은 payments.example.com이 될 수 있다. login.example.com이 될 수 있다. 당신 도메인 아래 아무 이름이나 지어내서, 완벽하게 검증되는 인증서로 그 이름이 될 수 있다. 당신의 인증서니까. 당신은 전체 서버 fleet에 마스터키를 쥐여주고, 그중 가장 약한 놈이 사본을 들고 있게 내버려 둔 것이다.
편의는 진짜다, 그래서 다들 계속 쓴다
와일드카드에 공정하고 싶다. 끌리는 이유가 멍청한 게 아니니까. *.example.com 하나 받아두면 새 서브도메인이 생길 때마다 티켓 끊을 일이 없고, 인턴이-방금-지은-이름.example.com의 발급을 기다릴 일도 없다. 인증서 하나, 무한한 서브도메인, 이름마다 갱신 춤을 출 필요 없음. 이걸 손으로 관리하는 세계라면, 진짜로 수고가 줄어든다.
그런데 “이걸 손으로 관리하는 세계라면”이 저 문장의 무게를 다 짊어지고 있다. 우리는 더 이상 거기 살지 않는다. ACME와 Let’s Encrypt가 2015년에 이름별 인증서를 공짜로, 자동으로 만들었다. 와일드카드가 절약해 주는 것 — 이름마다 인증서를 받는 수작업 — 이 바로 자동화로 사라진 그 일이다. cron job이 이미 대신 내주는 비용을 굳이 최적화하면서, 그 최적화의 대가를 키 배포 리스크로 치르고 있는 셈이다.
와일드카드 키는 돌아다녀야 한다, 그게 안티패턴이다
다들 슬쩍 넘기는 부분이 여기다. 인증서의 보안은 전적으로 개인키에 산다. 인증서 자체는 공개다 — 발급되는 순간 말 그대로 Certificate Transparency 로그에 게시된다. 유일한 비밀은 키다. 그래서 어떤 인증서든 보안 질문은 단 하나로 압축된다: 개인키가 몇 군데에 존재하고, 각 군데가 얼마나 잘 지켜지는가?
호스트별 인증서는 이 질문에 잘 답한다. api.example.com의 키는 API 서버에만 있고 다른 어디에도 없다. 거기가 털리면 하루가 망하긴 하지만, payments.example.com의 인증서는 다른 하드웨어 위의 다른 키라서 멀쩡하다.
와일드카드는 설계상 이 질문에 못 답한다. *.example.com을 열두 개 서비스에서 서빙하려면 키가 그 열두 서비스 위에 있어야 한다 — 아니면 로드밸런서, CDN 엣지 설정, 클러스터 전체에 복제된 쿠버네티스 시크릿, 누군가 한 번 테스트하고 잊은 개발자 노트북에. 사본 하나하나가 새는 지점이다. 한 군데 잘 지켜진 곳에 머무는 게 유일한 임무인 물건을, 여러 군데에 — 그중 일부는 목록조차 못 뽑는 곳에 — 있으라고 강제한 것이다. 편의와 리스크가 같은 메커니즘이다: 키 하나, 사방에.
절반만 폐기할 수는 없다
정리하려 들면 실패 양상이 더 나빠진다. 스테이징 서버가 키를 흘렸다고 확인했다 치자. 호스트별 인증서라면, 털린 그 이름의 인증서 하나만 폐기하고 재발급하면 나머지 인프라는 눈치도 못 챈다.
와일드카드에는 “그 인증서 하나”가 없다. 전부를 덮는 인증서 하나가 있을 뿐이고, 그걸 폐기하면 전부에 대해 폐기된다 — 모든 서브도메인, 모든 서비스가 동시에. 그래서 선택지는 둘이다: 털린 게 확실한 키를 프로덕션에 살려두거나, 와일드카드를 쓰는 모든 시스템에 걸친 재발급-재배포를 동시에, 사고 대응 압박 속에서 일으키거나. 폐기는 원래 당신의 안전밸브였다. 와일드카드에서는 기폭장치다.
매칭 규칙조차 당신 생각대로 작동하지 않는다
사람들은 와일드카드가 실제보다 더 많이 덮는다고 가정하고 손을 뻗기도 한다. *.example.com은 정확히 한 레벨의 라벨만 매칭한다. foo.example.com은 덮는다. bar.foo.example.com은 안 덮고, 맨몸의 example.com 자신도 안 덮는다. RFC 9525 — 오래 쓰인 RFC 6125를 대체한, TLS 서비스 식별에 관한 2025년 표준 — 이 이걸 못 박는다: 와일드카드는 완전한 맨 왼쪽 라벨일 때만 적법하며, *.example.com을 매칭하는 클라이언트는 그 하나의 맨 왼쪽 라벨 외에는 아무것도 비교하면 안 된다.
그러니 도메인의 apex, 사람들이 실제로 주소창에 치는 이름은 어차피 자기 인증서가 따로 필요하다. 그리고 두 번째 레벨 서브도메인 — 실제 인프라가 자라며 생기는 eu.api.example.com, staging.app.example.com 같은 모양 — 은 그냥 빠져나간다. 커버리지 때문에 산 와일드카드가 상상 속 이름들은 덮고 진짜 이름들은 놓치는 것이다. 그러면 사람들은 각 레벨마다 와일드카드를 사서 “고친다”. 더 많은 키가 더 많은 곳에 — 원래 문제에 단계만 더 붙인 꼴이다.
참고로 같은 RFC는, 한 호스트의 여러 서비스 앞에 인증서 하나를 두는 것 자체를 권장하지 않는다고 짚는다. 교차 프로토콜 공격의 문을 열기 때문이다 — 그리고 와일드카드는 “인증서 하나, 여러 서비스”의 극단판이다. 표준화 단체는 개정 한 사이클을 들여 지침을 더 날카롭게 다듬었고, 다듬어진 방향은 이거였다: 인증서를 넓히지 말고 좁혀라.
와일드카드가 당신에게서 가져가는, 눈치 못 채는 것
더 조용한 비용이 있다. Certificate Transparency 덕분에 당신이 발급하는 모든 이름별 인증서는 공개된, 추가만 가능한 로그에 남는다. 프라이버시 누출처럼 들리고 — 이제 누구나 당신에게 internal-admin.example.com이 있다는 걸 본다 — 실제로도 그렇다. 하지만 동시에 그건 당신 영역의 모든 TLS 이름에 대한 공짜의, 끊김 없는 인벤토리다. 보안팀은 CT 로그를 모니터링해 자기가 승인하지 않은 인증서를 잡아낸다: 계정 탈취의 징후, 무단 배포, 진행 중인 서브도메인 탈취.
와일드카드는 그 신호를 지운다. *.example.com은 로그에 딱 한 번 나타나고, 그 뒤에 실제로 어떤 이름들이 살아 있는지 감시자에게 아무것도 말해주지 않는다. 조금 더 작은 공개 발자국과, 자기 모니터링에서의 완전한 실명(失明)을 맞바꾼 것이다. 와일드카드 키를 손에 넣은 공격자는 secure-login.example.com을 띄우고 그에 대한 흠 없는 인증서를 서빙할 수 있는데, 당신의 CT 모니터링 — 정확히 이걸 잡는 게 존재 이유인 시스템 — 은 아무것도 못 본다. 와일드카드가 그 이름이 존재하기도 전에 이미 그 이름을 덮어버렸으니까.
그럼 뭘 해야 하나
이름별로 인증서를 발급하고 자동화하라. 권고는 이게 전부이고, ACME가 이걸 해결된 문제로 만들어 놨다: 클라이언트가 요청하고, 검증하고, 설치하고, 갱신한다 — 사람이 루프에 끼지 않은 채로. 키는 그게 필요한 호스트에 머문다. 침해는 침해된 범위에 머문다. 폐기는 외과수술처럼 정밀하게 유지된다. CT 로그는 인벤토리로서 쓸모를 유지한다.
진짜로 동적인 서브도메인 공간이 있다면 — 즉석에서 생성되는 수천 개의 고객 이름처럼, 이름마다 미리 발급하는 게 불가능한 경우 — 그렇다, 와일드카드가 실용적 답일 수 있고, ACME가 발급까지 해준다(단 DNS-01 챌린지로만. *.example.com에 대한 통제를 증명한다는 건 웹 루트 하나가 아니라 존 전체에 대한 통제를 증명하는 것이고, 이건 새로운 고가치 비밀인 DNS API 자격증명을 슬쩍 자동화에 쥐여준다는 뜻이다). 그건 진짜 유스케이스다. 그리고 프로덕션에 돌아다니는 와일드카드 수가 시사하는 것보다 훨씬 좁은 유스케이스다.
나머지 경우에 와일드카드는, 우리가 이미 떠나온 십 년 전의 편의다 — 목록도 못 뽑는 곳에 복사해 둔 키로 지켜지고, 장애 없이는 폐기도 못 하며, 그게 샜다고 경고해 줄 단 하나의 신호를 가리는. 편하긴 하다. 마스터키를 현관 매트 밑에 두는 것도 편하다.