אימות וחיבור למסד נתונים

דרישות החיבור

הדרישות הבאות חלות על לקוחות Cloud Firestore:

  • הנהגים צריכים להתחבר במצב load balanced. כך מנהלי ההתקנים לא צריכים לנסות להבין את הטופולוגיה המדויקת של השרת שאליו הם מתחברים.
  • הדרייברים חייבים להתחבר כש-SSL מופעל.
  • מנהלי ההתקנים צריכים להשבית את האפשרות לנסות שוב פעולות כתיבה. ‫Cloud Firestore לא תומך בכתיבה שאפשר לנסות שוב. אין צורך להשבית את האפשרות retryable reads כי היא נתמכת.

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

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

מחרוזת החיבור המדויקת תלויה במנגנון האימות, אבל מחרוזת החיבור הבסיסית משתמשת בפורמט הבא:

mongodb://UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&tls=true&retryWrites=false

אפשר לקבל את מחרוזת החיבור הבסיסית באחת מהדרכים הבאות:

מסוף Firebase
  1. במסוף Firebase, נכנסים לדף Firestore Database.

    כניסה למסד הנתונים ב-Firestore

  2. לוחצים על מסד הנתונים שרוצים לאמת.
  3. בחלונית Explorer, לוחצים על View more.
  4. בוחרים באפשרות Connect using MongoDB tools.
  5. מעתיקים את מחרוזת החיבור.
gcloud

משתמשים ב-gcloud firestore database describe כדי לאחזר את המזהה הייחודי ופרטי המיקום:

gcloud firestore databases describe \
--database=DATABASE_ID \
--format='yaml(locationId, uid)'

מחליפים את DATABASE_ID במזהה מסד הנתונים.

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

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

התחברות באמצעות שם משתמש וסיסמה (SCRAM)

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

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

כדי לקבל את ההרשאות שנדרשות ליצירת משתמש, צריך לבקש מהאדמין להקצות לכם ב-IAM את התפקיד userCredsAdmin (roles/datastore.userCredsAdmin) במסד הנתונים. כדי לקרוא הסבר על מתן תפקידים, קראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

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

יצירת משתמש והתחברות למסד נתונים

כדי ליצור משתמש למסד הנתונים ב-Cloud Firestore, משתמשים באחת מהשיטות הבאות:

מסוף Firebase
  1. במסוף Firebase, נכנסים לדף Firestore Database.

    כניסה למסד הנתונים ב-Firestore

  2. בוחרים מסד נתונים מרשימת מסדי הנתונים.
  3. בתפריט הניווט, לוחצים על אבטחה.
  4. לוחצים על הוספת משתמש.
  5. מזינים שם משתמש.
  6. בוחרים תפקיד למשתמש החדש.
  7. לוחצים על הוספת משתמש.
  8. הסיסמה של המשתמש החדש תוצג בתיבת הדו-שיח לאישור.

gcloud CLI
  1. כדי לבצע אימות באמצעות SCRAM, קודם צריך ליצור פרטי כניסה של משתמש. משתמשים בפקודה gcloud firestore user-creds:
    gcloud firestore user-creds create USERNAME --database=DATABASE_ID
    מחליפים את הערכים הבאים:
    • ‫USERNAME: שם המשתמש שרוצים ליצור.
    • ‫DATABASE_ID: מזהה מסד הנתונים.

    הפלט של הפקודה הזו כולל את הסיסמה של המשתמש.

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

    name: projects/PROJECT_NAME/databases/DATABASE_ID/userCreds/USERNAME
    resourceIdentity:
      principal: principal://firestore.googleapis.com/projects/PROJECT_NUMBER/name/databases/DATABASE_ID/userCreds/USERNAME
    securePassword: PASSWORD
  2. כברירת מחדל, לפרטי הכניסה של המשתמש החדש אין הרשאות. כדי לקבל גישת קריאה וכתיבה למסד הנתונים, מוסיפים את התפקיד roles/datastore.user למסד הנתונים הספציפי הזה:

    gcloud projects add-iam-policy-binding PROJECT_NAME \
    --member='principal://firestore.googleapis.com/projects/PROJECT_NUMBER/name/databases/DATABASE_ID/userCreds/USERNAME' \
    --role=roles/datastore.user \
    --condition='expression=resource.name == "projects/PROJECT_NAME/databases/DATABASE_ID",title="CONDITION_TITLE"'
    מחליפים את הערכים הבאים:
Java

בקטע הזה מופיעה דוגמה לקוד ליצירת פרטי כניסה של משתמשים ולהגדרת מדיניות IAM באמצעות ספריות לקוח של אדמין ב-Java. הדוגמה משתמשת בספרייה Firestore Admin Client כדי ליצור שם משתמש וסיסמה, ובספרייה Google Cloud Resource Manager כדי להגדיר את IAM.

ב-builds של Maven, אפשר להשתמש בקואורדינטות הבאות:

com.google.cloud:google-cloud-firestore-admin:3.33.1
com.google.cloud:google-cloud-resourcemanager:1.76.0

הקצאת פרטי כניסה של משתמש ומדיניות IAM:

import com.google.cloud.firestore.v1.FirestoreAdminClient;
import com.google.cloud.resourcemanager.v3.ProjectName;
import com.google.cloud.resourcemanager.v3.ProjectsClient;
import com.google.firestore.admin.v1.CreateUserCredsRequest;
import com.google.firestore.admin.v1.GetUserCredsRequest;
import com.google.firestore.admin.v1.UserCreds;
import com.google.iam.v1.Binding;
import com.google.iam.v1.GetIamPolicyRequest;
import com.google.iam.v1.GetPolicyOptions;
import com.google.iam.v1.Policy;
import com.google.iam.v1.SetIamPolicyRequest;
import com.google.protobuf.FieldMask;
import com.google.type.Expr;

public class FirestoreUserCredsExample {
  /**
   *   Provision user credentials and configure an IAM policy to allow SCRAM authentication into the
   *   specified Firestore with Mongo Compatibility database.
   */
  private static void provisionFirestoreUserCredsAndIAM(
      String projectId, String databaseId, String userName) throws Exception {
    UserCreds userCreds = createUserCreds(projectId, databaseId, userName);

    // Note the password returned in the UserCreds proto - it cannot be retrieved again
    // after the initial call to the createUserCreds API.
    System.out.printf(
        "Created credentials for username: %s:\nIAM principal: %s\nPassword: [%s]\n",
        userName, userCreds.getResourceIdentity().getPrincipal(), userCreds.getSecurePassword());

    // Provision an IAM binding for the principal associated with these user credentials.
    updateIamPolicyForUserCreds(projectId, databaseId, userName, userCreds);

    // Emit the password again.
    System.out.printf(
        "Successfully configured IAM policy for database: %s, username: %s\n",
        databaseId, userName);
    System.out.printf("Please make a note of the password: [%s]\n", userCreds.getSecurePassword());
  }

  /** Provision new user credentials using the FirestoreAdminClient. */
  private static UserCreds createUserCreds(String projectId, String databaseId, String userName)
      throws Exception {
    FirestoreAdminClient firestoreAdminClient = FirestoreAdminClient.create();
    return firestoreAdminClient.createUserCreds(
        CreateUserCredsRequest.newBuilder()
            .setParent(String.format("projects/%s/databases/%s", projectId, databaseId))
            .setUserCredsId(userName)
            .build());
  }

  /** Update the IAM policy using the Resource Manager ProjectsClient. */
  private static void updateIamPolicyForUserCreds(
      String projectId, String databaseId, String userName, UserCreds userCreds) throws Exception {
    try (ProjectsClient projectsClient = ProjectsClient.create()) {
      ProjectName projectName = ProjectName.of(projectId);

      // Get the current IAM policy.
      Policy currentPolicy =
          projectsClient.getIamPolicy(
              GetIamPolicyRequest.newBuilder()
                  .setResource(projectName.toString())
                  .setOptions(GetPolicyOptions.newBuilder().setRequestedPolicyVersion(3).build())
                  .build());

      String role = "roles/datastore.user";
      String title = String.format("Conditional IAM binding for %s", userName);
      String expression =
          String.format("resource.name == \"projects/%s/databases/%s\"", projectId, databaseId);

      // Construct an updated IAM policy with an additional binding for the user credentials.
      Policy.Builder policyBuilder = currentPolicy.toBuilder();
      Binding newBinding =
          Binding.newBuilder()
              .setRole(role)
              .setCondition(Expr.newBuilder().setTitle(title).setExpression(expression).build())
              .addMembers(userCreds.getResourceIdentity().getPrincipal())
              .build();
      policyBuilder.addBindings(newBinding);

      // Update the policy
      SetIamPolicyRequest request =
          SetIamPolicyRequest.newBuilder()
              .setResource(projectName.toString())
              .setPolicy(policyBuilder.build())
              .setUpdateMask(FieldMask.newBuilder().addPaths("bindings").addPaths("etag").build())
              .build();
      System.out.println(request);

      Policy updatedPolicy = projectsClient.setIamPolicy(request);
      System.out.println("Policy updated successfully: " + updatedPolicy);
    }
  }
}
Python

בקטע הזה מופיעה דוגמה לקוד ליצירת פרטי כניסה של משתמשים ולהגדרת מדיניות IAM באמצעות ספריות לקוח של אדמין ב-Python. בדוגמה הזו משתמשים בספריית הלקוח של Google Cloud Firestore API כדי ליצור שם משתמש וסיסמה, ובספריית הלקוח של Google Cloud IAM API ובספריית הלקוח של Google Cloud Resource Manager API כדי להגדיר את IAM.

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

pip install google-cloud-iam
pip install google-cloud-firestore
pip install google-cloud-resource-manager

הקצאת פרטי כניסה של משתמש ומדיניות IAM:

from google.cloud import resourcemanager_v3
from google.cloud.firestore_admin_v1 import FirestoreAdminClient
from google.cloud.firestore_admin_v1 import types
from google.iam.v1 import iam_policy_pb2
from google.iam.v1 import policy_pb2
from google.type import expr_pb2

def create_user_creds(project_id: str, database_id: str, user_name: str):
  """Provision new user credentials using the FirestoreAdminClient."""
  client = FirestoreAdminClient()
  request = types.CreateUserCredsRequest(
      parent=f'projects/{project_id}/databases/{database_id}',
      user_creds_id=user_name,
  )
  response = client.create_user_creds(request)
  return response

def update_iam_policy_for_user_creds(
    project_id: str, database_id: str, user_name: str, user_creds
):
  """Update the IAM policy using the Resource Manager ProjectsClient."""
  client = resourcemanager_v3.ProjectsClient()
  request = iam_policy_pb2.GetIamPolicyRequest()
  request.resource = f'projects/{project_id}'
  request.options.requested_policy_version = 3

  # Get the current IAM policy
  current_policy = client.get_iam_policy(request)

  # Construct an updated IAM policy with an additional binding
  # for the user credentials.
  updated_policy = policy_pb2.Policy()
  binding = policy_pb2.Binding()
  iam_condition = expr_pb2.Expr()

  iam_condition.title = f'Conditional IAM binding for {user_name}'
  iam_condition.expression = (
      f'resource.name == "projects/{project_id}/databases/{database_id}"'
  )

  binding.role = 'roles/datastore.user'
  binding.condition.CopyFrom(iam_condition)
  binding.members.append(user_creds.resource_identity.principal)
  updated_policy.bindings.append(binding)

  # Update the policy
  updated_policy.MergeFrom(current_policy)
  set_policy_request = iam_policy_pb2.SetIamPolicyRequest()
  set_policy_request.resource = f'projects/{project_id}'
  set_policy_request.policy.CopyFrom(updated_policy)

  final_policy = client.set_iam_policy(set_policy_request)
  print(f'Policy updated successfully {final_policy}')

def provision_firestore_user_creds_and_iam(
    project_id: str, database_id: str, user_name: str
):
  """Provision user credentials and configure an IAM policy."""
  user_creds = create_user_creds(project_id, database_id, user_name)

  # Note the password returned in the UserCreds proto - it cannot be
  # retrieved again after the initial call to the create_user_creds API.
  print(f'Created credentials for username: {user_name}')
  print(f'IAM principal: {user_creds.resource_identity.principal}')
  print(f'Password: [{user_creds.secure_password}]')

  # Provision an IAM binding for the principal associated with
  # these user credentials.
  update_iam_policy_for_user_creds(
      project_id, database_id, user_name, user_creds
  )

  # Emit the password again
  print(
      f'Successfully configured IAM policy for database: {database_id},'
      f' username: {user_name}'
  )
  print(f'Please make a note of the password: [{user_creds.secure_password}]')

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

mongodb://USERNAME:PASSWORD@UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&authMechanism=SCRAM-SHA-256&tls=true&retryWrites=false

מחליפים את מה שכתוב בשדות הבאים:

  • ‫USERNAME: שם המשתמש.
  • ‫PASSWORD: הסיסמה שיצרתם למשתמש הזה.
  • ‫UID: המזהה הייחודי של מסד הנתונים. לדוגמה: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • ‫LOCATION: המיקום של מסד הנתונים.
  • ‫DATABASE_ID: מזהה מסד הנתונים.

התחברות באמצעות ספריית האימות של Google

בדוגמת הקוד הבאה, הגורם המטפל בקריאה חוזרת (callback) של OIDC רשום באמצעות ספריית OAuth הרגילה של Google Cloud.

הספרייה הזו מאפשרת להשתמש בכמה סוגים שונים של אימות (Application Default Credentials, איחוד שירותי אימות הזהות של עומסי עבודה).

לשם כך צריך להוסיף את ספריית האימות כתלות:

// Maven
<dependency>
  <groupId>com.google.auth</groupId>
  <artifactId>google-auth-library-oauth2-http</artifactId>
  <version>1.19.0</version>
</dependency>

// Gradle
implementation 'com.google.auth:google-auth-library-oauth2-http:1.19.0'

דוגמת הקוד הבאה ממחישה איך להתחבר:

val db = MongoClients.create(
    clientSettings(
      "DATABASE_UID",
      "LOCATION"
    ).build()
  ).getDatabase("DATABASE_ID")

/**
 *   Creates a connection to a Firestore with MongoDB Compatibility database.
 *   @param databaseUid The uid of the database to connect to as a string. For example: f116f93a-519c-208a-9a72-3ef6c9a1f081
 *   @param locationId The location of the database to connect to, for example: nam5, us-central1, us-east4 etc...
 *   @param environment Determines whether to try and fetch an authentication credential from the
 *   Compute Engine VM metadata service or whether to call gcloud.
 */
private static MongoClientSettings.Builder clientSettings(
  String databaseUid: String
  String locationId:String
): MongoClientSettings.Builder {
  MongoCredential credential =
    MongoCredential.createOidcCredential(null)
      .withMechanismProperty(
        MongoCredential.OIDC_CALLBACK_KEY,
        new MongoCredential.OidcCallback() {
          @Override
          MongoCredential.OidcCallbackResult onRequest(
MongoCredential.OidcCallbackContext context) {
     // Customize this credential builder for additional credential types.
     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
            return new MongoCredential.OidcCallbackResult(
         credentials.getAccessToken().getTokenValue(),
         Duration.between(Instant.now(),
credentials.getAccessToken().getExpirationTime().toInstant()));
          }
        },
      );
  return MongoClientSettings.builder()
    .hosts(listOf(ServerAddress(
        "$databaseUid.$locationId.firestore.goog", 443)))
    .credential(credential)
    .applyToClusterSettings(builder ->
         builder.mode(ClusterConnectionMode.LOAD_BALANCED))
    ).applyToSslSettings(ssl -> ssl.enabled(true)).retryWrites(false);
}

מחליפים את מה שכתוב בשדות הבאים:

  • ‫DATABASE_UID: המזהה הייחודי של מסד הנתונים. לדוגמה: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • ‫LOCATION: המיקום של מסד הנתונים.
  • ‫DATABASE_ID מזהה מסד הנתונים.

התחברות מסביבת מחשוב של Google Cloud

בקטע הזה מוסבר איך להתחבר ל-Cloud Firestore מסביבת מחשוב של Google Cloud, כמו Compute Engine או שירות או משימה של Cloud Run.

התחברות ממכונה וירטואלית של Compute Engine

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

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

מגדירים חשבון שירות בניהול המשתמש בשביל ה-VM:

כדי להשלים את הגדרת מדיניות ה-IAM של חשבון השירות Compute Engine, עיינו בהוראות בקטעים הגדרת פרטי כניסה.

התחברות מ-Cloud Run

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

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

כדי להשלים את הגדרת מדיניות ה-IAM של חשבון השירות Cloud Run, עיינו בהוראות בקטעים הגדרת פרטי כניסה.

הגדרת פרטי כניסה

כדי להקצות לחשבון השירות את התפקיד roles/datastore.user לקריאה ולכתיבה ב-Cloud Firestore, מריצים את הפקודה הבאה:

gcloud projects add-iam-policy-binding PROJECT_NAME --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" --role=roles/datastore.user

מחליפים את מה שכתוב בשדות הבאים:

  • ‫PROJECT_NAME: שם הפרויקט.
  • ‫SERVICE_ACCOUNT_EMAIL: כתובת האימייל של חשבון השירות שיצרתם.

יצירת מחרוזת החיבור

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

mongodb://DATABASE_UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&tls=true&retryWrites=false&authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:FIRESTORE

מחליפים את מה שכתוב בשדות הבאים:

  • ‫DATABASE_UID: המזהה הייחודי של מסד הנתונים. לדוגמה: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • ‫LOCATION: המיקום של מסד הנתונים.
  • ‫DATABASE_ID מזהה מסד הנתונים.

למידע נוסף על אחזור ה-UID והמיקום, ראו אחזור מחרוזת החיבור.

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

אתם יכולים להשתמש בטוקן גישה זמני ל-Google Cloud כדי להריץ כלי אבחון כמו mongosh. אפשר להשתמש ב-gcloud auth print-access-token כדי לאמת באמצעות אסימון גישה לטווח קצר. האסימון הזה תקף לשעה אחת.

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

mongosh --tls \
      --username access_token --password $(gcloud auth print-access-token) \
      'mongodb://UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&authMechanism=PLAIN&authSource=$external&retryWrites=false'

מחליפים את מה שכתוב בשדות הבאים:

  • ‫DATABASE_UID: המזהה הייחודי של מסד הנתונים. לדוגמה: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • ‫LOCATION: המיקום של מסד הנתונים
  • ‫DATABASE_ID: מזהה מסד נתונים