파일로 받은 인증서와 서버가 내려주는 인증서가 다른 경우가 많다. 문제를 볼 때는 항상 서버에서 직접 받아 확인한다.
# 전체 정보
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -text
# 유효기간
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -dates
# 발급자와 주체
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer -subject
# 서버가 보내는 체인 전부
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
-servername 은 SNI 다. 한 IP 에서 여러 도메인을 서비스하면 이 값에 따라 다른 인증서가 나오므로 빠뜨리면 엉뚱한 것을 보게 된다.
-showcerts 출력에서 -----BEGIN CERTIFICATE----- 가 몇 번 나오는지 센다. 하나뿐이면 중간 인증서를 보내지 않는 것이며, 클라이언트에 따라 신뢰 실패가 난다. 자세한 것은 인증서 체인이 끊길 때 에 있다.
StartTLS 를 쓰는 프로토콜은 옵션을 준다.
openssl s_client -connect smtp.example.com:587 -starttls smtp
openssl s_client -connect ldap.example.com:389 -starttls ldap
# 인증서 내용
openssl x509 -in server.crt -noout -text
# 유효기간 · 주체 · 발급자만
openssl x509 -in server.crt -noout -dates -subject -issuer
# 어떤 도메인에 유효한지 (SAN)
openssl x509 -in server.crt -noout -ext subjectAltName
# CSR · 키
openssl req -in server.csr -noout -text
openssl rsa -in server.key -noout -check # RSA
openssl pkey -in server.key -noout -text_pub # 종류 무관
허가된 도메인은 CN 이 아니라 SAN(Subject Alternative Name) 으로 본다. 브라우저는 오래전부터 CN 을 이름 검증에 쓰지 않으므로, SAN 에 없는 이름은 CN 에 있어도 경고가 난다. 사설 인증서에 도메인을 추가하려면 SAN 을 넣어 CSR 을 다시 만들고 재발급받아야 한다. 발급된 인증서를 나중에 고칠 수는 없다.
파일이 PEM 인지 DER 인지 헷갈리면 텍스트인지부터 본다. -----BEGIN 으로 시작하면 PEM 이다.
# DER 이면 위 명령이 실패한다. 이때는 형식을 지정한다
openssl x509 -inform DER -in server.crt -noout -text
# 변환
openssl x509 -inform DER -in server.crt -out server.pem
세 값이 모두 같아야 짝이 맞는다.
openssl x509 -noout -modulus -in server.crt | openssl sha256
openssl rsa -noout -modulus -in server.key | openssl sha256
openssl req -noout -modulus -in server.csr | openssl sha256
ECDSA 키는 modulus 가 없으므로 공개키를 직접 비교한다.
openssl x509 -in server.crt -noout -pubkey | openssl sha256
openssl pkey -in server.key -pubout | openssl sha256
failed to parse private key 는 대개 형식 문제다. PKCS#1(BEGIN RSA PRIVATE KEY)과 PKCS#8(BEGIN PRIVATE KEY)을 요구하는 쪽이 다르고, 암호가 걸린 키(ENCRYPTED PRIVATE KEY)를 그대로 넣어도 같은 오류가 난다.
# PKCS#1 -> PKCS#8
openssl pkcs8 -topk8 -nocrypt -in server.key -out server.pk8.key
# 암호 제거
openssl rsa -in encrypted.key -out plain.key
openssl verify -CAfile ca.crt server.crt
openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt
-untrusted 에 중간 인증서를 주는 형태가 실제 체인과 같다. Root 만으로 검증이 안 되면 중간 인증서가 빠진 것이다.
kubectl create secret tls my-tls --cert=fullchain.crt --key=server.key -n <namespace>
kubectl apply 는 매니페스트 파일을 받는 명령이므로 .crt · .key 를 바로 넘기면 no objects passed to apply 가 난다. 인증서에서 시크릿을 만들 때는 create secret tls 를 쓴다.
--cert 에 넣는 파일은 서버 인증서 하나가 아니라 서버 인증서 + 중간 인증서 를 이어 붙인 fullchain 이어야 한다.
cat server.crt intermediate.crt > fullchain.crt
이미 만든 시크릿 내용을 확인할 때는 다음처럼 꺼내 본다.
kubectl get secret my-tls -n <namespace> -o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/tls.crt
grep -c 'BEGIN CERTIFICATE' /tmp/tls.crt
openssl x509 -in /tmp/tls.crt -noout -subject -issuer -dates -ext subjectAltName