Configure fine-grained access control

This page explains how to configure fine-grained access control for Spanner for GoogleSQL-dialect databases and PostgreSQL-dialect databases.

To learn about fine-grained access control, see About fine-grained access control .

Configure fine-grained access control by following these steps:

  1. Create database roles and grant privileges .

  2. Optional: Create a hierarchy of roles with inheritance .

  3. Grant database roles to principals .

  4. Inform users and developers to use database roles .

Fine-grained access control users must then specify a database role to perform queries, DML, or row operations against the database.

Before you begin

Ensure that each principal who is to be a fine-grained access control user is granted the Cloud Spanner Viewer IAM role ( roles/spanner.viewer ). This role is recommended at the project level for users who must interact with Spanner resources in the Google Cloud console.

For instructions, see Grant permissions to principals .

Create database roles and grant privileges

A database role is a collection of fine-grained access privileges. You can create up to 100 database roles for each database.

Decide on roles and role hierarchies in your database and encode them in DDL. As with other schema changes in Spanner, we strongly recommend issuing schema changes in a batch rather than separately. For more information, see Limit the frequency of schema updates .

Console

To create a database role and grant fine-grained access privileges to it, follow these steps:

  1. Go to the Instancespage in the Google Cloud console.

    Instances

  2. Select the instance containing the database for which you want to add the role.

  3. Select the database.

  4. On the Overviewpage, click Spanner Studio.

  5. On the Spanner Studiopage, for each database role that you want to create and grant privileges to, follow these steps:

    1. To create the role, enter the following statement:

      CREATE ROLE ROLE_NAME 
      ;

      Don't click Submityet.

    2. To grant privileges to the role, enter a GRANT statement on the next line after the CREATE ROLE statement.

      For syntax details for the GRANT statement, see GoogleSQL data definition language . For information about privileges, see Fine-grained access control privileges .

      For example, to grant SELECT , INSERT , and UPDATE on tables employees and contractors to the database role hr_manager , enter the following statement:

      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 
       ; 
       
      

      You can use a DDL template for the GRANT statement. In the Explorerpane, navigate to the role for which you want to grant privileges. Click View actionsand select the type of privilege you want to grant access to for this role. The GRANT template statement populates in a new editor tab.

  6. Click Submit.

    If there are errors in your DDL, the Google Cloud console returns an error.

gcloud

To create a database role and grant fine-grained access privileges to it, use the gcloud spanner databases ddl update command with CREATE ROLE and GRANT statements.

For syntax details on the CREATE ROLE and GRANT statements, see GoogleSQL data definition language .

For example, use the following command to create a database role and grant privileges to it on one or more tables.

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

Replace the following:

  • PRIVILEGES is a comma-delimited list of fine-grained access control privileges. For information about privileges, see Fine-grained access control privileges .

  • TABLES is a comma-delimited list of tables.

For example, to grant SELECT , INSERT , and UPDATE on the employees and contractors tables to the database role hr_analyst in the database hrdb1 in the instance hr , enter the following statement:

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

Client libraries

These code samples both create and drop a database role.

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 
 

Create a hierarchy of roles with inheritance

You can create a hierarchy of database roles by granting one database role to another. Child roles (known as member roles ) inherit privileges from the parent.

To grant a database role to another database role, use the following statement:

GoogleSQL

  GRANT 
  
 ROLE 
  
 role1 
  
 TO 
  
 ROLE 
  
 role2 
 ; 
 

PostgreSQL

  GRANT 
  
 role1 
  
 TO 
  
 role2 
 ; 
 

For more information, see Database role hierarchies and inheritance .

Grant database roles to principals

To access Spanner resources, a principal must be granted the necessary database role using one of the following options:

Console

  1. On the database Overviewpage, click SHOW INFO PANELif the Info panelis not already open.

  2. Click ADD PRINCIPAL.

  3. Under Add principals, in New principals, enter one or more principals.

  4. Under Assign roles, in Select a role, select Cloud Spanner > Cloud Spanner Fine-grained Access User.

    You need to grant this role only once to each principal. It makes the principal a fine-grained access control user.

  5. Click ADD ANOTHER ROLE.

  6. In Select a role, select Cloud Spanner > Cloud Spanner Database Role User.

  7. Follow these steps to create the IAM condition that specifies the roles to grant.

    1. Next to the Cloud Spanner Database Role User role, click ADD IAM CONDITION.

    2. In the Add conditionpanel, enter a title and optional description for the condition.

      If you're granting a single database role, you typically include the role name in the condition title. If you're granting multiple roles, you can indicate something about the set of roles.

    3. Click Condition editor.

    4. In the Expressionfield, enter the following code:

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

      Replace ROLE with your role name.

      To grant more than one role to the principal, add more conditions with the or( || ) operator, as shown in the following example:

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

      This code grants two roles. Replace ROLE1 and ROLE2 with your role names. To grant more than two roles, add more orconditions.

      You can use any condition expression that's supported by IAM. For more information, see Overview of IAM conditions .

    5. Click Save.

    6. Verify that the condition appears in the IAM Conditioncolumn next to the Rolefield.

    7. Click Save.

      Back on the Info panel, under Role/Principal, notice that Cloud Spanner Database Role Userappears for each defined condition.

      The number in parentheses next to the condition indicates the number of principals who are granted the database role by that condition. You can click the expander arrow to view the list of principals.

    8. To correct errors in database role names or conditions, or to add additional database roles for a principal, follow these steps:

      1. Expand the Cloud Spanner Database Role Userentry that lists the condition that you want.

      2. Click the Edit(pencil) icon next to a principal.

      3. On the Edit access to database_name panel, do one of the following:

        • Click ADD ANOTHER ROLE.

        • To edit the condition, click the Edit(pencil) icon adjacent to the condition name. Then on the Edit conditionpage, click Condition editor, make corrections, and click Savetwice.

gcloud

  1. Enable fine-grained access control for the principal by using the gcloud spanner databases add-iam-policy-binding command as follows:

    gcloud  
    spanner  
    databases  
    add-iam-policy-binding  
     DATABASE_NAME 
      
     \ 
    --instance = 
     INSTANCE_NAME 
      
     \ 
    --role = 
    roles/spanner.fineGrainedAccessUser  
     \ 
    --member = 
     MEMBER_NAME 
      
     \ 
    --condition = 
    None
    • MEMBER_NAME is the identifier for the principal. It must use one of the following syntaxes: user|group|serviceAccount: email or domain: domain .

    • This command makes the principal a fine-grained access control user. Submit this command only once for each principal.

    • If successful, the command outputs the entire policy for the database.

  2. Grant permission to use one or more database roles by using the gcloud spanner databases add-iam-policy-binding command as follows:

    gcloud  
    spanner  
    databases  
    add-iam-policy-binding  
     DATABASE_NAME 
      
     \ 
    --instance = 
     INSTANCE_NAME 
      
     \ 
    --role = 
    roles/spanner.databaseRoleUser  
     \ 
    --member = 
     MEMBER_NAME 
      
     \ 
    --condition = 
     CONDITION 
    
    • MEMBER_NAME is the identifier for the principal. It must use one of the following syntaxes: user|group|serviceAccount: email or domain: domain .

    • CONDITION is an IAM condition expression that specifies the roles to grant to the principal.

      CONDITION has the following form:

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

      Or, to grant access to the principal to more than one role, add more conditions with the or( || ) operator, as shown in the following example:

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

      This code grants two roles. Replace ROLE1 and ROLE2 with your role names. To grant more than two roles, add more orconditions with the || operator.

      You can use any condition expression that's supported by IAM. For more information, see Overview of IAM conditions .

    If successful, the command outputs the entire policy for the database.

    The following example grants the database roles hr_rep and hr_manager to the principal jsmith@example.com .

      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 
     ' 
     
    

Client libraries

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

   
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: