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

1. מבוא

סקירה כללית

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

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

ב-Cloud Functions, ‏ CMEK מצפין את הפריטים הבאים:

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

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

מה תפַתחו

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

מה תלמדו

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

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

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

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

הפעלת Cloud Shell

  1. ב-Cloud Console, לוחצים על 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 בפורמט Docker עם הפעלת CMEK

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

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

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

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

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

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

שלבים ל-Functions מדור שני

  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.

שלבים ל-Functions מדור ראשון

  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 שלכם.

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

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

למרות שב-Codelab הזה נעשה שימוש ב-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

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

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

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

curl $FUNCTION_URL

התוצאה היא:

Hello World!

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

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

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

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

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

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

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

למרות שב-Codelab הזה נעשה שימוש ב-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 Functions מדור ראשון באמצעות הצפנה מסוג 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

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

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

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

curl $FUNCTION_URL

התוצאה היא:

Hello World!

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

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

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

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

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

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

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 מושבת:

  • קוד המקור של הפונקציה
  • יצירת קובץ אימג' של קונטיינר מקוד המקור

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

ac3307bb05d30e19.png

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

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

10. מזל טוב

כל הכבוד, סיימתם את ה-Codelab!

מה נכלל

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

מידע נוסף

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