Skip to content

Commit

Permalink
Add grant ownership examples to the guides
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-jcieslak committed Jan 23, 2025
1 parent 1642c15 commit 4c89d0a
Show file tree
Hide file tree
Showing 4 changed files with 522 additions and 0 deletions.
259 changes: 259 additions & 0 deletions docs/guides/grant_ownership_common_use_cases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
---
page_title: "Grant ownership - common use cases"
subcategory: ""
description: |-
---
# Grant ownership - common use cases

That is a follow-up for the [grant_ownership resource overview](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/grant_ownership_resource_overview.md) document.
Those examples should help you to work with difficulties imposed by Snowflake role management and Terraform.
Here's a list of grant ownership common use cases:

- [Basic RBAC example](#basic-rbac-example)
- [Granting ownership with a less privileged role (granting MANAGED ACCESS)](#granting-ownership-with-a-less-privileged-role-granting-managed-access)
- [Modifying objects you don't own after transferring the ownership](#modifying-objects-you-dont-own-after-transferring-the-ownership)

#### Basic RBAC example
Here's an easy example of using RBAC. Of course, there are many ways to perform RBAC, and here, we are not proposing any
option over the other. It only supposed to show, more or less, how the grant_ownership could be used in such a scenario.
Keep in mind that this example uses highly privileged role (ACCOUNTADMIN) and for lower privileges roles, you should look into
other examples to see what else is needed to perform the same actions.

##### First deployment
This configuration imitates the "main" Terraform deployment that manages the account

```terraform
provider "snowflake" {
role = "ACCOUNTADMIN"
# ...
}
resource "snowflake_account_role" "team_a" {
name = "TEAM_A_ROLE"
}
resource "snowflake_account_role" "team_b" {
name = "TEAM_B_ROLE"
}
resource "snowflake_grant_account_role" "grant_team_a_role" {
role_name = snowflake_account_role.team_a.name
user_name = "<team_a_user>"
}
resource "snowflake_grant_account_role" "grant_team_b_role" {
role_name = snowflake_account_role.team_a.name
user_name = "<team_b_user>"
}
resource "snowflake_database" "team_a_database" {
name = "TEST_DATABASE"
}
resource "snowflake_grant_ownership" "grant_team_a_database" {
account_role_name = snowflake_account_role.team_a.name
on {
object_type = "DATABASE"
object_name = snowflake_database.team_a_database.name
}
}
```

##### Second deployment
If the second deployment uses different user, then the TEST_A_ROLE should be granted to that user in the first deployment first.
By using our ownership of the TEST_DATABASE, we can manage its further access to other teams.

```terraform
provider "snowflake" {
role = "TEAM_A_ROLE"
# ...
}
resource "snowflake_schema" "team_b_schema" {
database = "TEST_DATABASE"
name = "TEAM_B_SCHEMA"
}
resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_b" {
account_role_name = "TEAM_B_ROLE"
privileges = ["USAGE", "CREATE TABLE", "CREATE VIEW"]
on_schema {
schema_name = snowflake_schema.team_b_schema.fully_qualified_name
}
}
```

Then a team using TEAM_B_ROlE can take it from here and create all the tables / views they need.

#### Granting ownership with a less privileged role (granting MANAGED ACCESS)

This example shows how less privileged can be used to transfer ownership of the objects they currently own.
Read more in the [official Snowflake documentation](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege#access-control-requirements).
For this setup, the necessary objects were created by running:

```snowflake
USE ROLE ACCOUNTADMIN;
CREATE ROLE LESS_PRIVILEGED_ROLE;
CREATE ROLE ANOTHER_LESS_PRIVILEGED_ROLE;
GRANT ROLE LESS_PRIVILEGED_ROLE TO USER '<your_terraform_user>';
GRANT CREATE DATABASE, MANAGE GRANTS ON ACCOUNT TO ROLE LESS_PRIVILEGED_ROLE;
```

and after the initial, setup the following configuration can be tested:

```terraform
provider "snowflake" {
role = "LESS_PRIVILEGED_ROLE"
}
resource "snowflake_database" "test_database" {
name = "TEST_DATABASE"
}
resource "snowflake_grant_ownership" "grant_ownership_to_another_role" {
account_role_name = "ANOTHER_LESS_PRIVILEGED_ROLE"
on {
object_type = "DATABASE"
object_name = snowflake_database.test_database.name
}
}
```

The ownership transfer is possible because here you have both:
- Ownership of the created above database.
- MANAGE GRANTS privilege on the currently used role.

Once the ownership is taken away, you still must be able to take the ownership away, so that
the Terraform is able to perform successful delete operation once the resource is removed from the configuration.
That being said, granting ownership would be still possible without MANAGE GRANTS, but you wouldn't be able to grant
the ownership back to the original role. This is a common mistake when dealing with ownership transfers. With Terraform, you have to think
about ownership when it's taken away from the current role, and what will happen when you would like to take it back.

Currently, the least privileged role that is able to transfer ownership has to have at least MANAGE GRANTS privilege.
In the future, we are planning to support other mechanisms that would allow you to use roles without MANAGE GRANTS.
However, other assumptions would be imposed, e.g., that the current user is granted to the role it transfers the ownership to.

#### Modifying objects you don't own after transferring the ownership

By transferring ownership of an object to another role, you are limiting currently used role's access control on this object.
This can lead to another common error of updating object after its ownership was transferred to another role. Note that
every object has its access requirements and privileges needed to perform certain actions could be different in your case.
The example was also done on ACCOUNTADMIN role, which means depending on the use case; additional privileges could be necessary for a given action to run successfully.
Imagine you have the following configuration, and you want to change the comment parameter of the database:

```terraform
provider "snowflake" {
role = "ACCOUNTADMIN"
}
resource "snowflake_database" "test" {
name = "test_database"
}
resource "snowflake_account_role" "test" {
name = "test_role"
}
resource "snowflake_grant_ownership" "test" {
account_role_name = snowflake_account_role.test.name
on {
object_type = "DATABASE"
object_name = snowflake_database.test.name
}
}
```

Then, some day you would like to change the comment property of the database like so:

```terraform
# ...
resource "snowflake_database" "test" {
name = "test_database"
comment = "new comment"
}
# ...
```

With the current setup, you will encounter the following error (or similar one):
```text
│ Error: 003001 (42501): SQL access control error:
│ Insufficient privileges to operate on database 'test_database'
```

This happened, because now, you don't own this database, and your current role cannot perform any actions on it.
To let the current role modify the database it doesn't own you possibly have a few choices. One of the possible options
is to grant the currently used role with necessary privilege (we chose this one in the examples below).
Another one could be to create a hierarchy of roles that would possibly allow you to possess certain privileges to the database.
There are possibly more paths that lead to the same place, but to keep it simple, we focus on less extreme cases.

Also, keep in mind that the currently used role has MANAGE GRANTS privilege which makes it easier.
For less privileged roles, your options are very limited, and it would be easier to grant ownership back for a second,
perform the necessary action and grant the ownership back. For a less invasive approach, you could perform grants manually and import
the necessary resources into your configuration.

Going back to the example, firstly, you have to revert the database change and grant the correct privilege (MODIFY) to be able to set the comment on the database.

```terraform
# ...
resource "snowflake_database" "test" {
name = "test_database"
# comment = "new comment"
}
resource "snowflake_grant_privileges_to_account_role" "test" {
account_role_name = "ACCOUNTADMIN"
privileges = [ "MODIFY" ]
on_account_object {
object_type = "DATABASE"
object_name = snowflake_database.test.name
}
}
resource "snowflake_grant_ownership" "test" {
depends_on = [ snowflake_grant_privileges_to_account_role.test ]
# ...
}
# ...
```

After that, you should be able to set the comment of your database, here's how the complete configuration should look like:

```terraform
provider "snowflake" {
role = "ACCOUNTADMIN"
}
resource "snowflake_database" "test" {
name = "test_database"
comment = "new comment"
}
resource "snowflake_account_role" "test" {
name = "test_role"
}
resource "snowflake_grant_privileges_to_account_role" "test" {
account_role_name = "ACCOUNTADMIN"
privileges = [ "MODIFY" ]
on_account_object {
object_type = "DATABASE"
object_name = snowflake_database.test.name
}
}
resource "snowflake_grant_ownership" "test" {
depends_on = [ snowflake_grant_privileges_to_account_role.test ]
account_role_name = snowflake_account_role.test.name
on {
object_type = "DATABASE"
object_name = snowflake_database.test.name
}
}
```
2 changes: 2 additions & 0 deletions docs/resources/grant_ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ description: |-

## Example Usage

For more examples, head over to our usage guide where we present how to use the grant_ownership resource in [common use cases](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/grant_ownership_common_use_cases).

```terraform
##################################
### on object to account role
Expand Down
Loading

0 comments on commit 4c89d0a

Please sign in to comment.