במדריך הזה, אלכס ובולה רוצים לגלות למי יש את המשכורת הכי גבוהה בלי לחשוף אחד לשני את המספרים. הם מחליטים להשתמש ב-Confidential Space כדי לשמור על סודיות הנתונים שלהם, ומסכימים לקבל על עצמם את התפקידים הבאים:
אלכס: משתף פעולה עם נתונים, יוצר עומסי עבודה
Bola: שותף לעריכת נתונים, מפעיל של עומס עבודה
הסידור הזה נועד לפשט ככל האפשר את ההסברים במדריך הזה. עם זאת, יכול להיות שיוצר עומס העבודה והמפעיל שלו יהיו לגמרי נפרדים מהמשתפים בנתונים, ואפשר להגדיר כמה משתפים שרוצים.
לפני שמתחילים
במדריך הזה מוצג תרחיש של Confidential Space שבו נעשה שימוש בחשבון יחיד בארגון יחיד עם גישה למספר פרויקטים, כדי שתוכלו לחוות את התהליך כולו. בפריסה של סביבת ייצור, לשותפי עריכה, ליוצרי עומסי עבודה ולמפעילים של עומסי עבודה יש חשבונות נפרדים ופרויקטים משלהם שנמצאים בארגונים נפרדים. הם לא יכולים לגשת אחד לשני, והנתונים הסודיים שלהם נשמרים בנפרד.
הטכנולוגיה של Confidential Space יכולה ליצור אינטראקציה עם הרבה שירותים של Google Cloudכדי להפיק את התוצאות שלה, כולל (בין היתר):
המדריך הזה מבוסס על ההנחה שיש לכם הבנה בסיסית של כל התכונות האלה.
התפקידים הנדרשים
כדי לקבל את ההרשאות שדרושות להשלמת המדריך הזה, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:
- התפקיד Cloud KMS Admin (
roles/cloudkms.admin) למשתפי הפעולה עם הנתונים (Alex ו-Bola). - אדמין של מאגר זהויות של עומסי עבודה ב-IAM (
roles/iam.workloadIdentityPoolAdmin) בשביל משתפי הפעולה עם הנתונים (Alex ו-Bola). - אדמין ל-Service Usage (
roles/serviceusage.serviceUsageAdmin) עבור משתפי הפעולה עם הנתונים (Alex ו-Bola). - אדמין אחסון (
roles/storage.admin) עבור משתפי הפעולה עם הנתונים (Alex ו-Bola) ומפעיל עומס העבודה (Bola). - אדמין בחשבון שירות (
roles/iam.serviceAccountAdmin) עבור מפעיל עומס העבודה (Bola). - אדמין של Compute (
roles/compute.admin) עבור האופרטור של עומס העבודה (Bola). - אדמין לענייני אבטחה (
roles/securityAdmin) למפעיל עומס העבודה (Bola). - מנהל מערכת של Artifact Registry (
roles/artifactregistry.admin) עבור יוצר עומס העבודה (Alex).
להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.
יכול להיות שאפשר לקבל את ההרשאות הנדרשות גם באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש.
הגדרה של משאבים לשיתוף פעולה בנתונים
גם לאלכס וגם לבולה דרושים פרויקטים נפרדים שמכילים את המשאבים הבאים:
הנתונים הסודיים עצמם.
מפתח הצפנה כדי להצפין את הנתונים ולשמור אותם חסויים.
קטגוריה של Cloud Storage לאחסון הנתונים המוצפנים.
מאגר זהויות של עומסי עבודה. כוח העבודה שמבצע את העיבוד של הנתונים הסודיים משתמש במאגר כדי לגשת לנתונים הפרטיים ולפענח אותם.
כדי להתחיל, נכנסים למסוף Google Cloud :
הגדרת המשאבים של אלכס
כדי להגדיר את המשאבים בשביל אלכס, פועלים לפי ההוראות הבאות.
- לוחצים על הפעלת Cloud Shell.
-
ב-Cloud Shell, מזינים את הפקודה הבאה כדי ליצור פרויקט עבור אלכס, ומחליפים את ALEX_PROJECT_ID בשם שבחרתם:
gcloud projects create ALEX_PROJECT_ID -
עוברים לפרויקט החדש שנוצר:
gcloud config set project ALEX_PROJECT_ID -
מפעילים את ממשקי ה-API שנדרשים לאלכס כמשתף פעולה בנתונים ויוצר עומסי עבודה:
gcloud services enable \ artifactregistry.googleapis.com \ cloudkms.googleapis.com \ iamcredentials.googleapis.com -
יצירה של אוסף מפתחות ומפתח הצפנה באמצעות Cloud Key Management Service:
gcloud kms keyrings create ALEX_KEYRING_NAME \ --location=global gcloud kms keys create ALEX_KEY_NAME \ --location=global \ --keyring=ALEX_KEYRING_NAME \ --purpose=encryption -
נותנים לאלכס את ההרשאה
cloudkms.cryptoKeyEncrypterכדי שהוא יוכל להשתמש במפתח ההצפנה החדש שנוצר להצפנת נתונים:gcloud kms keys add-iam-policy-binding \ "projects/ALEX_PROJECT_ID/locations/global/\ keyRings/ALEX_KEYRING_NAME/\ cryptoKeys/ALEX_KEY_NAME" \ --member=user:$(gcloud config get-value account) \ --role=roles/cloudkms.cryptoKeyEncrypter -
יצירת מאגר הזהויות של עומסי העבודה של אלכס:
gcloud iam workload-identity-pools create ALEX_POOL_NAME \ --location=global -
יוצרים קטגוריה של Cloud Storage לנתוני הקלט, וקטגוריה נוספת לאחסון התוצאות:
gcloud storage buckets create gs://ALEX_INPUT_BUCKET_NAME \ gs://ALEX_OUTPUT_BUCKET_NAME -
יוצרים קובץ שמכיל רק את המשכורת של אלכס כמספר:
echo 123456 > ALEX_SALARY.txt -
מצפינים את הקובץ ואז מעלים אותו לקטגוריה של אלכס:
gcloud kms encrypt \ --ciphertext-file="ALEX_ENCRYPTED_SALARY_FILE" \ --plaintext-file="ALEX_SALARY.txt" \ --key="projects/ALEX_PROJECT_ID/locations/global/\ keyRings/ALEX_KEYRING_NAME/\ cryptoKeys/ALEX_KEY_NAME"gcloud storage cp ALEX_ENCRYPTED_SALARY_FILE gs://ALEX_INPUT_BUCKET_NAME
הגדרת המשאבים של בולה
כדי להגדיר את המשאבים ל-Bola, פועלים לפי ההוראות הבאות.
-
ב-Cloud Shell, מזינים את הפקודה הבאה כדי ליצור פרויקט עבור Bola, ומחליפים את BOLA_PROJECT_ID בשם שבחרתם:
gcloud projects create BOLA_PROJECT_ID -
עוברים לפרויקט החדש שנוצר:
gcloud config set project BOLA_PROJECT_ID -
מפעילים את ממשקי ה-API שנדרשים ל-Bola כמשתף פעולה בנתונים ומפעיל עומסי עבודה:
gcloud services enable \ cloudkms.googleapis.com \ compute.googleapis.com \ confidentialcomputing.googleapis.com \ iamcredentials.googleapis.com -
יצירה של אוסף מפתחות ומפתח הצפנה באמצעות Cloud Key Management Service:
gcloud kms keyrings create BOLA_KEYRING_NAME \ --location=global gcloud kms keys create BOLA_KEY_NAME \ --location=global \ --keyring=BOLA_KEYRING_NAME \ --purpose=encryption -
נותנים לבולה את ההרשאה
cloudkms.cryptoKeyEncrypterכדי שהיא תוכל להשתמש במפתח ההצפנה החדש שנוצר להצפנת נתונים:gcloud kms keys add-iam-policy-binding \ "projects/BOLA_PROJECT_ID/locations/global/\ keyRings/BOLA_KEYRING_NAME/\ cryptoKeys/BOLA_KEY_NAME" \ --member=user:$(gcloud config get-value account) \ --role=roles/cloudkms.cryptoKeyEncrypter -
יצירת מאגר הזהויות של עומסי העבודה של Bola:
gcloud iam workload-identity-pools create BOLA_POOL_NAME \ --location=global -
יוצרים קטגוריה של Cloud Storage לנתוני הקלט, וקטגוריה נוספת לאחסון התוצאות:
gcloud storage buckets create gs://BOLA_INPUT_BUCKET_NAME \ gs://BOLA_OUTPUT_BUCKET_NAME -
יוצרים קובץ שמכיל רק את השכר של בולה כמספר:
echo 111111 > BOLA_SALARY.txt -
מצפינים את הקובץ ואז מעלים אותו לקטגוריה של בולה:
gcloud kms encrypt \ --ciphertext-file="BOLA_ENCRYPTED_SALARY_FILE" \ --plaintext-file="BOLA_SALARY.txt" \ --key="projects/BOLA_PROJECT_ID/locations/global/\ keyRings/BOLA_KEYRING_NAME/\ cryptoKeys/BOLA_KEY_NAME"gcloud storage cp BOLA_ENCRYPTED_SALARY_FILE gs://BOLA_INPUT_BUCKET_NAME
יצירת חשבון שירות לעומס העבודה
במדריך הזה, בולה מפעילה את עומס העבודה ומריצה אותו, אבל כל אחד יכול לקחת על עצמו את התפקידים האלה, כולל צד שלישי. למכונה הווירטואלית שירון יוצר כדי להריץ את עומס העבודה יש חשבון שירות מצורף, עם הרשאה ליצור אסימוני אימות, לכתוב יומנים, לקרוא את הנתונים המוצפנים של ירון ושל עינת ולכתוב תוצאות לקטגוריות ספציפיות של Cloud Storage.
כדי להגדיר את חשבון השירות בפרויקט של בולה, צריך לבצע את השלבים הבאים:
יוצרים חשבון שירות להרצת עומס העבודה:
gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAMEמקצים ל-Bola את התפקיד
iam.serviceAccountUserכדי שיוכל לקשר את חשבון השירות למכונה הווירטואלית של עומס העבודה בהמשך:gcloud iam service-accounts add-iam-policy-binding \ WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --member=user:$(gcloud config get-value account) \ --role=roles/iam.serviceAccountUserמקצים לחשבון השירות את התפקיד
confidentialcomputing.workloadUserכדי שיוכל לבקש אסימון אישור:gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/confidentialcomputing.workloadUserמקצים לחשבון השירות את התפקיד
logging.logWriterכדי לכתוב יומנים ב-Cloud Logging, וכך תוכלו לבדוק את התקדמות עומס העבודה:gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/logging.logWriterנותנים לחשבון השירות הרשאת קריאה לקטגוריות של אלכס ושל בולה שמכילות את הנתונים המוצפנים שלהם, והרשאת כתיבה לכל אחת מהקטגוריות של התוצאות שלהם:
gcloud storage buckets add-iam-policy-binding gs://ALEX_INPUT_BUCKET_NAME \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/storage.objectViewer gcloud storage buckets add-iam-policy-binding gs://ALEX_OUTPUT_BUCKET_NAME \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/storage.objectAdmin gcloud storage buckets add-iam-policy-binding gs://BOLA_INPUT_BUCKET_NAME \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/storage.objectViewer gcloud storage buckets add-iam-policy-binding gs://BOLA_OUTPUT_BUCKET_NAME \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/storage.objectAdminההנחה היא שלמשתמש שמעניק את הגישה יש את התפקיד 'אדמין לניהול אחסון' (
roles/storage.admin) בפרויקט שמכיל את הקטגוריה של Cloud Storage שעליה מתבצעת הפעולה.
יצירת עומס העבודה
במדריך הזה, אלכס מספק את הקוד של עומס העבודה ויוצר קובץ אימג' של Docker שתכיל אותו, אבל כל אחד יכול לקחת על עצמו את התפקידים האלה, כולל צד שלישי.
אלכס צריך ליצור את המשאבים הבאים בשביל עומס העבודה:
הקוד שמבצע את עומס העבודה.
מאגר Docker ב-Artifact Registry, שלחשבון השירות שמריץ את עומס העבודה יש גישה אליו.
קובץ אימג' של Docker שמכיל את קוד עומס העבודה ומריץ אותו.
כדי ליצור ולהגדיר את המשאבים, מבצעים את השלבים הבאים בפרויקט של אלכס:
מעבר לפרויקט של אלכס:
gcloud config set project ALEX_PROJECT_IDלוחצים על Open editor כדי לפתוח את Cloud Shell Editor, ואז יוצרים קובץ חדש בשם
salary.go. מעתיקים את הקוד הבא לקובץ ושומרים אותו:package main import ( "context" "fmt" "io" "os" "strconv" "strings" "time" kms "cloud.google.com/go/kms/apiv1" kmspb "cloud.google.com/go/kms/apiv1/kmspb" "cloud.google.com/go/storage" "google.golang.org/api/option" ) type collaborator struct { name string wipName string keyName string inputBucket string inputFile string outputBucket string } // The following values are pulled from environment variables // Alex's values var collaborator1Name string = os.Getenv("COLLAB_1_NAME") // Alex's name var collaborator1EncryptedSalaryFileName string = os.Getenv("COLLAB_1_ENCRYPTED_SALARY") // The name of Alex's encrypted salary file. var collaborator1BucketInputName string = os.Getenv("COLLAB_1_INPUT_BUCKET") // The name of the storage bucket that contains Alex's encrypted salary file. var collaborator1BucketOutputName string = os.Getenv("COLLAB_1_OUTPUT_BUCKET") // The name of the storage bucket to store Alex's results in. var collaborator1KMSKeyringName string = os.Getenv("COLLAB_1_KEYRING_NAME") // Alex's Key Management Service key ring. var collaborator1KMSKeyName string = os.Getenv("COLLAB_1_KEY_NAME") // Alex's Key Management Service key. var collaborator1ProjectName string = os.Getenv("COLLAB_1_PROJECT_ID") // Alex's project ID. var collaborator1ProjectNumber string = os.Getenv("COLLAB_1_PROJECT_NUMBER") // Alex's project number. var collaborator1PoolName string = os.Getenv("COLLAB_1_POOL_NAME") // Alex's workload identity pool name. // Bola's values var collaborator2Name string = os.Getenv("COLLAB_2_NAME") // Bola's name var collaborator2EncryptedSalaryFileName string = os.Getenv("COLLAB_2_ENCRYPTED_SALARY") // The name of Bola's encrypted salary file. var collaborator2BucketInputName string = os.Getenv("COLLAB_2_INPUT_BUCKET") // The name of the storage bucket that contains Bola's encrypted salary file. var collaborator2BucketOutputName string = os.Getenv("COLLAB_2_OUTPUT_BUCKET") // The name of the storage bucket to store Bola's results in. var collaborator2KMSKeyringName string = os.Getenv("COLLAB_2_KEYRING_NAME") // Bola's Key Management Service key ring. var collaborator2KMSKeyName string = os.Getenv("COLLAB_2_KEY_NAME") // Bola's Key Management Service key. var collaborator2ProjectName string = os.Getenv("COLLAB_2_PROJECT_ID") // Bola's project ID. var collaborator2ProjectNumber string = os.Getenv("COLLAB_2_PROJECT_NUMBER") // Bola's project number. var collaborator2PoolName string = os.Getenv("COLLAB_2_POOL_NAME") // Bola's workload identity pool name. var collaborators = [2]collaborator{ { collaborator1Name, "projects/" + collaborator1ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator1PoolName + "/providers/attestation-verifier", "projects/" + collaborator1ProjectName + "/locations/global/keyRings/" + collaborator1KMSKeyringName + "/cryptoKeys/" + collaborator1KMSKeyName, collaborator1BucketInputName, collaborator1EncryptedSalaryFileName, collaborator1BucketOutputName, }, { collaborator2Name, "projects/" + collaborator2ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator2PoolName + "/providers/attestation-verifier", "projects/" + collaborator2ProjectName + "/locations/global/keyRings/" + collaborator2KMSKeyringName + "/cryptoKeys/" + collaborator2KMSKeyName, collaborator2BucketInputName, collaborator2EncryptedSalaryFileName, collaborator2BucketOutputName, }, } const credentialConfig = `{ "type": "external_account", "audience": "//iam.googleapis.com/%s", "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", "token_url": "https://sts.googleapis.com/v1/token", "credential_source": { "file": "/run/container_launcher/attestation_verifier_claims_token" } }` func main() { fmt.Println("workload started") ctx := context.Background() storageClient, err := storage.NewClient(ctx) // Using the default credential on the Compute Engine VM if err != nil { panic(err) } // Get and decrypt s0, err := getSalary(ctx, storageClient, collaborators[0]) if err != nil { panic(err) } s1, err := getSalary(ctx, storageClient, collaborators[1]) if err != nil { panic(err) } res := "" if s0 > s1 { res = fmt.Sprintf("%s earns more!\n", collaborators[0].name) } else if s1 > s0 { res = fmt.Sprintf("%s earns more!\n", collaborators[1].name) } else { res = "You earn the same!\n" } now := time.Now() for _, cw := range collaborators { outputWriter := storageClient.Bucket(cw.outputBucket).Object(fmt.Sprintf("comparison-result-%d", now.Unix())).NewWriter(ctx) _, err = outputWriter.Write([]byte(res)) if err != nil { fmt.Printf("Could not write: %v", err) panic(err) } if err = outputWriter.Close(); err != nil { fmt.Printf("Could not close: %v", err) panic(err) } } } func getSalary(ctx context.Context, storageClient *storage.Client, cw collaborator) (float64, error) { encryptedBytes, err := getFile(ctx, storageClient, cw.inputBucket, cw.inputFile) if err != nil { return 0.0, err } decryptedByte, err := decryptByte(ctx, cw.keyName, cw.wipName, encryptedBytes) if err != nil { return 0.0, err } decryptedNumber := strings.TrimSpace(string(decryptedByte)) num, err := strconv.ParseFloat(decryptedNumber, 64) if err != nil { return 0.0, err } return num, nil } func decryptByte(ctx context.Context, keyName, wippro string, encryptedData []byte) ([]byte, error) { cc := fmt.Sprintf(credentialConfig, wippro) kmsClient, err := kms.NewKeyManagementClient(ctx, option.WithCredentialsJSON([]byte(cc))) if err != nil { return nil, fmt.Errorf("creating a new KMS client with federated credentials: %w", err) } decryptRequest := &kmspb.DecryptRequest{ Name: keyName, Ciphertext: encryptedData, } decryptResponse, err := kmsClient.Decrypt(ctx, decryptRequest) if err != nil { return nil, fmt.Errorf("could not decrypt ciphertext: %w", err) } return decryptResponse.Plaintext, nil } func getFile(ctx context.Context, c *storage.Client, bucketName string, objPath string) ([]byte, error) { bucketHandle := c.Bucket(bucketName) objectHandle := bucketHandle.Object(objPath) objectReader, err := objectHandle.NewReader(ctx) if err != nil { return nil, err } defer objectReader.Close() s, err := io.ReadAll(objectReader) if err != nil { return nil, err } return s, nil }חשוב לוודא שכל הצדדים קראו את קוד המקור ובדקו אותו.
יוצרים קובץ בשם
Dockerfileב-Cloud Shell Editor עם התוכן הבא:# Compile the provided Go code to a statically linked binary FROM golang:latest AS build WORKDIR /build COPY salary.go . RUN go mod init salary RUN go get cloud.google.com/go/kms/apiv1 cloud.google.com/go/storage google.golang.org/api/option google.golang.org/genproto/googleapis/cloud/kms/v1 RUN CGO_ENABLED=0 go build -trimpath # Build the workload container image FROM alpine:latest AS run WORKDIR /test COPY --from=build /build/salary /test/salary ENTRYPOINT ["/test/salary"] CMD [] # Allow the workload to access the following environment variables LABEL "tee.launch_policy.allow_env_override"="\ COLLAB_1_NAME,\ COLLAB_2_NAME,\ COLLAB_1_ENCRYPTED_SALARY,\ COLLAB_2_ENCRYPTED_SALARY,\ COLLAB_1_INPUT_BUCKET,\ COLLAB_2_INPUT_BUCKET,\ COLLAB_1_OUTPUT_BUCKET,\ COLLAB_2_OUTPUT_BUCKET,\ COLLAB_1_KEYRING_NAME,\ COLLAB_2_KEYRING_NAME,\ COLLAB_1_KEY_NAME,\ COLLAB_2_KEY_NAME,\ COLLAB_1_PROJECT_ID,\ COLLAB_2_PROJECT_ID,\ COLLAB_1_PROJECT_NUMBER,\ COLLAB_2_PROJECT_NUMBER,\ COLLAB_1_POOL_NAME,\ COLLAB_2_POOL_NAME"ה-
Dockerfileהזה משתמש ב-build רב-שלבי כדי לבצע קומפילציה של קוד Go, ואז מעתיק את הגרסה שעברה קומפילציה של הקוד הזה למאגר התגים הסופי של עומס העבודה. הוא גם מאפשר להשתמש במשתני סביבה ספציפיים בקונטיינר של עומס העבודה. הערכים של משתני הסביבה האלה ממופים בהמשך למשאבים הספציפיים שעומס העבודה צריך כדי לפעול.לוחצים על Open Terminal כדי לחזור ל-Cloud Shell, או מפעילים את הטרמינל שמוטמע ב-Cloud Shell Editor מהתפריט View.
יוצרים מאגר Docker ב-Artifact Registry:
gcloud artifacts repositories create REPOSITORY_NAME \ --repository-format=docker \ --location=usמקצים לחשבון השירות שיריץ את עומס העבודה את התפקיד 'קורא Artifact Registry' (
roles/artifactregistry.reader) כדי שיוכל לקרוא מהמאגר:gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \ --location=us \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/artifactregistry.readerמעדכנים את פרטי הכניסה של Docker כך שיכללו את
us-docker.pkg.devשם הדומיין:gcloud auth configure-docker us-docker.pkg.devכדי ליצור קובץ אימג' של Docker מ-
Dockerfile, מזינים את הפקודה הבאה בטרמינל:docker build -t \ "us-docker.pkg.dev/ALEX_PROJECT_ID/\ REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest" .מעבירים בדחיפה את קובץ האימג' של Docker אל Artifact Registry:
docker push \ us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAMEבתגובה של Docker push מופיע תקציר SHA256 של התמונה, שנדרש בהמשך כדי לאשר את עומס העבודה. התקציר ייראה כמו בדוגמה הבאה:
sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855מעתיקים את התקציר של התמונה (כולל הקידומת
sha256:) למקום שאפשר יהיה להפנות אליו. אפשר גם להזין את ה-digest בדוגמת הקוד הבאה כדי למלא מראש את שאר דוגמאות הקוד במדריך הזה שצריכות את הערך:WORKLOAD_CONTAINER_IMAGE_DIGESTלפני שמאשרים את השימוש בקובץ אימג' של Docker, חשוב לוודא שכל הצדדים בודקים אותו ומאמתים שהוא מהימן.
אישור עומס העבודה
אחרי ששני הצדדים אישרו את עומס העבודה, אלכס ובולה צריכים להוסיף את אימות הזהות של Google Cloud כספק למאגרי הזהויות של עומס העבודה. הספק מציין את שירות האימות שבו צריך להשתמש, ואת המאפיינים שתואמים לעומס העבודה כדי לאפשר לו לפעול על הנתונים של אלכס או בולה. אם גורם זדוני משנה את קובץ אימג' של Docker או משנה מאפיין נמדד אחר, הגישה לעומס העבודה נדחית.
במדריך הזה נעשה שימוש במיפוי מאפיינים כדי לספק לעומס העבודה גישה ישירה למשאבים על סמך תקציר התמונה. עם זאת, במצבים אחרים יכול להיות שתעדיפו להשתמש בהתחזות לחשבון שירות כדי לגשת למשאבים. מידע נוסף זמין במאמר בנושא גישה לעומסי עבודה חיצוניים.
כדי להגדיר את הספקים של אלכס ובולה עם התנאים הנדרשים, מבצעים את השלבים הבאים:
מזינים את הפקודה הבאה כדי ליצור את הספק עבור Alex:
gcloud iam workload-identity-pools providers create-oidc attestation-verifier \ --location=global \ --workload-identity-pool=ALEX_POOL_NAME \ --issuer-uri="https://confidentialcomputing.googleapis.com/" \ --allowed-audiences="https://sts.googleapis.com" \ --attribute-mapping="google.subject=\"gcpcs\ ::\"+assertion.submods.container.image_digest+\"\ ::\"+assertion.submods.gce.project_number+\"\ ::\"+assertion.submods.gce.instance_id,\ attribute.image_digest=assertion.submods.container.image_digest" \ --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE'"כדי לקבל את מספר הפרויקט של אלכס בשביל הפקודה הבאה:
gcloud projects describe ALEX_PROJECT_ID --format="value(projectNumber)"נותנים לזהות המאוחדת שהוגדרה על ידי הספק של אלכס את התפקיד
cloudkms.cryptoKeyDecrypter, ומציינים את המאפייןimage_digestכדי שרק למאגרי עומסי עבודה עם הגיבוב שצוין תהיה אפשרות לפענח את המפתחות שלהם ב-KMS:gcloud kms keys add-iam-policy-binding \ "projects/ALEX_PROJECT_ID/locations/global/\ keyRings/ALEX_KEYRING_NAME/\ cryptoKeys/ALEX_KEY_NAME" \ --member="principalSet://iam.googleapis.com/\ projects/ALEX_PROJECT_NUMBER/locations/global/\ workloadIdentityPools/ALEX_POOL_NAME/\ attribute.image_digest/WORKLOAD_CONTAINER_IMAGE_DIGEST" \ --role=roles/cloudkms.cryptoKeyDecrypterמעבר לפרויקט של בולה:
gcloud config set project BOLA_PROJECT_IDמזינים את הפקודה הבאה כדי ליצור את הספק עבור Bola:
gcloud iam workload-identity-pools providers create-oidc attestation-verifier \ --location=global \ --workload-identity-pool=BOLA_POOL_NAME \ --issuer-uri="https://confidentialcomputing.googleapis.com/" \ --allowed-audiences="https://sts.googleapis.com" \ --attribute-mapping="google.subject=\"gcpcs\ ::\"+assertion.submods.container.image_digest+\"\ ::\"+assertion.submods.gce.project_number+\"\ ::\"+assertion.submods.gce.instance_id,\ attribute.image_digest=assertion.submods.container.image_digest" \ --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE'"כדי להשתמש בפקודה הבאה, צריך לקבל את מספר הפרויקט של בולה:
gcloud projects describe BOLA_PROJECT_ID --format="value(projectNumber)"נותנים לזהות המאוחדת שהוגדרה על ידי הספק של בולה את התפקיד
cloudkms.cryptoKeyDecrypter, ומציינים את המאפייןimage_digestכדי שרק קונטיינרים של עומסי עבודה עם ה-digest שצוין יוכלו לפענח את מפתחות ה-KMS שלהם:gcloud kms keys add-iam-policy-binding \ "projects/BOLA_PROJECT_ID/locations/global/\ keyRings/BOLA_KEYRING_NAME/\ cryptoKeys/BOLA_KEY_NAME" \ --member="principalSet://iam.googleapis.com/\ projects/BOLA_PROJECT_NUMBER/locations/global/\ workloadIdentityPools/BOLA_POOL_NAME/\ attribute.image_digest/WORKLOAD_CONTAINER_IMAGE_DIGEST" \ --role=roles/cloudkms.cryptoKeyDecrypter
בדיקת עומס העבודה
אחרי שמוסיפים ספקים למאגרי הזהויות של עומסי העבודה של אלכס ושל בולה, ומוודאים שהמשאבים הנדרשים קיימים, הגיע הזמן שאופרטור עומס העבודה יבדוק את עומס העבודה.
כדי לבדוק את עומס העבודה, יוצרים מכונת VM חדשה מסוג Confidential בפרויקט של בולה עם המאפיינים הבאים:
תצורה נתמכת עם AMD SEV, Intel TDX או Intel TDX עם NVIDIA Confidential Computing.
ההפעלה המאובטחת מופעלת.
מערכת הפעלה שמבוססת על תמונת ניפוי הבאגים של Confidential Space, כדי להקל על פתרון בעיות.
הפניה אל קובץ האימג' של Docker שאליקס יצר קודם. הוא נטען מעל התמונה של Confidential Space.
חשבון שירות מצורף שנוצר על ידי בולה בשלב מוקדם יותר, שמריץ את עומס העבודה.
STDOUTו-STDERRמופנים גם אל Cloud Logging וגם אל מסוף הנתונים הסדרתיים.פרטי המשאב שעומס העבודה צריך, מוגדרים כמשתני סביבה.
מזינים את הפקודה הבאה ב-Cloud Shell של בולה כדי לבדוק את עומס העבודה:
gcloud compute instances create WORKLOAD_VM_2_NAME \
--confidential-compute-type=SEV \
--shielded-secure-boot \
--scopes=cloud-platform \
--zone=us-west1-b \
--maintenance-policy=MIGRATE \
--min-cpu-platform="AMD Milan" \
--image-project=confidential-space-images \
--image-family=confidential-space-debug \
--service-account=WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
--metadata="^~^tee-image-reference=us-docker.pkg.dev/\
ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest\
~tee-container-log-redirect=true\
~tee-env-COLLAB_1_NAME=Alex\
~tee-env-COLLAB_2_NAME=Bola\
~tee-env-COLLAB_1_ENCRYPTED_SALARY=ALEX_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_2_ENCRYPTED_SALARY=BOLA_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_1_INPUT_BUCKET=ALEX_INPUT_BUCKET_NAME\
~tee-env-COLLAB_2_INPUT_BUCKET=BOLA_INPUT_BUCKET_NAME\
~tee-env-COLLAB_1_OUTPUT_BUCKET=ALEX_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_2_OUTPUT_BUCKET=BOLA_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_1_KEYRING_NAME=ALEX_KEYRING_NAME\
~tee-env-COLLAB_2_KEYRING_NAME=BOLA_KEYRING_NAME\
~tee-env-COLLAB_1_KEY_NAME=ALEX_KEY_NAME\
~tee-env-COLLAB_2_KEY_NAME=BOLA_KEY_NAME\
~tee-env-COLLAB_1_PROJECT_ID=ALEX_PROJECT_ID\
~tee-env-COLLAB_2_PROJECT_ID=BOLA_PROJECT_ID\
~tee-env-COLLAB_1_PROJECT_NUMBER=ALEX_PROJECT_NUMBER\
~tee-env-COLLAB_2_PROJECT_NUMBER=BOLA_PROJECT_NUMBER\
~tee-env-COLLAB_1_POOL_NAME=ALEX_POOL_NAME\
~tee-env-COLLAB_2_POOL_NAME=BOLA_POOL_NAME"
הצגת ההתקדמות
כדי לראות את ההתקדמות של עומס העבודה בפרויקט של בולה, עוברים אל כלי לבדיקת יומנים.
כדי להציג רק רשומות ביומן של Confidential Space, מסננים לפי שדות היומן הבאים, אם הם זמינים:
סוג המשאב: מכונת VM
Instance ID: מזהה המופע של מכונת ה-VM
שם היומן: confidential-space-launcher
כדי לרענן את היומן, לוחצים על מעבר להיום. אפשר גם לגלול לתוצאות קודמות, ואז לגלול שוב לסוף היומן כדי לטעון את הרשומות האחרונות.
צפייה בתוצאות
אם משימת העומס מסתיימת ומחזירה 0, זה אומר שלא התרחשו שגיאות ושהגיע הזמן לבדוק את הפלט בקטגוריות הפלט של אלכס ובולה:
מעבר לפרויקט של אלכס:
gcloud config set project ALEX_PROJECT_IDמציגים רשימה של כל הקבצים בקטגוריית התוצאות שלהם:
gcloud storage ls gs://ALEX_OUTPUT_BUCKET_NAMEקוראים את הקובץ האחרון שמופיע ברשימה, ומחליפים את
ALEX_OUTPUT_CLOUD_STORAGE_PATHבנתיב של הקובץ, כוללgs://:gcloud storage cat ALEX_OUTPUT_CLOUD_STORAGE_PATHאם אין קובץ, צריך לנפות באגים בעומס העבודה.
מעבר לפרויקט של בולה:
gcloud config set project BOLA_PROJECT_IDמציגים רשימה של כל הקבצים בקטגוריית התוצאות שלהם:
gcloud storage ls gs://BOLA_OUTPUT_BUCKET_NAMEקוראים את הקובץ האחרון שמופיע ברשימה, ומחליפים את
BOLA_RESULTS_CLOUD_STORAGE_PATHבנתיב של הקובץ, כוללgs://:gcloud storage cat BOLA_RESULTS_CLOUD_STORAGE_PATHאם אין קובץ, צריך לנפות באגים בעומס העבודה.
אחרי שקוראים את התוצאות, מפסיקים את מכונת ה-VM:
gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b
אלכס ובולה קוראים את הקבצים ומגלים מי מרוויח יותר, בלי לחשוף אחד לשני את המשכורות שלהם.
ניפוי באגים והפעלה מחדש של עומס העבודה
סביבת Confidential Space מורכבת מחלקים רבים, ויכול להיות שמשהו הוגדר בצורה שגויה וגורם לכך שעומס העבודה ייכשל.
בניגוד לתמונה של Confidential Space בסביבת הייצור, תמונת הניפוי שומרת על הפעלת מכונת ה-VM אחרי שעומס העבודה מסתיים. כלומר, אם הקבצים לא מספקים מספיק מידע לפתרון הבעיה, השלב הבא הוא להתחבר למופע של מכונה וירטואלית באמצעות SSH ולהמשיך בניפוי הבאגים.
אחרי שמסיימים את ניפוי הבאגים, מפסיקים את מופע ה-VM:
gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b
כדי להריץ את עומס העבודה בסביבה שעברה ניפוי באגים, מפעילים מחדש את המכונה הווירטואלית:
gcloud compute instances start WORKLOAD_VM_2_NAME --zone=us-west1-b
הגברת האבטחה של הסביבה לצורך ייצור
אחרי שבודקים את workload ומוודאים שהוא פועל כמו שצריך, הגיע הזמן להקשיח את סביבת Confidential Space לקראת פריסה בסביבת הייצור. אלכס ובולה צריכים להוסיף הצהרת support_attributes לספקים שלהם כדי לוודא שנעשה שימוש בתמונה של סביבת הייצור של Confidential Space עבור עומס העבודה:
מעבר לפרויקט של אלכס:
gcloud config set project ALEX_PROJECT_IDמזינים את הפקודה הבאה כדי לעדכן את הספק של אלכס:
gcloud iam workload-identity-pools providers update-oidc attestation-verifier \ --location=global \ --workload-identity-pool=ALEX_POOL_NAME \ --issuer-uri="https://confidentialcomputing.googleapis.com/" \ --allowed-audiences="https://sts.googleapis.com" \ --attribute-mapping="google.subject=\"gcpcs\ ::\"+assertion.submods.container.image_digest+\"\ ::\"+assertion.submods.gce.project_number+\"\ ::\"+assertion.submods.gce.instance_id,\ attribute.image_digest=assertion.submods.container.image_digest" \ --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' \ && 'STABLE' in assertion.submods.confidential_space.support_attributes"מעבר לפרויקט של בולה:
gcloud config set project BOLA_PROJECT_IDמזינים את הפקודה הבאה כדי לעדכן את הספק של Bola:
gcloud iam workload-identity-pools providers update-oidc attestation-verifier \ --location=global \ --workload-identity-pool=BOLA_POOL_NAME \ --issuer-uri="https://confidentialcomputing.googleapis.com/" \ --allowed-audiences="https://sts.googleapis.com" \ --attribute-mapping="google.subject=\"gcpcs\ ::\"+assertion.submods.container.image_digest+\"\ ::\"+assertion.submods.gce.project_number+\"\ ::\"+assertion.submods.gce.instance_id,\ attribute.image_digest=assertion.submods.container.image_digest" \ --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' \ && 'STABLE' in assertion.submods.confidential_space.support_attributes"
פריסת עומס העבודה בסביבת הייצור
Bola צריכה ליצור מכונה וירטואלית נפרדת כדי להריץ את עומס העבודה של הייצור. ההבדלים הבאים בהשוואה לעומס העבודה של הבדיקה:
מערכת ההפעלה מבוססת על תמונה של Confidential Space בייצור. ה-SSH מושבת, ומופע המכונה הווירטואלית מפסיק לפעול אחרי שעומס העבודה מסתיים.
ההפניה האוטומטית של הרישום הוסרה. ב-Cloud Logging מוצגים רק יומנים בסיסיים שלא חושפים מידע רגיש.
מזינים את הפקודה הבאה ב-Cloud Shell של בולה כדי לפרוס את עומס העבודה של הסביבה הפרודקטיבית:
gcloud compute instances create WORKLOAD_VM_NAME \
--confidential-compute-type=SEV \
--shielded-secure-boot \
--scopes=cloud-platform \
--zone=us-west1-b \
--maintenance-policy=MIGRATE \
--image-project=confidential-space-images \
--image-family=confidential-space \
--service-account=WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
--metadata="^~^tee-image-reference=us-docker.pkg.dev/\
ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest\
~tee-env-COLLAB_1_NAME=Alex\
~tee-env-COLLAB_2_NAME=Bola\
~tee-env-COLLAB_1_ENCRYPTED_SALARY=ALEX_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_2_ENCRYPTED_SALARY=BOLA_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_1_INPUT_BUCKET=ALEX_INPUT_BUCKET_NAME\
~tee-env-COLLAB_2_INPUT_BUCKET=BOLA_INPUT_BUCKET_NAME\
~tee-env-COLLAB_1_OUTPUT_BUCKET=ALEX_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_2_OUTPUT_BUCKET=BOLA_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_1_KEYRING_NAME=ALEX_KEYRING_NAME\
~tee-env-COLLAB_2_KEYRING_NAME=BOLA_KEYRING_NAME\
~tee-env-COLLAB_1_KEY_NAME=ALEX_KEY_NAME\
~tee-env-COLLAB_2_KEY_NAME=BOLA_KEY_NAME\
~tee-env-COLLAB_1_PROJECT_ID=ALEX_PROJECT_ID\
~tee-env-COLLAB_2_PROJECT_ID=BOLA_PROJECT_ID\
~tee-env-COLLAB_1_PROJECT_NUMBER=ALEX_PROJECT_NUMBER\
~tee-env-COLLAB_2_PROJECT_NUMBER=BOLA_PROJECT_NUMBER\
~tee-env-COLLAB_1_POOL_NAME=ALEX_POOL_NAME\
~tee-env-COLLAB_2_POOL_NAME=BOLA_POOL_NAME"
הדרך שבה רואים את ההתקדמות ורואים את התוצאות זהה לדרך שבה בודקים את עומס העבודה.
כשעומס העבודה של הייצור מסתיים, מופעלת עצירה של מופע המכונה הווירטואלית. כדי לראות תוצאות שונות, אפשר לשנות את המשכורות, להצפין אותן מחדש, להעלות אותן מחדש לדליים המתאימים ב-Cloud Storage, ואז להפעיל מחדש את המכונה הווירטואלית כדי להריץ שוב את עומס העבודה:
gcloud compute instances start WORKLOAD_VM_NAME --zone=us-west1-b
הסרת המשאבים
כדי להסיר את המשאבים שנוצרו במדריך הזה, מבצעים את ההוראות הבאות.
פינוי משאבי הבדיקה של אלכס
מעבר לפרויקט של אלכס:
gcloud config set project ALEX_PROJECT_IDמחיקת מאגר הזהויות של עומסי העבודה של Alex:
gcloud iam workload-identity-pools delete ALEX_POOL_NAME \ --location=globalמחיקת הקטגוריות של אלכס ב-Cloud Storage:
gcloud storage rm gs://ALEX_INPUT_BUCKET_NAME \ gs://ALEX_OUTPUT_BUCKET_NAME --recursiveלמחוק את קובצי השכר של אלכס, את קוד ה-Go ואת
Dockerfile:rm ALEX_SALARY.txt \ ALEX_ENCRYPTED_SALARY_FILE \ salary.go \ Dockerfileאופציונלי: משביתים או משמידים את המפתח של אלכס ב-Cloud Key Management Service.
אופציונלי: השבתת הפרויקט של אלכס.
לפנות את המשאבים של Bola
מעבר לפרויקט של בולה:
gcloud config set project BOLA_PROJECT_IDמוחקים את מכונת ה-VM שהריצה את תהליך העבודה של הבדיקה:
gcloud compute instances delete WORKLOAD_VM_2_NAME --zone=us-west1-bמוחקים את המכונה הווירטואלית שהריצה את תהליך העבודה של הייצור:
gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-bמוחקים את חשבון השירות שהפעיל את עומס העבודה:
gcloud iam service-accounts delete \ WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.comמחיקת מאגר הזהויות של עומסי העבודה של Bola:
gcloud iam workload-identity-pools delete BOLA_POOL_NAME \ --location=globalמחיקת הקטגוריות של Bola ב-Cloud Storage:
gcloud storage rm gs://BOLA_INPUT_BUCKET_NAME \ gs://BOLA_OUTPUT_BUCKET_NAME --recursiveמחיקת קובצי השכר של בולה:
rm BOLA_SALARY.txt \ BOLA_ENCRYPTED_SALARY_FILEאופציונלי: משביתים או משמידים את המפתח של Bola ב-Cloud Key Management Service.
אופציונלי: השבתת הפרויקט של בולה.