이 가이드에서는 Anthos Service Mesh 이그레스 게이트웨이 및 기타 Google Cloud 컨트롤을 사용하여 Google Kubernetes Engine 클러스터에 배포된 워크로드에서 아웃바운드 트래픽(이그레스)을 보호하는 방법을 설명합니다. 이 가이드는 권장사항 가이드의 보충 자료입니다.
이 가이드의 주요 이용 대상에는 하나 이상의 소프트웨어 제공팀이 사용하는 Google Kubernetes Engine 클러스터를 관리하는 네트워크, 플랫폼, 보안 엔지니어가 포함됩니다. 여기에 설명된 제어 기능은 규정 준수를 입증해야 하는 조직에 특히 유용합니다(예를 들어 GDPR 및 PCI).
목표
- Anthos Service Mesh를 실행하기 위한 인프라 설정:
- 커스텀 VPC 네트워크 및 비공개 서브넷
- 인터넷 액세스용 Cloud NAT
- 이그레스 게이트웨이 pod를 위한 추가 노드 풀이 있는 비공개 GKE 클러스터
- 제한된 이그레스 VPC 방화벽 규칙(게이트웨이 노드만 외부 호스트에 연결 가능)
- Container Registry 및 Google API에 연결하기 위한 비공개 Google 액세스
- 전용 노드 풀에서 실행되는 이그레스 게이트웨이로 Anthos Service Mesh 설치
- 이그레스 게이트웨이를 통해 외부 트래픽에 대한 멀티 테넌트 라우팅 규칙 구성:
- 'team-x' 네임스페이스의 애플리케이션을 example.com에 연결할 수 있음
- 'team-y' 네임스페이스의 애플리케이션을 httpbin.org에 연결할 수 있음
Sidecar
리소스를 사용하여 각 네임스페이스의 사이드카 프록시 이그레스 구성 범위 제한- 이그레스 규칙을 시행하도록 승인 정책 구성
- 일반 HTTP 요청을 TLS(TLS 원본)로 업그레이드하도록 이그레스 게이트웨이 구성
- TLS 트래픽을 통과하도록 이그레스 게이트웨이 구성
- Kubernetes 네트워크 정책을 추가 이그레스 제어로 설정
- 비공개 Google 액세스 및 Identity and Access Management(IAM) 권한을 사용하여 Google API에 대한 직접 액세스 구성
비용
이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.
- Compute Engine
- Google Kubernetes Engine(GKE)
- Container Registry
- Anthos Service Mesh
- Cloud Load Balancing
- Cloud NAT
- 네트워킹
- Cloud Storage
프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.
이 가이드를 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않도록 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.
시작하기 전에
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
가이드에 따라 사용할 작업 디렉터리를 만듭니다.
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
가이드에 따라 셸 스크립트를 만들어 환경을 초기화합니다. 프로젝트 및 환경설정에 따라 변수를 바꾸고 수정합니다. 셸 세션이 만료되면
source
명령어로 이 스크립트를 실행하여 환경을 다시 초기화합니다.cat << 'EOF' > ./init-egress-tutorial.sh #! /usr/bin/env bash PROJECT_ID=YOUR_PROJECT_ID REGION=REGION ZONE=ZONE gcloud config set project ${PROJECT_ID} gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE} EOF
스크립트를 실행 가능하게 만들고
source
명령어와 함께 실행하여 환경을 초기화합니다.chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
필요한 Identity and Access Management(IAM) 역할을 설정합니다. 프로젝트 소유자인 경우 설치를 완료하는 데 필요한 모든 권한이 있습니다. 프로젝트 소유자가 아닌 경우 관리자에게 다음 IAM 역할을 부여해 달라고 요청하세요. 다음 명령어에서 PROJECT_EMAIL_ADDRESS를 Google Cloud에 로그인하는 데 사용하는 계정으로 변경합니다.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member user:PROJECT_EMAIL_ADDRESS \ --role=roles/editor \ --role=roles/compute.admin \ --role=roles/container.admin \ --role=roles/resourcemanager.projectIamAdmin \ --role=roles/iam.serviceAccountAdmin \ --role=roles/iam.serviceAccountKeyAdmin \ --role=roles/gkehub.admin \ --role=roles/serviceusage.serviceUsageAdmin
가이드에 필요한 API를 사용 설정합니다.
gcloud services enable \ dns.googleapis.com \ container.googleapis.com \ compute.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshtelemetry.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com \ cloudresourcemanager.googleapis.com \ stackdriver.googleapis.com
API를 사용 설정하려면 완료하는 데 1분 이상 걸릴 수 있습니다. API가 사용 설정되면 다음과 비슷한 출력이 표시됩니다.
Operation "operations/acf.601db672-88e6-4f98-8ceb-aa3b5725533c" finished successfully.
인프라 설정
VPC 네트워크 및 서브넷 만들기
새 VPC 네트워크를 만듭니다.
gcloud compute networks create vpc-network \ --subnet-mode custom
pod 및 서비스에 사전 할당된 보조 IP 주소 범위를 사용하여 클러스터를 실행할 서브넷을 만듭니다. 내부 IP 주소만 있는 애플리케이션이 Google API 및 서비스에 연결할 수 있도록 비공개 Google 액세스가 사용 설정됩니다.
gcloud compute networks subnets create subnet-gke \ --network vpc-network \ --range 10.0.0.0/24 \ --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \ --enable-private-ip-google-access
Cloud NAT 구성
Cloud NAT를 사용하면 외부 IP 주소가 없는 워크로드를 인터넷의 대상에 연결하고 해당 대상에서 인바운드 응답을 수신할 수 있습니다.
Cloud Router를 만듭니다.
gcloud compute routers create nat-router \ --network vpc-network
라우터에 NAT 구성을 추가합니다.
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
각 GKE 노드 풀의 서비스 계정 만들기
2개의 GKE 노드 풀 두 개에서 사용할 서비스 계정 두 개를 만듭니다. 특정 노드에 VPC 방화벽 규칙을 적용할 수 있도록 각 노드 풀에 별도의 서비스 계정을 할당합니다.
기본 노드 풀의 노드에서 사용할 서비스 계정을 만듭니다.
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
게이트웨이 노드 풀의 노드에서 사용할 서비스 계정을 만듭니다.
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
서비스 계정에 권한 부여
애플리케이션 및 게이트웨이 서비스 계정에 최소한의 IAM 역할을 추가합니다. 이러한 역할은 Container Registry에서 비공개 컨테이너 이미지를 로깅, 모니터링, 가져오는 데 필요합니다.
project_roles=(
roles/logging.logWriter
roles/monitoring.metricWriter
roles/monitoring.viewer
roles/storage.objectViewer
)
for role in "${project_roles[@]}"
do
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
done
방화벽 규칙 만들기
다음 단계에서는 기본적으로 모든 이그레스 트래픽이 거부되도록 VPC 네트워크에 방화벽 규칙을 적용합니다. 클러스터가 작동하고 게이트웨이 노드가 VPC 외부의 대상에 연결하려면 특정 연결이 필요합니다. 특정 방화벽 규칙 최소 집합은 필요한 연결을 허용하도록 기본 deny-all 규칙을 재정의합니다.
VPC 네트워크의 모든 이그레스를 거부하는 기본(낮은 우선순위) 방화벽 규칙을 만듭니다.
gcloud compute firewall-rules create global-deny-egress-all \ --action DENY \ --direction EGRESS \ --rules all \ --destination-ranges 0.0.0.0/0 \ --network vpc-network \ --priority 65535 \ --description "Default rule to deny all egress from the network."
게이트웨이 서비스 계정이 있는 노드만 인터넷 연결을 허용하는 규칙을 만듭니다.
gcloud compute firewall-rules create gateway-allow-egress-web \ --action ALLOW \ --direction EGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --network vpc-network \ --priority 1000 \ --description "Allow the nodes running the egress gateways to connect to the web"
노드가 Kubernetes 제어 영역에 연결할 수 있도록 허용합니다.
gcloud compute firewall-rules create allow-egress-to-api-server \ --action ALLOW \ --direction EGRESS \ --rules tcp:443,tcp:10250 \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
Anthos Service Mesh는 사이드카 프록시를 워크로드에 삽입할 때 웹훅을 사용합니다. GKE API 서버가 노드에서 실행되는 서비스 메시 제어 영역에서 노출된 웹훅을 호출하도록 허용하세요.
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --source-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow the API server to call the webhooks exposed by istiod discovery"
클러스터에서 실행되는 pod와 서비스 간의 이그레스 연결을 허용하세요. 참고로 GKE는 해당 인그레스 규칙을 자동으로 만듭니다.
gcloud compute firewall-rules create allow-egress-pods-and-services \ --action ALLOW \ --direction EGRESS \ --rules all \ --destination-ranges 10.1.0.0/16,10.2.0.0/20 \ --network vpc-network \ --priority 1000 \ --description "Allow pods and services on nodes to reach each other"
Calico라는 서비스는 GKE에
NetworkPolicy
API 기능을 제공합니다. 서브넷 내에서 Calico 연결을 허용합니다.gcloud compute firewall-rules create allow-egress-calico \ --action ALLOW \ --direction EGRESS \ --rules tcp:5473 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow Calico Typha within the subnet"
GKE가 노드 측정항목을 읽으려면 kubelet 읽기 전용 포트가 필요합니다. 서브넷 내에서 여기에 대한 액세스를 허용합니다.
gcloud compute firewall-rules create allow-egress-kubelet-readonly \ --action ALLOW \ --direction EGRESS \ --rules tcp:10255 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the kubelet read-only port within the subnet"
비공개 Google 액세스가 Google API, Container Registry, 기타 서비스를 제공하기 위해 사용하는 예약된 IP 주소 집합에 대한 액세스를 허용하세요.
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --destination-ranges 199.36.153.8/30 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
Google Cloud 상태 확인 서비스가 클러스터에서 실행 중인 pod에 액세스하도록 허용하세요.
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --source-ranges 130.211.0.0/22,35.191.0.0/16,35.191.0.0/16,209.85.152.0/22,209.85.204.0/22 \ --network vpc-network \ --priority 1000 \ --description "Allow workloads to respond to Google Cloud health checks"
Google Cloud API에 대한 비공개 액세스 구성
비공개 Google 액세스를 사용하면 내부 IP 주소만 있는 VM 및 pod가 Google API 및 서비스에 액세스할 수 있습니다. Google API 및 서비스는 외부 IP에서 제공되지만 노드의 트래픽은 비공개 Google 액세스를 사용할 때 Google 네트워크를 벗어나지 않습니다.
노드 및 워크로드가 비공개 Google 액세스 및 'private.googleapis.com' 호스트 이름을 사용하여 Google API 및 서비스에 연결할 수 있도록 비공개 DNS 영역, 'CNAME', 'A' 레코드를 만듭니다.
gcloud dns managed-zones create private-google-apis \
--description "Private DNS zone for Google APIs" \
--dns-name googleapis.com \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-google-apis
gcloud dns record-sets transaction add private.googleapis.com. \
--name *.googleapis.com \
--ttl 300 \
--type CNAME \
--zone private-google-apis
gcloud dns record-sets transaction add "199.36.153.8" \
"199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name private.googleapis.com \
--ttl 300 \
--type A \
--zone private-google-apis
gcloud dns record-sets transaction execute --zone private-google-apis
Container Registry에 대한 비공개 액세스 구성
노드가 비공개 Google 액세스와 'gcr.io' 호스트 이름을 사용하여 Container Registry에 연결할 수 있도록 비공개 DNS 영역, 'CNAME' 및 'A' 레코드를 만듭니다.
gcloud dns managed-zones create private-gcr-io \
--description "private zone for Container Registry" \
--dns-name gcr.io \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-gcr-io
gcloud dns record-sets transaction add gcr.io. \
--name *.gcr.io \
--ttl 300 \
--type CNAME \
--zone private-gcr-io
gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name gcr.io \
--ttl 300 \
--type A \
--zone private-gcr-io
gcloud dns record-sets transaction execute --zone private-gcr-io
비공개 GKE 클러스터 만들기
클러스터의 API 서버에 액세스하도록 허용된 네트워크 목록에 추가할 수 있도록 Cloud Shell의 외부 IP 주소를 찾습니다.
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
일정 기간 활동이 없으면 Cloud Shell VM의 외부 IP 주소가 변경될 수 있습니다. 이 경우 클러스터의 승인된 네트워크 목록을 업데이트해야 합니다. 다음 명령어를 초기화 스크립트에 추가합니다.
cat << 'EOF' >> ./init-egress-tutorial.sh SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com) gcloud container clusters update cluster1 \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 EOF
비공개 GKE 클러스터를 만듭니다.
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --no-enable-basic-auth \ --no-issue-client-certificate \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-network-policy \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --num-nodes "4" \ --network "vpc-network" \ --subnetwork "subnet-gke" \ --cluster-secondary-range-name "pods" \ --services-secondary-range-name "services" \ --workload-pool "${PROJECT_ID}.svc.id.goog" \ --zone ${ZONE}
클러스터를 만드는 데 몇 분 정도 걸립니다. 클러스터에 내부 IP 주소가 있는 비공개 노드가 있습니다. VPC 서브넷을 만들 때 정의한 이름이 지정된 보조 범위의 IP가 pod 및 서비스에 할당됩니다.
Anthos Service Mesh에서는 클러스터 노드가 vCPU가 4개 이상인 머신 유형을 사용해야 합니다. 노드가 Anthos Service Mesh에서 지원하는 Kubernetes 버전을 실행하도록 하려면 클러스터가 '일반' 출시 채널을 구독하는 것이 좋습니다. 자세한 내용은 Anthos Service Mesh 설치 가이드를 참조하세요.
클러스터에는 워크로드 아이덴티티가 사용 설정되어 있습니다. Anthos Service Mesh를 사용하려면 워크로드 아이덴티티가 필요하며, 이는 GKE 워크로드에서 Google API에 액세스할 때 권장되는 방법입니다.
gateway라는 노드 풀을 만듭니다. 이 노드 풀은 이그레스 게이트웨이가 배포되는 위치입니다.
dedicated=gateway:NoSchedule
taint가 게이트웨이 노드 풀의 모든 노드에 추가됩니다.gcloud container node-pools create "gateway" \ --cluster "cluster1" \ --machine-type "e2-standard-4" \ --node-taints dedicated=gateway:NoSchedule \ --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --num-nodes "1"
Kubernetes taint 및 톨러레이션(toleration)은 이그레스 노드 pod만 게이트웨이 노드 풀의 노드에서 실행되도록 보장합니다.
kubectl을 사용하여 클러스터에 연결할 수 있도록 사용자 인증 정보를 다운로드하세요.
gcloud container clusters get-credentials cluster1
게이트웨이 노드에 올바른 taint가 있는지 확인합니다.
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
출력은 다음과 비슷합니다.
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
Anthos Service Mesh 설치 및 설정
이 가이드에서는 Anthos Service Mesh의 선택 기능을 사용합니다. 스크립트를 사용하여 Anthos Service Mesh를 설치하는 방법은 이 문서의 설치 가이드를 참조하세요.
서비스 메시 제어 영역과 배포 대상 이그레스 게이트웨이의 네임스페이스를 만듭니다.
kubectl create ns istio-system kubectl create ns istio-egress
istio-egress, istio-system, kube-system 네임스페이스에 라벨을 지정합니다.
kubectl label ns istio-egress istio=egress istio-injection=disabled kubectl label ns istio-system istio=system kubectl label ns kube-system kube-system=true
이러한 라벨은 나중에 Kubernetes NetworkPolicy를 적용하는 데 사용됩니다.
istio-injection=disabled
라벨은istioctl
분석을 실행할 때 허위 경고를 방지합니다.Istio OperatorAPI를 사용하여 Anthos Service Mesh 설치를 맞춤설정하는 매니페스트 파일을 만듭니다.
cat << 'EOF' > ./asm-custom-install.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: "egress-gateway" spec: meshConfig: accessLogFile: "/dev/stdout" components: egressGateways: - name: "istio-egressgateway" enabled: true namespace: "istio-egress" label: istio: "egress" k8s: tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
이 파일은 설치 스크립트에 인수로 제공되며 다음 구성을 지정합니다.
gateway
노드에서만 실행되도록 톨러레이션(toleration) 및 nodeSelector를 사용하여istio-egress
네임스페이스에서 실행되는 이그레스 게이트웨이 배포- 모든 사이드카 프록시의 'stdout'에 대한 액세스 로깅
설치 스크립트를 다운로드합니다.
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm
파일의 SHA-256 서명을 작업 디렉터리에 다운로드합니다.
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm.sha256
같은 디렉터리에서 두 파일의 다운로드 파일의 유효성을 검증합니다.
sha256sum -c --ignore-missing install_asm.sha256
검증이 성공하면 출력은 다음과 같습니다.
install_asm: OK
호환성을 위해
install_asm.sha256
파일에는 모든 버전의 스크립트 이름을install_asm
으로 바꿀 수 있게 해주는 체크섬이 두 배로 포함됩니다.--ignore-missing
이 없다는 오류가 발생하면--ignore-missing
플래그를 사용하지 않고 이전 명령어를 다시 실행합니다.스크립트를 실행 가능하게 만듭니다.
chmod +x install_asm
스크립트를 실행하여 Anthos Service Mesh를 설치합니다.
./install_asm \ --mode install \ --project_id ${PROJECT_ID} \ --cluster_name cluster1 \ --cluster_location ${ZONE} \ --custom_overlay ./asm-custom-install.yaml \ --output_dir ./ \ --enable_all
스크립트가 완료되면
istioctl
도구에 경로를 저장할 환경 변수를 설정하고 초기화 스크립트에 추가합니다.ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
Anthos Service Mesh 설치 확인
Anthos Service Mesh 제어 영역 구성요소가
istio-system
네임스페이스에서 실행 중인지 확인합니다.kubectl get pod -n istio-system
istio-ingressgateway
및istiod-asm
pod가 실행 중입니다.istio-egress
네임스페이스와gateway
노드 풀의 노드에서 이그레스 게이트웨이 pod가 실행 중인지 확인합니다.kubectl get pods -n istio-egress -o wide
이그레스 게이트웨이 pod에는
gateway
노드 풀의 노드를 선택할 수 있는nodeSelector
와 연결된 게이트웨이 노드에서 실행할 수 있는 톨러레이션(toleration)이 있습니다. nodeSelector 및 이그레스 게이트웨이 pod의 톨러레이션(toleration)을 검토하세요.kubectl -n istio-egress get pod -l app=istio-egressgateway \ -o=custom-columns='name:metadata.name,nodeSelector:spec.nodeSelector,\ tolerations:spec.tolerations[?(@.key=="dedicated")]'
출력은 다음과 비슷합니다.
name nodeSelector tolerations istio-egressgateway-74687946f5-dg9mp map[cloud.google.com/gke-nodepool:gateway] map[key:dedicated operator:Equal value:gateway]
메시 및 테스트 애플리케이션 준비
STRICT 상호 TLS가 사용 설정되어 있는지 확인합니다.
istio-system
네임스페이스에 메시의 기본PeerAuthentication
정책을 적용합니다.cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
특정 네임스페이스에서
PeerAuthentication
리소스를 만들어 이 구성을 재정의할 수 있습니다.테스트 워크로드를 배포하는 데 사용할 네임스페이스를 만듭니다. 이 가이드의 이후 단계에서는 각 네임스페이스에 서로 다른 이그레스 라우팅 규칙을 구성하는 방법을 설명합니다.
kubectl create namespace team-x kubectl create namespace team-y
Kubernetes 네트워크 정책에서 선택할 수 있도록 네임스페이스에 라벨을 지정합니다.
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
Anthos Service Mesh가 프록시 사이드카를 자동으로 삽입하도록 하려면 워크로드 네임스페이스에 버전 라벨을 설정해야 합니다. 버전 라벨은 클러스터에 배포된 Anthos Service Mesh 제어 영역의 버전과 일치해야 합니다.
istiod
pod에서 버전 라벨을 찾아 환경 변수에 저장합니다.REVISION_LABEL=$(kubectl get pod -n istio-system -l app=istiod \ -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}')
team-x
및team-y
네임스페이스에 버전 라벨을 설정합니다.kubectl label ns team-x istio.io/rev=${REVISION_LABEL} kubectl label ns team-y istio.io/rev=${REVISION_LABEL}
테스트 배포에 사용할 YAML 파일을 만듭니다.
cat << 'EOF' > ./test.yaml apiVersion: v1 kind: ServiceAccount metadata: name: test --- apiVersion: v1 kind: Service metadata: name: test labels: app: test spec: ports: - port: 80 name: http selector: app: test --- apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: serviceAccountName: test containers: - name: test image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent EOF
테스트 애플리케이션을
team-x
네임스페이스에 배포합니다.kubectl -n team-x create -f ./test.yaml
테스트 애플리케이션이 기본 풀의 노드에 배포되었고 프록시 사이드카 컨테이너가 삽입되었는지 확인합니다. pod 상태가
Running
이 될 때까지 다음 명령어를 반복합니다.kubectl -n team-x get po -l app=test -o wide
출력은 다음과 비슷합니다.
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-d5bdf6f4f-9nxfv 2/2 Running 0 19h 10.1.1.25 gke-cluster1-default-pool-f6c7a51f-wbzj
컨테이너 2개 중 2개가
Running
입니다. 한 컨테이너는 테스트 애플리케이션이고 다른 컨테이너는 프록시 사이드카입니다.pod가 기본 노드 풀의 노드에서 실행 중입니다.
테스트 컨테이너에서 외부 사이트로 HTTP 요청을 보낼 수 없는지 확인합니다.
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test -- curl -v http://example.com
'global-deny-egress-all' 방화벽 규칙이 업스트림 연결을 거부하므로 사이드카 프록시에서 오류 메시지가 생성됩니다.
사이드카 리소스를 사용하여 사이드카 프록시 구성 범위 제한
사이드카 리소스를 사용하여 사이드카 프록시용으로 구성된 이그레스 리스너의 범위를 제한할 수 있습니다. 구성 블로트 및 메모리 사용량을 줄이려면 모든 네임스페이스에 기본 Sidecar
리소스를 적용하는 것이 좋습니다.
사이드카에서 Anthos Service Mesh가 실행하는 프록시는 Envoy입니다. Envoy 용어에서 cluster
는 부하 분산의 대상으로 사용되는 논리적으로 유사한 업스트림 엔드포인트 그룹입니다.
istioctl proxy-config
명령어를 실행하여 테스트 pod의 Envoy 사이드카 프록시에 구성된 아웃바운드 클러스터를 검사합니다.${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
목록에 이그레스 게이트웨이용 몇 개를 포함한 약 20개의 Envoy 클러스터가 있습니다.
프록시 구성을
istio-egress
및team-x
네임스페이스의 서비스 항목으로 명시적으로 정의된 이그레스 경로로 제한합니다.Sidecar
리소스를team-x
네임스페이스에 적용합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-x spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-x/*' EOF
아웃바운드 트래픽 정책 모드를
REGISTRY_ONLY
로 설정하면 서비스 항목을 정의함으로써 메시의 서비스 레지스트리에 명시적으로 추가된 외부 호스트만 포함하도록 프록시 구성이 제한됩니다.'
istio-egress/*
' 부분은 사이드카 프록시가exportTo
속성을 사용하여 사용 가능하게 만든istio-egress
네임스페이스에서 경로를 선택하도록 지정합니다. 'team-x/*
' 부분에는team-x
네임스페이스에 로컬로 구성된 모든 경로가 포함됩니다.Envoy 사이드카 프록시에서 구성된 아웃바운드 클러스터를 열람하고
Sidecar
리소스를 적용하기 전에 구성된 클러스터 목록과 비교합니다.${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
출력에는 이그레스 게이트웨이용 테스트 클러스터 몇 개와 테스트 pod 자체에 대한 클러스터 1개만 포함됩니다.
이그레스 게이트웨이를 통해 트래픽을 라우팅하도록 Anthos Service Mesh 구성
포트 80에서 HTTP 트래픽의
Gateway
를 구성합니다.Gateway
는istio-egress
네임스페이스에 설치 프로그램이 배포된istio-egressgateway
프록시를 선택합니다.Gateway
구성이istio-egress
네임스페이스에 적용되고 모든 호스트의 트래픽을 처리합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egress servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL EOF
인증 및 암호화용 상호 TLS를 사용하여 이그레스 게이트웨이의
DestinationRule
을 만듭니다. 모든 외부 호스트에 단일 공유 대상 규칙을 사용합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: loadBalancer: simple: ROUND_ROBIN tls: mode: ISTIO_MUTUAL EOF
istio-egress
네임스페이스에ServiceEntry
를 만들어team-x
네임스페이스의 메시 서비스 레지스트리에 example.com을 명시적으로 등록합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress spec: hosts: - example.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'team-x' - 'istio-egress' EOF
이그레스 게이트웨이를 통해 트래픽을 example.com으로 라우팅하도록
VirtualService
을 만듭니다. 두 가지 일치 조건이 있습니다. 첫 번째 조건은 이그레스 게이트웨이로 트래픽을 전달하고 두 번째 조건은 이그레스 게이트웨이에서 대상 호스트로 트래픽을 전달합니다.exportTo
속성은 가상 서비스를 사용할 수 있는 네임스페이스를 제어합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
istioctl analyze
를 실행하여 구성 오류를 확인하세요.${ISTIOCTL} analyze -n istio-egress
출력은 다음과 비슷합니다.
✔ No validation issues found when analyzing namespace: istio-egress.
이그레스 게이트웨이를 통해 외부 사이트로 여러 요청을 보냅니다.
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- \ curl -s -o /dev/null -w "%{http_code}\n" http://example.com done
4개의 응답 모두에
200
상태 코드가 표시됩니다.프록시 액세스 로그를 확인하여 요청이 이그레스 게이트웨이를 통해 전달되었는지 확인합니다. 먼저 테스트 애플리케이션과 함께 배포된 프록시 사이드카의 액세스 로그를 확인합니다.
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
보내는 요청마다 다음과 비슷한 로그 항목이 표시됩니다.
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
이그레스 게이트웨이 액세스 로그도 확인하세요.
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egress \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
보내는 요청마다 다음과 비슷한 이그레스 게이트웨이 액세스 로그 항목이 표시됩니다.
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
두 번째 네임스페이스에 다른 라우팅 구성
두 번째 외부 호스트에 라우팅을 구성하여 여러 팀의 여러 외부 연결을 구성할 수 있습니다.
team-y
네임스페이스용Sidecar
리소스를 만듭니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-y spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-y/*' EOF
테스트 애플리케이션을
team-y
네임스페이스에 배포합니다.kubectl -n team-y create -f ./test.yaml
두 번째 외부 호스트를 등록하고
team-x
및team-y
네임스페이스로 내보냅니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: httpbin-org-ext namespace: istio-egress spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
이그레스 게이트웨이를 통해 트래픽을 httpbin.org로 라우팅하는 가상 서비스를 만듭니다.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
istioctl analyze
를 실행하여 구성 오류를 확인하세요.${ISTIOCTL} analyze -n istio-egress
다음과 같은 항목이 포함되어 있습니다.
✔ No validation issues found when analyzing namespace: istio-egress.
team-y
테스트 앱에서 httpbin.org에 요청합니다.kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \ jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
200 OK
응답이 표시됩니다.또한
team-x
테스트 앱에서 httpbin.org로 요청합니다.kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
200 OK
응답이 표시됩니다.team-y
네임스페이스에서 example.com에 요청을 시도하세요.kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
example.com
호스트에 구성된 아웃바운드 경로가 없으므로 요청이 실패합니다.
승인 정책을 사용하여 트래픽에 대한 추가 컨트롤 제공
이 가이드에서는 이그레스 게이트웨이의 승인 정책이 istio-egress
네임스페이스에 생성됩니다. 네트워크 관리자만 istio-egress
네임스페이스에 액세스할 수 있도록 Kubernetes RBAC를 구성할 수 있습니다.
AuthorizationPolicy
를 만드세요. 그러면team-x
네임스페이스의 애플리케이션은 example.com에 연결할 수 있지만 포트 80을 사용하여 요청을 보낼 때 다른 외부 호스트에 연결할 수 없습니다. 이그레스 게이트웨이 pod의 해당targetPort
는 8080입니다.cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-x-to-example-com namespace: istio-egress spec: rules: - from: - source: namespaces: - 'team-x' to: - operation: hosts: - 'example.com' when: - key: destination.port values: ["8080"] EOF
team-x
네임스페이스의 테스트 애플리케이션에서 example.com에 요청을 보낼 수 있는지 확인합니다.kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
200 OK
응답이 표시됩니다.team-x
네임스페이스의 테스트 애플리케이션에서 httpbin.org에 요청을 보내 봅니다.kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
RBAC: access denied
메시지 및 403 Forbidden 상태 코드와 함께 요청이 실패합니다. 승인 정책이 적용되기 전에 약간의 지연이 발생하는 경우가 있으므로 몇 초 정도 기다려야 할 수 있습니다.승인 정책은 허용 또는 거부되는 트래픽을 세부적으로 제어합니다. 다음 승인 정책을 적용하여
team-y
네임스페이스의 테스트 앱이 포트 80을 사용하여 요청을 보낼 때 특정 URL 경로를 사용하여 httpbin.org에 요청하도록 허용합니다. 이그레스 게이트웨이 pod의 해당targetPort
는 8080입니다.cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-y-to-httpbin-teapot namespace: istio-egress spec: rules: - from: - source: namespaces: - 'team-y' to: - operation: hosts: - httpbin.org paths: ['/status/418'] when: - key: destination.port values: ["8080"] EOF
team-y
네임스페이스의 테스트 앱에서 httpbin.org에 연결을 시도합니다.kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
RBAC: 액세스 거부 메시지 및 403 Forbidden 상태 코드와 함께 요청이 실패합니다.
이제 동일한 앱에서 httpbin.org/status/418에 요청을 보냅니다.
kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
경로가 승인 정책의 패턴과 일치하므로 요청이 성공합니다. 출력은 다음과 비슷합니다.
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
이그레스 게이트웨이에서 TLS 시작
일반 HTTP 요청을 TLS로 '업그레이드'하도록 이그레스 게이트웨이를 구성할 수 있습니다. 애플리케이션이 일반 HTTP 요청을 하도록 허용하면 Istio 상호 TLS와 TLS 원본과 함께 사용할 때 여러 가지 이점이 있습니다. 자세한 내용은 권장사항 가이드를 참조하세요.
DestinationRule. The DestinationRule
을 만드세요. 이는 게이트웨이로부터 example.com에 TLS 연결이 시작되도록 지정합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: example-com-originate-tls namespace: istio-egress spec: host: example.com subsets: - name: example-com-originate-TLS trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
게이트웨이의 포트 80에 대한 요청이 대상 호스트로 전송될 때 포트 443에서 TLS로 '업그레이드'되도록 example.com의 가상 서비스를 업데이트합니다.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 EOF
team-x
네임스페이스의 테스트 앱에서 example.com에 대한 여러 요청을 전송합니다.for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com done
전과 마찬가지로 요청은
200 OK
응답과 함께 성공합니다.이그레스 게이트웨이 로그에서 게이트웨이가 발신 TLS 연결을 통해 요청을 대상 호스트로 라우팅했는지 확인하세요.
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egress \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
출력은 다음과 비슷합니다.
[2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
프록시 사이드카가 포트 80을 사용하여 게이트웨이로 요청을 보냈고, 포트 443에서 TLS가 시작되어 대상 호스트로 요청이 전송되었습니다.
HTTPS/TLS 연결 패스스루
기존 애플리케이션은 이미 외부 서비스와 통신할 때 TLS 연결을 사용하고 있을 수 있습니다. TLS 연결을 복호화하지 않고 전달하도록 이그레스 게이트웨이를 구성할 수 있습니다.
이그레스 게이트웨이가 포트 443에 연결을 위해 TLS 패스스루를 사용하도록 구성을 수정합니다.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egress servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL - port: number: 443 name: tls protocol: TLS hosts: - '*' tls: mode: PASSTHROUGH EOF
이그레스 게이트웨이를 가리키는
DestinationRule
을 업데이트하여 게이트웨이에 포트 443의 두 번째 하위 집합을 추가합니다. 이 새 하위 집합은 상호 TLS를 사용하지 않습니다. TLS 연결의 패스스루에는 Istio 상호 TLS가 지원되지 않습니다. 포트 80의 연결에서는 mTLS를 계속 사용합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 80 tls: mode: ISTIO_MUTUAL - name: target-egress-gateway-TLS-passthrough EOF
포트 443의 TLS 트래픽이 게이트웨이를 패스스루하도록 example.com의 가상 서비스를 업데이트하세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - example.com route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - example.com route: - destination: host: example.com port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
포트 443의 TLS 트래픽이 게이트웨이를 패스스루하도록 httpbin.org의 가상 서비스를 업데이트하세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - httpbin.org route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - httpbin.org route: - destination: host: httpbin.org port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
이그레스 게이트웨이 서비스의 포트 443으로 전송된 모든 종류의 트래픽을 허용하는 승인 정책을 추가합니다. 게이트웨이 pod의 해당
targetPort
는 8443입니다.cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-all-443 namespace: istio-egress spec: rules: - when: - key: destination.port values: ["8443"] EOF
istioctl analyze
를 실행하여 구성 오류를 확인하세요.${ISTIOCTL} analyze -n istio-egress
다음과 같은 항목이 포함되어 있습니다.
✔ No validation issues found when analyzing namespace: istio-egress.
team-x
네임스페이스의 테스트 애플리케이션에서 example.com으로 일반 HTTP 요청을 보냅니다.kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
200 OK
응답과 함께 요청이 성공합니다.이제
team-x
네임스페이스의 테스트 애플리케이션에서 여러 TLS(HTTPS) 요청을 수행합니다.for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \ -w "%{http_code}\n" \ https://example.com done
200개의 응답이 표시됩니다.
이그레스 게이트웨이 로그를 다시 조사합니다.
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egress \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
다음과 비슷한 로그 항목이 표시됩니다.
[2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
HTTPS 요청이 TCP 트래픽으로 취급되어 게이트웨이를 통해 대상 호스트로 전달되었으므로 HTTP 정보가 로그에 포함되지 않습니다.
Kubernetes NetworkPolicy를 추가 컨트롤로 사용
애플리케이션이 사이드카 프록시를 우회할 수 있는 시나리오는 여러 가지가 있습니다.
Kubernetes NetworkPolicy
를 사용하여 허용되는 연결 워크로드를 추가로 지정할 수 있습니다. 단일 네트워크 정책이 적용되면 명시적으로 허용되지 않은 모든 연결이 거부됩니다.
이 가이드에서는 네트워크 정책의 이그레스 연결과 이그레스 선택기만 고려합니다. 자체 클러스터에서 네트워크 정책으로 인그레스를 제어하는 경우 이그레스 정책에 해당하는 인그레스 정책을 만들어야 합니다. 예를 들어 team-x
네임스페이스의 워크로드에서 team-y
네임스페이스로의 이그레스를 허용하는 경우 team-x
네임스페이스에서 team-y
네임스페이스로의 인그레스도 허용해야 합니다.
team-x
네임스페이스에 배포된 워크로드 및 프록시가istiod
및 이그레스 게이트웨이에 연결하도록 허용하세요.cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-control-plane namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: istio: system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: istio: egress podSelector: matchLabels: istio: egress EOF
워크로드 및 프록시에서 DNS를 쿼리할 수 있도록 허용하세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-dns namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kube-system: "true" ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
워크로드 및 프록시가 Mesh CA를 포함한 Google API 및 서비스를 제공하는 IP에 연결하도록 허용하세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-google-apis namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - ipBlock: cidr: 199.36.153.4/30 - ipBlock: cidr: 199.36.153.8/30 EOF
워크로드 및 프록시가 GKE 메타데이터 서버에 연결하도록 허용하세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-metadata-server namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: # For GKE data plane v2 - ipBlock: cidr: 169.254.169.254/32 - to: # For GKE data plane v1 - ipBlock: cidr: 127.0.0.1/32 ports: - protocol: TCP port: 988 EOF
선택사항:
team-x
네임스페이스의 워크로드와 프록시가 서로 연결하도록 허용하세요.cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-same-namespace namespace: team-x spec: podSelector: {} ingress: - from: - podSelector: {} egress: - to: - podSelector: {} EOF
선택사항:
team-x
네임스페이스의 워크로드와 프록시가 다른 팀에서 배포한 워크로드에 연결할 수 있도록 허용하세요.cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-team-y namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: team: 'y' EOF
사이드카 프록시 간의 연결이 유지됩니다. 새 네트워크 정책을 적용해도 기존 연결은 종료되지 않습니다. team-x 네임스페이스에서 워크로드를 다시 시작하여 기존 연결이 종료되었는지 확인합니다.
kubectl -n team-x rollout restart deployment
team-x
네임스페이스의 테스트 애플리케이션에서 example.com에 HTTP 요청을 계속할 수 있는지 확인하세요.kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
200 OK
응답과 함께 요청이 성공합니다.
비공개 Google 액세스 및 IAM 권한을 사용하여 Google API에 직접 액세스
Google의 API 및 서비스는 외부 IP 주소를 사용하여 노출됩니다. VPC 기반 별칭 IP 주소가 있는 pod가 비공개 Google 액세스를 사용하여 Google API에 연결되면 트래픽이 Google 네트워크에서 벗어나지 않습니다.
이 가이드의 인프라를 설정할 때 GKE pod에서 사용하는 서브넷에 비공개 Google 액세스를 사용 설정했습니다. 비공개 Google 액세스에서 사용되는 IP 주소에 대한 액세스를 허용하기 위해 경로, VPC 방화벽 규칙, 비공개 DNS 영역을 만들었습니다. 이 구성을 사용하면 이그레스 게이트웨이를 통해 트래픽을 전송하지 않고도 pod가 Google API에 직접 도달할 수 있습니다. 워크로드 아이덴티티 및 IAM을 사용하여 특정 Kubernetes 서비스 계정 및 네임스페이스에서 사용할 수 있는 API를 제어할 수 있습니다. 이그레스 게이트웨이가 Google API에 대한 연결을 처리하지 않기 때문에 Istio 승인이 적용되지 않습니다.
pod가 Google API를 호출할 수 있도록 하려면 먼저 IAM을 사용하여 권한을 부여해야 합니다. 이 가이드에서 사용하는 클러스터는 워크로드 아이덴티티를 사용하도록 구성되었으므로 Kubernetes 서비스 계정이 Google 서비스 계정으로 작동할 수 있습니다.
애플리케이션이 사용할 Google 서비스 계정을 만드세요.
gcloud iam service-accounts create sa-test-app-team-x
Kubernetes 서비스 계정이 Google 서비스 계정을 가장하도록 허용하세요.
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \ sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
team-x
네임스페이스에서 테스트 앱의 Kubernetes 서비스 계정을 Google 서비스 계정의 이메일 주소로 주석 처리하세요.cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com name: test namespace: team-x EOF
테스트 애플리케이션 pod는 Google API 호출을 위한 임시 사용자 인증 정보를 얻기 위해 DaemonSet로 실행되는 Google 메타데이터 서버에 액세스할 수 있어야 합니다. GKE 메타데이터 서버의 서비스 항목을 만듭니다.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: metadata-google-internal namespace: istio-egress spec: hosts: - metadata.google.internal ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
또한 private.googleapis.com 및 storage.googleapis.com에 대한 서비스 항목을 만드세요.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: private-googleapis-com namespace: istio-egress spec: hosts: - private.googleapis.com - storage.googleapis.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
Kubernetes 서비스 계정이 Google 서비스 계정 역할을 하도록 올바르게 구성되었는지 확인합니다.
kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
Google 서비스 계정이 유일한 활성 ID로 표시됩니다.
Cloud Storage 버킷에 테스트 파일을 만듭니다.
echo "Hello, World!" > /tmp/hello gsutil mb gs://${PROJECT_ID}-bucket gsutil cp /tmp/hello gs://${PROJECT_ID}-bucket/
서비스 계정에 버킷의 파일을 나열하고 볼 수 있는 권한을 부여하세요.
gsutil iam ch \ serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com:objectViewer \ gs://${PROJECT_ID}-bucket/
테스트 애플리케이션이 테스트 버킷에 액세스할 수 있는지 확인합니다.
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gsutil cat gs://${PROJECT_ID}-bucket/hello
다음과 같은 항목이 포함되어 있습니다.
Hello, World!
삭제
이 가이드에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.
이 가이드에서 사용한 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 섹션의 절차를 완료하세요.
프로젝트 삭제
청구되지 않도록 하는 가장 쉬운 방법은 가이드에서 만든 프로젝트를 삭제하는 것입니다.
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
다음 단계
- 컴패니언 권장사항 가이드 참조하기
- GKE 강화 가이드 참조하기
- GKE Enterprise 구성 관리를 사용하여 모든 인프라에서 구성 및 정책을 관리하는 방법 알아보기
- 그 밖의 참조 아키텍처, 다이어그램, 튜토리얼, 권장사항을 알아보려면 클라우드 아키텍처 센터를 확인하세요.