Javascript

Node.js 서버가 자체 서명 SSL 서버와 통신할 때 생기는 문제와 해결 방법

kyoulho 2025. 5. 29. 22:44

 

✅ 문제 배경

회사 내부 시스템이나 개발 환경에서는 종종 Let's Encrypt 같은 인증기관(CA)을 거치지 않고, OpenSSL 등으로 만든 자체 서명된 인증서(Self-signed certificate) 를 사용하는 경우가 많습니다. 예를 들면, 다음과 같은 시스템에 자체 인증서가 사용될 수 있습니다:

  • 내부 로그인 서버 (예: Keycloak)
  • 내부 파일 저장 서버 (예: MinIO)
  • API 서버 (직접 만든 HTTPS 서버)

이때 이들 서버와 Node.js 기반 서버(Next.js, NestJS 등) 가 통신하려고 하면, 아래와 같은 에러가 발생할 수 있습니다:

Error: self signed certificate
UNABLE_TO_VERIFY_LEAF_SIGNATURE


🧨 왜 이런 문제가 생기나요?

📌 1. HTTPS는 신뢰 기반으로 작동합니다

HTTPS는 웹 브라우저나 서버가 "상대방이 진짜인지" 확인하기 위해 공식적으로 인증된 신뢰 기관(CA) 에서 발급한 인증서를 사용합니다.

📌 2. Node.js도 똑같이 검증합니다

Node.js도 기본적으로 운영 체제에 내장된 '공식 인증서 목록(CA 목록)' 만을 신뢰합니다. 이 목록에 등록된 인증서만 믿습니다.

📌 3. 그런데 자체 서명 인증서는?

  • 자체 서명된 인증서는 이 공식 목록에 없기 때문에 신뢰하지 않습니다.
  • 인증기관이 검증해준 적도 없고, Node.js 입장에서 보면 "이거 누가 만든 건데? 못 믿겠어!" 같은 상태입니다.


✅ 방법 1. NODE_TLS_REJECT_UNAUTHORIZED=0 (모든 검증 무시 – 개발 한정)

services:
  node-app:
    image: your-node-app
    environment:
      - NODE_TLS_REJECT_UNAUTHORIZED=0

이 설정은 모든 HTTPS 인증서 검증을 끕니다.

🚨 주의

  • 이 방법은 너무 위험해서 운영 환경에서는 절대 사용하면 안 됩니다.
  • 공격자가 중간에 끼어들어도 눈치 못 챌 수 있습니다.
  • 정말 개발 중 "일단 되게만 하자" 할 때만 임시로 쓰세요.


✅ 방법 2. 신뢰할 인증서를 수동으로 지정 (NODE_EXTRA_CA_CERTS)

이 방법은 안전하고, 운영 환경에서도 사용할 수 있습니다.

📌 과정 요약

  1. 서버가 사용하는 인증서를 .crt 형식으로 저장
  2. docker-compose로 해당 인증서를 컨테이너 내부에 복사
  3. Node.js가 해당 인증서를 추가 신뢰 목록으로 인식하도록 환경 변수 설정

📁 디렉토리 구성 예시

project/
├── docker-compose.yml
└── certs/
    └── my-ca.crt   ← 자체 서명된 인증서

🛠️ docker-compose.yml 예시

services:
  node-app:
    image: your-node-app
    volumes:
      - ./certs/my-ca.crt:/usr/local/share/ca-certificates/my-ca.crt:ro
    environment:
      - NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/my-ca.crt

이렇게 설정하면, Node.js는 my-ca.crt 인증서를 공식 CA처럼 믿고 통신합니다.
대부분의 fetch, axios, graphql, grpc 요청이 오류 없이 작동하게 됩니다.

 


✅ 방법 3. 시스템 trust store 전체 교체 (SSL_CERT_FILE)

Linux 시스템에 존재하는 전체 신뢰 CA 목록을 덮어쓰는 방법입니다.

📁 먼저 호스트에서 기존 목록과 합치기

cat /etc/ssl/certs/ca-certificates.crt ./certs/my-ca.crt > combined-ca.crt

🛠️ docker-compose.yml 예시

services:
  node-app:
    image: your-node-app
    volumes:
      - ./combined-ca.crt:/etc/ssl/certs/ca-certificates.crt:ro
    environment:
      - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

이 방법은 전체 시스템에서 사용하는 인증서 목록을 교체하므로 보다 광범위하게 적용되며, 역시 코드 수정 없이 적용 가능합니다.

 

✅ 요약

방법 설명 보안성 환경
NODE_TLS_REJECT_UNAUTHORIZED=0 인증서 검증 무시 ❌ 매우 낮음 개발 전용
NODE_EXTRA_CA_CERTS 특정 인증서만 신뢰 ✅ 안전 운영 가능
SSL_CERT_FILE 전체 신뢰 인증서 목록 교체 ✅ 보안적 운영 가능