LabHub
배우기 러닝패스 코스

The certificate was renewed, but the browser still showed the old one

Renewed, yet the old certificate is served

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

인증서를 기동 때 한 번만 읽는 HTTPS 서버에 대해 갱신 사고를 재현하고, 디스크가 아니라 서버가 내보내는 인증서를 감시하는 스크립트 두 개를 만듭니다.

왜 중요한가

갱신 도구는 파일을 바꾸고 서버는 메모리를 내보냅니다. 그 사이에 재기동이 없으면 "갱신 성공" 로그와 "만료 임박" 경고가 동시에 참이 됩니다. 재료 서버 /opt/app/tlsserve.pyload_cert_chain 을 딱 한 번 부르는 파이썬 HTTPS 서버로, 실제 서버 대부분이 그렇듯 파일이 바뀌어도 다시 읽지 않습니다. 이 실습의 감시 스크립트는 채점기가 따로 띄운 서버로 양방향(같은 파일 FRESH, 다른 파일 STALE) 검사를 받습니다.

단계

  1. /root/renew/ca.key·/root/renew/ca.crt(CN=Lab Root CA)와 /root/renew/server.key, 그리고 CA 가 서명한 3일짜리 /root/renew/v1.crt(SAN DNS:www.lab.internal)를 만드세요.
  2. v1.crt/root/renew/live.crt 로, server.key/root/renew/live.key 로 복사한 뒤 python3 /opt/app/tlsserve.py --cert /root/renew/live.crt --key /root/renew/live.key --port 8443 을 띄우세요. openssl s_client 로 받은 인증서의 serial= 줄을 /root/renew/02-served.txt 에 저장하세요.
  3. 같은 키로 30일짜리 /root/renew/v2.crt 를 발급하고 live.crt 에 덮어쓰세요(갱신 도구가 하는 일). 서버는 재기동하지 마세요.
  4. 다시 s_client 로 serial=/root/renew/04-served.txt 에, curl -sk https://127.0.0.1:8443/ 의 본문을 /root/renew/04-body.txt 에 저장하세요. 디스크는 v2 인데 서버는 v1 이어야 합니다.
  5. /root/renew/certdiff.sh <인증서파일> <host:port> 를 만드세요. 디스크 파일과 서버가 내보내는 인증서의 SHA-256 지문이 같으면 FRESH 를 출력하고 0, 다르면 STALE 을 출력하고 1 로 끝나야 합니다. live.crt127.0.0.1:8443 에 대해 돌린 출력을 /root/renew/05-detect.txt 에 저장하세요.
  6. 서버를 끝내고 다시 띄운 뒤 s_client 의 serial=/root/renew/06-served.txt 에 저장하세요.
  7. /root/renew/servedcheck.sh <host:port> <초> 를 만드세요. 서버가 내보내는 인증서가 그 초 안에 만료되면 EXPIRING 을 출력하고 1, 아니면 OK 를 출력하고 0 으로 끝나야 합니다. 127.0.0.1:8443 604800 으로 돌린 출력을 /root/renew/07-monitor.txt 에 저장하세요.
  8. /root/renew/08-report.md 에 v1·v2 의 일련번호, 서버가 새 파일을 읽게 만든 방법, 감시는 디스크가 아니라 서버가 내보내는 인증서를 봐야 하는 이유를 적으세요.

참고

CA 와 3일짜리 v1

/root/renew/ 에 ca.key·ca.crt(CN=Lab Root CA)·server.key 와 3일짜리 v1.crt(SAN DNS:www.lab.internal)를 만드세요.

앞 모듈과 같은 순서입니다 — CA 자기 서명, SAN 있는 CSR, x509 -req 로 서명(-copy_extensions copy). CSR 은 3단계에서 다시 쓰니 server.csr 로 남겨 두세요.

서버가 든 인증서 읽기

v1.crt→live.crt, server.key→live.key 로 복사해 tlsserve.py 를 8443 에 띄우고, s_client 로 받은 serial= 줄을 /root/renew/02-served.txt 에 저장하세요.

서버는 nohup 으로 뒤에 두고 로그는 /root/renew/server.log 로 보내세요. s_client 출력 전체를 x509 -noout -serial 에 넘기면 serial= 한 줄이 나옵니다.

갱신 — 파일을 덮어쓴다

같은 키로 30일짜리 /root/renew/v2.crt 를 발급하고 live.crt 에 덮어쓰세요. 서버는 재기동하지 마세요.

같은 CSR 을 다시 서명하면 됩니다(-days 30). serial 이 새로 매겨지고 만료일이 늘어납니다. cp v2.crt live.crt 가 갱신 도구가 하는 일의 전부입니다.

디스크는 v2, 서버는 v1

s_client 의 serial=/root/renew/04-served.txt 에, curl -sk https://127.0.0.1:8443/ 본문을 /root/renew/04-body.txt 에 저장하세요.

서버는 기동 때 읽은 것을 계속 내보냅니다. 두 파일 모두 v1 의 serial 이 보여야 사고가 재현된 것입니다. curl 의 -k 는 자체 CA 라 검증을 끄는 것이고, 본문에는 서버가 스스로 말하는 serial 이 있습니다.

디스크와 서버를 비교하는 스크립트

/root/renew/certdiff.sh <인증서파일> <host:port> 를 만들고(같으면 FRESH·0, 다르면 STALE·1), live.crt 와 127.0.0.1:8443 에 대한 출력을 /root/renew/05-detect.txt 에 저장하세요.

두 지문을 구합니다 — 파일은 x509 -in 파일 -fingerprint -sha256, 서버는 s_client 출력을 x509 -fingerprint -sha256 에 넘겨서. 서버에서 인증서를 못 받으면 ERROR 로 2 를 돌려주면 좋습니다. 채점기는 자기 서버로 같은 파일·다른 파일 두 경우를 돌립니다.

재기동 — 서버가 새 파일을 읽는다

서버를 끝내고 다시 띄운 뒤 s_client 의 serial=/root/renew/06-served.txt 에 저장하세요.

pkill -f tlsserve.py 로 끝내고 같은 명령으로 다시 띄웁니다. 기동 때 live.crt 를 새로 읽으므로 이번에는 v2 의 serial 이 나와야 합니다.

서버가 내보내는 인증서의 만료 감시

/root/renew/servedcheck.sh <host:port> <초> 를 만들고(그 초 안에 만료면 EXPIRING·1, 아니면 OK·0), 127.0.0.1:8443 604800 의 출력을 /root/renew/07-monitor.txt 에 저장하세요.

s_client 로 받은 인증서를 임시 파일에 x509 -out 으로 저장한 뒤 -checkend <초> 를 걸면 됩니다. 디스크의 live.crt 를 보면 안 됩니다 — 채점기는 2일짜리 인증서를 든 자기 서버에 7일 창을 주어 EXPIRING 이 나오는지 봅니다.

사고 보고서

/root/renew/08-report.md 에 v1·v2 일련번호, 서버가 새 파일을 읽게 만든 방법, 감시가 서버가 내보내는 인증서를 봐야 하는 이유를 적으세요.

두 serial 은 v1.crt·v2.crt 에서 -serial 로 뽑아 그대로 넣으세요. '재기동' 이라는 말과 's_client' 가 들어가면 채점기가 결론을 찾습니다.