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

Air-Gapped Mirrors and a Private CA

Make every tool trust a private CA

LabHub 에서 이어서 보기

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

목표

사설 루트 CA 와 서버 인증서를 만들어 사내 이름으로 HTTPS 를 띄우고, 운영체제·파이썬·Node 의 신뢰 저장소에 각각 넣는다. 어느 도구가 어느 저장소를 보는지 직접 재서 표로 남기고, 중간 CA 체인까지 서버가 보내게 한다.

왜 중요한가

사내 미러가 HTTPS 인 순간 모든 빌드 도구가 그 CA 를 믿어야 한다. 그런데 신뢰 저장소는 운영체제, certifi, Node 내장 목록, JVM 으로 나뉘어 있어서 한 곳에만 넣으면 일부 도구만 된다. 안 되는 도구에서 검증을 끄는 것이 가장 흔한 사고다. 이 실습 파드는 바깥에 닿지 않는다(DNS 만). 사설 CA 는 폐쇄망 안의 일이기 때문이다.

단계

  1. /root/pki/ca.key·/root/pki/ca.crt 로 CN 이 Airgap Internal Root CA 인 루트 CA 를 만든다(CA:TRUE, keyCertSign).
  2. /root/pki/server.key·/root/pki/server.crtrepo.airgap.internal 서버 인증서를 그 CA 로 발급한다(SAN 에 DNS 이름, 용도 serverAuth, CA 아님). 서명할 때 준 확장은 /root/pki/server.ext 로 남긴다.
  3. /etc/hosts127.0.0.1 repo.airgap.internal 을 더하고, /root/pki/www/hello.txt(내용 hello-airgap)를 https://repo.airgap.internal:8443/ 로 내주는 서버를 /root/pki/serve.py 로 띄운다.
  4. 루트 CA 를 운영체제 저장소에 airgap-root.crt 라는 이름으로 넣고 갱신한다. curl--cacert 없이 통과해야 한다.
  5. /etc/profile.d/airgap-ca.sh 에 파이썬 requests 와 httpx 가 운영체제 묶음을 쓰게 하는 환경 변수를 적는다.
  6. 같은 파일에 Node 가 사설 루트를 믿게 하는 환경 변수를 더한다.
  7. 환경 변수 없이(운영체제 저장소만으로) 각 도구가 통과하는지 재서 /root/pki/trust-matrix.txtcurl·urllib·requests·httpx·node·go 여섯 줄을 도구=os 또는 도구=env 로 적는다.
  8. 중간 CA(/root/pki/int.crt, pathlen 0)를 루트로 발급하고, 그 중간 CA 로 mirror.airgap.internal 인증서(/root/pki/mirror.crt)를 발급한다. /etc/hosts 에 이름을 더하고, 잎+중간을 이은 /root/pki/mirror-chain.crt 로 9443 포트에 같은 서버를 띄운다.

참고

사설 루트 CA 만들기

/root/pki/ca.key·/root/pki/ca.crt 로 CN Airgap Internal Root CA 인 루트 CA 를 만든다(CA:TRUE, keyCertSign).

openssl req 에 -x509 를 주면 요청 대신 자기 서명 인증서를 바로 만듭니다. 확장은 -addext 로 줄 수 있고, 루트 CA 에 필요한 것은 기본 제약(CA)과 키 용도(인증서 서명)입니다.

SAN 이 든 서버 인증서 발급

/root/pki/server.key·/root/pki/server.crtrepo.airgap.internal 서버 인증서를 루트 CA 로 발급한다(SAN DNS, serverAuth, CA 아님). 서명할 때 준 확장은 /root/pki/server.ext 로 남긴다.

키와 서명 요청(CSR)을 만든 뒤, CA 키로 서명할 때 확장 파일로 subjectAltName 과 extendedKeyUsage 를 줍니다. openssl x509 -req 는 요청의 확장을 기본으로 옮기지 않는다는 점에 주의하세요.

사내 이름으로 HTTPS 띄우기

/etc/hosts127.0.0.1 repo.airgap.internal 을 더하고, /root/pki/www/hello.txt(hello-airgap)를 https://repo.airgap.internal:8443/ 로 내주는 서버를 /root/pki/serve.py 로 띄운다.

파이썬 표준 라이브러리의 http.server 를 ssl 컨텍스트로 감싸면 HTTPS 서버가 됩니다. 인증서 파일과 키 파일을 load_cert_chain 에 줍니다. 백그라운드로 띄우고, 확인은 --cacert 로 루트를 지정한 curl 로 하세요.

운영체제 저장소에 넣기

루트 CA 를 운영체제 저장소에 airgap-root.crt 로 넣고 갱신한다. curl--cacert 없이 통과해야 한다.

데비안 계열은 정해진 디렉터리에 .crt 확장자로 두고 갱신 명령을 돌리면 한 파일로 이어 붙인 묶음이 다시 만들어집니다. 갱신 명령의 출력에 몇 개가 더해졌는지 나옵니다.

파이썬 requests·httpx 가 믿게 하기

/etc/profile.d/airgap-ca.sh 에 requests 와 httpx 가 운영체제 묶음을 쓰게 하는 환경 변수를 적는다.

requests 와 httpx 는 운영체제 저장소가 아니라 certifi 묶음을 씁니다. 두 라이브러리가 따르는 환경 변수는 서로 다릅니다 — 읽기 자료의 표를 보세요. 값은 운영체제가 만든 묶음 파일입니다.

Node 가 믿게 하기

/etc/profile.d/airgap-ca.sh 에 Node 가 사설 루트를 믿게 하는 환경 변수를 더한다.

Node 는 빌드에 들어간 목록을 쓰고, 그 목록에 인증서를 더하는 환경 변수가 있습니다. 프로세스가 시작할 때 한 번만 읽으므로 새 셸에서 확인하세요.

도구별 신뢰 표 재기

환경 변수 없이 각 도구가 통과하는지 재서 /root/pki/trust-matrix.txtcurl·urllib·requests·httpx·node·go도구=os 또는 도구=env 로 적는다.

env -i 로 환경을 비우면 profile.d 의 변수도 없습니다. 그 상태에서 통과하면 운영체제 저장소만으로 되는 것(os), 실패하면 환경 변수가 필요한 것(env)입니다. Go 는 작은 프로그램을 go run 으로 돌려 보세요.

중간 CA 와 체인 보내기

중간 CA /root/pki/int.crt(pathlen 0)와 그 CA 가 발급한 mirror.airgap.internal 인증서 /root/pki/mirror.crt 를 만들고, 잎+중간을 이은 /root/pki/mirror-chain.crt 로 9443 포트에 서버를 띄운다.

중간 CA 도 CA 이므로 기본 제약이 필요하고, pathlen 으로 그 아래 CA 를 못 두게 막습니다. 서버의 인증서 파일에는 잎 인증서 뒤에 중간 CA 인증서를 이어 붙입니다. 클라이언트는 루트만 알고 있습니다.