במדריך הזה נסביר איך להשתמש בשערי תעבורת נתונים יוצאת (egress) של Cloud Service Mesh ובאמצעי בקרה אחרים של Google Cloud כדי לאבטח תעבורת נתונים יוצאת מעומסי עבודה שנפרסו באשכול Google Kubernetes Engine. המדריך הזה מיועד כתוספת לשיטות מומלצות לשימוש בשערי יציאה (egress) של Cloud Service Mesh באשכולות GKE.
המדריך הזה מיועד למהנדסי רשת, פלטפורמה ואבטחה שמנהלים אשכולות של Google Kubernetes Engine שמשמשים צוות אחד או יותר להכנת תוכנה להפצה. אמצעי הבקרה שמתוארים כאן שימושיים במיוחד לארגונים שצריכים להוכיח שהם עומדים בדרישות של תקנות מסוימות, למשל GDPR ו-PCI.
מטרות
- הגדרת התשתית להרצת Cloud Service Mesh:
- רשת VPC מותאמת אישית ורשת משנה פרטית
- Cloud NAT לגישה לאינטרנט
- אשכול GKE פרטי עם מאגר צמתים נוסף לפודים של שער תעבורה יוצאת
- כללי חומת אש מגבילים של VPC לתעבורת נתונים יוצאת; רק צומתי שער יכולים להגיע למארחים חיצוניים
- גישה פרטית ל-Google כדי להתחבר ל-Container Registry ול-Google APIs
- מתקינים את Cloud Service Mesh.
- מתקינים שרתי proxy של שערים לתעבורת נתונים יוצאת (egress) שפועלים במאגר צמתים ייעודי.
- מגדירים כללי ניתוב לכמה דיירים לתעבורת נתונים חיצונית דרך שער תעבורת הנתונים היוצאת:
- אפליקציות במרחב השמות
team-xיכולות להתחבר אלexample.com - אפליקציות במרחב השמות
team-yיכולות להתחבר אלhttpbin.org
- אפליקציות במרחב השמות
- משתמשים במשאב
Sidecarכדי להגביל את היקף ההגדרות של יציאת ה-sidecar proxy לכל מרחב שמות. - הגדרת מדיניות הרשאות כדי לאכוף כללי יציאה.
- מגדירים את שער היציאה כך שישדרג בקשות HTTP רגילות ל-TLS (התחלת TLS).
- הגדרת שער היציאה כך שיעביר תעבורת TLS.
- הגדרת כללי מדיניות רשת ב-Kubernetes כאמצעי בקרה נוסף על תעבורת נתונים יוצאת.
- הגדרת גישה ישירה ל-Google APIs באמצעות Private Google Access והרשאות לניהול זהויות והרשאות גישה (IAM).
עלויות
במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
כדי ליצור הערכת עלויות בהתאם לשימוש החזוי, אתם יכולים להשתמש במחשבון התמחור.
כדי להימנע מעלויות נוספות אחרי שסיימתם את המדריך, אתם יכולים למחוק את המשאבים שיצרתם. מידע נוסף זמין בקטע ניקוי.
לפני שמתחילים
-
בדף לבחירת הפרויקט במסוף Google Cloud , בוחרים פרויקט ב- Google Cloud או יוצרים אותו.
התפקידים שנדרשים כדי לבחור או ליצור פרויקט
- בחירת פרויקט: כדי לבחור פרויקט לא נדרש תפקיד IAM ספציפי – אתם יכולים לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד "יצירת פרויקטים" (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים?
-
מפעילים את Cloud Shell במסוף Google Cloud .
יוצרים ספריית עבודה לשימוש במהלך המדריך:
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יוצרים רשת משנה שבה האשכול יפעל, עם טווחי כתובות IP משניים שהוקצו מראש ל-Pods ולשירותים. הגישה הפרטית ל-Google מופעלת, כך שאפליקציות עם כתובות IP פנימיות בלבד יכולות להגיע ל-Google APIs ולשירותים של 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
יוצרים שני חשבונות שירות לשימוש בשני מאגרי הצמתים של 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, נדרשת קישוריות ספציפית. קבוצה מינימלית של כללי חומת אש ספציפיים מבטלת את כלל ברירת המחדל "דחיית הכול" כדי לאפשר את הקישוריות הנדרשת.
יוצרים כלל חומת אש שמוגדר כברירת מחדל (בעדיפות נמוכה) כדי לדחות את כל תעבורת הנתונים היוצאת מרשת ה-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."אופציונלי: לא צריך להשתמש בכלל חומת האש הזה אם משתמשים ב-Managed Cloud Service Mesh.
Cloud Service Mesh משתמש ב-webhooks כשהוא מוסיף שרתי proxy מסוג sidecar לעומסי עבודה. מאפשרים לשרת ה-API של GKE לשלוח קריאות ל-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). לא נדרש כלל לקישוריות של Service כי שרשרת הניתוב של iptables תמיד ממירה כתובות IP של Service לכתובות 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 health checker לגשת ל-pods שפועלים באשכול. מידע נוסף זמין במאמר בדיקות תקינות.
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"
הגדרת גישה פרטית לממשקי API של Google Cloud
גישה פרטית ל-Google מאפשרת למכונות וירטואליות ול-Pods שיש להם רק כתובות IP פנימיות לגשת ל-Google APIs ולשירותים של Google. למרות שממשקי ה-API והשירותים של Google מוגשים מכתובות IP חיצוניות, התעבורה מהצמתים אף פעם לא יוצאת מהרשת של Google כשמשתמשים בגישה פרטית ל-Google.
מפעילים את Cloud DNS API:
gcloud services enable dns.googleapis.com
יוצרים תחום DNS פרטי, רשומת CNAME ורשומות A כדי שצמתים ועומסי עבודה יוכלו להתחבר לממשקי ה-API ולשירותים של Google באמצעות גישה פרטית ל-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 פרטי
מאתרים את כתובת ה-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 פנימיות. ל-Pods ולשירותים מוקצות כתובות IP מטווחים משניים עם שמות שהגדרתם כשנוצרת רשת המשנה של ה-VPC.
כדי להשתמש ב-Cloud Service Mesh עם מישור בקרה בתוך האשכול, צריך להשתמש בצומתי אשכול עם סוג מכונה שיש לה לפחות 4 מעבדי vCPU.
Google ממליצה לרשום את האשכול לערוץ ההפצה "רגיל" כדי לוודא שהצמתים מריצים גרסת Kubernetes שנתמכת על ידי Cloud Service Mesh.
למידע נוסף על הדרישות המוקדמות להרצת Cloud Service Mesh עם מישור בקרה בתוך האשכול, קראו את הדרישות המוקדמות בתוך האשכול.
מידע נוסף על הדרישות והמגבלות להפעלת Cloud Service Mesh מנוהל זמין במאמר תכונות נתמכות של Cloud Service Mesh מנוהל.
איחוד זהויות של עומסי עבודה ל-GKE מופעל באשכול. Cloud Service Mesh דורש איחוד זהויות של עומסי עבודה ל-GKE, וזו הדרך המומלצת לגשת ל-Google APIs מעומסי עבודה ב-GKE.
יוצרים מאגר צמתים בשם gateway. במאגר הצמתים הזה פורסים את שער היציאה. ה
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"הכתמות וסבילות של Kubernetes עוזרות להבטיח שרק Pods של שער תעבורת הנתונים היוצאת יפעלו בצמתים במאגר הצמתים של השער.
מורידים את פרטי הכניסה כדי להתחבר לאשכול באמצעות 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, עוצרים וחוזרים למדריך הזה בלי להתקין שערים של תעבורת נכנסת או יוצאת.
התקנת שער לתעבורת נתונים יוצאת (egress)
יוצרים מרחב שמות של Kubernetes לשער היציאה:
kubectl create namespace istio-egressמפעילים את מרחב השמות להזרקה. השלבים תלויים בהטמעה של מישור הבקרה.
מנוהל (TD)
החלת תווית ברירת המחדל להוספה למרחב השמות:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwriteמנוהל (Istiod)
מומלץ: מריצים את הפקודה הבאה כדי להחיל את תווית ברירת המחדל להחדרה על מרחב השמות:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwriteאם אתם משתמשים קיימים עם מישור הבקרה Managed Istiod: אנחנו ממליצים להשתמש בהחדרה כברירת מחדל, אבל יש תמיכה בהחדרה מבוססת-גרסה. פועלים לפי ההוראות הבאות:
מריצים את הפקודה הבאה כדי לאתר את ערוצי ההפצה הזמינים:
kubectl -n istio-system get controlplanerevisionהפלט אמור להיראות כך:
NAME AGE asm-managed-rapid 6d7hבפלט, הערך בעמודה
NAMEהוא תווית הגרסה שתואמת לערוץ ההפצה הזמין של גרסת Cloud Service Mesh.מחילים את תווית הגרסה על מרחב השמות:
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
בתוך האשכול
מומלץ: מריצים את הפקודה הבאה כדי להחיל את תווית ברירת המחדל להחדרה על מרחב השמות:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwriteמומלץ להשתמש בהחדרה שמוגדרת כברירת מחדל, אבל יש תמיכה גם בהחדרה שמבוססת על תיקון: פועלים לפי ההוראות הבאות:
כדי לאתר את תווית הגרסה ב-
istiod, משתמשים בפקודה הבאה:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'מחילים את תווית הגרסה על מרחב השמות. בפקודה הבאה,
REVISION_LABELהוא הערך של תווית הגרסהistiodשציינתם בשלב הקודם.kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
יוצרים מניפסט של אופרטור לשער תעבורת הנתונים היוצאת:
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/מוודאים ששער היציאה פועל בצמתים במאגר הצמתים
gateway:kubectl get pods -n istio-egress -o wideלפודים של שער התעבורה היוצאת יש
affinityלצמתים במאגר הצמתיםgateway, וטולרנטיות שמאפשרת להם לפעול בצמתים הנגועים של השער. בודקים את ההעדפה של הצמתים ואת ההרשאות של ה-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]
הפעלת רישום ביומן של הגישה ל-Envoy
השלבים הנדרשים להפעלת יומני הגישה של Envoy תלויים בסוג של Cloud Service Mesh, מנוהל או באשכול:
מנוהל
פועלים לפי ההוראות להפעלת יומני גישה ב-Cloud Service Mesh מנוהל.
באשכול
פועלים לפי ההוראות להפעלת יומני גישה ב-Cloud Service Mesh באשכול.
הכנת רשת האריג ואפליקציית בדיקה
מוודאים שפרוטוקול 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במרחבי שמות ספציפיים.יוצרים מרחבי שמות (namespaces) כדי לפרוס עומסי עבודה לבדיקה. בשלבים הבאים במדריך הזה מוסבר איך להגדיר כללי ניתוב שונים של תעבורה יוצאת לכל מרחב שמות.
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 יוסיף באופן אוטומטי שרתי proxy מסוג sidecar, צריך להגדיר את תווית הגרסה של מישור הבקרה במרחבי השמות של עומסי העבודה:
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwriteיוצרים קובץ 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הודעת שגיאה מקובץ העזר החיצוני נוצרת כי כלל חומת האש
global-deny-egress-allדוחה את החיבור במעלה הזרם.
שימוש במשאב Sidecar כדי להגביל את ההיקף של הגדרת קובץ העזר החיצוני
אתם יכולים להשתמש במשאב Sidecar כדי להגביל את ההיקף של מאזין תעבורת הנתונים היוצאת שמוגדר לקובצי עזר חיצוניים. כדי לצמצם את השימוש בזיכרון ואת העומס על ההגדרות, מומלץ להחיל משאב Sidecar כברירת מחדל לכל מרחב שמות.
שרת ה-proxy שמופעל ב-Cloud Service Mesh ב-sidecar הוא Envoy. בטרמינולוגיה של Envoy, cluster היא קבוצה דומה מבחינה לוגית של נקודות קצה במעלה הזרם שמשמשות כיעדים לאיזון עומסים.
מריצים את הפקודה
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 לנתיבי תעבורת נתונים יוצאת שהוגדרו במפורש באמצעות רשומות שירות במרחבי השמות של תעבורת הנתונים היוצאת ו-
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מציינת שקובץ העזר החיצוני בוחר רק נתיבים ממרחב השמות של תעבורת הנתונים היוצאת, שזמינים באמצעות המאפייןexportTo. החלק "team-x/*" כולל את כל הנתיבים שהוגדרו באופן מקומי במרחב השמותteam-x.מציגים את האשכולות היוצאים שהוגדרו בשרת ה-Proxy של Envoy, ומשווים אותם לרשימת האשכולות שהוגדרו לפני החלת המשאב
Sidecar:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outboundאתם רואים אשכולות עבור שער היציאה ועבור ה-Pod של הבדיקה עצמו.
הגדרת Cloud Service Mesh לניתוב תעבורה דרך שער תעבורת נתונים יוצאת (egress)
מגדירים
Gatewayלתנועת HTTP ביציאה 80. השדהGatewayבוחר את שרת ה-proxy של שער התעבורה היוצאת שפרסתם במרחב השמות של התעבורה היוצאת. ההגדרה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יוצרים
DestinationRuleלשער התעבורה היוצאת עם TLS הדדי לאימות ולהצפנה. משתמשים בכלל יעד משותף אחד לכל המארחים החיצוניים.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במרחב השמות של תעבורת הנתונים היוצאת כדי לרשום באופן מפורש את 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.
שימוש במדיניות הרשאות כדי לספק שליטה נוספת בתנועה
במדריך הזה, מדיניות ההרשאות לשער היציאה נוצרת במרחב השמות istio-egress. אפשר להגדיר RBAC ב-Kubernetes כך שרק למנהלי רשת תהיה גישה למרחב השמות istio-egress.
יוצרים
AuthorizationPolicyכדי שאפליקציות במרחב השמותteam-xיוכלו להתחבר ל-example.com אבל לא למארחים חיצוניים אחרים כשהן שולחות בקשות באמצעות יציאה 80. הערך התואם שלtargetPortב-pods של שער היציאה הוא 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בפודים של שער היציאה הוא 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 ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
התחלת TLS בשער היציאה
אפשר להגדיר שערי תעבורה יוצאת כדי upgrade (ליצור) בקשות HTTP רגילות ל-TLS או ל-TLS הדדי. כשמאפשרים לאפליקציות לשלוח בקשות HTTP רגילות, יש כמה יתרונות כשמשתמשים ב-Istio mutual TLS ובהתחלת TLS. למידע נוסף, עיינו במדריך לשיטות מומלצות.
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 -שרת ה-proxy של ה-sidecar שלח את הבקשה לשער באמצעות יציאה 80, והתחלת ה-TLS בוצעה ביציאה 443 כדי לשלוח את הבקשה למארח היעד.
העברה של חיבורי HTTPS/TLS
יכול להיות שהאפליקציות הקיימות שלכם כבר משתמשות בחיבורי TLS כשהן מתקשרות עם שירותים חיצוניים. אפשר להגדיר את שער היציאה כך שיעביר חיבורי TLS בלי לפענח אותם.
משנים את ההגדרות כך ששער היציאה ישתמש ב-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 בשער. קבוצת המשנה החדשה הזו לא משתמשת ב-Mutual TLS. אין תמיכה ב-Istio mutual TLS להעברה של חיבורי 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במאגרי ה-pods של השער היא 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.
שימוש ב-NetworkPolicy של Kubernetes כאמצעי בקרה נוסף
יש הרבה תרחישים שבהם אפליקציה יכולה לעקוף קובץ עזר חיצוני.
אפשר להשתמש ב-Kubernetes NetworkPolicy כדי לציין בנוסף אילו חיבורים עומסי העבודה יכולים לבצע. אחרי שמחילים מדיניות רשת אחת, כל החיבורים שלא אושרו באופן ספציפי נדחים.
ההדרכה הזו מתייחסת רק לחיבורים יוצאים ולבוררים של תעבורה יוצאת במדיניות רשת ב-Kubernetes. אם אתם שולטים בתעבורת הנתונים הנכנסת באמצעות מדיניות רשת באשכולות שלכם, אתם צריכים ליצור מדיניות לתעבורת נתונים נכנסת שתתאים למדיניות של תעבורת הנתונים היוצאת. לדוגמה, אם מאפשרים תעבורת נתונים יוצאת מעומסי עבודה במרחב השמות team-x למרחב השמות team-y, צריך גם לאפשר תעבורת נתונים נכנסת למרחב השמות team-y ממרחב השמות team-x.
מאפשרים לעומסי עבודה ולשרתי 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החיבורים בין קובצי העזר החיצוניים נשמרים. חיבורים קיימים לא נסגרים כשמחילים מדיניות רשת חדשה. מפעילים מחדש את עומסי העבודה במרחב השמות 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 APIs באמצעות גישה פרטית ל-Google והרשאות IAM
ממשקי ה-API והשירותים של Google חשופים באמצעות כתובות IP חיצוניות. כשפודים עם כתובות IP חלופיות שמותאמות ל-VPC מתחברים ל-Google APIs באמצעות גישה פרטית ל-Google, תנועת הנתונים לא יוצאת מהרשת של Google.
כשהגדרתם את התשתית למדריך הזה, הפעלתם את "גישה פרטית ל-Google" ברשת המשנה שמשמשת את הפודים של GKE. כדי לאפשר גישה לכתובות ה-IP שמשמשות את הגישה הפרטית ל-Google, יצרתם מסלול, כלל של חומת אש ב-VPC ותחום DNS פרטי. ההגדרה הזו מאפשרת לפודים להגיע ישירות לממשקי ה-API של Google בלי לשלוח תנועה דרך שער היציאה. אתם יכולים לשלוט באילו ממשקי API זמינים לחשבונות שירות ספציפיים של Kubernetes (ומכאן גם למרחבי שמות) באמצעות איחוד שירותי אימות הזהות של עומסי עבודה ב-GKE ו-IAM. ההרשאה של Istio לא נכנסת לתוקף כי שער היציאה לא מטפל בחיבורים ל-Google APIs.
כדי ש-pods יוכלו להתקשר לממשקי 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}.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ל-pod של אפליקציית הבדיקה צריכה להיות גישה לשרת המטא-נתונים של 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!
הסרת המשאבים
כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.
כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, צריך לבצע את השלבים שמפורטים בקטעים הבאים:
מחיקת הפרויקט
הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל המדריך.
- במסוף Google Cloud , נכנסים לדף Manage resources.
- ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
- כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.
המאמרים הבאים
- קוראים את מדריך השיטות המומלצות הנלווה.
- מומלץ לעיין במדריך לחיזוק האבטחה של GKE.
- איך משתמשים ב-CA Service כדי לנהל באופן אוטומטי את אישורי ה-TLS של שער הכניסה ב-Cloud Service Mesh
- ניהול ההגדרות והמדיניות בכל התשתית באמצעות GKE Enterprise Configuration Management
- לדוגמאות נוספות של ארכיטקטורות, תרשימים ושיטות מומלצות, עיינו במאמר Cloud Architecture Center.