Windows 인증서 저장소 실무 가이드 ── 사용자와 컴퓨터, 어느 쪽에 넣을 것인가

· 업데이트: · · 인증서, Windows, 보안, PKI, TLS, PowerShell, 업무 앱, 정보 시스템

수정 이력(4건, 최종 수정 2026년 09월 05일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

본문에서 두 번 표시되던 지식 맵의 중복 부분을 제거했습니다. 기술 설명은 바꾸지 않았습니다.
Codex 리뷰에 따라 상담·문의 링크에 /ko/ 로케일 접두를 붙였습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
이 글의 지식 맵에 포함된 관계를 다시 살펴보았습니다. 본문보다 넓은 주장이 되어 있던 것(조건부일 때만 성립하는 관계, 「방지한다」가 아니라 「완화한다」에 해당하는 관계, 전제가 아니라 권고에 해당하는 관계)을 조건부로 고치거나, 더 정확한 서술어로 바꾸었습니다. 본문의 주장은 바꾸지 않았습니다.
최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22175580)

아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.

Go Komura (2026). 「Windows 인증서 저장소 실무 가이드 ── 사용자와 컴퓨터, 어느 쪽에 넣을 것인가」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/windows-certificate-store-guide/

DOI(등록된 아카이브)
10.5281/zenodo.22175580
DOI(마지막 등록 버전)
10.5281/zenodo.22175581

「온라인자격확인 단말을 갱신하면서 클라이언트 인증서를 새 PC에 다시 넣었더니 연결되지 않는다」, 「개발 머신에서는 은행 API에 붙는데 Windows 서비스로 올리면 『인증서를 찾을 수 없습니다』라고 한다」, 「애초에 certmgr.msc에 보이는 인증서와 certlm.msc에 보이는 인증서 중 어느 쪽이 진짜인지 모르겠다」──클라이언트 인증서를 쓰는 Web API 연동을 수탁으로 만들다 보면, 이런 상담이 주기적으로 들어옵니다.

의료기관의 온라인자격확인, 전자 신청, 은행계 API, 거래처와의 EDI. 예전에는 대기업 인프라 담당만 다루던 클라이언트 인증서를, 지금은 중소기업의 정보시스템 담당자나 업무 앱 개발자가 다루는 시대입니다. 그리고 인증서 관련 사고는 사실 몇 가지 패턴으로 모입니다. 넣을 위치를 잘못 고른다, 비밀 키 권한을 잊는다, 만료를 잊는다──이 세 가지입니다.

이 글에서는 클라이언트 인증서를 쓰는 업무 앱 개발자와, 인증서 교체 작업을 맡는 정보시스템 담당자를 대상으로, 「사용자 저장소와 컴퓨터 저장소 중 어디에 넣을 것인가」라는 판단을 축으로 Windows 인증서 저장소의 구조부터 비밀 키 권한 부여, PowerShell로 만료를 점검하는 방법, .NET에서 쓰는 코드까지 한 번에 정리합니다. 내용은 2026년 8월 시점 Microsoft Learn의 1차 정보에 근거합니다.

1. 먼저 결론

  • Windows의 인증서 저장소는 「사용자(CurrentUser)」와 「컴퓨터(LocalMachine)」 두 계통입니다. 사용자 저장소는 계정마다 별개(레지스트리의 HKEY_CURRENT_USER 아래), 컴퓨터 저장소는 PC 전체에서 공통(HKEY_LOCAL_MACHINE 아래)입니다.12
  • 관리 도구도 두 가지입니다. certmgr.msc가 현재 사용자, certlm.msc가 로컬 컴퓨터의 저장소를 엽니다. PowerShell에서는 Cert:\CurrentUserCert:\LocalMachine입니다.34
  • 어디에 넣을지는 「그 인증서를 쓰는 프로그램이 누구로서 동작하는가」로 정합니다. 대화형 사용자 앱이면 사용자 저장소, Windows 서비스·IIS·작업 스케줄러의 무인 실행이면 컴퓨터 저장소가 원칙입니다(3장의 판단표).
  • 「개발 중에는 됐는데 서비스로 올리니 찾을 수 없다」의 원인은 거의 하나입니다. 개발자가 자신의 사용자 저장소에 넣은 인증서는, 다른 계정으로 동작하는 서비스의 CurrentUser에서는 보이지 않습니다(3장).
  • 인증서와 비밀 키는 별개입니다. 컴퓨터 저장소에 넣기만 해서는 서비스 계정이 비밀 키를 읽지 못하는 경우가 보통입니다. certlm.msc의 「비밀 키 관리」에서 실행 계정에 읽기 권한을 부여합니다.5
  • pfx를 가져올 때 비밀 키는 기본적으로 내보내기 불가가 됩니다. Import-PfxCertificate-Exportable을 지정하지 않는 한 비밀 키를 다시 내보낼 수 없는 형태로 가져옵니다. 이것은 사고가 아니라 바람직한 기본값입니다.6
  • 만료는 점검을 자동화해서 막습니다. Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60처럼, 지정한 일수 이내에 만료되는 인증서를 기계적으로 추출할 수 있습니다.4
  • 지문(thumbprint)을 코드나 구성에 하드코딩하면, 인증서를 갱신할 때마다 죽습니다. 새 인증서는 지문이 반드시 바뀌기 때문입니다. 구성을 밖으로 빼고 신구 병행 기간을 두는 것이 설계의 기본입니다(5장·7장).

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 41건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. 인증서 저장소의 전체 그림 ── 두 위치와 논리 저장소

2.1. 사용자와 컴퓨터, 두 계통

Windows의 인증서 저장소는 크게 두 「위치」로 나뉩니다.1

  • 컴퓨터(로컬 컴퓨터, LocalMachine)의 인증서 저장소: 그 PC에 하나이며, PC상의 모든 사용자와 서비스에 공통입니다. 실체는 레지스트리의 HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates 아래에 있습니다.2
  • 사용자(현재 사용자, CurrentUser)의 인증서 저장소: 사용자 계정마다 별개입니다. 실체는 HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates 아래, 즉 사용자 프로필의 일부입니다.2

이 외에 서비스 계정 단위의 저장소도 있으며3, 실체는 서비스 이름별 레지스트리 키입니다.2 실무에서 먼저 잡아야 할 것은 앞의 두 가지입니다.

중요한 사양이 하나 있습니다. 사용자 저장소의 각 논리 저장소는, 「개인」을 제외하고, 컴퓨터 저장소의 같은 이름 저장소 내용을 상속해서 보여 줍니다. 1 예를 들어 컴퓨터 저장소의 「신뢰할 수 있는 루트 인증 기관」에 사내 CA 인증서를 넣으면, 모든 사용자의 「신뢰할 수 있는 루트 인증 기관」에도 그 인증서가 나타납니다. 반대로 말하면, 「개인」 저장소만은 상속되지 않으므로, 클라이언트 인증서(=개인 저장소에 넣는 것)는 「누구에게 보여야 하는가」를 스스로 정해야 합니다. 이 비대칭성이 이 글 전체의 주역입니다.

사용자(CurrentUser)계정마다 별개컴퓨터(LocalMachine)PC에 1개·모든 사용자와 서비스에 공통내용을 상속해서 보임상속상속개인(My)※상속되지 않음=넣을 위치를 직접 정함신뢰할 수 있는 루트 인증 기관(Root)중간 인증 기관(CA)신뢰할 수 있는 게시자(TrustedPublisher)개인(My)신뢰할 수 있는 루트 인증 기관(Root)중간 인증 기관(CA)신뢰할 수 있는 게시자(TrustedPublisher)

2.2. 주요 논리 저장소

각 위치 안은 역할별 논리 저장소로 나뉩니다. certmgr.msc / certlm.msc에서 보이는 폴더가 그것이고, PowerShell이나 명령에서 볼 때는 영어 내부 이름을 씁니다.24

표시 이름 내부 이름 무엇을 넣는 위치인가
개인 My 자신(이 PC·이 사용자)이 쓰는 인증서. 클라이언트 인증서·서버 인증서는 여기. 비밀 키와 연결되는 곳도 여기
신뢰할 수 있는 루트 인증 기관 Root 신뢰의 기점이 되는 루트 CA 인증서. 여기에 넣은 CA 아래는 「신뢰됨」
중간 인증 기관 CA 루트와 말단을 잇는 중간 CA 인증서. 체인 구축의 재료
신뢰할 수 있는 게시자 TrustedPublisher 서명된 소프트웨어의 게시자로 신뢰하는 인증서(8장)

2.3. 세 개의 창 ── certmgr.msc / certlm.msc / Cert: 드라이브

같은 저장소를 보는 수단이 세 가지 있습니다.34

  • certmgr.msc: 현재 사용자의 저장소를 여는 관리 콘솔.
  • certlm.msc: 로컬 컴퓨터의 저장소를 여는 관리 콘솔.
  • PowerShell의 Cert: 드라이브: Cert:\CurrentUser\...Cert:\LocalMachine\... 계층으로 저장소를 파일 시스템처럼 다룰 수 있습니다. 인증서는 지문으로 식별됩니다.

참고로, mmc.exe에 인증서 스냅인을 수동으로 추가할 때는 「사용자 계정」, 「컴퓨터 계정」, 「서비스 계정」 세 종류에서 대상을 고릅니다. 관리자가 아닌 사용자가 관리할 수 있는 것은 자신의 사용자 계정 저장소뿐입니다.3

문제 조사의 첫걸음은, 「앱이 어느 저장소를 보고 있는가」와 「내가 어느 저장소를 보고 있는가」를 맞추는 것입니다. certmgr.msc를 들여다보며 서비스 장애를 조사해도, 보고 있는 위치가 다르면 답은 나오지 않습니다.

3. 어디에 넣을 것인가 ── 프로그램 실행 형태로 정하는 판단표

판단 기준은 하나입니다. 그 인증서를 쓰는 프로그램은 누구의 계정으로 동작하는가.

실행 형태 실행 계정 넣는 저장소 비고
대화형 사용자가 실행하는 데스크톱 앱 로그온 사용자 본인 사용자(Cert:\CurrentUser\My) 쓰는 사람 계정마다 도입이 필요. 공유 PC에서 여러 사람이 쓰면 컴퓨터 저장소도 검토
Windows 서비스 LocalSystem / NETWORK SERVICE / 전용 서비스 계정 컴퓨터(Cert:\LocalMachine\My) LocalSystem 이외(NETWORK SERVICE·전용 계정 등)는 비밀 키 읽기 권한 부여가 필수(4장). LocalSystem은 기본 SYSTEM 권한으로 읽을 수 있음
IIS상의 Web 앱 애플리케이션 풀의 ID 컴퓨터 위와 같음
작업 스케줄러의 무인 실행(사용자 로그온 여부와 관계없이 실행) 작업에 지정한 계정 컴퓨터 권장 실행 계정의 사용자 저장소로도 돌릴 수는 있지만, 프로필이나 저장소가 어떻게 보이는지 검증만 늘고 이점이 거의 없음
브라우저에서의 전자 신청·Web 인증 로그온 사용자 본인 사용자 배포한 본인 외에는 쓰지 못하게 한다는 의미에서도 자연스러움

헷갈리면, 무인으로 도는 것은 컴퓨터 저장소, 사람이 조작하는 것은 사용자 저장소입니다.

3.1. 단골 사고 해부 ── 「개발 중에는 됐는데 서비스로 올리니 찾을 수 없다」

이 사고는 다음 순서로 정확히 재현할 수 있습니다.

  1. 개발자가 자기 PC에서 pfx를 더블클릭해서 가져온다. 마법사의 기본값은 「현재 사용자」이므로, 인증서는 개발자 계정의 사용자 저장소에 들어간다.
  2. 개발 중인 앱은 Visual Studio에서, 즉 개발자 계정으로 동작하므로 StoreLocation.CurrentUser를 열면 인증서가 보인다. 된다.
  3. 운영 서버에 Windows 서비스로 등록한다. 서비스는 NETWORK SERVICE나 전용 계정으로 동작한다.
  4. 서비스 코드가 여는 CurrentUser서비스 실행 계정의 사용자 저장소. 거기는 비어 있다. 「인증서를 찾을 수 없습니다」.
운영 서버개발 머신같은 프로그램을 배치코드가 여는 CurrentUser는서비스 계정의 사용자 저장소Windows 서비스로 등록실행 계정은 NETWORK SERVICE 등거기는 비어 있음→「인증서를 찾을 수 없습니다」개발자 계정의사용자 저장소에 들어감pfx를 더블클릭으로 가져옴마법사 기본값은 「현재 사용자」Visual Studio에서 실행=개발자 계정으로 동작CurrentUser를 열면 찾힘→ 된다

핵심은 사용자 저장소가 「계정 수만큼 존재한다」는 점입니다. 관리자가 certmgr.msc를 열고 「분명히 들어 있는데요?」라고 확인해도, 그것은 관리자 자신의 저장소이지 서비스 계정의 저장소가 아닙니다. 대응은 그때그때 복사하는 것이 아니라, 컴퓨터 저장소에 다시 넣고 코드도 StoreLocation.LocalMachine에 맞추는 것입니다. 그리고 다음 장의 권한 부여까지가 한 세트입니다.

4. 비밀 키와 액세스 권한 ── 두 번째 단골 사고

4.1. 인증서와 비밀 키는 별개

인증서 저장소 목록에 보이는 것은 인증서(공개 정보)이지, 비밀 키 자체가 아닙니다. 클라이언트 인증에서 실제로 필요한 것은 비밀 키를 쓰는 서명 처리이므로, 「목록에 보인다」는 것과 「쓸 수 있다」는 것은 다른 문제입니다. 여기를 혼동하면, 「인증서는 있는데 TLS 핸드셰이크에서 실패한다」, 「Access Denied 계열의 내부 오류가 난다」처럼 겉으로 잘 안 보이는 장애가 됩니다.

4.2. pfx 가져오기의 실무 ── 내보내기 가능 여부는 의사결정

인증서와 비밀 키 쌍은 pfx(PKCS #12) 파일로 주고받으며, Import-PfxCertificate로 저장소에 가져올 수 있습니다.6

$pwd = Get-Credential -UserName '(비밀번호를 아래에 입력)' -Message 'PFX의 비밀번호'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
    -CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password

여기서 중요한 것은, -Exportable을 붙이지 않는 한, 가져온 비밀 키는 다시 내보낼 수 없다는 기본 동작입니다.6 「나중에 이전할 수 있게」라며 무엇이든 내보내기 가능으로 넣는 것은, 비밀 키를 빼 갈 경로를 하나 늘리는 행위입니다. 원본 pfx를 안전하게 보관하는 운용으로 두고, 저장소상의 비밀 키는 내보내기 불가가 기본──이것이 당사의 권고입니다. 참고로, 원본 pfx와 그 비밀번호의 보관이야말로 평문으로 방치되기 쉽습니다. 사고방식은 「Windows 앱의 비밀 정보 저장 ── DPAPI로 평문 설정을 피한다」와 「PowerShell에서 자격 정보를 안전하게 다루기」에서 정리하고 있습니다.

4.3. 서비스 계정에 비밀 키 권한 부여

컴퓨터 저장소에 넣은 인증서의 비밀 키는, 기본적으로 관리자와 SYSTEM 외에는 읽지 못하는 구성이 보통입니다. 이 때문에 LocalSystem으로 동작하는 서비스는 기본값 그대로 비밀 키를 읽을 수 있지만, NETWORK SERVICE·전용 서비스 계정·IIS 앱 풀 ID처럼 그 외 계정으로 돌리는 경우에는, 실행 계정에 읽기 권한을 명시적으로 부여합니다. 절차는 인증서 스냅인 UI에서 할 수 있습니다.5

  1. certlm.msc(또는 컴퓨터 계정을 대상으로 한 인증서 스냅인)를 연다.
  2. 「개인」→「인증서」에서 대상 인증서를 마우스 오른쪽 단추로 클릭하고, 「모든 작업」에서 「비밀 키 관리」를 연다.
  3. 「보안」 탭에서 실행 계정(NETWORK SERVICE, 전용 서비스 계정, IIS의 앱 풀 ID 등)을 추가하고, 「읽기」를 허용한다.5

모든 권한이 필요한 것은 아닙니다. 서명에만 쓰면 읽기로 충분합니다. 반대로, 안 된다고 Everyone에 모든 권한을 주는 것은 비밀 키를 평문 비밀번호 수준으로 떨어뜨리는 행위이므로 절대 피하십시오. 컴퓨터 저장소에 두는 것과 비밀 키 권한 부여는 항상 한 세트──이것을 절차서에 적어 두는 것만으로, 이 계통의 사고는 사라집니다.

5. 만료 사고를 막는다 ── 점검·교체·대장

5.1. PowerShell로 점검한다

인증서의 유효 기간은 NotAfter 속성에 들어 있습니다. Cert: 드라이브에 대한 Get-ChildItem으로 기계적으로 점검할 수 있습니다.4

# 컴퓨터 저장소의 「개인」을 유효 기간 순으로 나열
Get-ChildItem Cert:\LocalMachine\My |
    Sort-Object NotAfter |
    Format-Table Thumbprint, Subject, NotAfter

# 60일 이내에 만료되는 것만 추출(0을 지정하면 이미 만료된 것)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60

-ExpiringInDays는 「지정한 일수 이내에 만료되는 인증서」를 반환하는 매개 변수이며, 0이면 이미 만료된 인증서가 나옵니다.4 이것을 매월 예약 작업으로 모든 서버를 돌리고, 결과를 메일이나 대장으로 모은다──그것만으로 「만료 때문에 월요일 아침부터 자격 확인이 통과되지 않는」 유형의 사고는 거의 막을 수 있습니다.

5.2. 교체 절차 ── 신구 병행 기간과 지문의 함정

인증서 갱신은 「지우고 넣기」가 아니라 「추가한 다음 전환하고, 확인한 뒤에 지우기」입니다.

  1. 새 인증서(pfx)를 같은 저장소에 가져온다. 지문이 다르므로, 신구는 같은 저장소에 공존할 수 있습니다.
  2. 새 인증서의 비밀 키 권한을 부여한다(4장). 갱신 때 잊기 쉬운 것이 여기입니다. 권한은 인증서의 비밀 키마다 붙으므로, 인증서를 바꾸면 부여도 다시 해야 합니다.
  3. 상대 시스템에 대한 신고(인증서 사전 등록이 필요한 API인 경우)를, 구 인증서로 운용을 이어 가면서 먼저 마치고, 신구 어느 쪽이든 받을 수 있는 병행 기간을 확보한다. 전환을 먼저 하면, 상대가 새 인증서를 거부해서 운영 통신이 멈춥니다.
  4. 앱 구성을 새 인증서로 전환하고, 동작을 확인한다.
  5. 충분한 기간 뒤에, 오래된 인증서를 삭제한다.
1. 새 pfx를 같은 저장소로가져오기(신구 공존)2. 새 인증서의비밀 키 권한 부여3. 상대에게 사전 등록(구 인증서 그대로 운용 계속)4. 구성의 지문을 바꿔전환·동작 확인5. 병행 기간 뒤에구 인증서 삭제

이때 가장 큰 함정이 구성 파일이나 코드에 적힌 지문입니다. 지문은 인증서마다 고유하므로, 갱신하면 반드시 바뀝니다. 어디 한 곳이라도 옛 지문을 그대로 참조하면, 「인증서는 갱신했는데 연결되지 않는다」가 일어납니다. 지문이 어디에 적혀 있는지(앱 구성, IIS 바인딩, 스크립트, 상대에 대한 신고)를 대장으로 관리하는 것이 확실합니다.

5.3. 인증서 대장을 권합니다

대장이라고 해도, 우선은 Excel 한 장이면 충분합니다. 최소한 용도/발급자/주체/지문/들어 있는 위치(서버 이름+저장소)/비밀 키 권한을 가진 계정/유효 기간/갱신 절차 링크/담당자 열을 만들고, 5.1의 점검 결과와 대조합니다. 인증서 사고의 실태는 기술 문제가 아니라 「아무도 목록을 갖고 있지 않다」는 문제이므로, 대장이 가장 효과가 있습니다.

6. 검증과 실패를 읽는 법 ── 체인과 루트 배포

6.1. 체인 검증의 기본과 certutil

「이 인증서는 신뢰되지 않습니다」 계열의 오류는, 말단 인증서에서 루트 CA까지의 체인(증명 경로)이 어딘가에서 끊긴 상태입니다. 원인을 가려내려면 certutil이 편리합니다.7

입수할 수 없음(제시·AIA·저장소 모두)배포되지 않음만료말단 인증서(클라이언트 인증서·서버 인증서)중간 CA 인증서두는 곳: 중간 인증 기관(CA) 저장소루트 CA 인증서두는 곳: 신뢰할 수 있는 루트 인증 기관(Root)체인을 구축할 수 없음(단골 원인 1)「신뢰되지 않습니다」 오류(단골 원인 2)유효 기간 오류(단골 원인 3)
:: 인증서 파일의 체인을 구축·검증한다(해지 확인 URL 가져오기 포함)
certutil -urlfetch -verify client.cer

:: 대상 앱이 사용자 저장소를 쓰면 -user를 붙여 같은 맥락에서 검증한다
certutil -user -urlfetch -verify client.cer

:: 저장소 내용을 덤프한다(-user를 붙이면 사용자 저장소)
certutil -store My
certutil -user -store My

certutil -verify는 인증서·CRL·체인을 검증하며, CACertFile을 지정하지 않으면 완전한 체인을 구축해 검증합니다.7 출력은 길지만, 어느 계층에서 신뢰가 끊겼는지, 해지 정보를 가져왔는지를 읽을 수 있습니다. 전형적인 원인은 (1)중간 CA 인증서를 입수할 수 없다(TLS 상대가 보내지 않고, 인증서의 AIA 정보에서도 가져올 수 없으며, 「중간 인증 기관」 저장소에도 없다), (2)사내 CA 루트가 「신뢰할 수 있는 루트 인증 기관」에 배포되지 않았다, (3)인증서 자체의 만료, 이 세 가지입니다. 중간 CA는 상대로부터의 제시나 AIA를 통한 자동 취득으로도 해결되므로, 저장소 배치는 「확실하게 하는 수단의 하나」로 보십시오.

6.2. 사내 CA·자체 서명의 루트 배포는 GPO/Intune으로

사내 CA나 검증용 자체 서명 인증서를 쓰는 경우, 그 루트 인증서를 각 PC에 배포해야 합니다. 한 대씩 손으로 넣지 말고, 배포 메커니즘에 태웁니다.

  • Active Directory 환경(GPO): 그룹 정책의 컴퓨터 구성\정책\Windows 설정\보안 설정\공개 키 정책에 있는 「신뢰할 수 있는 루트 인증 기관」으로 인증서를 가져오면, 대상 PC에 배포됩니다.8
  • Intune 관리 환경: 「신뢰할 수 있는 인증서」 프로필로 루트/중간 CA 인증서를 배포합니다. Windows에서는 배포 대상 저장소(컴퓨터의 루트/중간, 사용자의 중간)를 고를 수 있습니다.9

2.1에서 말했듯이, 컴퓨터 저장소의 루트에 넣으면 모든 사용자에게 신뢰됩니다.1 그렇기 때문에 반대쪽 위험도 직시하십시오. 자체 서명 인증서를 「신뢰할 수 있는 루트 인증 기관」에 넣는 운용은, 그 PC에 새로운 신뢰의 기점을 심는 행위입니다. 그 비밀 키가 새면, 임의의 사이트나 소프트웨어로 위장하는 인증서를 발행당하는 발판이 됩니다. 상시 운용으로 가져가려면 비밀 키를 적절히 보호한 사내 CA를 세우거나 퍼블릭 CA 인증서로 옮기는 것이 순리이며, 자체 서명 루트는 「검증 환경 한정·기한을 정해 두고」가 원칙입니다.

7. 개발자의 관점 ── .NET에서 저장소를 올바르게 쓰기

7.1. X509Store로 지문 검색하기

.NET에서는 X509Store로 저장소를 열고, Find로 인증서를 가져옵니다.1011

using System.Security.Cryptography.X509Certificates;

static X509Certificate2 GetClientCertificate(string thumbprint)
{
    using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    var found = store.Certificates.Find(
        X509FindType.FindByThumbprint, thumbprint, validOnly: true);

    if (found.Count == 0)
        throw new InvalidOperationException(
            $"인증서를 찾을 수 없습니다: 지문={thumbprint}, " +
            $"위치={store.Location}\\{store.Name}");

    var cert = found[0];
    if (!cert.HasPrivateKey)
        throw new InvalidOperationException(
            $"인증서는 있지만 비밀 키가 연결되어 있지 않습니다(.cer에서 " +
            $"가져온 경우 등): 지문={thumbprint}, 위치={store.Location}\\{store.Name}");

    return cert;
}

3장의 판단이 여기에 직결됩니다. 서비스에서 도는 코드라면 StoreLocation.LocalMachine, 대화형 앱이라면 StoreLocation.CurrentUser입니다. 하나 더, Find의 세 번째 인수 validOnly에 주의하십시오. true검증을 통과한 유효한 인증서만 반환합니다.11 만료된 인증서를 집어 들지 않는 보험이 되는 한편, 체인이 신뢰되지 않은 테스트용 자체 서명 인증서도 「찾을 수 없음」 쪽으로 떨어지므로, 「들어 있는데 찾을 수 없다」일 때는 여기도 의심하십시오. 또한 찾지 못했을 때의 오류 메시지에는, 위 예처럼 어느 저장소를 찾았는지를 반드시 넣습니다. 3장 사고의 조사 시간이 자릿수 단위로 달라집니다.

7.2. HttpClient에 클라이언트 인증서를 올리기

가져온 인증서는 HttpClientHandler.ClientCertificates에 추가해 서버에 제시합니다. 이 컬렉션이, 인증서 기반 클라이언트 인증에서 서버에 제시되는 인증서의 집합입니다.12

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));

var client = new HttpClient(handler);
// 이후는 일반적인 HttpClient로 사용

참고로 .NET Core 계열에서는, 인증서에 키 사용법(Key Usage) 특성이 있는 경우 「Digital Signature」를 포함하지 않으면 요청 전송에 쓰이지 않는다는 점이 문서에 명시되어 있습니다.12 클라이언트 인증서 발급을 의뢰하는 입장이 되면, 용도(클라이언트 인증)를 정확히 전하십시오. 또한 HttpClient는 생성 패턴을 잘못하면 소켓 고갈이나 DNS 변경을 따라가지 못하는 문제가 납니다. 핸들러까지 오래 유지하는 설계는 「HttpClient를 using으로 감싸면 안 된다」에서 다룬 그대로입니다.

7.3. 하드코딩한 지문이 교체에서 죽는 문제

지문 검색은 확실하지만, 지문을 코드에 넣으면 인증서를 갱신할 때마다 빌드와 릴리스가 필요해집니다. 설계에서의 대응은 다음 세 단계입니다.

  • 최소한: 지문을 구성 파일(appsettings 등)로 빼고, 릴리스 없이 갈아 끼울 수 있게 한다. 구성 위치는 5.3의 대장에 올린다.
  • 한 걸음 더: 주체 이름이나 발급자로 검색하고, validOnly: true와 조합해 「그 이름으로 현재 유효한 것 중 NotAfter가 가장 먼 것」을 고른다. 신구 병행 기간에 새 인증서로 자동 전환됩니다. 다만 같은 이름의 의도하지 않은 인증서를 집을 위험이 있으므로, 발급자 확인과 로그 출력을 세트로 둡니다. 또한 이 자동 전환이 성립하는 것은 상대가 인증서 사전 등록을 요구하지 않는 경우뿐입니다. 사전 등록이 필요한 API(5.2)에서는, 가져오기만 한 미등록 인증서로 제멋대로 바뀌어 통신이 멈출 수 있으므로, 등록 완료를 확인한 뒤에 전환하는 구성 외부화 방식에 머무르십시오.
  • 운용으로 닫기: 어느 방식이든, 시작 시 「어느 인증서(지문·기한)를 골랐는지」를 로그에 남긴다. 장애 조사에서도 대장 대조에서도, 이 한 줄이 효과를 냅니다.

8. 코드 서명 인증서와의 관계 ── 「신뢰할 수 있는 게시자」 저장소

지금까지 다룬 것은 통신(TLS)용 인증서이지만, 인증서 저장소에는 또 하나의 세계──코드 서명──이 함께 있습니다. 2.2 표에 나온 「신뢰할 수 있는 게시자(TrustedPublisher)」 저장소가 그 접점이며, 서명된 소프트웨어의 게시자 인증서를 신뢰됨으로 등록하는 위치입니다. 사용자·컴퓨터 양쪽 위치에 존재하며10, 사내 배포 앱의 게시자를 GPO로 각 PC의 TrustedPublisher에 배포하는 식의 운용에 쓰입니다.

앱을 「배포하는 쪽」으로서 코드 서명이나 SmartScreen 경고(「Windows가 PC를 보호했습니다」)에 대처해야 하는 분은, 별도 글 「Windows에서 「Windows가 PC를 보호했습니다」가 나오는 이유」에 정리해 두었습니다. 이 글의 지식(저장소의 두 계통, 루트 배포)은 그대로 전제 지식으로 쓸 수 있습니다.

9. 정리

  • 인증서 저장소는 사용자(CurrentUser)와 컴퓨터(LocalMachine) 두 계통입니다. certmgr.msc / certlm.msc / Cert: 드라이브는 같은 것을 보는 세 개의 창입니다. 조사의 첫걸음은 「어느 저장소 이야기인가」를 맞추는 것입니다.
  • 넣는 위치는 「프로그램이 누구로서 동작하는가」로 정합니다. 무인 실행(서비스·IIS·작업)은 컴퓨터 저장소, 대화형 앱은 사용자 저장소가 원칙입니다.
  • 「개발 중에는 됐는데 운영에서 찾을 수 없다」는, 개발자의 사용자 저장소와 서비스 계정의 사용자 저장소가 별개이기 때문입니다. 컴퓨터 저장소+StoreLocation.LocalMachine에 맞춰 해결합니다.
  • 컴퓨터 저장소에 두는 것과 「비밀 키 관리」에서 읽기 권한을 부여하는 것은 한 세트입니다. 갱신 때 다시 부여하는 것도 잊지 마십시오.
  • pfx 가져오기는 기본적으로 내보내기 불가입니다. -Exportable은 정말 필요할 때만 씁니다. 원본 pfx와 비밀번호 보관도 설계에 넣습니다.
  • 만료는 Get-ChildItem Cert: ... -ExpiringInDays의 정기 점검과 인증서 대장으로 막습니다. 교체는 「추가→전환→확인→삭제」 순이며, 구성 안의 지문 갱신 누락에 주의합니다.
  • 체인을 가려내는 데는 certutil -urlfetch -verify를 씁니다. 사내 CA 루트는 GPO/Intune으로 배포하고, 자체 서명을 루트에 넣는 운용은 검증 환경 한정·기한을 정해 두고 합니다.
  • 코드에서는 지문을 구성으로 빼고, 고른 인증서를 로그에 남깁니다. 그것만으로 인증서 기인 장애 대응이 달라집니다.

관련 글

관련 상담 영역

합동회사 고무라소프트에서는 클라이언트 인증서를 쓰는 Web API 연동(은행계 API, 온라인자격확인 등)을 넣은 업무 앱 개발, 「인증서를 찾을 수 없다」「갱신하니 연결되지 않는다」 유형의 장애 조사, 인증서 교체 절차 정비를 다룹니다. 저장소의 어디를 보면 되는지 모르겠다는 단계의 상담이어도 괜찮습니다.

참고 링크

  1. Microsoft Learn, Local Machine and Current User Certificate Stores. 컴퓨터의 인증서 저장소가 PC에 대해 로컬이며 모든 사용자에 공통이고 HKEY_LOCAL_MACHINE 아래에 있다는 것, 사용자의 인증서 저장소가 사용자 계정마다이며 HKEY_CURRENT_USER 아래에 있다는 것, 사용자 저장소가 「개인」 저장소를 제외하고 컴퓨터 저장소의 내용을 상속한다는 것(컴퓨터의 「신뢰할 수 있는 루트 인증 기관」에 추가한 인증서가 각 사용자의 같은 저장소에도 나타난다는 것)에 대해.  2 3 4

  2. Microsoft Learn, System Store Locations. CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE의 레지스트리 위치(각각 HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE의 Software\Microsoft\SystemCertificates), 미리 정의된 논리 저장소가 MY·Root·Trust·CA라는 것, 서비스용 저장소가 서비스 이름별 레지스트리 키(Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates)에 있다는 것, 그룹 정책 배포용 저장소가 별도로 존재한다는 것에 대해.  2 3 4 5

  3. Microsoft Learn, How to: View certificates with the MMC snap-in. certlm.msc가 로컬 장치(로컬 컴퓨터)의 인증서를, certmgr.msc가 현재 사용자의 인증서를 관리하는 도구라는 것, 인증서 스냅인 대상으로 「컴퓨터 계정」「사용자 계정」「서비스 계정」 세 종류가 있다는 것, 관리자가 아닌 사용자는 자신의 사용자 계정 인증서만 관리할 수 있다는 것에 대해.  2 3 4

  4. Microsoft Learn, about_Certificate_Provider. PowerShell의 Cert: 드라이브가 CurrentUser와 LocalMachine 두 저장소 위치를 가진 계층 네임스페이스라는 것, Get-ChildItem으로 저장소와 인증서를 열거할 수 있다는 것, -ExpiringInDays 매개 변수가 지정 일수 이내에 만료되는 인증서(0이면 이미 만료된 것)를 반환한다는 것, -CodeSigningCert 등의 동적 매개 변수, NotAfter 속성에 유효 기간이 들어간다는 것, 인증서가 지문으로 식별된다는 것에 대해.  2 3 4 5 6

  5. Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. 로컬 컴퓨터의 인증서 저장소를 대상으로 한 인증서 스냅인에서 「비밀 키 관리」(Manage Private Keys)를 열고, 「보안」 탭에서 서비스 실행 계정(예: Network Service)에 「읽기」 액세스 권한을 추가하는 절차에 대해.  2 3

  6. Microsoft Learn, Import-PfxCertificate. Import-PfxCertificate가 PFX 파일에서 인증서와 비밀 키를 지정 저장소로 가져온다는 것, -Exportable 스위치를 지정하지 않으면 가져온 비밀 키를 내보낼 수 없다는 것, -CertStoreLocation·-Password·-FilePath 각 매개 변수의 구문과 사용 예에 대해.  2 3

  7. Microsoft Learn, certutil. certutil -verify가 인증서·CRL·인증서 체인을 검증하고, CA 인증서 파일을 지정하지 않으면 완전한 체인을 구축해 검증한다는 것, -urlfetch 옵션을 쓸 수 있다는 것, certutil -store가 인증서 저장소를 덤프하고, -user 옵션으로 컴퓨터 저장소 대신 사용자 저장소에 접근할 수 있다는 것에 대해.  2

  8. Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. 그룹 정책의 「컴퓨터 구성\정책\Windows 설정\보안 설정\공개 키 정책」 아래 「신뢰할 수 있는 루트 인증 기관」에 인증서를 가져와 도메인 내 클라이언트 컴퓨터로 배포하는 절차와, 필요한 권한(Domain Admins / Enterprise Admins 상당)에 대해. 

  9. Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. Intune의 「신뢰할 수 있는 인증서」 프로필이 루트 또는 중간 CA 인증서를 관리 대상 장치에 배포하는 메커니즘이라는 것, SCEP/PKCS 인증서 프로필의 전제로서 루트 CA에 대한 신뢰 확립에 쓰인다는 것, Windows에서는 배포 대상 저장소로 「컴퓨터 인증서 저장소 - 루트」「컴퓨터 인증서 저장소 - 중간」「사용자 인증서 저장소 - 중간」을 고를 수 있다는 것에 대해. 

  10. Microsoft Learn, X509Store Class. X509Store가 StoreName과 StoreLocation(CurrentUser / LocalMachine)을 지정해 구축할 수 있고, Open 메서드와 OpenFlags(ReadOnly, OpenExistingOnly 등)로 저장소를 열며, Certificates 속성으로 인증서 컬렉션을 가져올 수 있다는 것, 표준 저장소 이름에 My·Root·CA·TrustedPublisher 등이 포함되고, TrustedPublisher 저장소가 CurrentUser·LocalMachine 양쪽에 존재한다는 것에 대해.  2

  11. Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. Find 메서드가 X509FindType(FindByThumbprint 등)과 검색 값으로 인증서를 검색한다는 것, 세 번째 인수 validOnly에 true를 지정하면 검증을 통과한 유효한 인증서만 반환된다는 것에 대해.  2

  12. Microsoft Learn, HttpClientHandler.ClientCertificates Property. ClientCertificates 속성이 인증서 기반 클라이언트 인증에서 서버에 제시되는 X509CertificateCollection이라는 것, .NET Core에서는 인증서에 키 사용법 특성이 있으면 「Digital Signature」를 포함해야 한다는 것에 대해.  2

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

certmgr.msc와 certlm.msc는 무엇이 다른가요?
대상 저장소가 다릅니다. certmgr.msc는 로그온 중인 사용자의 인증서 저장소(현재 사용자, CurrentUser)를, certlm.msc는 컴퓨터의 인증서 저장소(로컬 컴퓨터, LocalMachine)를 엽니다. 컴퓨터 저장소는 PC상의 모든 사용자와 서비스에 공통이며, 관리에는 관리자 권한이 필요합니다. 관리자가 아닌 사용자가 관리할 수 있는 것은 자신의 사용자 저장소뿐입니다. 두 저장소 모두 내용은 「개인」, 「신뢰할 수 있는 루트 인증 기관」 등의 논리 저장소로 나뉘어 있으며, PowerShell에서는 Cert:\CurrentUser와 Cert:\LocalMachine으로 같은 구조가 보입니다.
클라이언트 인증서는 사용자와 컴퓨터 중 어느 저장소에 넣어야 하나요?
그 인증서를 사용하는 프로그램이 「누구로서」 동작하는지로 정합니다. 대화형 사용자가 실행하는 데스크톱 앱이라면, 사용하는 본인의 사용자 저장소(Cert:\CurrentUser\My)가 기본입니다. Windows 서비스·IIS 애플리케이션 풀·작업 스케줄러로 무인 실행하는 프로그램이라면, 컴퓨터 저장소(Cert:\LocalMachine\My)에 넣고, 실행 계정에 비밀 키 읽기 권한을 부여합니다. 사용자 저장소는 계정마다 별개이므로, 개발자가 자신의 사용자 저장소에 넣은 인증서는 다른 계정으로 동작하는 서비스에서는 보이지 않습니다. 이것이 「개발 중에는 됐는데 운영에서 찾을 수 없다」는 사고의 전형적인 원인입니다.
Windows 서비스에서 인증서를 찾을 수 없거나 사용할 수 없을 때는 무엇을 확인하면 되나요?
확인은 두 단계입니다. 첫째는 「어느 저장소를 보고 있는가」입니다. 코드가 StoreLocation.CurrentUser를 열고 있다면, 그것은 서비스 실행 계정의 사용자 저장소이며, 관리자가 certmgr.msc로 보고 있는 자신의 저장소와는 별개입니다. 인증서를 컴퓨터 저장소로 옮기고, 코드도 StoreLocation.LocalMachine에 맞춥니다. 둘째는 「비밀 키를 읽을 수 있는가」입니다. 인증서 목록에 보이는 것과 비밀 키를 사용할 수 있는 것은 별개이며, 컴퓨터 저장소의 비밀 키는 기본적으로 관리자와 SYSTEM만 접근할 수 있는 구성이 일반적입니다. certlm.msc에서 대상 인증서의 「비밀 키 관리」를 열고, 서비스의 실행 계정(NETWORK SERVICE 등)에 「읽기」를 부여하십시오.
인증서 만료를 PowerShell로 사전에 찾아내려면?
Cert: 드라이브에 대한 Get-ChildItem으로 점검할 수 있습니다. 예를 들어 Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter로, 컴퓨터 저장소의 개인 저장소를 유효 기간 순으로 나열할 수 있습니다. 또한 -ExpiringInDays 매개 변수를 쓰면 「지정한 일수 이내에 만료되는 인증서」만 추출할 수 있으며, 0을 지정하면 이미 만료된 인증서가 나옵니다. 이것을 매월 모든 서버에 대해 실행하고, 결과를 인증서 대장과 대조하는 운용으로 해 두면, 「만료 때문에 아침부터 연결할 수 없는」 유형의 사고는 거의 막을 수 있습니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기