수정 약 4분

Apache와 IIS 인증서 교체 절차

Nginx 교체 절차는 앞 글에 적었다. Apache도 설정이 파일 경로를 가리키는 방식이라 거의 같고, 다른 점만 알면 된다. IIS는 구조가 아예 다르다. 인증서가 파일이 아니라 Windows 인증서 저장소에 들어 있다.

Apache / Nginx IIS
인증서 위치 파일 경로 (설정이 가리킴) Windows 인증서 저장소
개인키 별도 파일 인증서와 함께 저장소에
교체 단위 파일 덮어쓰기 + 리로드 저장소 임포트 + 바인딩 변경
흔한 사고 파일 바꾸고 리로드 누락 저장소에 넣고 바인딩 안 바꿈

사고의 모양은 결국 같다. 새 인증서를 준비해 놓고 옛 인증서를 계속 내보낸다.

Apache

기록, 검증, 원자적 교체, 설정 검증, 리로드, 서빙 지문 대조로 이어지는 순서는 Nginx와 같다. 명령만 다르다.

apachectl configtest        # nginx -t 에 해당
apachectl graceful          # 무중단 리로드 (nginx -s reload 에 해당)
# systemd 환경이면
systemctl reload apache2    # Debian 계열
systemctl reload httpd      # RHEL 계열

graceful은 처리 중인 요청을 마치고 워커를 교체한다. restart는 끊는다. 인증서를 바꾸는 데 restart를 쓸 이유는 Apache에서도 없다.

체인 지정

Apache에서 가장 큰 함정은 체인을 지정하는 방식이 버전마다 다르다는 점이다.

# 2.4.8 이상 — fullchain 을 한 파일로
SSLCertificateFile      /etc/ssl/certs/fullchain.pem
SSLCertificateKeyFile   /etc/ssl/private/privkey.pem

# 2.4.8 미만 — 체인을 따로
SSLCertificateFile      /etc/ssl/certs/cert.pem
SSLCertificateChainFile /etc/ssl/certs/chain.pem
SSLCertificateKeyFile   /etc/ssl/private/privkey.pem

SSLCertificateChainFile은 2.4.8에서 deprecated 됐지만 여전히 동작한다. 사고는 옛 설정을 복사해 쓰면서 ChainFile 갱신을 빼먹을 때 난다. leaf는 새것, 체인은 옛것이 되고, 발급사가 중간 인증서를 바꿨다면 그대로 체인 오류다.

mod_md

Apache 2.4.30+는 ACME 클라이언트를 내장하고 있다. certbot 없이 MDomain example.com 설정만으로 발급과 갱신이 된다. 새로 구축한다면 검토해 볼 만하다. 다만 갱신한 인증서를 적용하려면 graceful이 필요한 건 같다.

IIS

IIS의 인증서는 컴퓨터 계정의 인증서 저장소에 있다. 사이트 설정에는 파일 경로 대신 지문(thumbprint)이 적혀 있고, IIS는 그 지문을 가진 인증서를 저장소에서 꺼내 쓴다. 그래서 교체는 두 단계다. 새 인증서를 저장소에 임포트하고, 사이트 바인딩이 새 인증서를 가리키게 바꾼다. 임포트만 하고 끝내면 새 인증서는 저장소에 얌전히 들어 있고 옛것이 계속 서빙된다.

지금 상태 기록

# 지금 바인딩된 인증서의 지문
Get-WebBinding -Protocol https | ForEach-Object {
    $_.certificateHash + "  " + $_.bindingInformation
}

# 외부에서 본 서빙 지문 (교체 후 대조용)
# openssl 이 있는 아무 곳에서:
# openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256

PFX로 임포트

IIS는 개인키가 들어 있는 PFX(PKCS#12)를 쓴다. PEM(fullchain + key)으로 받았다면 먼저 변환한다.

openssl pkcs12 -export -out cert.pfx \
  -inkey privkey.pem -in fullchain.pem \
  -passout pass:임시비밀번호

PFX를 만들 때 fullchain을 넣어야 한다. 중간 인증서가 PFX에 들어 있어야 임포트할 때 중간 인증 기관 저장소에도 같이 들어가고, IIS가 체인을 완성해 보낼 수 있다.

$pw = Read-Host -AsSecureString   # 임시비밀번호 입력
Import-PfxCertificate -FilePath .\cert.pfx `
  -CertStoreLocation Cert:\LocalMachine\My -Password $pw

# 임포트 확인 + 새 지문 확보
Get-ChildItem Cert:\LocalMachine\My |
  Sort-Object NotAfter -Descending |
  Select-Object -First 3 Subject, NotAfter, Thumbprint

저장소는 Cert:\LocalMachine\My(개인)가 맞다. CurrentUser에 넣으면 IIS 서비스 계정이 못 본다. 임포트는 됐는데 목록에 없다면 흔히 이것 때문이다.

바인딩 교체

$thumb = "새_인증서_지문"
$binding = Get-WebBinding -Name "Default Web Site" -Protocol https
$binding.AddSslCertificate($thumb, "My")

IIS 관리자에서는 사이트 → 바인딩 → https 편집 → SSL 인증서 드롭다운에서 새것을 고른다. 이 드롭다운은 “식별 이름”만 보여 줘서 신·구 인증서가 같은 이름으로 두 줄 나오고, 만료일은 안 보인다. GUI로 할 거면 교체 전에 옛 인증서의 식별 이름을 바꿔 두면(예: 뒤에 -old) 고를 때 헷갈리지 않는다.

바인딩 교체는 재시작 없이 바로 적용된다. iisreset은 필요 없고, 오히려 전체 사이트를 끊는다.

서빙되는 인증서 확인

저장소에 들어간 것 말고 실제로 나가는 인증서를 봐야 한다. 바인딩부터 확인한다.

# 바인딩이 새 지문을 가리키는지
Get-WebBinding -Protocol https | Select-Object bindingInformation, certificateHash

그다음 처음에 기록한 외부 지문과 비교한다. 지문이 그대로면 다른 사이트에 바인딩했거나, SNI 구성에서 다른 바인딩이 응답하고 있는 것이다.

옛 인증서는 며칠 둔다

교체하고 나면 옛 인증서를 저장소에서 바로 지우고 싶어진다. 적어도 며칠은 둔다. 남아 있으면 롤백이 바인딩 되돌리기 한 줄로 끝나고, 지웠으면 임포트부터 다시 해야 한다.

# 며칠 뒤, 문제 없으면
Remove-Item Cert:\LocalMachine\My\옛_지문

교체 후 체인 확인

Apache는 ChainFile을 안 바꿔서, IIS는 PFX에 체인을 안 넣어서 중간 인증서가 빠진다. 경로는 달라도 결과는 같다. 확인은 서버 종류와 상관없이 이 명령 하나로 한다.

openssl s_client -connect example.com:443 -servername example.com \
  -verify_return_error </dev/null 2>&1 | grep "Verify return code"

0 (ok)가 아니면 브라우저별 체인 오류가 이미 시작된 것이다. 도메인만 넣으면 바로 확인해 주는 진단 툴도 있다.