איך מפעילים פונקציות מאומתות ב-Cloud Run

1. מבוא

סקירה כללית

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

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

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

מה תלמדו

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

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

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

הפעלת Cloud Shell

  1. ב-Cloud Console, לוחצים על Activate Cloud Shell d1264ca30785e435.png.

84688aa223b1c3a2.png

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

d95252b003979716.png

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

7833d5e1c5d18f54.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 Run מאומתת

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

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

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

REGION=us-central1
PROJECT_ID=$(gcloud config get-value project)

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

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

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

mkdir auth-function-codelab && cd $_

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

touch package.json

echo '{
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.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

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

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

FUNCTION_NAME=authenticated-function-codelab
ENTRY_POINT=helloWorld

כדי לפרוס פונקציית Cloud Run ישירות ב-Cloud Run, מריצים את הפקודה הבאה:

gcloud beta run deploy $FUNCTION_NAME \
      --source . \
      --function helloWorld \
      --region $REGION \
      --no-allow-unauthenticated

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

FUNCTION_URL="$(gcloud run services describe $FUNCTION_NAME --region $REGION --format 'value(status.url)')"

אם אתם מעדיפים לפרוס כ-Cloud Functions מדור שני, משתמשים בפקודה הבאה:

gcloud functions deploy nodejs-http-function \
  --gen2 \
  --runtime=nodejs20 \
  --region=$REGION \
  --source=. \
  --entry-point=helloWorld \
  --trigger-http \
  --no-allow-unauthenticated

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

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

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

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

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

curl -i $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`

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

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

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

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

Hello World!

פתרון בעיות

אם מוצגת השגיאה 403 Forbidden, צריך לוודא שלזהות שלכם יש את התפקיד 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 Run function Authentication codelab"

מקצים לחשבון השירות את התפקיד Cloud Run Invoker:

gcloud run services add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1  \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role='roles/run.invoker'

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

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

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

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

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

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

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. יצירת ספרייה חדשה
mkdir local-dev && cd $_
  1. יצירת אפליקציית Node.js חדשה
npm init -y
  1. התקנה של ספריית הלקוח של Google Auth
npm install google-auth-library
  1. יצירת קובץ index.js
  2. מאחזרים את כתובת ה-URL של פונקציית Cloud Run, שתוסיפו לקוד בשלב הבא.
echo $FUNCTION_URL
  1. מוסיפים את הקוד הבא אל index.js. חשוב לשנות את המשתנה targetAudience לכתובת ה-URL של פונקציית Cloud Run.

index.js

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

const targetAudience = '<YOUR-CLOUD-RUN-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 Run.

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

מה נכלל

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

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

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

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

gcloud auth application-default login

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

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

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