הגדרת אבטחת שירות באמצעות Envoy

במדריך הזה מוסבר איך להגדיר אימות והרשאה לשירותים שנפרסו באמצעות Cloud Service Mesh ושרתי proxy של Envoy. מידע מלא על אבטחת שירותים ב-Cloud Service Mesh זמין במאמר אבטחת שירותים ב-Cloud Service Mesh.

דרישות

לפני שמגדירים אבטחת שירותים ב-Cloud Service Mesh באמצעות Envoy, צריך לוודא שההגדרה עומדת בדרישות המוקדמות הבאות:

הכנה להגדרה

בקטעים הבאים מתוארות המשימות שצריך לבצע לפני שמגדירים את שירות האבטחה של Cloud Service Mesh. המשימות האלה הן:

  • עדכון Google Cloud CLI
  • הגדרת משתנים
  • הפעלת ממשקי ה-API שנדרשים כדי ש-Cloud Service Mesh יעבוד עם Certificate Authority Service

עדכון כלי שורת הפקודה gcloud

כדי לעדכן את Google Cloud CLI, מריצים את הפקודה הבאה במחשב המקומי:

gcloud components update

הגדרת משתנים

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

  • PROJECT_ID: מחליפים את מזהה הפרויקט.
  • CLUSTER_NAME: מחליפים את שם האשכול שרוצים להשתמש בו, לדוגמה, secure-td-cluster.
  • ZONE: מחליפים את האזור שבו נמצא האשכול.
  • GKE_CLUSTER_URL: תחליף https://container.googleapis.com/v1/projects/PROJECT_ID/locations/ZONE/clusters/CLUSTER_NAME
  • WORKLOAD_POOL: תחליף PROJECT_ID.svc.id.goog
  • K8S_NAMESPACE: Substitute default.
  • DEMO_CLIENT_KSA: מחליפים את השם של חשבון השירות של הלקוח ב-Kubernetes.
  • DEMO_SERVER_KSA: מחליפים את השם של חשבון השירות של שרת Kubernetes.
  • PROJNUM: מחליפים את מספר הפרויקט שלכם, שאפשר לראות במסוף Google Cloud או באמצעות הפקודה הבאה:

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  • SA_GKE: תחליף service-PROJNUM@container-engine-robot.iam.gserviceaccount.com

  • CLUSTER_VERSION: מחליפים את הגרסה העדכנית ביותר שזמינה. אפשר למצוא את המידע הזה בנתוני הגרסה של הערוץ המהיר. הגרסה המינימלית הנדרשת היא 1.21.4-gke.1801. זוהי גרסת אשכול GKE שמשמשת בדוגמה הזו.

מגדירים את הערכים כאן:

# Substitute your project ID
PROJECT_ID=PROJECT_ID

# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
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=K8S_NAMESPACE
DEMO_CLIENT_KSA=DEMO_CLIENT_KSA
DEMO_SERVER_KSA=DEMO_SERVER_KSA

# Compute other values
# Project number for your project
PROJNUM=PROJNUM

CLUSTER_VERSION=CLUSTER_VERSION
SA_GKE=service-PROJNUM@container-engine-robot.iam.gserviceaccount.com

הפעלת ממשקי ה-API

משתמשים בפקודה gcloud services enable כדי להפעיל את כל ממשקי ה-API שצריך להגדיר אבטחה של Cloud Service Mesh באמצעות Certificate Authority Service.

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

יצירה או עדכון של אשכול 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
    

פריסה בסביבה מרובת אשכולות

אם אתם מבצעים פריסה בסביבה מרובת אשכולות, צריך לפעול לפי ההליך הכללי שמתואר בקטע הזה. ההנחיות האלה מניחות ש-Pods של לקוחות פועלים באשכול אחד, ו-Pods של שרתים פועלים באשכול השני.

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

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

    gcloud compute firewall-rules list \
      --filter="name~gke-{CLUSTER_NAME}-[0-9a-z]*-all" \
      --format="value(sourceRanges)"
    

    לדוגמה, עבור אשכולות בשם cluster-a ו-cluster-b, הפקודות מחזירות תוצאות כמו אלה:

    cluster-a, pod CIDR: 10.4.0.0/14, node network tag: gke-cluster-a-9cd18751-node
    cluster-b, pod CIDR: 10.8.0.0/14, node network tag: gke-cluster-b-acd14479-node
    
  3. יוצרים כללים של חומת אש ב-VPC שמאפשרים לאשכולות לתקשר ביניהם. לדוגמה, הפקודה הבאה יוצרת כלל חומת אש שמאפשר לכתובות ה-IP של הפוד cluster-a לתקשר עם הצמתים cluster-b:

    gcloud compute firewall-rules create per-cluster-a-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-b-acd14479-node"
    

    הפקודה הבאה יוצרת כלל חומת אש שמאפשר לכתובות ה-IP של ה-Pod cluster-b לתקשר עם הצמתים cluster-a:

    gcloud compute firewall-rules create per-cluster-b-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-a-9cd18751-node"
    

רישום אשכולות ב-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
    

הגדרת ניהול זהויות והרשאות גישה (IAM)

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

שימו לב שהמדיניות networksecurity.googleapis.com.clientTlsPolicies.use ו-networksecurity.googleapis.com.serverTlsPolicies.use לא נאכפת כשמפנים למשאבים האלה בשירות לקצה העורפי.

אם ההרשאות האלה ייאכפו בעתיד ואתם משתמשים בתפקיד compute.NetworkAdmin, לא תיתקלו בבעיות כשהבדיקה הזו תיאכף.

אם אתם משתמשים בתפקידים בהתאמה אישית והבדיקה הזו תיאכף בעתיד, תצטרכו לוודא שאתם כוללים את ההרשאה המתאימה .use. אחרת, בעתיד יכול להיות שתגלו שלתפקיד המותאם אישית אין את ההרשאות הנדרשות כדי להפנות אל clientTlsPolicy או אל serverTlsPolicy משירות הקצה העורפי או ממדיניות נקודת הקצה.

ההוראות הבאות מאפשרות לחשבון השירות שמוגדר כברירת מחדל לגשת אל Cloud Service Mesh Security API וליצור חשבונות שירות של Kubernetes.

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

    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_SERVER_KSA
    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_CLIENT_KSA
    
  3. כדי לאפשר לחשבונות השירות של Kubernetes להתחזות לחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine, צריך ליצור קשר בין מדיניות IAM לשני החשבונות. הקישור הזה מאפשר לחשבון השירות של Kubernetes לפעול כחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine.

    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_SERVER_KSA]" ${GSA_EMAIL}
    
    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser  \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_CLIENT_KSA]" ${GSA_EMAIL}
    
  4. מוסיפים הערות לחשבונות השירות של Kubernetes כדי לשייך אותם לחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine.

    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_SERVER_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    
    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_CLIENT_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    

הגדרת Cloud Service Mesh

כדי להתקין את כלי ההזרקה של sidecar, להגדיר שירות בדיקה ולהשלים משימות פריסה אחרות, פועלים לפי ההוראות הבאות.

התקנת Envoy sidecar injector באשכול

כדי לפרוס ולהפעיל הזרקת Envoy sidecar באשכול, צריך לפעול לפי ההוראות בשני הקטעים הבאים של הגדרת Cloud Service Mesh עבור GKE Pods עם הזרקת Envoy אוטומטית:

חשוב להשלים את שני סוגי ההוראות לפני שמגדירים שירות בדיקה.

הגדרת שירות בדיקה

אחרי שמתקינים את Envoy sidecar injector, משתמשים בהוראות האלה כדי להגדיר שירות בדיקה לפריסה.

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/service_sample.yaml | sed -e s/DEMO_SERVER_KSA_PLACEHOLDER/DEMO_SERVER_KSA/g > service_sample.yaml

kubectl apply -f service_sample.yaml

הקובץ service_sample.yaml מכיל את podspec של אפליקציית שרת ההדגמה. יש הערות ספציפיות לאבטחה של Cloud Service Mesh.

מטא נתונים של שרת Proxy ב-Cloud Service Mesh

קובץ ה-podspec מציין את ההערה proxyMetadata:

spec:
...
      annotations:
        cloud.google.com/proxyMetadata: '{"app": "payments"}'
...

כשה-Pod מאותחל, שרת ה-proxy של קובץ העזר החיצוני מאתר את ההערה הזו ומעביר אותה ל-Cloud Service Mesh. אחרי כן, Cloud Service Mesh יכול להשתמש במידע הזה כדי לשלוח חזרה הגדרה מסוננת:

  • בהמשך המדריך הזה, שימו לב שמדיניות נקודות הקצה מציינת התאמה של נקודת קצה.
  • התאמת נקודת הקצה מציינת שרק לקוחות שמציגים תווית עם שם app וערך payments יקבלו את ההגדרה המסוננת.

שימוש במפתחות ובאישורים של רשת שחתומים על ידי שירות CA

קובץ ה-podspec מציין את ההערה enableManagedCerts:

spec:
...
      annotations:
        ...
        cloud.google.com/enableManagedCerts: "true"
...

כשה-Pod מאותחל, אישורים ומפתחות שחתומים על ידי CA Service מותקנים אוטומטית במערכת הקבצים של קובץ העזר החיצוני המקומי.

הגדרת היציאה לחסימת תנועה נכנסת

קובץ ה-podspec מציין את ההערה includeInboundPorts:

spec:
...
      annotations:
        ...
        cloud.google.com/includeInboundPorts: "8000"
...

זו היציאה שבה אפליקציית השרת מאזינה לחיבורים. כשה-Pod מאותחל, שרת ה-proxy של קובץ העזר החיצוני מאתר את ההערה הזו ומעביר אותה ל-Cloud Service Mesh. לאחר מכן, Cloud Service Mesh יכול להשתמש במידע הזה כדי לשלוח בחזרה הגדרה מסוננת שמיירטת את כל התנועה הנכנסת ליציאה הזו ויכולה להחיל עליה מדיניות אבטחה.

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

הגדרת שירותי GKE באמצעות NEGs

שירותי GKE צריכים להיות חשופים דרך קבוצות של נקודות קצה ברשת (NEGs) כדי שתוכלו להגדיר אותם כשרתי קצה של שירות קצה של Cloud Service Mesh. חבילת service_sample.yaml שמסופקת עם מדריך ההגדרה הזה משתמשת בשם ה-NEG‏ service-test-neg בהערה הבאה:

...
metadata:
  annotations:
    cloud.google.com/neg: '{"exposed_ports": {"80":{"name": "service-test-neg"}}}'
spec:
  ports:
  - port: 80
    name: service-test
    protocol: TCP
    targetPort: 8000

אין צורך לשנות את קובץ service_sample.yaml.

שמירת השם של ה-NEG

שומרים את השם של קבוצת ה-NEG במשתנה NEG_NAME:

NEG_NAME="service-test-neg"

פריסת אפליקציית לקוח ב-GKE

מריצים את הפקודה הבאה כדי להפעיל לקוח הדגמה עם שרת proxy של Envoy כ-sidecar, שנדרש להדגמת תכונות האבטחה.

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/client_sample.yaml | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > client_sample.yaml

kubectl apply -f client_sample.yaml

קובץ ה-podspec של הלקוח כולל רק את ההערה enableManagedCerts. הפעולה הזו נדרשת כדי לטעון את אמצעי האחסון הנדרשים עבור אישורים ומפתחות של רשת GKE מנוהלת, שנחתמים על ידי מופע CA Service.

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

בקטע הזה יוצרים משאבים של בדיקת תקינות, כלל חומת אש ושירות לקצה העורפי עבור Cloud Service Mesh.

  1. יוצרים את בדיקת התקינות.

    gcloud compute health-checks create http td-gke-health-check \
      --use-serving-port
    
  2. יוצרים את הכלל בחומת האש כדי לאפשר את טווחי כתובות ה-IP של בודק התקינות.

    gcloud compute firewall-rules create fw-allow-health-checks \
       --action ALLOW \
       --direction INGRESS \
       --source-ranges 35.191.0.0/16,130.211.0.0/22 \
      --rules tcp
    
  3. יוצרים את שירות לקצה העורפי ומשייכים את בדיקת תקינות לשירות לקצה העורפי.

    gcloud compute backend-services create td-gke-service \
      --global \
      --health-checks td-gke-health-check \
      --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  4. מוסיפים את ה-NEG שנוצר קודם כקצה עורפי לשירות הקצה העורפי.

    gcloud compute backend-services add-backend td-gke-service \
      --global \
      --network-endpoint-group ${NEG_NAME} \
      --network-endpoint-group-zone ZONE \
      --balancing-mode RATE \
     --max-rate-per-endpoint 5
    

הגדרת משאבים של Mesh ו-HTTPRoute

בקטע הזה יוצרים משאבים מסוג Mesh ו-HTTPRoute.

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

    name: sidecar-mesh
    interceptionPort: 15001
    

    אם לא מציינים את יציאת היירוט בקובץ mesh.yaml, ברירת המחדל היא 15001.

  2. יוצרים את המשאב Mesh באמצעות המפרט mesh.yaml.

    gcloud network-services meshes import sidecar-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. יוצרים את המפרט HTTPRoute ושומרים אותו בקובץ בשם http_route.yaml.

    אפשר להשתמש ב-PROJECT_ID או ב-PROJECT_NUMBER.

    name: helloworld-http-route
    hostnames:
    - service-test
    meshes:
    - projects/PROJNUM/locations/global/meshes/sidecar-mesh
    rules:
    - action:
       destinations:
       - serviceName: "projects/PROJNUM/locations/global/backendServices/td-gke-service"
    
  4. יוצרים את המשאב HTTPRoute באמצעות המפרט בקובץ http_route.yaml.

    gcloud network-services http-routes import helloworld-http-route \
      --source=http_route.yaml \
      --location=global
    

ההגדרה של Cloud Service Mesh הושלמה ועכשיו אפשר להגדיר מדיניות אימות והרשאה.

הגדרת אבטחה משירות לשירות

בקטעים הבאים מפורטות ההוראות להגדרת אבטחה משירות לשירות.

הפעלת mTLS ברשת

כדי להגדיר mTLS ברשת, צריך לאבטח את התנועה היוצאת לשירות הקצה העורפי ואת התנועה הנכנסת לנקודת הקצה.

הפורמט של סימוכין בתקנון המדיניות

חשוב לשים לב לפורמט הנדרש הבא להפניה ל-TLS של שרת, ל-TLS של לקוח ולמדיניות הרשאות:

projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies|authorizationPolicies]/[server-tls-policy|client-mtls-policy|authz-policy]

לדוגמה:

projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
projects/PROJECT_ID/locations/global/authorizationPolicies/authz-policy

אבטחת תעבורה יוצאת לשירות הקצה העורפי

כדי לאבטח תנועה יוצאת, קודם יוצרים מדיניות TLS של לקוח שמבצעת את הפעולות הבאות:

  • משתמש ב-google_cloud_private_spiffe כפלאגין ל-clientCertificate, שמגדיר את Envoy להשתמש באישור רשת מנוהל של GKE בתור זהות הלקוח.
  • משתמש ב-google_cloud_private_spiffe כפלאגין ל-serverValidationCa, שמתכנת את Envoy להשתמש באישורים מנוהלים של GKE Mesh לצורך אימות שרת.

לאחר מכן, מצרפים את מדיניות ה-TLS של הלקוח לשירות הקצה העורפי. הפעולה הזו גורמת לדברים הבאים:

  • מחיל את מדיניות האימות ממדיניות TLS של הלקוח על חיבורים יוצאים לנקודות קצה של שירות לקצה העורפי.
  • שמות נושאים חלופיים (SAN) מנחים את הלקוח לאמת את הזהות המדויקת של השרת שאליו הוא מתחבר.
  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 של הלקוח:

    gcloud network-security client-tls-policies import client-mtls-policy \
        --source=client-mtls-policy.yaml --location=global
    
  3. מצרפים את מדיניות ה-TLS של הלקוח לשירות הקצה העורפי. הפעולה הזו מחייבת אימות mTLS בכל הבקשות היוצאות מהלקוח לשירות הקצה העורפי הזה.

    gcloud compute backend-services export td-gke-service \
        --global --destination=demo-backend-service.yaml
    

    מוסיפים את השורות הבאות ל-demo-backend-service.yaml:

    securitySettings:
      clientTlsPolicy: projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
      subjectAltNames:
        - "spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA"
    
  4. מייבאים את הערכים:

    gcloud compute backend-services import td-gke-service \
        --global --source=demo-backend-service.yaml
    
  5. אפשר להריץ את הפקודה הבאה כדי לבדוק אם הבקשה נכשלה. זהו כשל צפוי, כי הלקוח מצפה לקבל אישורים מנקודת הקצה, אבל נקודת הקצה לא מתוכנתת עם מדיניות אבטחה.

    # Get the name of the Podrunning Busybox.
    BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')
    
    # Command to execute that tests connectivity to the service service-test.
    TEST_CMD="wget -q -O - service-test; echo"
    
    # Execute the test command on the pod.
    kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"
    

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

    wget: server returned error: HTTP/1.1 503 Service Unavailable
    

אבטחת תנועה נכנסת לנקודת הקצה

כדי לאבטח תנועה נכנסת, קודם יוצרים מדיניות TLS של שרת שמבצעת את הפעולות הבאות:

  • משתמש ב-google_cloud_private_spiffe כפלאגין ל-serverCertificate, שמגדיר את Envoy להשתמש באישור רשת מנוהל של GKE בתור זהות השרת.
  • משתמש ב-google_cloud_private_spiffe כפלאגין ל-clientValidationCa, שמגדיר את Envoy להשתמש באימות לקוח באמצעות אישורים של רשתות GKE מנוהלות.
  1. שומרים את ערכי המדיניות של TLS בשרת בקובץ בשם server-mtls-policy.yaml.

    name: "server-mtls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    mtlsPolicy:
      clientValidationCa:
      - certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
    
  2. יוצרים את מדיניות ה-TLS של השרת:

    gcloud network-security server-tls-policies import server-mtls-policy \
        --source=server-mtls-policy.yaml --location=global
    
  3. יוצרים קובץ בשם ep_mtls.yaml שמכיל את התאמת נקודת הקצה ומצרפים את מדיניות ה-TLS של השרת.

    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: MATCH_ALL
        metadataLabels:
        - labelName: app
          labelValue: payments
    name: "ep"
    serverTlsPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy
    type: SIDECAR_PROXY
    
  4. מייבאים את endpoint matcher.

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

אימות ההגדרה

מריצים את הפקודה הבאה curl. אם הבקשה מסתיימת בהצלחה, הפלט יציג x-forwarded-client-cert. הכותרת מודפסת רק אם החיבור הוא חיבור mTLS.

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

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

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: 10.48.0.6
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

שימו לב שהכותרת x-forwarded-client-cert מוכנסת על ידי Envoy בצד השרת, והיא מכילה את הזהות שלו (השרת) ואת הזהות של לקוח המקור. מכיוון שאנחנו רואים את הזהויות של הלקוח והשרת, זהו אות לחיבור mTLS.

הגדרת גישה ברמת השירות באמצעות מדיניות הרשאות

ההוראות האלה יוצרות מדיניות הרשאות שמאפשרת בקשות שנשלחות על ידי חשבון DEMO_CLIENT_KSA שבו שם המארח הוא service-test, היציאה היא 8000 ושיטת ה-HTTP היא GET. לפני שיוצרים מדיניות הרשאות, חשוב לקרוא את האזהרה שבמאמר הגבלת הגישה באמצעות הרשאות.

  1. יוצרים מדיניות הרשאות על ידי יצירת קובץ בשם authz-policy.yaml.

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        ports:
        - 8000
        methods:
        - GET
    
  2. מייבאים את המדיניות:

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

    authorizationPolicy: projects/PROJECT_ID/locations/global/authorizationPolicies/authz-policy
    

    מדיניות נקודת הקצה מציינת עכשיו שצריך לאכוף גם mTLS וגם את מדיניות ההרשאה על בקשות נכנסות ל-Pods שבהם פרוקסי Envoy sidecar מציג את התווית app:payments.

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

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

אימות ההגדרה

מריצים את הפקודות הבאות כדי לאמת את ההגדרה.

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
# This is a valid request and will be allowed.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

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

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: redacted
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

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

# Failure case
# Command to execute that tests connectivity to the service service-test.
# This is an invalid request and server will reject because the server
# authorization policy only allows GET requests.
TEST_CMD="wget -q -O - service-test --post-data='' ; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

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

<RBAC: access denied HTTP/1.1 403 Forbidden>

הגדרת מדיניות הרשאות ב-sidecars ב-GKE

בקטע הזה נסביר איך להגדיר סוגים שונים של מדיניות הרשאות ב-sidecar של Cloud Service Mesh ב-GKE.

כדי ליצור מדיניות הרשאות, צריך להתקין את GCPAuthzPolicy CustomResourceDefinition ‏ (CRD):

curl https://github.com/GoogleCloudPlatform/gke-networking-recipes/blob/main/gateway-api/config/mesh/crd/experimental/gcpauthzpolicy.yaml \
| kubectl apply -f -

מדיניות הרשאות לדחיית בקשות

אם יש לכם עומס עבודה שאמור לבצע רק שיחות יוצאות, כמו משימת cron, אתם יכולים להגדיר מדיניות הרשאות שתדחה כל בקשות HTTP נכנסות לעומס העבודה. בדוגמה הבאה נדחות בקשות HTTP נכנסות לעומס העבודה example-app.

כדי ליצור את מדיניות הדחייה ולהחיל אותה:

  1. יוצרים מדיניות מותאמת אישית על ידי יצירת קובץ בשם deny-all-authz-policy.yaml:

    cat >deny-all-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - to:
        operations:
        - paths:
          - type: Prefix
            value: "/"
    action: DENY
    EOF
    
  2. החלת המדיניות:

    kubectl apply -f deny-all-authz-policy.yaml
    

מדיניות הרשאות שמאפשרת בקשות

אפשר גם להגדיר מדיניות הרשאה שמאשרת רק בקשות שתואמות לקריטריונים ספציפיים, ודוחה את השאר. בדוגמה הבאה מוגדרת מדיניות הרשאות בפריסת example-app כדי לאפשר רק בקשות mTLS מ-Pods עם הזהות spiffee://cluster.local/ns1/pod1.

כדי ליצור את מדיניות ההרשאה וליישם אותה:

  1. יוצרים מדיניות מותאמת אישית על ידי יצירת קובץ בשם allow-authz-policy.yaml:

    cat >allow-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - from:
        sources:
        - principals:
          - type: Exact
            value: "spiffee://cluster.local/ns1/pod1"
    action: ALLOW
    EOF
    
  2. החלת המדיניות:

    kubectl apply -f allow-authz-policy.yaml
    

הגדרת אבטחה של שער כניסה

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

בקטע הזה פורסים פרוקסי של Envoy כשער כניסה שמסיים חיבורי TLS ומאשר בקשות מלקוחות פנימיים של אשכול.

סיום TLS בשער כניסה (ingress) (לחצו להגדלה)
סיום TLS בשער כניסה (לחצו כדי להגדיל)

כדי להגדיר שער כניסה לניתוק TLS:

  1. פריסת שירות Kubernetes שאפשר להגיע אליו באמצעות כתובת IP פנימית של האשכול.
    1. הפריסה כוללת שרת proxy עצמאי של Envoy שנחשף כשירות Kubernetes ומתחבר ל-Cloud Service Mesh.
  2. יוצרים מדיניות TLS לשרת כדי להפסיק את ה-TLS.
  3. יוצרים מדיניות הרשאות כדי לאשר בקשות נכנסות.

פריסת שירות שער כניסה ל-GKE

מריצים את הפקודה הבאה כדי לפרוס את שירות שער הכניסה ב-GKE:

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/gateway_sample_xdsv3.yaml | sed -e s/PROJECT_NUMBER_PLACEHOLDER/PROJNUM/g | sed -e s/NETWORK_PLACEHOLDER/default/g | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > gateway_sample.yaml

kubectl apply -f gateway_sample.yaml

הקובץ gateway_sample.yaml הוא המפרט של שער הכניסה. בקטעים הבאים מתוארים כמה תוספות למפרט.

השבתה של הזרקת sidecar ב-Cloud Service Mesh

ה-gateway_sample.yaml spec פורס פרוקסי של Envoy כקונטיינר היחיד. בשלבים הקודמים, Envoy הוזרק כ-sidecar למאגר אפליקציות. כדי למנוע מצב שבו כמה שרתי Envoy מטפלים בבקשות, אפשר להשבית את הזרקת קובץ העזר לשירות Kubernetes הזה באמצעות ההצהרה הבאה:

sidecar.istio.io/inject: "false"

הרכבה של אמצעי האחסון הנכון

מפרט gateway_sample.yaml מרכיב את עוצמת הקול gke-workload-certificates. הנפח הזה משמש גם בפריסת sidecar, אבל הוא מתווסף באופן אוטומטי על ידי sidecar injector כשהוא מזהה את ההערה cloud.google.com/enableManagedCerts: "true". הווליום gke-workload-certificates מכיל את האישורים והמפתחות של SPIFFE שמנוהלים על ידי GKE, שחתומים על ידי מופע CA Service שהגדרתם.

הגדרת כתובת ה-IP הפנימית של האשכול

מגדירים את שער הכניסה עם שירות מסוג ClusterInternal. הפעולה הזו יוצרת שם מארח DNS שניתן לפענוח באופן פנימי עבור mesh-gateway. כשלקוח שולח בקשה ל-mesh-gateway:443, ‏ Kubernetes מנתב את הבקשה באופן מיידי ליציאה 8080 של פריסת שער הכניסה Envoy.

הפעלת TLS בשער כניסה

כדי להפעיל TLS בשער כניסה, צריך לפעול לפי ההוראות הבאות.

  1. יוצרים משאב מדיניות TLS לשרת כדי לסיים חיבורי TLS, עם הערכים בקובץ שנקרא server-tls-policy.yaml:

    description: tls server policy
    name: server-tls-policy
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. מייבאים את מדיניות ה-TLS של השרת:

    gcloud network-security server-tls-policies import server-tls-policy \
        --source=server-tls-policy.yaml --location=global
    
  3. יוצרים יעד חדש Gateway ושומרים אותו בקובץ td-gke-gateway.yaml. הפעולה הזו מצרפת את מדיניות ה-TLS של השרת ומגדירה את שער הכניסה של פרוקסי Envoy כדי לסיים את תעבורת ה-TLS הנכנסת.

    name: td-gke-gateway
    scope: gateway-proxy
    ports:
    - 8080
    type: OPEN_MESH
    serverTlsPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
    
  4. מייבאים את השער:

    gcloud network-services gateways import td-gke-gateway \
      --source=td-gke-gateway.yaml \
      --location=global
    
  5. יוצרים ושומרים HTTPRoute חדש בשם td-gke-route שמפנה לשער ומנתב את כל הבקשות אל td-gke-service.

    name: td-gke-route
    hostnames:
    - mesh-gateway
    gateways:
    - projects/PROJECT_NUMBER/locations/global/gateways/td-gke-gateway
    rules:
    - action:
        destinations:
        - serviceName: "projects/PROJECT_NUMBER/locations/global/backendServices/td-gke-service"
    
  6. מייבאים את HTTPRoute:

    gcloud network-services http-routes import td-gke-route \
      --source=td-gke-route.yaml \
      --location=global
    
    
  7. אפשרות נוספת: לעדכן את מדיניות ההרשאות בשרתי הקצה העורפיים כדי לאפשר בקשות כשכל התנאים הבאים מתקיימים:

    • בקשות שנשלחו על ידי DEMO_CLIENT_KSA. (הפריסה של שער הכניסה משתמשת בחשבון השירות DEMO_CLIENT_KSA).
    • בקשות עם מארח mesh-gateway או service-test
    • יציאה: 8000

    אין צורך להריץ את הפקודות האלה אלא אם הגדרתם מדיניות הרשאות לשרתי הקצה שלכם. אם אין מדיניות הרשאות בנקודת הקצה או שהיא לא מכילה התאמה של מארח או של חשבון משתמש מקור במדיניות ההרשאות, הבקשות יאושרו בלי השלב הזה. מוסיפים את הערכים האלה אל authz-policy.yaml.

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        - mesh-gateway
        ports:
        - 8000
        methods:
        - GET
    
  8. מייבאים את המדיניות:

    gcloud network-security authorization-policies import authz-policy \
      --source=authz-policy.yaml \
      --location=global
    

אימות הפריסה של שער הכניסה

אתם משתמשים בקונטיינר חדש בשם debug כדי לשלוח בקשות לשער ה-Ingress כדי לאמת את ה-Deployment (פריסה).

במפרט הבא, ההערה "sidecar.istio.io/inject":"false" מונעת מהכלי להזרקת sidecar של Cloud Service Mesh להזריק אוטומטית פרוקסי sidecar. אין sidecar שיכול לעזור למאגר התגים debug בניתוב הבקשה. המאגר צריך להתחבר לשער הכניסה כדי להגדיר ניתוב.

המפרט כולל את הדגל --no-check-certificate, שמתעלם מאימות אישור השרת. למאגר התגים של debug אין אישורי אימות של רשות האישורים שנדרשים לאימות אישורים שנחתמו על ידי שירות הרשות שמנפיקה את האישורים (CA), שמשמשים את שער הכניסה להפסקת TLS.

בסביבת ייצור, מומלץ להוריד את אישור האימות של CA Service ולהטמיע או להתקין אותו בלקוח. אחרי שמתקינים את אישור האימות, מסירים את האפשרות --no-check-certificate מהפקודה wget.

מריצים את הפקודה הבאה:

kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway; echo"

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

GET / HTTP/1.1
Host: 10.68.7.132
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
x-envoy-expected-rq-timeout-ms: 15000
x-envoy-internal: true
x-request-id: 5ae429e7-0e18-4bd9-bb79-4e4149cf8fef
x-forwarded-for: 10.64.0.53
x-forwarded-proto: https
content-length: 0
user-agent: Wget

מריצים את פקודת הבדיקה השלילית הבאה:

# Negative test
# Expect this to fail because gateway expects TLS.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - http://mesh-gateway:443/headers; echo"

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

wget: error getting response: Connection reset by peer

מריצים את פקודת הבדיקה השלילית הבאה:

# Negative test.
# AuthorizationPolicy applied on the endpoints expect a GET request. Otherwise
# the request is denied authorization.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway --post-data=''; echo"

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

HTTP/1.1 403 Forbidden
wget: server returned error: HTTP/1.1 403 Forbidden

מחיקת הפריסה

אפשר להריץ את הפקודות האלה כדי למחוק את הפריסה שיצרתם באמצעות המדריך הזה.

כדי למחוק את האשכול, מריצים את הפקודה הבאה:

gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet

כדי למחוק את המשאבים שיצרתם, מריצים את הפקודות הבאות:

gcloud compute backend-services delete td-gke-service --global --quiet
cloud compute network-endpoint-groups delete service-test-neg --zone ZONE --quiet
gcloud compute firewall-rules delete fw-allow-health-checks --quiet
gcloud compute health-checks delete td-gke-health-check --quiet
gcloud network-services endpoint-policies delete ep \
    --location=global --quiet
gcloud network-security authorization-policies delete authz-gateway-policy \
   --location=global --quiet
gcloud network-security authorization-policies delete 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 נתמכת רק ב-GKE. אי אפשר לפרוס אבטחת שירות באמצעות Compute Engine.

פתרון בעיות

בקטע הזה מוסבר איך לפתור בעיות שנתקלים בהן במהלך ההגדרה של שירות אבטחה.

כשלים בחיבור

אם החיבור נכשל עם שגיאה upstream connect או שגיאה disconnect/reset before headers, כדאי לבדוק את היומנים של Envoy, שבהם יכול להיות שתופיע אחת מהודעות היומן הבאות:

gRPC config stream closed: 5, Requested entity was not found

gRPC config stream closed: 2, no credential token is found

אם השגיאות האלה מופיעות ביומן של Envoy, סביר להניח שהטוקן של חשבון השירות לא הועלה בצורה נכונה, או שהוא משתמש ב-audience אחר, או בשניהם.

מידע נוסף זמין במאמר הודעות שגיאה ביומני Envoy מצביעות על בעיה בהגדרה.

לא נוצרו פודים

כדי לפתור את הבעיה, אפשר לעיין במאמר בנושא פתרון בעיות בפריסות אוטומטיות של GKE Pods.

‫Envoy לא מבצע אימות באמצעות Cloud Service Mesh

כש-Envoy ‏ (envoy-proxy) מתחבר ל-Cloud Service Mesh כדי לאחזר את הגדרות ה-xDS, הוא משתמש באיחוד זהויות של עומסי עבודה ל-GKE ובחשבון השירות שמוגדר כברירת מחדל במכונה הווירטואלית של Compute Engine (אלא אם שונה ה-bootstrap). אם האימות נכשל, Envoy לא עובר למצב מוכן.

לא ניתן ליצור אשכול עם --workload-identity-certificate-authority flag

אם השגיאה הזו מופיעה, צריך לוודא שאתם מריצים את הגרסה העדכנית ביותר של Google Cloud CLI:

gcloud components update

הפודים נשארים במצב המתנה

אם ה-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.

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