Envoy 내부 구조 · 한 포트가 여러 얼굴을 가질 때 · 실습
인증서 두 장으로 한 포트를 갈라 쓴다
목표
한 리스너에 필터 체인을 여러 개 두고 SNI · 전송 프로토콜 · ALPN 으로 갈라 받는다. 조건이 겹칠 때 무엇이 이기는지도 직접 확인한다.
왜 중요한가
인그레스 게이트웨이 한 대가 도메인 수십 개를 받는 구성에서는 '어느 체인이 이 연결을 받는가' 가 곧 '어떤 인증서를 내보내는가' 이다. 이 규칙을 순서로 오해하면 체인을 위아래로 옮기며 하루를 보내게 된다. 실제 판정은 여덟 단계의 고정된 순서로 구체성을 비교해 이뤄지고, 맞는 체인이 없으면 오류 응답이 아니라 연결이 그냥 끊긴다 — 이 두 가지를 손으로 겪어 두면 '이 도메인만 안 됩니다' 신고를 몇 분 만에 끝낼 수 있다.
단계
1. /root/envd-listener/listener.yaml 에 리스너 두 개를 두세요 — edge-a 는 127.0.0.1:10021 에서 listener=a 를, edge-b 는 127.0.0.1:10022 에서 listener=b 를 direct_response 로 돌려줍니다(관리 포트는 9921). 띄운 뒤 /listeners?format=json 을 /root/envd-listener/01-listeners.json 에 저장하세요.
2. /root/envd-listener/tls/ 에 자체 서명 인증서 두 장을 만드세요 — a.crt/a.key 는 CN 과 SAN 이 a.envd.test, b.crt/b.key 는 b.envd.test 입니다. 두 인증서의 subject 와 SAN 을 /root/envd-listener/02-certs.txt 에 적으세요.
3. /root/envd-listener/listener.yaml 에 리스너 mixed(127.0.0.1:10443)를 더하세요. tls_inspector 리스너 필터를 켜고, TLS 체인 두 개를 server_names 로 가릅니다 — a.envd.test 는 chain=sni-a, b.envd.test 는 chain=sni-b 를 돌려줍니다. 두 이름으로 각각 요청한 결과를 /root/envd-listener/03-sni.txt 에 a= 와 b= 두 줄로 적으세요.
4. openssl s_client 로 10443 에 두 번 붙되 -servername 만 바꿔, 각각 어떤 인증서가 나오는지 /root/envd-listener/04-cert.txt 에 a= 와 b= 두 줄로 적으세요(값은 인증서의 CN).
5. mixed 리스너에 transport_protocol: "raw_buffer" 로 맞는 체인 plain 을 맨 앞에 더해 chain=plain 을 돌려주게 하세요. 같은 포트 10443 로 평문 HTTP 와 TLS 요청을 각각 보내 결과를 /root/envd-listener/05-raw.txt 에 plain= 와 tls= 두 줄로 적으세요.
6. mixed 에 네 번째 체인 alpn-h2 를 더하세요 — transport_protocol: "tls" 와 application_protocols: ["h2"] 로만 맞고, chain=alpn-h2 를 HTTP/2 로 돌려줍니다. 그다음 SNI 를 a.envd.test 로 두고 HTTP/2 로 요청해 어느 체인이 받는지, SNI 를 z.envd.test 로 두고 HTTP/2 로 요청하면 어느 체인이 받는지 확인해 /root/envd-listener/06-alpn.txt 에 sni_and_h2= 와 h2_only= 두 줄로 적으세요.
7. z.envd.test 로 HTTP/1.1 TLS 요청을 보내 보세요 — 어느 체인에도 맞지 않습니다. /root/envd-listener/07-nomatch.txt 에 nomatch_rc=(그 요청의 curl 종료 코드)와 match_rc=(a.envd.test 로 보낸 같은 요청의 종료 코드) 두 줄을 적으세요.
8. /root/envd-listener/08-report.md 에 chains=(mixed 리스너의 체인 개수), same_port_plain_and_tls=(yes 또는 no), sni_beats_alpn=(6단계에서 SNI 와 ALPN 이 함께 맞았을 때 이긴 체인의 이름), nomatch_rc= 네 줄을 적고, 그 아래 배운 것을 네 줄 이상 적으세요.
참고
- Envoy 를 띄울 때는
setsid --fork nohup envoy -c <파일> --log-level warn > <로그> 2>&1 </dev/null를 쓰고, 다시 띄우기 전에는pkill -x envoy로 정리하세요. - 기동을 기다릴 때는 고정
sleep대신/ready가 LIVE 를 돌려줄 때까지 도는 루프를 쓰세요. - 자체 서명 인증서라
curl에는-k가 필요합니다. 이름을 붙여 보내려면--resolve 이름:포트:127.0.0.1을 함께 씁니다. - 흔한 실수 —
tls_inspector를 켜지 않으면server_names와application_protocols조건이 아무에게도 맞지 않습니다. 설정은 통과하는데 동작만 안 합니다. - 흔한 실수 —
-addext "subjectAltName=DNS:..."를 빠뜨리면 CN 만 있는 인증서가 나옵니다.
단계 8개
- 한 프로세스가 포트 두 개를 듣는다
- 이름이 다른 인증서 두 장을 굽는다
- 같은 포트인데 이름에 따라 다른 체인이 받는다
- 체인이 갈리면 내보내는 인증서도 갈린다
- 한 포트에서 평문과 TLS 를 함께 받는다
- 조건이 둘 다 맞으면 무엇이 이기는가
- 어느 체인에도 맞지 않으면 응답이 아니라 침묵이다
- 체인 설계 메모를 남긴다