이 튜토리얼에서는 Cloud Service Mesh 이그레스 게이트웨이 및 기타 Google Cloud 컨트롤을 사용하여 Google Kubernetes Engine 클러스터에 배포된 워크로드에서 아웃바운드 트래픽(이그레스)을 보호하는 방법을 설명합니다. 이 튜토리얼은 GKE 클러스터에서 Cloud Service Mesh 이그레스 게이트웨이를 사용하기 위한 권장사항의 보충 자료입니다.
이 튜토리얼의 주요 이용 대상에는 하나 이상의 소프트웨어 배포팀이 사용하는 Google Kubernetes Engine 클러스터를 관리하는 네트워크, 플랫폼, 보안 엔지니어가 포함됩니다. 여기에 설명된 제어 기능은 규정 준수를 입증해야 하는 조직에 특히 유용합니다(예를 들어 GDPR 및 PCI).
목표
- Cloud Service Mesh를 실행하기 위한 인프라 설정:
- 커스텀 VPC 네트워크 및 비공개 서브넷
- 인터넷 액세스용 Cloud NAT
- 이그레스 게이트웨이 pod를 위한 추가 노드 풀이 있는 비공개 GKE 클러스터
- 제한된 이그레스 VPC 방화벽 규칙(게이트웨이 노드만 외부 호스트에 연결 가능)
- Container Registry 및 Google API에 연결하기 위한 비공개 Google 액세스
- Cloud 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
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- 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
compute.googleapis.com
사용 설정:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
스크립트를 실행 가능하게 만들고
source
명령어와 함께 실행하여 환경을 초기화합니다.compute.googleapis.com
을 사용 설정하라는 메시지가 표시되면Y
를 선택합니다.chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
인프라 설정
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}." \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}." \
--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}. \ --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 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.,sa-gateway-nodes@${PROJECT_ID}. \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
(선택사항) 관리형 Cloud Service Mesh를 사용하는 경우 이 방화벽 규칙은 필요하지 않습니다.
Cloud Service Mesh는 사이드카 프록시를 워크로드에 삽입할 때 웹훅을 사용합니다. GKE API 서버가 노드에서 실행되는 서비스 메시 컨트롤 플레인에서 노출된 웹훅을 호출하도록 허용하세요.
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.,sa-gateway-nodes@${PROJECT_ID}. \ --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"
클러스터에서 실행되는 노드와 포드 간의 이그레스 연결을 허용합니다. GKE는 해당 인그레스 규칙을 자동으로 만듭니다. iptables 라우팅 체인이 항상 서비스 IP 주소를 포드 IP 주소로 변환하기 때문에 서비스 연결에 규칙이 필요하지 않습니다.
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.,sa-gateway-nodes@${PROJECT_ID}. \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
비공개 Google 액세스가 Google API, Container Registry, 기타 서비스를 제공하기 위해 사용하는 예약된 IP 주소 집합에 대한 액세스를 허용하세요.
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.,sa-gateway-nodes@${PROJECT_ID}. \ --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 상태 확인 서비스가 클러스터에서 실행 중인 포드에 액세스하도록 허용하세요. 자세한 내용은 상태 점검을 참조하세요.
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.,sa-gateway-nodes@${PROJECT_ID}. \ --source-ranges 35.191.0.0/16,130.211.0.0/22,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 네트워크를 벗어나지 않습니다.
Cloud DNS API 사용 설정:
gcloud services enable dns.googleapis.com
노드 및 워크로드가 비공개 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
Google Kubernetes Engine API를 사용 설정합니다.
gcloud services enable container.googleapis.com
비공개 GKE 클러스터를 만듭니다.
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-dataplane-v2 \ --service-account "sa-application-nodes@${PROJECT_ID}." \ --machine-type "e2-standard-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 및 서비스에 할당됩니다.
클러스터 내 컨트롤 플레인이 있는 Cloud Service Mesh에는 클러스터 노드에서 vCPU가 4개 이상인 머신 유형을 사용해야 합니다.
노드가 Cloud Service Mesh에서 지원하는 Kubernetes 버전을 실행하도록 하려면 클러스터가 '일반' 출시 채널을 구독하는 것이 좋습니다.
클러스터 내 컨트롤 플레인에서 Cloud Service Mesh를 실행하기 위한 기본 요건에 대한 자세한 내용은 클러스터 내 기본 요건을 참조하세요.
관리형 Cloud Service Mesh 실행에 관한 요구사항 및 제한사항에 대한 자세한 내용은 관리형 Cloud Service Mesh 지원 기능을 참조하세요.
GKE용 워크로드 아이덴티티 제휴는 클러스터에서 사용 설정됩니다. Cloud Service Mesh를 사용하려면 GKE용 워크로드 아이덴티티 제휴가 필요하며, 이는 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}." \ --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]
Cloud Service Mesh 설치 및 설정
Cloud Service Mesh의 설치 옵션 중 하나를 수행합니다.
Cloud Service Mesh를 설치한 후 인그레스 또는 이그레스 게이트웨이를 설치하지 않고 중지하고 이 튜토리얼로 돌아갑니다.
이그레스 게이트웨이 설치
이그레스 게이트웨이의 Kubernetes 네임스페이스를 만듭니다.
kubectl create namespace istio-egress
이그레스 게이트웨이를 배포하면 배포 또는 네임스페이스에 적용하는 라벨을 기준으로 구성이 자동으로 삽입됩니다. 기본 태그가 설정되어 있는 경우 네임스페이스에기본 삽입 라벨을 지정하고 그렇지 않은 경우 설치한 컨트롤 플레인의 버전 라벨을 사용합니다. 또한 버전 라벨은 관리형 Cloud Service Mesh를 배포했거나 클러스터 내 컨트롤 플레인을 설치했는지에 따라 달라집니다.
설치 유형(관리형 또는 클러스터 내)에 따라 다음 탭을 선택합니다.
관리됨
다음 명령어를 사용하여 사용 가능한 컨트롤 플레인 버전을 찾습니다.
kubectl -n istio-system get controlplanerevision
출력은 다음과 비슷합니다.
NAME RECONCILED STALLED AGE asm-managed True False 112m
사용하려는 컨트롤 플레인 버전에 대한
NAME
열의 값을 기록합니다. 일반적으로 Cloud Service Mesh 출시 채널이 Google Kubernetes Engine 클러스터의 출시 채널에 해당합니다.클러스터 내
클러스터 내 컨트롤 플레인의 경우
istiod
서비스 및 배포에는 일반적으로istio.io/rev=
과 유사한 버전 라벨이 있습니다. 여기서은 Cloud Service Mesh 버전을 식별합니다. 버전은
istiod
서비스 이름의 일부가 됩니다(예:istiod-.istio-system
).다음 명령어를 사용하여 클러스터 컨트롤 플레인에 대해
istiod
에서 버전 라벨을 찾습니다.kubectl get deploy -n istio-system -l app=istiod \ -o=jsonpath='{.items[*].metadata.labels.istio\.io\/rev}''{"\n"}'
선택사항: 게이트웨이 구성이 자동으로 삽입되도록 네임스페이스에 라벨을 지정합니다. 네임스페이스 또는 배포에 라벨을 지정하는 것으로 충분합니다. 이 튜토리얼에서는
istioctl analyze
도구 경고가 표시되지 않도록 두 항목 모두에 라벨을 지정합니다.kubectl label namespace istio-egress istio.io/rev=REVISION
이그레스 게이트웨이에 대해 연산자 매니페스트를 만듭니다.
cat << EOF > egressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: egressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: REVISION components: egressGateways: - name: istio-egressgateway namespace: istio-egress enabled: true values: gateways: istio-egressgateway: injectionTemplate: gateway tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
istioctl
도구를 다운로드합니다. Cloud Service Mesh 버전 1.15 이하를 사용하는 경우에도 1.16.2-asm.2 이상 버전을 사용해야 합니다. 올바른 istioctl 버전 다운로드를 참조하세요.다운로드한 보관 파일 추출한 후
istioctl
도구의 경로를 보존할 환경 변수를 설정하고 초기화 스크립트에 추가합니다.ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
연산자 매니페스트 및
istioctl
을 사용하여 이그레스 게이트웨이 설치 매니페스트를 만듭니다.${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
이그레스 게이트웨이를 설치합니다.
kubectl apply --recursive --filename egressgateway/
이그레스 게이트웨이가
gateway
노드 풀의 노드에서 실행 중인지 확인합니다.kubectl get pods -n istio-egress -o wide
이그레스 게이트웨이 포드에는
gateway
노드 풀의 노드에 대한affinity
및 연결된 게이트웨이 노드에서 실행할 수 있는 톨러레이션(toleration)이 있습니다. 노드 어피니티 및 이그레스 게이트웨이 포드의 톨러레이션(toleration)을 검토합니다.kubectl -n istio-egress get pod -l istio=egressgateway \ -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
출력은 다음과 비슷합니다.
name node-affinity tolerations istio-egressgateway-754d9684d5-jjkdz [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]] map[key:dedicated operator:Equal value:gateway]
Envoy 액세스 로깅 사용 설정
Envoy 액세스 로그를 사용 설정하는 데 필요한 단계는 관리형 또는 클러스터 내 Cloud Service Mesh 유형에 따라 다릅니다.
관리됨
안내를 따라 관리형 Cloud Service Mesh에서 액세스 로그를 사용 설정합니다.
클러스터 내
안내에 따라 클러스터 내 Cloud Service Mesh에서 액세스 로그를 사용 설정합니다.
메시 및 테스트 애플리케이션 준비
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
Cloud Service Mesh가 프록시 사이드카를 자동으로 삽입하도록 워크로드 네임스페이스에 컨트롤 플레인 버전 라벨을 설정합니다.
kubectl label ns team-x istio.io/rev=REVISION kubectl label ns team-y istio.io/rev=REVISION
테스트 배포에 사용할 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
리소스를 적용하는 것이 좋습니다.
사이드카에서 Cloud 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
목록에 이그레스 게이트웨이용의 일부 클러스터를 포함한 약 11개의 Envoy 클러스터가 있습니다.
프록시 구성을 이그레스 및
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
로 설정하면 서비스 항목을 정의함으로써 메시의 서비스 레지스트리에 명시적으로 추가된 외부 호스트만 포함하도록 프록시 구성이 제한됩니다.egress.hosts
을 설정하면 사이드카 프록시가exportTo
속성을 사용하여 사용할 수 있는 이그레스 네임스페이스에서만 경로를 선택하도록 지정합니다. '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
이그레스 게이트웨이용 클러스터와 테스트 포드 자체에 대한 클러스터 한 개가 표시됩니다.
이그레스 게이트웨이를 통해 트래픽을 라우팅하도록 Cloud Service Mesh 구성
포트 80에서 HTTP 트래픽의
Gateway
를 구성합니다.Gateway
가 이그레스 네임스페이스에 배포한 이그레스 게이트웨이 프록시를 선택합니다.Gateway
구성이 이그레스 네임스페이스에 적용되고 모든 호스트의 트래픽을 처리합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway 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: tls: mode: ISTIO_MUTUAL EOF
team-x
네임스페이스에ServiceEntry
를 만들어 이그레스 네임스페이스의 메시 서비스 레지스트리에 example.com을 명시적으로 등록합니다.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: example.com 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 --revision REVISION
출력은 다음과 비슷합니다.
✔ 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=egressgateway \ -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 labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: httpbin.org 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 --revision REVISION
다음과 같은 항목이 포함되어 있습니다.
✔ 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: action: ALLOW 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: action: ALLOW 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 또는 상호 TLS에 대한 upgrade
(원본)로 이그레스 게이트웨이를 구성할 수 있습니다. 애플리케이션이 일반 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: portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
게이트웨이의 포트 80에 대한 요청이 대상 호스트로 전송될 때 포트 443에서 TLS로
upgraded
되도록 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=egressgateway \ -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: egressgateway 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: 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: action: ALLOW rules: - when: - key: destination.port values: ["8443"] EOF
istioctl analyze
를 실행하여 구성 오류를 확인하세요.${ISTIOCTL} analyze -n istio-egress --revision REVISION
다음과 같은 항목이 포함되어 있습니다.
✔ 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=egressgateway \ -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: "kubernetes.io/metadata.name": istio-system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-egress podSelector: matchLabels: istio: egressgateway 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: "kubernetes.io/metadata.name": kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
워크로드 및 프록시가 Cloud Service Mesh 인증 기관을 포함한 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 # Prior to 1.21.0-gke.1000 - ipBlock: cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later ports: - protocol: TCP port: 987 - 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: "kubernetes.io/metadata.name": 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에 직접 도달할 수 있습니다. GKE용 워크로드 아이덴티티 제휴 및 IAM을 사용하여 특정 Kubernetes 서비스 계정 및 네임스페이스에서 사용할 수 있는 API를 제어할 수 있습니다. 이그레스 게이트웨이가 Google API에 대한 연결을 처리하지 않기 때문에 Istio 승인이 적용되지 않습니다.
포드가 Google API를 호출할 수 있도록 하려면 먼저 IAM을 사용하여 권한을 부여해야 합니다. 이 튜토리얼에서 사용하는 클러스터는 GKE용 워크로드 아이덴티티 제휴를 사용하도록 구성되었으므로 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}.
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}. 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 labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: metadata.google.internal 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 labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: googleapis.com 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 gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
서비스 계정에 버킷의 파일을 나열하고 볼 수 있는 권한을 부여하세요.
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \ --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}. \ --role=roles/storage.objectViewer
테스트 애플리케이션이 테스트 버킷에 액세스할 수 있는지 확인합니다.
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gcloud storage 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 강화 튜토리얼 참조하기
- CA 서비스를 사용하여 Cloud Service Mesh 인그레스 게이트웨이에 대한 TLS 인증서 관리를 자동화하는 방법 알아보기
- GKE Enterprise 구성 관리를 사용하여 모든 인프라에서 구성 및 정책을 관리하는 방법 알아보기
- 그 밖의 참조 아키텍처, 다이어그램, 튜토리얼, 권장사항을 알아보려면 Cloud 아키텍처 센터 살펴보기