הצפנת Cloud Functions באמצעות מפתחות הצפנה בניהול הלקוח (CMEK)

1. מבוא

סקירה כללית

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

אתם יכולים להשתמש במפתחות הצפנה בניהול הלקוח (CMEK) של Cloud Key Management Service כדי להגן על Cloud Functions ועל נתונים קשורים במנוחה. פריסת פונקציה עם CMEK מגינה על הנתונים המשויכים אליה באמצעות מפתח הצפנה שנמצא בשליטתכם המלאה. סוג ההצפנה הזה מאפשר לעמוד בדרישות התאימות בענפים מסוימים, כמו שירותים פיננסיים. מכיוון שהמפתח בבעלותכם ולא בשליטת Google, אף אחד (כולל אתכם) לא יכול לגשת לנתונים שמוגנים על ידי מפתחות ההצפנה האלה כשהמפתחות מושבתים או נהרסים.

ב-Cloud Functions, CMEK מצפין את הנתונים הבאים:

  • קוד המקור של הפונקציה, שהועלו לפריסה ונשמרו על ידי Google ב-Cloud Storage, ומשמשים בתהליך ה-build.
  • התוצאות של תהליך ה-build של הפונקציה, כולל קובץ האימג' בקונטיינר שנוצר מקוד המקור של הפונקציה, כל מופע של הפונקציה שפורס.
  • נתונים במצב מנוחה לערוצים פנימיים של העברת אירועים (דור ראשון בלבד).

מידע נוסף על הנתונים שמאובטחים בהצפנה מופיע במסמכי התיעוד של Cloud Function CMEK.

מה תפַתחו

בשיעור הזה תלמדו איך לפרוס פונקציה ב-Cloud Functions (דור ראשון או דור שני) שמופעלת בה הצפנה באמצעות CMEK. במסגרת הקודלאב הזה נעשה שימוש בפונקציה ציבורית ב-Cloud Functions, כלומר פונקציה שלא דורשת אימות, למטרות הדגמה. אפשר להפעיל פונקציה מאומתת עם CMEK כמו כל פונקציית Cloud Function אחרת שדורשת אימות.

מה תלמדו

  • איך יוצרים מפתח CMEK על אוסף מפתחות סימטרי קיים
  • איך יוצרים מאגר ב-Artifact Registry
  • איך מגדירים CMEK בפונקציה של Cloud Functions גם לדור הראשון וגם לדור השני

2. הגדרה ודרישות

דרישות מוקדמות

  • אתם מחוברים למסוף Cloud
  • כבר פרסתם בעבר פונקציית Cloud שמופעלת על ידי HTTP (כדי לוודא שהתפקידים וממשקי ה-API המתאימים מופעלים)

הפעלת Cloud Shell

  1. במסוף Cloud, לוחצים על Activate Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים שמתאר מהו. אם יוצג לכם מסך ביניים, תוכלו ללחוץ על המשך.

9c92662c6a846a5c.png

תהליך ההקצאה וההתחברות ל-Cloud Shell אמור להימשך רק כמה רגעים.

9f0e51b578fecce5.png

המכונה הווירטואלית הזו כוללת את כל הכלים הנדרשים לפיתוח. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, משפרת מאוד את הביצועים והאימות של הרשת. אפשר לבצע את רוב העבודה ב-codelab הזה, אם לא את כולה, באמצעות דפדפן.

אחרי ההתחברות ל-Cloud Shell, אתם אמורים לראות שהפרויקט מאומת ושהפרויקט מוגדר לפי מזהה הפרויקט שלכם.

  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שהאימות בוצע:
gcloud auth list

פלט הפקודה

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שהפקודה gcloud מכירה את הפרויקט:
gcloud config list project

פלט הפקודה

[core]
project = <PROJECT_ID>

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

gcloud config set project <PROJECT_ID>

פלט הפקודה

Updated property [core/project].

3. יצירת אוסף מפתחות ומפתח חדשים ל-Cloud Functions

מריצים את הפקודה הבאה כדי לוודא ש-Cloud KMS API מופעל:

gcloud services enable cloudkms.googleapis.com

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

KEYRING_NAME="keyring-functions"
REGION="us-central1"
KEY_NAME="key-encrypted-function"
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER="$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')"
USER_EMAIL="$(gcloud config list account --format "value(core.account)")"

בשלב הבא יוצרים אוסף מפתחות, שהוא משאב הבסיס למפתחות ולגרסאות של מפתחות ב-Cloud KMS.

gcloud kms keyrings create $KEYRING_NAME --location $REGION

לבסוף, עכשיו אפשר ליצור מפתח סימטרי באוסף המפתחות החדש ב-Cloud KMS.

gcloud kms keys create $KEY_NAME --keyring $KEYRING_NAME --location $REGION --purpose "encryption"

4. יצירת מאגר Artifact Registry שתואם ל-CMEK

בקטע הזה תלמדו ליצור מאגר בפורמט Docker ב-Artifact Registry עם CMEK מופעל. זהו המפתח שייעשה בו שימוש לפריסה של Cloud Function.

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

gcloud beta services identity create --service=artifactregistry.googleapis.com --project=$PROJECT_ID

משתמשים בפקודה הבאה כדי לתת את תפקיד CryptoKey Encrypter/Decrypter IAM (roles/cloudkms.cryptoKeyEncrypterDecrypter) לחשבון השירות של Artifact Registry כדי לקבל הרשאות למפתח:

gcloud kms keys add-iam-policy-binding \
  $KEY_NAME --location $REGION --keyring=$KEYRING_NAME \
  --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com \
  --role roles/cloudkms.cryptoKeyEncrypterDecrypter

מעניקים את התפקיד לחשבון המשתמש שיוצר את המאגר במרשם הארטיפקטים, למשל החשבון הפעיל הנוכחי שלכם. כדי לבדוק איזה חשבון פעיל, אפשר להריץ את הפקודה gcloud auth list.

gcloud kms keys add-iam-policy-binding \
       $KEY_NAME --location $REGION --keyring=$KEYRING_NAME \
       --member user:$USER_EMAIL \
       --role roles/cloudkms.cryptoKeyEncrypterDecrypter

עכשיו אפשר ליצור מאגר בפורמט Docker שמותאם ל-CMEK.

הערה: האזור חייב להיות זהה לאזור של מפתח CMEK.

REPO_NAME=my-cmek-encrypted-repo 

KEY_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/keyRings/"$KEYRING_NAME"/cryptoKeys/"$KEY_NAME" 

gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --kms-key=$KEY_FULLPATH \
    --async

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

gcloud artifacts repositories describe $REPO_NAME --location=$REGION

5. איך נותנים לחשבונות שירות הרשאת גישה למפתח (דור שני)

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

צריך להעניק גישה למפתח לכמה סוכני שירות על ידי הקצאת תפקיד IAM של CryptoKey Encrypter/Decrypter (roles/cloudkms.cryptoKeyEncrypterDecrypter). סוכני השירות האלה משמשים לקבלת גישה לקוד המקור שנשמר ב-Cloud Storage, לאחסון קובצי אימג' של פונקציות במאגר שמוגן על ידי CMEK ב-Artifact Registry ולפריסה של Cloud Function מוצפן באמצעות CMEK.

שלבים לפונקציות של דור שני

  1. מעניקים לסוכן השירות של Cloud Run גישה למפתח:
CLOUDRUN_SA=service-$PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$CLOUDRUN_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. מעניקים לסוכן השירות של Eventarc גישה למפתח:
EVENTARC_SA=service-$PROJECT_NUMBER@gcp-sa-eventarc.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$EVENTARC_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. מעניקים לסוכן השירות של Artifact Registry גישה למפתח:
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$AR_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. כדי לתת לסוכני השירות של Cloud Storage גישה למפתח:
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$STORAGE_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter

בקטע הבא נסביר איך יוצרים ומפרסים פונקציה מוצפנת ב-CMEK.

6. איך נותנים לחשבונות שירות הרשאת גישה למפתח (דור ראשון)

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

צריך להעניק גישה למפתח לכמה סוכני שירות על ידי הקצאת תפקיד IAM של CryptoKey Encrypter/Decrypter (roles/cloudkms.cryptoKeyEncrypterDecrypter). סוכני השירות האלה משמשים לקבלת גישה לקוד המקור שנשמר ב-Cloud Storage, לאחסון קובצי אימג' של פונקציות במאגר שמוגן על ידי CMEK ב-Artifact Registry ולפריסה של Cloud Function מוצפן באמצעות CMEK.

שלבים לפונקציות מדור ראשון

  1. נותנים לסוכן השירות של Cloud Functions גישה למפתח:
FUNCTION_SA=service-$PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$FUNCTION_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. מעניקים לסוכן השירות של Artifact Registry גישה למפתח:
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$AR_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter
  1. כדי לתת לסוכני השירות של Cloud Storage גישה למפתח:
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com

gcloud kms keys add-iam-policy-binding $KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION \
--member=serviceAccount:$STORAGE_SA \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter

בקטע הבא נסביר איך יוצרים ומפרסים פונקציה מוצפנת ב-CMEK.

7. יצירת פונקציה בהצפנת CMEK (דור שני)

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

עכשיו, אחרי שהגדרתם מאגר Artifact Registry עם CMEK מופעל והענקת גישה למפתח ל-Cloud Functions, אתם יכולים לפרוס פונקציה שמאובטחת באמצעות מפתח ה-CMEK.

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

יצירת קוד המקור של הפונקציה

למרות שבסדנת הקוד הזו נעשה שימוש ב-Node.js, אפשר להשתמש בכל סביבת זמן ריצה נתמכת.

קודם יוצרים ספרייה ומעבירים את נתיב העבודה (cd) לספרייה הזו.

mkdir ~/cmek-function-2ndgen && cd $_

לאחר מכן, יוצרים את הקובץ package.json.

touch package.json

echo '{
  "dependencies": {
    "@google-cloud/functions-framework": "^2.1.0"
  }
}
' > package.json

בשלב הבא יוצרים את קובץ המקור index.js.

touch index.js

echo 'const functions = require("@google-cloud/functions-framework");

functions.http("helloWorld", (req, res) => {
 res.send(`Hello ${req.query.name || req.body.name || "World"}!`);
});' > index.js

פריסת פונקציית Cloud Functions מדור שני באמצעות הצפנת CMEK

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

FUNCTION_NAME=protect-me-cmek-2ndgen
ENTRY_POINT=helloWorld

REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME

gcloud beta functions deploy $FUNCTION_NAME  \
--gen2 \
--region $REGION \
--kms-key $KEY_FULLPATH \
--docker-repository $REPO_FULLPATH \
--source . \
--trigger-http \
--allow-unauthenticated \
--runtime nodejs16 \
--entry-point $ENTRY_POINT

אפשר לראות את מפתח ה-CMEK מהפלט שנוצר על ידי הרצת הפקודה הבאה

gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName

בדיקת הפונקציה של דור שני

אפשר לבדוק את הפונקציה על ידי קריאה לה:

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(serviceConfig.uri)')"

curl $FUNCTION_URL

וכתוצאה מכך:

Hello World!

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

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

8. יצירת פונקציה מוצפנת באמצעות CMEK (דור ראשון)

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

עכשיו, אחרי שהגדרתם מאגר Artifact Registry עם CMEK מופעל והענקת גישה למפתח ל-Cloud Functions, אתם יכולים לפרוס פונקציה שמאובטחת באמצעות מפתח ה-CMEK.

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

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

למרות שבסדנת הקוד הזו נעשה שימוש ב-Node.js, אפשר להשתמש בכל סביבת זמן ריצה נתמכת.

קודם יוצרים ספרייה ומעבירים את נתיב העבודה (cd) לספרייה הזו.

mkdir ~/cmek-function-1stgen && cd $_

בשלב הבא יוצרים את הקובץ package.json.

touch package.json

echo '{
    "name": "function-cmek-codelab",
    "version": "0.0.1"
}' > package.json

לאחר מכן, יוצרים את קובץ המקור index.js.

touch index.js

echo "exports.helloWorld = (req, res) => {
    let message = req.query.message || req.body.message || 'Hello World!';
    res.status(200).send(message);
};" > index.js

פריסת פונקציית Cloud מדור ראשון באמצעות הצפנת CMEK

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

FUNCTION_NAME=protect-me-cmek-1stgen
ENTRY_POINT=helloWorld

REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME

gcloud functions deploy $FUNCTION_NAME  \
--region $REGION \
--kms-key $KEY_FULLPATH \
--docker-repository $REPO_FULLPATH \
--source . \
--trigger-http \
--allow-unauthenticated \
--runtime nodejs16 \
--entry-point $ENTRY_POINT

אפשר לראות את מפתח ה-CMEK מהפלט שנוצר על ידי הרצת הפקודה הבאה

gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName

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

אפשר לבדוק את הפונקציה על ידי קריאה לה:

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(httpsTrigger.url)')"

curl $FUNCTION_URL

וכתוצאה מכך:

Hello World!

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

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

9. קריאה לפונקציה מוצפנת ב-CMEK שבה מפתח ההצפנה הושבת

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

השבתת מפתח ההצפנה

אפשר להריץ את הפקודה הזו כדי להשבית את המפתח. מכיוון שה-Codelab הזה יוצר רק גרסה אחת של המפתח, הגרסה הזו תושבת.

gcloud kms keys versions disable 1 \
    --key=$KEY_NAME \
    --keyring=$KEYRING_NAME \
    --location=$REGION

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

algorithm: GOOGLE_SYMMETRIC_ENCRYPTION
createTime: '2023-04-11T03:30:49.111832653Z'
generateTime: '2023-04-11T03:30:49.111832653Z'
name: projects/dogfood-gcf-saraford/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function/cryptoKeyVersions/1
protectionLevel: SOFTWARE
state: DISABLED

הפעלת הפונקציה עם מפתח מושבת

עכשיו curl את הפונקציה שוב.

curl $FUNCTION_URL

ולא תקבלו הפעם את התשובה Hello World.

ביומני הפונקציה ב-Cloud Functions יופיע

User's CMEK key has been disabled. CMEK key: projects/<PROJECT-NAME>/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function

ניסיון להציג משאבים כשמפתח ה-CMEK מושבת

בקטע הזה מפורטים המשאבים הבאים שיהפכו ללא זמינים כשמפתח ה-CMEK יושבת:

  • קוד המקור של הפונקציה
  • פיתוח גרסת build של קונטיינר מקוד המקור

לדוגמה, כניסה לכרטיסייה 'מקור' של הפונקציה של Cloud Functions תציג שגיאה במהלך אחזור הארכיון. שגיאה דומה תופיע גם אם תנסו להציג את קובץ ה-zip שמכיל את קוד המקור ישירות ב-Cloud Storage.

ac3307bb05d30e19.png

בנוסף, לא תהיה לכם גישה לשימוש בקובץ האימג' של הקונטיינר של הפונקציה מ-Artifact Registry. לדוגמה, אם תנסו לפרוס את קובץ האימג' של הקונטיינר הזה ב-Cloud Run, תופיע הודעת שגיאה על כך שלא נמצא קובץ האימג'.

רשימה מלאה של משאבים מוצפנים זמינה במסמכי התיעוד של CMEK Functions.

10. מזל טוב

כל הכבוד, סיימת את הקודלאב!

מה עסקנו בו

  • איך יוצרים מפתח CMEK על אוסף מפתחות סימטרי קיים
  • איך ליצור מאגר של Artifact Registry
  • איך מגדירים CMEK בפונקציה של Cloud Functions

מידע נוסף

מידע נוסף על Cloud Functions ועל CMEK זמין בקישורים הבאים: