Air-gapped 컨테이너

Air-gapped 컨테이너 (Air-gapped containers)

컨테이너가 데이터를 주고받을 수 있는 곳을 제어해 컨테이너 네트워크 접근을 제한하는 방법을 배워볼게요.

출처: 문서

본문

Air-gapped 컨테이너를 사용하면 컨테이너가 데이터를 보내고 받을 수 있는 위치를 제어해 컨테이너 네트워크 접근을 제한할 수 있어요. 이 기능은 컨테이너 네트워크 트래픽에 맞춤 프록시 규칙을 적용해, 컨테이너가 제한 없이 인터넷에 접근해서는 안 되는 환경을 보호하는 데 도움이 돼요.

Docker Desktop은 컨테이너 네트워크 트래픽이 연결을 허용, 거부, 또는 HTTP·SOCKS 프록시를 통해 터널링하도록 구성할 수 있어요. 정책이 적용되는 TCP 포트와 단일 프록시 또는 PAC(Proxy Auto-Configuration) 파일을 통한 대상별 정책을 사용할지 제어할 수 있어요.

Air-gapped 컨테이너를 사용해야 하는 경우?

다음과 같은 경우 air-gapped 컨테이너를 사용해요:

  • 조직이 컨테이너가 승인된 내부 서비스와만 통신하도록 요구하는 경우
  • 네트워크 격리를 요구하는 규정 준수 표준(SOC 2, ISO 27001, PCI DSS 등)을 충족해야 하는 경우
  • 빌드 중이나 런타임 중 컨테이너가 데이터를 유출하거나 승인되지 않은 외부 엔드포인트에 도달하지 못하게 하려는 경우

Air-gapped 컨테이너가 작동하는 방식

containersProxy는 두 개의 뚜렷한 트래픽 경로를 관장해요:

  • 이미지 풀 (항상 강제): Docker Desktop은 VM 시작 시 daemon.json에서 http.docker.internal:3128을 데몬 프록시로 하드와이어해요. 따라서 모든 docker pull과 Compose pull 작업은 PAC 파일 규칙을 포함해 항상 containersProxy를 거쳐가요.
  • 실행 중인 컨테이너 외부 트래픽 (선택): Docker Desktop은 컨테이너 TCP 연결을 가로채 transparentPorts에 나열된 포트에 대해서만 프록시 규칙을 적용해요. 이 없이는 실행 중인 컨테이너 트래픽이 containersProxy를 완전히 우회해요.

중요: containersProxy 아래에 PAC 파일을 구성하면, PAC 파일이 이미지가 호스팅된 레지스트리에 연결할 적절한 프록시 서버를 반환해야 해요.

기타 고려 사항:

  • PAC 파일 다운로드가 실패하면 컨테이너가 대상 URL에 대한 요청을 차단해요
  • 호스트 이름은 80·443 포트에서 사용할 수 있지만, 다른 포트에서는 IP 주소만 사용할 수 있어요

사전 요구 사항

Air-gapped 컨테이너를 구성하기 전에 다음이 있어야 해요:

  • 사용자가 조직으로 인증하도록 Enforce sign-in 이 활성화돼 있어야 함
  • Docker Business 구독
  • 조직 정책을 관리하는 admin-settings.json 파일로 Settings Management 가 구성되어 있어야 함

Air-gapped 컨테이너 구성

[admin-settings.json 파일]에 컨테이너 프록시를 추가해요. 예:

{
  "configurationFileVersion": 2,
  "containersProxy": {
    "locked": true,
    "mode": "manual",
    "http": "",
    "https": "",
    "exclude": [],
    "pac": "http://192.168.1.16:62039/proxy.pac",
    "transparentPorts": "*"
  }
}

구성 매개변수

containersProxy 설정은 docker image pull과, transparentPorts가 구성되면 실행 중인 컨테이너 외부 트래픽에 적용되는 네트워크 정책을 제어해요:

매개변수 설명 값
locked 개발자가 설정을 오버라이드하지 못하게 합니다 true (잠금), false (기본)
mode 프록시 구성 방법 system (시스템 프록시 사용), manual (맞춤)
http HTTP 프록시 서버 URL (예: "http://proxy.company.com:8080")
https HTTPS 프록시 서버 URL (예: "https://proxy.company.com:8080")
exclude 이 주소들에 대해 프록시 우회 호스트 이름/IP 배열
pac PAC(Proxy Auto-Configuration) 파일 URL PAC 파일 URL
transparentPorts 프록시 규칙이 적용되는 포트 쉼표로 구분된 포트 또는 와일드카드 ("*")

구성 예시

모든 외부 접근 차단:

"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "",
  "https": "",
  "exclude": [],
  "transparentPorts": "*"
}

특정 내부 서비스 허용:

"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "",
  "https": "",
  "exclude": ["internal.company.com", "10.0.0.0/8"],
  "transparentPorts": "80,443"
}

회사 프록시를 통해 라우팅:

"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "http://corporate-proxy.company.com:8080",
  "https": "http://corporate-proxy.company.com:8080",
  "exclude": ["localhost", "*.company.local"],
  "transparentPorts": "*"
}

PAC(Proxy Auto-Configuration) 파일

PAC 파일은 대상별 규칙을 정의해 컨테이너 네트워크 접근에 대한 세밀한 제어를 제공해요.

기본 PAC 파일 구조

function FindProxyForURL(url, host) {
	if (localHostOrDomainIs(host, 'internal.corp')) {
		return "PROXY 10.0.0.1:3128";
	}
	if (isInNet(host, "192.168.0.0", "255.255.255.0")) {
	    return "DIRECT";
	}
    return "PROXY reject.docker.internal:1234";
}

일반적인 고려 사항

  • FindProxyForURL 함수 URL 매개변수 형식은 http://host_or_ip:port 또는 https://host_or_ip:port예요.
  • 내부 컨테이너가 https://docs.docker.com/enterprise/security/hardened-desktop/air-gapped-containers에 접근하려고 하면 Docker 프록시 서비스는 host 값으로 docs.docker.com을, URL 값으로 https://docs.docker.com:443 을 FindProxyForURL에 제출해요. PAC 파일에서 shExpMatch 함수를 아래처럼 사용한다면:
if(shExpMatch(url, "https://docs.docker.com:443/enterprise/security/hardened-desktop/*")) return "DIRECT";

shExpMatch 함수는 실패하므로 대신 다음을 사용해요:

if (host == docs.docker.com && url.indexOf(":443") > 0) return "DIRECT";

PAC 파일 반환 값

반환 값 동작
PROXY host:port 지정된 호스트·포트의 HTTP 프록시로 라우팅
SOCKS5 host:port 지정된 호스트·포트의 SOCKS5 프록시로 라우팅
DIRECT 프록시 없이 직접 연결 허용
PROXY reject.docker.internal:any_port 요청을 완전히 차단

고급 PAC 파일 예시

function FindProxyForURL(url, host) {
  // 승인된 기본 이미지에 대한 Docker Hub 접근 허용
  if (dnsDomainIs(host, ".docker.io") || host === "docker.io") {
    return "PROXY corporate-proxy.company.com:8080";
  }

  // 내부 패키지 저장소 허용
  if (localHostOrDomainIs(host, 'nexus.company.com') ||
      localHostOrDomainIs(host, 'artifactory.company.com')) {
    return "DIRECT";
  }

  // 특정 포트의 개발 도구 허용
  if (url.indexOf(":3000") > 0 || url.indexOf(":8080") > 0) {
    if (isInNet(host, "10.0.0.0", "255.0.0.0")) {
      return "DIRECT";
    }
  }

  // 개발자 localhost 접근 차단
  if (host === "host.docker.internal" || host === "localhost") {
    return "PROXY reject.docker.internal:1234";
  }

  // 다른 모든 외부 접근 차단
  return "PROXY reject.docker.internal:1234";
}

Air-gapped 컨테이너 구성 검증

구성을 적용한 후 컨테이너 네트워크 제한이 작동하는지 테스트해요.

차단된 접근 테스트:

$ docker run --rm alpine wget -O- https://www.google.com
# 프록시 규칙에 따라 실패하거나 타임아웃되어야 함

허용된 접근 테스트:

$ docker run --rm alpine wget -O- https://internal.company.com
# internal.company.com이 exclude 목록이나 PAC 규칙에 있으면 성공해야 함

프록시 라우팅 테스트:

$ docker run --rm alpine wget -O- https://docker.io
# 승인된 프록시를 통해 라우팅되면 성공해야 함

보안 고려 사항

  • 네트워크 정책 집행: Air-gapped 컨테이너는 Docker Desktop 수준에서 작동해요. 고급 사용자가 다양한 방법으로 제한을 우회할 수 있으므로, 고보안 환경에서는 추가 네트워크 수준 제어를 고려해요.
  • 개발 워크플로우 영향: 지나치게 제한적인 정책은 정당한 개발 워크플로우를 깨뜨릴 수 있어요. 철저히 테스트하고 필요한 서비스에 대한 명확한 예외를 제공해요.
  • PAC 파일 관리: PAC 파일을 신뢰할 수 있는 내부 인프라에 호스팅해요. PAC 다운로드 실패는 컨테이너 네트워크 접근 차단으로 이어져요.
  • 성능 고려 사항: 규칙이 많은 복잡한 PAC 파일은 컨테이너 네트워크 성능에 영향을 줄 수 있어요. 규칙을 간단하고 효율적으로 유지해요.

다음 단계

  • 런타임에 컨테이너가 할 수 있는 일을 더 제한하려면 Enhanced Container Isolation 을 살펴봐요
  • Docker Desktop이 호스트·컨테이너 네트워킹을 어떻게 처리하는지 이해하려면 관련 문서를 참고해요

더 알아보기 (Learn more)