איך מפעילים Cloud Functions מאומתים

1. מבוא

סקירה כללית

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

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

  1. שימוש באסימון הזהות של gcloud כדי להפעיל פונקציה למטרות פיתוח ובדיקה מקומיות
  2. להתחזות לחשבון שירות כשמפתחים ובודקים באופן מקומי כדי להשתמש באותם פרטי כניסה כמו בסביבת הייצור
  3. להשתמש בספריות לקוח של Google כדי לטפל באימות ל-Google Cloud APIs, למשל כששירות צריך להפעיל פונקציה

מה תלמדו

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

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

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

  • אתם מחוברים ל-Cloud Console
  • פרסתם בעבר פונקציית Cloud Functions מדור שני עם טריגר HTTP
  • (אופציונלי) בתרחיש השלישי, ה-Codelab הזה משתמש ב-Node.js וב-npm כדוגמה, אבל אפשר להשתמש בכל סביבת זמן ריצה שנתמכת על ידי ספריות הלקוח של Google Auth.

הפעלת 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

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

אם נדרש אימות, זה אומר שהגורם הראשי שמפעיל את הפונקציה צריך לקבל את התפקידים Cloud Functions Invoker (מפעיל Cloud Functions) ו-Cloud Run Invoker (מפעיל Cloud Run) (בדור השני). אחרת, הפונקציה תחזיר שגיאה מסוג 403 Forbidden (אסור). ב-Codelab הזה נסביר איך להעניק את התפקידים המתאימים של Invoker למשתמש.

יצירת פונקציה מאומתת

כך משתמשים במסוף Cloud:

  1. נכנסים לדף Cloud Functions Overview (סקירה כללית של Cloud Functions) ולוחצים על Create Function (יצירת פונקציה).
  2. בקטע סביבה, בוחרים באפשרות דור שני.
  3. נותנים שם לפונקציה my-authenticated-function
  4. בשדה 'אימות', משאירים את ברירת המחדל דרוש אימות.

936eee0d5930d12b.png

  1. לוחצים על הבא.
  2. ב-Codelab הזה, אתם יכולים לבחור כל שפה
  3. אחר כך לוחצים על פריסה.

פריסת הפונקציה נמשכת כדקה.

הגדרה של משתני סביבה מקומיים לפקודות gcloud פשוטות יותר

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

צריך לציין את האזור של הפונקציה. בדוגמה הזו נשתמש ב-us-central1.

REGION="us-central1"

ואז אפשר לשמור את כתובת ה-URL של הפונקציה כמשתנה סביבה לשימוש בהמשך.

PROJECT_ID=$(gcloud config get-value project)
FUNCTION_URL="$(gcloud functions describe my-authenticated-function --gen2 --region us-central1 --format='get(serviceConfig.uri)')"

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

תפעילו את הפונקציה ללא אימות כדי לוודא שמתקבלת שגיאת 403 הצפויה.

מריצים את הפקודה curl הבאה משורת הפקודה:

curl $FUNCTION_URL

תוצג התוצאה הבאה:

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/</code> from this server.</h2>
<h2></h2>
</body></html>

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

4. תרחיש 1: שימוש בטוקן הזהות של gcloud

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

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

gcloud auth list

כוכבית אמורה להופיע לצד הזהות הפעילה, לדוגמה:

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

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

ACCOUNT_EMAIL=$(gcloud auth list --filter=status:ACTIVE --format="value(account)")

מידע נוסף על הגדרת gcloud init ועל gcloud auth login זמין במסמכי העזרה.

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

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token)"

עכשיו תראו את התוצאה:

Hello World!

פתרון בעיות

אם מוצגת שגיאת 403 Forbidden, צריך לוודא שלזהות שלכם יש את התפקיד Cloud Functions Invoker או את התפקיד Cloud Run Invoker עבור פונקציות מהדור השני. אתם יכולים להשתמש במסוף IAM כדי לאמת את התפקידים שניתנו לחשבון ראשי.

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

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

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

5. תרחיש 2: התחזות לחשבון שירות

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

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

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

יצירת חשבון שירות חדש

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

SERVICE_ACCOUNT_NAME="invoke-functions-codelab"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com

אחר כך יוצרים את חשבון השירות.

gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
  --display-name="Cloud Function Authentication codelab"

ומקצים לחשבון השירות את התפקיד 'הפעלת פונקציות של Cloud Functions'

gcloud functions add-iam-policy-binding my-authenticated-function \
  --region=us-central1 --gen2 \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role='roles/cloudfunctions.invoker'

הפעלת הפונקציה באמצעות התחזות לחשבון השירות

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

הוספת תפקידים נדרשים לחיקוי זהות

כדי להתחזות לחשבון שירות, לחשבון המשתמש שלכם צריך להיות התפקיד 'יצירת אסימונים בחשבון שירות' (roles/iam.serviceAccountTokenCreator) כדי ליצור אסימון מזהה לחשבון השירות.

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_ADDRESS  \
  --member user:$ACCOUNT_EMAIL \
  --role='roles/iam.serviceAccountTokenCreator'

שימוש באסימון המזהה של חשבון השירות

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

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token --impersonate-service-account $SERVICE_ACCOUNT_ADDRESS)" 

יוצגו הפרטים הבאים:

WARNING: This command is using service account impersonation. All API calls will be executed as [invoke-functions-codelab@<project-id>.iam.gserviceaccount.com].
Hello World!

6. תרחיש 3: שימוש בספריות לקוח של Google

בחלק האחרון של ה-codelab הזה, תריצו שירות קטן באופן מקומי כדי ליצור אסימון מזהה לחשבון שירות, ואז תבצעו קריאה לפונקציה באופן פרוגרמטי באמצעות ספריות הלקוח של Google Auth וApplication Default Credentials (‏ADC). מידע נוסף על ספריות לקוח של Google זמין בקטע 'הסבר על ספריות לקוח' במסמכים.

השימוש ב-ADC חשוב במיוחד כשרוצים לכתוב ולבדוק את הפונקציה באופן מקומי (למשל במחשב הנייד, ב-Cloud Shell וכו') תוך אינטראקציה עם משאבים אחרים של Google Cloud (למשל Cloud Storage,‏ Vision API וכו'). בדוגמה הזו נראה איך שירות מפעיל פונקציה אחרת שנדרש אימות כדי להשתמש בה. מידע נוסף על ADC ופיתוח מקומי זמין בפוסט בבלוג How to develop and test your Cloud Functions locally | Google Cloud Blog (איך לפתח ולבדוק את Cloud Functions באופן מקומי | הבלוג של Google Cloud).

מריצים את פקודת gcloud כדי להתחזות לחשבון שירות

השירות ADC מוצא את פרטי הכניסה באופן אוטומטי על סמך הסביבה שבה פועלת האפליקציה, ומשתמש בהם לאימות מול ממשקי ה-API של Google Cloud. הדגל ‎–impersonate-service-account מאפשר לכם להתחזות לחשבון שירות באמצעות הזהות שלו לצורך אימות מול Google Cloud APIs.

כדי להתחזות לחשבון שירות, אפשר להריץ את הפקודה הבאה:

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

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

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

לכל סביבת ריצה יש ספריית לקוח משלה של Google Auth שאפשר להתקין. ב-Codelab הזה נסביר איך ליצור ולהריץ אפליקציית Node.js באופן מקומי.

אלה השלבים ל-Node.js:

  1. יצירת אפליקציית Node.js חדשה
npm init
  1. התקנה של ספריית הלקוח של Google Auth
npm install google-auth-library
  1. יצירת קובץ index.js
  2. מאחזרים את כתובת ה-URL של פונקציית Cloud Functions, שתוסיפו לקוד בשלב הבא.
echo $FUNCTION_URL
  1. מוסיפים את הקוד הבא אל index.js. חשוב לשנות את המשתנה targetAudience לכתובת ה-URL של Cloud Function.

index.js

// Cloud Functions uses your function's url as the `targetAudience` value

const targetAudience = '<YOUR-CLOUD-FUNCTION-URL>';

// For Cloud Functions, endpoint(`url`) and `targetAudience` should be equal

const url = targetAudience;

const { GoogleAuth } = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
    console.info(`request ${url} with target audience ${targetAudience}`);

    // this call retrieves the ID token for the impersonated service account
    const client = await auth.getIdTokenClient(targetAudience);

    const res = await client.request({ url });
    console.info(res.data);
}

request().catch(err => {
    console.error(err.message);
    process.exitCode = 1;
});
  1. הפעלת האפליקציה
node index.js

אחרי זה אמור להופיע הטקסט 'Hello World!‎'.

פתרון בעיות

אם מוצגת השגיאה 'ההרשאה iam.serviceAccounts.getOpenIdToken נדחתה במשאב (או שהוא לא קיים)', צריך להמתין כמה דקות עד שהתפקיד 'יצירת אסימונים בחשבון שירות' יופעל.

אם קיבלתם את השגיאה Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to a service account credentials JSON file, יכול להיות ששכחתם להריץ את הפקודה

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

7. מעולה!

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

מומלץ לעיין במסמכים בנושא אבטחת Cloud Functions.

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

מה נכלל

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

8. הסרת המשאבים

כדי להימנע מחיובים לא מכוונים (לדוגמה, אם הפונקציה של Cloud Functions מופעלת בטעות יותר פעמים מההקצאה החודשית של הפעלות של Cloud Functions ברמת השימוש ללא תשלום), אפשר למחוק את הפונקציה של Cloud Functions או למחוק את הפרויקט שיצרתם בשלב 2.

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

gcloud auth application-default login

כדי למחוק את Cloud Function, עוברים אל Cloud Function Cloud Console בכתובת https://console.cloud.google.com/functions/. מוודאים שהפרויקט שיצרתם בשלב 2 הוא הפרויקט שנבחר כרגע.

בוחרים את my-authenticated-function שפרסתם קודם. ואז לוחצים על מחיקה.

אם אתם רוצים למחוק את הפרויקט כולו, אתם יכולים להיכנס לכתובת https://console.cloud.google.com/cloud-resource-manager, לבחור את הפרויקט שיצרתם בשלב 2 וללחוץ על 'מחיקה'. אם תמחקו את הפרויקט, תצטרכו לשנות את הפרויקטים ב-Cloud SDK. כדי לראות את רשימת כל הפרויקטים הזמינים, מריצים את הפקודה gcloud projects list.