unable to get local issuer certificate 에러, git·curl·pip·npm에서 5분 안에 해결하기
어제까지 되던 git clone이 갑자기 막혔다면
분명 어제까지 잘 되던 git clone이 오늘 아침 갑자기 이런 메시지를 뱉으며 멈춰 섭니다.
fatal: unable to access 'https://github.com/...': SSL certificate problem:
unable to get local issuer certificatecurl은 이렇게,
curl: (60) SSL certificate problem: self signed certificate in certificate chainpip은 또 이렇게 토라집니다.
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificate'))증상은 도구마다 다르지만 본질은 하나입니다. 클라이언트가 서버 인증서의 발급자(CA)를 신뢰 체인에서 검증하지 못한 것이죠. 특히 2026년 들어 Zscaler·Netskope 같은 SSL 인스펙션(MITM) 프록시가 사내 표준으로 자리 잡으면서, 이 에러는 회사망에 출근한 개발자라면 누구나 한 번쯤 마주치는 통과의례가 됐습니다.
이 글은 일단 빨리 빌드를 돌리고 → 왜 그런지 이해하고 → 팀 차원 정공법으로 마무리하는 순서로 갑니다.
1. 근본 원인 4가지부터 구분하자
에러 메시지의 미묘한 차이가 원인을 알려줍니다.
| 원인 | 대표 에러 메시지 | 한 줄 설명 |
|---|---|---|
| ① CA 번들 누락·만료 | unable to get local issuer certificate | 클라이언트에 루트 CA가 없거나 오래된 ca-bundle |
| ② 사내 프록시(MITM) | self signed certificate in certificate chain | Zscaler 등이 트래픽을 가로채며 자체 루트로 재서명 |
| ③ 자체 서명 인증서 | self signed certificate | 사내 GitLab/Nexus가 직접 발급한 인증서 |
| ④ 시스템 시간 오류 | certificate has expired / not yet valid | PC 시계가 틀려 유효기간 검증 실패 |
핵심 구분: unable to get local issuer certificate 는 "발급자를 못 찾겠다"(중간 CA 누락), self signed certificate in certificate chain 은 "체인 꼭대기가 신뢰할 수 없는 자체 서명"(MITM 프록시·사내 인증서)이라는 뜻입니다. 후자가 보이면 십중팔구 회사 프록시 또는 사내 서버입니다.
2. 진단 명령: 추측하지 말고 인증서 체인을 직접 보자
가장 먼저 실제로 어떤 인증서가 내려오는지 확인합니다.
# 인증서 체인 전체와 발급자(issuer) 확인
openssl s_client -connect github.com:443 -showcerts </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject -datesissuer에 Zscaler Root CA나 회사 이름이 보이면 → MITM 프록시 확정입니다. github.com인데 발급자가 회사라면 트래픽이 중간에서 재서명되고 있다는 뜻이죠.
# curl의 검증 단계를 그대로 들여다보기
curl -v https://github.com 2>&1 | grep -E "issuer|subject|SSL certificate|verify"# 시스템 시간과 인증서 유효기간 비교 (원인 ④ 확인)
date
openssl s_client -connect github.com:443 </dev/null 2>/dev/null \
| openssl x509 -noout -datesnotBefore가 현재보다 미래라면 PC 시계부터 맞추세요(sudo ntpdate/w32tm /resync).
3. 도구별 복붙 해결법 (일단 빨리)
회사에서 받은(또는 4단계에서 추출한) 루트 인증서를 corp-ca.pem이라 가정합니다.
git
# 전역 설정
git config --global http.sslCAInfo /etc/ssl/certs/corp-ca.pem
# 특정 저장소만
git config http.https://gitlab.company.com.sslCAInfo /etc/ssl/certs/corp-ca.pemcurl
curl --cacert /etc/ssl/certs/corp-ca.pem https://github.com
# 환경변수로 전역 적용
export CURL_CA_BUNDLE=/etc/ssl/certs/corp-ca.pempip — pip.conf(Linux/macOS: ~/.pip/pip.conf, Windows: %APPDATA%\pip\pip.ini)
[global]
cert = /etc/ssl/certs/corp-ca.pem# 일회성
pip install --cert /etc/ssl/certs/corp-ca.pem requests
# requests 계열 라이브러리 전역
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/corp-ca.pem
export SSL_CERT_FILE=/etc/ssl/certs/corp-ca.pemnpm / node
npm config set cafile /etc/ssl/certs/corp-ca.pem
# Node 런타임 전역 (Yarn, fetch 등 포함)
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-ca.pem환경변수 방식(
REQUESTS_CA_BUNDLE,NODE_EXTRA_CA_CERTS,SSL_CERT_FILE)은 CI/CD 러너나 Docker 컨테이너에서 특히 유용합니다. 도구마다 설정하지 않고Dockerfile이나 러너 환경에 한 번만 주입하면 끝나니까요.
4. OS별 CA 영구 등록 (제대로 한 번에)
매번 옵션을 붙이기 싫다면 시스템 신뢰 저장소에 한 번 등록해 두는 게 정공법입니다.
| OS | 인증서 위치 | 적용 명령 |
|---|---|---|
| Ubuntu/Debian | /usr/local/share/ca-certificates/corp-ca.crt | sudo update-ca-certificates |
| RHEL/CentOS | /etc/pki/ca-trust/source/anchors/corp-ca.crt | sudo update-ca-trust |
| macOS | 시스템 키체인 | sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-ca.pem |
| Windows | 신뢰할 수 있는 루트 저장소 | certutil -addstore -f "ROOT" corp-ca.crt (또는 certmgr.msc) |
주의: 시스템에 등록해도 Python(certifi)·Node·git for Windows는 자체 CA 번들을 쓰는 경우가 많아 3단계 설정을 병행해야 할 수 있습니다.
Zscaler 등 사내 프록시 루트 인증서 추출하기
IT팀에 요청하는 게 가장 확실하지만, 직접 뽑을 수도 있습니다.
# 프록시가 재서명한 루트 인증서를 그대로 저장
openssl s_client -connect github.com:443 -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > corp-ca.pem브라우저에서 자물쇠 아이콘 → 인증서 보기 → 체인 최상단(Zscaler Root CA)을 Base64(.pem)로 내보내도 됩니다. 추출한 파일을 위 3·4단계 흐름에 그대로 등록하면 됩니다.
5. sslVerify=false, 제발 쓰지 마세요
급하다고 아래 명령들로 검증을 꺼버리는 건 MITM 공격에 문을 활짝 여는 행위입니다.
⚠️ 위험 — 임시방편 금지
Bashgit config --global http.sslVerify false # 모든 HTTPS 검증 무력화 pip install --trusted-host pypi.org ... # 위변조 패키지 무방비 npm config set strict-ssl false # 공급망 공격에 노출검증을 끄면 누가 중간에서 코드를 바꿔치기해도 알 수 없습니다. 올바른 CA를 등록하는 위 정공법으로 대체하세요.
실무 경험 한 마디
사내에 SSL 인스펙션 프록시가 깔린 뒤로, 개발자 수십 명이 각자 sslVerify false로 우회하던 팀을 본 적이 있습니다. 결국 한 일은 단순했습니다. 회사 루트 인증서를 사내 패키지 저장소에 올리고, 표준 dotfiles와 베이스 Docker 이미지에 CA 등록 스크립트를 한 줄 박아 배포한 것이죠. 그 뒤로 SSL 관련 문의가 거의 사라졌습니다. 개인이 5분 끄는 것보다 팀이 한 번 제대로 까는 것이 훨씬 쌉니다.
의사결정 체크리스트
openssl s_client ... -issuer→ issuer가 회사명? → MITM 프록시, 루트 CA 추출·등록- issuer는 정상인데 에러? → CA 번들 만료,
update-ca-certificates/certifi 갱신 - 사내 GitLab/Nexus 대상? → 자체 서명 인증서, 해당 호스트만 sslCAInfo 등록
expired/not yet valid? → 시스템 시간 동기화
자주 묻는 질문 (FAQ)
Q. CA를 등록했는데도 여전히 에러가 납니다.
A. 도구가 시스템 저장소를 안 보는 경우입니다. Python은 certifi(python -m certifi로 경로 확인 후 REQUESTS_CA_BUNDLE), Node는 NODE_EXTRA_CA_CERTS, git for Windows는 http.sslCAInfo를 별도로 지정하세요. 인증서가 PEM(Base64) 형식인지도 확인합니다.
Q. Docker 컨테이너 안에서만 SSL 에러가 납니다.
A. 컨테이너는 호스트의 CA 저장소를 상속하지 않습니다. Dockerfile에 COPY corp-ca.crt /usr/local/share/ca-certificates/ 후 RUN update-ca-certificates를 넣거나, 빌드 인자로 NODE_EXTRA_CA_CERTS/REQUESTS_CA_BUNDLE를 주입하세요.
Q. 회사망에서만 에러가 나고 집에서는 정상입니다. A. 전형적인 SSL 인스펙션 프록시(Zscaler 등) 증상입니다. 회사에서는 트래픽이 재서명되므로 회사 루트 CA를 등록해야 합니다. issuer를 확인하면 회사명이 보일 겁니다.
Q. VPN을 켜면 에러가 납니다.
A. VPN 경유 시 프록시가 끼어들어 인증서가 바뀌는 경우입니다. VPN on/off 각각 openssl s_client로 issuer를 비교해 보고, 프록시 루트 CA를 시스템에 등록하면 양쪽 모두 동작합니다.
AI 도구는 자료 조사와 초안 작성의 보조 수단으로 사용될 수 있습니다. Nodelog는 공개 전 내용과 출처를 검토하고, 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서를 함께 확인하도록 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
댓글
첫 번째 댓글을 남겨보세요.