הדרכה בנושא אימות משתמשי קצה ב-Cloud Run

במדריך הזה נסביר איך ליצור שירות הצבעה שמורכב מהרכיבים הבאים:

  • לקוח מבוסס-דפדפן שמבצע את הפעולות הבאות:

    1. משתמש ב-Identity Platform כדי לאחזר טוקן של מזהה.
    2. המשתמשים יכולים להצביע לחיית הבית האהובה עליהם.
    3. מוסיף את הטוקן של המזהה לבקשה לשרת Cloud Run שמעבד את ההצבעה.
  • שרת Cloud Run שמבצע את הפעולות הבאות:

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

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

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

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

השירות הזה ממזער את סיכוני האבטחה באמצעות Secret Manager, כדי להגן על נתונים רגישים שמשמשים להתחברות למכונה של Cloud SQL. בנוסף, הוא משתמש בזהות שירות עם הרשאות מינימליות כדי לאבטח את הגישה למסד הנתונים.

מטרות

כתיבה, פיתוח ופריסה של שירות ב-Cloud Run שמראה איך:

  • משתמשים ב-Identity Platform כדי לאמת משתמש קצה ב-backend של שירות Cloud Run.

  • יצירת זהות עם הרשאות מינימליות לשירות כדי לתת גישה מינימלית למשאבי Google Cloud .

  • משתמשים ב-Secret Manager כדי לטפל בנתונים רגישים כשמחברים את שירות Cloud Run למסד נתונים של PostgreSQL.

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

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

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

לפני שמתחילים

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. מפעילים את ממשקי ה-API של Cloud Run,‏ Secret Manager,‏ Cloud SQL,‏ Artifact Registry ו-Cloud Build, אם הם עדיין לא מופעלים.

    התפקידים שנדרשים כדי להפעיל ממשקי API

    כדי להפעיל ממשקי API, צריך את ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    הפעלת ממשקי ה-API

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות להשלמת המדריך, בקשו מהאדמין לתת לכם את התפקידים הבאים ב-IAM ברמת הפרויקט:

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

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

הגדרת ברירות המחדל של ה-CLI של gcloud

כדי להגדיר את Google Cloud CLI עם ברירות מחדל לשירות Cloud Run:

  1. מגדירים את פרויקט ברירת המחדל:

    gcloud config set project PROJECT_ID

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

  2. מגדירים את Google Cloud CLI לאזור שבחרתם:

    gcloud config set run/region REGION

    מחליפים את REGION באזור הנתמך של Cloud Run לבחירתכם.

מיקומים של Cloud Run

‫Cloud Run הוא שירות אזורי, כלומר התשתית שמפעילה את שירותי Cloud Run נמצאת באזור ספציפי ומנוהלת על ידי Google, כך שהיא זמינה באופן יתיר בכל האזורים באותו אזור.

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

אפשר להשתמש ב-Cloud Run באזורים הבאים:

בכפוף לתמחור ברמה 1

בכפוף לתמחור ברמה 2

  • africa-south1 (יוהנסבורג)
  • asia-east2 (הונג קונג)
  • asia-northeast3 (סיאול, דרום קוריאה)
  • asia-southeast1 (סינגפור)
  • asia-southeast2 (ג'קרטה)
  • asia-south2 (דלהי, הודו)
  • australia-southeast1 (סידני)
  • australia-southeast2 (מלבורן)
  • ‫europe-central2 (ורשה, פולין) סמל של עלה רמה נמוכה של CO2
  • europe-west10 (ברלין)
  • ‫europe-west12 (טורינו) סמל של עלה רמה נמוכה של CO2
  • ‫europe-west2 (לונדון, בריטניה) סמל של עלה רמה נמוכה של CO2
  • europe-west3 (פרנקפורט, גרמניה)
  • europe-west6 (ציריך, שווייץ) סמל של עלה רמה נמוכה של CO2
  • me-central1 (דוחא)
  • me-central2 (דמאם)
  • ‫northamerica-northeast1 (מונטריאול) סמל של עלה רמה נמוכה של CO2
  • ‫northamerica-northeast2 (טורונטו) סמל של עלה רמה נמוכה של CO2
  • ‫southamerica-east1 (סאו פאולו, ברזיל) סמל של עלה רמה נמוכה של CO2
  • southamerica-west1 (סנטיאגו, צ'ילה) סמל של עלה רמה נמוכה של CO2
  • us-west2 (לוס אנג'לס)
  • us-west3 (סולט לייק סיטי)
  • us-west4 (לאס וגאס)

אם כבר יצרתם שירות Cloud Run, אתם יכולים לראות את האזור במרכז הבקרה של Cloud Run במסוףGoogle Cloud .

אחזור של דוגמת הקוד

כדי לאחזר את דוגמת הקוד לשימוש:

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

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    אפשר גם להוריד את הדוגמה כקובץ ZIP ולחלץ אותו.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    אפשר גם להוריד את הדוגמה כקובץ ZIP ולחלץ אותו.

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    אפשר גם להוריד את הדוגמה כקובץ ZIP ולחלץ אותו.

  2. עוברים לספרייה שמכילה את הקוד לדוגמה של Cloud Run:

    Node.js

    cd nodejs-docs-samples/run/idp-sql/

    Python

    cd python-docs-samples/run/idp-sql/

    Java

    cd java-docs-samples/run/idp-sql/

המחשה של הארכיטקטורה

תהליך הכניסה של משתמש הקצה.
הדיאגרמה מציגה משתמש קצה שמתחבר באמצעות תיבת דו-שיח של כניסה באמצעות חשבון Google שסופקה על ידי Identity Platform, ואז מופנה בחזרה ל-Cloud Run עם זהות המשתמש.
  1. משתמש קצה שולח את הבקשה הראשונה לשרת Cloud Run.

  2. הלקוח נטען בדפדפן.

  3. המשתמש מספק את פרטי הכניסה דרך תיבת הדו-שיח של הכניסה באמצעות חשבון Google מ-Identity Platform. המשתמש המחובר מקבל הודעת פתיחה.

  4. השליטה מופנית חזרה לשרת. משתמש הקצה מצביע באמצעות הלקוח, שמאחזר טוקן של מזהה מ-Identity Platform ומוסיף אותו ל-request header של בקשת ההצבעה.

  5. כשהשרת מקבל את הבקשה, הוא מאמת את אסימון המזהה של פלטפורמת הזהויות, ומאשר שמשתמש הקצה מאומת כראוי. לאחר מכן השרת שולח את ההצבעה ל-Cloud SQL באמצעות פרטי הכניסה שלו.

הבנת הקוד המרכזי

הדוגמה מיושמת כלקוח וכשרת, כפי שמתואר בהמשך.

שילוב עם Identity Platform: קוד בצד הלקוח

הדוגמה הזו משתמשת ב-Firebase SDK כדי לשלב עם Identity Platform לצורך כניסה וניהול של משתמשים. כדי להתחבר ל-Identity Platform, קוד ה-JavaScript בצד הלקוח מכיל את ההפניה לפרטי הכניסה של הפרויקט כאובייקט config ומייבא את ערכות ה-SDK של Firebase ל-JavaScript הנדרשות:

const config = {
  apiKey: 'API_KEY',
  authDomain: 'PROJECT_ID.firebaseapp.com',
};
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first-->
<script src="https://www.gstatic.com/firebasejs/7.18/firebase-app.js"></script>
<!-- Add Firebase Auth service-->
<script src="https://www.gstatic.com/firebasejs/7.18/firebase-auth.js"></script>

‫Firebase JavaScript SDK מטפל בתהליך הכניסה על ידי הצגת חלון דו-שיח שבו משתמש הקצה מתבקש להיכנס לחשבון Google שלו. ואז מפנה אותם בחזרה לשירות.

function signIn() {
  const provider = new firebase.auth.GoogleAuthProvider();
  provider.addScope('https://www.googleapis.com/auth/userinfo.email');
  firebase
    .auth()
    .signInWithPopup(provider)
    .then(result => {
      // Returns the signed in user along with the provider's credential
      console.log(`${result.user.displayName} logged in.`);
      window.alert(`Welcome ${result.user.displayName}!`);
    })
    .catch(err => {
      console.log(`Error during sign in: ${err.message}`);
      window.alert('Sign in failed. Retry or check your browser logs.');
    });
}

כשהמשתמש נכנס לחשבון, הלקוח משתמש בשיטות של Firebase כדי להנפיק טוקן של מזהה. הלקוח מוסיף את הטוקן של המזהה לכותרת Authorization של הבקשה לשרת.

async function vote(team) {
  if (firebase.auth().currentUser) {
    // Retrieve JWT to identify the user to the Identity Platform service.
    // Returns the current token if it has not expired. Otherwise, this will
    // refresh the token and return a new one.
    try {
      const token = await firebase.auth().currentUser.getIdToken();
      const response = await fetch('/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          Authorization: `Bearer ${token}`,
        },
        body: 'team=' + team, // send application data (vote)
      });
      if (response.ok) {
        const text = await response.text();
        window.alert(text);
        window.location.reload();
      }
    } catch (err) {
      console.log(`Error when submitting vote: ${err}`);
      window.alert('Something went wrong... Please try again!');
    }
  } else {
    window.alert('User not signed in.');
  }
}

שילוב עם Identity Platform: קוד בצד השרת

השרת משתמש ב-SDK של Firebase לאדמינים כדי לאמת את טוקן המזהה של המשתמש שנשלח מהלקוח. אם הטוקן של המזהה שסופק הוא בפורמט הנכון, לא פג תוקף ונחתם כראוי, השיטה מחזירה את הטוקן של המזהה המפוענח. השרת מחלץ את uid של המשתמש מ-Identity Platform.

Node.js

const firebase = require('firebase-admin');
// Initialize Firebase Admin SDK
firebase.initializeApp();

// Extract and verify Id Token from header
const authenticateJWT = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (authHeader) {
    const token = authHeader.split(' ')[1];
    // If the provided ID token has the correct format, is not expired, and is
    // properly signed, the method returns the decoded ID token
    firebase
      .auth()
      .verifyIdToken(token)
      .then(decodedToken => {
        const uid = decodedToken.uid;
        req.uid = uid;
        next();
      })
      .catch(err => {
        req.logger.error(`Error with authentication: ${err}`);
        return res.sendStatus(403);
      });
  } else {
    return res.sendStatus(401);
  }
};

Python

def jwt_authenticated(func: Callable[..., int]) -> Callable[..., int]:
    """Use the Firebase Admin SDK to parse Authorization header to verify the
    user ID token.

    The server extracts the Identity Platform uid for that user.
    """

    @wraps(func)
    def decorated_function(*args: a, **kwargs: a) -> a:
        header = request.headers.get("Authorization", None)
        if header:
            token = header.split(" ")[1]
            try:
                decoded_token = firebase_admin.auth.verify_id_token(token)
            except Exception as e:
                logger.exception(e)
                return Response(status=403, response=f"Error with authentication: {e}")
        else:
            return Response(status=401)

        request.uid = decoded_token["uid"]
        return func(*args, **kwargs)

    return decorated_function

Java

/** Extract and verify Id Token from header */
private String authenticateJwt(Map<String, String> headers) {
  String authHeader =
      (headers.get("authorization") != null)
          ? headers.get("authorization")
          : headers.get("Authorization");
  if (authHeader != null) {
    String idToken = authHeader.split(" ")[1];
    // If the provided ID token has the correct format, is not expired, and is
    // properly signed, the method returns the decoded ID token
    try {
      FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);
      String uid = decodedToken.getUid();
      return uid;
    } catch (FirebaseAuthException e) {
      logger.error("Error with authentication: " + e.toString());
      throw new ResponseStatusException(HttpStatus.FORBIDDEN, "", e);
    }
  } else {
    logger.error("Error no authorization header");
    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
  }
}

חיבור השרת ל-Cloud SQL

השרת מתחבר לשקע הדומיין של Unix במכונה של Cloud SQL בפורמט: /cloudsql/CLOUD_SQL_CONNECTION_NAME.

Node.js

/**
 * Connect to the Cloud SQL instance through UNIX Sockets
 *
 * @param {object} credConfig The Cloud SQL connection configuration from Secret Manager
 * @returns {object} Knex's PostgreSQL client
 */
const connectWithUnixSockets = async credConfig => {
  const dbSocketPath = process.env.DB_SOCKET_PATH || '/cloudsql';
  // Establish a connection to the database
  return Knex({
    client: 'pg',
    connection: {
      user: credConfig.DB_USER, // e.g. 'my-user'
      password: credConfig.DB_PASSWORD, // e.g. 'my-user-password'
      database: credConfig.DB_NAME, // e.g. 'my-database'
      host: `${dbSocketPath}/${credConfig.CLOUD_SQL_CONNECTION_NAME}`,
    },
    ...config,
  });
};

Python

def init_unix_connection_engine(
    db_config: dict[str, int]
) -> sqlalchemy.engine.base.Engine:
    """Initializes a Unix socket connection pool for a Cloud SQL instance of PostgreSQL.

    Args:
        db_config: a dictionary with connection pool config

    Returns:
        A SQLAlchemy Engine instance.
    """
    creds = credentials.get_cred_config()
    db_user = creds["DB_USER"]
    db_pass = creds["DB_PASSWORD"]
    db_name = creds["DB_NAME"]
    db_socket_dir = creds.get("DB_SOCKET_DIR", "/cloudsql")
    cloud_sql_connection_name = creds["CLOUD_SQL_CONNECTION_NAME"]

    pool = sqlalchemy.create_engine(
        # Equivalent URL:
        # postgres+pg8000://<db_user>:<db_pass>@/<db_name>
        #                         ?unix_sock=<socket_path>/<cloud_sql_instance_name>/.s.PGSQL.5432
        sqlalchemy.engine.url.URL.create(
            drivername="postgresql+pg8000",
            username=db_user,  # e.g. "my-database-user"
            password=db_pass,  # e.g. "my-database-password"
            database=db_name,  # e.g. "my-database-name"
            query={
                "unix_sock": f"{db_socket_dir}/{cloud_sql_connection_name}/.s.PGSQL.5432"
                # e.g. "/cloudsql", "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"
            },
        ),
        **db_config,
    )
    pool.dialect.description_encoding = None
    logger.info("Database engine initialized from unix connection")

    return pool

Java

משתמשים בשילוב של Spring Cloud Google Cloud PostgreSQL starter כדי ליצור אינטראקציה עם מסדי הנתונים של PostgreSQL ב-Cloud SQL באמצעות ספריות Spring JDBC. מגדירים את Cloud SQL ל-MySQL כך שיגדיר באופן אוטומטי bean של DataSource. בשילוב עם Spring JDBC, הוא מספק bean של אובייקט JdbcTemplate שמאפשר לבצע פעולות כמו שליחת שאילתות למסד נתונים ושינוי שלו.

# Uncomment and add env vars for local development
# spring.datasource.username=${DB_USER}
# spring.datasource.password=${DB_PASSWORD}
# spring.cloud.gcp.sql.database-name=${DB_NAME}
# spring.cloud.gcp.sql.instance-connection-name=${CLOUD_SQL_CONNECTION_NAME}  
private final JdbcTemplate jdbcTemplate;

public VoteController(JdbcTemplate jdbcTemplate) {
  this.jdbcTemplate = jdbcTemplate;
}

טיפול בהגדרות רגישות באמצעות Secret Manager

ב-Secret Manager אפשר לאחסן באופן מאובטח ומרכזי נתונים רגישים, כמו הגדרות אישיות של Cloud SQL. השרת מוסיף את פרטי הכניסה ל-Cloud SQL מ-Secret Manager בזמן הריצה באמצעות משתנה סביבה. מידע נוסף על שימוש בסודות ב-Cloud Run

Node.js

// CLOUD_SQL_CREDENTIALS_SECRET is the resource ID of the secret, passed in by environment variable.
// Format: projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION
const {CLOUD_SQL_CREDENTIALS_SECRET} = process.env;
if (CLOUD_SQL_CREDENTIALS_SECRET) {
  try {
    // Parse the secret that has been added as a JSON string
    // to retrieve database credentials
    return JSON.parse(CLOUD_SQL_CREDENTIALS_SECRET.toString('utf8'));
  } catch (err) {
    throw Error(
      `Unable to parse secret from Secret Manager. Make sure that the secret is JSON formatted: ${err}`
    );
  }
}

Python

def get_cred_config() -> dict[str, str]:
    """Retrieve Cloud SQL credentials stored in Secret Manager
    or default to environment variables.

    Returns:
        A dictionary with Cloud SQL credential values
    """
    secret = os.environ.get("CLOUD_SQL_CREDENTIALS_SECRET")
    if secret:
        return json.loads(secret)

Java

/** Retrieve config from Secret Manager */
public static HashMap<String, Object> getConfig() {
  String secret = System.getenv("CLOUD_SQL_CREDENTIALS_SECRET");
  if (secret == null) {
    throw new IllegalStateException("\"CLOUD_SQL_CREDENTIALS_SECRET\" is required.");
  }
  try {
    HashMap<String, Object> config = new Gson().fromJson(secret, HashMap.class);
    return config;
  } catch (JsonSyntaxException e) {
    logger.error(
        "Unable to parse secret from Secret Manager. Make sure that it is JSON formatted: "
            + e);
    throw new RuntimeException(
        "Unable to parse secret from Secret Manager. Make sure that it is JSON formatted.");
  }
}

הגדרת Identity Platform

כדי להשתמש ב-Identity Platform, צריך להגדיר אותו ידנית במסוף Google Cloud .

  1. במסוף Google Cloud , מפעילים את Identity Platform API:

    הפעלה של ה-API

  2. מגדירים את הפרויקט:

    1. בחלון חדש, נכנסים לדף "סקירה כללית" בפלטפורמת האימות של Google.

      לסקירה הכללית

    2. לוחצים על Get Started (שנתחיל?) ומגדירים את הפרויקט.

    3. בתיבת הדו-שיח פרטי האפליקציה:

      1. מזינים את שם האפליקציה.
      2. בוחרים אחת מכתובות האימייל שמוצגות לתמיכה במשתמשים.
    4. בתיבת הדו-שיח Audience, בוחרים באפשרות External.

    5. בתיבת הדו-שיח Contact information, מזינים כתובת אימייל ליצירת קשר.

    6. מאשרים את המדיניות בנושא נתוני משתמשים ולוחצים על יצירה.

  3. יוצרים ומקבלים את מזהה הלקוח ואת סוד הלקוח ב-OAuth:

    1. במסוף Google Cloud , נכנסים לדף APIs & Services > Credentials.

      כניסה לדף Credentials

    2. בחלק העליון של הדף, לוחצים על Create Credentials ובוחרים באפשרות OAuth client ID.

    3. ב-Application Type, בוחרים באפשרות אפליקציית אינטרנט ומזינים את השם.

    4. לוחצים על יצירה.

    5. הערכים client_id ו-client_secret ישמשו אתכם בשלב הבא.

  4. מגדירים את Google כספק:

    1. במסוף Google Cloud , נכנסים לדף Identity Providers.

      כניסה לדף Identity Providers

    2. לוחצים על הוספת ספק.

    3. בוחרים באפשרות Google מהרשימה.

    4. בהגדרות של Web SDK Configuration, מזינים את הערכים של client_id ו-client_secret מהשלב הקודם.

    5. בקטע Configure your application, לוחצים על Setup Details.

  5. מעתיקים את ההגדרות לאפליקציה:

    • מעתיקים את הערכים של apiKey ו-authDomain אל static/config.js של הדוגמה כדי לאתחל את Identity Platform Client SDK.

פריסת השירות

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

  1. יוצרים מכונה של Cloud SQL עם מסד נתונים של PostgreSQL באמצעות המסוף או ה-CLI:

    gcloud sql instances create CLOUD_SQL_INSTANCE_NAME \
        --database-version=POSTGRES_16 \
        --region=CLOUD_SQL_REGION \
        --cpu=2 \
        --memory=7680MB \
        --root-password=DB_PASSWORD
  2. מוסיפים את ערכי פרטי הכניסה של Cloud SQL אל postgres-secrets.json:

    Node.js

    {
      "CLOUD_SQL_CONNECTION_NAME": "PROJECT_ID:REGION:INSTANCE",
      "DB_NAME": "postgres",
      "DB_USER": "postgres",
      "DB_PASSWORD": "PASSWORD_SECRET"
    }
    

    Python

    {
      "CLOUD_SQL_CONNECTION_NAME": "PROJECT_ID:REGION:INSTANCE",
      "DB_NAME": "postgres",
      "DB_USER": "postgres",
      "DB_PASSWORD": "PASSWORD_SECRET"
    }
    

    Java

    {
      "spring.cloud.gcp.sql.instance-connection-name": "PROJECT_ID:REGION:INSTANCE",
      "spring.cloud.gcp.sql.database-name": "postgres",
      "spring.datasource.username": "postgres",
      "spring.datasource.password": "PASSWORD_SECRET"
    }

  3. יוצרים סוד עם גרסאות באמצעות המסוף או ה-CLI:

    gcloud secrets create idp-sql-secrets \
        --replication-policy="automatic" \
        --data-file=postgres-secrets.json
  4. יוצרים חשבון שירות לשרת באמצעות המסוף או ה-CLI:

    gcloud iam service-accounts create idp-sql-identity
  5. מקצים תפקידים לגישה ל-Secret Manager ול-Cloud SQL באמצעות המסוף או ה-CLI:

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

      gcloud secrets add-iam-policy-binding idp-sql-secrets \
        --member serviceAccount:idp-sql-identity@PROJECT_ID. \
        --role roles/secretmanager.secretAccessor
    2. נותנים לחשבון השירות שמשויך לשרת גישה ל-Cloud SQL:

      gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:idp-sql-identity@PROJECT_ID. \
        --role roles/cloudsql.client
  6. יוצרים Artifact Registry:

    gcloud artifacts repositories create REPOSITORY \
        --repository-format docker \
        --location REGION
    • ‫REPOSITORY הוא שם המאגר. לכל מיקום של מאגר בפרויקט, שמות המאגרים חייבים להיות ייחודיים.
  7. יוצרים את קובץ האימג' של הקונטיינר באמצעות Cloud Build:

    Node.js

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

    Python

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

    Java

    בדוגמה הזו משתמשים ב-Jib כדי ליצור קובצי אימג' של Docker באמצעות כלי Java נפוצים. ‫Jib מבצע אופטימיזציה של גרסאות build של קונטיינרים בלי צורך בקובץ Docker או בהתקנה של Docker. מידע נוסף על יצירת קונטיינרים של Java באמצעות Jib

    1. משתמשים בכלי העזר של פרטי הכניסה של gcloud כדי לתת ל-Docker הרשאה להעביר קבצים בדחיפה ל-Artifact Registry.

      gcloud auth configure-docker

    2. משתמשים בפלאגין Jib Maven כדי ליצור את הקונטיינר ולהעביר אותו בדחיפה ל-Artifact Registry.

      mvn compile jib:build -Dimage=REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql

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

    gcloud run deploy idp-sql \
        --image REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/idp-sql \
        --allow-unauthenticated \
        --service-account idp-sql-identity@PROJECT_ID. \
        --add-cloudsql-instances PROJECT_ID:REGION:CLOUD_SQL_INSTANCE_NAME \
        --update-secrets CLOUD_SQL_CREDENTIALS_SECRET=idp-sql-secrets:latest

    שימו לב גם לדגלים --service-account,‏ --add-cloudsql-instances ו---update-secrets, שמציינים את זהות השירות, את החיבור למכונה של Cloud SQL ואת שם הסוד עם הגרסה כמשתנה סביבה, בהתאמה.

ליטושים אחרונים

ב-Identity Platform צריך לאשר את כתובת ה-URL של השירות ב-Cloud Run ככתובת URL מותרת להפניה אוטומטית אחרי שהמשתמש נכנס לחשבון:

  1. עורכים את הספק של Google בלחיצה על סמל העט בדף Identity Providers.

  2. לוחצים על Add Domain בקטע Authorized Domains בחלונית השמאלית, ומזינים את כתובת ה-URL של שירות Cloud Run.

    אפשר לאתר את כתובת ה-URL של השירות ביומנים אחרי ה-build או הפריסה, או למצוא אותה בכל שלב באמצעות:

    gcloud run services describe idp-sql --format 'value(status.url)'
  3. נכנסים לדף APIs & Services > Credentials.

    1. לוחצים על סמל העיפרון לצד מזהה הלקוח ב-OAuth כדי לערוך אותו, ומתחת ללחצן Authorized redirect URIs click the הוספת URI.

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

    https://PROJECT_ID.firebaseapp.com/__/auth/handler

רוצה לנסות?

כדי לנסות את השירות המלא:

  1. בדפדפן, עוברים לכתובת ה-URL שסופקה בשלב הפריסה הקודם.

  2. לוחצים על הכפתור כניסה באמצעות חשבון Google ומבצעים את תהליך האימות.

  3. הצביעו גם אתם!

    הוא אמור להיראות כך:

    בממשק המשתמש מוצג מספר ההצבעות לכל קבוצה ורשימת הצבעות.

אם תבחרו להמשיך לפתח את השירותים האלה, זכרו שיש להם גישה מוגבלת לניהול זהויות והרשאות גישה (IAM) לשאר השירותים של Google Cloud , וצריך לתת להם תפקידי IAM נוספים כדי לגשת לשירותים רבים אחרים.

הסרת המשאבים

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

מחיקת הפרויקט

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

הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל המדריך.

כדי למחוק את הפרויקט:

  1. במסוף Google Cloud , נכנסים לדף Manage resources.

    כניסה לדף Manage resources

  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מחיקת משאבי המדריך

  1. מוחקים את שירות Cloud Run שפרסתם במדריך הזה. שירותי Cloud Run לא צוברים עלויות עד שהם מקבלים בקשות.

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

    gcloud run services delete SERVICE-NAME

    מחליפים את SERVICE-NAME בשם השירות.

    אפשר גם למחוק שירותי Cloud Run ממסוףGoogle Cloud .

  2. מסירים את הגדרת ברירת המחדל של האזור gcloud שהוספתם במהלך הגדרת המדריך:

     gcloud config unset run/region
    
  3. מסירים את הגדרות הפרויקט:

     gcloud config unset project
    
  4. מוחקים משאבים אחרים של Google Cloud שנוצרו במדריך הזה:

המאמרים הבאים