크롬이 말하는 것
인증서는 브라우저가 이미 신뢰하는 누군가가 서명했을 때만 의미가 있습니다. 크롬은 이것을 체인으로 확인합니다. 사이트 인증서(leaf)는 중간 인증서가 서명했고, 중간 인증서는 루트가 서명했으며, 그 루트가 크롬이 쓰는 신뢰 저장소에 있어야 합니다.
NET::ERR_CERT_AUTHORITY_INVALID는 이 체인이 신뢰하는 루트에서 끝나지 않았다는 뜻입니다. 다른 면에서는 멀쩡한 인증서일 수 있습니다. 이름도 맞고 만료되지도 않았습니다. 크롬은 그저 서명한 쪽을 믿어도 되는지 모를 뿐입니다.
화면 전체에 “연결이 비공개로 설정되어 있지 않습니다”라는 경고가 뜹니다. 다른 브라우저는 같은 실패를 다르게 표시합니다. 파이어폭스는 SEC_ERROR_UNKNOWN_ISSUER, 자체 서명 인증서라면 MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT이고, 사파리는 인증서를 신뢰할 수 없다고 말합니다.
먼저 발급자를 보세요
발급자 이름만 봐도 어느 경우인지 대부분 알 수 있으니 10초를 쓸 가치가 있습니다. 크롬 주소창의 “주의 요함” → “인증서가 유효하지 않음”을 눌러 “발급자”를 봅니다. 터미널에서는 이렇게 봅니다.
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null 2>/dev/null \
| grep -E '^ +([0-9]+ )?[si]:'
| 발급자로 보이는 것 | 대개 뜻하는 것 |
|---|---|
| 주체와 같음(사이트 자기 이름) | 자체 서명 인증서 |
| 공인 CA(Let’s Encrypt, DigiCert, Sectigo, GlobalSign 등)인데 체인에 인증서가 하나뿐 | 서버의 중간 인증서 누락 |
| 백신 제품, 회사 이름, 방화벽·프록시 제조사 | 내 쪽에서 TLS를 가로채고 있음 |
Kubernetes Ingress Controller Fake Certificate, TRAEFIK DEFAULT CERT, 호스팅 회사 이름, 공유기·NAS 모델명 | 기본 임시 인증서. 실제 인증서가 설정되지 않음 |
(STAGING)으로 시작하는 이름 | Let’s Encrypt 테스트용 인증서 |
Cloudflare Origin으로 시작하는 이름 | Cloudflare Origin CA 인증서가 브라우저에 바로 노출됨 |
| 회사 내부 CA | 사설 PKI. 이 기기에 루트가 설치되지 않음 |
그다음 질문 하나만 더 답하면 됩니다. 이 사이트가 어디서나 실패하는지, 나만 실패하는지입니다. SSL 점검은 서울에 있는 서버에서 접속해 표준 Mozilla 루트 목록으로 체인을 검증합니다. 여기서 체인이 OK로 나오는데 나는 계속 오류를 본다면 원인은 내 쪽입니다.
방문자라면
여러 사이트에서 한꺼번에 오류가 나거나, 특정 네트워크나 특정 기기에서만 난다면 서버 문제가 아닙니다.
백신의 HTTPS 검사. 일부 백신은 HTTPS를 복호화해 검사하면서 사이트마다 자기 루트 인증서로 다시 서명합니다. 보통은 설치 프로그램이 그 루트를 신뢰 저장소에 넣어 두기 때문에 알아챌 일이 없습니다. 설치가 깨졌거나 파이어폭스(자체 저장소를 씀)를 쓰면 모든 HTTPS 사이트가 백신 제조사를 발급자로 단 채 실패합니다. 백신 설정에서 HTTPS/SSL 검사 옵션을 끄거나 백신을 다시 설치하세요.
회사의 검사 프록시. 회사 노트북에는 회사 루트가 설치돼 있어 아무 문제가 없습니다. 개인 휴대폰을 사무실 와이파이에 붙이면 루트가 없으니 전부 실패합니다. 우회할 문제가 아니라 IT 부서에 물어볼 정책 문제입니다.
캡티브 포털. 호텔·공항·카페 와이파이는 로그인 화면을 보여 주려고 첫 요청을 가로챕니다. 아무 http:// 페이지(예: http://neverssl.com)를 열어 로그인 화면을 띄우고, 로그인한 뒤 다시 시도하세요.
오래된 기기. 몇 년 동안 업데이트를 받지 못한 기기는 루트 저장소도 낡았습니다. 새 CA나 새 루트가 들어 있지 않습니다. 예를 들어 Let’s Encrypt 인증서는 ISRG Root X1으로 이어지는데, 안드로이드는 7.1.1부터 이 루트를 담았습니다. 예전 안드로이드를 받쳐 주던 교차 서명 체인은 이미 만료됐습니다. 근본 해결책은 운영체제 업데이트나 자체 루트 저장소를 가진 브라우저뿐입니다. 파이어폭스가 그렇고, 데스크톱 크롬도 그렇습니다.
시스템 시계가 틀리면 보통 NET::ERR_CERT_DATE_INVALID라는 다른 오류가 나지만, 확인하는 데 드는 비용이 거의 없으니 같이 보세요.
공개 사이트에서는 경고를 무시하고 넘어가지 마세요. 누군가 연결을 가로채고 있을 때 보이는 화면과 똑같습니다. 도메인이 HSTS를 쓰면 크롬은 넘어가는 선택지 자체를 주지 않습니다.
사이트 운영자라면
1. 서버가 중간 인증서를 보내지 않음
leaf는 공인 CA 것인데 서버가 그것만 보냅니다. 데스크톱 크롬은 인증서 안의 AIA URL에서 중간 인증서를 직접 받아 와 이 문제를 가려 주는 경우가 많습니다. 크롬에서 AUTHORITY_INVALID가 보이는 것은 그 다운로드가 실패했을 때뿐이지만, curl·Java·Python·안드로이드 앱은 매번 실패합니다.
해결: 전체 체인을 설정합니다(certbot이라면 fullchain.pem, 상용 인증서라면 내 인증서 + CA 번들, leaf가 앞). 이렇게 확인합니다.
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null
“Certificate chain”에 인증서가 최소 두 개 있고 Verify return code: 0 (ok)여야 합니다. 21 (unable to verify the first certificate)는 중간 인증서가 빠졌다는 뜻입니다. 파일 구성, 순서, 키 불일치 문제는 SSL 체인 누락·도메인 불일치에 정리해 두었습니다.
2. 자체 서명 또는 임시 인증서가 나가고 있음
대개 누가 일부러 자체 서명 인증서를 고른 게 아닙니다. 이 이름에 실제 인증서가 설정되지 않아서 어떤 구성 요소가 내장 기본 인증서로 물러선 것입니다.
- ingress-nginx는 Ingress에 맞는 TLS 시크릿이 없거나, 시크릿이 다른 네임스페이스에 있거나,
tls:아래hosts에 이 이름이 없을 때Kubernetes Ingress Controller Fake Certificate를 내보냅니다. - Traefik은 이 호스트명에 맞는 TLS 라우터가 없거나 ACME 발급이 실패했을 때
TRAEFIK DEFAULT CERT를 내보냅니다. - 호스팅 관리 화면은 도메인에 SSL을 켜기 전까지 자체 서명 임시 인증서를 내보내는 경우가 많습니다.
- 장비(공유기, NAS, 프린터, 관리 인터페이스)는 자체 서명 인증서를 달고 출고됩니다.
해결: 이 호스트명에 실제 인증서를 설정하고, 기본값으로 물러선 구성 요소의 로그를 확인합니다. Kubernetes라면 kubectl describe ingress <name>과 컨트롤러 로그가 시크릿을 못 쓴 이유를 알려 줍니다. cert-manager를 쓴다면 kubectl get certificate로 발급이 실제로 성공했는지 보세요.
로컬 개발이라면 경고와 싸우지 마세요. mkcert가 로컬 CA를 만들어 시스템과 브라우저 신뢰 저장소에 설치하고, localhost나 원하는 이름으로 인증서를 발급해 줍니다.
3. Let’s Encrypt 스테이징 인증서가 운영에 나감
certbot의 --staging(또는 --test-cert)과 다른 클라이언트의 ACME 스테이징 엔드포인트는 일부러 어떤 브라우저도 신뢰하지 않는 CA에서 인증서를 발급합니다. 발급자 이름이 (STAGING)으로 시작합니다. 설정을 시험해 보고 그대로 두기 쉽습니다.
해결: 운영 엔드포인트로 다시 발급합니다. certbot이라면 --staging 없이 같은 명령을 실행하고, 현재 인증서가 아직 유효하다며 건너뛰면 --force-renewal을 붙입니다. 그다음 웹 서버를 리로드합니다.
4. Cloudflare Origin CA 인증서가 브라우저에 노출됨
Origin CA 인증서는 무료이고 유효 기간도 길지만, Cloudflare만 신뢰합니다. 방문자가 언제나 Cloudflare 엣지 인증서만 본다면 괜찮습니다. 이럴 때 깨집니다.
- DNS 레코드를 Proxied에서 DNS only로 바꿨을 때
- 방문자가 IP나 다른 호스트명으로 원 서버에 직접 접속할 때
해결: 레코드를 프록시 상태로 유지하거나, 직접 서비스되는 이름에는 공인 인증서(Let’s Encrypt면 충분합니다)를 원 서버에 둡니다. 두 구간의 인증서 관계는 Cloudflare SSL 모드에 정리했습니다.
5. 외부에 노출된 이름에 사설 CA를 씀
사내 CA(Active Directory 인증서 서비스, HashiCorp Vault, step-ca, 몇 년 전 누군가 OpenSSL로 만든 CA)는 모든 클라이언트가 루트를 신뢰하는 한 내부 서비스에 써도 괜찮습니다. 그런데 같은 이름에 외부 사용자나 관리되지 않는 기기가 접속하면 이 오류를 봅니다.
해결: 그 이름에는 공인 인증서를 쓰거나, 필요한 모든 클라이언트에 루트를 설치합니다.
# Debian / Ubuntu
sudo cp corp-root.crt /usr/local/share/ca-certificates/corp-root.crt
sudo update-ca-certificates
# RHEL / Fedora / Rocky
sudo cp corp-root.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-root.crt
# Windows (관리자 권한 프롬프트)
certutil -addstore -f Root corp-root.crt
운영체제 저장소는 크롬·엣지·사파리에 적용됩니다. 이것을 무시하는 클라이언트가 꽤 있습니다.
- 파이어폭스는 자체 저장소를 씁니다. 설정 → 인증서에서 루트를 가져오거나,
security.enterprise_roots.enabled로 운영체제의 기업 루트를 신뢰하게 합니다. - Java는 자체
cacerts를 씁니다.keytool -importcert -cacerts -alias corp-root -file corp-root.crt - Python requests는 certifi 번들을 씁니다.
REQUESTS_CA_BUNDLE이 루트가 든 파일을 가리키게 합니다. - Node.js는 내장 목록을 씁니다.
NODE_EXTRA_CA_CERTS=/path/to/corp-root.crt를 설정합니다. - 컨테이너는 호스트가 아니라 이미지 안에 루트를 설치해야 합니다.
6. 이 브라우저가 그 CA를 더는(또는 아직) 신뢰하지 않음
브라우저는 규정 위반 문제가 생긴 CA를 루트 프로그램에서 빼기도 하고, 그 뒤에 발급된 인증서는 해당 브라우저에서 작동하지 않습니다. 반대로 새로 나온 루트는 모든 기기에 퍼지는 데 몇 년이 걸립니다. SSL 점검에서는 체인이 정상인데 특정 브라우저나 운영체제만 거부한다면, 내 체인 맨 위의 루트를 그 플랫폼의 현재 루트 목록과 비교해 보고, 필요하면 그 플랫폼이 담고 있는 루트를 쓰는 CA로 옮기세요.
고친 다음에
openssl s_client -showcerts에 전체 체인과Verify return code: 0 (ok)가 나와야 합니다.- SSL 점검에서 체인이 OK로 나와야 합니다. 여전히 Untrusted라면 옆에 붙은 사유가 남은 경우를 알려 줍니다. “self-signed certificate”(자체 서명), “untrusted root in chain”(신뢰하지 않는 루트), “incomplete chain or unknown issuer”(체인 불완전 또는 알 수 없는 발급자)입니다. 이 점검은 체인을 검증하지만 인증서 폐기 여부는 확인하지 않습니다.
- 크롬만이 아니라 엄격한 클라이언트로도 확인하세요.
curl -sSI https://www.example.com/이면 충분합니다. - 마지막으로 HTTP 점검으로 HTTPS 응답과 리다이렉트가 기대대로 동작하는지 확인합니다.
관련 오류
- NET::ERR_CERT_COMMON_NAME_INVALID: 신뢰되는 인증서지만 이름이 다릅니다.
- NET::ERR_CERT_DATE_INVALID: 만료됐거나 아직 유효 기간 전이거나, 기기 시계가 틀렸습니다.
- SSL 체인 누락·도메인 불일치: 둘 중 어느 쪽인지 가리고 체인 파일을 고치는 법.
- Cloudflare 526 에러: 같은 신뢰 문제가 Cloudflare와 원 서버 사이에서 생긴 경우입니다.
내 도메인에서 바로 확인
무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.