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이 호스트·컨테이너 네트워킹을 어떻게 처리하는지 이해하려면 관련 문서를 참고해요