LabHub
Get started
배우기 러닝패스 코스

Air-Gapped Mirrors and a Private CA

An intake bundle: from request to signature verification

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

반입 요청서에서 시작해 번들을 받고, 상대 경로 해시 목록에 서명하고, 개인 키 없는 매체로 옮겨, 폐쇄망 쪽에서 서명 먼저·해시 다음으로 검증한 뒤 번들만으로 설치하고 기록을 남긴다.

왜 중요한가

해시 목록만 함께 넣은 USB 는 전송 중 손상은 잡지만 바꿔치기는 못 잡는다 — 바꾼 사람이 목록도 고치면 그만이다. 목록에 서명하고 공개 키를 다른 길로 미리 건네 두어야 "누가 만든 목록인가" 가 보증된다. 그리고 검증 스크립트는 실패할 때 0 이 아닌 값으로 끝나야 자동화가 멈춘다. 이 파드는 인터넷(80/443)에 닿으므로 받는 쪽 역할을 하고, 설치 단계는 바깥을 닫힌 프록시로 막은 채 번들만으로 한다.

단계

  1. /root/intake/request.txt 에 반입 요청을 생태계 이름 버전 두 줄로 적는다: pypi requests 2.32.3, go rsc.io/quote v1.5.2.
  2. 번들 /root/intake/bundle/ 에 파이썬 휠(pypi/, 의존성 포함, 휠만)과 Go 모듈 프록시(goproxy/, 새 모듈 캐시의 cache/download 내용)를 받는다.
  3. 번들 디렉터리 안에서 상대 경로로 /root/intake/bundle/SHA256SUMS 를 만든다(목록과 서명 파일 자신은 뺀다).
  4. /root/intake/keys/intake.key(Ed25519 개인 키)·intake.pub 를 만들고 SHA256SUMS 에 서명해 /root/intake/bundle/SHA256SUMS.sig 에 둔다.
  5. 매체 /root/intake/media/bundle.tar 를 만들고(개인 키는 넣지 않는다), 폐쇄망 쪽 /root/intake/inside/ 에 풀고, 공개 키는 따로 /root/intake/inside/trusted.pub 로 둔다.
  6. 폐쇄망 쪽 검증 스크립트 /root/intake/verify.sh <번들> <공개키> 를 쓴다. 서명 먼저, 해시 다음, 목록에 없는 파일까지 보고, 실패하면 0 이 아닌 값으로 끝나야 한다.
  7. 바깥을 막은 채 /root/intake/inside/bundle 만으로 설치한다: venv /root/intake/venv 에 requests, 그리고 /root/intake/goapp 의 Go 프로그램(rsc.io/quote 의 quote.Hello() 출력)을 빌드해 /root/intake/bin/hello 로.
  8. 반입 기록 /root/intake/record.json 을 남긴다(키: request, files, sha256sums_sha256, signer_pub_sha256, verified, installed).

참고

반입 요청서는 정확한 버전으로

/root/intake/request.txtpypi requests 2.32.3go rsc.io/quote v1.5.2 두 줄을 적는다.

한 줄에 생태계, 이름, 버전 세 칸입니다. 범위(>=)나 latest 를 쓰면 받는 날마다 결과가 달라집니다. Go 모듈의 버전은 v 로 시작합니다.

요청서대로 번들 받기

/root/intake/bundle/pypi/ 에 requests 2.32.3 과 의존성 휠을, /root/intake/bundle/goproxy/ 에 rsc.io/quote v1.5.2 의 모듈 프록시 내용을 받는다.

pip 는 휠만 받게 하는 옵션과 함께 download 를, Go 는 새 모듈 캐시(GOMODCACHE)로 한 번 받은 뒤 그 cache/download 를 옮기면 됩니다. Go 는 받을 모듈이 쓰일 작은 모듈이 필요합니다 — 7단계에서 쓸 /root/intake/goapp 을 지금 만들어 두세요.

상대 경로 해시 목록

번들 디렉터리 안에서 상대 경로로 /root/intake/bundle/SHA256SUMS 를 만든다(목록·서명 파일 자신은 뺀다).

번들 디렉터리로 들어가 find 로 파일을 모으고 sha256sum 에 넘기면 경로가 ./ 로 시작합니다. 목록 파일이 자기 자신을 포함하지 않게 이름으로 빼세요. 만든 뒤 같은 디렉터리에서 -c 로 확인합니다.

목록에 서명하기

/root/intake/keys/intake.key(Ed25519)·intake.pub 를 만들고 SHA256SUMS 의 서명을 /root/intake/bundle/SHA256SUMS.sig 에 둔다.

OpenSSL 3 의 genpkey 로 ed25519 키를 만들고, pkey 로 공개 키를 뽑습니다. Ed25519 는 원문을 그대로 받으므로 pkeyutl 에 -rawin 이 필요합니다. 개인 키는 번들 밖(keys/)에 둡니다.

개인 키 없는 매체와 따로 건네는 공개 키

/root/intake/media/bundle.tar 를 만들고 /root/intake/inside/ 에 풀며, 공개 키는 따로 /root/intake/inside/trusted.pub 로 둔다.

tar 는 bundle 디렉터리 하나만 담습니다. 풀면 inside/bundle 이 생기게 하세요. 공개 키가 매체 안에 있으면 바꿔치기한 사람이 자기 키를 넣으면 그만이라, 신뢰할 키는 다른 길로 미리 가 있어야 합니다.

서명 먼저, 해시 다음 — 검증 스크립트

/root/intake/verify.sh <번들> <공개키> 를 쓴다. 서명 → 해시 → 목록에 없는 파일 순으로 보고, 실패하면 0 이 아닌 값으로 끝난다.

채점기는 여러분의 스크립트를 번들 사본 두 개(파일 한 바이트를 바꾼 것, 그 파일에 맞춰 목록까지 고친 것)에 돌려 둘 다 거절하는지 봅니다. 두 번째는 해시만 보는 스크립트로는 막을 수 없습니다.

번들만으로 설치

바깥을 막은 채 /root/intake/inside/bundle 만으로 venv /root/intake/venv 에 requests 를, /root/intake/goapp 을 빌드해 /root/intake/bin/hello 를 만든다.

설치 전에 6단계 스크립트로 검증부터 하세요. pip 는 인덱스를 보지 않고 번들 디렉터리만 보게, Go 는 번들의 goproxy 디렉터리를 file:// 프록시로 가리키고 새 모듈 캐시로 빌드합니다.

반입 기록 남기기

/root/intake/record.jsonrequest(요청서 줄 목록), files(번들 목록의 파일 수), sha256sums_sha256, signer_pub_sha256(trusted.pub 파일의 sha256), verified(true), installed(설치한 것 목록)를 적는다.

값은 손으로 옮기지 말고 파일에서 계산하세요. files 는 SHA256SUMS 의 줄 수입니다. installed 에는 requests 와 Go 모듈처럼 실제로 설치·빌드에 쓴 것을 이름==버전 또는 모듈@버전 모양으로 적습니다.