--- kind: PROJECT_DECISION slug: dns-01-because-the-lab-is-not-on-the-public-internet title: 인증서는 DNS-01 로 받는다 — 실험대 주소가 공개 인터넷에 없어 HTTP-01 이 성립하지 않는다 topic: lab-environment-build topicName: 실험대 환경 구성 project: virtualization status: 게시 전 decisionStatus: ADOPTED sourceRevision: 9465582b5d1630eb4ae7c4e078021486919bf6b6 source: - final/document.md#190-단계-04-let's-encrypt-와-인증서-갱신 - final/document.md#184-이-부의-출처와-범위 --- # 인증서는 DNS-01 로 받는다 — 실험대 주소가 공개 인터넷에 없어 HTTP-01 이 성립하지 않는다 인증서는 Let's Encrypt 의 DNS-01 로 받는다. HTTP-01 은 80 포트와 공개 A 레코드를 요구하는데 이 실험대의 주소는 공개 인터넷에 없고, certbot 이 DNS 공급자 API 로 나가는 DNS-01 만 성립한다. Cloudflare API 토큰이 엣지 VM 안 평문 파일에 놓이는 비용을 감수한다. ## 근거 - **갱신은 매번 SUCCESS 였고 옛 인증서가 계속 나갔다 — 2305초와 1~2초** 이 결정으로 받은 인증서가 갱신 뒤에 실제로 서빙되는지는 이 결정 밖이고 그 기록이 받는다. 발급 방식을 정하는 것과 갱신된 것을 nginx 가 읽게 만드는 것은 다른 일이다. - **엣지 nginx 를 호스트에서 게스트 VM 으로 옮긴다 — 성능이 아니라 더러워지는 층의 격리** 그 결정이 새로 요구한 일곱 가지 가운데 7번이 certbot 과 인증서와 갱신 훅을 게스트로 옮기는 것이었다. 이 결정이 세우는 것을 전부 엣지 게스트에 두는 이유가 거기서 왔다. - **도구가 낸 출력은 대상의 상태가 아니다 — 그 명령이 무엇을 세는지부터 가른다** 체인이 이어졌는지를 openssl s_client 의 단계 수로 판정하는 근거다. cert.pem 을 써서 체인이 끊겨도 브라우저는 캐시나 AIA 로 보완해 정상으로 보인다. - **가까운 층부터 한 층씩 건너뛰며 확인한다 — 층마다 성공 신호가 다르다** 04 단계의 확인을 어느 기계에서 치는지가 그 기준에 걸려 있다. 엣지 게스트 안에서 치면 층의 답이 아니라 친 위치의 답이 돌아온다. - **단계별 구축 문서는 작성 시점이 아니라 실행 순서로 검증한다** 이 결정이 남긴 이름 규칙을 가이드가 틀리게 적었고, §182 가 그것을 결함 여섯 중 하나로 셌다. 결함 여섯을 나란히 적은 표는 그 기록에 있다. ## 결정문 인증서는 Let's Encrypt 의 DNS-01 로 받는다. 엣지 게스트에 certbot 과 python3-certbot-dns-cloudflare 를 깐다. Cloudflare API 토큰은 /etc/letsencrypt/cloudflare.ini 에 600 으로 두고, 발급 대상은 hyeonworks.com 과 그 와일드카드 둘을 -d 로 준다. certbot 과 인증서와 갱신 타이머와 deploy 훅은 전부 엣지 게스트에 두고 물리 호스트에는 아무것도 두지 않는다. ## 판단 이유 두 방식은 검증이 오가는 방향이 반대다. HTTP-01 은 Let's Encrypt 가 우리 서버로 들어오는 인바운드 검증이라 80 포트와 공개 A 레코드가 있어야 한다. DNS-01 은 certbot 이 DNS 공급자 API 로 나가는 아웃바운드 검증이라 공개 인터넷에서 보일 필요가 없다. 이 실험대의 주소는 공개 인터넷에 없으므로 HTTP-01 은 성립하지 않는다. §190 는 이 선택을 우열로 적지 않는다. 공개 서버라면 HTTP-01 이 맞고, 토큰도 DNS 연동도 없어 관리할 것이 적다고 대안 쪽을 먼저 적는다. 이 결정은 더 나은 방식을 고른 것이 아니라 하나만 성립하는 조건에서 그것을 쓴 것이다. 딸려 온 이득이 하나 있는데, DNS-01 은 와일드카드를 받을 수 있어 hyeonworks.com 아래의 이름을 인증서 한 장으로 덮는다. 그 이득은 뒤늦게 챙겼다. 이 실험대는 처음에 와일드카드를 안 쓰고 이름마다 따로 받았고, 네 번째 이름이 없어 다른 실험에서 app2 를 빌려 써야 했다. 정한 대로 이미 서 있다. 엣지 게스트에는 certbot 과 python3-certbot-dns-cloudflare 가 깔려 있다. certbot plugins 는 dns-cloudflare 와 standalone 과 webroot 세 줄을 내고, 자격증명 파일은 600 으로 놓여 있다. 밖에서 친 openssl s_client 는 체인 0 부터 3 까지 네 단계와 Verify return code: 0 (ok) 를 냈고, curl 은 404 tls=0 을 냈다. 설정 원본은 §184 가 가리키는 저장소의 deploy/lab/edge/ 에 있고 리비전은 frontmatter 에 적었다. 없는 것도 분명하다. HTTP-01 을 실제로 시도해 실패한 기록은 없다. 그 경로가 막혔다는 근거는 시도가 아니라 주소 대역이고, 100.64.0.0/10 이 CGNAT(Carrier-Grade NAT) 예약 대역이라는 것은 이 실험대가 잰 값이 아니라 규격이다. ## 영향 감수한 비용이 셋이다. Cloudflare API 토큰 : 엣지 VM 안 평문 파일에 놓인다 발급 검증 시간 : TXT 가 퍼질 때까지 기다리느라 수십 초 걸린다. 정상이므로 중간에 끊지 않는다 DNS 공급자 의존 : 인증서를 받는 일이 Cloudflare 계정에 묶인다 토큰이 평문으로 놓이는 것을 줄이려고 가드레일을 넷 둔다. 권한 범위 : Edit zone DNS · Specific zone · hyeonworks.com 으로 좁힌다. All zones 로 두면 계정의 모든 도메인에서 DNS 를 고칠 권한이 그 파일에 놓이고, Global API Key 는 폐기하면 그 키를 쓰던 다른 것들이 전부 같이 못 쓰게 된다 파일 권한 : install -m 600 /dev/null 로 비어 있을 때 먼저 600 을 만든다. 토큰을 쓰고 나서 권한을 고치면 그사이가 열려 있다 확인 방법 : ls -l 이 -rw------- 을 내는지와 바이트 수가 0 이 아닌지만 보고 값은 찍지 않는다 토큰 검증 : Cloudflare 의 user/tokens/verify 가 내는 status 가 active 이고 success 가 true 인지 본다. code 가 6003 이면 값이 틀렸거나 잘렸고 9109 면 권한 범위가 모자라다. 여기서 걸러 두면 뒤에서 실패했을 때 DNS 문제인지 토큰 문제인지가 섞이지 않는다 그래도 토큰이 엣지 안에만 있는 것은 아니다. 원본은 Cloudflare 쪽 서버가 들고 있고 엣지에 놓인 것은 사본이라, 엣지 게스트를 지우는 것으로는 계정 쪽 토큰이 없어지지 않는다. 폐기는 Cloudflare 에서 따로 해야 하는데 가이드는 그것을 적지 않았다. 그 배치가 노린 것이 하나 더 있다. virsh undefine kc-lab-edge 한 줄로 이 계층을 통째로 되돌린다는 것이 가이드가 적은 이유인데, 그것은 게스트를 지우면 같이 없어진다는 말이지 걷어내는 절차가 아니다. 원본 가이드 04 에는 걷어내는 순서도, 지운 뒤에 무엇을 확인하는지도 없고, 이 실험대가 그렇게 지워 본 적도 없다. 발급 자체에도 순서가 붙는다. --dry-run 을 먼저 돌리는 것은 Let's Encrypt 의 주당 중복 인증서 5장 한도를 dry-run 이 쓰지 않기 때문이다. dry-run 은 인증서를 저장하지 않으므로 그 직후 certbot certificates 가 No certificates found 를 내는 것이 정상이다. 이 결정이 남긴 이름 규칙이 하나 있다. live/hyeonworks.com/ 은 certbot 이 이 묶음을 관리하려고 첫 번째 -d 에서 따온 라벨이고 서빙과 무관하다. 브라우저가 보는 유효 호스트명은 -d 로 준 이름 전부이므로 auth.hyeonworks.com 으로 다시 받을 필요가 없다. 대신 nginx 설정에는 그 디렉터리 경로를 한 글자도 다르지 않게 적어야 한다. live/auth.hyeonworks.com/ 이라고 적으면 cannot load certificate 로 막히고, §182 가 이것을 가이드 결함 여섯 중 하나로 셌다. 와일드카드는 한 단계만 덮는다. a.b.hyeonworks.com 도, apex 인 hyeonworks.com 자신도 와일드카드에 들어가지 않아 -d 를 둘 준다. 이 결정이 끝내지 못한 것이 하나 있다. 받은 인증서가 갱신 뒤에 실제로 서빙되는지는 발급 방식과 별개이고, 근거로 건 첫 기록이 그것을 받는다.