Как выполнить аутентификацию и подключиться к базе данных

Требования к подключению

Для клиентов Cloud Firestore требуется следующее:

  • Водители должны подключаться в режиме load balanced. Это позволяет драйверам не разбираться в точной топологии сервера, к которому они подключаются.
  • Драйверы должны подключаться с включенным SSL.
  • Драйверы должны отключать повторные записи. Cloud Firestore не поддерживает повторные записи. Отключать повторные попытки чтения не нужно, так как они поддерживаются.

Получите строку подключения

Строка подключения к базе данных зависит от UID базы данных, ее местоположения и механизма аутентификации. Ниже описано, как формируется строка подключения.

Точная строка подключения зависит от механизма аутентификации, но базовая строка подключения использует следующий формат:

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

Получить базовую строку подключения можно одним из следующих способов:

Консоль Firebase
  1. В консоли Firebase перейдите на страницу База данных Firestore.

    Перейти к базе данных Firestore

  2. Выберите базу данных, для которой нужно выполнить аутентификацию.
  3. На панели Проводник нажмите Ещё.
  4. Выберите Connect using MongoDB tools (Подключиться с помощью инструментов MongoDB).
  5. Скопируйте строку подключения.
gcloud

Используйте gcloud firestore database describe, чтобы получить UID и данные о местоположении:

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

Замените DATABASE_ID на идентификатор базы данных.

В выходных данных будет указано местоположение и UID базы данных. Используйте эту информацию, чтобы создать базовую строку подключения.

Используйте базовую строку подключения и один из следующих способов аутентификации и подключения к базе данных:

Подключение с помощью имени пользователя и пароля (SCRAM)

Чтобы создать учетные данные пользователя для базы данных и подключиться к ней, выполните следующие действия:

Подготовка

Чтобы получить разрешения, необходимые для создания пользователя, попросите администратора назначить вам роль IAM userCredsAdmin (roles/datastore.userCredsAdmin) в базе данных. Подробнее о том, как управлять доступом к проектам, папкам и организациям…

Вы также можете получить необходимые разрешения с помощью специальных ролей или других предопределенных ролей.

Как создать пользователя и подключиться к базе данных

Чтобы создать пользователя для базы данных Cloud Firestore, воспользуйтесь одним из следующих способов:

Консоль Firebase
  1. В консоли Firebase перейдите на страницу База данных Firestore.

    Перейти к базе данных 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.

Для сборок 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 Auth

В следующем примере кода регистрируется обработчик обратных вызовов OIDC, использующий стандартную библиотеку OAuth Google Cloud.

Эта библиотека позволяет использовать разные типы аутентификации (Application Default Credentials, Workload Identity Federation).

Для этого нужно добавить библиотеку аутентификации в качестве зависимости:

// 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'

В приведенном ниже примере кода показано, как подключиться к API:

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, в котором находится ваша база данных.

Подготовка

Настройте управляемый пользователем сервисный аккаунт для виртуальной машины:

Чтобы завершить настройку правил 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 – идентификатор базы данных;