VPN 클라이언트가 시작될 때 나타나는 프롬프트는 잘못 읽기 쉽다. VPN 계정 비밀번호도, 터널 비밀번호도 아니며, 입력한다고 연결이 안전해지는 것도 아니다. 이는 저장된 개인 키 표현 하나를 잠금 해제하여 클라이언트가 키 자료를 읽고 인증에 사용할 수 있게 한다. 그 뒤에 일어나는 일은 별개의 문제다.

실제로 답이 틀어지는 곳은 가장자리다. 사람들은 암호 문구가 실행 중인 터널을 보호한다고, 또는 바꾸면 이미 유출된 키 사본이 폐기된다고 가정한다. 두 가정 모두 틀리며, 자격 증명이 노출된 채로 운영자는 처리되었다고 믿는 방식으로 틀린다.

하나의 대화상자, 여러 가지 비밀

개인 키 암호 문구는 파일을 복호화한다. 계정 비밀번호는 서비스에 대한 본인 인증이다. PKCS#12 가져오기 비밀번호는 키와 인증서를 담은 번들을 복호화하며, 키 자체의 암호 문구와 같은 문자열이 아닐 수 있다. 이 프롬프트들은 거의 똑같이 보일 수 있고, 어느 비밀이 어디로 가는지 추측하는 것이 키를 잘못된 필드에 붙여 넣게 되는 이유다.

터널 자체의 암호화는 네 번째 문제다. 데이터 채널은 핸드셰이크 중 협상된 세션 키를 사용하며, 개인 키의 암호 문구는 개별 패킷 보호에 아무 역할도 하지 않는다. 누군가 키 파일을 읽을 수 있다면 오프라인으로 암호 문구를 추측할 수 있지만, 패킷을 읽을 수 있다면 암호 문구는 무관하다.

디스크의 암호화가 덮는 범위

암호화된 PEM 키는 두 가지 형태가 있으며, 헤더가 어느 것인지 알려 준다. 현대적인 PKCS#8 형식은 -----BEGIN ENCRYPTED PRIVATE KEY----- 로 시작하고, 오래된 OpenVPN 설정에서 여전히 흔한 레거시 PEM 형식은 -----BEGIN RSA PRIVATE KEY----- 로 시작하며 바로 아래에 Proc-Type: 4,ENCRYPTED 와 DEK-Info 줄을 포함한다. 파일은 암호 문구에서 파생된 키 아래에서 개인 키를 암호화해 보관하며, 보통 반복 횟수나 작업 계수가 명시된 암호 기반 KDF를 사용한다. OpenSSL pkey 문서가 형식과 읽을 때 적용되는 암호 문구 옵션을 다룬다.

두 가지 결과가 따른다. 약한 암호 문구는 KDF가 허용하는 속도로 오프라인 공격이 가능하므로, 파일이 암호화되어 있어도 파일 권한과 백업 접근 권한은 여전히 중요하다. 그리고 암호 문구 없이 파일만 얻은 공격자는 추측해야 하지만, 파일과 암호 문구를 모두 얻은 사람은 키를 가지며, 암호화되지 않았을 때와 똑같다.

head -3 vpn.key
openssl pkey -in vpn.key -noout -pubout
openssl pkcs12 -in bundle.p12 -info -noout

head -3 는 헤더를 보여 주고, 레거시 파일에서는 암호화를 증명하는 Proc-Type 와 DEK-Info 줄을 보여 준다. 한 줄만으로는 어느 쪽의 증거도 되지 않는다. pkey 줄은 암호 문구를 묻고 공개 절반만 출력하므로, 파일과 암호 문구가 작동함을 개인 키를 노출하지 않고 증명한다. 그 확인에 -text 를 사용하지 말라. 이는 개인 구성 요소인 privateExponent, prime1, prime2 등을 출력하며, 그 출력은 티켓, 채팅, 로그 어디에도 붙여 넣어서는 안 된다. PKCS#12 명령은 번들에 별도의 MAC 또는 암호화 비밀번호가 있는지도 알려 주므로, 동료에게 넘기기 전에 알아 두면 좋다.

키가 로드된 뒤 보호하지 않는 것

잠금 해제는 그 프로세스에 일방향 사건이다. 클라이언트는 KDF에 키를 요청하고 파일을 복호화하며, 필요한 동안 개인 키를 메모리에 유지한다. 그 순간부터 암호 문구는 실행 중인 세션에 대해 아무것도 보호하지 않는다. 프로세스 메모리도, 코어 덤프도, 클라이언트에 붙은 디버깅 세션도, 키가 사용되는 동안 찍은 머신 백업도 보호하지 않는다.

이는 암호 문구가 있는 SSH 키나 비밀번호 관리자의 잠금 해제된 금고와 같은 경계다. 저장 상태의 파일을 훔치는 비용을 높일 뿐, 사용자 권한으로 실행되는 악성코드, 클라이언트에 서명을 요청하는 승인된 애플리케이션, 메모리를 읽을 수 있는 관리자에 대해서는 아무것도 하지 않는다. 키를 아무렇게나 두어도 안전하게 만드는 통제가 아니라 하나의 계층으로 취급해야 한다.

프롬프트가 계속 돌아오는 이유

재연결마다 다시 묻는 클라이언트가 반드시 고장난 것은 아니다. 일부 클라이언트는 세션 동안 암호 문구를 캐시하고, 일부는 OS 키체인에 저장하며, 일부는 이를 제공하는 도우미를 가리킬 수 있다. 따라서 어떤 동작을 얻는지는 클라이언트와 그 구성에 달려 있지, 키 파일에 달려 있지 않다.

반복되는 프롬프트가 실제 불만이라면, 키에서 암호화를 제거하기 전에 클라이언트의 캐싱 및 인증 옵션을 살펴보라. 암호 문구를 제거하면 보호된 파일이 평문 키가 되고, 재연결은 조용해지지만 유일한 저장 상태 통제를 잃는다. 더 나은 답은 보통 같은 파일 권한을 사용하는 지원되는 자격 증명 저장소다.

손실과 노출은 같은 수리가 아니다

잃어버린 암호 문구는 인증서에서 복구할 수 없다. 인증서는 이름을 키에 묶는 공개 자료이며, 개인 키로 돌아가는 경로도 암호 문구에 대한 힌트도 없다. 실질적인 선택은 키의 승인된 백업이나 운영자의 정상 절차를 통해 발급된 새 신원이다. 암호 문구를 '복구'하겠다고 제안하는 사람은 그것을 추측하겠다고 제안하는 것이다.

노출에는 다른 대응이 필요하다. 같은 키를 새 암호 문구로 다시 암호화해도 키 자료는 그대로이므로, 이미 다른 곳에서 잠금 해제된 사본은 여전히 작동한다. 수리는 자격 증명을 폐기하거나 교체하는 것이다. 새 키와 인증서를 발급하고 배포하며, 상대방에서 이전 것을 은퇴시킨다. 그때까지 파일 비밀번호 변경은 정리 작업이지 봉쇄가 아니다. 새 신원이 작동함을 확인한 뒤에만 이전 파일을 백업에서 빼고, 어떤 일련번호나 지문이 그것을 대체했는지 기록하라.

관련 글