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

1. מבוא

סקירה כללית

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

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

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

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

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

מה תפַתחו

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

מה תלמדו

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

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

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

  • אתם מחוברים למסוף Cloud
  • פרסתם בעבר פונקציה של Cloud Functions שפועלת ב-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)")"

בשלב הבא יוצרים אוסף מפתחות שהוא המשאב הבסיסי (root) של מפתחות 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 Functions.

תחילה צריך את חשבון השירות של 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

ונותנים את התפקיד לעקרון שיוצר את המאגר במרשם של פריטי מידע שנוצרו בתהליך הפיתוח (Artifact), למשל: בחשבון הפעיל הנוכחי. כדי לאמת את החשבון הפעיל, מריצים רשימת auth של gcloud.

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. איך נותנים לחשבונות שירות הרשאת גישה למפתח (דור שני)

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

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

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

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

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

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

אמנם ה-codelab הזה משתמש ב-Node.js, אבל אפשר להשתמש בכל סביבת זמן ריצה נתמכת.

קודם כל, יוצרים ספרייה ותקליטור בספרייה הזו.

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 מתארות $FUNCTION_NAME –region $REGION | gRep kmsKeyName

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

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

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, אבל אפשר להשתמש בכל סביבת זמן ריצה נתמכת.

קודם כל, יוצרים ספרייה ותקליטור בספרייה הזו.

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 מתארות $FUNCTION_NAME –region $REGION | gRep kmsKeyName

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

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

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

curl $FUNCTION_URL

שהתוצאה שלו היא:

Hello World!

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

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

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

ולא תקבל תגובה 'שלום עולם' הפעם.

ביומנים של הפונקציה של 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. מזל טוב

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

אילו נושאים דיברנו?

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

מידע נוסף

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