
"보안 릴리즈인데 설치 파일이 없다": Python 3.10/3.11/3.12 소스-온리 보안 릴리즈를 실무에서 처리하는 법
보안 릴리즈 공지가 떴다. 팀 채널에 링크가 공유되고, 누군가가 한 줄 던진다.
“이번에도 올려야죠?”
여기까지는 평소와 같다. 문제가 되는 건 다음 장면이다. 릴리즈 페이지로 들어가서 다운로드 섹션을 훑다가 멈춘다.
설치 파일이 없다.
Windows 인스톨러도 없고, macOS 패키지도 없고, “그냥 받아서 설치”할 수 있는 게 없다. 그러면 대화가 이상해진다.
“그럼 우리는 못 올리는 건가?”
아니다. 이건 ‘못 올리는’ 게 아니라, 업스트림이 “이번엔 이렇게 배포한다”라고 명확히 말해주는 구간이다. Python 3.10.20 / 3.11.15 / 3.12.13 릴리즈 페이지에는 보안 릴리즈이며(그리고 설치 파일이 없다는 점까지) 같이 적혀 있다(참고자료). 처음 겪으면 당황하지만, 실무에서는 이걸 우리 파이프라인이 어디에 의존하고 있는지 드러나는 신호로 읽게 된다.
이 글은 CVE 번호를 나열하는 글이 아니다. 우리 팀이 오늘 해야 하는 건 “무서워하기”가 아니라 “어떻게 먹일지”를 결정하는 거다. 소스-온리 릴리즈를 운영에서 처리하는 흐름을, 실제로 막히는 지점에서부터 풀어보겠다.
여기서 말하는 ‘처리’는 거창한 프로젝트가 아니다. 오늘 안에 끝낼 수 있는 쪽으로 잘게 자르면 된다. 지금 서비스가 어떤 파이썬에서 돌고 있는지부터 확인하고, 그 파이썬이 어디서 들어오는지(베이스 이미지인지, 우리가 직접 빌드하는지)를 확인하고, 올렸다가 되돌리는 길이 열려 있는지까지 같이 본다. 이 흐름이 잡히면 “설치 파일이 없다”는 말은 장애가 아니라 공급 방식의 차이로 내려온다.
본문에는 생 URL을 넣지 않고, 맨 아래 참고자료에만 링크를 둔다.
릴리즈 노트에서 멈추는 포인트: installers 없음은 ‘단계’의 문제다
Python Insider 공지와 Discourse 스레드에서도 반복되는 문장이 있다(참고자료).
공지/릴리즈 페이지에는 이번 보안 릴리즈들이 installers 없이 source-only로 제공된다는 점이 적혀 있다(참고자료). 그리고 ‘security fixes only’라는 표현은(내가 보기엔) “기능 추가가 아니라 운영이 빨리 먹여야 하는 패치만 들어온다”는 신호다.
이걸 “불친절하다”로 받아들이면 업데이트가 늦어진다. 나는 오히려 반대로 읽는다. source-only는 “누가 파이썬을 공급하나(베이스 이미지/직접 빌드)”라는 질문을 피하지 말라는 알람이다.
문제는 우리 팀의 현실이다. 많은 서비스는 “소스 받아서 빌드”를 평소에 하지 않는다.
개발자는 로컬에서 pyenv나 공식 인스톨러로 올리고, 서버는 베이스 이미지나 런타임 이미지에 기대고, CI는 캐시된 파이썬을 쓴다. 그러니 소스-온리 릴리즈가 오면 업데이트가 갑자기 ‘특수 작업’이 된다.
하지만 보안 릴리즈는 특수 작업이 아니라 운영의 기본값이어야 한다. 그래서 이 타이밍에 제일 먼저 해야 할 일은 “이 릴리즈를 어떻게 배포 경로에 흘려보낼지”를 정하는 것이다.
“이게 우리 서비스에 어디로 들어오지?": 표면을 내 관점으로 번역하기
릴리즈 페이지를 보면 메일, HTTP, XML, SSL 같은 단어가 나온다(참고자료). 이런 단어는 다 맞는 말인데, 운영팀 입장에선 너무 넓다.
실무에서는 질문을 더 좁혀야 한다.
- 우리 서비스가 외부에서 받는 입력은 무엇인가
- 그 입력이 파이썬 표준 라이브러리의 어떤 부분을 타고 들어오는가
- 이 서비스는 어디에서 파이썬을 공급받는가(베이스 이미지? OS 패키지? 런타임?)
이 과정이 없으면 업데이트는 늘 “해야 하는데 못 하는 일”로 남는다.
그래서 나는 보안 릴리즈 공지를 보면 먼저 현재 상태부터 꺼내 본다. 버전 확인이 단순한데도, 의외로 팀이 몰라서 시작이 늦어진다.
python -V
python -c "import sys; print(sys.version)"
cat /etc/os-release 2>/dev/null || true
이건 체크리스트가 아니라, 대화의 기준점이다. “우리 서비스는 지금 여기 있다.” 이걸 알아야 “여기서 어디로 가야 하는지”가 나온다.
소스-온리 릴리즈를 파이프라인에 넣는 방식은 결국 두 갈래다
실무에서 선택지는 복잡해 보이지만, 결국 두 갈래로 수렴한다.
하나는 베이스 이미지에서 파이썬을 공급받는 방식이다.
이 경우 팀이 직접 소스를 빌드하지 않아도, 베이스 이미지가 업데이트되면 자연스럽게 따라간다. 문제는 타이밍이다. 보안 릴리즈는 “지금 올려야 하는데, 이미지가 아직 안 나왔네”라는 공백을 만들 수 있다.
다른 하나는 우리가 파이썬을 직접 빌드해서 런타임에 넣는 방식이다.
이게 처음엔 부담스럽지만, 소스-온리 릴리즈를 자주 만나게 되면 오히려 이 방식이 안정적일 때가 많다. 왜냐하면 ‘나오는 즉시’ 우리가 적용할 수 있기 때문이다.
둘 중 어느 쪽이든 중요한 건, 소스 릴리즈를 빌드 파이프라인에 흘려보낼 수 있어야 한다는 점이다. 그걸 못하면 매번 긴급 작업이 된다.
예를 들어 도커 기반이라면, 파이썬을 빌드하는 스테이지를 별도로 두고 결과만 런타임 이미지로 넘기는 식이 흔하다.
FROM debian:stable-slim AS python-build
ARG PY_VERSION=3.12.13
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential wget ca-certificates xz-utils libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev libffi-dev \
&& rm -rf /var/lib/apt/lists/*
RUN wget -q https://www.python.org/ftp/python/${PY_VERSION}/Python-${PY_VERSION}.tgz \
&& tar -xzf Python-${PY_VERSION}.tgz \
&& cd Python-${PY_VERSION} \
&& ./configure --prefix=/usr/local --enable-optimizations \
&& make -j"$(nproc)" \
&& make install
FROM debian:stable-slim
COPY --from=python-build /usr/local /usr/local
RUN python -V
여기서 포인트는 “도커파일 예쁘게 쓰기”가 아니다.
- 버전이 한 곳(빌드 인자)에서만 바뀌고
- 빌드 결과가 재현되고
- 런타임에서 의도한 버전이 들어갔는지 확인할 수 있고
- 롤백이 가능한 이미지 태그로 배포된다
이 네 가지가 갖춰지면, 소스-온리 릴리즈는 ‘특수 상황’이 아니라 ‘평소 작업’이 된다.
빨리 올리고 안전하게 되돌리기: 확인할 건 “기능”보다 “신호”다
보안 릴리즈는 결국 속도와 안전의 균형이다.
무작정 올리면 무섭고, 충분히 검증하려고 하면 늦는다. 그래서 실무에서는 “어떤 신호를 보면 됐다고 말할지”를 먼저 정하는 게 빠르다.
나는 보안 릴리즈 적용 뒤에 기능 테스트보다 먼저 로그를 본다.
- TLS/SSL 핸드셰이크 오류가 늘었는지
- HTTP 클라이언트/서버에서 타임아웃 패턴이 바뀌었는지
- XML 파싱이 실패하는 입력이 새로 생겼는지
- 메일 관련 처리가 있는 서비스라면, 인코딩/헤더 파싱이 달라졌는지
이건 “이번에 뭐가 고쳐졌는지”를 다 외우기 위해서가 아니다.
보안 릴리즈의 성격상, 표준 라이브러리의 모서리에서 동작이 달라지는 일이 생기기 때문이다. 그래서 우리 서비스에 해당하는 ‘표면’의 신호를 먼저 보는 게 빠르다.
그리고 항상 롤백 가능한 형태로 배포한다. 소스-온리 릴리즈를 직접 빌드했다면 더더욱 그렇다. 롤백이 되면, 업데이트는 공포가 아니라 작업이 된다.
마무리: installers 없음은 장애가 아니라, 파이프라인의 숙제다
Python 3.10.20 / 3.11.15 / 3.12.13 같은 보안 릴리즈에서 설치 파일이 없는 건, 업스트림이 우리를 괴롭히려는 게 아니다. 릴리즈 페이지에는 (1) 이 릴리즈가 보안 릴리즈라는 점과, (2) installers가 제공되지 않는다는 점, (3) 라이프사이클이 ‘security fixes only’ 단계라는 점이 함께 적혀 있다(참고자료).
여기까지는 ‘사실’이고, 내 해석은 하나다. 결국 문제는 “왜 없냐”가 아니라 “우리가 소스를 받아서 배포 가능한 형태로 굳힐 준비가 돼 있냐”로 바뀐다.
그래서 나는 보안 릴리즈를 받을 때마다 같은 질문으로 끝낸다.
“지금 이 팀은 소스를 받아서 이미지로 굳혀 배포할 준비가 되어 있나, 아니면 아직도 누군가의 서버에서 제각각 패치하고 있나?”
둘 중 전자라면, 오늘 같은 소스-온리 릴리즈는 큰 사건이 아니라 평소 작업이다. 반대로 후자라면, 다음 보안 릴리즈 때도 똑같이 늦는다. (그때는 더 급할 확률이 높고.)
결국 이 글의 결말은 업데이트 독려가 아니라, 파이프라인의 형태를 고치자는 얘기다.
무서운 건 업데이트가 아니라, 업데이트가 ‘특수 작업’으로 남는 상태다. 이번 릴리즈를 계기로 “버전만 바꾸고 태그만 바꾸는” 쪽으로 팀을 옮겨두자.
참고자료
- Python Insider — Python 3.12.13, 3.11.15 and 3.10.20 are now available!
- https://blog.python.org/2026/03/python-31213-31115-31020/
- Discourse — Python 3.12.13, 3.11.15 and 3.10.20 are now available!
- https://discuss.python.org/t/python-3-12-13-3-11-15-and-3-10-20-are-now-available/106363
- Python 3.12.13 release page
- https://www.python.org/downloads/release/python-31213/
- Python 3.11.15 release page
- https://www.python.org/downloads/release/python-31115/
- Python 3.10.20 release page
- https://www.python.org/downloads/release/python-31020/
댓글
댓글 쓰기