הגדרת אבטחת שירות באמצעות gRPC ללא proxy

במדריך הזה מוסבר איך להגדיר שירות אבטחה ל-Service mesh של gRPC ללא שרת proxy.

דרישות

לפני שמגדירים אבטחת שירות ל-Service mesh ללא proxy של gRPC, צריך לוודא שמתקיימות הדרישות הבאות.

הגדרת ניהול זהויות והרשאות גישה (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 הם:

  1. הגדרת שירות CA, שבו יוצרים מאגרי CA פרטיים ואת רשויות האישורים הנדרשות.
  2. יצירת אשכול GKE עם תכונות של איחוד זהויות של עומסי עבודה ב-GKE ואישורי mesh, ושילוב של שירות CA.
  3. הגדרת הנפקת אישורים לרשת באשכול.
  4. יצירת חשבונות השירות של הלקוח והשרת.
  5. הגדרת שרת לדוגמה שמשתמש בממשקי xDS API ובפרטי כניסה של שרת xDS כדי לקבל הגדרת אבטחה מ-Cloud Service Mesh.
  6. הגדרת לקוח לדוגמה שמשתמש בהרשאות xDS.
  7. עדכון ההגדרה של 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 הנדרשים.

  1. מריצים את הפקודה הבאה כדי להפעיל את 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
    
  2. מריצים את הפקודה הבאה כדי לאפשר לחשבון השירות שמוגדר כברירת מחדל לגשת ל-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 ולהגדיר בו אישורי רשת, כמו שמתואר במאמר יצירת רשויות אישורים להנפקת אישורים.
  1. יוצרים אשכול חדש שמשתמש באיחוד זהויות של עומסי עבודה ל-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
    

    יצירת האשכול עשויה להימשך כמה דקות.

  2. אם אתם משתמשים באשכול קיים, אתם צריכים להפעיל את איחוד הזהויות של עומסי עבודה ל-GKE ואת האישורים של GKE Mesh. מוודאים שהאשכול נוצר עם הדגל --enable-ip-alias, שלא ניתן להשתמש בו עם הפקודה update.

    gcloud container clusters update CLUSTER_NAME \
      --enable-mesh-certificates
    
  3. מריצים את הפקודה הבאה כדי לעבור לאשכול החדש כאשכול ברירת המחדל עבור פקודות kubectl:

    gcloud container clusters get-credentials CLUSTER_NAME \
      --zone ZONE
    

רישום אשכולות ב-Fleet

רושמים את האשכול שיצרתם או עדכנתם במאמר יצירת אשכול GKE בצי. רישום האשכול מקל על הגדרת אשכולות בפרויקטים מרובים.

הערה: כל אחד מהשלבים האלה עשוי להימשך עד עשר דקות.

  1. רושמים את האשכול ב-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.
  2. מחילים את קובץ המניפסט שנוצר על האשכול:

    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
    
  3. מקבלים את משאב החברות מהאשכול:

    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
  1. נותנים את הרשאת 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
    
  2. מקצים את התפקיד role/privateca.admin בשירות CA לאנשים שצריכים לשנות את כללי המדיניות של IAM, כאשר MEMBER הוא אדם שצריך את הגישה הזו, במיוחד כל אדם שמבצע את השלבים הבאים שנותנים את התפקידים privateca.auditor ו-privateca.certificateManager:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.admin
    
  3. יוצרים את המאגר של שירות רשות האישורים (CA) הבסיסית.

    gcloud privateca pools create ROOT_CA_POOL_NAME \
      --location ROOT_CA_POOL_LOCATION \
      --tier enterprise
    
  4. יוצרים רשות אישורים (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"
  5. יוצרים את המאגר המשני ואת רשות האישורים המשנית. מוודאים שמצב ההנפקה מבוסס-ההגדרה שמוגדר כברירת מחדל עדיין מותר.

    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
  6. מקצים את התפקיד 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"
    
  7. מקצים את התפקיד 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"
    
  8. שומרים את הגדרת ה-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
  9. שומרים את הגדרת ה-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
  10. מחילים את ההגדרות על האשכול:

    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 של השירות כדי לציין את שם ה-NEG‏ example-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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט:

    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++‎

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט:

    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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט:

    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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט:

    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
    

    כך משלימים את התהליך.

  1. החלת המפרט:

    kubectl apply -f example-grpc-server.yaml
    
  2. מקצים לחשבון השירות את התפקידים הנדרשים:

    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
    
  3. מריצים את הפקודות האלה כדי לוודא שהשירות וה-Pod נוצרו בצורה נכונה:

    kubectl get deploy/example-grpc-server
    kubectl get svc/example-grpc-server
    
  4. מוודאים שהשם של ה-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. לכן, מומלץ להשתמש בגישה הראשונה.

  1. יוצרים את בדיקת התקינות. שימו לב: בדיקת תקינות מתחילה רק אחרי שיוצרים את השרת ומפעילים אותו.

    • אם אתם יוצרים יציאה ייעודית להצגת נתונים לצורך בדיקת תקינות, וזו הגישה המומלצת שלנו, אתם צריכים להשתמש בפקודה הזו:

      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
      
  2. יוצרים את חומת האש. מוודאים שהערך של --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
    
  3. יוצרים את שירות הקצה העורפי:

    gcloud compute backend-services create grpc-gke-helloworld-service \
       --global \
       --load-balancing-scheme=INTERNAL_SELF_MANAGED \
       --protocol=GRPC \
       --health-checks grpc-gke-helloworld-hc
    
  4. מצרפים את ה-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.

  1. יוצרים את המפרט Mesh ושומרים אותו בקובץ בשם mesh.yaml.

    name: grpc-mesh
    
  2. מייבאים את המשאב Mesh מהמפרט.

    gcloud network-services meshes import grpc-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. יוצרים את המפרט 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
    
  4. מייבאים את המשאב 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 שמכיל את הערכים של משאב מדיניות נקודת הקצה, על סמך המדיניות שכבר הגדרתם.

  1. יוצרים קובץ זמני 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
    
  2. יוצרים משאב מדיניות 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
    
  3. יוצרים את מדיניות נקודת הקצה על ידי יצירת הקובץ הזמני 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
    
  4. מייבאים את הקובץ ep-mtls-psms.yaml כדי ליצור את משאב מדיניות נקודת הקצה:

    gcloud beta network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

הגדרת mTLS בצד הלקוח

מדיניות האבטחה בצד הלקוח מצורפת לשירות הקצה העורפי. כשלקוח ניגש לחלק האחורי (שרת gRPC) דרך שירות החלק האחורי, מדיניות האבטחה בצד הלקוח שמצורפת נשלחת ללקוח.

  1. יוצרים את התוכן של משאב מדיניות TLS של הלקוח בקובץ זמני בשם client-mtls-policy.yaml בספרייה הנוכחית:

    name: "client-mtls-policy"
    clientCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. יוצרים את משאב מדיניות 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
    
  3. יוצרים קטע קוד בקובץ זמני כדי להפנות למדיניות הזו ומוסיפים פרטים לגבי 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
    
  4. מוסיפים את ההודעה 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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט הבא:

    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++‎

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט הבא:

    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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט הבא:

    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

  1. מריצים את הפקודה הבאה כדי לוודא שמספר הפרויקט מוגדר בצורה נכונה:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. יוצרים את המפרט הבא:

    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
    

כך משלימים את התהליך.

  1. החלת המפרט:

    kubectl apply -f example-grpc-client.yaml
    
  2. מקצים לחשבון השירות את התפקידים הנדרשים:

    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
    
  3. מוודאים ש-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

  1. כדי לקבל את השם של ה-Pod שנוצר עבור השירות example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    יוצג משוב כמו זה:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של השרת:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. במעטפת, מוודאים שקובץ האתחול בנתיב /tmp/grpc-xds/td-grpc-bootstrap.json תואם לסכימה שמתוארת בקטע קובץ האתחול.

  4. מורידים את 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
    
  5. מריצים את השרת עם הדגל --xds-creds כדי לציין אבטחה עם xDS, באמצעות 50051 כיציאת ההאזנה ו-xds-server כשם הזיהוי של השרת:

    ./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
    
  6. אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:

    Listening on port 50051
    plain text health service listening on port 50052
    

C++‎

  1. כדי לקבל את השם של ה-Pod שנוצר עבור השירות example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    יוצג משוב כמו זה:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של השרת:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. במעטפת, מוודאים שקובץ האתחול בנתיב /tmp/grpc-xds/td-grpc-bootstrap.json תואם לסכימה שמתוארת בקטע קובץ האתחול.

  4. מורידים את 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
    
  5. מריצים את השרת באמצעות 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
    
  6. אחרי שהשרת מקבל את ההגדרה הנדרשת מ-Cloud Service Mesh, מוצגת הפלט הבא:

    Listening on port 50051
    plain text health service listening on port 50052
    

Python

  1. כדי לקבל את השם של ה-Pod שנוצר עבור השירות example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    יוצג משוב כמו זה:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של השרת:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. במעטפת, מוודאים שקובץ האתחול בנתיב /tmp/grpc-xds/td-grpc-bootstrap.json תואם לסכימה שמתוארת בקטע קובץ האתחול.

  4. מורידים את 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
    

  5. מריצים את השרת עם הדגל --xds-creds כדי לציין אבטחה עם xDS, באמצעות 50051 כפורט ההאזנה.

    python3 server.py 50051 --xds-creds
    
  6. אחרי שהשרת מקבל את ההגדרה הנדרשת מ-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

  1. כדי לקבל את השם של ה-Pod שנוצר עבור השירות example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    יוצג משוב כמו זה:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של השרת:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
    
  3. במעטפת, מוודאים שקובץ האתחול בנתיב /tmp/grpc-xds/td-grpc-bootstrap.json תואם לסכימה שמתוארת בקטע קובץ האתחול.

  4. מורידים את 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
    
    
  5. בונים ומריצים את השרת עם הדגל --xds_creds כדי לציין אבטחה עם xDS, באמצעות 50051 כיציאת ההאזנה:

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -port 50051
    
  6. אחרי שהשרת מקבל את ההגדרה הנדרשת מ-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

  1. משיגים את השם של ה-Pod של הלקוח:

    kubectl get pods | grep example-grpc-client
    

    מוצג לכם משוב כמו זה:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של הלקוח:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. במעטפת הפקודות, מורידים את 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
    
  4. מריצים את הלקוח עם הדגל --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++‎

  1. משיגים את השם של ה-Pod של הלקוח:

    kubectl get pods | grep example-grpc-client
    

    מוצג לכם משוב כמו זה:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של הלקוח:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. אחרי שנכנסים למעטפת, מורידים את 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_client
    
  4. מריצים את הלקוח עם הדגל --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

  1. משיגים את השם של ה-Pod של הלקוח:

    kubectl get pods | grep example-grpc-client
    

    מוצג לכם משוב כמו זה:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של הלקוח:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. אחרי שנכנסים למעטפת, מורידים את 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
    
  4. מריצים את הלקוח עם הסימון --xds-creds כדי לציין אבטחה עם הפעלת xDS, שם לקוח ומחרוזת חיבור ליעד:

    python3 client.py xds:///helloworld-gke:8000 --xds-creds
    

    הפלט אמור להיראות כך:

    Greeter client received: Hello you from example-host!
    

Go

  1. משיגים את השם של ה-Pod של הלקוח:

    kubectl get pods | grep example-grpc-client
    

    מוצג לכם משוב כמו זה:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. פותחים מעטפת ל-Pod של הלקוח:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
    
  3. אחרי שנכנסים למעטפת, מורידים את 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
    
  4. בונים ומריצים את הלקוח עם הדגל --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.

  1. עדכון המפרט GRPCRoute שאוחסן בעבר ב-grpc_route.yaml

    name: 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
    
  2. מייבאים שוב את המשאב 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

  1. יוצרים מדיניות הרשאות על ידי יצירת קובץ בשם 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
    
  2. מייבאים את המדיניות.

    gcloud network-security authorization-policies import \
      helloworld-gke-authz-policy \
      --source=helloworld-gke-authz-policy.yaml \
      --location=global
    
  3. מעדכנים את מדיניות נקודת הקצה כך שתפנה למדיניות ההרשאות החדשה על ידי הוספת השורה הבאה לקובץ ep-mtls-psms.yaml.

    authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
    

    במדיניות של נקודת הקצה מצוין עכשיו שצריך לאכוף גם mTLS וגם מדיניות הרשאות על בקשות נכנסות ל-Pods שקבצי ה-bootstrap של gRPC שלהם מכילים את התווית app:helloworld.

  4. מייבאים את המדיניות:

    gcloud network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

אימות מדיניות ההרשאות

כדי לוודא שמדיניות ההרשאות פועלת בצורה תקינה, פועלים לפי ההוראות הבאות.

Java

  1. פותחים מעטפת (shell) לפוד הלקוח שבו השתמשתם קודם.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. במעטפת הפקודות, מריצים את הפקודות הבאות כדי לאמת את ההגדרה.

    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
    
  3. מריצים את הלקוח שוב עם שם השרת החלופי. שימו לב שזהו מקרה של כשל. הבקשה לא חוקית כי מדיניות ההרשאה מאפשרת גישה רק לשם המארח 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

  1. פותחים מעטפת (shell) לפוד הלקוח שבו השתמשתם קודם.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. במעטפת הפקודות, מריצים את הפקודות הבאות כדי לאמת את ההגדרה.

    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
    
  3. מריצים את הלקוח שוב עם שם השרת החלופי. שימו לב שזהו מקרה של כשל. הבקשה לא חוקית כי מדיניות ההרשאה מאפשרת גישה רק לשם המארח 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 צריך לבצע שינוי קטן בלבד.

  1. ב-ServerTlsPolicy, מחזירים את mtlsPolicy:

    cat << EOF > server-tls-policy.yaml
    name: "server-tls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    
  2. במקומה, צריך להשתמש במדיניות 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
    
  3. ההגדרה 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 .

כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:

  1. משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
  2. עורכים את הקובץ 00-common-env.sh. מוסיפים הערה לשורה הקיימת שקובעת את הערך של WALLET_DOCKER_IMAGE לקובץ אימג' של Go Docker, ומבטלים סימון כהערה (uncomment) בשורה שקובעת את הערך של WALLET_DOCKER_IMAGE לקובץ אימג' של Java Docker.
  3. יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה create_cloud_router_instances בסקריפט 10.apis.sh.
  4. יוצרים אשכול באמצעות ההוראות לדוגמה hello world או הפונקציה create_cluster בסקריפט 20-cluster.sh.
  5. יוצרים רשויות אישורים פרטיות באמצעות ההוראות ל-CA Service או באמצעות הסקריפט 30-private-ca-setup.sh.
  6. יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים: account,‏ stats,‏ stats_premium,‏ wallet_v1,‏ wallet_v2, באמצעות הסקריפט 40-k8s-resources.sh.
  7. לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות create_health_check ו-create_backend_service בסקריפט 50-td-components.sh.
  8. יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות create_routing_components בסקריפט 60-routing-components.sh.
  9. יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות create_security_components בסקריפט 70-security-components.sh.
  10. יוצרים את פריסת לקוח ארנק Google באמצעות create_client_deployment בסקריפט 75-client-deployment.sh.
  11. כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות grpc-wallet.

C++‎

אפשר למצוא את קוד המקור לדוגמה עבור C++‎ ב-github. הקוד כבר משתמש בפרטי הכניסה XdsChannel ו-XdsServer כשמגדירים אבטחה בלי שרת Proxy.

בהוראות האלה מתואר איך להגדיר את הדוגמה ל-Wallet באמצעות Go. התהליך דומה ל-C++‎. ההוראות מתייחסות לתמונת Docker קיימת מראש שאפשר לקבל ממאגר מאגרי הנתונים שלGoogle Cloud .

כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:

  1. משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
  2. עורכים את הקובץ 00-common-env.sh. מסמנים כהערה את השורה הקיימת שקובעת את הערך של WALLET_DOCKER_IMAGE לקובץ אימג' של Go Docker ומבטלים את הסימון כהערה בשורה שקובעת את הערך של WALLET_DOCKER_IMAGE לקובץ אימג' של C++ Docker.
  3. יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה create_cloud_router_instances בסקריפט 10.apis.sh.
  4. יוצרים אשכול באמצעות ההוראות לדוגמה hello world או הפונקציה create_cluster בסקריפט 20-cluster.sh.
  5. יוצרים רשויות אישורים פרטיות באמצעות ההוראות לשימוש בשירות CA או באמצעות הסקריפט 30-private-ca-setup.sh.
  6. יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים: account,‏ stats,‏ stats_premium,‏ wallet_v1,‏ wallet_v2, באמצעות הסקריפט 40-k8s-resources.sh.
  7. לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות create_health_check ו-create_backend_service בסקריפט 50-td-components.sh.
  8. יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות create_routing_components בסקריפט 60-routing-components.sh.
  9. יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות create_security_components בסקריפט 70-security-components.sh.
  10. יוצרים את פריסת לקוח ארנק Google באמצעות create_client_deployment בסקריפט 75-client-deployment.sh.
  11. כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות grpc-wallet.

Go

קוד מקור לדוגמה ל-Go זמין ב-github. הקוד כבר משתמש בפרטי הכניסה של XdsChannel ושלXdsServer כשמגדירים אבטחה בלי שרת Proxy.

ההוראות מתייחסות לקובץ אימג' קיים של Docker שמתקבל מGoogle Cloud מאגר קונטיינרים.

כדי ליצור את הדוגמה, פועלים לפי ההוראות הבאות:

  1. משכפלים את מאגר הקוד ומקבלים את הקבצים בספרייה gRPC examples.
  2. עורכים את הקובץ 00-common-env.sh כדי להגדיר את הערכים הנכונים למשתני הסביבה.
  3. יוצרים ומגדירים מופעים של Cloud Router באמצעות ההוראות שבמאמר יצירה והגדרה של מופעים של Cloud Router או באמצעות הפונקציה create_cloud_router_instances בסקריפט 10.apis.sh.
  4. יוצרים אשכול באמצעות ההוראות לדוגמה hello world או הפונקציה create_cluster בסקריפט 20-cluster.sh.
  5. יוצרים רשויות אישורים פרטיות באמצעות ההוראות ל-CA Service או באמצעות הסקריפט 30-private-ca-setup.sh.
  6. יצירת משאבי Kubernetes, כולל חשבונות שירות, מרחבי שמות, שירותי Kubernetes, קבוצות נקודות קצה ברשת (NEGs) ופריסה בצד השרת לכל השירותים: account,‏ stats,‏ stats_premium,‏ wallet_v1,‏ wallet_v2, באמצעות הסקריפט 40-k8s-resources.sh.
  7. לכל אחד מהשירותים שיצרתם, יוצרים בדיקת תקינות ושירות קצה עורפי באמצעות create_health_check ו-create_backend_service בסקריפט 50-td-components.sh.
  8. יוצרים את רכיבי הניתוב של Cloud Service Mesh באמצעות create_routing_components בסקריפט 60-routing-components.sh.
  9. יוצרים את רכיבי האבטחה של Cloud Service Mesh לכל שירות לקצה העורפי באמצעות create_security_components בסקריפט 70-security-components.sh.
  10. יוצרים את פריסת לקוח ארנק Google באמצעות create_client_deployment בסקריפט 75-client-deployment.sh.
  11. כדי לאמת את ההגדרה, מפעילים את הלקוח כמו שמתואר במאמר בנושא אימות באמצעות לקוחות 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 של מופע של ספק אישורים כולל שני שדות:
  • plugin_name. ערך חובה שמזהה את התוסף של ספק האישורים שבו צריך להשתמש, כנדרש בארכיטקטורת התוספים של gRPC לספקי אישורים. ל-gRPC יש תמיכה מובנית בתוסף file-watcher שמשמש בהגדרה הזו. שם הפלאגין הוא file_watcher.
  • config. ערך חובה שמזהה את בלוג ההגדרות של JSON עבור הפלאגין file_watcher. הסכימה והתוכן תלויים בתוסף.

התוכן של מבנה ה-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-platform argument.
  • הקציתם את 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, צריך לפעול לפי ההוראות האלה כדי לגלות את הסיבה.

  1. השבתת אבטחה בלי שרת Proxy ופתרון בעיות בתרחישי שימוש של איזון עומסים ב-Service mesh בלי שרת Proxy. כדי להשבית את האבטחה ברשת, מבצעים אחת מהפעולות הבאות:
    1. שימוש בהרשאות בטקסט פשוט בצד הלקוח ובצד השרת או
    2. לא מגדירים אבטחה לשירות לקצה העורפי ולמדיניות נקודת הקצה בהגדרות של Cloud Service Mesh.

פועלים לפי השלבים במאמר פתרון בעיות בפריסות של Cloud Service Mesh ללא שרת proxy, כי אין הגדרת אבטחה בפריסה.

  1. משנים את עומסי העבודה כך שישתמשו בפרטי כניסה של xDS עם טקסט פשוט או פרטי כניסה לא מאובטחים כפרטי הכניסה החלופיים. משאירים את ההגדרה של Cloud Service Mesh עם אבטחה מושבתת, כמו שצוין קודם. במקרה הזה, למרות ש-gRPC מאפשר ל-Cloud Service Mesh להגדיר אבטחה,‏ Cloud Service Mesh לא שולח מידע אבטחה, ולכן gRPC צריך לחזור לשימוש בפרטי כניסה בטקסט פשוט (או לא מאובטח), שצריכים לפעול באופן דומה למקרה הראשון הקודם. אם זה לא עובד, אפשר לנסות את הפעולות הבאות:

    1. להגדיל את רמת הרישום ביומן בצד הלקוח ובצד השרת, כדי שתוכלו לראות את הודעות ה-xDS שהועברו בין gRPC לבין Cloud Service Mesh.
    2. מוודאים ש-Cloud Service Mesh לא מפעיל אבטחה בתגובות של CDS ו-LDS שנשלחות לעומסי העבודה.
    3. מוודאים שעומסי העבודה לא משתמשים במצבי TLS או mTLS בערוצים שלהם. אם מופיעות הודעות יומן שקשורות ללחיצות יד של TLS, צריך לבדוק את קוד המקור של האפליקציה ולוודא שאתם משתמשים בטקסט לא מאובטח או בטקסט רגיל כגיבוי לפרטי הכניסה. אם קוד המקור של האפליקציה תקין, יכול להיות שמדובר בבאג בספריית gRPC
  2. כדי לוודא שהשילוב של שירות CA עם GKE פועל בצורה תקינה באשכול GKE, צריך לפעול לפי השלבים לפתרון בעיות שמפורטים במדריך למשתמש. חשוב לוודא שהאישורים והמפתחות שסופקו על ידי התכונה הזו זמינים בספרייה שצוינה, /var/run/secrets/workload-spiffe-credentials/.

  3. מפעילים TLS (במקום mTLS) ברשת, כמו שמתואר למעלה, ומפעילים מחדש את עומסי העבודה של הלקוח והשרת.

    1. כדי לראות את הודעות xDS שמועברות בין gRPC לבין Cloud Service Mesh, צריך להגדיל את רמת הרישום ביומן בצד הלקוח ובצד השרת.
    2. מוודאים ש-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, צריך לבצע את הפעולות הבאות:

  1. מוודאים שמפרט ה-Pod מכיל את ההערה security.cloud.google.com/use-workload-certificates שמתוארת במאמר יצירת שירות gRPC בלי שרת Proxy עם NEGs.

  2. מוודאים שאפשר לגשת לקבצים שמכילים את שרשרת האישורים, את אישור העלה, את המפתח הפרטי ואת האישורים של רשות האישורים המהימנה בנתיבים הבאים מתוך ה-Pod:

    1. שרשרת האישורים יחד עם אישור הקצה: "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
    2. מפתח פרטי: ‎/var/run/secrets/workload-spiffe-credentials/private_key.pem
    3. חבילת CA:‏ ‎"/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"‎
  3. אם האישורים מהשלב הקודם לא זמינים, צריך לבצע את הפעולות הבאות:

      gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME 
    --location=LOCATION

    1. מוודאים שלמישור הבקרה של 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.
      
    2. מוודאים שתוקף האישור לא פג. זו שרשרת האישורים ואישור הקצה בכתובת /var/run/secrets/workload-spiffe-credentials/certificates.pem. כדי לבדוק, מריצים את הפקודה הבאה:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
      

    3. מריצים את הפקודה הבאה כדי לוודא שסוג המפתח נתמך באפליקציה:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
      

    4. מוודאים שלאפליקציית gRPC Java יש את ההגדרות הבאות keyAlgorithm בקובץ WorkloadCertificateConfig YAML:

      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
  4. מוודאים שרשות האישורים משתמשת באותה משפחת מפתחות כמו מפתח האישור.

האישור של האפליקציה נדחה על ידי הלקוח, השרת או העמית

  1. מוודאים שאפליקציית העמיתים משתמשת באותו חבילת אמון כדי לאמת את האישור.
  2. מוודאים שתוקף האישור שבשימוש לא פג (שרשרת האישורים יחד עם אישור הקצה: ‎/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.

  1. בודקים את הסטטוס של ה-Pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME
    

    מחליפים את מה שכתוב בשדות הבאים:

    • POD_NAMESPACE: מרחב השמות של ה-Pod.
    • POD_NAME: השם של ה-Pod.
  2. כדי לבדוק אירועים אחרונים ב-Pod:

    kubectl describe pod -n POD_NAMESPACE POD_NAME
    
  3. אם הקצאת האישורים נכשלת, יוצג אירוע עם 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)
    
  4. אם ה-Pods לא מופעלים בגלל אובייקטים שהוגדרו בצורה שגויה או בגלל בקשות חתימה על אישורים (CSR) שנדחו, כדאי לפעול לפי השלבים הבאים לפתרון בעיות.

ההגדרה של WorkloadCertificateConfig או TrustConfig שגויה

מוודאים שיצרתם את האובייקטים WorkloadCertificateConfig ו-TrustConfig בצורה נכונה. אפשר לאבחן הגדרות שגויות באחד מהאובייקטים האלה באמצעות kubectl.

  1. אחזור הסטטוס הנוכחי.

    עבור WorkloadCertificateConfig:

    kubectl get WorkloadCertificateConfig default -o yaml
    

    עבור TrustConfig:

    kubectl get TrustConfig default -o yaml
    
  2. בודקים את פלט הסטטוס. אובייקט תקין יכלול תנאי עם 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.

  1. מציגים רשימה של בקשות CSR רלוונטיות באמצעות kubectl:

    kubectl get csr \
      --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
    
  2. בוחרים בקובץ CSR שערכו הוא Approved ולא Issued, או שערכו לא Approved.

  3. כדי לקבל פרטים על בקשת ה-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

  1. מקבלים את מפרט ה-Pod של ה-Pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
    

    מחליפים את מה שכתוב בשדות הבאים:

    • POD_NAMESPACE: מרחב השמות של ה-Pod.
    • POD_NAME: השם של ה-Pod.
  2. מוודאים שמפרט ה-Pod מכיל את ההערה security.cloud.google.com/use-workload-certificates שמתוארת במאמר הגדרת Pods לקבלת פרטי כניסה של mTLS.

  3. מוודאים שפקדת הכניסה של אישורי GKE mesh הצליחה להוסיף נפח של מנהל התקן CSI מסוג workloadcertificates.security.cloud.google.com למפרט ה-Pod:

    volumes:
    ...
    -csi:
      driver: workloadcertificates.security.cloud.google.com
      name: gke-workload-certificates
    ...
    
  4. בודקים אם יש נפח שמוצמד לכל אחד מהקונטיינרים:

    containers:
    - name: ...
      ...
      volumeMounts:
      - mountPath: /var/run/secrets/workload-spiffe-credentials
        name: gke-workload-certificates
        readOnly: true
      ...
    
  5. מוודאים שחבילות האישורים הבאות והמפתח הפרטי זמינים במיקומים הבאים ב-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
  6. אם הקבצים לא זמינים, מבצעים את הפעולות הבאות:

    1. מאחזרים את מופע שירות ה-CA‏ (תצוגה מקדימה) עבור האשכול:

      kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
      
    2. אחזור הסטטוס של מופע 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).
    3. מקבלים את מדיניות ה-IAM עבור רשות האישורים הבסיסית:

      gcloud privateca roots get-iam-policy ROOT_CA_NAME
      

      מחליפים את ROOT_CA_NAME בשם של רשות האישורים הבסיסית.

    4. במדיניות IAM, מוודאים שקיים privateca.auditor policy binding:

      ...
      - members:
        - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.auditor
      ...
      

      בדוגמה הזו, PROJECT_NUMBER הוא מספר הפרויקט של האשכול.

    5. מקבלים את מדיניות ה-IAM עבור רשות אישורים משנית:

      gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
      

      מחליפים את SUBORDINATE_CA_NAME בשם של רשות אישורים משנית.

    6. במדיניות IAM, מוודאים שקיים privateca.certificateManager קישור למדיניות:

      ...
      - members:
        - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.certificateManager
      ...
      

      בדוגמה הזו, PROJECT_NUMBER הוא מספר הפרויקט של האשכול.

לא ניתן להשתמש באישורי mTLS שהונפקו באפליקציות

  1. מוודאים שתוקף האישור לא פג:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  2. בודקים שסוג המפתח שבו השתמשתם נתמך על ידי האפליקציה.

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
    
  3. בודקים שרשות האישורים שהנפיקה את האישור משתמשת באותה משפחת מפתחות כמו מפתח האישור.

    1. קבלת הסטטוס של שירות ה-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).
    2. בודקים שאלגוריתם המפתח 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
       ...
      

האישורים נדחים

  1. מוודאים שאפליקציית העמיתים משתמשת באותו חבילת אמון כדי לאמת את האישור.
  2. מוודאים שתוקף האישור לא פג:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  3. אם לא משתמשים ב-Credentials Reloading API של gRPC Go, צריך לוודא שקוד הלקוח מרענן מעת לעת את פרטי הכניסה ממערכת הקבצים.

  4. מוודאים שעומסי העבודה נמצאים באותו דומיין מהימן כמו רשות האישורים. אישורים של GKE mesh תומכים בתקשורת בין עומסי עבודה בדומיין אמון יחיד.

מגבלות

אבטחת שירותים ב-Cloud Service Mesh נתמכת רק ב-GKE. אי אפשר לפרוס אבטחת שירות באמצעות Compute Engine.

‫Cloud Service Mesh לא תומך בתרחישים שבהם יש שני משאבי מדיניות של נקודות קצה או יותר שתואמים באופן שווה לנקודת קצה. לדוגמה, שתי מדיניות עם אותן תוויות ואותם פורטים, או שתי מדיניות או יותר עם תוויות שונות שתואמות באופן שווה לתוויות של נקודת קצה. מידע נוסף על האופן שבו מתבצעת התאמה בין מדיניות נקודות קצה לתוויות של נקודת קצה זמין במאמר בנושא ממשקי API ל-EndpointPolicy.EndpointMatcher.MetadataLabelMatcher. במקרים כאלה, Cloud Service Mesh לא יוצר הגדרת אבטחה מאף אחת ממדיניות ההרשאה שמתנגשות.