33개 CVE를 한 번에: Debian이 rsync를 패치 대신 3.5.0으로 올린 이유

한눈에 보는 요약
Debian이 rsync에서 발견된 33개 CVE를 처리하면서 흥미로운 선택을 했습니다. 보통 안정 배포판은 개별 보안 패치를 하나씩 백포트하는 방식을 택하는데, 이번에는 그렇게 하지 않고 rsync를 3.5.0 버전으로 통째로 올려버린 것입니다.
trixie-security패키지가3.5.0+ds1-0+deb13u1로 업그레이드되었습니다- 보안 수정 외의 추가 변경 사항까지 분석한 결과, 버전 업그레이드가 개별 패치 백포트보다 위험이 낮다고 판단했습니다
- 중요한 점은, 기존 환경에 영향을 줄 수 있는 동작 변경이 "버전 업그레이드 때문"이 아니라 CVE 수정 자체에서 비롯되었다는 것입니다. 즉 패치를 백포트했어도 같은 변화를 겪었을 거라는 뜻이죠
- 전체 변경 목록은
/usr/share/doc/rsync/NEWS.md.gz에서 확인할 수 있습니다
33개짜리 패치 세트를 손으로 엮는 일과, 검증된 상위 버전을 가져오는 일 중 후자가 더 안전하다는 판단은 꽤 실용적인 결정입니다. 다만 그 대가로 운영 환경에서 깨질 수 있는 동작 변경이 여럿 따라옵니다. 하나씩 살펴보겠습니다.
1. 심볼릭 링크를 더 이상 아무렇게나 따라가지 않습니다
가장 체감이 큰 변화입니다. 이제 rsync는 운영자가 지정한 경로를 구성 요소별로 하나씩 해석하고, 심볼릭 링크의 소유자가 root 또는 rsync를 실행하는 사용자일 때만 그 링크를 따라갑니다. 신뢰할 수 없는 제3의 사용자가 소유한 링크는 거부합니다.
refusing to follow a symlink owned by an untrusted user
적용 대상이 상당히 넓습니다.
- 목적지 디렉터리
--backup-dir,--temp-dir,--partial-dir--link-dest,--compare-dest,--copy-dest--log-file,--password-file--files-from,--include-from,--exclude-from--write-batch,--read-batch--filter로 병합되는 파일
이전 동작으로 되돌리고 싶다면 --insecure-links 옵션이 있지만, 로컬 전송에만 적용되고 데몬은 이 옵션을 무시합니다. 데몬 환경에서 특정 모듈만 예외로 두려면 해당 모듈 설정에 직접 insecure links = yes를 넣어야 합니다.
💡 백업 스크립트에서
--backup-dir나--link-dest를 공유 디렉터리의 심링크로 가리키고 있다면, 업그레이드 후 조용히 실패할 수 있는 지점입니다. 링크 소유자를 먼저 확인해 보세요.
2. rrsync 제한이 더 촘촘해졌습니다
rrsync는 SSH authorized_keys에 묶어 rsync 호출을 특정 디렉터리로 가두는 래퍼 도구입니다. 여기에 방어선이 추가되었습니다.
- 모든 호출에서
--debug를 거부합니다 (하위 디렉터리 제한 여부와 무관) - 하위 디렉터리로 제한된 경우 추가 제약이 붙습니다:
--copy-unsafe-links거부--confine-root를 전달해, 클라이언트가 지정한 필터 병합 파일을 제한 디렉터리 밖에서 해석하지 못하게 차단- 수신 시
--drop-D를 전달해 업로드로 장치 파일·특수 파일을 생성하지 못하게 차단. 해당 파일은skipping non-regular file메시지와 함께 건너뜁니다
다행히 일반적인 rsync -a는 계속 그대로 동작합니다. 평범한 백업·동기화 용도라면 걱정할 일이 거의 없습니다.
그리고 작지만 헷갈릴 수 있는 변경: --chmod=a+s가 이제 chmod(1)과 동일하게 setuid와 setgid를 모두 설정합니다. 이전에는 setuid만 설정했습니다.
3. rsyncd 접근 제어: 허용되던 접속이 차단될 수 있습니다
데몬 설정 해석 방식이 바뀌면서, 기존에 통과했던 연결이 막히는 경우가 생깁니다. 데몬을 운영한다면 이 절이 가장 중요합니다.
PROXY 프로토콜
proxy protocol = true인데 proxy protocol hosts가 비어 있으면, 시작 시 경고를 띄우고 모든 연결을 거부합니다. 이전에는 클라이언트가 보낸 PROXY 헤더를 그냥 신뢰했는데, 이건 사실상 클라이언트가 자기 IP를 마음대로 주장할 수 있다는 뜻이었습니다. 당연한 수정이지만, 설정이 불완전했던 서버는 업그레이드 직후 전면 장애를 겪습니다.
호스트 이름 해석 실패
기본값인 forward lookup을 쓸 때, hosts deny에 적어 둔 호스트 이름을 해석할 수 없으면 접근을 차단하는 쪽으로 처리합니다. 이전에는 거부 항목을 해석하지 못하면 그냥 넘어가서 통과했습니다. 즉 DNS가 흔들리면 정상 호스트도 막힐 수 있습니다.
auth users 파싱
쉼표로 시작하는 auth users 값은 이제 문서대로 쉼표만 구분자로 사용합니다. 그 결과 이전에는 무시되던 규칙들이 실제로 적용됩니다.
- 이름에 공백이 포함된 그룹의 거부 규칙
:ro규칙
"원래 의도대로 동작하게 된" 변화지만, 무시되던 규칙에 기대어 돌아가던 설정은 깨집니다.
호스트 패턴 대소문자
hosts allow / hosts deny 패턴은 [...] 대괄호 안에서도 대소문자를 구분하지 않습니다. 따라서 [A-Z]* 같은 규칙이 이전에는 놓쳤던 호스트와도 매칭됩니다.
기타
클라이언트가 요청하는 --compress-threads 값은 상한이 8로 제한됩니다.
4. rsync-ssl이 드디어 인증서를 검증합니다
rsync-ssl이 서버 인증서를 실제로 검증하기 시작했습니다. 백엔드별로 조건이 다릅니다.
| 백엔드 | 동작 |
|---|---|
| openssl (기본값) | 인증서 검증 + 요청한 호스트 이름까지 확인. 다른 이름에만 유효한 인증서는 거부 |
| stunnel | RSYNC_SSL_CA_CERT를 설정하거나 검증 예외를 명시해야 실행 |
| gnutls | RSYNC_SSL_CA_CERT를 설정하거나 검증 예외를 명시해야 실행 |
검증을 건너뛰어야 한다면 백엔드에 따라 아래 환경 변수를 설정해야 합니다.
RSYNC_SSL_ALLOW_INSECURE_STUNNEL=1
# 또는
RSYNC_SSL_ALLOW_INSECURE_GNUTLS=1
자체 서명 인증서나 내부 CA로 운영하던 환경이라면, 업그레이드 즉시 연결이 끊어집니다. 올바른 해법은 예외를 켜는 쪽이 아니라 RSYNC_SSL_CA_CERT로 CA를 알려주는 쪽입니다.
업그레이드 전 체크리스트
정리하면, 확인할 지점은 다음과 같습니다.
- 심링크 — 백업 스크립트의
--link-dest,--backup-dir,--temp-dir등이 가리키는 경로에 제3자 소유 심링크가 있는지 - rsyncd 설정 —
proxy protocol hosts가 비어 있지 않은지,hosts deny의 호스트 이름이 모두 해석되는지,auth users가 쉼표로 시작하지 않는지 - rsync-ssl — 내부 CA를 쓴다면
RSYNC_SSL_CA_CERT준비 - rrsync — 자동화 스크립트에서
--debug나--copy-unsafe-links를 쓰고 있지 않은지 --chmod=a+s— setgid까지 붙어도 괜찮은지
마무리
이번 사례에서 눈여겨볼 점은 Debian의 판단 기준입니다. "안정 배포판은 버전을 올리지 않는다"는 원칙을 기계적으로 따르는 대신, 33개 패치를 수작업으로 엮는 위험과 상위 버전을 가져오는 위험을 실제로 비교해서 후자를 택했습니다.
그리고 동작 변경이 "3.5.0이라는 새 버전 탓"이 아니라 CVE 수정 자체의 필연적 결과라는 설명도 중요합니다. 심링크를 함부로 따라가지 않는 것, PROXY 헤더를 무조건 믿지 않는 것, TLS 인증서를 검증하는 것 — 이건 모두 "원래 그래야 했던" 동작입니다. 느슨한 기본값에 의존해 돌아가던 설정이 드러나는 것이지요.
업그레이드 전에 /usr/share/doc/rsync/NEWS.md.gz를 한 번 훑어보시길 권합니다. 특히 rsyncd를 공개 서비스로 운영하고 있다면, 스테이징에서 접속 테스트를 먼저 해보는 편이 안전합니다.