במדריך הזה נסביר איך להשתמש בשערי יציאה (egress) של Cloud Service Mesh ובאמצעי בקרה Google Cloud נוספים כדי לאבטח תעבורת נתונים יוצאת (egress) מעומסי עבודה שנפרסו באשכול Google Kubernetes Engine. המדריך הזה נועד לשמש כתוספת לשיטות המומלצות לשימוש בשערי יציאה (egress) של Cloud Service Mesh באשכולות GKE.
קהל היעד של המדריך הזה כולל מהנדסי רשת, פלטפורמה ואבטחה שמנהלים אשכולות של Google Kubernetes Engine שמשמשים צוות אחד או יותר של הכנת תוכנה להפצה. אמצעי הבקרה שמתוארים כאן שימושיים במיוחד לארגונים שצריכים להוכיח עמידה בדרישות של תקנות – למשל, GDPR ו-PCI.
מטרות
- מגדירים את התשתית להרצת Cloud Service Mesh:
- רשת VPC מותאמת אישית ותת-רשת פרטית
- Cloud NAT לגישה לאינטרנט
- אשכול GKE פרטי עם מאגר צמתים נוסף ל-pods של שער יציאה
- כללי חומת אש ב-VPC מגבילים את התעבורה היוצאת. רק צמתי שער יכולים להגיע למארחים חיצוניים
- גישה פרטית ל-Google לחיבור אל Container Registry וממשקי Google API
- מתקינים את Cloud Service Mesh.
- מתקינים שרתי proxy של שערים לתעבורת נתונים יוצאת (egress) שפועלים במאגר צמתים ייעודי.
- הגדרת כללי ניתוב מרובי דיירים לתעבורה חיצונית דרך שער היציאה:
- אפליקציות במרחב השמות
team-xיכולות להתחבר אלexample.com - אפליקציות במרחב השמות
team-yיכולות להתחבר אלhttpbin.org
- אפליקציות במרחב השמות
- משתמשים במשאב
Sidecarכדי להגביל את היקף ההגדרה של תעבורת נתונים יוצאת (egress) של פרוקסי ה-sidecar לכל מרחב שמות. - הגדרת מדיניות הרשאות כדי לאכוף כללי יציאה.
- מגדירים את שער היציאה לשדרוג בקשות HTTP רגילות ל-TLS (התחלת TLS).
- מגדירים את שער היציאה כך שיעביר תעבורת TLS.
- הגדרת כללי מדיניות של רשת Kubernetes כאמצעי בקרה נוסף על תעבורת נתונים יוצאת (egress).
- הגדרת גישה ישירה ל-Google APIs באמצעות גישה פרטית ל-Google והרשאות לניהול זהויות והרשאות גישה (IAM).
עלויות
במסמך הזה משתמשים ברכיבים הבאים של 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.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify 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כדי לאתחל את הסביבה. אם מוצגת בקשה להפעיל אתY, בוחרים באפשרותY:compute.googleapis.comchmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.shיוצרים רשת VPC חדשה:
gcloud compute networks create vpc-network \ --subnet-mode customיוצרים רשת משנה להרצת האשכול עם טווחי כתובות IP משניות שהוקצו מראש לקבוצות Pod ולשירותים. הגישה הפרטית ל-Google מופעלת כדי שאפליקציות עם כתובות IP פנימיות בלבד יוכלו להגיע לשירותים ולממשקי ה-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 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יוצרים חשבון שירות לשימוש על ידי הצמתים במאגר הצמתים שמוגדר כברירת מחדל:
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"יוצרים כלל ברירת מחדל (עדיפות נמוכה) של חומת אש שחוסם את כל התעבורה היוצאת מרשת ה-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 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."Cloud Service Mesh משתמש ב-webhook כשמזריקים שרתי proxy מסוג sidecar לעומסי עבודה. מאפשרים לשרת GKE API לקרוא ל-webhooks שנחשפים על ידי מישור הבקרה של Service mesh שפועל בצמתים:
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}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --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"מאפשרים קישוריות יוצאת בין הצמתים לבין ה-Pods שפועלים באשכול. מערכת GKE יוצרת באופן אוטומטי כלל תואם של תעבורת נתונים נכנסת (ingress). לא נדרש כלל לקישוריות של שירותים, כי שרשרת הניתוב של iptables תמיד ממירה כתובות IP של שירותים לכתובות IP של Pod.
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --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"מאפשרים גישה לקבוצות השמורות של כתובות ה-IP שמשמשות את הגישה הפרטית ל-Google להצגת ממשקי Google API, Container Registry ושירותים אחרים:
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --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}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --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"כדי להוסיף את כתובת ה-IP החיצונית של Cloud Shell לרשימת הרשתות שמורשות לגשת לשרת ה-API של האשכול:
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)אחרי תקופה של חוסר פעילות, כתובת ה-IP החיצונית של המכונה הווירטואלית של Cloud Shell עשויה להשתנות. במקרה כזה, צריך לעדכן את רשימת הרשתות המורשות של האשכול. מוסיפים את הפקודה הבאה לסקריפט ההפעלה:
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}.iam.gserviceaccount.com" \ --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 פנימיות. לפודים ולשירותים מוקצות כתובות IP מתוך טווחי המשנה שמוגדרים בשם שהגדרתם כשייצרתם את רשת המשנה של ה-VPC.
כדי להשתמש ב-Cloud Service Mesh עם מישור בקרה בתוך האשכול, צריך להשתמש בצמתי האשכול בסוג מכונה עם לפחות 4 ליבות וירטואליות (vCPU).
Google ממליצה להירשם לערוץ ההפצה 'רגיל' כדי לוודא שהצמתים מריצים גרסת Kubernetes שנתמכת על ידי Cloud Service Mesh.
מידע נוסף על הדרישות המוקדמות להפעלת Cloud Service Mesh עם מישור בקרה בתוך האשכול זמין במאמר בנושא דרישות מוקדמות בתוך האשכול.
איחוד זהויות של עומסי עבודה ל-GKE מופעל באשכול. Cloud Service Mesh דורש איחוד זהויות של עומסי עבודה ל-GKE, וזו הדרך המומלצת לגשת ל-Google APIs מעומסי עבודה של GKE.
יוצרים מאגר צמתים בשם gateway. מאגר הצמתים הזה הוא המקום שבו שער היציאה (egress) נפרס. ה
dedicated=gateway:NoScheduletaint מתווסף לכל צומת במאגר הצמתים של השער.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"taints and tolerations ב-Kubernetes עוזרים לוודא שרק קבוצות 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]יוצרים מרחב שמות של Kubernetes לשער היציאה:
kubectl create namespace istio-egressכשפורסים את שער היציאה, ההגדרה מוזרקת באופן אוטומטי על סמך תווית שמחילים על הפריסה או על מרחב השמות. אם תג ברירת המחדל מוגדר, צריך להוסיף למרחב השמות את התווית default injection labels. אחרת, צריך להשתמש בrevision label למישור הבקרה שהתקנתם.
במישורי בקרה בתוך האשכול, בדרך כלל לשירות
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. צריך להשתמש בגרסה 1.16.2-asm.2 ואילך, גם אם אתם משתמשים ב-Cloud Service Mesh מגרסה 1.15 ומטה. הורדת הגרסה הנכונה של 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/בודקים ששער היציאה פועל בצמתים ב-node pool
gateway:kubectl get pods -n istio-egress -o wideל-pods של שער היציאה יש
affinityלצמתים במאגר הצמתיםgatewayוטולרנטיות שמאפשרת להם לפעול בצמתים של השער עם ההגדרה tainted. בודקים את ההעדפה של הצמתים ואת הטולרנטיות של ה-Pods של שער היציאה: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]מוודאים שפרוטוקול TLS הדדי מחמיר מופעל. החלת מדיניות ברירת מחדל
PeerAuthenticationעבור הרשת במרחב השמותistio-system:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOFאפשר לשנות את ההגדרה הזו על ידי יצירת משאבי
PeerAuthenticationבמרחבי שמות ספציפיים.יוצרים מרחבי שמות לשימוש בפריסת עומסי עבודה לבדיקה. בשלבים הבאים במדריך הזה מוסבר איך להגדיר כללי ניתוב שונים של תעבורת נתונים יוצאת (egress) לכל מרחב שמות.
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 יזריק באופן אוטומטי sidecars של proxy, צריך להגדיר את התווית של עדכון מישור הבקרה במרחבי השמות של עומס העבודה:
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מוודאים שאפליקציית הבדיקה נפרסה לצומת במאגר ברירת המחדל ושקונטיינר proxy sidecar מוזרק. חוזרים על הפקודה הבאה עד שהסטטוס של ה-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-wbzj2 מתוך 2 מאגרים בסטטוס
Running. קונטיינר אחד הוא אפליקציית הבדיקה והשני הוא proxy sidecar.ה-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נוצרת הודעת שגיאה משרת ה-Proxy של קובץ העזר החיצוני כי כלל חומת האש
global-deny-egress-allדוחה את החיבור במעלה הזרם.מריצים את הפקודה
istioctl proxy-configכדי לבדוק את האשכולות היוצאים שהוגדרו ב-Envoy קובץ עזר חיצוני עבור ה-Pod של הבדיקה:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outboundברשימה יש בערך 11 אשכולות של Envoy, כולל כמה לשער היציאה.
הגבלת הגדרת ה-proxy לנתיבי יציאה שהוגדרו באופן מפורש באמצעות service entries במרחבי השמות של היציאה ושל
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מגבילה את הגדרת ה-proxy כך שתכלול רק את המארחים החיצוניים שנוספו באופן מפורש למרשם השירותים של הרשת על ידי הגדרת רשומות שירות.ההגדרה
egress.hostsמציינת ששרת ה-proxy מסוג קובץ עזר חיצוני בוחר רק מסלולים ממרחב השמות של תעבורת נתונים יוצאת שזמינים באמצעות המאפיין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אפשר לראות אשכולות עבור שער היציאה ואשכול אחד עבור ה-pod של הבדיקה עצמו.
מגדירים
Gatewayלתנועת HTTP ביציאה 80. Gatewayבוחר את שרת ה-proxy של שער היציאה שפרסתם במרחב השמות של היציאה. ההגדרה שלGatewayחלה על מרחב השמות של תעבורת הנתונים היוצאת (egress) ומטפלת בתעבורה של כל מארח.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יוצרים
DestinationRuleלשער היציאה עם TLS הדדי (mTLS) לאימות ולהצפנה. משתמשים בכלל יעד משותף אחד לכל המארחים החיצוניים.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יוצרים
ServiceEntryבמרחב השמות של תעבורת נתונים יוצאת (egress) כדי לרשום באופן מפורש את example.com במרשם השירותים של הרשת עבור מרחב השמותteam-x: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יוצרים
VirtualServiceכדי להפנות תנועה אל example.com דרך שער היציאה. יש שני תנאי התאמה: התנאי הראשון מפנה את התנועה לשער היציאה, והתנאי השני מפנה את התנועה משער היציאה למארח היעד. המאפיין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מוצגים קודי הסטטוס
200לכל ארבע התגובות.כדי לוודא שהבקשות הופנו דרך שער היציאה, בודקים את יומני הגישה של ה-proxy. קודם כל, בודקים את יומן הגישה של ה-proxy sidecar שנפרס עם אפליקציית הבדיקה:
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 -יוצרים משאב
Sidecarלמרחב השמותteam-y: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.שליחת בקשה אל httpbin.org מאפליקציית הבדיקה
team-y: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תשובה.בנוסף, שולחים בקשה אל httpbin.org מאפליקציית הבדיקה
team-x: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תשובה.ניסיון לשלוח בקשה אל example.com ממרחב השמות
team-y: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.יוצרים
AuthorizationPolicyכדי שאפליקציות במרחב השמותteam-xיוכלו להתחבר ל-example.com אבל לא למארחים חיצוניים אחרים כשהן שולחות בקשות באמצעות יציאה 80. היציאה התואמת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מוודאים שאפשר לשלוח בקשה אל example.com מאפליקציית הבדיקה במרחב השמות
team-x: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תשובה.מנסים לשלוח בקשה אל httpbin.org מאפליקציית הבדיקה במרחב השמות
team-x: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לשלוח בקשות אל httpbin.org באמצעות נתיב כתובת ה-URL מסוים כששולחים בקשות באמצעות יציאה 80, צריך להחיל את מדיניות ההרשאות הבאה. היציאה התואמתtargetPortבתרמילי שער תעבורת נתונים יוצאת (egress) היא 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מנסים להתחבר אל httpbin.org מאפליקציית הבדיקה במרחב השמות
team-y: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: access denied וקוד הסטטוס 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 ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`Create a
DestinationRule. The DestinationRuleמציין ששער יתחיל חיבור TLS אל example.com.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מעדכנים את השירות הווירטואלי עבור example.com כך שהבקשות ליציאה 80 בשער יהיו
upgradedל-TLS ביציאה 443 כשהן נשלחות למארח היעד: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שליחת כמה בקשות אל example.com מאפליקציית הבדיקה במרחב השמות
team-x: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 -ה-sidecar של ה-proxy שלח את הבקשה לשער באמצעות יציאה 80, והתחלת TLS נוצרה ביציאה 443 כדי לשלוח את הבקשה למארח היעד.
משנים את ההגדרה כך שהשער ליציאה יתבסס על TLS pass-through לחיבורים ליציאה 443:
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מעדכנים את השירות הווירטואלי עבור example.com כך שתנועת TLS ביציאה 443 תעבור דרך השער:
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מעדכנים את השירות הווירטואלי עבור httpbin.org כך שתנועת TLS ביציאה 443 תעבור דרך השער:
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 של שירות שער היציאה. היציאה התואמת
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.שליחת בקשת HTTP פשוטה אל example.com מאפליקציית הבדיקה במרחב השמות
team-x: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.עכשיו שולחים כמה בקשות TLS (HTTPS) מאפליקציית הבדיקה במרחב השמות
team-x: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 ביומן.
לאפשר לעומסי עבודה ולשרתי proxy שנפרסו במרחב השמות
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מתן הרשאה לעומסי עבודה ולשרתי proxy לשאילתות 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מתן אפשרות לעומסי עבודה ולשרתי proxy להתחבר לכתובות ה-IP שמשרתות את ממשקי ה-API והשירותים של Google, כולל רשות האישורים של Cloud Service Mesh:
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מתן אפשרות לעומסי עבודה ולשרתי proxy להתחבר לשרת המטא-נתונים של 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אופציונלי: מאפשרים לעומסי עבודה ולשרתי proxy במרחב השמות
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אופציונלי: מאפשרים לעומסי עבודה ולשרתי proxy במרחב השמות
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החיבורים בין שרתי proxy מסוג sidecar נשמרים. חיבורים קיימים לא נסגרים כשמחילים מדיניות רשת חדשה. מפעילים מחדש את עומסי העבודה במרחב השמות team-x כדי לוודא שהחיבורים הקיימים נסגרו:
kubectl -n team-x rollout restart deploymentמוודאים שאפשר עדיין לשלוח בקשת HTTP אל example.com מאפליקציית הבדיקה במרחב השמות
team-x: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 לשימוש באפליקציה:
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מוסיפים הערה לחשבון השירות של Kubernetes עבור אפליקציית הבדיקה במרחב השמות
team-xעם כתובת האימייל של חשבון השירות של 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לפוד של אפליקציית הבדיקה צריכה להיות גישה לשרת המטא-נתונים של Google (שפועל כ-DaemonSet) כדי לקבל פרטי כניסה זמניים להתקשרות עם Google APIs. יוצרים רשומה של שירות לשרת המטא-נתונים של 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 מופיע כזהות הפעילה והיחידה.
יוצרים קובץ בדיקה בקטגוריה של 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}.iam.gserviceaccount.com \ --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!- 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 Service כדי להגדיר אוטומציה של ניהול אישורי TLS בשער הכניסה של Cloud Service Mesh
- ניהול ההגדרות והמדיניות בכל התשתית באמצעות GKE Enterprise Configuration Management
- לדוגמאות נוספות של ארכיטקטורות, תרשימים ושיטות מומלצות, עיינו במאמר Cloud Architecture Center.
הגדרת התשתית
יצירת רשת VPC ורשת משנה
הגדרת Cloud NAT
Cloud NAT מאפשר לעומסי עבודה ללא כתובות IP חיצוניות להתחבר ליעדים באינטרנט ולקבל תשובות נכנסות מהיעדים האלה.
יצירת חשבונות שירות לכל מאגר צמתים של GKE
יוצרים שני חשבונות שירות לשימוש בשתי קבוצות הצמתים של GKE. לכל מאגר צמתים מוקצה חשבון שירות נפרד, כדי שתוכלו להחיל כללי חומת אש של VPC על צמתים ספציפיים.
מתן הרשאות לחשבונות השירות
מוסיפים קבוצה מינימלית של תפקידי 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, נדרשת קישוריות ספציפית. קבוצה מינימלית של כללי חומת אש ספציפיים מבטלת את כלל ברירת המחדל של דחיית הכול כדי לאפשר את הקישוריות הנדרשת.
הגדרת גישה פרטית ל- Google Cloud API
הגישה הפרטית ל-Google מאפשרת למכונות וירטואליות ול-Pods שיש להם רק כתובות IP פנימיות לגשת לשירותים ול-Google APIs. למרות שממשקי ה-API והשירותים של Google מוגשים מכתובות IP חיצוניות, התעבורה מהצמתים אף פעם לא יוצאת מהרשת של Google כשמשתמשים בגישה פרטית ל-Google.
מפעילים את Cloud DNS API:
gcloud services enable dns.googleapis.com
יוצרים אזור DNS פרטי, רשומות CNAME ו-A כדי שהצמתים ועומסי העבודה יוכלו להתחבר לשירותים ול-Google APIs באמצעות גישה פרטית ל-Google ושם המארח private.googleapis.com:
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
יוצרים שרת DNS פרטי, רשומת CNAME ורשומת A כדי שהצמתים יוכלו להתחבר ל-Container Registry באמצעות גישה פרטית ל-Google ושם המארח gcr.io:
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
התקנה והגדרה של Cloud Service Mesh
פועלים לפי הדרישות המוקדמות ומדריך ההתקנה של Cloud Service Mesh בתוך האשכול.
אחרי שמתקינים את Cloud Service Mesh, עוצרים וחוזרים אל המדריך הזה בלי להתקין שערים של תעבורת נכנסת או יוצאת.
התקנה של שער לתעבורת נתונים יוצאת
הפעלת רישום ביומן של גישת Envoy
פועלים לפי ההוראות כדי להפעיל יומני גישה ב-Cloud Service Mesh בתוך האשכול.
הכנת הרשת ואפליקציית בדיקה
שימוש במשאב Sidecar כדי להגביל את ההיקף של הגדרת שרת proxy מסוג Sidecar
אתם יכולים להשתמש במשאב Sidecar כדי להגביל את היקף המאזין ליציאה שמוגדר ל-Sidecar proxies. כדי לצמצם את נפח ההגדרות ואת השימוש בזיכרון, מומלץ להחיל משאב Sidecar ברירת מחדל על כל מרחב שמות.
שרת ה-proxy שמופעל ב-Cloud Service Mesh ב-sidecar הוא Envoy. בטרמינולוגיה של Envoy, cluster היא קבוצה דומה מבחינה לוגית של נקודות קצה במעלה הזרם שמשמשות כיעדים לאיזון עומסים.
הגדרת Cloud Service Mesh לניתוב תעבורה דרך שער היציאה
הגדרת ניתוב שונה למרחב שמות שני
כדי ללמוד איך אפשר להגדיר קישוריות חיצונית שונה לצוותים שונים, אפשר להגדיר ניתוב למארח חיצוני שני.
שימוש במדיניות הרשאות כדי לספק שליטה נוספת בתנועה
במדריך הזה, מדיניות ההרשאות לשער היציאה נוצרת במרחב השמות istio-egress. אפשר להגדיר RBAC ב-Kubernetes כך שרק לאדמינים של הרשת תהיה גישה למרחב השמות istio-egress.
התחלת TLS בשער היציאה
אפשר להגדיר שערים ליציאת נתונים כדי upgrade (ליצור) בקשות HTTP רגילות ל-TLS או ל-TLS הדדי. יש כמה יתרונות לשימוש באפליקציות המבצעות בקשות HTTP רגילות, בשילוב עם Mutual TLS (mTLS) ועם התחלת TLS ב-Istio. מידע נוסף זמין במדריך לשיטות מומלצות.
העברה של חיבורי HTTPS/TLS
יכול להיות שהאפליקציות הקיימות שלכם כבר משתמשות בחיבורי TLS כשהן מתקשרות עם שירותים חיצוניים. אפשר להגדיר את שער היציאה כך שיעביר חיבורי TLS בלי לפענח אותם.
שימוש ב-Kubernetes NetworkPolicy כבקרה נוספת
יש הרבה תרחישים שבהם אפליקציה יכולה לעקוף קובץ עזר חיצוני.
אתם יכולים להשתמש ב-Kubernetes NetworkPolicy כדי לציין בנוסף אילו חיבורים עומסי העבודה יכולים לבצע. אחרי שמחילים מדיניות רשת אחת, כל החיבורים שלא אושרו באופן ספציפי נדחים.
ההדרכה הזו מתייחסת רק לחיבורים יוצאים ולבוררים של תעבורת נתונים יוצאת (egress) במדיניות רשת. אם אתם שולטים בתעבורה הנכנסת באמצעות מדיניות רשת באשכולות שלכם, אתם צריכים ליצור מדיניות תעבורה נכנסת שתתאים למדיניות התעבורה היוצאת. לדוגמה, אם מאפשרים תעבורת נתונים יוצאת (egress) מעומסי עבודה במרחב השמות team-x אל מרחב השמות team-y, צריך גם לאפשר תעבורת נתונים נכנסת (ingress) למרחב השמות team-y ממרחב השמות team-x.
גישה ישירה ל-Google API באמצעות גישה פרטית ל-Google והרשאות IAM
ממשקי ה-API והשירותים של Google נחשפים באמצעות כתובות IP חיצוניות. כשפודים עם כתובות IP של כינוי מקורי ב-VPC יוצרים חיבורים לממשקי Google API באמצעות גישה פרטית ל-Google, התנועה אף פעם לא יוצאת מהרשת של Google.
כשמגדירים את התשתית במדריך הזה, מפעילים את הגישה הפרטית ל-Google עבור רשת המשנה שמשמשת את ה-Pods של GKE. כדי לאפשר גישה לכתובות ה-IP שמשמשות את הגישה הפרטית ל-Google, יצרתם נתיב, כלל חומת אש ב-VPC ותחום DNS פרטי. ההגדרה הזו מאפשרת ל-pods להגיע ישירות לממשקי ה-API של Google בלי לשלוח תנועה דרך שער היציאה. אתם יכולים לשלוט בממשקי ה-API שזמינים לחשבונות שירות ספציפיים של Kubernetes (ומכאן גם למרחבי שמות) באמצעות איחוד שירותי אימות הזהות של עומסי עבודה ב-GKE ו-IAM. הרשאות ב-Istio לא נכנסות לתוקף כי שער היציאה לא מטפל בחיבורים ל-Google APIs.
כדי ש-pods יוכלו להתקשר לממשקי Google API, צריך להשתמש ב-IAM כדי להעניק הרשאות. האשכול שבו משתמשים במדריך הזה מוגדר לשימוש באיחוד שירותי אימות הזהות של עומסי עבודה ב-GKE, שמאפשר לחשבון שירות של Kubernetes לפעול כחשבון שירות של Google.
הסרת המשאבים
כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם במדריך הזה, אתם יכולים למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.
כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, צריך לפעול לפי השלבים שמתוארים בקטעים הבאים:
מחיקת הפרויקט
הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל המדריך.