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

במדריך הזה נסביר איך לאחסן ב-Secret Manager את הנתונים הרגישים שמשמשים את אשכולות Google Kubernetes Engine ‏ (GKE). במאמר הזה מוסבר איך לגשת לנתונים מה-Pods בצורה מאובטחת יותר באמצעות איחוד שירותי אימות הזהות של עומסי עבודה ב-GKE וספריות הלקוחGoogle Cloud .

אחסון הנתונים הרגישים מחוץ לאחסון של האשכול מפחית את הסיכון לגישה לא מורשית לנתונים במקרה של מתקפה. שימוש באיחוד שירותי אימות הזהות של עומסי עבודה ב-GKE כדי לגשת לנתונים מאפשר לכם להימנע מהסיכונים שקשורים לניהול מפתחות של חשבונות שירות לטווח ארוך, ולשלוט בגישה לסודות באמצעות ניהול זהויות והרשאות גישה (IAM) במקום באמצעות כללי בקרת גישה שמבוססת על תפקידים (RBAC) באשכול. אתם יכולים להשתמש בכל ספק חיצוני של מאגר סודות, כמו Secret Manager או HashiCorp Vault.

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

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

אתם יכולים להשתמש ב-איחוד זהויות של עומסי עבודה ל-GKE כדי לגשת לכל Google Cloud API מעומסי עבודה של GKE בלי להשתמש בשיטות פחות מאובטחות כמו קובצי מפתחות סטטיים של חשבונות שירות. במדריך הזה נעשה שימוש ב-Secret Manager כדוגמה, אבל אפשר להשתמש באותם שלבים כדי לגשת לממשקי API אחרים. Google Cloudמידע נוסף זמין במאמר איחוד זהויות של עומסי עבודה ל-GKE.

מטרות

  • יוצרים סוד ב- Google Cloud Secret Manager.
  • יוצרים אשכול GKE Autopilot, מרחבי שמות של Kubernetes וחשבונות שירות של Kubernetes.
  • יוצרים מדיניות הרשאות ב-IAM כדי להעניק גישה לחשבונות השירות של Kubernetes בסוד.
  • משתמשים באפליקציות לבדיקה כדי לאמת את הגישה לחשבון השירות.
  • מריצים אפליקציה לדוגמה שגשת לסוד באמצעות Secret Manager API.

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

כדי להעריך את ההוצאות בהתאם לתחזית השימוש שלכם, אתם יכולים להיעזר במחשבון העלויות.

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

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

לפני שמתחילים

  1. נכנסים לחשבון Google Cloud . אם אתם משתמשים חדשים ב- Google Cloud, צרו חשבון כדי שתוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. התקינו את ה-CLI של Google Cloud.

  3. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  4. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  5. יוצרים או בוחרים Google Cloud פרויקט.

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

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  6. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  7. מפעילים את ממשקי ה-API של Kubernetes Engine ו-Secret Manager:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאה serviceusage.services.enable. איך מקצים תפקידים

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  8. התקינו את ה-CLI של Google Cloud.

  9. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  10. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  11. יוצרים או בוחרים Google Cloud פרויקט.

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

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  12. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  13. מפעילים את ממשקי ה-API של Kubernetes Engine ו-Secret Manager:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאה serviceusage.services.enable. איך מקצים תפקידים

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  14. מעניקים תפקידים לחשבון המשתמש. מריצים את הפקודה הבאה לכל אחד מהתפקידים הבאים ב-IAM: roles/secretmanager.admin, roles/container.clusterAdmin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

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

    • PROJECT_ID: מזהה הפרויקט.
    • USER_IDENTIFIER: המזהה של חשבון המשתמש . לדוגמה, myemail@example.com.
    • ROLE: תפקיד ה-IAM שאתם מקצים לחשבון המשתמש.

הכנת הסביבה

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

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd ~/kubernetes-engine-samples/security/wi-secrets

יצירת סוד ב-Secret Manager

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

    key=my-api-key
  2. יוצרים סוד כדי לאחסן את הנתונים לדוגמה:

    gcloud secrets create bq-readonly-key \
        --data-file=manifests/bq-readonly-key \
        --ttl=3600s
    

    הפקודה הזו מבצעת את הפעולות הבאות:

    • יוצרת סוד חדש ב-Secret Manager עם מפתח לדוגמה באזור us-central1 Google Cloud .
    • הגדרת תפוגה של הסוד שעה אחרי שמריצים את הפקודה.

יצירת האשכול ומשאבי Kubernetes

יוצרים אשכול GKE, מרחבי שמות של Kubernetes וחשבונות שירות של Kubernetes. יוצרים שני מרחבי שמות, אחד עם הרשאת קריאה בלבד ואחד עם הרשאת קריאה וכתיבה לסוד. בנוסף, אתם יוצרים חשבון שירות של Kubernetes בכל מרחב שמות לשימוש עם איחוד זהויות של עומסי עבודה ל-GKE.

  1. יוצרים אשכול GKE Autopilot:

    gcloud container clusters create-auto secret-cluster \
        --location=us-central1
    

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

  2. יוצרים מרחב שמות readonly-ns ומרחב שמות admin-ns:

    kubectl create namespace readonly-ns
    kubectl create namespace admin-ns
    
  3. יוצרים חשבון שירות של readonly-sa Kubernetes וחשבון שירות של admin-sa Kubernetes:

    kubectl create serviceaccount readonly-sa --namespace=readonly-ns
    kubectl create serviceaccount admin-sa --namespace=admin-ns
    

יצירת כללי מדיניות הרשאה ב-IAM

  1. מעניקים לחשבון השירות readonly-sa הרשאת קריאה בלבד לסוד:

    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/readonly-ns/sa/readonly-sa \
        --role='roles/secretmanager.secretAccessor' \
        --condition=None
    

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

    • PROJECT_NUMBER: מספר הפרויקט Google Cloud.
    • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
  2. נותנים לחשבון השירות admin-sa הרשאת קריאה וכתיבה לסוד:

    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
        --role='roles/secretmanager.secretAccessor' \
        --condition=None
    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
        --role='roles/secretmanager.secretVersionAdder' \
        --condition=None
    

אימות גישה סודית

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

  1. בודקים את מניפסט ה-Pod לקריאה בלבד:

    # Copyright 2022 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: readonly-test
      namespace: readonly-ns
    spec:
      containers:
      - image: google/cloud-sdk:slim
        name: workload-identity-test
        command: ["sleep","infinity"]
        resources:
          requests:
            cpu: "150m"
            memory: "150Mi"
      serviceAccountName: readonly-sa

    ה-Pod הזה משתמש בחשבון השירות readonly-sa במרחב השמות readonly-ns.

  2. בודקים את מניפסט ה-Pod לקריאה וכתיבה:

    # Copyright 2022 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: admin-test
      namespace: admin-ns
    spec:
      containers:
      - image: google/cloud-sdk:slim
        name: workload-identity-test
        command: ["sleep","infinity"]
        resources:
          requests:
            cpu: "150m"
            memory: "150Mi"
      serviceAccountName: admin-sa

    ה-Pod הזה משתמש בחשבון השירות admin-sa במרחב השמות admin-ns.

  3. פורסים את ה-Pods של הבדיקה:

    kubectl apply -f manifests/admin-pod.yaml
    kubectl apply -f manifests/readonly-pod.yaml
    

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

    watch kubectl get pods -n readonly-ns
    

    כשהסטטוס של ה-Pod משתנה ל-RUNNING, לוחצים על Ctrl+C כדי לחזור לשורת הפקודה.

בדיקת גישה לקריאה בלבד

  1. פותחים מעטפת ב-readonly-test Pod:

    kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
    
  2. נסו לקרוא את הסוד:

    gcloud secrets versions access 1 --secret=bq-readonly-key
    

    הפלט הוא key=my-api-key.

  3. מנסים לכתוב נתונים חדשים לסוד:

    printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
    

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

    ERROR: (gcloud.secrets.versions.add) PERMISSION_DENIED: Permission 'secretmanager.versions.add' denied for resource 'projects/PROJECT_ID/secrets/bq-readonly-key' (or it may not exist).
    

    ה-Pod שמשתמש בחשבון השירות לקריאה בלבד יכול רק לקרוא את הסוד, ולא יכול לכתוב נתונים חדשים.

  4. יציאה מהתרמיל:

    exit
    

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

  1. פותחים מעטפת ב-admin-test Pod:

    kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
    
  2. נסו לקרוא את הסוד:

    gcloud secrets versions access 1 --secret=bq-readonly-key
    

    הפלט הוא key=my-api-key.

  3. מנסים לכתוב נתונים חדשים לסוד:

    printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
    

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

    Created version [2] of the secret [bq-readonly-key].
    
  4. קוראים את הגרסה החדשה של הסוד:

    gcloud secrets versions access 2 --secret=bq-readonly-key
    

    הפלט הוא my-second-api-key.

  5. יציאה מהתרמיל:

    exit
    

לקבוצות ה-Pod יש רק את רמת הגישה שהענקתם לחשבון השירות של Kubernetes שמשמש במניפסט של ה-Pod. כל קבוצות ה-Pod שמשתמשות בחשבון Kubernetes במרחב השמות admin-ns יכולות לכתוב גרסאות חדשות של הסוד, אבל כל קבוצות ה-Pod במרחב השמות readonly-ns שמשתמשות בחשבון השירות של Kubernetes‏ readonly-sa יכולות רק לקרוא את הסוד.admin-sa

גישה לסודות מהקוד

בקטע הזה תבצעו את הפעולות הבאות:

  1. פריסת אפליקציה לדוגמה שקוראת את הסוד שלכם ב-Secret Manager באמצעות ספריות לקוח.

  2. בודקים שהאפליקציה יכולה לגשת לסוד.

כדאי לגשת לסודות של Secret Manager מקוד האפליקציה שלכם באמצעות Secret Manager API, כשזה אפשרי.

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

    // Copyright 2022 Google LLC
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //     http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"os"
    
    	secretmanager "cloud.google.com/go/secretmanager/apiv1"
    	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
    )
    
    func main() {
    
            // Get environment variables from Pod spec.
            projectID := os.Getenv("PROJECT_ID")
            secretId := os.Getenv("SECRET_ID")
            secretVersion := os.Getenv("SECRET_VERSION")
    
            // Create the Secret Manager client.
            ctx := context.Background()
            client, err := secretmanager.NewClient(ctx)
            if err != nil {
                    log.Fatalf("failed to setup client: %v", err)
            }
            defer client.Close()
    
            // Create the request to access the secret.
            accessSecretReq := &secretmanagerpb.AccessSecretVersionRequest{
                    Name: fmt.Sprintf("projects/%s/secrets/%s/versions/%s", projectID, secretId, secretVersion),
            }
    
            secret, err := client.AccessSecretVersion(ctx, accessSecretReq)
            if err != nil {
                    log.Fatalf("failed to access secret: %v", err)
            }
    
            // Print the secret payload.
            //
            // WARNING: Do not print the secret in a production environment - this
            // snippet is showing how to access the secret material.
            log.Printf("Welcome to the key store, here's your key:\nKey: %s", secret.Payload.Data)
    }
    

    האפליקציה הזו קוראת ל-Secret Manager API כדי לנסות לקרוא את הסוד.

  2. בודקים את קובץ המניפסט של ה-Pod של האפליקציה לדוגמה:

    # Copyright 2022 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: readonly-secret-test
      namespace: readonly-ns
    spec:
      containers:
      - image: us-docker.pkg.dev/google-samples/containers/gke/wi-secret-store:latest
        name: secret-app
        env:
          - name: PROJECT_ID
            value: "YOUR_PROJECT_ID"
          - name: SECRET_ID
            value: "bq-readonly-key"
          - name: SECRET_VERSION
            value: "latest"
        resources:
          requests:
            cpu: "125m"
            memory: "64Mi"
      serviceAccountName: readonly-sa

    קובץ המניפסט הזה:

    • יוצר Pod במרחב השמות readonly-ns שמשתמש בחשבון השירות readonly-sa.
    • שליפת אפליקציה לדוגמה ממאגר תמונות של Google. האפליקציה הזו קוראת ל-Secret Manager API באמצעותGoogle Cloud ספריות הלקוח. אפשר לראות את קוד האפליקציה ב-/main.go במאגר.
    • מגדיר משתני סביבה לשימוש באפליקציה לדוגמה.
  3. מחליפים את משתני הסביבה באפליקציה לדוגמה:

    sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
    
  4. מפעילים את האפליקציה לדוגמה:

    kubectl apply -f manifests/secret-app.yaml
    

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

  5. מאמתים את הגישה הסודית:

    kubectl logs readonly-secret-test -n readonly-ns
    

    הפלט הוא my-second-api-key. אם הפלט ריק, יכול להיות שה-Pod עדיין לא פועל. מחכים כמה דקות ומנסים שוב.

גישות חלופיות

אם אתם צריכים להוסיף את הנתונים הרגישים שלכם ל-Pods, אתם יכולים להשתמש בתוסף Secret Manager ל-GKE. התוסף הזה פורס ומנהל את ספק Google Cloud Secret Manager עבור מנהל ההתקן של Kubernetes Secret Store CSI באשכולות GKE. הוראות מפורטות במאמר שימוש בתוסף Secret Manager עם GKE.

יש סיכונים בשימוש בסודות כנפחים מוצמדים:

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

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

הסרת המשאבים

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

מחיקת משאבים בודדים

  1. מחיקת האשכול:

    gcloud container clusters delete secret-cluster \
        --location=us-central1
    
  2. אופציונלי: מוחקים את הסוד ב-Secret Manager:

    gcloud secrets delete bq-readonly-key
    

    אם לא תבצעו את השלב הזה, הסוד יפוג אוטומטית כי הגדרתם את הדגל --ttl במהלך היצירה.

מחיקת הפרויקט

    כדי למחוק Google Cloud פרויקט:

    gcloud projects delete PROJECT_ID

המאמרים הבאים