LabHub
배우기 러닝패스 코스

Tomcat & nginx Operations

Issuing a Certificate From a Private CA and Applying It to nginx

LabHub 에서 이어서 보기

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

목표

사설 CA 를 만들어 SAN 이 포함된 서버 인증서를 발급하고, 체인 파일을 구성해 nginx 에 HTTPS 를 적용하고, 만료 감시 스크립트까지 만들 수 있게 됩니다.

왜 중요한가

인증서 장애의 대부분은 암호학이 아니라 체인 누락과 만료 두 가지입니다. 중간 인증서를 빼먹으면 브라우저에서는 잘 되는데 연동 상대 시스템에서만 실패합니다. 브라우저는 중간 인증서를 캐시하거나 알아서 받아 오지만, 서버 간 HTTP 클라이언트는 그러지 않기 때문입니다. "개발자 PC 에서는 되는데요"는 이 증상의 전형입니다. 그리고 만료는 예고 없이 오지 않는데도 담당자 교체와 알림 누락으로 매년 사고가 납니다. 사설 CA 로 한 번 직접 만들어 보면 이 구조가 손에 남습니다.

단계

  1. /root/ng/tls 디렉터리를 만들고 RSA 2048비트 개인키를 /root/ng/tls/server.key 로 생성합니다.
  2. 그 키로 CSR 을 만들어 /root/ng/tls/server.csr 로 저장합니다. 주체는 CN=labhub.local, O=LabHub, C=KR 을 포함해야 합니다.
  3. 사설 CA 를 만듭니다. /root/ng/tls/ca.key/root/ng/tls/ca.crt. CA 인증서의 주체는 CN=LabHub Root CA 이고 유효기간은 3650일 이상, basicConstraintsCA:TRUE 가 있어야 합니다.
  4. CA 로 CSR 에 서명해 /root/ng/tls/server.crt 를 만듭니다. SAN 에 DNS:labhub.localIP:127.0.0.1 이 모두 들어가야 하고, 발급자(issuer)가 CA 의 주체와 같아야 합니다.
  5. /root/ng/tls/fullchain.pem 을 만듭니다. 서버 인증서 → CA 인증서 순서로 이어 붙이며, 파일 안에 인증서가 정확히 2개여야 합니다. openssl verify -CAfile ca.crt server.crt 가 성공해야 합니다.
  6. nginx 에 8443 포트 HTTPS 서버 블록을 추가합니다. ssl_certificate 는 fullchain, ssl_certificate_key 는 server.key, ssl_protocolsTLSv1.2 TLSv1.3 만 허용합니다. openssl s_client -connect 127.0.0.1:8443 -CAfile /root/ng/tls/ca.crt 의 결과에 Verify return code: 0 이 나와야 합니다.
  7. 8088 포트의 모든 요청이 https://301 리다이렉트되게 합니다. curl -s -o /dev/null -w '%{http_code} %{redirect_url}' http://127.0.0.1:8088/x 결과가 301 이고 리다이렉트 URL 이 https:// 로 시작하며 8443 을 포함해야 합니다.
  8. /root/ng/certcheck.sh 를 만듭니다. 인자 두 개(인증서파일 임계일수)를 받아 남은 유효기간이 임계일수보다 많으면 종료코드 0, 임계일수 이내로 임박했으면 0 이 아닌 종료코드로 끝냅니다. 인증서 파일이 없으면 역시 0 이 아닌 종료코드로 끝나야 합니다.

참고

서버 개인키 생성

/root/ng/tls 디렉터리를 만들고 RSA 2048비트 개인키를 /root/ng/tls/server.key 로 생성합니다.

RSA 2048비트가 아직 표준적인 선택입니다. 생성한 키가 정상인지 확인하는 openssl 서브커맨드도 함께 익혀 두세요.

CSR 생성

그 키로 CSR 을 만들어 /root/ng/tls/server.csr 로 저장합니다. 주체는 CN=labhub.local, O=LabHub, C=KR 을 포함해야 합니다.

CSR 의 주체 정보는 -subj 로 한 번에 줄 수 있습니다. 국가 코드는 두 글자 대문자입니다.

사설 CA 만들기

사설 CA 를 만듭니다. /root/ng/tls/ca.key/root/ng/tls/ca.crt. CA 인증서의 주체는 CN=LabHub Root CA 이고 유효기간은 3650일 이상, basicConstraintsCA:TRUE 가 있어야 합니다.

CA 인증서는 일반 서버 인증서와 달라야 합니다. 어떤 확장이 CA 임을 표시하는지 확인하세요. openssl req 에 -x509 를 주면 자체 서명 인증서가 나옵니다.

CA 로 서버 인증서 서명

CA 로 CSR 에 서명해 /root/ng/tls/server.crt 를 만듭니다. SAN 에 DNS:labhub.localIP:127.0.0.1 이 모두 들어가야 하고, 발급자(issuer)가 CA 의 주체와 같아야 합니다.

요즘 브라우저와 라이브러리는 CN 이 아니라 SAN 을 봅니다. openssl x509 로 서명할 때 확장을 파일로 넘겨야 SAN 이 들어갑니다.

체인 파일 구성

/root/ng/tls/fullchain.pem 을 만듭니다. 서버 인증서 → CA 인증서 순서로 이어 붙이며, 파일 안에 인증서가 정확히 2개여야 합니다. openssl verify -CAfile ca.crt server.crt 가 성공해야 합니다.

서버 인증서와 CA 인증서를 이어 붙입니다. 순서가 중요합니다. 만든 뒤에는 검증 명령으로 실제로 신뢰 경로가 서는지 확인하세요.

nginx HTTPS 적용

nginx 에 8443 포트 HTTPS 서버 블록을 추가합니다. ssl_certificate 는 fullchain, ssl_certificate_key 는 server.key, ssl_protocolsTLSv1.2 TLSv1.3 만 허용합니다. openssl s_client -connect 127.0.0.1:8443 -CAfile /root/ng/tls/ca.crt 의 결과에 Verify return code: 0 이 나와야 합니다.

인증서와 키가 짝이 아니면 nginx 는 기동조차 안 됩니다. 프로토콜은 폐기된 버전을 빼고 지정하세요.

HTTP → HTTPS 리다이렉트

8088 포트의 모든 요청이 https://301 리다이렉트되게 합니다. curl -s -o /dev/null -w '%{http_code} %{redirect_url}' http://127.0.0.1:8088/x 결과가 301 이고 리다이렉트 URL 이 https:// 로 시작하며 8443 을 포함해야 합니다.

rewrite 보다 return 이 명확하고 빠릅니다. 상태코드와 Location 헤더가 모두 맞아야 합니다.

만료 감시 스크립트

/root/ng/certcheck.sh 를 만듭니다. 인자 두 개(인증서파일 임계일수)를 받아 남은 유효기간이 임계일수보다 많으면 종료코드 0, 임계일수 이내로 임박했으면 0 이 아닌 종료코드로 끝냅니다. 인증서 파일이 없으면 역시 0 이 아닌 종료코드로 끝나야 합니다.

openssl x509 에는 '남은 유효기간이 N초 이상인가'를 종료코드로 알려 주는 옵션이 있습니다. 감시 스크립트는 이걸 쓰면 날짜 파싱이 필요 없습니다.