הגדרת אבטחת שירות באמצעות gRPC ללא proxy
במדריך הזה מוסבר איך להגדיר שירות אבטחה ל-Service mesh של gRPC ללא שרת proxy.
דרישות
לפני שמגדירים אבטחת שירות ל-Service mesh ללא proxy של gRPC, צריך לוודא שמתקיימות הדרישות הבאות.
- הפריסה שלכם עומדת בדרישות שמפורטות במאמר הכנה להגדרה של ממשקי API לניתוב שירותים עם Envoy ועומסי עבודה ללא שרת Proxy.
- חובה להשתמש ב-xDS v3.
- יש לכם גישה לגרסת xDS הנדרשת ולפונקציונליות של ספק האישורים באחת מהשפות הבאות:
- gRPC Java
- gRPC C++
- gRPC Python
- gRPC Go אפשר למצוא את גרסאות השפה הנדרשות ב-github
- יש לכם גישה לכלי ליצירת קוד bootstrap, גרסה 0.16.0. תמונת הגנרטור של ה-bootstrap נמצאת במאגר הקונטיינרים Google Cloud .
- עומדים בכל הדרישות המוקדמות לאיזון עומסים ברשת Service mesh ללא proxy של gRPC.
- יש לכם הרשאות מספיקות ליצור או לעדכן את Cloud Service Mesh ואתGoogle Cloud משאבי רשת השירות כדי להשתמש באבטחת PSM. מידע מלא על ההרשאות הנדרשות זמין במאמר הכנה להגדרת Cloud Service Mesh עם שירותי gRPC ללא proxy.
- יש לכם את ההרשאות הנדרשות לשימוש ב-Certificate Authority Service, שמתוארות במאמר יצירת רשויות אישורים להנפקת אישורים
הגדרת ניהול זהויות והרשאות גישה (IAM)
צריכות להיות לכם ההרשאות הנדרשות לשימוש ב-Google Kubernetes Engine. לפחות אחד מהתפקידים הבאים צריך להיות מוקצה לכם:
- תפקיד ב-
roles/container.clusterAdmin roles/compute.instanceAdminתפקיד ב-Compute Engine- תפקיד
roles/iam.serviceAccountUser
כדי ליצור את המשאבים שנדרשים להגדרה, צריך להיות לכם תפקיד compute.NetworkAdmin. התפקיד הזה מכיל את כל ההרשאות שנדרשות כדי ליצור, לעדכן, למחוק, להציג רשימה ולהשתמש במשאבים הנדרשים (כלומר, להפנות אליהם במשאבים אחרים). אם אתם הבעלים של הפרויקט ויש לכם הרשאת עריכה בו, התפקיד הזה מוקצה לכם באופן אוטומטי.
שימו לב שהמגבלות networksecurity.googleapis.com.clientTlsPolicies.use ו-networksecurity.googleapis.com.serverTlsPolicies.use לא נאכפות כשמפנים למשאבים האלה במשאב של שירות לקצה העורפי.
אם האכיפה הזו תופעל בעתיד ואתם משתמשים בתפקיד compute.NetworkAdmin, לא תיתקלו בבעיות כשהבדיקה הזו תיאכף.
אם אתם משתמשים בתפקידים בהתאמה אישית והבדיקה הזו תיאכף בעתיד, תצטרכו לוודא שאתם כוללים את ההרשאה המתאימה .use. אחרת, בעתיד יכול להיות שתגלו שלתפקיד המותאם אישית שלכם אין את ההרשאות הנדרשות כדי להפנות אל clientTlsPolicy או אל serverTlsPolicy משירות הקצה העורפי.
הכנה להגדרה
אבטחת רשת שירותים ללא proxy (PSM) מוסיפה אבטחה לרשת שירותים שהוגדרה לאיזון עומסים בהתאם למסמכי התיעוד של שירותי gRPC ללא proxy. ב-service mesh בלי שרת Proxy, לקוח gRPC משתמש בסכימה xds: ב-URI כדי לגשת לשירות, וכך מפעיל את התכונות של איזון העומסים וגילוי נקודות הקצה ב-PSM.
עדכון של לקוחות ושרתי gRPC לגרסה הנכונה
בונים מחדש את האפליקציות באמצעות גרסת gRPC המינימלית שנתמכת בשפה.
עדכון קובץ ה-bootstrap
אפליקציות gRPC משתמשות בקובץ אתחול יחיד, שחייבים להיות בו כל השדות שנדרשים על ידי קוד בצד הלקוח ובצד השרת של gRPC. מחולל bootstrap יוצר באופן אוטומטי את קובץ ה-bootstrap כדי לכלול דגלים וערכים שנדרשים לאבטחת PSM. מידע נוסף זמין בקטע בנושא קובץ Bootstrap, שכולל קובץ Bootstrap לדוגמה.
סקירה כללית של ההגדרה
תהליך ההגדרה הזה הוא הרחבה של הגדרת Cloud Service Mesh עם שירותי GKE ו-gRPC ללא proxy. השלבים הקיימים שלא שונו בתהליך ההגדרה מצוינים במקומות שבהם הם רלוונטיים.
השיפורים העיקריים בהגדרת Cloud Service Mesh עם GKE הם:
- הגדרת שירות CA, שבו יוצרים מאגרי CA פרטיים ואת רשויות האישורים הנדרשות.
- יצירת אשכול GKE עם תכונות של איחוד זהויות של עומסי עבודה ב-GKE ואישורי mesh, ושילוב של שירות CA.
- הגדרת הנפקת אישורים לרשת באשכול.
- יצירת חשבונות השירות של הלקוח והשרת.
- הגדרת שרת לדוגמה שמשתמש בממשקי xDS API ובפרטי כניסה של שרת xDS כדי לקבל הגדרת אבטחה מ-Cloud Service Mesh.
- הגדרת לקוח לדוגמה שמשתמש בהרשאות xDS.
- עדכון ההגדרה של Cloud Service Mesh כך שתכלול הגדרת אבטחה.
דוגמאות קוד לשימוש בפרטי כניסה של xDS זמינות במיקומים הבאים:
עדכון Google Cloud CLI
כדי לעדכן את Google Cloud CLI, מריצים את הפקודה הבאה:
gcloud components update
הגדרה של משתני סביבה
במדריך הזה משתמשים בפקודות Cloud Shell, ומידע שחוזר על עצמו בפקודות מיוצג על ידי משתני סביבה שונים. לפני שמריצים את הפקודות, צריך להגדיר את הערכים הספציפיים שלכם למשתני הסביבה הבאים בסביבת המעטפת. כל שורת הערה מציינת את המשמעות של משתנה הסביבה המשויך.
# Your project ID
PROJECT_ID=PROJECT_ID
# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
ZONE=ZONE
gcloud config set compute/zone $ZONE
# GKE cluster URL derived from the above
GKE_CLUSTER_URL="https://container.googleapis.com/v1/projects/${PROJECT_ID}/locations/${ZONE}/clusters/${CLUSTER_NAME}"
# Workload pool to be used with the GKE cluster
WORKLOAD_POOL="${PROJECT_ID}.svc.id.goog"
# Kubernetes namespace to run client and server demo.
K8S_NAMESPACE='default'
DEMO_BACKEND_SERVICE_NAME='grpc-gke-helloworld-service'
# Compute other values
# Project number for your project
PROJNUM=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
# VERSION is the GKE cluster version. Install and use the most recent version
# from the rapid release channel and substitute its version for
# CLUSTER_VERSION, for example:
# VERSION=latest available version
# Note that the minimum required cluster version is 1.21.4-gke.1801.
VERSION="CLUSTER_VERSION"
SA_GKE=service-${PROJNUM}@container-engine-robot.iam.gserviceaccount.com
הפעלת גישה לממשקי API נדרשים
בקטע הזה מוסבר איך להפעיל גישה לממשקי ה-API הנדרשים.
מריצים את הפקודה הבאה כדי להפעיל את Cloud Service Mesh ואת ממשקי ה-API האחרים שנדרשים לאבטחת רשת שירותי gRPC בלי שרת Proxy.
gcloud services enable \ container.googleapis.com \ cloudresourcemanager.googleapis.com \ compute.googleapis.com \ trafficdirector.googleapis.com \ networkservices.googleapis.com \ networksecurity.googleapis.com \ privateca.googleapis.com \ gkehub.googleapis.comמריצים את הפקודה הבאה כדי לאפשר לחשבון השירות שמוגדר כברירת מחדל לגשת ל-Cloud Service Mesh security API.
GSA_EMAIL=$(gcloud iam service-accounts list --format='value(email)' \ --filter='displayName:Compute Engine default service account') gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member serviceAccount:${GSA_EMAIL} \ --role roles/trafficdirector.client
יצירה או עדכון של אשכול GKE
האבטחה של שירות Cloud Service Mesh תלויה בשילוב של שירות CA עם GKE. אשכול GKE צריך לעמוד בדרישות הבאות בנוסף לדרישות ההגדרה:
- צריך להשתמש בגרסת אשכול מינימלית של 1.21.4-gke.1801. אם אתם צריכים תכונות שזמינות בגרסה מאוחרת יותר, תוכלו לקבל את הגרסה הזו מערוץ ההפצה המהירה.
- צריך להפעיל את אשכול GKE ולהגדיר בו אישורי רשת, כמו שמתואר במאמר יצירת רשויות אישורים להנפקת אישורים.
יוצרים אשכול חדש שמשתמש באיחוד זהויות של עומסי עבודה ל-GKE. אם אתם מעדכנים אשכול קיים, דלגו לשלב הבא. הערך שאתם מציינים עבור
--tagsצריך להיות זהה לשם שמועבר לדגל--target-tagsעבור הפקודהfirewall-rules createבקטע הגדרת Cloud Service Mesh באמצעות רכיבי Cloud Load Balancing.# Create a GKE cluster with GKE managed mesh certificates. gcloud container clusters create CLUSTER_NAME \ --release-channel=rapid \ --scopes=cloud-platform \ --image-type=cos_containerd \ --machine-type=e2-standard-2 \ --zone=ZONE \ --workload-pool=PROJECT_ID.svc.id.goog \ --enable-mesh-certificates \ --cluster-version=CLUSTER_VERSION \ --enable-ip-alias \ --tags=allow-health-checks \ --workload-metadata=GKE_METADATA
יצירת האשכול עשויה להימשך כמה דקות.
אם אתם משתמשים באשכול קיים, אתם צריכים להפעיל את איחוד הזהויות של עומסי עבודה ל-GKE ואת האישורים של GKE Mesh. מוודאים שהאשכול נוצר עם הדגל
--enable-ip-alias, שלא ניתן להשתמש בו עם הפקודהupdate.gcloud container clusters update CLUSTER_NAME \ --enable-mesh-certificates
מריצים את הפקודה הבאה כדי לעבור לאשכול החדש כאשכול ברירת המחדל עבור פקודות
kubectl:gcloud container clusters get-credentials CLUSTER_NAME \ --zone ZONE
רישום אשכולות ב-Fleet
רושמים את האשכול שיצרתם או עדכנתם במאמר יצירת אשכול GKE בצי. רישום האשכול מקל על הגדרת אשכולות בפרויקטים מרובים.
הערה: כל אחד מהשלבים האלה עשוי להימשך עד עשר דקות.
רושמים את האשכול ב-Fleet:
gcloud container fleet memberships register CLUSTER_NAME \ --gke-cluster=ZONE/CLUSTER_NAME \ --enable-workload-identity --install-connect-agent \ --manifest-output-file=MANIFEST-FILE_NAME
מחליפים את המשתנים באופן הבא:
- CLUSTER_NAME: השם של האשכול.
- ZONE: האזור של האשכול.
- MANIFEST-FILE_NAME: הנתיב שבו הפקודות האלה יוצרות את המניפסט לצורך רישום.
אם תהליך ההרשמה יצליח, תופיע הודעה כמו זו:
Finished registering the cluster CLUSTER_NAME with the fleet.
מחילים את קובץ המניפסט שנוצר על האשכול:
kubectl apply -f MANIFEST-FILE_NAME
אם תהליך הבקשה יצליח, יוצגו הודעות כמו אלה:
namespace/gke-connect created serviceaccount/connect-agent-sa created podsecuritypolicy.policy/gkeconnect-psp created role.rbac.authorization.k8s.io/gkeconnect-psp:role created rolebinding.rbac.authorization.k8s.io/gkeconnect-psp:rolebinding created role.rbac.authorization.k8s.io/agent-updater created rolebinding.rbac.authorization.k8s.io/agent-updater created role.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created clusterrole.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-feature-authorizer-20210416-01-00 created rolebinding.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created role.rbac.authorization.k8s.io/gke-connect-namespace-getter created rolebinding.rbac.authorization.k8s.io/gke-connect-namespace-getter created secret/http-proxy created deployment.apps/gke-connect-agent-20210416-01-00 created service/gke-connect-monitoring created secret/creds-gcp create
מקבלים את משאב החברות מהאשכול:
kubectl get memberships membership -o yaml
הפלט צריך לכלול את מאגר הזהויות של עומסי העבודה שהוקצה על ידי הצי, כאשר PROJECT_ID הוא מזהה הפרויקט:
workload_identity_pool: PROJECT_ID.svc.id.goog
המשמעות היא שהאשכול נרשם בהצלחה.
יצירת רשויות אישורים להנפקת אישורים
כדי להנפיק אישורים ל-Pods, צריך ליצור מאגר של שירות CA ואת רשויות האישורים (CA) הבאות:
- רשות אישורים (CA) עליונה. זהו בסיס המהימנות לכל האישורים שהונפקו לרשת ה-Mesh. אפשר להשתמש ב-CA בסיסי קיים, אם יש לכם כזה. יוצרים את רשות האישורים (CA) ברמת
enterprise, שמיועדת להנפקת אישורים לטווח ארוך עם נפח נמוך. - רשות אישורים משנית. רשות האישורים הזו מנפיקה אישורים לעומסי עבודה. יוצרים את רשות האישורים המשנית באזור שבו האשכול שלכם נפרס. יוצרים את רשות האישורים המשנית ברמה
devops, שמיועדת להנפקת אישורים לטווח קצר בכמויות גדולות.
יצירת רשות אישורים משנית היא אופציונלית, אבל מומלץ מאוד ליצור אחת כזו במקום להשתמש ברשות אישורי הבסיס כדי להנפיק אישורי GKE Mesh. אם מחליטים להשתמש ב-CA הבסיסי כדי להנפיק אישורים לרשת, צריך לוודא שמצב ההנפקה מבוסס-ההגדרה שמוגדר כברירת מחדל עדיין מותר.
ה-CA המשני יכול להיות באזור אחר מהאזור של האשכול, אבל מומלץ מאוד ליצור אותו באותו אזור של האשכול כדי לשפר את הביצועים. עם זאת, אפשר ליצור את רשויות האישורים הבסיסיות והמשניות באזורים שונים בלי להשפיע על הביצועים או על הזמינות.
האזורים הבאים נתמכים בשירות CA:
| שם האזור | תיאור האזור |
|---|---|
asia-east1 |
טייוואן |
asia-east2 |
הונג קונג |
asia-northeast1 |
טוקיו |
asia-northeast2 |
אוסקה |
asia-northeast3 |
סיאול |
asia-south1 |
מומבאי |
asia-south2 |
דלהי |
asia-southeast1 |
סינגפור |
asia-southeast2 |
ג'קארטה |
australia-southeast1 |
סידני |
australia-southeast2 |
מלבורן |
europe-central2 |
ורשה |
europe-north1 |
פינלנד |
europe-southwest1 |
מדריד |
europe-west1 |
בלגיה |
europe-west2 |
לונדון |
europe-west3 |
פרנקפורט |
europe-west4 |
הולנד |
europe-west6 |
ציריך |
europe-west8 |
מילאנו |
europe-west9 |
פריז |
europe-west10 |
ברלין |
europe-west12 |
טורינו |
me-central1 |
דוחה |
me-central2 |
דמאם |
me-west1 |
תל אביב |
northamerica-northeast1 |
מונטריאול |
northamerica-northeast2 |
טורונטו |
southamerica-east1 |
סאו פאולו |
southamerica-west1 |
סנטיאגו |
us-central1 |
איווה |
us-east1 |
דרום קרוליינה |
us-east4 |
צפון וירג'יניה |
us-east5 |
קולומבוס |
us-south1 |
דאלאס |
us-west1 |
אורגון |
us-west2 |
לוס-אנג׳לס |
us-west3 |
סולט לייק סיטי |
us-west4 |
לאס וגאס |
אפשר גם להריץ את הפקודה הבאה כדי לבדוק את רשימת המיקומים הנתמכים:
gcloud privateca locations list
נותנים את הרשאת IAM
roles/privateca.caManagerלאנשים שיוצרים מאגר רשויות אישורים ורשות אישורים. שימו לב: הפורמט הנכון של MEMBER הואuser:userid@example.com. אם האדם הזה הוא המשתמש הנוכחי, אפשר לקבל את מזהה המשתמש הנוכחי באמצעות פקודת ה-Shell$(gcloud auth list --filter=status:ACTIVE --format="value(account)").gcloud projects add-iam-policy-binding PROJECT_ID \ --member=MEMBER \ --role=roles/privateca.caManager
מקצים את התפקיד
role/privateca.adminבשירות CA לאנשים שצריכים לשנות את כללי המדיניות של IAM, כאשרMEMBERהוא אדם שצריך את הגישה הזו, במיוחד כל אדם שמבצע את השלבים הבאים שנותנים את התפקידיםprivateca.auditorו-privateca.certificateManager:gcloud projects add-iam-policy-binding PROJECT_ID \ --member=MEMBER \ --role=roles/privateca.admin
יוצרים את המאגר של שירות רשות האישורים (CA) הבסיסית.
gcloud privateca pools create ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --tier enterprise
יוצרים רשות אישורים (CA) עליונה.
gcloud privateca roots create ROOT_CA_NAME --pool ROOT_CA_POOL_NAME \ --subject "CN=ROOT_CA_NAME, O=ROOT_CA_ORGANIZATION" \ --key-algorithm="ec-p256-sha256" \ --max-chain-length=1 \ --location ROOT_CA_POOL_LOCATION
בהדגמה הזו, משתמשים בערכים הבאים למשתנים:
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_NAME=pkcs2-ca
- ROOT_CA_POOL_LOCATION=us-east1
- ROOT_CA_ORGANIZATION="TestCorpLLC"
יוצרים את המאגר המשני ואת רשות האישורים המשנית. מוודאים שמצב ההנפקה מבוסס-ההגדרה שמוגדר כברירת מחדל עדיין מותר.
gcloud privateca pools create SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --tier devops
gcloud privateca subordinates create SUBORDINATE_CA_NAME \ --pool SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --issuer-pool ROOT_CA_POOL_NAME \ --issuer-location ROOT_CA_POOL_LOCATION \ --subject "CN=SUBORDINATE_CA_NAME, O=SUBORDINATE_CA_ORGANIZATION" \ --key-algorithm "ec-p256-sha256" \ --use-preset-profile subordinate_mtls_pathlen_0
בהדגמה הזו, משתמשים בערכים הבאים למשתנים:
- SUBORDINATE_CA_POOL_NAME="td-ca-pool"
- SUBORDINATE_CA_POOL_LOCATION=us-east1
- SUBORDINATE_CA_NAME="td-ca"
- SUBORDINATE_CA_ORGANIZATION="TestCorpLLC"
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_POOL_LOCATION=us-east1
מקצים את התפקיד
privateca.auditorב-IAM למאגר CA הבסיסי כדי לאפשר גישה מחשבון השירות של GKE:gcloud privateca pools add-iam-policy-binding ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --role roles/privateca.auditor \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
מקצים את התפקיד
privateca.certificateManagerב-IAM למאגר של רשות אישורים משנית כדי לאפשר גישה מחשבון השירות של GKE:gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --role roles/privateca.certificateManager \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
שומרים את הגדרת ה-YAML הבאה
WorkloadCertificateConfigכדי להגדיר לאשכול איך להנפיק אישורים לרשת:apiVersion: security.cloud.google.com/v1 kind: WorkloadCertificateConfig metadata: name: default spec: # Required. The CA service that issues your certificates. certificateAuthorityConfig: certificateAuthorityServiceConfig: endpointURI: ISSUING_CA_POOL_URI # Required. The key algorithm to use. Choice of RSA or ECDSA. # # To maximize compatibility with various TLS stacks, your workloads # should use keys of the same family as your root and subordinate CAs. # # To use RSA, specify configuration such as: # keyAlgorithm: # rsa: # modulusSize: 4096 # # Currently, the only supported ECDSA curves are "P256" and "P384", and the only # supported RSA modulus sizes are 2048, 3072 and 4096. keyAlgorithm: rsa: modulusSize: 4096 # Optional. Validity duration of issued certificates, in seconds. # # Defaults to 86400 (1 day) if not specified. validityDurationSeconds: 86400 # Optional. Try to start rotating the certificate once this # percentage of validityDurationSeconds is remaining. # # Defaults to 50 if not specified. rotationWindowPercentage: 50מחליפים את מה שכתוב בשדות הבאים:
- מזהה הפרויקט שבו פועל האשכול:
PROJECT_ID
- ה-URI המוגדר במלואו של רשות האישורים שמנפיקה את אישורי הרשת (ISSUING_CA_POOL_URI).
יכול להיות שזו רשות אישורים משנית (מומלץ) או רשות אישורים בסיסית. הפורמט הוא:
//privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
- מזהה הפרויקט שבו פועל האשכול:
שומרים את הגדרת ה-YAML הבאה
TrustConfigכדי להגדיר לאשכול איך לתת אמון באישורים שהונפקו:apiVersion: security.cloud.google.com/v1 kind: TrustConfig metadata: name: default spec: # You must include a trustStores entry for the trust domain that # your cluster is enrolled in. trustStores: - trustDomain: PROJECT_ID.svc.id.goog # Trust identities in this trustDomain if they appear in a certificate # that chains up to this root CA. trustAnchors: - certificateAuthorityServiceURI: ROOT_CA_POOL_URIמחליפים את מה שכתוב בשדות הבאים:
- מזהה הפרויקט שבו פועל האשכול:
PROJECT_ID
- ה-URI המוגדר במלואו של מאגר רשויות האישורים (CA) הבסיסי (ROOT_CA_POOL_URI).
הפורמט הוא:
//privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
- מזהה הפרויקט שבו פועל האשכול:
מחילים את ההגדרות על האשכול:
kubectl apply -f WorkloadCertificateConfig.yaml kubectl apply -f TrustConfig.yaml
יצירת שירות gRPC בלי שרת Proxy עם NEGs
כדי להשתמש באבטחת PSM, צריך שרת gRPC ללא proxy שיוכל להשתמש ב-xDS כדי לקבל הגדרות אבטחה מ-Cloud Service Mesh. השלב הזה דומה להגדרת שירותי GKE עם NEGs במדריך להגדרת איזון עומסים של PSM, אבל במקום קובץ האימג' java-example-hostname משתמשים בשרת helloworld עם xDS בדוגמה של xDS במאגר grpc-java.
אתם יוצרים ומריצים את השרת הזה בקונטיינר שנבנה מקובץ אימג' של openjdk:8-jdk.
אפשר גם להשתמש בתכונה של NEG עם שם, שמאפשרת לציין שם ל-NEG. הפעולה הזו מפשטת את השלבים הבאים כי הפריסה יודעת את השם של קבוצת ה-NEG בלי שתצטרך לחפש אותו.
זוהי דוגמה מלאה למפרט Kubernetes של שרת gRPC. שימו לב:
- המפרט יוצר חשבון שירות של Kubernetes
example-grpc-serverשמשמש את קבוצת ה-Pod של שרת gRPC. - במפרט נעשה שימוש בשדה
nameבהערהcloud.google.com/negשל השירות כדי לציין את שם ה-NEGexample-grpc-server. - המשתנה
${PROJNUM}מייצג את מספר הפרויקט שלכם. - במפרט נעשה שימוש בקטע
initContainersכדי להריץ מחולל אתחול לאכלוס קובץ האתחול שספריית gRPC ללא proxy צריכה. קובץ האתחול הזה נמצא בנתיב/tmp/grpc-xds/td-grpc-bootstrap.jsonבמאגר התגים בצד השרת שנקראexample-grpc-server.
מוסיפים את ההערה הבאה למפרט ה-Pod:
annotations: security.cloud.google.com/use-workload-certificates: ""
בהמשך מופיע המפרט המלא עם המיקום הנכון.
בזמן היצירה, לכל פוד מוגדרת עוצמת קול בערך /var/run/secrets/workload-spiffe-credentials.
נפח האחסון הזה מכיל את הפריטים הבאים:
-
private_key.pemהוא מפתח פרטי שנוצר באופן אוטומטי. -
certificates.pemהוא חבילה של אישורים בפורמט PEM שאפשר להציג ל-Pod אחר כשרשרת אישורי לקוח, או להשתמש בה כשרשרת אישורי שרת. -
ca_certificates.pemהוא חבילה של אישורים בפורמט PEM שמשמשים כנקודות עוגן מהימנות כשמאמתים את שרשרת האישורים של הלקוח שמוצגת על ידי Pod אחר, או את שרשרת האישורים של השרת שמתקבלת כשמתחברים ל-Pod אחר.
שימו לב שהקובץ ca_certificates.pem מכיל אישורים של דומיין האמון המקומי של עומסי העבודה, שהוא מאגר עומסי העבודה של האשכול.
אישור העלה ב-certificates.pem מכיל את הצהרת הזהות הבאה ב-SPIFFE בטקסט פשוט:
spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT
בטענה הזו:
- WORKLOAD_POOL הוא השם של מאגר הזהויות של עומסי העבודה של האשכול.
- NAMESPACE הוא מרחב השמות של חשבון השירות של Kubernetes.
- KUBERNETES_SERVICE_ACCOUNT הוא השם של חשבון השירות של Kubernetes.
ההוראות הבאות בשפה שלך יוצרות את המפרט לשימוש בדוגמה הזו.
Java
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOFכך משלימים את התהליך.
החלת המפרט:
kubectl apply -f example-grpc-server.yaml
מקצים לחשבון השירות את התפקידים הנדרשים:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ --role roles/trafficdirector.clientמריצים את הפקודות האלה כדי לוודא שהשירות וה-Pod נוצרו בצורה נכונה:
kubectl get deploy/example-grpc-server kubectl get svc/example-grpc-server
מוודאים שהשם של ה-NEG נכון:
gcloud compute network-endpoint-groups list \ --filter "name=example-grpc-server" --format "value(name)"הפקודה צריכה להחזיר את שם ה-NEG
example-grpc-server.
הגדרת Cloud Service Mesh עם Google Cloud רכיבי איזון עומסים
השלבים בקטע הזה דומים לאלה שבקטע הגדרת Cloud Service Mesh עם רכיבי איזון עומסים, אבל יש כמה שינויים, כפי שמתואר בקטעים הבאים.
יצירת בדיקת התקינות, כלל חומת האש ושירות הקצה העורפי
כששרת gRPC מוגדר לשימוש ב-mTLS, בדיקות התקינות של gRPC לא פועלות כי לקוח בדיקת התקינות לא יכול להציג אישור לקוח תקף לשרתים. יש שתי דרכים לפתור את הבעיה הזו.
בגישה הראשונה, השרת יוצר יציאת שירות נוספת שמיועדת לבדיקת תקינות. הוא מצורף לשירות מיוחד לבדיקת תקינות, כטקסט רגיל או כ-TLS ליציאה הזו.
helloworld שרת לדוגמה של xDS משתמש ב-PORT_NUMBER + 1 בתור יציאת בדיקת תקינות של טקסט פשוט. בדוגמה נעשה שימוש ביציאה 50052 לבדיקת התקינות, כי 50051 היא יציאת שרת האפליקציות של gRPC.
בגישה השנייה, מגדירים בדיקת תקינות כדי לבדוק רק את קישוריות ה-TCP ליציאת האפליקציה להצגת מודעות. הבדיקה הזו בודקת רק את הקישוריות, והיא גם יוצרת תנועה מיותרת לשרת כשיש לחיצות ידיים לא מוצלחות של TLS. לכן, מומלץ להשתמש בגישה הראשונה.
יוצרים את בדיקת התקינות. שימו לב: בדיקת תקינות מתחילה רק אחרי שיוצרים את השרת ומפעילים אותו.
אם אתם יוצרים יציאה ייעודית להצגת נתונים לצורך בדיקת תקינות, וזו הגישה המומלצת שלנו, אתם צריכים להשתמש בפקודה הזו:
gcloud compute health-checks create grpc grpc-gke-helloworld-hc \ --enable-logging --port 50052
אם אתם יוצרים בדיקת תקינות של TCP, שאנחנו לא ממליצים עליה, משתמשים בפקודה הזו:
gcloud compute health-checks create tcp grpc-gke-helloworld-hc \ --use-serving-port
יוצרים את חומת האש. מוודאים שהערך של
--target-tagsזהה לערך שסיפקתם עבור--tagsבקטע יצירה או עדכון של אשכול GKE.gcloud compute firewall-rules create grpc-gke-allow-health-checks \ --network default --action allow --direction INGRESS \ --source-ranges 35.191.0.0/16,130.211.0.0/22 \ --target-tags allow-health-checks \ --rules tcp:50051-50052
יוצרים את שירות הקצה העורפי:
gcloud compute backend-services create grpc-gke-helloworld-service \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --protocol=GRPC \ --health-checks grpc-gke-helloworld-hc
מצרפים את ה-NEG לשירות הקצה העורפי:
gcloud compute backend-services add-backend grpc-gke-helloworld-service \ --global \ --network-endpoint-group example-grpc-server \ --network-endpoint-group-zone ${ZONE} \ --balancing-mode RATE \ --max-rate-per-endpoint 5
יצירת משאבי Mesh ו-GRPCRoute
ההגדרה דומה להגדרת המשאבים Mesh ו-GRPCRoute במאמר הגדרת שירותי gRPC בלי שרת Proxy.
יוצרים את המפרט
Meshושומרים אותו בקובץ בשםmesh.yaml.name: grpc-mesh
מייבאים את המשאב
Meshמהמפרט.gcloud network-services meshes import grpc-mesh \ --source=mesh.yaml \ --location=global
יוצרים את המפרט
GRPCRouteושומרים אותו בקובץ בשםgrpc_route.yaml.name: helloworld-grpc-route hostnames: - helloworld-gke:8000 meshes: - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh rules: - action: destinations: - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-serviceמייבאים את המשאב
GRPCRouteמהמפרטgrpc_route.yaml.gcloud network-services grpc-routes import helloworld-grpc-route \ --source=grpc_route.yaml \ --location=global
הגדרת Cloud Service Mesh עם אבטחת gRPC ללא proxy
בדוגמה הזו מוסבר איך להגדיר mTLS בצד הלקוח ובצד השרת.
הפורמט של סימוכין בתקנון המדיניות
שימו לב לפורמט הנדרש הבא להפניה למדיניות TLS של שרת ו-TLS של לקוח:
projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies]/[server-tls-policy|client-mtls-policy]
לדוגמה:
projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
הגדרת mTLS בצד השרת
קודם יוצרים מדיניות TLS של שרת. המדיניות מבקשת מצד השרת של gRPC להשתמש בהגדרת התוסף certificateProvicerInstance שמזוהה לפי השם google_cloud_private_spiffe עבור אישור הזהות, שהוא חלק מ-serverCertificate. בקטע mtlsPolicy מצוינת אבטחת mTLS, והוא משתמש באותו google_cloud_private_spiffe כמו הגדרת הפלאגין של clientValidationCa, שהוא מפרט אישור הבסיס (אימות).
בשלב הבא יוצרים מדיניות של נקודת קצה. ההגדרה הזו מציינת ששרת קצה עורפי, לדוגמה שרת gRPC, שמשתמש ביציאה 50051 עם תוויות מטא-נתונים כלשהן או ללא תוויות מטא-נתונים, מקבל את מדיניות ה-TLS של השרת המצורפת שנקראת server-mtls-policy. אפשר לציין תוויות של מטא-נתונים באמצעות MATCH_ALL או ערך נתמך. תוויות המטא-נתונים הנתמכות מופיעות בשדה endpointMatcher.metadataLabelMatcher.metadataLabelMatchCriteria במסמך NetworkServicesEndpointPolicy. יוצרים את מדיניות נקודת הקצה באמצעות קובץ זמני ep-mtls-psms.yaml שמכיל את הערכים של משאב מדיניות נקודת הקצה, על סמך המדיניות שכבר הגדרתם.
יוצרים קובץ זמני
server-mtls-policy.yamlבספרייה הנוכחית עם הערכים של משאב מדיניות ה-TLS של השרת:name: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe mtlsPolicy: clientValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffeיוצרים משאב מדיניות TLS לשרת בשם
server-mtls-policyעל ידי ייבוא של הקובץ הזמניserver-mtls-policy.yaml:gcloud network-security server-tls-policies import server-mtls-policy \ --source=server-mtls-policy.yaml --location=global
יוצרים את מדיניות נקודת הקצה על ידי יצירת הקובץ הזמני
ep-mtls-psms.yaml:name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: - labelName: app labelValue: helloworldמייבאים את הקובץ
ep-mtls-psms.yamlכדי ליצור את משאב מדיניות נקודת הקצה:gcloud beta network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
הגדרת mTLS בצד הלקוח
מדיניות האבטחה בצד הלקוח מצורפת לשירות הקצה העורפי. כשלקוח ניגש לחלק האחורי (שרת gRPC) דרך שירות החלק האחורי, מדיניות האבטחה בצד הלקוח שמצורפת נשלחת ללקוח.
יוצרים את התוכן של משאב מדיניות TLS של הלקוח בקובץ זמני בשם
client-mtls-policy.yamlבספרייה הנוכחית:name: "client-mtls-policy" clientCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffeיוצרים את משאב מדיניות TLS של הלקוח שנקרא
client-mtls-policyעל ידי ייבוא של הקובץ הזמניclient-mtls-policy.yaml:gcloud network-security client-tls-policies import client-mtls-policy \ --source=client-mtls-policy.yaml --location=global
יוצרים קטע קוד בקובץ זמני כדי להפנות למדיניות הזו ומוסיפים פרטים לגבי
subjectAltNamesבהודעהSecuritySettingsכמו בדוגמה הבאה. מחליפים את${PROJECT_ID}בערך של מזהה הפרויקט, שהוא הערך של משתנה הסביבה${PROJECT_ID}שמתואר למעלה. שימו לב:example-grpc-serverב-subjectAltNamesהוא שם חשבון השירות של Kubernetes שמשמש את קבוצת ה-Pod של שרת gRPC במפרט הפריסה.if [ -z "$PROJECT_ID" ] ; then echo Please make sure PROJECT_ID is set. ; fi cat << EOF > client-security-settings.yaml securitySettings: clientTlsPolicy: projects/${PROJECT_ID}/locations/global/clientTlsPolicies/client-mtls-policy subjectAltNames: - "spiffe://${PROJECT_ID}.svc.id.goog/ns/default/sa/example-grpc-server" EOFמוסיפים את ההודעה
securitySettingsלשירות לקצה העורפי שכבר יצרתם. בשלבים האלה מייצאים את התוכן הנוכחי של שירות לקצה העורפי, מוסיפים את ההודעה של הלקוחsecuritySettingומייבאים מחדש את התוכן החדש כדי לעדכן את שירות לקצה העורפי.gcloud compute backend-services export grpc-gke-helloworld-service --global \ --destination=/tmp/grpc-gke-helloworld-service.yaml cat /tmp/grpc-gke-helloworld-service.yaml client-security-settings.yaml \ >/tmp/grpc-gke-helloworld-service1.yaml gcloud compute backend-services import grpc-gke-helloworld-service --global \ --source=/tmp/grpc-gke-helloworld-service1.yaml -q
אימות ההגדרה
ההגדרה של Cloud Service Mesh הושלמה, כולל אבטחה בצד השרת ובצד הלקוח. לאחר מכן, מכינים ומריצים את עומסי העבודה של השרת והלקוח. כך מסתיימת הדוגמה.
יצירת לקוח gRPC ללא proxy
השלב הזה דומה לשלב הקודם יצירת שירות gRPC ללא proxy.
משתמשים בלקוח helloworld עם תמיכה ב-xDS מתוך ספריית הדוגמאות של xDS במאגר grpc-java. אתם יוצרים ומריצים את הלקוח בקונטיינר שנבנה מקובץ אימג' של openjdk:8-jdk. מפרט Kubernetes של לקוח gRPC מבצע את הפעולות הבאות.
- הוא יוצר חשבון שירות של Kubernetes
example-grpc-clientשמשמש את פוד הלקוח של gRPC. -
${PROJNUM}מייצג את מספר הפרויקט שלכם, וצריך להחליף אותו במספר האמיתי.
מוסיפים את ההערה הבאה למפרט ה-Pod:
annotations:
security.cloud.google.com/use-workload-certificates: ""
בזמן היצירה, לכל פוד מוגדרת עוצמת קול בערך /var/run/secrets/workload-spiffe-credentials.
נפח האחסון הזה מכיל את הפריטים הבאים:
-
private_key.pemהוא מפתח פרטי שנוצר באופן אוטומטי. -
certificates.pemהוא חבילה של אישורים בפורמט PEM שאפשר להציג ל-Pod אחר כשרשרת אישורי לקוח, או להשתמש בה כשרשרת אישורי שרת. -
ca_certificates.pemהוא חבילה של אישורים בפורמט PEM שמשמשים כנקודות עוגן מהימנות כשמאמתים את שרשרת האישורים של הלקוח שמוצגת על ידי Pod אחר, או את שרשרת האישורים של השרת שמתקבלת כשמתחברים ל-Pod אחר.
שימו לב שהקובץ ca_certificates.pem מכיל את אישורי הבסיס של דומיין האמון המקומי של עומסי העבודה, שהוא מאגר הזהויות של עומסי העבודה של האשכול.
אישור העלה ב-certificates.pem מכיל את הצהרת הזהות הבאה ב-SPIFFE בטקסט פשוט:
spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT
בטענה הזו:
- WORKLOAD_POOL הוא השם של מאגר הזהויות של עומסי העבודה של האשכול.
- NAMESPACE הוא השם של חשבון השירות של Kubernetes.
- KUBERNETES_SERVICE_ACCOUNT הוא מרחב השמות של חשבון השירות של Kubernetes.
ההוראות הבאות בשפה שלך יוצרות את המפרט לשימוש בדוגמה הזו.
Java
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט הבא:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט הבא:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט הבא:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
יוצרים את המפרט הבא:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --config-mesh-experimental - "grpc-mesh" - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
כך משלימים את התהליך.
החלת המפרט:
kubectl apply -f example-grpc-client.yaml
מקצים לחשבון השירות את התפקידים הנדרשים:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ --role roles/trafficdirector.clientמוודאים ש-Pod הלקוח פועל:
kubectl get pods
הפקודה מחזירה טקסט שדומה לזה:
NAMESPACE NAME READY STATUS RESTARTS AGE default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 104s [..skip..]
הפעלת השרת
יוצרים ומריצים את שרת helloworld עם תמיכה ב-xDS בפוד של השרת שיצרתם קודם.
Java
כדי לקבל את השם של ה-Pod שנוצר עבור השירות
example-grpc-server:kubectl get pods | grep example-grpc-server
יוצג משוב כמו זה:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
פותחים מעטפת ל-Pod של השרת:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
במעטפת, מוודאים שקובץ האתחול בנתיב
/tmp/grpc-xds/td-grpc-bootstrap.jsonתואם לסכימה שמתוארת בקטע קובץ האתחול.מורידים את gRPC Java גרסה 1.42.1 ויוצרים את אפליקציית השרת
xds-hello-world.curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
מריצים את השרת עם הדגל
--xds-credsכדי לציין אבטחה עם xDS, באמצעות50051כיציאת ההאזנה ו-xds-serverכשם הזיהוי של השרת:./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:
Listening on port 50051 plain text health service listening on port 50052
C++
כדי לקבל את השם של ה-Pod שנוצר עבור השירות
example-grpc-server:kubectl get pods | grep example-grpc-server
יוצג משוב כמו זה:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
פותחים מעטפת ל-Pod של השרת:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
במעטפת, מוודאים שקובץ האתחול בנתיב
/tmp/grpc-xds/td-grpc-bootstrap.jsonתואם לסכימה שמתוארת בקטע קובץ האתחול.מורידים את gRPC C++ ויוצרים את אפליקציית השרת
xds-hello-world.apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-dev curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz cd grpc-master tools/bazel build examples/cpp/helloworld:xds_greeter_serverמריצים את השרת באמצעות
50051כיציאת ההאזנה, ו-xds_greeter_serverכשם הזיהוי של השרת:bazel-bin/examples/cpp/helloworld/xds_greeter_server --port=50051 --maintenance_port=50052 --secure
כדי להריץ את השרת בלי פרטי כניסה, אפשר לציין את הפרטים הבאים:
bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:
Listening on port 50051 plain text health service listening on port 50052
Python
כדי לקבל את השם של ה-Pod שנוצר עבור השירות
example-grpc-server:kubectl get pods | grep example-grpc-server
יוצג משוב כמו זה:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
פותחים מעטפת ל-Pod של השרת:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
במעטפת, מוודאים שקובץ האתחול בנתיב
/tmp/grpc-xds/td-grpc-bootstrap.jsonתואם לסכימה שמתוארת בקטע קובץ האתחול.מורידים את gRPC Python בגרסה 1.41.0 ויוצרים את האפליקציה לדוגמה.
apt-get update -y
apt-get install -y python3 python3-pip
curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
cd grpc-1.41.x/examples/python/xds/
python3 -m virtualenv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
מריצים את השרת עם הדגל
--xds-credsכדי לציין אבטחה עם xDS, באמצעות50051כפורט ההאזנה.python3 server.py 50051 --xds-creds
אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:
2021-05-06 16:10:34,042: INFO Running with xDS Server credentials 2021-05-06 16:10:34,043: INFO Greeter server listening on port 50051 2021-05-06 16:10:34,046: INFO Maintenance server listening on port 50052
Go
כדי לקבל את השם של ה-Pod שנוצר עבור השירות
example-grpc-server:kubectl get pods | grep example-grpc-server
יוצג משוב כמו זה:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
פותחים מעטפת ל-Pod של השרת:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
במעטפת, מוודאים שקובץ האתחול בנתיב
/tmp/grpc-xds/td-grpc-bootstrap.jsonתואם לסכימה שמתוארת בקטע קובץ האתחול.מורידים את gRPC Go בגרסה 1.41.0 ועוברים אל הספרייה שמכילה את אפליקציית השרת
xds-hello-world.apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/server
בונים ומריצים את השרת עם הדגל
--xds_credsכדי לציין אבטחה עם xDS, באמצעות50051כיציאת ההאזנה:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \ go run main.go \ -xds_creds \ -port 50051
אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:
Using xDS credentials... Serving GreeterService on 0.0.0.0:50051 and HealthService on 0.0.0.0:50052
תהליך בדיקת התקינות נמשך 3 עד 5 דקות עד שמוצג שהשירות תקין אחרי הפעלת השרת.
מריצים את הלקוח ומאמתים את ההגדרה
יוצרים ומריצים את לקוח helloworld עם תמיכה ב-xDS בפוד של הלקוח שיצרתם קודם.
Java
משיגים את השם של ה-Pod של הלקוח:
kubectl get pods | grep example-grpc-client
מוצג לכם משוב כמו זה:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
פותחים מעטפת ל-Pod של הלקוח:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
במעטפת הפקודות, מורידים את gRPC Java גרסה 1.42.1 ויוצרים את אפליקציית הלקוח
xds-hello-world.curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
מריצים את הלקוח עם הדגל
--xds-credsכדי לציין אבטחה עם xDS, שם לקוח ומחרוזת חיבור ליעד:./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000הפלט אמור להיראות כך:
Greeting: Hello xds-client, from xds-server
C++
משיגים את השם של ה-Pod של הלקוח:
kubectl get pods | grep example-grpc-client
מוצג לכם משוב כמו זה:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
פותחים מעטפת ל-Pod של הלקוח:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
אחרי שנכנסים למעטפת, מורידים את gRPC C++ ויוצרים את אפליקציית הלקוח
xds-hello-world.apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-devcurl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
cd grpc-master
tools/bazel build examples/cpp/helloworld:xds_greeter_client
מריצים את הלקוח עם הדגל
--xds-credsכדי לציין אבטחה עם xDS, שם לקוח ומחרוזת חיבור ליעד:bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000
כדי להריץ את הלקוח ללא פרטי כניסה, משתמשים בפקודה הבאה:
bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000 --nosecure
הפלט אמור להיראות כך:
Greeter received: Hello world
Python
משיגים את השם של ה-Pod של הלקוח:
kubectl get pods | grep example-grpc-client
מוצג לכם משוב כמו זה:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
פותחים מעטפת ל-Pod של הלקוח:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
אחרי שנכנסים למעטפת, מורידים את gRPC Python בגרסה 1.41.0 ויוצרים את אפליקציית הלקוח לדוגמה.
apt-get update -y apt-get install -y python3 python3-pip python3 -m pip install virtualenv curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz cd grpc-1.41.x/examples/python/xds/ python3 -m virtualenv venv source venv/bin/activate python3 -m pip install -r requirements.txt
מריצים את הלקוח עם הסימון
--xds-credsכדי לציין אבטחה עם הפעלת xDS, שם לקוח ומחרוזת חיבור ליעד:python3 client.py xds:///helloworld-gke:8000 --xds-creds
הפלט אמור להיראות כך:
Greeter client received: Hello you from example-host!
Go
משיגים את השם של ה-Pod של הלקוח:
kubectl get pods | grep example-grpc-client
מוצג לכם משוב כמו זה:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
פותחים מעטפת ל-Pod של הלקוח:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
אחרי שנכנסים למעטפת, מורידים את gRPC Go בגרסה 1.42.0 ועוברים לספרייה שמכילה את אפליקציית הלקוח
xds-hello-world.apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/client
בונים ומריצים את הלקוח עם הדגל
--xds_credsכדי לציין אבטחה עם xDS, שם לקוח ומחרוזת חיבור ליעד:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
הפלט אמור להיראות כך:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
הגדרת גישה ברמת השירות באמצעות מדיניות הרשאות
כדי לתמוך במדיניות הרשאות, צריך לתמוך ב-gRFC A41. אפשר למצוא את הגרסאות בשפות הנדרשות ב-github
במאמר הזה מוסבר איך להגדיר גישה ברמת השירות באמצעות מדיניות הרשאות. לפני שיוצרים מדיניות הרשאות, חשוב לקרוא את האזהרה במאמר הגבלת הגישה באמצעות הרשאות.
כדי להקל על אימות ההגדרה, יוצרים שם מארח נוסף שהלקוח יכול להשתמש בו כדי להתייחס לשירות helloworld-gke.
עדכון המפרט
GRPCRouteשאוחסן בעבר ב-grpc_route.yamlname: helloworld-grpc-route hostnames: - helloworld-gke:8000 - helloworld-gke-noaccess:8000 meshes: - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh rules: - action: destinations: - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-serviceמייבאים שוב את המשאב
GRPCRouteמהמפרטgrpc_route.yaml.gcloud network-services grpc-routes import helloworld-grpc-route \ --source=grpc_route.yaml \ --location=global
ההוראות הבאות יוצרות מדיניות הרשאות שמאפשרת בקשות שנשלחות מחשבון example-grpc-client שבו שם המארח הוא helloworld-gke:8000 והיציאה היא 50051.
gcloud
יוצרים מדיניות הרשאות על ידי יצירת קובץ בשם
helloworld-gke-authz-policy.yaml.action: ALLOW name: helloworld-gke-authz-policy rules: - sources: - principals: - spiffe://PROJECT_ID.svc.id.goog/ns/default/sa/example-grpc-client destinations: - hosts: - helloworld-gke:8000 ports: - 50051מייבאים את המדיניות.
gcloud network-security authorization-policies import \ helloworld-gke-authz-policy \ --source=helloworld-gke-authz-policy.yaml \ --location=global
מעדכנים את מדיניות נקודת הקצה כך שתפנה למדיניות ההרשאות החדשה על ידי הוספת השורה הבאה לקובץ
ep-mtls-psms.yaml.authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policyבמדיניות של נקודת הקצה מצוין עכשיו שצריך לאכוף גם mTLS וגם מדיניות הרשאות על בקשות נכנסות ל-Pods שקבצי ה-bootstrap של gRPC שלהם מכילים את התווית
app:helloworld.מייבאים את המדיניות:
gcloud network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
אימות מדיניות ההרשאות
כדי לוודא שמדיניות ההרשאות פועלת בצורה תקינה, פועלים לפי ההוראות הבאות.
Java
פותחים מעטפת (shell) לפוד הלקוח שבו השתמשתם קודם.
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
במעטפת הפקודות, מריצים את הפקודות הבאות כדי לאמת את ההגדרה.
cd grpc-java-1.42.1/examples/example-xds ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000הפלט אמור להיראות כך:
Greeting: Hello xds-client, from xds-server
מריצים את הלקוח שוב עם שם השרת החלופי. שימו לב שזהו מקרה של כשל. הבקשה לא חוקית כי מדיניות ההרשאה מאפשרת גישה רק לשם המארח
helloworld-gke:8000../build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke-noaccess:8000הפלט אמור להיראות כך:
WARNING: RPC failed: Status{code=PERMISSION_DENIED}אם הפלט הזה לא מופיע, יכול להיות שמדיניות ההרשאות עדיין לא בשימוש. צריך לחכות כמה דקות ולנסות שוב את כל תהליך האימות.
Go
פותחים מעטפת (shell) לפוד הלקוח שבו השתמשתם קודם.
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
במעטפת הפקודות, מריצים את הפקודות הבאות כדי לאמת את ההגדרה.
cd grpc-go-1.42.0/examples/features/xds/client GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
הפלט אמור להיראות כך:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
מריצים את הלקוח שוב עם שם השרת החלופי. שימו לב שזהו מקרה של כשל. הבקשה לא חוקית כי מדיניות ההרשאה מאפשרת גישה רק לשם המארח
helloworld-gke:8000.GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke-noaccess:8000
הפלט אמור להיראות כך:
could not greet: rpc error: code = PermissionDenied desc = Incoming RPC is not allowed: rpc error: code = PermissionDenied desc = incoming RPC did not match an allow policy exit status 1
אם הפלט הזה לא מופיע, יכול להיות שמדיניות ההרשאות עדיין לא בשימוש. צריך לחכות כמה דקות ולנסות שוב את כל תהליך האימות.
שימוש ב-TLS במקום ב-mTLS
בדוגמה הזו, כדי להשתמש ב-TLS צריך לבצע שינוי קטן בלבד.
ב-
ServerTlsPolicy, מחזירים אתmtlsPolicy:cat << EOF > server-tls-policy.yaml name: "server-tls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOFבמקומה, צריך להשתמש במדיניות
EndpointPolicy:cat << EOF > ep-tls-psms.yaml name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-tls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: [] EOFההגדרה
ClientTlsPolicyשל mTLS פועלת גם במקרה של TLS, אבל אפשר להשמיט את הקטעclientCertificateבמדיניות כי הוא לא נדרש ל-TLS:cat << EOF > client-tls-policy.yaml name: "client-tls-policy" serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOF
שימוש באבטחת שירות עם הדוגמה של Wallet
בקטע הזה מפורטת סקירה כללית על הפעלת הדוגמה של Wallet עם אבטחת שירות, עבור Java, C++ ו-Go.
Java
אפשר למצוא את קוד המקור לדוגמה של Java ב-github.
הקוד כבר משתמש בפרטי הכניסה של XdsChannel ושל XdsServer כשמגדירים אבטחה בלי שרת Proxy.
בהוראות האלה מוסבר איך להגדיר את הדוגמה של Wallet באמצעות Go. התהליך דומה לזה של Java. ההוראות מתייחסות לתמונת Docker קיימת שאפשר להשיג ממאגר התמונות שלGoogle Cloud .
כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:
- משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
- עורכים את הקובץ
00-common-env.sh. מוסיפים הערה לשורה הקיימת שקובעת את הערך שלWALLET_DOCKER_IMAGEלקובץ אימג' של Go Docker, ומבטלים סימון כהערה (uncomment) בשורה שקובעת את הערך שלWALLET_DOCKER_IMAGEלקובץ אימג' של Java Docker. - יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה
create_cloud_router_instancesבסקריפט10.apis.sh. - יוצרים אשכול באמצעות ההוראות לדוגמה
hello worldאו הפונקציהcreate_clusterבסקריפט20-cluster.sh. - יוצרים רשויות אישורים פרטיות באמצעות ההוראות ל-CA Service או באמצעות הסקריפט
30-private-ca-setup.sh. - יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים:
account,stats,stats_premium,wallet_v1,wallet_v2, באמצעות הסקריפט40-k8s-resources.sh. - לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות
create_health_checkו-create_backend_serviceבסקריפט50-td-components.sh. - יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות
create_routing_componentsבסקריפט60-routing-components.sh. - יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות
create_security_componentsבסקריפט70-security-components.sh. - יוצרים את פריסת לקוח ארנק Google באמצעות
create_client_deploymentבסקריפט75-client-deployment.sh. - כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות grpc-wallet.
C++
אפשר למצוא את קוד המקור לדוגמה עבור C++ ב-github. הקוד כבר משתמש בפרטי הכניסה XdsChannel ו-XdsServer כשמגדירים אבטחה בלי שרת Proxy.
בהוראות האלה מתואר איך להגדיר את הדוגמה ל-Wallet באמצעות Go. התהליך דומה ל-C++. ההוראות מתייחסות לתמונת Docker קיימת מראש שאפשר לקבל ממאגר מאגרי הנתונים שלGoogle Cloud .
כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:
- משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
- עורכים את הקובץ
00-common-env.sh. מסמנים כהערה את השורה הקיימת שקובעת את הערך שלWALLET_DOCKER_IMAGEלקובץ אימג' של Go Docker ומבטלים את הסימון כהערה בשורה שקובעת את הערך שלWALLET_DOCKER_IMAGEלקובץ אימג' של C++ Docker. - יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה
create_cloud_router_instancesבסקריפט10.apis.sh. - יוצרים אשכול באמצעות ההוראות לדוגמה
hello worldאו הפונקציהcreate_clusterבסקריפט20-cluster.sh. - יוצרים רשויות אישורים פרטיות באמצעות ההוראות לשימוש בשירות CA
או באמצעות הסקריפט
30-private-ca-setup.sh. - יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים:
account,stats,stats_premium,wallet_v1,wallet_v2, באמצעות הסקריפט40-k8s-resources.sh. - לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות
create_health_checkו-create_backend_serviceבסקריפט50-td-components.sh. - יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות
create_routing_componentsבסקריפט60-routing-components.sh. - יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות
create_security_componentsבסקריפט70-security-components.sh. - יוצרים את פריסת לקוח ארנק Google באמצעות
create_client_deploymentבסקריפט75-client-deployment.sh. - כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות grpc-wallet.
Go
קוד מקור לדוגמה ל-Go זמין ב-github. הקוד כבר משתמש בפרטי הכניסה של XdsChannel
ושלXdsServer כשמגדירים אבטחה בלי שרת Proxy.
ההוראות מתייחסות לקובץ אימג' קיים של Docker שמתקבל מGoogle Cloud מאגר קונטיינרים.
כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:
- משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
- עורכים את הקובץ
00-common-env.shכדי להגדיר את הערכים הנכונים למשתני הסביבה. - יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה
create_cloud_router_instancesבסקריפט10.apis.sh. - יוצרים אשכול באמצעות ההוראות לדוגמה
hello worldאו הפונקציהcreate_clusterבסקריפט20-cluster.sh. - יוצרים רשויות אישורים פרטיות באמצעות ההוראות ל-CA Service או באמצעות הסקריפט
30-private-ca-setup.sh. - יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים:
account,stats,stats_premium,wallet_v1,wallet_v2, באמצעות הסקריפט40-k8s-resources.sh. - לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות
create_health_checkו-create_backend_serviceבסקריפט50-td-components.sh. - יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות
create_routing_componentsבסקריפט60-routing-components.sh. - יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות
create_security_componentsבסקריפט70-security-components.sh. - יוצרים את פריסת לקוח ארנק Google באמצעות
create_client_deploymentבסקריפט75-client-deployment.sh. - כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות grpc-wallet.
קובץ Bootstrap
תהליך ההגדרה במדריך הזה משתמש במחולל bootstrap כדי ליצור את קובץ ה-bootstrap הנדרש. בקטע הזה מפורט מידע על קובץ ה-bootstrap עצמו.
קובץ ה-bootstrap מכיל פרטי תצורה שנדרשים לקוד של gRPC בלי שרת Proxy, כולל פרטי חיבור לשרת xDS. קובץ ה-bootstrap מכיל הגדרת אבטחה שנדרשת לאמצעי האבטחה של gRPC בלי שרת Proxy. שרת ה-gRPC דורש שדה נוסף. קובץ bootstrap לדוגמה נראה כך:
{
"xds_servers": [
{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [
{
"type": "google_default"
}
],
"server_features": [
"xds_v3"
]
}
],
"authorities": {
"traffic-director-c2p.xds.googleapis.com": {
"xds_servers": [
{
"server_uri": "dns:///directpath-pa.googleapis.com",
"channel_creds": [
{
"type": "google_default"
}
],
"server_features": [
"xds_v3",
"ignore_resource_deletion"
]
}
],
"client_listener_resource_name_template": "xdstp://traffic-director-c2p.xds.googleapis.com/envoy.config.listener.v3.Listener/%s"
}
},
"node": {
"id": "projects/9876012345/networks/mesh:grpc-mesh/nodes/b59f49cc-d95a-4462-9126-112f794d5dd3",
"cluster": "cluster",
"metadata": {
"INSTANCE_IP": "10.28.2.8",
"TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true,
"TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": "223606568246",
"TRAFFICDIRECTOR_NETWORK_NAME": "default",
"app": "helloworld"
},
"locality": {
"zone": "us-central1-c"
}
},
"certificate_providers": {
"google_cloud_private_spiffe": {
"plugin_name": "file_watcher",
"config": {
"certificate_file": "/var/run/secrets/workload-spiffe-credentials/certificates.pem",
"private_key_file": "/var/run/secrets/workload-spiffe-credentials/private_key.pem",
"ca_certificate_file": "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem",
"refresh_interval": "600s"
}
}
},
"server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s"
}
עדכונים בקובץ האתחול של שירות האבטחה
השדות הבאים משקפים שינויים שקשורים לאבטחה ולשימוש ב-xDS v3:
השדה id בתוך node מספק זהות ייחודית ללקוח gRPC ב-Cloud Service Mesh. צריך לספק את מספר הפרויקט ואת שם הרשת באמצעות מזהה הצומת בפורמט הבא: Google Cloud
projects/{project number}/networks/{network name}/nodes/[UNIQUE_ID]
דוגמה למספר פרויקט 1234 ולרשת ברירת המחדל:
projects/1234/networks/default/nodes/client1
בשדה INSTANCE_IP מזינים את כתובת ה-IP של ה-Pod, או 0.0.0.0 כדי לציין INADDR_ANY. השדה הזה משמש את שרת ה-gRPC לאחזור משאב Listener מ-Cloud Service Mesh לצורך אבטחה בצד השרת.
שדות הגדרות האבטחה בקובץ ה-bootstrap
| מפתח JSON | סוג | ערך | הערות |
|---|---|---|---|
server_listener_resource_name_template |
String | grpc/server?xds.resource.listening_address=%s |
נדרש לשרתי gRPC. מערכת gRPC משתמשת בערך הזה כדי ליצור את שם המשאב לצורך אחזור המשאב Listener מ-Cloud Service Mesh לאבטחה בצד השרת ולהגדרות אחרות. מערכת gRPC משתמשת בערך הזה כדי ליצור את מחרוזת שם המשאב. |
certificate_providers |
מבנה JSON | google_cloud_private_spiffe |
חובה. הערך הוא מבנה JSON שמייצג מיפוי של שמות למופעים של ספקי אישורים. מופע של ספק אישורים משמש לאחזור זהות ואישורי שורש. קובץ ה-bootstrap לדוגמה מכיל שם אחד: google_cloud_private_spiffe עם מבנה JSON של מופע ספק האישורים כערך. כל מבנה JSON של מופע של ספק אישורים כולל שני שדות:
|
התוכן של מבנה ה-JSON config של התוסף file_watcher הוא:
-
certificate_file: מחרוזת חובה. הערך הזה הוא המיקום של אישור הזהות. -
private_key_file: מחרוזת חובה. הערך הוא המיקום של קובץ המפתח הפרטי, שצריך להיות זהה לזה של אישור הזהות. -
ca_certificate_file: מחרוזת חובה. הערך הוא המיקום של אישור הבסיס, שנקרא גם חבילת האמון. -
refresh_interval: מחרוזת אופציונלית. הערך מציין את מרווח הרענון, שמוגדר באמצעות ייצוג המחרוזת של מיפוי JSON של משך זמן. ערך ברירת המחדל הוא 600s, כלומר משך זמן של 10 דקות.
מחולל Bootstrap
קובץ אימג' של קונטיינר של גנרטור ה-bootstrap זמין בכתובת gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0. קוד המקור שלו זמין בכתובת https://github.com/GoogleCloudPlatform/traffic-director-grpc-bootstrap.
אלה האפשרויות הנפוצות ביותר של שורת הפקודה:
-
--output: משתמשים באפשרות הזו כדי לציין לאן ייכתב קובץ האתחול של הפלט. לדוגמה, הפקודה--output /tmp/bootstrap/td-grpc-bootstrap.jsonיוצרת את קובץ האתחול ב-/tmp/bootstrap/td-grpc-bootstrap.jsonבמערכת הקבצים של ה-Pod. -
--config-mesh-experimental: משתמשים באפשרות הזו כדי לציין את שם הרשת, שזהה למשאבMesh. -
--node-metadata: משתמשים בדגל הזה כדי לאכלס את המטא-נתונים של הצומת בקובץ האתחול. הדרישה הזו חלה כשמשתמשים במתאמי תוויות של מטא-נתונים ב-EndpointPolicy, שבו Cloud Service Mesh משתמש בנתוני התוויות שמופיעים בקטע המטא-נתונים של הצומת בקובץ האתחול. הארגומנט מסופק בפורמט key=value, לדוגמה:--node-metadata version=prod --node-metadata type=grpc
הפרטים הקודמים מוסיפים את השורות הבאות לקטע המטא-נתונים של הצומת בקובץ ה-bootstrap:
{
"node": {
...
"metadata": {
"version": "prod",
"type": "grpc",
...
},
...
},
...
}
מחיקת הפריסה
אפשר להריץ את הפקודות האלה כדי למחוק את הפריסה שיצרתם באמצעות המדריך הזה.
כדי למחוק את האשכול, מריצים את הפקודה הבאה:
gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet
כדי למחוק את המשאבים שיצרתם, מריצים את הפקודות הבאות:
gcloud compute backend-services delete grpc-gke-helloworld-service --global --quiet
gcloud compute network-endpoint-groups delete example-grpc-server --zone ZONE --quiet
gcloud compute firewall-rules delete grpc-gke-allow-health-checks --quiet
gcloud compute health-checks delete grpc-gke-helloworld-hc --quiet
gcloud network-services endpoint-policies delete ep-mtls-psms \
--location=global --quiet
gcloud network-security authorization-policies delete helloworld-gke-authz-policy \
--location=global --quiet
gcloud network-security client-tls-policies delete client-mtls-policy \
--location=global --quiet
gcloud network-security server-tls-policies delete server-tls-policy \
--location=global --quiet
gcloud network-security server-tls-policies delete server-mtls-policy \
--location=global --quiet
פתרון בעיות
ההוראות האלה יעזרו לכם לפתור בעיות בהטמעה של אמצעי האבטחה.
עומסי העבודה לא יכולים לקבל הגדרה מ-Cloud Service Mesh
אם מופיעה שגיאה דומה לזו:
PERMISSION_DENIED: Request had insufficient authentication scopes.
חשוב לוודא את הדברים הבאים:
- יצרתם את אשכול GKE באמצעות הארגומנט
--scopes=cloud-platformargument. - הקציתם את
roles/trafficdirector.clientלחשבונות השירות של Kuberneters. - הקצית את
roles/trafficdirector.clientלחשבון השירות Google Cloud שמוגדר כברירת מחדל (${GSA_EMAIL} למעלה). - הפעלתם את השירות (API) של
trafficdirector.googleapis.com.
שרת ה-gRPC לא משתמש ב-TLS/mTLS גם אם הגדרת Cloud Service Mesh נכונה
צריך לוודא שציינתם את GRPC_SERVER בהגדרות של מדיניות נקודות הקצה. אם ציינתם את SIDECAR_PROXY, פרוטוקול gRPC מתעלם מההגדרה.
אי אפשר ליצור את אשכול GKE עם גרסת האשכול המבוקשת
יכול להיות שהפקודה ליצירת אשכול GKE תיכשל עם שגיאה כמו:
Node version "1.20.5-gke.2000" is unsupported.
מוודאים שמשתמשים בארגומנט --release-channel rapid בפקודה ליצירת האשכול. כדי לקבל את הגרסה הנכונה של הגרסה הזו, צריך להשתמש בערוץ ההפצה המהירה.
מוצגת השגיאה No usable endpoint
אם לקוח לא יכול לתקשר עם השרת בגלל שגיאה No usable endpoint
יכול להיות שכלי הבדיקה של תקינות השרתים סימן את השרתים העורפיים כלא תקינים.
כדי לבדוק את תקינות השרתים העורפיים, מריצים את הפקודה gcloud הבאה:
gcloud compute backend-services get-health grpc-gke-helloworld-service --global
אם הפקודה מחזירה את הסטטוס של ה-backend כלא תקין, יכולות להיות לכך כמה סיבות:
- חומת האש לא נוצרה או שהיא לא מכילה את טווח כתובות ה-IP הנכון של המקור.
- תגי היעד בחומת האש לא תואמים לתגים באשכול שיצרתם.
עומסי העבודה לא יכולים לתקשר בהגדרת האבטחה
אם עומסי העבודה לא מצליחים לתקשר אחרי שמגדירים אבטחה ל-Service mesh בלי שרת Proxy, צריך לפעול לפי ההוראות האלה כדי לגלות את הסיבה.
- השבתת אבטחה בלי שרת Proxy ופתרון בעיות בתרחישי שימוש של איזון עומסים ב-Service mesh בלי שרת Proxy. כדי להשבית את האבטחה ברשת, מבצעים אחת מהפעולות הבאות:
- שימוש בהרשאות בטקסט פשוט בצד הלקוח ובצד השרת או
- לא מגדירים אבטחה לשירות לקצה העורפי ולמדיניות נקודת הקצה בהגדרות של Cloud Service Mesh.
פועלים לפי השלבים במאמר פתרון בעיות בפריסות של Cloud Service Mesh ללא שרת proxy, כי אין הגדרת אבטחה בפריסה.
משנים את עומסי העבודה כך שישתמשו בפרטי כניסה של xDS עם טקסט פשוט או פרטי כניסה לא מאובטחים כפרטי הכניסה החלופיים. משאירים את ההגדרה של Cloud Service Mesh עם אבטחה מושבתת, כמו שצוין קודם. במקרה הזה, למרות ש-gRPC מאפשר ל-Cloud Service Mesh להגדיר אבטחה, Cloud Service Mesh לא שולח מידע אבטחה, ולכן gRPC צריך לחזור לשימוש בפרטי כניסה בטקסט פשוט (או לא מאובטח), שצריכים לפעול באופן דומה למקרה הראשון הקודם. אם זה לא עובד, אפשר לנסות את הפעולות הבאות:
- להגדיל את רמת הרישום ביומן בצד הלקוח ובצד השרת, כדי שתוכלו לראות את הודעות ה-xDS שהועברו בין gRPC לבין Cloud Service Mesh.
- מוודאים ש-Cloud Service Mesh לא מפעיל אבטחה בתגובות של CDS ו-LDS שנשלחות לעומסי העבודה.
- מוודאים שעומסי העבודה לא משתמשים במצבי TLS או mTLS בערוצים שלהם. אם מופיעות הודעות יומן שקשורות ללחיצות יד של TLS, צריך לבדוק את קוד המקור של האפליקציה ולוודא שאתם משתמשים בטקסט לא מאובטח או בטקסט רגיל כגיבוי לפרטי הכניסה. אם קוד המקור של האפליקציה תקין, יכול להיות שמדובר בבאג בספריית gRPC
כדי לוודא שהשילוב של שירות CA עם GKE פועל בצורה תקינה באשכול GKE, צריך לפעול לפי השלבים לפתרון בעיות שמפורטים במדריך למשתמש. חשוב לוודא שהאישורים והמפתחות שסופקו על ידי התכונה הזו זמינים בספרייה שצוינה,
/var/run/secrets/workload-spiffe-credentials/.מפעילים TLS (במקום mTLS) ברשת, כמו שמתואר למעלה, ומפעילים מחדש את עומסי העבודה של הלקוח והשרת.
- כדי לראות את הודעות xDS שמועברות בין gRPC לבין Cloud Service Mesh, צריך להגדיל את רמת הרישום ביומן בצד הלקוח ובצד השרת.
- מוודאים ש-Cloud Service Mesh הפעיל אבטחה בתגובות של CDS ו-LDS שנשלחות לעומסי העבודה.
הלקוח נכשל עם CertificateException וההודעה Peer certificate SAN check failed
המשמעות היא שיש בעיה בערכים של subjectAltNames בהודעה SecuritySettings. שימו לב שהערכים האלה מבוססים על שירותי Kubernetes שיצרתם עבור שירות לקצה העורפי. לכל שירות Kubernetes שיצרתם יש מזהה SPIFFE משויך, בפורמט הבא:
spiffe://${WORKLOAD_POOL}/ns/${K8S_NAMESPACE}/sa/${SERVICE_ACCOUNT}
הערכים האלה הם:
-
WORKLOAD_POOL: מאגר הזהויות של עומסי העבודה של האשכול, שהוא${PROJECT_ID}.svc.id.goog -
K8S_NAMESPACE: מרחב השמות של Kubernetes שבו השתמשתם בפריסת השירות -
SERVICE_ACCOUNT: חשבון השירות של Kubernetes שבו השתמשתם בפריסה של השירות
לכל שירות Kubernetes שצירפתם לשירות לקצה העורפי כקבוצת נקודות קצה ברשת, ודאו שחישבתם נכון את מזהה SPIFFE והוספתם את מזהה SPIFFE הזה לשדה subjectAltNames בהודעה SecuritySettings.
אי אפשר להשתמש באישורי mTLS עם ספריית gRPC
אם האפליקציות לא יכולות להשתמש באישורי mTLS עם ספריית gRPC, צריך לבצע את הפעולות הבאות:
מוודאים שמפרט ה-Pod מכיל את ההערה
security.cloud.google.com/use-workload-certificatesשמתוארת במאמר יצירת שירות gRPC בלי שרת Proxy עם NEGs.מוודאים שאפשר לגשת לקבצים שמכילים את שרשרת האישורים, את אישור העלה, את המפתח הפרטי ואת האישורים של רשות האישורים המהימנה בנתיבים הבאים מתוך ה-Pod:
- שרשרת האישורים יחד עם אישור הקצה: "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
- מפתח פרטי: /var/run/secrets/workload-spiffe-credentials/private_key.pem
- חבילת CA: "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"
אם האישורים מהשלב הקודם לא זמינים, צריך לבצע את הפעולות הבאות:
gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME
--location=LOCATIONמוודאים שלמישור הבקרה של GKE יש את הקישור הנכון לתפקיד IAM, שמעניק לו גישה לשירות CA:
# Get the IAM policy for the CA gcloud privateca roots get-iam-policy ROOT_CA_POOL_NAME # Verify that there is an IAM binding granting access in the following format - members: - serviceAccount:service-projnumber@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.certificateManager # Where projnumber is the project number (e.g. 2915810291) for the GKE cluster.
מוודאים שתוקף האישור לא פג. זו שרשרת האישורים ואישור הקצה בכתובת
/var/run/secrets/workload-spiffe-credentials/certificates.pem. כדי לבדוק, מריצים את הפקודה הבאה:cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
מריצים את הפקודה הבאה כדי לוודא שסוג המפתח נתמך באפליקציה:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
מוודאים שלאפליקציית gRPC Java יש את ההגדרות הבאות
keyAlgorithmבקובץWorkloadCertificateConfigYAML:
keyAlgorithm: rsa: modulusSize: 4096מוודאים שרשות האישורים משתמשת באותה משפחת מפתחות כמו מפתח האישור.
האישור של האפליקציה נדחה על ידי הלקוח, השרת או העמית
- מוודאים שאפליקציית העמיתים משתמשת באותו חבילת אמון כדי לאמת את האישור.
- מוודאים שתוקף האישור שבשימוש לא פג (שרשרת האישורים יחד עם אישור הקצה: /var/run/secrets/workload-spiffe-credentials/certificates.pem).
הפודים נשארים במצב המתנה
אם ה-Pods נשארים במצב 'בהמתנה' במהלך תהליך ההגדרה, צריך להגדיל את משאבי ה-CPU והזיכרון של ה-Pods במפרט הפריסה.
לא ניתן ליצור אשכול עם הדגל --enable-mesh-certificates
מוודאים שאתם מריצים את הגרסה העדכנית של ה-CLI של gcloud:
gcloud components update
הערה: הדגל --enable-mesh-certificates פועל רק עם gcloud beta.
פודים לא מופעלים
יכול להיות ש-Pods שמשתמשים באישורים של GKE mesh לא יופעלו אם הקצאת האישורים נכשלת. מצב כזה יכול לקרות במקרים הבאים:
- ההגדרה של
WorkloadCertificateConfigאו שלTrustConfigשגויה או שהם חסרים. - בקשות CSR לא מאושרות.
כדי לבדוק אם הקצאת האישורים נכשלת, בודקים את אירועי ה-Pod.
בודקים את הסטטוס של ה-Pod:
kubectl get pod -n POD_NAMESPACE POD_NAMEמחליפים את מה שכתוב בשדות הבאים:
-
POD_NAMESPACE: מרחב השמות של ה-Pod. -
POD_NAME: השם של ה-Pod.
-
כדי לבדוק אירועים אחרונים ב-Pod:
kubectl describe pod -n POD_NAMESPACE POD_NAMEאם הקצאת האישורים נכשלת, יוצג אירוע עם
Type=Warning,Reason=FailedMount,From=kubeletושדהMessageשמתחיל ב-MountVolume.SetUp failed for volume "gke-workload-certificates". השדהMessageמכיל מידע לפתרון בעיות.Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedMount 13s (x7 over 46s) kubelet MountVolume.SetUp failed for volume "gke-workload-certificates" : rpc error: code = Internal desc = unable to mount volume: store.CreateVolume, err: unable to create volume "csi-4d540ed59ef937fbb41a9bf5380a5a534edb3eedf037fe64be36bab0abf45c9c": caPEM is nil (check active WorkloadCertificateConfig)אם ה-Pods לא מופעלים בגלל אובייקטים שהוגדרו בצורה שגויה או בגלל בקשות חתימה על אישורים (CSR) שנדחו, כדאי לפעול לפי השלבים הבאים לפתרון בעיות.
ההגדרה של WorkloadCertificateConfig או TrustConfig שגויה
מוודאים שיצרתם את האובייקטים WorkloadCertificateConfig ו-TrustConfig בצורה נכונה. אפשר לאבחן הגדרות שגויות באחד מהאובייקטים האלה באמצעות kubectl.
אחזור הסטטוס הנוכחי.
עבור
WorkloadCertificateConfig:kubectl get WorkloadCertificateConfig default -o yamlעבור
TrustConfig:kubectl get TrustConfig default -o yamlבודקים את פלט הסטטוס. אובייקט תקין יכלול תנאי עם
type: Readyו-status: "True".status: conditions: - lastTransitionTime: "2021-03-04T22:24:11Z" message: WorkloadCertificateConfig is ready observedGeneration: 1 reason: ConfigReady status: "True" type: Readyבמקום זאת, מופיע
status: "False"לאובייקטים לא תקינים. השדותreasonוmessageמכילים פרטים נוספים לפתרון בעיות.
בקשות CSR לא מאושרות
אם משהו משתבש במהלך תהליך אישור ה-CSR, אפשר לבדוק את פרטי השגיאה בתנאים type: Approved ו-type: Issued של ה-CSR.
מציגים רשימה של בקשות CSR רלוונטיות באמצעות
kubectl:kubectl get csr \ --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'בוחרים בקובץ CSR שערכו הוא
ApprovedולאIssued, או שערכו לאApproved.כדי לקבל פרטים על בקשת ה-CSR שנבחרה באמצעות kubectl:
kubectl get csr CSR_NAME -o yamlמחליפים את
CSR_NAMEבשם של בקשת ה-CSR שבחרתם.
בקשת חתימה על אישור (CSR) תקינה כוללת תנאי עם type: Approved ו-status: "True", ואישור תקין בשדה status.certificate:
status:
certificate: <base64-encoded data>
conditions:
- lastTransitionTime: "2021-03-04T21:58:46Z"
lastUpdateTime: "2021-03-04T21:58:46Z"
message: Approved CSR because it is a valid SPIFFE SVID for the correct identity.
reason: AutoApproved
status: "True"
type: Approved
מידע לפתרון בעיות שקשורות לבקשות CSR לא תקינות מופיע בשדות message ו-reason.
חסרים אישורים ב-Pods
מקבלים את מפרט ה-Pod של ה-Pod:
kubectl get pod -n POD_NAMESPACE POD_NAME -o yamlמחליפים את מה שכתוב בשדות הבאים:
-
POD_NAMESPACE: מרחב השמות של ה-Pod. -
POD_NAME: השם של ה-Pod.
-
מוודאים שמפרט ה-Pod מכיל את ההערה
security.cloud.google.com/use-workload-certificatesשמתוארת במאמר הגדרת Pods לקבלת פרטי כניסה של mTLS.מוודאים שפקדת הכניסה של אישורי GKE mesh הצליחה להוסיף נפח של מנהל התקן CSI מסוג
workloadcertificates.security.cloud.google.comלמפרט ה-Pod:volumes: ... -csi: driver: workloadcertificates.security.cloud.google.com name: gke-workload-certificates ...בודקים אם יש נפח שמוצמד לכל אחד מהקונטיינרים:
containers: - name: ... ... volumeMounts: - mountPath: /var/run/secrets/workload-spiffe-credentials name: gke-workload-certificates readOnly: true ...מוודאים שחבילות האישורים הבאות והמפתח הפרטי זמינים במיקומים הבאים ב-Pod:
- חבילת שרשרת אישורים:
/var/run/secrets/workload-spiffe-credentials/certificates.pem - מפתח פרטי:
/var/run/secrets/workload-spiffe-credentials/private_key.pem - חבילת ישויות עוגן אמינות של רשות אישורים (CA):
/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
- חבילת שרשרת אישורים:
אם הקבצים לא זמינים, מבצעים את הפעולות הבאות:
מאחזרים את מופע שירות ה-CA (תצוגה מקדימה) עבור האשכול:
kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'אחזור הסטטוס של מופע CA Service (Preview):
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATIONמחליפים את מה שכתוב בשדות הבאים:
-
ISSUING_CA_TYPE: סוג רשות האישורים המנפיקה, שחייב להיותsubordinatesאוroots. -
ISSUING_CA_NAME: השם של רשות האישורים המנפיקה. -
ISSUING_CA_LOCATION: האזור של הרשות שמנפיקה את האישורים (CA).
-
מקבלים את מדיניות ה-IAM עבור רשות האישורים הבסיסית:
gcloud privateca roots get-iam-policy ROOT_CA_NAMEמחליפים את
ROOT_CA_NAMEבשם של רשות האישורים הבסיסית.במדיניות IAM, מוודאים שקיים
privateca.auditorpolicy binding:... - members: - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.auditor ...בדוגמה הזו,
PROJECT_NUMBERהוא מספר הפרויקט של האשכול.מקבלים את מדיניות ה-IAM עבור רשות אישורים משנית:
gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAMEמחליפים את
SUBORDINATE_CA_NAMEבשם של רשות אישורים משנית.במדיניות IAM, מוודאים שקיים
privateca.certificateManagerקישור למדיניות:... - members: - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.certificateManager ...בדוגמה הזו,
PROJECT_NUMBERהוא מספר הפרויקט של האשכול.
לא ניתן להשתמש באישורי mTLS שהונפקו באפליקציות
מוודאים שתוקף האישור לא פג:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"בודקים שסוג המפתח שבו השתמשתם נתמך על ידי האפליקציה.
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3בודקים שרשות האישורים שהנפיקה את האישור משתמשת באותה משפחת מפתחות כמו מפתח האישור.
קבלת הסטטוס של שירות ה-CA (תצוגה מקדימה):
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATIONמחליפים את מה שכתוב בשדות הבאים:
-
ISSUING_CA_TYPE: סוג רשות האישורים המנפיקה, שחייב להיותsubordinatesאוroots. -
ISSUING_CA_NAME: השם של רשות האישורים המנפיקה. -
ISSUING_CA_LOCATION: האזור של הרשות שמנפיקה את האישורים (CA).
-
בודקים שאלגוריתם המפתח
keySpec.algorithmבפלט זהה לזה שהגדרתם במניפסט YAML שלWorkloadCertificateConfig. הפלט אמור להיראות כך:config: ... subjectConfig: commonName: td-sub-ca subject: organization: TestOrgLLC subjectAltName: {} createTime: '2021-05-04T05:37:58.329293525Z' issuingOptions: includeCaCertUrl: true keySpec: algorithm: RSA_PKCS1_2048_SHA256 ...
האישורים נדחים
- מוודאים שאפליקציית העמיתים משתמשת באותו חבילת אמון כדי לאמת את האישור.
מוודאים שתוקף האישור לא פג:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"אם לא משתמשים ב-Credentials Reloading API של gRPC Go, צריך לוודא שקוד הלקוח מרענן מעת לעת את פרטי הכניסה ממערכת הקבצים.
מוודאים שעומסי העבודה נמצאים באותו דומיין מהימן כמו רשות האישורים. אישורים של GKE mesh תומכים בתקשורת בין עומסי עבודה בדומיין אמון יחיד.
מגבלות
אבטחת שירותים ב-Cloud Service Mesh נתמכת רק ב-GKE. אי אפשר לפרוס אבטחת שירות באמצעות Compute Engine.
Cloud Service Mesh לא תומך בתרחישים שבהם יש שני משאבי מדיניות של נקודות קצה או יותר שתואמים באופן שווה לנקודת קצה. לדוגמה, שתי מדיניות עם אותן תוויות ואותם פורטים, או שתי מדיניות או יותר עם תוויות שונות שתואמות באופן שווה לתוויות של נקודת קצה. מידע נוסף על האופן שבו מתבצעת התאמה בין מדיניות נקודות קצה לתוויות של נקודת קצה זמין במאמר בנושא ממשקי API ל-EndpointPolicy.EndpointMatcher.MetadataLabelMatcher. במקרים כאלה, Cloud Service Mesh לא יוצר הגדרת אבטחה מאף אחת ממדיניות ההרשאה שמתנגשות.