Skip to content

필사 모드: OpenSSH 10.4 정독 — 실험적 ML-DSA 복합 서명, mlkem768 기본값의 다음 단계, 그리고 운영자를 무는 폐기들

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며 — 버그픽스 릴리스처럼 보이는 전환점

OpenSSH 10.4는 2026년 7월 6일에 나왔습니다. 릴리스 노트의 자기소개는 겸손합니다 — "a number of security fixes as well as general bugfixes and a couple of new features". 대부분의 운영자는 여기까지 읽고 패키지 업데이트 큐에 넣은 뒤 넘어갈 겁니다.

그런데 그 "a couple of new features" 중 하나가 SSH 프로토콜의 다음 5년을 예고합니다. ML-DSA-44와 Ed25519를 묶은 포스트양자 복합 서명이 실험적으로 들어왔습니다. 키 교환의 포스트양자 전환이 사실상 끝난 시점에서, 이제 서명 차례가 시작된 것입니다.

어제 올린 PQ 인증서가 아직 안 오는 이유 편에서 TLS/WebPKI 쪽 이야기를 다뤘습니다 — 그쪽은 ML-DSA 서명이 너무 커서 Merkle Tree Certificates라는 우회로를 만드는 중입니다. SSH 쪽은 사정이 다르고, 그래서 다른 길을 갑니다. 이 글은 OpenSSH 10.0부터 10.4까지의 릴리스 노트를 원문으로 대조하면서 그 길을 따라가고, 중간중간 운영자를 무는 비호환 변경들을 함께 정리합니다.

먼저 타임라인부터 박아두겠습니다. 전부 공식 릴리스 노트 기준입니다.

9.0   2022-04       sntrup761x25519-sha512 기본 KEX (포스트양자 기본값의 시작)
9.9   2024-09-19    mlkem768x25519-sha256 추가
10.0  2025-04-09    mlkem768x25519-sha256이 기본 KEX로. DSA 제거. 서버 기본값에서 modp DH 제거
10.1  2025-10-06    비-PQ 키 교환 경고 도입(WarnWeakCrypto). XMSS 제거. 에이전트 소켓 /tmp 탈출
10.2  2025-10-10    긴급 버그픽스 (ControlPersist가 세션을 못 쓰게 만드는 문제, bz3872)
10.3  2026-04-02    인증서 빈 principals 의미 반전. rekey 미지원 구현 호환 코드 제거
10.4  2026-07-06    실험적 복합 서명 ssh-mldsa44-ed25519@openssh.com. seccomp 실패 치명화

키 교환 쪽 이야기 — sntrup761에서 mlkem768 기본값까지

OpenSSH의 포스트양자 페이지에 따르면, 포스트양자 키 교환이 기본값이 된 건 2022년 4월의 9.0부터입니다. 당시에는 NIST 표준화가 끝나기 전이라 NTRU Prime 계열의 sntrup761x25519-sha512를 골랐습니다. 9.9에서 NIST 표준(FIPS 203) 기반의 mlkem768x25519-sha256이 추가됐고, 10.0에서 기본값이 됐습니다.

10.0 릴리스 노트가 기본값 교체의 근거로 든 것은 네 가지입니다 — 양자 컴퓨터 공격에 안전하다고 간주되고, 기존의 curve25519-sha256보다 약해지지 않음이 보장되며, NIST가 표준화했고, 이전 기본값(sntrup761)보다 상당히 빠르다는 것("considerably faster than the previous default" — 프로젝트 자체 설명이고, 릴리스 노트에 벤치마크 수치가 따로 제시되지는 않았습니다).

여기서 "약해지지 않음이 보장"이 하이브리드 구조의 핵심입니다. mlkem768x25519-sha256은 ML-KEM-768과 고전 x25519 ECDH를 둘 다 수행하고, 두 공유 비밀을 이어붙여 해시합니다. IETF 문서(draft-ietf-sshm-mlkem-hybrid-kex, 이 글을 쓰는 시점 기준 -10 리비전이 RFC 편집자 큐에 들어가 있습니다)의 정의로는 이렇습니다.

K = HASH(K_PQ || K_CL)
  K_PQ: ML-KEM-768 캡슐화로 얻은 공유 비밀 (FIPS 203)
  K_CL: x25519 ECDH로 얻은 공유 비밀 (RFC 8731)

ML-KEM이 미래의 암호분석으로 무너져도 x25519가 남고, 양자 컴퓨터가 x25519를 부수면 ML-KEM이 막습니다. 왜 이런 보험까지 들어가며 지금 서두르냐면, "store now, decrypt later" — 지금 오가는 트래픽을 저장해 뒀다가 나중에 양자 컴퓨터로 푸는 공격 때문입니다. 키 교환이 뚫리면 세션 전체가 복호화되므로, 암호학적으로 유의미한 양자 컴퓨터(CRQC)가 없는 오늘도 키 교환만큼은 미리 바꿔야 한다는 논리입니다. OpenSSH의 PQ 페이지는 CRQC 도래 전망을 5~20년 범위로, 다수 관측자의 기대를 2030년대 중반으로 적고 있습니다.

프로토콜 수준의 배경 — KEX가 어디에 끼어들고 무엇을 서명하는지 — 은 SSH 프로토콜 딥다이브 편을 참고하세요.

10.1의 경고 — WarnWeakCrypto가 만든 운영 현실

기본값을 바꾸는 것과 생태계를 움직이는 것은 다른 문제입니다. 10.1(2025-10-06)은 더 직접적인 수단을 꺼냈습니다. 클라이언트가 포스트양자가 아닌 키 교환으로 협상을 마치면 이런 경고를 띄웁니다.

** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

이 경고는 기본으로 켜져 있고, 새 ssh_config 옵션 WarnWeakCrypto로 제어합니다. 운영 관점에서 이 경고의 의미는 단순합니다 — 클라이언트를 10.1 이상으로 올린 순간, 조직 안의 오래된 SSH 서버 전부가 사용자 눈앞에 드러납니다. 오래된 네트워크 장비, 벤더가 방치한 어플라이언스, KexAlgorithms를 옛날 값으로 고정해 둔 골든 이미지가 전부 경고를 냅니다.

올바른 해법은 서버를 올리는 것입니다. sntrup761은 9.0부터, mlkem768은 9.9부터 지원하니 서버가 이미 그 버전대라면 설정이 KexAlgorithms로 PQ 알고리즘을 꺼 버리고 있지 않은지부터 확인하면 됩니다. 도저히 서버를 못 올리는 경우를 위해 PQ 페이지가 권하는 방식은 호스트 단위의 선별적 침묵입니다.

Match host unsafe.example.com
    WarnWeakCrypto no-pq-kex

전역으로 WarnWeakCrypto no를 박고 싶은 유혹이 있겠지만, 릴리스 노트는 이 옵션이 앞으로 다른 약한 암호 경고에도 쓰일 것이라고 예고하고 있습니다. 전역으로 끄면 미래의 경고까지 미리 끄는 셈입니다. 경고를 무시하도록 사용자를 훈련시키는 것이 최악의 결과라는 점을 생각하면, 침묵은 좁게 거는 편이 맞습니다.

10.4 — 서명 전선이 열렸다

키 교환과 달리 서명은 "store now, decrypt later"의 대상이 아닙니다. 서명 위조는 연결이 살아 있는 그 순간에 해내야 하는 일이라, 오늘 저장한 트래픽의 인증을 10년 뒤에 소급해서 깰 수는 없습니다. OpenSSH PQ 페이지도 이 점을 명시하면서, 서명 쪽의 유일한 시급성은 CRQC가 현실이 되기 전에 고전 서명 키들을 은퇴시키는 것뿐이라고 적습니다. 그래서 서명 전환은 키 교환보다 몇 년 늦게 출발해도 되는 경주였고, 실제로 그렇게 진행되고 있습니다.

전조는 10.1에 있었습니다. 실험적으로 들어 있던 해시 기반 서명 XMSS를 제거하면서 릴리스 노트에 이렇게 적었습니다 — "We expect to implement a new post-quantum signature scheme in the near future." 그 near future가 10.4입니다.

10.4draft-miller-sshm-mldsa44-ed25519-composite-sigs에 명세된 복합 서명 ssh-mldsa44-ed25519@openssh.com을 실험 지원합니다. 드래프트 저자가 OpenSSH의 Damien Miller 본인입니다. 구조는 키 교환의 하이브리드와 같은 철학입니다 — 포스트양자 ML-DSA-44와 고전 Ed25519로 같은 메시지를 각각 서명하고, 검증은 둘 다 통과해야 유효합니다. 드래프트의 보안 고려사항 그대로, 위조하려면 두 알고리즘을 모두 깨야 합니다.

M' = Prefix || Label || len(ctx) || ctx || SHA512(M)
  Prefix = "CompositeAlgorithmSignatures2025"
  Label  = "COMPSIG-MLDSA44-Ed25519-SHA512"

mldsa_sig   = ML-DSA-44.Sign(mldsa_sk, M', ctx=Label)
ed25519_sig = Ed25519.Sign(ed25519_sk, M')
composite_signature = mldsa_sig || ed25519_sig

기본값이 아니므로 쓰려면 양쪽 끝에서 HostKeyAlgorithms, PubkeyAcceptedAlgorithms 등에 직접 추가해야 하고, 키 생성은 이렇게 합니다.

ssh-keygen -t mldsa44-ed25519

크기 감각을 잡아 보면 — Ed25519는 공개키 32바이트에 서명 64바이트입니다. FIPS 204 기준 ML-DSA-44는 공개키 1,312바이트에 서명 2,420바이트입니다. 복합 공개키는 두 공개키를 이어붙인 1,344바이트이고, 복합 서명은 2,484바이트가 됩니다. 어제 다룬 TLS 쪽에서는 핸드셰이크 하나가 서명 여러 개와 공개키 여러 개를 나르기 때문에 이 크기가 감당이 안 돼 Merkle Tree Certificates라는 우회로를 파는 중인데, SSH 핸드셰이크는 호스트 키 하나와 서명 하나만 나릅니다(RFC 4253의 KEX 구조). 연결당 4KB 남짓의 추가 비용이라, SSH는 우회로 없이 알고리즘을 그대로 갈아 끼우는 정공법이 가능한 것입니다.

드래프트 -00의 현재 상태 — 숫자가 안 맞는다

여기서 "실험적"이라는 딱지를 진지하게 받아들여야 할 이유를 하나 보여드리겠습니다. 드래프트 -00(2026년 6월 2일자) 본문은 복합 서명의 크기를 이렇게 적고 있습니다.

byte[3309] mldsa_sig
byte[64]   ed25519_sig

This 3373-byte combination is henceforth referred to as
"composite_signature".

그런데 FIPS 204가 정한 ML-DSA-44 서명은 2,420바이트입니다. 3,309바이트는 한 단계 위인 ML-DSA-65의 서명 크기입니다. 실제 OpenSSH 10.4 소스(태그 V_10_4_P1의 crypto_api.h)는 MLDSA44_SIGBYTES 2420으로 FIPS 204와 일치하게 구현했으니, 드래프트 본문 쪽이 오기(誤記)로 보입니다. 같은 문서의 서명 컨텍스트 절에는 "TODO TODO TODO"가 그대로 남아 있기도 합니다.

이건 드래프트를 조롱하려는 게 아닙니다 — -00 개인 제출(individual submission) 문서란 원래 이런 상태고, 그래서 아직 워킹그룹 채택도 안 된 문서라는 사실 자체가 정보입니다. 와이어 포맷과 키 포맷이 리비전마다 바뀔 수 있는 단계라는 뜻이고, OpenSSH가 "experimental"이라고 못 박은 것과 정확히 같은 이야기를 문서 상태가 하고 있는 것입니다.

운영자를 무는 변경들 — 10.0부터 10.4까지

포스트양자 이야기에 가려 잘 안 보이지만, 이 릴리스 트레인은 폐기(deprecation)의 연속이기도 했습니다. 실패가 드러나는 방식별로 묶어 보겠습니다.

연결 시점에 실패하는 것들. 10.0이 DSA 서명 알고리즘을 완전히 제거했습니다(2015년에 기본 비활성화로 시작한 폐기 절차의 완결입니다). 같은 릴리스에서 서버 기본값의 finite field DH — diffie-hellman-group*diffie-hellman-group-exchange-* — 가 빠졌습니다. ECDH도 PQ도 못 하는 오래된 클라이언트는 10.0 이상 서버의 기본 설정에 연결하지 못합니다(클라이언트 쪽 기본값은 유지됐으므로, 새 클라이언트가 옛 서버에 붙는 방향은 계속 됩니다). 또 moduli 파일이 존재하는데 요청 범위의 값이 없을 때 컴파일된 그룹으로 조용히 폴백하던 동작도 사라져서, 손으로 편집한 moduli 파일이 이제는 연결 실패로 이어질 수 있습니다.

세션 도중에 죽는 것들. 이쪽이 디버깅하기 훨씬 고약합니다. 10.3(2026-04-02)은 rekey를 지원하지 않는 구현과의 버그 호환 코드를 제거했습니다 — 연결은 정상으로 맺어지고, 전송량이 쌓여 재키잉이 필요해지는 시점에 가서야 실패합니다. 10.4는 인증 후 재키잉 중에 KEX가 아닌 메시지를 보내는 피어를 즉시 끊도록 프로토콜을 엄격화했습니다(RFC 4253 7.1절을 안 지키는 구현이 대상입니다). 둘 다 물리는 건 최신 OpenSSH가 아니라 반대편의 레거시 임베디드 장비들입니다. "붙긴 붙는데 큰 파일만 보내면 끊겨요"라는 티켓이 올라오면 이걸 의심하세요.

자동화와 툴링이 깨지는 것들. 10.1이 에이전트 소켓을 /tmp에서 ~/.ssh/agent 밑으로 옮겼습니다. /tmp 접근이 제한된 프로세스가 에이전트 키를 못 집게 하려는 보안 개선인데, /tmp/ssh- 경로를 글롭하던 모니터링·정리 스크립트는 전부 무효가 됩니다. 부수 효과도 있습니다 — OS의 /tmp 청소가 더는 낡은 소켓을 치워 주지 않아 ssh-agent가 자체 정리 기능과 플래그들(-U, -u, -uu, 그리고 /tmp로 되돌리는 -T)을 새로 얻었고, NFS 홈을 위해 소켓 경로에 호스트명 해시가 들어갑니다. 10.4에서는 sshd -G 설정 덤프가 소문자 일색에서 대소문자 혼합("PubkeyAuthentication")으로 바뀌었습니다 — 소문자를 전제로 grep하던 컴플라이언스 스크립트가 조용히 빈 결과를 내기 시작합니다. 10.1의 IPQoS 개편으로 lowdelay, throughput, reliability 같은 ToS 키워드는 이제 무시되고 시스템 기본 QoS로 떨어집니다.

인증 동작이 바뀐 것들. 10.3의 변경 중 가장 음미할 만한 것 — 이전에는 principals 섹션이 비어 있는 인증서가 authorized_keys의 principals= 옵션 경로에서 와일드카드로, 즉 아무 principal에나 매칭되는 것으로 취급됐습니다. 의도된 동작이었지만, CA가 실수로 principals가 빈 인증서를 발급하면 쓸모없는 인증서가 되기는커녕 그 CA를 신뢰하는 모든 계정으로 로그인 가능한 만능 키가 되는 함정이었습니다. 10.3부터 빈 principals는 아무것에도 매칭되지 않습니다(TrustedUserCAKeys 경로는 원래 이 문제가 없었습니다). 반대로 이 와일드카드 동작에 기대던 환경이 있다면 업그레이드 직후 인증이 깨집니다 — 그 의존이 애초에 위험했다는 뜻이지만, 깨지는 건 깨지는 겁니다. 10.1의 ssh-add는 인증서를 에이전트에 넣을 때 만료를 인증서 만료 시각 + 5분 유예로 자동 설정하게 됐고(-N으로 비활성화), 장수 에이전트에 단명 인증서를 넣어 두고 "계속 있겠지" 하던 파이프라인은 이제 만료 후 실패합니다.

빌드와 배포 환경. 10.4부터 리눅스에서 seccomp 샌드박스나 NO_NEW_PRIVS 활성화 실패가 치명적 오류가 됩니다. 예전에는 로그만 남기고 계속 돌았지만, 이제 그런 시스템은 configure 시점에 샌드박스를 명시적으로 꺼야 합니다. 아주 오래된 커널이나 특이한 컨테이너 런타임 위에 sshd를 올리는 경우가 대상입니다.

예고된 다음 타자. 10.1과 10.2 릴리스 노트는 SHA1 SSHFP DNS 레코드의 폐기를 예고하고 있습니다 — 미래 릴리스에서 SHA1 SSHFP는 무시되고 ssh-keygen -r은 SHA256 레코드만 생성하게 됩니다. SSHFP를 DNS에 심어 둔 조직이라면 지금 재생성해 두는 게 쌉니다(SHA256 SSHFP는 2012년의 6.1부터 지원됐습니다).

덧붙여 10.4에는 업그레이드 자체의 동기가 되는 보안 수정도 여럿 있습니다 — 악의적 서버가 sftp host:/path . 다운로드를 엉뚱한 위치에 쓰게 만들 수 있던 문제, 원격 간 scp 복사에서 대상 디렉터리의 부모에 파일을 쓸 수 있던 문제, internal-sftp의 커맨드라인이 9번째 인자 이후로 조용히 잘려 보안 옵션이 버려질 수 있던 문제, GSSAPI 인증 활성화 시의 사전 인증 DoS, 재키잉 중 서버가 호스트 키를 바꿀 때의 클라이언트 use-after-free 같은 것들입니다.

하지 말아야 할 것들

복합 서명을 프로덕션에 켜지 마세요. 위에서 본 대로 명세는 -00 개인 제출 드래프트이고, 본문에 TODO와 크기 오기가 남아 있으며, OpenSSH 스스로 experimental이라고 부릅니다. 와이어/키 포맷이 바뀌면 지금 만든 키와 배포 설정이 부채가 됩니다. 랩에서 키를 만들어 보고 상호운용을 관찰하는 것까지가 지금 단계에 맞는 행동입니다.

서명 때문에 호스트 키를 지금 갈아엎지 마세요. 서명에는 소급 위협이 없다는 게 OpenSSH 자신의 설명입니다. 지금 필요한 건 PQ 호스트 키 배포가 아니라, CRQC가 가시화됐을 때 조직 전체의 호스트 키와 CA 키를 얼마나 빨리 갈 수 있는지 — 그 회전 근육입니다. 인벤토리 없이는 회전도 없습니다.

경고를 전역으로 끄지 마세요. WarnWeakCrypto는 앞으로 다른 약한 암호 경고까지 관장할 예정인 옵션입니다. Match 블록으로 호스트 단위로만 침묵시키고, 침묵시킨 호스트 목록 자체를 기술 부채 목록으로 관리하세요.

KexAlgorithms를 골든 이미지에 고정해 두고 잊지 마세요. 옛날 장비 호환을 위해 한 번 고정한 알고리즘 목록은 PQ 기본값도, 미래의 제거도 전부 비껴가게 만듭니다. 고정이 정말 필요하면 만료일을 함께 적어 두는 편이 낫습니다.

실무 체크리스트

# 1) 클라이언트가 실제 협상할 KEX 확인 — 첫 항목이 mlkem768x25519-sha256인지
ssh -G host.example.com | grep -i kexalgorithms

# 2) 설정 어딘가에서 알고리즘을 고정해 둔 곳 찾기
grep -riE 'kexalgorithms|hostkeyalgorithms|pubkeyacceptedalgorithms' /etc/ssh/

# 3) /tmp 밑 에이전트 소켓을 가정한 스크립트 찾기 (10.1에서 ~/.ssh/agent로 이동)
grep -rn 'tmp/ssh-' /opt/scripts/

# 4) sshd -G 출력을 소문자로 grep하던 곳 찾기 (10.4에서 대소문자 혼합으로 변경)
grep -rn 'sshd -G' /opt/scripts/ | xargs -r grep -l 'grep [a-z]'

# 5) 레거시 장비의 rekey 생존 테스트 — 임계값을 낮춰 강제로 재키잉 유발
ssh -o RekeyLimit=1M legacy-appliance 'dd if=/dev/zero bs=1M count=16' > /dev/null

여기에 더해, SSH 인증서를 쓰는 조직이라면 CA 발급 파이프라인이 principals가 빈 인증서를 만들 수 있는지(10.3 이전 서버가 남아 있다면 그게 만능 키가 됩니다), authorized_keys의 principals= 옵션을 쓰는 곳이 어디인지 지금 목록화해 두세요. 포스트양자 전환의 전체 그림 — SSH 바깥의 TLS, VPN, 코드 서명까지 — 은 포스트양자 암호 마이그레이션 편과 겹쳐 보면 좋습니다.

마치며

OpenSSH의 포스트양자 전환은 교과서적인 순서로 진행되고 있습니다. 소급 위협이 있는 키 교환부터 — 표준화 전에 sntrup761로 시작(9.0), 표준이 나오자 mlkem768로 교체(10.0), 경고로 생태계를 밀어붙이기(10.1) — 그리고 소급 위협이 없는 서명은 표준 문서와 실험 구현으로 이제 막 출발(10.4). 급한 것부터 강하게, 덜 급한 것은 신중하게. 이 순서 감각은 어제 본 TLS 쪽 이야기와 정확히 같은 원리로 움직이면서도, SSH의 가벼운 핸드셰이크 덕에 훨씬 단순한 경로를 탑니다.

동시에 이 릴리스 트레인은 오래된 것들을 꾸준히 치워 왔습니다. DSA, modp DH 서버 기본값, /tmp의 에이전트 소켓, rekey 못 하는 구현과의 인내심, 빈 principals의 와일드카드. 각각은 합리적인 제거지만, 물리는 시점이 연결 시, 재키잉 시, 업그레이드 직후, 스크립트 실행 시로 제각각이라 인벤토리 없이 맞으면 아픕니다. 릴리스 노트의 "Potentially-incompatible changes" 섹션을 릴리스마다 정독하는 것 — 결국 그게 이 글 전체의 요약입니다.

참고 자료

현재 단락 (1/77)

[OpenSSH 10.4](https://www.openssh.com/txt/release-10.4)는 2026년 7월 6일에 나왔습니다. 릴리스 노트의 자기소개는 겸손합니다 — ...

작성 글자: 0원문 글자: 10,061작성 단락: 0/77