콘텐츠로 이동
Study Note서버 관리 일반

9. 사내 프록시 — 프로그램마다 따로 논다

사내 프록시가 어려운 이유는 하나다 — “시스템 프록시 설정”이라는 것이 리눅스에 없다. 프로그램마다 자기 방식으로 따로 읽는다

이 장에서 처음 나오는 말5개
포워드 프록시forward proxy
내부에서 외부로 나가는 요청을 대신 보내주는 중계 서버. 사내망에서 인터넷 접근을 한 지점으로 모아 통제·기록하려고 둔다. 이 장의 "프록시"는 전부 이것이다.
CONNECT 터널
HTTPS 요청을 프록시로 보낼 때 쓰는 방식. 프록시에 "이 호스트의 443으로 터널을 열어 달라"고 먼저 요청한 뒤 그 위로 TLS를 한다.
MITM 검사Man-In-The-Middle inspection
프록시가 TLS를 일단 풀어서 내용을 검사하고 자기 인증서로 다시 암호화하는 것. 사내 보안 정책으로 흔하다 — 그래서 클라이언트에 사내 CA 인증서를 심어야 한다.
CACertificate Authority
인증서에 서명해 주는 기관. 브라우저·OS는 신뢰하는 CA 목록을 들고 있고, 그 목록에 없는 CA가 서명한 인증서는 거부된다. 사내 CA는 목록에 없으므로 직접 추가해야 한다.
NO_PROXY
"이 주소들은 프록시를 거치지 말라"는 예외 목록. 빠뜨리면 사내 서버끼리의 통신까지 프록시로 나갔다가 막힌다 — 프록시 설정에서 가장 사고가 잦은 항목이다.
환경변수·apt·snap·systemd·git·CA 저장소가 각각 어떤 프로그램의 프록시와 TLS 검증을 담당하는지 짝지은 표

환경변수를 읽는 프로그램이 가장 많지만 전부는 아니다. apt·snap·systemd 서비스·git·docker는 각자 자기 설정을 본다 — “curl은 되는데 apt는 안 돼요”의 정체가 이것이다.

터미널 창
# 확인부터
env | grep -i proxy
echo $http_proxy $https_proxy $no_proxy

/etc/environment (모든 사용자·모든 세션에 적용, 로그인 시 읽힌다)

http_proxy="http://proxy.corp.local:3128"
https_proxy="http://proxy.corp.local:3128"
no_proxy="localhost,127.0.0.1,::1,.corp.local,10.0.0.0/8,169.254.169.254"
HTTP_PROXY="http://proxy.corp.local:3128"
HTTPS_PROXY="http://proxy.corp.local:3128"
NO_PROXY="localhost,127.0.0.1,::1,.corp.local,10.0.0.0/8,169.254.169.254"
넣어야 하는 것이유
localhost,127.0.0.1,::1자기 자신에게 가는 요청까지 프록시로 나가면 전부 실패한다
.corp.local (앞의 점)사내 도메인 전체. 점 하나가 서브도메인 매칭을 만든다
10.0.0.0/8 등 사내 대역사내 IP 직접 접근
169.254.169.254클라우드 메타데이터 주소. 빠뜨리면 인스턴스가 이상해진다

apt는 환경변수를 보지 않는다. 별도 파일이 필요하다.

/etc/apt/apt.conf.d/95proxy

Acquire::http::Proxy "http://proxy.corp.local:3128";
Acquire::https::Proxy "http://proxy.corp.local:3128";
// 사내 미러는 직접
Acquire::http::Proxy::mirror.corp.local "DIRECT";
터미널 창
sudo apt update -o Debug::Acquire::http=true # 실제로 프록시를 타는지 확인
apt-config dump | grep -i proxy

인증이 필요하면 http://사용자:비밀번호@proxy… 형식인데, 파일에 평문으로 남는다 — sudo chmod 600 하고, 가능하면 IP 기반 인증을 요청한다.

프로그램설정 위치환경변수를 보나
curl · wget환경변수 (curl은 -x도)✅ (curl은 소문자만)
apt/etc/apt/apt.conf.d/95proxy❌
snapsnap set system proxy.*❌
systemd 서비스유닛 drop-in Environment=❌ (로그인 셸을 안 거친다)
docker pull데몬 drop-in❌
docker build/run~/.docker/config.json❌
git (https)git config http.proxy⚠️ 보긴 하지만 config가 우선
git (ssh)~/.ssh/config의 ProxyCommand❌
pip · npm환경변수 또는 각자 config✅

3. 사내 사설 CA 인증서 — TLS가 깨질 때

섹션 제목: “3. 사내 사설 CA 인증서 — TLS가 깨질 때”

프록시가 MITM 검사를 하면 서버 인증서가 사내 CA가 서명한 것으로 바뀐다. OS는 그 CA를 모르니 전부 거부한다.

curl: (60) SSL certificate problem: self-signed certificate in certificate chain
SSL: CERTIFICATE_VERIFY_FAILED (Python)
unable to get local issuer certificate (git · node)
x509: certificate signed by unknown authority (docker · go)

이 메시지들이 보이면 전부 같은 원인이고 해법도 같다.

  1. 사내 CA 인증서(.crt, PEM 형식)를 받는다. 없으면 실제 연결에서 뽑는다

    터미널 창
    openssl s_client -showcerts -connect example.com:443 -servername example.com </dev/null \
    | openssl x509 -outform PEM > /tmp/corp-ca.crt
    openssl x509 -in /tmp/corp-ca.crt -noout -subject -issuer -dates
  2. 확장자가 반드시 .crt 여야 하고 PEM 형식이어야 한다 (.pem은 무시된다)

    터미널 창
    sudo cp /tmp/corp-ca.crt /usr/local/share/ca-certificates/corp-ca.crt
    sudo update-ca-certificates
    # 1 added, 0 removed; done.
  3. 확인

    터미널 창
    curl -vI https://example.com # 이제 --insecure 없이 통과해야 한다

진단 — 프록시를 타고 있는지 어떻게 아나

섹션 제목: “진단 — 프록시를 타고 있는지 어떻게 아나”
터미널 창
curl -v https://example.com 2>&1 | head -20
# 프록시 경유: * Connected to proxy.corp.local (10.x.x.x) port 3128
# > CONNECT example.com:443 HTTP/1.1
# 직접 연결: * Connected to example.com (93.x.x.x) port 443
curl -v -x http://proxy.corp.local:3128 https://example.com # 환경변수 무시하고 강제
curl -v --noproxy '*' https://example.com # 프록시 강제 우회 — 둘을 비교한다
증상원인
407 Proxy Authentication Required프록시 인증 필요 — 자격 증명 또는 IP 등록
Connected to proxy … 후 타임아웃프록시는 닿는데 그 목적지를 프록시가 막고 있다 (차단 정책)
프록시 주소로 연결 자체가 실패프록시 주소/포트 오타, 또는 프록시까지의 경로 문제(8장)
내부 서버인데 Connected to proxyno_proxy에 그 주소가 빠졌다
사용자로는 되고 sudo로는 실패sudo가 환경변수를 버렸다 — sudo -E
CLI는 되는데 서비스는 실패데몬에 환경변수가 안 갔다 — /proc/PID/environ 확인
  • 리눅스에는 통합 프록시 설정이 없다 — 환경변수 · apt · snap · systemd · docker · git이 전부 따로다
  • 환경변수는 대소문자 둘 다, https_proxy 값도 보통 http:// 로 시작한다
  • sudo는 프록시 환경변수를 버린다 — sudo -E 또는 env_keep
  • no_proxy에 localhost · 사내 도메인 · 메타데이터 IP를 빠뜨리면 사고가 난다
  • 데몬이 프록시를 먹었는지는 /proc/PID/environ 으로 확정한다
  • TLS 오류 4종은 전부 같은 원인 — /usr/local/share/ca-certificates/*.crt + update-ca-certificates. 단 Node·Python·Java는 별도 지정이 필요하다
  • -k·sslVerify false는 진단용이지 해결이 아니다