Detaillierte Zugriffssteuerung konfigurieren

Auf dieser Seite wird beschrieben, wie Sie die detaillierte Zugriffssteuerung für Spanner-Datenbanken mit GoogleSQL-Dialekt und PostgreSQL-Dialekt konfigurieren.

Weitere Informationen zur detaillierten Zugriffssteuerung finden Sie unter Detaillierte Zugriffssteuerung.

So konfigurieren Sie die detaillierte Zugriffssteuerung:

  1. Datenbankrollen erstellen und Berechtigungen erteilen

  2. Optional: Erstellen Sie eine Hierarchie von Rollen mit Vererbung.

  3. Hauptkonten Datenbankrollen zuweisen

  4. Nutzer und Entwickler über die Verwendung von Datenbankrollen informieren:

Nutzer der detaillierten Zugriffssteuerung müssen dann eine Datenbankrolle angeben, um Abfragen, DML- oder Zeilenoperationen für die Datenbank auszuführen.

Hinweise

Achten Sie darauf, dass jedem Hauptkonto, das ein Nutzer der detaillierten Zugriffssteuerung sein soll, die IAM-Rolle Cloud Spanner Viewer (roles/spanner.viewer) zugewiesen wird. Diese Rolle wird auf Projektebene für Nutzer empfohlen, die in der Google Cloud Console mit Spanner-Ressourcen interagieren müssen.

Eine Anleitung finden Sie unter Berechtigungen für Principals erteilen.

Datenbankrollen erstellen und Berechtigungen erteilen

Eine Datenbankrolle ist eine Sammlung von detaillierten Zugriffsberechtigungen. Sie können für jede Datenbank bis zu 100 Datenbankrollen erstellen.

Legen Sie Rollen und Rollenhierarchien in Ihrer Datenbank fest und codieren Sie sie in DDL. Wie bei anderen Schemaänderungen in Spanner empfehlen wir dringend, Schemaänderungen in einem Batch und nicht separat auszuführen. Weitere Informationen finden Sie unter Häufigkeit von Schemaaktualisierungen begrenzen.

Console

So erstellen Sie eine Datenbankrolle und gewähren ihr detaillierte Zugriffsrechte:

  1. Rufen Sie in der Google Cloud Console die Seite Instanzen auf.

    Instanzen

  2. Wählen Sie die Instanz aus, die die Datenbank enthält, für die Sie die Rolle hinzufügen möchten.

  3. Wählen Sie die Datenbank aus.

  4. Klicken Sie auf der Seite Übersicht auf Spanner Studio.

  5. Führen Sie auf der Seite Spanner Studio für jede Datenbankrolle, die Sie erstellen und für die Sie Berechtigungen erteilen möchten, die folgenden Schritte aus:

    1. Geben Sie zum Erstellen der Rolle die folgende Anweisung ein:

      CREATE ROLE ROLE_NAME;

      Klicken Sie noch nicht auf Senden.

    2. Wenn Sie der Rolle Berechtigungen zuweisen möchten, geben Sie in der Zeile nach der CREATE ROLE-Anweisung eine GRANT-Anweisung ein.

      Syntaxdetails zur GRANT-Anweisung finden Sie unter GoogleSQL-Datendefinitionssprache. Informationen zu Berechtigungen finden Sie unter Berechtigungen für die detaillierte Zugriffssteuerung.

      Wenn Sie beispielsweise die Berechtigungen SELECT, INSERT und UPDATE für die Tabellen employees und contractors der Datenbankrolle hr_manager zuweisen möchten, geben Sie die folgende Anweisung ein:

      GoogleSQL

      GRANT SELECT, INSERT, UPDATE ON TABLE employees, contractors TO ROLE hr_manager;
      

      PostgreSQL

      GRANT SELECT, INSERT, UPDATE ON TABLE employees, contractors TO hr_manager;
      

      Sie können eine DDL-Vorlage für die GRANT-Anweisung verwenden. Suchen Sie im Bereich Explorer nach der Rolle, für die Sie Berechtigungen gewähren möchten. Klicken Sie auf  Aktionen ansehen und wählen Sie den Berechtigungstyp aus, auf den diese Rolle Zugriff haben soll. Die GRANT-Vorlagenanweisung wird in einem neuen Editor-Tab eingefügt.

  6. Klicken Sie auf Senden.

    Wenn in Ihrer DDL Fehler vorhanden sind, gibt die Google Cloud -Konsole einen Fehler zurück.

gcloud

Verwenden Sie den Befehl gcloud spanner databases ddl update mit den Anweisungen CREATE ROLE und GRANT, um eine Datenbankrolle zu erstellen und ihr detaillierte Zugriffsberechtigungen zu gewähren.

Syntaxdetails zu den Anweisungen CREATE ROLE und GRANT finden Sie unter GoogleSQL-Datendefinitionssprache.

Mit dem folgenden Befehl wird beispielsweise eine Datenbankrolle erstellt und ihr werden Berechtigungen für eine oder mehrere Tabellen gewährt.

GoogleSQL

gcloud spanner databases ddl update DATABASE_NAME --instance=INSTANCE_NAME \
--ddl='CREATE ROLE ROLE_NAME; GRANT PRIVILEGES ON TABLE TABLES TO ROLE ROLE_NAME;'

PostgreSQL

gcloud spanner databases ddl update DATABASE_NAME --instance=INSTANCE_NAME \
--ddl='CREATE ROLE ROLE_NAME; GRANT PRIVILEGES ON TABLE TABLES TO ROLE_NAME;'

Ersetzen Sie Folgendes:

  • PRIVILEGES ist eine durch Kommas getrennte Liste mit detaillierten Berechtigungen für die Zugriffssteuerung. Informationen zu Berechtigungen finden Sie unter Berechtigungen für die detaillierte Zugriffssteuerung.

  • TABLES ist eine durch Kommas getrennte Liste von Tabellen.

Um beispielsweise SELECT, INSERT und UPDATE für die Tabellen employees und contractors die Datenbankrolle hr_analyst in der Datenbank hrdb1 in der Instanz hr zuzuweisen, geben Sie die folgende Anweisung ein:

GoogleSQL

gcloud spanner databases ddl update hrdb1 --instance=hr \
--ddl='CREATE ROLE hr_analyst; GRANT SELECT, INSERT, UPDATE ON TABLE employees, contractors TO ROLE hr_analyst;'

PostgreSQL

gcloud spanner databases ddl update hrdb1 --instance=hr \
--ddl='CREATE ROLE hr_analyst; GRANT SELECT, INSERT, UPDATE ON TABLE employees, contractors TO hr_analyst;'

Clientbibliotheken

In diesen Codebeispielen wird eine Datenbankrolle erstellt und gelöscht.

C++

void AddAndDropDatabaseRole(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id, std::string const& role_parent,
    std::string const& role_child) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  std::vector<std::string> grant_statements = {
      "CREATE ROLE " + role_parent,
      "GRANT SELECT ON TABLE Singers TO ROLE " + role_parent,
      "CREATE ROLE " + role_child,
      "GRANT ROLE " + role_parent + " TO ROLE " + role_child,
  };
  auto metadata =
      client.UpdateDatabaseDdl(database.FullName(), grant_statements).get();
  google::cloud::spanner_testing::LogUpdateDatabaseDdl(  //! TODO(#4758)
      client, database, metadata.status());              //! TODO(#4758)
  if (!metadata) throw std::move(metadata).status();
  std::cout << "Created roles " << role_parent << " and " << role_child
            << " and granted privileges\n";

  std::vector<std::string> revoke_statements = {
      "REVOKE ROLE " + role_parent + " FROM ROLE " + role_child,
      "DROP ROLE " + role_child,
  };
  metadata =
      client.UpdateDatabaseDdl(database.FullName(), revoke_statements).get();
  google::cloud::spanner_testing::LogUpdateDatabaseDdl(  //! TODO(#4758)
      client, database, metadata.status());              //! TODO(#4758)
  if (!metadata) throw std::move(metadata).status();
  std::cout << "Revoked privileges and dropped role " << role_child << "\n";
}

C#


using Google.Cloud.Spanner.Data;
using System.Threading.Tasks;

public class AddAndDropDatabaseRoleAsyncSample
{
    public async Task AddDatabaseRoleAsync(string projectId, string instanceId, string databaseId, string databaseRole)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        string createRoleStatement = $"CREATE ROLE {databaseRole}";

        // Creates the given database role.
        using var connection = new SpannerConnection(connectionString);
        using var updateCmd = connection.CreateDdlCommand(createRoleStatement);
        await updateCmd.ExecuteNonQueryAsync();
    }

    public async Task DropDatabaseRoleAsync(string projectId, string instanceId, string databaseId, string databaseRole)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        string deleteRoleStatement = $"DROP ROLE {databaseRole}";

        // Drops the given database role.
        using var connection = new SpannerConnection(connectionString);
        using var updateCmd = connection.CreateDdlCommand(deleteRoleStatement);
        await updateCmd.ExecuteNonQueryAsync();
    }
}

Go


import (
	"context"
	"io"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

func addAndDropDatabaseRole(w io.Writer, db string) error {
	ctx := context.Background()
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return err
	}
	defer adminClient.Close()

	// Set up database roles and membership. After database roles are created,
	// users can be granted roles by setting IAM policies.
	op, err := adminClient.UpdateDatabaseDdl(ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database: db,
		Statements: []string{
			"CREATE ROLE parent",
			"GRANT SELECT ON TABLE Albums TO ROLE parent",
			"CREATE ROLE child",
			"GRANT ROLE parent TO ROLE child",
		},
	})
	if err != nil {
		return err
	}
	if err := op.Wait(ctx); err != nil {
		return err
	}

	// Delete role and membership.
	op, err = adminClient.UpdateDatabaseDdl(ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database: db,
		Statements: []string{
			"REVOKE ROLE parent FROM ROLE child",
			"DROP ROLE child",
		},
	})
	if err != nil {
		return err
	}
	if err := op.Wait(ctx); err != nil {
		return err
	}
	return nil
}

Java


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AddAndDropDatabaseRole {

  static void addAndDropDatabaseRole() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String parentRole = "parent_role";
    String childRole = "child_role";
    addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole, "Albums");
  }

  static void addAndDropDatabaseRole(
      String projectId, String instanceId, String databaseId,
      String parentRole, String childRole, String... tables) {
    try (Spanner spanner =
        SpannerOptions.newBuilder()
            .setProjectId(projectId)
            .build()
            .getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      System.out.println("Waiting for role create operation to complete...");
      List<String> roleStatements = new ArrayList<>(ImmutableList.of(
          String.format("CREATE ROLE %s", parentRole),
          String.format("CREATE ROLE %s", childRole),
          String.format("GRANT ROLE %s TO ROLE %s", parentRole, childRole)));
      for (String table : tables) {
        roleStatements.add(String.format("GRANT SELECT ON TABLE %s TO ROLE %s", table, parentRole));
      }
      databaseAdminClient.updateDatabaseDdlAsync(
              DatabaseName.of(projectId, instanceId, databaseId), roleStatements)
          .get(5, TimeUnit.MINUTES);
      System.out.printf(
          "Created roles %s and %s and granted privileges%n", parentRole, childRole);
      // Delete role and membership.
      System.out.println("Waiting for role revoke & drop operation to complete...");
      databaseAdminClient.updateDatabaseDdlAsync(
          DatabaseName.of(projectId, instanceId, databaseId),
          ImmutableList.of(
              String.format("REVOKE ROLE %s FROM ROLE %s", parentRole, childRole),
              String.format("DROP ROLE %s", childRole))).get(5, TimeUnit.MINUTES);
      System.out.printf("Revoked privileges and dropped role %s%n", childRole);
    } catch (ExecutionException | TimeoutException e) {
      System.out.printf(
          "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage());
      e.printStackTrace();
    } catch (InterruptedException e) {
      System.out.println(
          "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted");
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const projectId = 'my-project-id';

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

const databaseAdminClient = spanner.getDatabaseAdminClient();

async function addAndDropNewDatabaseRole() {
  // Creates a new user defined role and grant permissions
  try {
    const request = [
      'CREATE ROLE parent',
      'GRANT SELECT ON TABLE Singers TO ROLE parent',
      'CREATE ROLE child',
      'GRANT ROLE parent TO ROLE child',
    ];
    const [operation] = await databaseAdminClient.updateDatabaseDdl({
      database: databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      ),
      statements: request,
    });

    console.log('Waiting for operation to complete...');
    await operation.promise();

    console.log('Created roles child and parent and granted privileges');
  } catch (err) {
    console.error('ERROR:', err);
  }

  // Revoke permissions and drop child role.
  // A role can't be dropped until all its permissions are revoked.
  try {
    const request = ['REVOKE ROLE parent FROM ROLE child', 'DROP ROLE child'];
    const [operation] = await databaseAdminClient.updateDatabaseDdl({
      database: databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      ),
      statements: request,
    });

    console.log('Waiting for operation to complete...');
    await operation.promise();

    console.log('Revoked privileges and dropped role child');
  } catch (err) {
    console.error('ERROR:', err);
  } finally {
    // Close the spanner client when finished.
    // The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
    spanner.close();
  }
}
addAndDropNewDatabaseRole();

PHP

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Adds and drops roles to the Singers table in the example database.
 * Example:
 * ```
 * add_drop_database_role($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function add_drop_database_role(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [
            'CREATE ROLE new_parent',
            'GRANT SELECT ON TABLE Singers TO ROLE new_parent',
            'CREATE ROLE new_child',
            'GRANT ROLE new_parent TO ROLE new_child'
        ]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    printf('Waiting for create role and grant operation to complete...%s', PHP_EOL);
    $operation->pollUntilComplete();

    printf('Created roles %s and %s and granted privileges%s', 'new_parent', 'new_child', PHP_EOL);

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [
            'REVOKE ROLE new_parent FROM ROLE new_child',
            'DROP ROLE new_child'
        ]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    printf('Waiting for revoke role and drop role operation to complete...%s', PHP_EOL);
    $operation->pollUntilComplete();

    printf('Revoked privileges and dropped role %s%s', 'new_child', PHP_EOL);
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

from google.cloud.spanner_admin_database_v1.types import spanner_database_admin

spanner_client = spanner.Client()
database_admin_api = spanner_client.database_admin_api

role_parent = "new_parent"
role_child = "new_child"

request = spanner_database_admin.UpdateDatabaseDdlRequest(
    database=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    statements=[
        "CREATE ROLE {}".format(role_parent),
        "GRANT SELECT ON TABLE Singers TO ROLE {}".format(role_parent),
        "CREATE ROLE {}".format(role_child),
        "GRANT ROLE {} TO ROLE {}".format(role_parent, role_child),
    ],
)
operation = database_admin_api.update_database_ddl(request)

operation.result(OPERATION_TIMEOUT_SECONDS)
print(
    "Created roles {} and {} and granted privileges".format(role_parent, role_child)
)

request = spanner_database_admin.UpdateDatabaseDdlRequest(
    database=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    statements=[
        "REVOKE ROLE {} FROM ROLE {}".format(role_parent, role_child),
        "DROP ROLE {}".format(role_child),
    ],
)
operation = database_admin_api.update_database_ddl(request)

operation.result(OPERATION_TIMEOUT_SECONDS)
print("Revoked privileges and dropped role {}".format(role_child))

Ruby

require "google/cloud/spanner"

def spanner_add_and_drop_database_role project_id:, instance_id:, database_id:
  # project_id  = "Your Google Cloud project ID"
  # instance_id = "Your Spanner instance ID"
  # database_id = "Your Spanner database ID"

  admin_client = Google::Cloud::Spanner::Admin::Database::V1::DatabaseAdmin::Client.new
  role_parent = "new_parent"
  role_child = "new_child"

  db_path = admin_client.database_path project: project_id, instance: instance_id, database: database_id

  job = admin_client.update_database_ddl database: db_path, statements: [
    "CREATE ROLE #{role_parent}",
    "GRANT SELECT ON TABLE Singers TO ROLE #{role_parent}",
    "CREATE ROLE #{role_child}",
    "GRANT ROLE #{role_parent} TO ROLE #{role_child}"
  ]

  job.wait_until_done!
  puts "Created roles #{role_parent} and #{role_child} and granted privileges"


  job = admin_client.update_database_ddl database: db_path, statements: [
    "REVOKE ROLE #{role_parent} FROM ROLE #{role_child}",
    "DROP ROLE #{role_child}"
  ]

  job.wait_until_done!
  puts "Revoked privileges and dropped role #{role_child}"
end

Hierarchie von Rollen mit Vererbung erstellen

Sie können eine Hierarchie von Datenbankrollen erstellen, indem Sie einer Datenbankrolle eine andere zuweisen. Untergeordnete Rollen (Mitgliedsrollen) erben Berechtigungen von der übergeordneten Rolle.

Verwenden Sie die folgende Anweisung, um einer anderen Datenbankrolle eine Datenbankrolle zuzuweisen:

GoogleSQL

GRANT ROLE role1 TO ROLE role2;

PostgreSQL

GRANT role1 TO role2;

Weitere Informationen finden Sie unter Hierarchien und Übernahme von Datenbankrollen.

Hauptkonten Datenbankrollen zuweisen

Damit ein Hauptkonto auf Spanner-Ressourcen zugreifen kann, muss ihm mit einer der folgenden Optionen die erforderliche Datenbankrolle zugewiesen werden:

Console

  1. Klicken Sie auf der Seite Übersicht der Datenbank auf Infofeld ansehen, wenn das Infofeld noch nicht geöffnet ist.

  2. Klicken Sie auf HAUPTKONTO HINZUFÜGEN.

  3. Geben Sie unter Hauptkonten hinzufügen im Feld Neue Hauptkonten ein oder mehrere Hauptkonten ein.

  4. Wählen Sie unter Rollen zuweisen die Option Cloud Spanner > Cloud Spanner-Nutzer mit detailliertem Zugriff aus.

    Sie müssen diese Rolle jedem Hauptkonto nur einmal zuweisen. Dadurch wird der Prinzipal zu einem Nutzer mit detaillierter Zugriffssteuerung.

  5. Klicken Sie auf WEITERE ROLLE HINZUFÜGEN.

  6. Wählen Sie unter Rolle auswählen die Option Cloud Spanner > Cloud Spanner-Datenbankrollen-Nutzer aus.

  7. So erstellen Sie die IAM-Bedingung, in der die zuzuweisenden Rollen angegeben werden:

    1. Klicken Sie neben der Rolle „Cloud Spanner Database Role User“ auf IAM-BEDINGUNG HINZUFÜGEN.

    2. Geben Sie im Bereich Bedingung hinzufügen einen Titel und eine optionale Beschreibung für die Bedingung ein.

      Wenn Sie eine einzelne Datenbankrolle zuweisen, geben Sie den Rollennamen in der Regel im Bedingungstitel an. Wenn Sie mehrere Rollen zuweisen, können Sie etwas über die Gruppe von Rollen angeben.

    3. Klicken Sie auf Bedingungseditor.

    4. Geben Sie im Feld Ausdruck den folgenden Code ein:

      resource.type == "spanner.googleapis.com/DatabaseRole" &&
      resource.name.endsWith("/ROLE")

      Ersetzen Sie ROLE durch Ihren Rollennamen.

      Wenn Sie dem Hauptkonto mehrere Rollen zuweisen möchten, fügen Sie weitere Bedingungen mit dem Operator or (||) hinzu, wie im folgenden Beispiel gezeigt:

      resource.type == "spanner.googleapis.com/DatabaseRole" &&
      (resource.name.endsWith("/ROLE1") || resource.name.endsWith("/ROLE2"))

      Mit diesem Code werden zwei Rollen zugewiesen. Ersetzen Sie ROLE1 und ROLE2 durch Ihre Rollennamen. Wenn Sie mehr als zwei Rollen zuweisen möchten, fügen Sie weitere ODER-Bedingungen hinzu.

      Sie können jeden Bedingungsausdruck verwenden, der von IAM unterstützt wird. Weitere Informationen finden Sie unter Übersicht über IAM Conditions.

    5. Klicken Sie auf Speichern.

    6. Prüfen Sie, ob die Bedingung neben dem Feld Rolle in der Spalte IAM-Bedingung angezeigt wird.

    7. Klicken Sie auf Speichern.

      Zurück im Infofeld wird unter Rolle/Hauptkonto die Rolle Nutzer einer Cloud Spanner-Datenbankrolle für jede definierte Bedingung angezeigt.

      Die Zahl in Klammern neben der Bedingung gibt die Anzahl der Principals an, denen die Datenbankrolle durch diese Bedingung gewährt wird. Klicken Sie auf den Erweiterungspfeil, um die Liste der Hauptkonten aufzurufen.

    8. So korrigieren Sie Fehler in Datenbankrollennamen oder ‑bedingungen oder fügen einem Prinzipal zusätzliche Datenbankrollen hinzu:

      1. Maximieren Sie den Eintrag Nutzer einer Cloud Spanner-Datenbankrolle, in dem die gewünschte Bedingung aufgeführt ist.

      2. Klicken Sie neben einem Hauptkonto auf das Symbol Bearbeiten (Stift).

      3. Führen Sie im Bereich Zugriff auf database_name einen der folgenden Schritte aus:

        • Klicken Sie auf WEITERE ROLLE HINZUFÜGEN.

        • Wenn Sie die Bedingung bearbeiten möchten, klicken Sie neben dem Namen der Bedingung auf das Stiftsymbol Bearbeiten. Klicken Sie dann auf der Seite Bedingung bearbeiten auf Bedingungseditor, nehmen Sie die Korrekturen vor und klicken Sie zweimal auf Speichern.

gcloud

  1. Aktivieren Sie die detaillierte Zugriffssteuerung für den Prinzipal mit dem Befehl gcloud spanner databases add-iam-policy-binding:

    gcloud spanner databases add-iam-policy-binding DATABASE_NAME \
    --instance=INSTANCE_NAME \
    --role=roles/spanner.fineGrainedAccessUser \
    --member=MEMBER_NAME \
    --condition=None
    • MEMBER_NAME ist die Kennung für das Prinzipal. Sie muss eine der folgenden Syntaxen verwenden: user|group|serviceAccount:email oder domain:domain.

    • Mit diesem Befehl wird das Hauptkonto zu einem Nutzer für die detaillierte Zugriffssteuerung. Reichen Sie diesen Befehl nur einmal für jede Identität ein.

    • Bei Erfolg gibt der Befehl die gesamte Richtlinie für die Datenbank aus.

  2. Gewähren Sie die Berechtigung zur Verwendung einer oder mehrerer Datenbankrollen mit dem Befehl gcloud spanner databases add-iam-policy-binding:

    gcloud spanner databases add-iam-policy-binding DATABASE_NAME \
    --instance=INSTANCE_NAME \
    --role=roles/spanner.databaseRoleUser \
    --member=MEMBER_NAME \
    --condition=CONDITION
    • MEMBER_NAME ist die Kennung für das Prinzipal. Sie muss eine der folgenden Syntaxen verwenden: user|group|serviceAccount:email oder domain:domain.

    • CONDITION ist ein IAM-Bedingungsausdruck, der die Rollen angibt, die dem Hauptkonto zugewiesen werden sollen.

      CONDITION hat das folgende Format:

      --condition='expression=(resource.type == "spanner.googleapis.com/DatabaseRole" && resource.name.endsWith("/ROLE1")),title=TITLE,description=DESCRIPTION'

      Wenn Sie dem Hauptkonto Zugriff auf mehrere Rollen gewähren möchten, fügen Sie weitere Bedingungen mit dem Operator or (||) hinzu, wie im folgenden Beispiel gezeigt:

      --condition='expression=(resource.type == "spanner.googleapis.com/DatabaseRole" && (resource.name.endsWith("/ROLE1") || resource.name.endsWith("/ROLE2"))),title=TITLE,description=DESCRIPTION'

      Mit diesem Code werden zwei Rollen zugewiesen. Ersetzen Sie ROLE1 und ROLE2 durch Ihre Rollennamen. Wenn Sie mehr als zwei Rollen zuweisen möchten, fügen Sie mit dem Operator || weitere or-Bedingungen hinzu.

      Sie können jeden Bedingungsausdruck verwenden, der von IAM unterstützt wird. Weitere Informationen finden Sie unter Übersicht über IAM Conditions.

    Bei Erfolg gibt der Befehl die gesamte Richtlinie für die Datenbank aus.

    Im folgenden Beispiel werden dem Hauptkonto jsmith@example.com die Datenbankrollen hr_rep und hr_manager zugewiesen.

    gcloud spanner databases add-iam-policy-binding myDatabase \
      --instance=myInstance \
      --role=roles/spanner.databaseRoleUser \
      --member=user:jsmith@example.com \
      --condition='expression=(resource.type == "spanner.googleapis.com/DatabaseRole" && (resource.name.endsWith("/hr_rep") || resource.name.endsWith("/hr_manager"))),title=HR roles,description=Grant permissions on HR roles'
    

Clientbibliotheken

C++

void EnableFineGrainedAccess(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id, std::string const& iam_member,
    std::string const& database_role, std::string const& title) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);

  google::iam::v1::GetIamPolicyRequest request;
  request.set_resource(database.FullName());
  request.mutable_options()->set_requested_policy_version(3);
  auto policy = client.GetIamPolicy(request);
  if (!policy) throw std::move(policy).status();
  if (policy->version() < 3) policy->set_version(3);

  auto& binding = *policy->add_bindings();
  binding.set_role("roles/spanner.fineGrainedAccessUser");
  binding.add_members(iam_member);
  auto& condition = *binding.mutable_condition();
  condition.set_expression("resource.name.endsWith(\"/databaseRoles/" +
                           database_role + "\")");
  condition.set_title(title);

  auto new_policy =
      client.SetIamPolicy(database.FullName(), *std::move(policy));
  if (!new_policy) throw std::move(new_policy).status();
  std::cout << "Enabled fine-grained access in IAM. New policy has version "
            << new_policy->version() << "\n";
}

C#


using Google.Api.Gax;
using Google.Cloud.Iam.V1;
using Google.Cloud.Spanner.Admin.Database.V1;

public class EnableFineGrainedAccessSample
{
    public Policy EnableFineGrainedAccess(
        string projectId, string instanceId, string databaseId, 
        string databaseRole, string iamMember)
    {
        var resourceName = new UnparsedResourceName($"projects/{projectId}/instances/{instanceId}/databases/{databaseId}");

        var client = new DatabaseAdminClientBuilder().Build();

        // Request policy version 3 as earlier versions do not support condition field in role binding.
        // For more information see https://cloud.google.com/iam/docs/policies#versions.

        GetIamPolicyRequest getIamPolicyRequest = new GetIamPolicyRequest
        {
            ResourceAsResourceName = resourceName,
            Options = new GetPolicyOptions
            {
                RequestedPolicyVersion = 3
            }
        };

        var policy = client.GetIamPolicy(getIamPolicyRequest);

        // Gives the given IAM member access to the all the database roles
        // with resource name ending in ../databaseRoles/{databaseRole}.
        // For more information see https://cloud.google.com/iam/docs/conditions-overview.
        Binding newBinding = new Binding
        {
            Role = "roles/spanner.fineGrainedAccessUser",
            Members = { iamMember },
            Condition = new Google.Type.Expr
            {
                Title = "DatabaseRoleBindingTitle",
                Expression = $"resource.name.endsWith('/databaseRoles/{databaseRole}')"
            }
        };

        policy.Bindings.Add(newBinding);
        if (policy.Version < 3)
        {
            policy.Version = 3;
        }
        SetIamPolicyRequest setIamPolicyRequest = new SetIamPolicyRequest
        {
            Policy = policy,
            ResourceAsResourceName = resourceName,
        };
        var updatedPolicy = client.SetIamPolicy(setIamPolicyRequest);
        return updatedPolicy;
    }
}

Go


import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/iam/apiv1/iampb"
	database "cloud.google.com/go/spanner/admin/database/apiv1"
	expr "google.golang.org/genproto/googleapis/type/expr"
)

func enableFineGrainedAccess(w io.Writer, db string, iamMember string, databaseRole string, title string) error {
	// iamMember = "user:alice@example.com"
	// databaseRole = "parent"
	// title = "condition title"
	ctx := context.Background()
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return err
	}
	defer adminClient.Close()

	policy, err := adminClient.GetIamPolicy(ctx, &iampb.GetIamPolicyRequest{
		Resource: db,
		Options: &iampb.GetPolicyOptions{
			// IAM conditions need at least version 3
			RequestedPolicyVersion: 3,
		},
	})
	if err != nil {
		return err
	}

	// IAM conditions need at least version 3
	if policy.Version < 3 {
		policy.Version = 3
	}
	policy.Bindings = append(policy.Bindings, []*iampb.Binding{
		{
			Role:    "roles/spanner.fineGrainedAccessUser",
			Members: []string{iamMember},
		},
		{
			Role:    "roles/spanner.databaseRoleUser",
			Members: []string{iamMember},
			Condition: &expr.Expr{
				Expression: fmt.Sprintf(`resource.name.endsWith("/databaseRoles/%s")`, databaseRole),
				Title:      title,
			},
		},
	}...)
	_, err = adminClient.SetIamPolicy(ctx, &iampb.SetIamPolicyRequest{
		Resource: db,
		Policy:   policy,
	})
	if err != nil {
		return err
	}

	fmt.Fprintf(w, "Enabled fine-grained access in IAM.\n")
	return nil
}

Java


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
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.spanner.admin.database.v1.DatabaseName;
import com.google.type.Expr;

public class EnableFineGrainedAccess {

  static void enableFineGrainedAccess() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String iamMember = "user:alice@example.com";
    String role = "my-role";
    String title = "my-condition-title";
    enableFineGrainedAccess(projectId, instanceId, databaseId, iamMember, title, role);
  }

  static void enableFineGrainedAccess(
      String projectId,
      String instanceId,
      String databaseId,
      String iamMember,
      String title,
      String role) {
    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      final GetPolicyOptions options =
          GetPolicyOptions.newBuilder().setRequestedPolicyVersion(3).build();
      final GetIamPolicyRequest getRequest =
          GetIamPolicyRequest.newBuilder()
              .setResource(DatabaseName.of(projectId, instanceId, databaseId).toString())
              .setOptions(options).build();
      final Policy policy = databaseAdminClient.getIamPolicy(getRequest);
      int policyVersion = policy.getVersion();
      // The policy in the response from getDatabaseIAMPolicy might use the policy version
      // that you specified, or it might use a lower policy version. For example, if you
      // specify version 3, but the policy has no conditional role bindings, the response
      // uses version 1. Valid values are 0, 1, and 3.
      if (policy.getVersion() < 3) {
        // conditional role bindings work with policy version 3
        policyVersion = 3;
      }

      Binding binding1 =
          Binding.newBuilder()
              .setRole("roles/spanner.fineGrainedAccessUser")
              .addAllMembers(ImmutableList.of(iamMember))
              .build();

      Binding binding2 =
          Binding.newBuilder()
              .setRole("roles/spanner.databaseRoleUser")
              .setCondition(
                  Expr.newBuilder().setDescription(title).setExpression(
                      String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)
                  ).setTitle(title).build())
              .addAllMembers(ImmutableList.of(iamMember))
              .build();
      ImmutableList<Binding> bindings =
          ImmutableList.<Binding>builder()
              .addAll(policy.getBindingsList())
              .add(binding1)
              .add(binding2)
              .build();
      Policy policyWithConditions =
          Policy.newBuilder()
              .setVersion(policyVersion)
              .setEtag(policy.getEtag())
              .addAllBindings(bindings)
              .build();
      final SetIamPolicyRequest setRequest =
          SetIamPolicyRequest.newBuilder()
              .setResource(DatabaseName.of(projectId, instanceId, databaseId).toString())
              .setPolicy(policyWithConditions).build();
      final Policy response = databaseAdminClient.setIamPolicy(setRequest);
      System.out.printf(
          "Enabled fine-grained access in IAM with version %d%n", response.getVersion());
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const projectId = 'my-project-id';
// iamMember = 'user:alice@example.com';
// databaseRole = 'parent';
// title = 'condition title';
// Imports the Google Cloud Spanner client library
const {Spanner, protos} = require('@google-cloud/spanner');

// Instantiates a client
const spanner = new Spanner({
  projectId: projectId,
});

async function enableFineGrainedAccess() {
  // Gets a reference to a Cloud Spanner Database Admin Client object
  const databaseAdminClient = spanner.getDatabaseAdminClient();

  const [policy] = await databaseAdminClient.getIamPolicy({
    resource: databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    ),
    options: (protos.google.iam.v1.GetPolicyOptions = {
      requestedPolicyVersion: 3,
    }),
  });
  if (policy.version < 3) {
    policy.version = 3;
  }

  const newBinding = {
    role: 'roles/spanner.fineGrainedAccessUser',
    members: [`user:${iamMember}`],
    condition: {
      title: title,
      expression: `resource.name.endsWith("/databaseRoles/${databaseRole}")`,
    },
  };
  policy.bindings.push(newBinding);
  await databaseAdminClient.setIamPolicy({
    resource: databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    ),
    policy: policy,
  });
  // Requested Policy Version is Optional. The maximum policy version that will be used to format the policy.
  // Valid values are 0, 1, and 3. Requests specifying an invalid value will be rejected.
  const newPolicy = await databaseAdminClient.getIamPolicy({
    resource: databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    ),
    options: (protos.google.iam.v1.GetPolicyOptions = {
      requestedPolicyVersion: 3,
    }),
  });
  console.log(newPolicy);
}
enableFineGrainedAccess();

PHP

use \Google\Cloud\Iam\V1\Binding;
use \Google\Type\Expr;
use Google\Cloud\Iam\V1\GetIamPolicyRequest;
use Google\Cloud\Iam\V1\SetIamPolicyRequest;
use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;

/**
 * Enable Fine Grained Access.
 * Example:
 * ```
 * enable_fine_grained_access($projectId, $instanceId, $databaseId, $iamMember, $databaseRole, $title);
 * ```
 *
 * @param string $projectId The Google cloud project ID
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $iamMember The IAM member. Eg: `user:{emailid}`,
 *        `serviceAccount:{emailid}`, `group:{emailid}`, `domain:{domain}`
 * @param string $databaseRole The database role bound to
 *        the IAM member.
 * @param string $title Condition title.
 */
function enable_fine_grained_access(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $iamMember,
    string $databaseRole,
    string $title
): void {
    $adminClient = new DatabaseAdminClient();
    $resource = $adminClient->databaseName($projectId, $instanceId, $databaseId);
    $getIamPolicyRequest = (new GetIamPolicyRequest())
        ->setResource($resource);
    $policy = $adminClient->getIamPolicy($getIamPolicyRequest);

    // IAM conditions need at least version 3
    if ($policy->getVersion() != 3) {
        $policy->setVersion(3);
    }

    $binding = new Binding([
        'role' => 'roles/spanner.fineGrainedAccessUser',
        'members' => [$iamMember],
        'condition' => new Expr([
            'title' => $title,
            'expression' => sprintf("resource.name.endsWith('/databaseRoles/%s')", $databaseRole)
        ])
    ]);
    $policy->setBindings([$binding]);
    $setIamPolicyRequest = (new SetIamPolicyRequest())
        ->setResource($resource)
        ->setPolicy($policy);
    $adminClient->setIamPolicy($setIamPolicyRequest);

    printf('Enabled fine-grained access in IAM' . PHP_EOL);
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
# iam_member = "user:alice@example.com"
# database_role = "new_parent"
# title = "condition title"

from google.iam.v1 import iam_policy_pb2, options_pb2, policy_pb2
from google.type import expr_pb2

spanner_client = spanner.Client()
database_admin_api = spanner_client.database_admin_api

# The policy in the response from getDatabaseIAMPolicy might use the policy version
# that you specified, or it might use a lower policy version. For example, if you
# specify version 3, but the policy has no conditional role bindings, the response
# uses version 1. Valid values are 0, 1, and 3.
request = iam_policy_pb2.GetIamPolicyRequest(
    resource=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    options=options_pb2.GetPolicyOptions(requested_policy_version=3),
)
policy = database_admin_api.get_iam_policy(request=request)
if policy.version < 3:
    policy.version = 3

new_binding = policy_pb2.Binding(
    role="roles/spanner.fineGrainedAccessUser",
    members=[iam_member],
    condition=expr_pb2.Expr(
        title=title,
        expression=f'resource.name.endsWith("/databaseRoles/{database_role}")',
    ),
)

policy.version = 3
policy.bindings.append(new_binding)
set_request = iam_policy_pb2.SetIamPolicyRequest(
    resource=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    policy=policy,
)
database_admin_api.set_iam_policy(set_request)

new_policy = database_admin_api.get_iam_policy(request=request)
print(
    f"Enabled fine-grained access in IAM. New policy has version {new_policy.version}"
)

Ruby

require "google/cloud/spanner"

def spanner_enable_fine_grained_access project_id:, instance_id:, database_id:, iam_member:, database_role:, title:
  # project_id  = "Your Google Cloud project ID"
  # instance_id = "Your Spanner instance ID"
  # database_id = "Your Spanner database ID"
  # iam_member = "user:alice@example.com"
  # database_role = "new_parent"
  # title = "condition title"

  admin_client = Google::Cloud::Spanner::Admin::Database::V1::DatabaseAdmin::Client.new
  db_path = admin_client.database_path project: project_id, instance: instance_id, database: database_id

  policy = admin_client.get_iam_policy resource: db_path, options: { requested_policy_version: 3 }

  policy.version = 3 if policy.version < 3

  binding = Google::Iam::V1::Binding.new(
    role: "roles/spanner.fineGrainedAccessUser",
    members: [iam_member],
    condition: Google::Type::Expr.new(
      title: title,
      expression: "resource.name.endsWith('/databaseRoles/#{database_role}')"
    )
  )

  policy.bindings << binding
  result = admin_client.set_iam_policy resource: db_path, policy: policy

  puts "Enabled fine-grained access in IAM."
end

Nutzer und Entwickler informieren, damit sie Datenbankrollen verwenden

Nachdem die erste Konfiguration der detaillierten Zugriffssteuerung abgeschlossen ist, müssen Sie Nutzer und Anwendungsentwickler darüber informieren, dass sie Datenbankrollen verwenden müssen.

  • Nutzer der detaillierten Zugriffssteuerung müssen eine Datenbankrolle angeben, wenn sie über die Google Cloud Console oder die Google Cloud CLI auf Spanner-Datenbanken zugreifen.

  • Anwendungen, die die detaillierte Zugriffssteuerung verwenden, müssen beim Zugriff auf die Datenbank eine Datenbankrolle angeben.

Weitere Informationen finden Sie unter Mit detaillierter Zugriffssteuerung auf eine Datenbank zugreifen.

Principal auf detaillierte Zugriffssteuerung umstellen

So stellen Sie einen Prinzipal von der Zugriffssteuerung auf Datenbankebene auf die detaillierte Zugriffssteuerung um:

  1. Aktivieren Sie die detaillierte Zugriffssteuerung für das Hauptkonto und gewähren Sie Zugriff auf alle erforderlichen Datenbankrollen, wie unter Hauptkonten Datenbankrollen zuweisen beschrieben.

  2. Aktualisieren Sie alle Anwendungen, die als dieses Hauptkonto ausgeführt werden. Geben Sie die entsprechenden Datenbankrollen in Aufrufen von Clientbibliotheksmethoden an.

  3. Entziehen Sie dem Hauptkonto alle IAM-Rollen auf Datenbankebene. So wird der Zugriff für das Hauptkonto nur über eine Methode gesteuert.

    Ausnahme: Für die Interaktion mit Spanner-Ressourcen in derGoogle Cloud -Konsole müssen alle Nutzer die IAM-Rolle roles/spanner.viewer haben.

    Wenn Sie IAM-Rollen auf Datenbankebene widerrufen möchten, folgen Sie der Anleitung unter Berechtigungen auf Datenbankebene entfernen.

Datenbankrollen auflisten

Sie können die Datenbankrollen auflisten, die einer Datenbank zugeordnet sind.

Console

Geben Sie auf der Spanner Studio-Seite für die Datenbank die folgende Abfrage ein, um Datenbankrollen aufzulisten:

GoogleSQL

SELECT * FROM INFORMATION_SCHEMA.ROLES;

PostgreSQL

SELECT * FROM information_schema.enabled_roles;

Die Antwort enthält die aktuelle Rolle und Rollen, deren Berechtigungen die aktuelle Rolle durch Vererbung nutzen kann. Verwenden Sie den Google Cloud CLI-Befehl, um alle Rollen abzurufen.

gcloud

Geben Sie den folgenden Befehl ein, um eine ungefilterte Liste der Datenbankrollen abzurufen. Hierfür ist die Berechtigung spanner.databaseRoles.list erforderlich.

gcloud spanner databases roles list --database=DATABASE_NAME --instance=INSTANCE_NAME

Clientbibliotheken

C++

void ListDatabaseRoles(google::cloud::spanner_admin::DatabaseAdminClient client,
                       std::string const& project_id,
                       std::string const& instance_id,
                       std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  std::cout << "Database Roles are:\n";
  for (auto& role : client.ListDatabaseRoles(database.FullName())) {
    if (!role) throw std::move(role).status();
    std::cout << role->name() << "\n";
  }
}

C#


using Google.Api.Gax;
using Google.Cloud.Spanner.Admin.Database.V1;
using System;

public class ListDatabaseRolesSample
{
    public PagedEnumerable<ListDatabaseRolesResponse, DatabaseRole> ListDatabaseRoles(string projectId, string instanceId, string databaseId)
    {
        string parent = $"projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        var client = DatabaseAdminClient.Create();
        PagedEnumerable<ListDatabaseRolesResponse, DatabaseRole> databaseRoles = client.ListDatabaseRoles(parent);
        foreach (var dbRole in databaseRoles)
        {
            Console.WriteLine($"Database Role: {dbRole.DatabaseRoleName}");
        }
        return databaseRoles;
    }
}

Go


import (
	"context"
	"fmt"
	"io"
	"strings"

	"google.golang.org/api/iterator"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

func listDatabaseRoles(w io.Writer, db string) error {
	ctx := context.Background()
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return err
	}
	defer adminClient.Close()

	iter := adminClient.ListDatabaseRoles(ctx, &adminpb.ListDatabaseRolesRequest{
		Parent: db,
	})
	rolePrefix := db + "/databaseRoles/"
	for {
		role, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		if !strings.HasPrefix(role.Name, rolePrefix) {
			return fmt.Errorf("Role %v does not have prefix %v", role.Name, rolePrefix)
		}
		fmt.Fprintf(w, "%s\n", strings.TrimPrefix(role.Name, rolePrefix))
	}
	return nil
}

Java


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseRolesPage;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseRolesPagedResponse;
import com.google.spanner.admin.database.v1.DatabaseName;
import com.google.spanner.admin.database.v1.DatabaseRole;

public class ListDatabaseRoles {

  static void listDatabaseRoles() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    listDatabaseRoles(projectId, instanceId, databaseId);
  }

  static void listDatabaseRoles(String projectId, String instanceId, String databaseId) {
    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      DatabaseName databaseName = DatabaseName.of(projectId, instanceId, databaseId);
      ListDatabaseRolesPagedResponse response
          = databaseAdminClient.listDatabaseRoles(databaseName);
      System.out.println("List of Database roles");
      for (ListDatabaseRolesPage page : response.iteratePages()) {
        for (DatabaseRole role : page.iterateAll()) {
          System.out.printf("Obtained role %s%n", role.getName());
        }
      }
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const projectId = 'my-project-id';

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

const databaseAdminClient = spanner.getDatabaseAdminClient();

async function getDatabaseRoles() {
  // Fetching database roles
  const [databaseRoles] = await databaseAdminClient.listDatabaseRoles({
    parent: databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    ),
  });
  console.log(
    `Roles for Database: ${databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    )}`,
  );
  databaseRoles.forEach(role => {
    console.log(`Role: ${role.name}`);
  });
}
getDatabaseRoles();

PHP

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\ListDatabaseRolesRequest;

/**
 * List Database roles in the given database.
 * Example:
 * ```
 * list_database_roles($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google cloud project ID
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function list_database_roles(
    string $projectId,
    string $instanceId,
    string $databaseId
): void {
    $adminClient = new DatabaseAdminClient();
    $resource = $adminClient->databaseName($projectId, $instanceId, $databaseId);
    $listDatabaseRolesRequest = (new ListDatabaseRolesRequest())
        ->setParent($resource);

    $roles = $adminClient->listDatabaseRoles($listDatabaseRolesRequest);
    printf('List of Database roles:' . PHP_EOL);
    foreach ($roles as $role) {
        printf($role->getName() . PHP_EOL);
    }
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin

spanner_client = spanner.Client()
database_admin_api = spanner_client.database_admin_api

request = spanner_database_admin.ListDatabaseRolesRequest(
    parent=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    )
)
# List database roles.
print("Database Roles are:")
for role in database_admin_api.list_database_roles(request):
    print(role.name.split("/")[-1])

Ruby

require "google/cloud/spanner"

def spanner_list_database_roles project_id:, instance_id:, database_id:
  # project_id  = "Your Google Cloud project ID"
  # instance_id = "Your Spanner instance ID"
  # database_id = "Your Spanner database ID"

  admin_client = Google::Cloud::Spanner::Admin::Database::V1::DatabaseAdmin::Client.new

  db_path = admin_client.database_path project: project_id, instance: instance_id, database: database_id

  result = admin_client.list_database_roles parent: db_path

  puts "List of Database roles:"
  result.each do |role|
    puts role.name
  end
end

Einer Datenbankrolle gewährte Berechtigungen ansehen

Führen Sie die folgenden Abfragen aus, um die einer Rolle gewährten Berechtigungen aufzurufen:

GoogleSQL

SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE grantee = 'ROLE_NAME';
SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE grantee = 'ROLE_NAME';
SELECT * FROM INFORMATION_SCHEMA.CHANGE_STREAM_PRIVILEGES WHERE grantee = 'ROLE_NAME';

INFORMATION_SCHEMA.TABLE_PRIVILEGES gibt Berechtigungen für Tabellen und Ansichten zurück. Die Berechtigungen SELECT, INSERT und UPDATE in TABLE_PRIVILEGES werden auch in COLUMN_PRIVILEGES angezeigt.

PostgreSQL

SELECT * FROM information_schema.table_privileges WHERE grantee = 'ROLE_NAME';
SELECT * FROM information_schema.column_privileges WHERE grantee = 'ROLE_NAME';
SELECT * FROM information_schema.change_stream_privileges WHERE grantee = 'ROLE_NAME';

information_schema.table_privileges gibt Berechtigungen für Tabellen und Ansichten zurück. Die Berechtigungen SELECT, INSERT und UPDATE in table_privileges werden auch in column_privileges angezeigt.

Nutzer der detaillierten Zugriffssteuerung ansehen

Führen Sie den folgenden Befehl aus, um eine Liste der Identitäten aufzurufen, die Nutzer der detaillierten Zugriffssteuerung sind. Damit Sie den Befehl ausführen können, muss die Cloud Asset API für Ihr Projekt aktiviert sein und Sie müssen die IAM-Berechtigung cloudasset.assets.searchAllIamPolicies haben.

gcloud asset search-all-iam-policies \
--scope=projects/PROJECT_NAME \
--query='roles=roles/spanner.fineGrainedAccessUser AND resource=//spanner.googleapis.com/projects/PROJECT_NAME/instances/INSTANCE_NAME/databases/DATABASE_NAME' \
--flatten=policy.bindings[].members[] \
--format='table(policy.bindings.members)'

Die Ausgabe sieht etwa so aus:

MEMBERS
user:222larabrown@gmail.com
user:baklavainthebalkans@gmail.com
serviceAccount:cs-fgac-sa-1@cloud-spanner-demo.google.com.iam.gserviceaccount.com
serviceAccount:cs-fgac-sa-2@cloud-spanner-demo.google.com.iam.gserviceaccount.com

Weitere Informationen finden Sie unter API in Ihrem Google Cloud Projekt aktivieren.

Hauptkonten mit Datenbankzugriff ansehen

Führen Sie die folgenden Befehle aus, um eine Liste der Identitäten aufzurufen, denen Zugriff auf eine bestimmte Datenbank gewährt wurde. Damit Sie diese Befehle ausführen können, muss die Cloud Asset API für Ihr Projekt aktiviert sein und Sie benötigen die IAM-Berechtigung cloudasset.assets.searchAllIamPolicies.

gcloud asset search-all-iam-policies \
--scope=projects/PROJECT_NAME \
--query='roles=roles/spanner.databaseRoleUser AND policy:"resource.name" AND policy:/ROLE_NAME AND resource=//spanner.googleapis.com/projects/PROJECT_NAME/instances/INSTANCE_NAME/databases/DATABASE_NAME' \
--flatten=policy.bindings[].members[] \
--format='table(policy.bindings.members)'

Die Ausgabe sieht etwa so aus:

MEMBERS
222larabrown@gmail.com

IAM-Bedingungen für ein Konto aufrufen

Wenn Sie eine Liste der IAM-Bedingungen aufrufen möchten, die beim Zuweisen der Rolle Nutzer einer Cloud Spanner-Datenbankrolle an ein Hauptkonto angegeben wurden, führen Sie den folgenden Befehl aus:

gcloud asset search-all-iam-policies \
--scope=projects/PROJECT_NAME \
--query='roles=roles/spanner.databaseRoleUser AND policy:resource.name AND policy:"PRINCIPAL_IDENTIFIER" AND resource=//spanner.googleapis.com/projects/PROJECT_NAME/instances/INSTANCE_NAME/databases/DATABASE_NAME' \
--flatten=policy.bindings[] \
--format='table(policy.bindings.condition.expression)'

Dabei gilt:PRINCIPAL_IDENTIFIER

  { user:user-account-name | serviceAccount:service-account-name }

PRINCIPAL_IDENTIFIER Beispiele:

user:222larabrown@gmail.com
serviceAccount:cs-fgac-sa-1@cloud-spanner-demo.google.com.iam.gserviceaccount.com

Die folgende Beispielausgabe zeigt zwei Bedingungsausdrücke.

EXPRESSION
resource.type == "spanner.googleapis.com/DatabaseRole" &&
resource.name.endsWith("/hr_analyst")
resource.type == "spanner.googleapis.com/DatabaseRole" &&
resource.name.endsWith("/hr_manager")

IAM-Richtlinien auf fehlende Bedingungen für Datenbankrollen prüfen

Nachdem Sie Hauptkonten Zugriff auf Datenbankrollen gewährt haben, empfehlen wir, dass Sie dafür sorgen, dass für jede IAM-Bindung eine Bedingung angegeben ist.

Führen Sie dazu den folgenden Befehl aus:

gcloud asset search-all-iam-policies \
--scope=projects/PROJECT_NAME \
--query='roles:roles/spanner.databaseRoleUser AND resource=//spanner.googleapis.com/projects/PROJECT_NAME/instances/INSTANCE_NAME/databases/DATABASE_NAME'
--flatten=policy.bindings[].members[]

Die Ausgabe sieht etwa so aus:

ROLE                              MEMBERS                         EXPRESSION
roles/spanner.databaseRoleUser    serviceAccount:cs-fgac-sa-1@...
roles/spanner.databaseRoleUser    serviceAccount:cs-fgac-sa-2@... resource.type == "spanner…"

Beachten Sie, dass im ersten Ergebnis eine Bedingung fehlt. Daher haben die Hauptkonten in dieser Bindung Zugriff auf alle Datenbankrollen.

Datenbankrolle löschen

Wenn Sie eine Datenbankrolle löschen, wird die Mitgliedschaft anderer Rollen in der Rolle und die Mitgliedschaft der Rolle in anderen Rollen automatisch widerrufen.

Wenn Sie eine Datenbankrolle löschen möchten, müssen Sie zuerst Folgendes tun:

  1. Heben Sie alle Berechtigungen für die detaillierte Zugriffssteuerung für die Rolle auf.
  2. Entfernen Sie alle IAM-Richtlinienbindungen, die sich auf diese Rolle beziehen, damit eine später erstellte Datenbankrolle mit demselben Namen diese Bindungen nicht erbt.

Console

So löschen Sie eine Datenbankrolle:

  1. Klicken Sie auf der Seite Übersicht der Datenbank auf Spanner Studio.

  2. Wenn Sie der Rolle Berechtigungen entziehen möchten, geben Sie eine REVOKE-Anweisung ein.

    GoogleSQL

    Syntaxdetails zur REVOKE-Anweisung finden Sie unter GoogleSQL-Datendefinitionssprache. Informationen zu Berechtigungen finden Sie unter Berechtigungen für die detaillierte Zugriffssteuerung.

    Wenn Sie beispielsweise die Berechtigungen SELECT, INSERT und UPDATE für die Tabellen employees und contractors aus der Datenbankrolle hr_manager widerrufen möchten, geben Sie die folgende Anweisung ein:

    REVOKE SELECT, INSERT, UPDATE ON TABLE employees, contractors FROM ROLE hr_manager;
    

    PostgreSQL

    Syntaxdetails zur REVOKE-Anweisung finden Sie unter PostgreSQL-Datendefinitionssprache. Informationen zu Berechtigungen finden Sie unter Berechtigungen für die detaillierte Zugriffssteuerung.

    Wenn Sie beispielsweise die Berechtigungen SELECT, INSERT und UPDATE für die Tabellen employees und contractors aus der Datenbankrolle hr_manager widerrufen möchten, geben Sie die folgende Anweisung ein:

    REVOKE SELECT, INSERT, UPDATE ON TABLE employees, contractors FROM hr_manager;
    

    Sie können eine DDL-Vorlage für die REVOKE-Anweisung verwenden. Suchen Sie im Bereich Explorer nach der Rolle, für die Sie die Berechtigung aufheben möchten. Klicken Sie auf  Aktionen ansehen und wählen Sie den Berechtigungstyp aus, für den Sie den Zugriff für diese Rolle widerrufen möchten. Die REVOKE-Vorlagenanweisung wird in einem neuen Editor-Tab eingefügt.

  3. Löschen Sie alle IAM-Bedingungen, die mit der Rolle verknüpft sind.

    1. Suchen Sie in der Liste der Rollen im Infobereich nach der Rolle Cloud Spanner-Datenbankrollennutzer, neben der der gewünschte Bedingungstitel steht, und maximieren Sie dann die Rolle, um die Hauptkonten zu sehen, die Zugriff auf die Rolle haben.

    2. Klicken Sie für eines der Hauptkonten auf das Symbol Hauptkonto bearbeiten (Stift).

    3. Klicken Sie auf der Seite Bearbeitungszugriff neben der Rolle „Cloud Spanner Database Role User“ auf das Symbol Rolle löschen (Papierkorb).

    4. Klicken Sie auf Speichern.

    5. Wiederholen Sie die drei vorherigen Schritte für andere Principals, die unter der Bedingung aufgeführt sind.

  4. Wenn Sie die Rolle entfernen möchten, rufen Sie die Seite Spanner Studio auf und geben Sie die folgende Anweisung ein:

    DROP ROLE ROLE_NAME;

  5. Klicken Sie auf Senden.

gcloud

  1. Wenn Sie alle Berechtigungen für eine Rolle widerrufen und die Rolle dann löschen möchten, verwenden Sie den Befehl gcloud spanner databases ddl update so:

    GoogleSQL

    gcloud spanner databases ddl update DATABASE_NAME \
    --instance=INSTANCE_NAME \
    --ddl='REVOKE PERMISSIONS ON TABLE TABLE_NAME FROM ROLE ROLE_NAME; DROP ROLE ROLE_NAME;'

    PostgreSQL

    gcloud spanner databases ddl update DATABASE_NAME \
    --instance=INSTANCE_NAME \
    --ddl='REVOKE PERMISSIONS ON TABLE TABLE_NAME FROM ROLE_NAME; DROP ROLE ROLE_NAME;'

    Gültige Werte für PERMISSIONS sind SELECT, INSERT, UPDATE und DELETE.

  2. Verwenden Sie den Befehl gcloud spanner databases remove-iam-policy-binding, um alle zugehörigen IAM-Bedingungen zu löschen:

    gcloud spanner databases remove-iam-policy-binding DATABASE_NAME \
    --instance=INSTANCE_NAME \
    --role=ROLE_NAME \
    --member=MEMBER_NAME \
    --condition=CONDITION
    • MEMBER_NAME ist die Kennung für das Prinzipal. Muss das Format user|group|serviceAccount:email oder domain:domain haben.

    • CONDITION ist ein IAM-Bedingungsausdruck, der die Rollen angibt, die dem Hauptkonto zugewiesen werden sollen.

      CONDITION hat das folgende Format:

      --condition='expression=(resource.type == "spanner.googleapis.com/DatabaseRole" && (resource.name.endsWith("/ROLE1") || resource.name.endsWith("/ROLE2"))),title=TITLE,description=DESCRIPTION'

      Die gesamte Bedingungsspezifikation muss genau mit der Bedingungsspezifikation übereinstimmen, die im Befehl verwendet wurde, mit dem die Berechtigung erteilt wurde, einschließlich Titel und Beschreibung.

Clientbibliotheken

In diesen Codebeispielen wird eine Datenbankrolle erstellt und gelöscht.

C++

void AddAndDropDatabaseRole(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id, std::string const& role_parent,
    std::string const& role_child) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  std::vector<std::string> grant_statements = {
      "CREATE ROLE " + role_parent,
      "GRANT SELECT ON TABLE Singers TO ROLE " + role_parent,
      "CREATE ROLE " + role_child,
      "GRANT ROLE " + role_parent + " TO ROLE " + role_child,
  };
  auto metadata =
      client.UpdateDatabaseDdl(database.FullName(), grant_statements).get();
  google::cloud::spanner_testing::LogUpdateDatabaseDdl(  //! TODO(#4758)
      client, database, metadata.status());              //! TODO(#4758)
  if (!metadata) throw std::move(metadata).status();
  std::cout << "Created roles " << role_parent << " and " << role_child
            << " and granted privileges\n";

  std::vector<std::string> revoke_statements = {
      "REVOKE ROLE " + role_parent + " FROM ROLE " + role_child,
      "DROP ROLE " + role_child,
  };
  metadata =
      client.UpdateDatabaseDdl(database.FullName(), revoke_statements).get();
  google::cloud::spanner_testing::LogUpdateDatabaseDdl(  //! TODO(#4758)
      client, database, metadata.status());              //! TODO(#4758)
  if (!metadata) throw std::move(metadata).status();
  std::cout << "Revoked privileges and dropped role " << role_child << "\n";
}

C#


using Google.Cloud.Spanner.Data;
using System.Threading.Tasks;

public class AddAndDropDatabaseRoleAsyncSample
{
    public async Task AddDatabaseRoleAsync(string projectId, string instanceId, string databaseId, string databaseRole)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        string createRoleStatement = $"CREATE ROLE {databaseRole}";

        // Creates the given database role.
        using var connection = new SpannerConnection(connectionString);
        using var updateCmd = connection.CreateDdlCommand(createRoleStatement);
        await updateCmd.ExecuteNonQueryAsync();
    }

    public async Task DropDatabaseRoleAsync(string projectId, string instanceId, string databaseId, string databaseRole)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        string deleteRoleStatement = $"DROP ROLE {databaseRole}";

        // Drops the given database role.
        using var connection = new SpannerConnection(connectionString);
        using var updateCmd = connection.CreateDdlCommand(deleteRoleStatement);
        await updateCmd.ExecuteNonQueryAsync();
    }
}

Go


import (
	"context"
	"io"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

func addAndDropDatabaseRole(w io.Writer, db string) error {
	ctx := context.Background()
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return err
	}
	defer adminClient.Close()

	// Set up database roles and membership. After database roles are created,
	// users can be granted roles by setting IAM policies.
	op, err := adminClient.UpdateDatabaseDdl(ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database: db,
		Statements: []string{
			"CREATE ROLE parent",
			"GRANT SELECT ON TABLE Albums TO ROLE parent",
			"CREATE ROLE child",
			"GRANT ROLE parent TO ROLE child",
		},
	})
	if err != nil {
		return err
	}
	if err := op.Wait(ctx); err != nil {
		return err
	}

	// Delete role and membership.
	op, err = adminClient.UpdateDatabaseDdl(ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database: db,
		Statements: []string{
			"REVOKE ROLE parent FROM ROLE child",
			"DROP ROLE child",
		},
	})
	if err != nil {
		return err
	}
	if err := op.Wait(ctx); err != nil {
		return err
	}
	return nil
}

Java


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AddAndDropDatabaseRole {

  static void addAndDropDatabaseRole() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String parentRole = "parent_role";
    String childRole = "child_role";
    addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole, "Albums");
  }

  static void addAndDropDatabaseRole(
      String projectId, String instanceId, String databaseId,
      String parentRole, String childRole, String... tables) {
    try (Spanner spanner =
        SpannerOptions.newBuilder()
            .setProjectId(projectId)
            .build()
            .getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      System.out.println("Waiting for role create operation to complete...");
      List<String> roleStatements = new ArrayList<>(ImmutableList.of(
          String.format("CREATE ROLE %s", parentRole),
          String.format("CREATE ROLE %s", childRole),
          String.format("GRANT ROLE %s TO ROLE %s", parentRole, childRole)));
      for (String table : tables) {
        roleStatements.add(String.format("GRANT SELECT ON TABLE %s TO ROLE %s", table, parentRole));
      }
      databaseAdminClient.updateDatabaseDdlAsync(
              DatabaseName.of(projectId, instanceId, databaseId), roleStatements)
          .get(5, TimeUnit.MINUTES);
      System.out.printf(
          "Created roles %s and %s and granted privileges%n", parentRole, childRole);
      // Delete role and membership.
      System.out.println("Waiting for role revoke & drop operation to complete...");
      databaseAdminClient.updateDatabaseDdlAsync(
          DatabaseName.of(projectId, instanceId, databaseId),
          ImmutableList.of(
              String.format("REVOKE ROLE %s FROM ROLE %s", parentRole, childRole),
              String.format("DROP ROLE %s", childRole))).get(5, TimeUnit.MINUTES);
      System.out.printf("Revoked privileges and dropped role %s%n", childRole);
    } catch (ExecutionException | TimeoutException e) {
      System.out.printf(
          "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage());
      e.printStackTrace();
    } catch (InterruptedException e) {
      System.out.println(
          "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted");
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const projectId = 'my-project-id';

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

const databaseAdminClient = spanner.getDatabaseAdminClient();

async function addAndDropNewDatabaseRole() {
  // Creates a new user defined role and grant permissions
  try {
    const request = [
      'CREATE ROLE parent',
      'GRANT SELECT ON TABLE Singers TO ROLE parent',
      'CREATE ROLE child',
      'GRANT ROLE parent TO ROLE child',
    ];
    const [operation] = await databaseAdminClient.updateDatabaseDdl({
      database: databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      ),
      statements: request,
    });

    console.log('Waiting for operation to complete...');
    await operation.promise();

    console.log('Created roles child and parent and granted privileges');
  } catch (err) {
    console.error('ERROR:', err);
  }

  // Revoke permissions and drop child role.
  // A role can't be dropped until all its permissions are revoked.
  try {
    const request = ['REVOKE ROLE parent FROM ROLE child', 'DROP ROLE child'];
    const [operation] = await databaseAdminClient.updateDatabaseDdl({
      database: databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      ),
      statements: request,
    });

    console.log('Waiting for operation to complete...');
    await operation.promise();

    console.log('Revoked privileges and dropped role child');
  } catch (err) {
    console.error('ERROR:', err);
  } finally {
    // Close the spanner client when finished.
    // The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
    spanner.close();
  }
}
addAndDropNewDatabaseRole();

PHP

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Adds and drops roles to the Singers table in the example database.
 * Example:
 * ```
 * add_drop_database_role($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function add_drop_database_role(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [
            'CREATE ROLE new_parent',
            'GRANT SELECT ON TABLE Singers TO ROLE new_parent',
            'CREATE ROLE new_child',
            'GRANT ROLE new_parent TO ROLE new_child'
        ]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    printf('Waiting for create role and grant operation to complete...%s', PHP_EOL);
    $operation->pollUntilComplete();

    printf('Created roles %s and %s and granted privileges%s', 'new_parent', 'new_child', PHP_EOL);

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [
            'REVOKE ROLE new_parent FROM ROLE new_child',
            'DROP ROLE new_child'
        ]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    printf('Waiting for revoke role and drop role operation to complete...%s', PHP_EOL);
    $operation->pollUntilComplete();

    printf('Revoked privileges and dropped role %s%s', 'new_child', PHP_EOL);
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

from google.cloud.spanner_admin_database_v1.types import spanner_database_admin

spanner_client = spanner.Client()
database_admin_api = spanner_client.database_admin_api

role_parent = "new_parent"
role_child = "new_child"

request = spanner_database_admin.UpdateDatabaseDdlRequest(
    database=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    statements=[
        "CREATE ROLE {}".format(role_parent),
        "GRANT SELECT ON TABLE Singers TO ROLE {}".format(role_parent),
        "CREATE ROLE {}".format(role_child),
        "GRANT ROLE {} TO ROLE {}".format(role_parent, role_child),
    ],
)
operation = database_admin_api.update_database_ddl(request)

operation.result(OPERATION_TIMEOUT_SECONDS)
print(
    "Created roles {} and {} and granted privileges".format(role_parent, role_child)
)

request = spanner_database_admin.UpdateDatabaseDdlRequest(
    database=database_admin_api.database_path(
        spanner_client.project, instance_id, database_id
    ),
    statements=[
        "REVOKE ROLE {} FROM ROLE {}".format(role_parent, role_child),
        "DROP ROLE {}".format(role_child),
    ],
)
operation = database_admin_api.update_database_ddl(request)

operation.result(OPERATION_TIMEOUT_SECONDS)
print("Revoked privileges and dropped role {}".format(role_child))

Ruby

require "google/cloud/spanner"

def spanner_add_and_drop_database_role project_id:, instance_id:, database_id:
  # project_id  = "Your Google Cloud project ID"
  # instance_id = "Your Spanner instance ID"
  # database_id = "Your Spanner database ID"

  admin_client = Google::Cloud::Spanner::Admin::Database::V1::DatabaseAdmin::Client.new
  role_parent = "new_parent"
  role_child = "new_child"

  db_path = admin_client.database_path project: project_id, instance: instance_id, database: database_id

  job = admin_client.update_database_ddl database: db_path, statements: [
    "CREATE ROLE #{role_parent}",
    "GRANT SELECT ON TABLE Singers TO ROLE #{role_parent}",
    "CREATE ROLE #{role_child}",
    "GRANT ROLE #{role_parent} TO ROLE #{role_child}"
  ]

  job.wait_until_done!
  puts "Created roles #{role_parent} and #{role_child} and granted privileges"


  job = admin_client.update_database_ddl database: db_path, statements: [
    "REVOKE ROLE #{role_parent} FROM ROLE #{role_child}",
    "DROP ROLE #{role_child}"
  ]

  job.wait_until_done!
  puts "Revoked privileges and dropped role #{role_child}"
end

Weitere Informationen