폐쇄망 현장 — 방산·국방 도메인 · 반입 번들과 무결성 · 이론
반입은 파일을 옮기는 일이 아니라 의존성을 닫는 일이다
한 줄 요약
폐쇄망 반입에서 실패의 대부분은 서명이 아니라 의존성에서 나오고, 그것을 막는 장치가 전부 동봉된 번들과 파일 단위 매니페스트다.
왜 이게 필요했나
밖에서 배포는 이렇게 됩니다. 저장소에서 코드를 받고, 패키지 관리자가 의존성을 내려받고, 컨테이너 레지스트리가 이미지 층을 채웁니다. 우리가 옮기는 것은 사실 '주소' 이고, 실제 내용물은 실행 시점에 네트워크가 채웁니다.
폐쇄망에서는 그 네트워크가 없습니다. 주소를 옮겨 봐야 아무것도 채워지지 않습니다. 그래서 옮기는 것이 주소가 아니라 내용물 전부 여야 합니다. 응용 코드만이 아니라, 그 코드가 부르는 라이브러리, 그 라이브러리가 부르는 라이브러리까지 전부입니다.
여기서 나오는 실패가 아주 특징적입니다. 반입 심사를 통과하고, 매체를 들고 들어가고, 설치를 시작한 다음에야 라이브러리 하나가 빠진 것을 알게 됩니다. 그리고 그 하나를 채우려면 다시 나가서, 다시 담고, 다시 심사를 받아야 합니다. 심사 주기가 주 단위인 곳에서는 이것이 일주일입니다. 빠진 파일 하나의 비용이 일주일 이라는 사실이 이 모듈 전체의 이유입니다.
어떻게 동작하나
그래서 반입 번들에는 세 가지가 함께 들어갑니다.
하나, 페이로드. 실행에 필요한 파일 전부입니다. 여기서 원칙은 "밖에서 한 번이라도 네트워크가 채워 준 것은 전부 동봉한다" 입니다. 개발 환경에서 되니까 될 것이라는 판단이 가장 위험합니다 — 개발 환경에는 이미 캐시가 있습니다.
둘, 매니페스트. 페이로드에 든 파일 하나하나의 SHA-256 목록입니다. 왜 번들 전체 해시 하나로 부족한가 — 전체 해시는 "무언가 다르다" 까지만 알려 줍니다. 어느 파일이 다른지 모르면 조사할 곳이 번들 전체가 되고, 수백 개짜리 번들에서 이것은 사실상 조사 불가입니다. 경로는 상대 경로로 적습니다. 받는 쪽은 다른 디렉터리에 풀기 때문에 절대 경로는 그 자리에서 무용지물이 됩니다.
셋, 서명. 매니페스트 한 장에 대한 서명입니다. 파일이 수천 개여도 서명은 하나면 됩니다. 파일별 무결성은 매니페스트가 책임지고, 매니페스트의 진위는 서명이 책임집니다. 이 두 층을 나누는 것이 다음 이야기의 전부입니다.
페이로드 파일들 ──(각 파일의 SHA-256)──▶ MANIFEST.sha256 ──(개인키 서명)──▶ MANIFEST.sig ▲ ▲ ▲ └ 파일 해시 대조로 확인 └ 목록이 맞는지 └ 목록을 우리가 아는 사람이 만들었는지현장에서 만나는 모습
gpg 가 없는 곳이 많습니다. 인가된 소프트웨어 목록에 없으면 설치할 수 없고, 목록에 넣으려면 그것부터 반입 심사입니다. 그래서 현실적으로는 어디에나 있는 openssl 로 합니다. openssl dgst -sha256 -sign 과 -verify 두 명령이면 서명과 검증이 끝납니다. 화려하지 않지만 이 환경에서 실제로 되는 방법입니다.
바이너리는 눈으로 확인할 수 없습니다. 텍스트 파일은 diff 로 볼 수 있지만 .so 나 .whl 은 열어도 아무것도 안 보입니다. 게다가 NUL 이 섞여 있어서 head 나 grep 에 물리면 결과 자체를 믿을 수 없습니다. 바이너리를 다루는 도구는 file, sha256sum, openssl 세 개뿐이라고 생각하는 편이 안전합니다.
한 번 당한 것 하나. 번들을 다시 묶고 나서 해시 파일을 다시 뜨지 않은 적이 있습니다. 매체에 담아 들어가서, 받는 쪽에서 해시가 안 맞아 반려됐습니다. 다시 나오는 데 하루가 걸렸습니다. 그 뒤로는 묶는 명령과 해시를 뜨는 명령을 반드시 같은 스크립트 안에 붙여 둡니다.
이어서 읽을 것
여기까지가 '무엇을 담아 보내는가' 입니다. 바로 뒤에 오는 글은 '받는 쪽이 무엇을 어떤 순서로 확인하는가' 를 다룹니다. 해시와 서명이 각각 무엇을 지켜 주는지, 한 층만 보면 어떤 변조가 통과하는지, 그리고 공개키가 번들 안에 들어 있으면 왜 검증이 통째로 무의미해지는지가 그 글의 내용입니다. 그다음 실습에서 두 글을 한 번에 손으로 밟습니다.