From 4c89d0a93e47895f8b07a382c7c7cc097a892325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Thu, 23 Jan 2025 14:50:12 +0100 Subject: [PATCH 1/6] Add grant ownership examples to the guides --- .../grant_ownership_common_use_cases.md | 259 ++++++++++++++++++ docs/resources/grant_ownership.md | 2 + .../grant_ownership_common_use_cases.md.tmpl | 259 ++++++++++++++++++ templates/resources/grant_ownership.md.tmpl | 2 + 4 files changed, 522 insertions(+) create mode 100644 docs/guides/grant_ownership_common_use_cases.md create mode 100644 templates/guides/grant_ownership_common_use_cases.md.tmpl diff --git a/docs/guides/grant_ownership_common_use_cases.md b/docs/guides/grant_ownership_common_use_cases.md new file mode 100644 index 0000000000..e2efebf3a4 --- /dev/null +++ b/docs/guides/grant_ownership_common_use_cases.md @@ -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 = "" +} + +resource "snowflake_grant_account_role" "grant_team_b_role" { + role_name = snowflake_account_role.team_a.name + user_name = "" +} + +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 ''; +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 + } +} +``` diff --git a/docs/resources/grant_ownership.md b/docs/resources/grant_ownership.md index 56391876f4..0bd26682ed 100644 --- a/docs/resources/grant_ownership.md +++ b/docs/resources/grant_ownership.md @@ -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 diff --git a/templates/guides/grant_ownership_common_use_cases.md.tmpl b/templates/guides/grant_ownership_common_use_cases.md.tmpl new file mode 100644 index 0000000000..e2efebf3a4 --- /dev/null +++ b/templates/guides/grant_ownership_common_use_cases.md.tmpl @@ -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 = "" +} + +resource "snowflake_grant_account_role" "grant_team_b_role" { + role_name = snowflake_account_role.team_a.name + user_name = "" +} + +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 ''; +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 + } +} +``` diff --git a/templates/resources/grant_ownership.md.tmpl b/templates/resources/grant_ownership.md.tmpl index 431aec68a9..5def1a03ab 100644 --- a/templates/resources/grant_ownership.md.tmpl +++ b/templates/resources/grant_ownership.md.tmpl @@ -21,6 +21,8 @@ description: |- {{ if .HasExample -}} ## 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). + {{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} -> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). From 5d33cca65a684439272fb81723230d3765091121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Thu, 23 Jan 2025 15:04:59 +0100 Subject: [PATCH 2/6] Add grant ownership examples to the guides --- .../grant_ownership_common_use_cases.md | 20 ++++++++++--------- .../grant_ownership_common_use_cases.md.tmpl | 20 ++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/guides/grant_ownership_common_use_cases.md b/docs/guides/grant_ownership_common_use_cases.md index e2efebf3a4..86ebbb6bcb 100644 --- a/docs/guides/grant_ownership_common_use_cases.md +++ b/docs/guides/grant_ownership_common_use_cases.md @@ -6,7 +6,7 @@ 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. +This guide 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: @@ -14,13 +14,15 @@ Here's a list of grant ownership common use cases: - [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. +If other problematic cases arise, we will add new examples to this list. + +### Basic RBAC example +Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any +option over the other. It is 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 +#### First deployment This configuration imitates the "main" Terraform deployment that manages the account ```terraform @@ -60,7 +62,7 @@ resource "snowflake_grant_ownership" "grant_team_a_database" { } ``` -##### Second deployment +#### 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. @@ -84,9 +86,9 @@ resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_ } ``` -Then a team using TEAM_B_ROlE can take it from here and create all the tables / views they need. +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) +### 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). @@ -134,7 +136,7 @@ Currently, the least privileged role that is able to transfer ownership has to h 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 +### 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 diff --git a/templates/guides/grant_ownership_common_use_cases.md.tmpl b/templates/guides/grant_ownership_common_use_cases.md.tmpl index e2efebf3a4..86ebbb6bcb 100644 --- a/templates/guides/grant_ownership_common_use_cases.md.tmpl +++ b/templates/guides/grant_ownership_common_use_cases.md.tmpl @@ -6,7 +6,7 @@ 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. +This guide 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: @@ -14,13 +14,15 @@ Here's a list of grant ownership common use cases: - [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. +If other problematic cases arise, we will add new examples to this list. + +### Basic RBAC example +Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any +option over the other. It is 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 +#### First deployment This configuration imitates the "main" Terraform deployment that manages the account ```terraform @@ -60,7 +62,7 @@ resource "snowflake_grant_ownership" "grant_team_a_database" { } ``` -##### Second deployment +#### 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. @@ -84,9 +86,9 @@ resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_ } ``` -Then a team using TEAM_B_ROlE can take it from here and create all the tables / views they need. +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) +### 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). @@ -134,7 +136,7 @@ Currently, the least privileged role that is able to transfer ownership has to h 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 +### 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 From e59a4285e5bde19bf5137da17746793fcf3ed5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Fri, 24 Jan 2025 10:41:54 +0100 Subject: [PATCH 3/6] Add grant ownership examples to the guides --- .../grant_ownership_common_use_cases.md | 45 ++++++++++++++++--- .../grant_ownership_common_use_cases.md.tmpl | 45 ++++++++++++++++--- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/docs/guides/grant_ownership_common_use_cases.md b/docs/guides/grant_ownership_common_use_cases.md index 86ebbb6bcb..18cc85b67c 100644 --- a/docs/guides/grant_ownership_common_use_cases.md +++ b/docs/guides/grant_ownership_common_use_cases.md @@ -14,7 +14,7 @@ Here's a list of grant ownership common use cases: - [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) -If other problematic cases arise, we will add new examples to this list. +If other common problematic cases arise, we will add them to this list. ### Basic RBAC example Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any @@ -23,7 +23,7 @@ Keep in mind that this example uses highly privileged role (ACCOUNTADMIN) and fo 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 +This configuration imitates the "main" Terraform deployment that manages the account objects ```terraform provider "snowflake" { @@ -39,13 +39,15 @@ resource "snowflake_account_role" "team_b" { name = "TEAM_B_ROLE" } +# Make able to use the TEAM_A_ROLE resource "snowflake_grant_account_role" "grant_team_a_role" { role_name = snowflake_account_role.team_a.name user_name = "" } +# Make able to use the TEAM_B_ROLE resource "snowflake_grant_account_role" "grant_team_b_role" { - role_name = snowflake_account_role.team_a.name + role_name = snowflake_account_role.team_b.name user_name = "" } @@ -77,6 +79,23 @@ resource "snowflake_schema" "team_b_schema" { name = "TEAM_B_SCHEMA" } +resource "snowflake_grant_privileges_to_account_role" "grant_access_to_database" { + account_role_name = "TEAM_B_ROLE" + privileges = ["USAGE"] + on_account_object { + object_type = "DATABASE" + object_name = "TEST_DATABASE" + } +} + +resource "snowflake_grant_privileges_to_account_role" "grant_access_to_schema" { + account_role_name = "TEAM_B_ROLE" + privileges = ["USAGE"] + on_schema { + schema_name = snowflake_schema.team_b_schema.fully_qualified_name + } +} + resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_b" { account_role_name = "TEAM_B_ROLE" privileges = ["USAGE", "CREATE TABLE", "CREATE VIEW"] @@ -86,7 +105,17 @@ resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_ } ``` -Then a team using TEAM_B_ROLE can take it from here and create all the tables / views they need. +Then a team using TEAM_B_ROLE can take it from here and create all the tables / views they need (in the worksheet SQL or in any other way). +Just to confirm the above configuration work, you can use the following script: + +```snowflake +USE ROLE TEAM_B_ROLE; +USE DATABASE TEST_DATABASE; +USE SCHEMA TEAM_B_SCHEMA; +CREATE TABLE TEST_TABLE(N INT); +-- Has only privilege to create tables and views, so the following command will fail: +CREATE TASK TEST_TASK SCHEDULE = '60 MINUTES' AS SELECT CURRENT_TIMESTAMP; +``` ### Granting ownership with a less privileged role (granting MANAGED ACCESS) @@ -125,7 +154,7 @@ resource "snowflake_grant_ownership" "grant_ownership_to_another_role" { 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 @@ -251,7 +280,7 @@ resource "snowflake_grant_privileges_to_account_role" "test" { 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" @@ -259,3 +288,7 @@ resource "snowflake_grant_ownership" "test" { } } ``` + +This shows that using ownership transfer (either in provider or only in Snowflake) +requires pre-planning on the overall access architecture and foresight in possible incoming changes. +Otherwise, It may be challenging to introduce certain changes afterward. diff --git a/templates/guides/grant_ownership_common_use_cases.md.tmpl b/templates/guides/grant_ownership_common_use_cases.md.tmpl index 86ebbb6bcb..18cc85b67c 100644 --- a/templates/guides/grant_ownership_common_use_cases.md.tmpl +++ b/templates/guides/grant_ownership_common_use_cases.md.tmpl @@ -14,7 +14,7 @@ Here's a list of grant ownership common use cases: - [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) -If other problematic cases arise, we will add new examples to this list. +If other common problematic cases arise, we will add them to this list. ### Basic RBAC example Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any @@ -23,7 +23,7 @@ Keep in mind that this example uses highly privileged role (ACCOUNTADMIN) and fo 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 +This configuration imitates the "main" Terraform deployment that manages the account objects ```terraform provider "snowflake" { @@ -39,13 +39,15 @@ resource "snowflake_account_role" "team_b" { name = "TEAM_B_ROLE" } +# Make able to use the TEAM_A_ROLE resource "snowflake_grant_account_role" "grant_team_a_role" { role_name = snowflake_account_role.team_a.name user_name = "" } +# Make able to use the TEAM_B_ROLE resource "snowflake_grant_account_role" "grant_team_b_role" { - role_name = snowflake_account_role.team_a.name + role_name = snowflake_account_role.team_b.name user_name = "" } @@ -77,6 +79,23 @@ resource "snowflake_schema" "team_b_schema" { name = "TEAM_B_SCHEMA" } +resource "snowflake_grant_privileges_to_account_role" "grant_access_to_database" { + account_role_name = "TEAM_B_ROLE" + privileges = ["USAGE"] + on_account_object { + object_type = "DATABASE" + object_name = "TEST_DATABASE" + } +} + +resource "snowflake_grant_privileges_to_account_role" "grant_access_to_schema" { + account_role_name = "TEAM_B_ROLE" + privileges = ["USAGE"] + on_schema { + schema_name = snowflake_schema.team_b_schema.fully_qualified_name + } +} + resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_b" { account_role_name = "TEAM_B_ROLE" privileges = ["USAGE", "CREATE TABLE", "CREATE VIEW"] @@ -86,7 +105,17 @@ resource "snowflake_grant_privileges_to_account_role" "grant_privileges_to_team_ } ``` -Then a team using TEAM_B_ROLE can take it from here and create all the tables / views they need. +Then a team using TEAM_B_ROLE can take it from here and create all the tables / views they need (in the worksheet SQL or in any other way). +Just to confirm the above configuration work, you can use the following script: + +```snowflake +USE ROLE TEAM_B_ROLE; +USE DATABASE TEST_DATABASE; +USE SCHEMA TEAM_B_SCHEMA; +CREATE TABLE TEST_TABLE(N INT); +-- Has only privilege to create tables and views, so the following command will fail: +CREATE TASK TEST_TASK SCHEDULE = '60 MINUTES' AS SELECT CURRENT_TIMESTAMP; +``` ### Granting ownership with a less privileged role (granting MANAGED ACCESS) @@ -125,7 +154,7 @@ resource "snowflake_grant_ownership" "grant_ownership_to_another_role" { 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 @@ -251,7 +280,7 @@ resource "snowflake_grant_privileges_to_account_role" "test" { 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" @@ -259,3 +288,7 @@ resource "snowflake_grant_ownership" "test" { } } ``` + +This shows that using ownership transfer (either in provider or only in Snowflake) +requires pre-planning on the overall access architecture and foresight in possible incoming changes. +Otherwise, It may be challenging to introduce certain changes afterward. From 0a9c6cae80505eae1ea47b0c1b4414f5f999b9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Fri, 24 Jan 2025 10:47:19 +0100 Subject: [PATCH 4/6] Add grant ownership examples to the guides --- .../grant_ownership_resource_overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/technical-documentation/grant_ownership_resource_overview.md b/docs/technical-documentation/grant_ownership_resource_overview.md index adfb56bfc4..a65ce7809e 100644 --- a/docs/technical-documentation/grant_ownership_resource_overview.md +++ b/docs/technical-documentation/grant_ownership_resource_overview.md @@ -15,7 +15,7 @@ where granting ownership is crucial and a role-based approach is not feasible. After reviewing these use cases, we decided to offer this resource, but with only essential functionalities to keep it simple while meeting necessary requirements. Over time, we've found it challenging to use, especially when debugging role-based access errors. -Therefore, in the coming week, we will provide examples for common use cases and error handling to help resolve most frustrations that come up when using the grant\_ownership resource. +Because of that, we provided [examples of common use cases and error handling](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/grant_ownership_common_use_cases) to help resolve most frustrations that come up when using the grant\_ownership resource. ## Limitations and workarounds From 6c4a634b58abc97cc3d1dcafb3b4dd500c470bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Thu, 30 Jan 2025 11:24:26 +0100 Subject: [PATCH 5/6] Changes after review --- CREATING_ISSUES.md | 6 + .../grant_ownership_common_use_cases.md | 126 ++++++++++++++++-- docs/resources/grant_ownership.md | 2 +- .../grant_ownership_common_use_cases.md.tmpl | 126 ++++++++++++++++-- templates/resources/grant_ownership.md.tmpl | 2 +- 5 files changed, 236 insertions(+), 26 deletions(-) diff --git a/CREATING_ISSUES.md b/CREATING_ISSUES.md index bf82dcdf64..740e3f56f8 100644 --- a/CREATING_ISSUES.md +++ b/CREATING_ISSUES.md @@ -23,6 +23,7 @@ * [Granting on Functions or Procedures](#granting-on-functions-or-procedures) * [Infinite diffs, empty privileges, errors when revoking on grant resources](#infinite-diffs-empty-privileges-errors-when-revoking-on-grant-resources) * [Granting PUBLIC role fails](#granting-public-role-fails) + * [Issues with grant_ownership resource](#issues-with-grant_ownership) This guide was made to aid with creating the GitHub issues, so you can maximize your chances of getting help as quickly as possible. To correctly report the issue, we suggest going through the following steps. @@ -276,3 +277,8 @@ Terraform may fail with: **Related issues:** [#3001](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/3001), [#2848](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2848) **Solution:** This happens, because the PUBLIC role is a "pseudo-role" (see [docs](https://docs.snowflake.com/en/user-guide/security-access-control-overview#system-defined-roles)) that is already assigned to every role and user, so there is no need to grant it through Terraform. If you have an issue with removing the resources please use `terraform state rm ` to remove the resource from the state (and you can safely remove the configuration). + +### Issues with grant_ownership + +Please read our [guide for grant_ownership](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/grant_ownership_common_use_cases) resource. +It contains common use cases and issues that you may encounter when dealing with ownership transfers. \ No newline at end of file diff --git a/docs/guides/grant_ownership_common_use_cases.md b/docs/guides/grant_ownership_common_use_cases.md index 18cc85b67c..b042f0aec5 100644 --- a/docs/guides/grant_ownership_common_use_cases.md +++ b/docs/guides/grant_ownership_common_use_cases.md @@ -6,19 +6,23 @@ description: |- --- # Grant ownership - common use cases -This guide 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. +This guide is a follow-up for the [grant_ownership resource overview](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/b863d2e79ae6ae021552c4348e3012b8053ede17/docs/technical-documentation/resource_migration.md) document. +These examples should guide you through Snowflake role management in Terraform with the use of grant_ownership resource. 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) +- [Fixing the state after using a less privileged role in grant_ownership resource](#fixing-the-state-after-using-a-less-privileged-role-in-grant_ownership-resource) -If other common problematic cases arise, we will add them to this list. +This list may be further extended with more cases; please approach us through [GitHub issue](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/new?template=03-documentation.yml) +if you would like to see any others or contribute ([contribution guidelines](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/b863d2e79ae6ae021552c4348e3012b8053ede17/CONTRIBUTING.md)). ### Basic RBAC example Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any option over the other. It is only supposed to show, more or less, how the grant_ownership could be used in such a scenario. +The approach is depending on the use case and should be first consulted with a Snowflake Account Manager before creating any role-based system right away. + 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. @@ -119,7 +123,7 @@ CREATE TASK TEST_TASK SCHEDULE = '60 MINUTES' AS SELECT CURRENT_TIMESTAMP; ### 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. +This example shows how a less privileged role 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: @@ -155,8 +159,10 @@ 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 +Once the ownership is taken away, you still must be able to take the ownership back to the original role, so that the Terraform is able to perform successful delete operation once the resource is removed from the configuration. +If you used a less privileged role to grant ownership, [here's an example](#fixing-the-state-after-using-a-less-privileged-role-in-grant_ownership-resource) of how the errors may look like and how to fix them. + 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. @@ -168,7 +174,10 @@ However, other assumptions would be imposed, e.g., that the current user is gran ### 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 +This doesn't play well with Terraform ideology that the resource "owns" its part on the infrastructure +and should be able to make changes on that object to eventually match the configuration with the state on the Snowflake side. +By limiting privileges for that resource to make changes on the Snowflake side, you may encounter strange errors related to limited access. +You can commonly encounter this when there will be a need for updating an 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: @@ -215,15 +224,15 @@ With the current setup, you will encounter the following error (or similar one): ``` 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. +To let the current role modify the database it doesn't own you possibly have a few choices. +1. One of the possible options is to grant the currently used role with necessary privilege (we chose this one in the examples below). +2. 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. +Currently, using less privileged roles (minimum is having MANAGE GRANTS privilege) is not possible. +It will be available once more functionalities are added to the resource. 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. @@ -292,3 +301,96 @@ resource "snowflake_grant_ownership" "test" { This shows that using ownership transfer (either in provider or only in Snowflake) requires pre-planning on the overall access architecture and foresight in possible incoming changes. Otherwise, It may be challenging to introduce certain changes afterward. + +### Fixing the state after using a less privileged role in grant_ownership resource + +Here's a short example showing how this could look like. Firstly, let's prepare a few objects on the Snowflake side: + +```snowflake +CREATE ROLE CREATE_DATABASES_ROLE; +CREATE ROLE ANOTHER_ROLE; +GRANT CREATE DATABASE ON ACCOUNT TO ROLE CREATE_DATABASES_ROLE; +GRANT ROLE CREATE_DATABASES_ROLE TO USER ""; +``` + +then run the following configuration: + +```terraform +provider "snowflake" { + role = "CREATE_DATABASES_ROLE" +} + +resource "snowflake_database" "test" { + name = "TEST_DATABASE_NAME" +} + +resource "snowflake_grant_ownership" "transfer_ownership" { + account_role_name = "ANOTHER_ROLE" + on { + object_type = "DATABASE" + object_name = snowflake_database.test.name + } +} +``` + +After the first apply the provider will raise a warning and an error: +```text +╷ +│ Warning: Failed to retrieve grants. Marking the resource as removed. +│ +│ with snowflake_grant_ownership.transfer_ownership, +│ on main.tf line 18, in resource "snowflake_grant_ownership" "transfer_ownership": +│ 18: resource "snowflake_grant_ownership" "transfer_ownership" { +│ +│ Id: +│ Error: [errors.go:22] object does not exist or not authorized +╵ +╷ +│ Error: Provider produced inconsistent result after apply +│ +│ When applying changes to snowflake_grant_ownership.transfer_ownership, provider +│ "provider[\"registry.terraform.io/snowflake-labs/snowflake\"]" produced an unexpected new value: Root object was present, but now absent. +│ +│ This is a bug in the provider, which should be reported in the provider's own issue tracker. +╵ +``` + +What happened is after ownership transfers, the current role lost the ability to confirm that the ownership is granted to the correct role. +Because of that, the grant_ownership resource produces inconsistent results and database resource removed itself from the state because +from its perspective the database wasn't created (it couldn't find the database by calling SHOW DATABASES). + +To fix this issue, you have to firstly grant the ownership back to the original role. You have to do this from a role +that has at least MANAGE GRANTS privilege (e.g. ACCOUNTADMIN or a custom role with this privilege). + +```snowflake +GRANT OWNERSHIP ON DATABASE TEST_DATABASE_NAME TO ROLE CREATE_DATABASES_ROLE; +``` + +then you have to adjust the configuration, so the ownership is commented out (or completely removed), and import the database resource. + +```shell +terraform import snowflake_database.test '"TEST_DATABASE_NAME"' +``` + +At this point, your configuration should look similar to this: + +```terraform +provider "snowflake" { + role = "CREATE_DATABASES_ROLE" +} + +resource "snowflake_database" "test" { + name = "TEST_DATABASE_NAME" +} + +# resource "snowflake_grant_ownership" "transfer_ownership" { +# account_role_name = "ANOTHER_ROLE" +# on { +# object_type = "DATABASE" +# object_name = snowflake_database.test.name +# } +# } +``` + +After running `terraform plan` you should see no changes planned from the provider side, +and you can start over from this point to grant ownership again, but now apply it using one of the provided examples. diff --git a/docs/resources/grant_ownership.md b/docs/resources/grant_ownership.md index 0bd26682ed..a6b0807353 100644 --- a/docs/resources/grant_ownership.md +++ b/docs/resources/grant_ownership.md @@ -16,7 +16,7 @@ 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). +For more examples, head over to our usage guide where we present how to use the grant_ownership resource in [common use cases](../guides/grant_ownership_common_use_cases). ```terraform ################################## diff --git a/templates/guides/grant_ownership_common_use_cases.md.tmpl b/templates/guides/grant_ownership_common_use_cases.md.tmpl index 18cc85b67c..b042f0aec5 100644 --- a/templates/guides/grant_ownership_common_use_cases.md.tmpl +++ b/templates/guides/grant_ownership_common_use_cases.md.tmpl @@ -6,19 +6,23 @@ description: |- --- # Grant ownership - common use cases -This guide 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. +This guide is a follow-up for the [grant_ownership resource overview](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/b863d2e79ae6ae021552c4348e3012b8053ede17/docs/technical-documentation/resource_migration.md) document. +These examples should guide you through Snowflake role management in Terraform with the use of grant_ownership resource. 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) +- [Fixing the state after using a less privileged role in grant_ownership resource](#fixing-the-state-after-using-a-less-privileged-role-in-grant_ownership-resource) -If other common problematic cases arise, we will add them to this list. +This list may be further extended with more cases; please approach us through [GitHub issue](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/new?template=03-documentation.yml) +if you would like to see any others or contribute ([contribution guidelines](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/b863d2e79ae6ae021552c4348e3012b8053ede17/CONTRIBUTING.md)). ### Basic RBAC example Here's an easy example of using RBAC (Role-based Access Control). Of course, there are many ways to perform RBAC, and here, we are not proposing any option over the other. It is only supposed to show, more or less, how the grant_ownership could be used in such a scenario. +The approach is depending on the use case and should be first consulted with a Snowflake Account Manager before creating any role-based system right away. + 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. @@ -119,7 +123,7 @@ CREATE TASK TEST_TASK SCHEDULE = '60 MINUTES' AS SELECT CURRENT_TIMESTAMP; ### 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. +This example shows how a less privileged role 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: @@ -155,8 +159,10 @@ 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 +Once the ownership is taken away, you still must be able to take the ownership back to the original role, so that the Terraform is able to perform successful delete operation once the resource is removed from the configuration. +If you used a less privileged role to grant ownership, [here's an example](#fixing-the-state-after-using-a-less-privileged-role-in-grant_ownership-resource) of how the errors may look like and how to fix them. + 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. @@ -168,7 +174,10 @@ However, other assumptions would be imposed, e.g., that the current user is gran ### 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 +This doesn't play well with Terraform ideology that the resource "owns" its part on the infrastructure +and should be able to make changes on that object to eventually match the configuration with the state on the Snowflake side. +By limiting privileges for that resource to make changes on the Snowflake side, you may encounter strange errors related to limited access. +You can commonly encounter this when there will be a need for updating an 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: @@ -215,15 +224,15 @@ With the current setup, you will encounter the following error (or similar one): ``` 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. +To let the current role modify the database it doesn't own you possibly have a few choices. +1. One of the possible options is to grant the currently used role with necessary privilege (we chose this one in the examples below). +2. 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. +Currently, using less privileged roles (minimum is having MANAGE GRANTS privilege) is not possible. +It will be available once more functionalities are added to the resource. 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. @@ -292,3 +301,96 @@ resource "snowflake_grant_ownership" "test" { This shows that using ownership transfer (either in provider or only in Snowflake) requires pre-planning on the overall access architecture and foresight in possible incoming changes. Otherwise, It may be challenging to introduce certain changes afterward. + +### Fixing the state after using a less privileged role in grant_ownership resource + +Here's a short example showing how this could look like. Firstly, let's prepare a few objects on the Snowflake side: + +```snowflake +CREATE ROLE CREATE_DATABASES_ROLE; +CREATE ROLE ANOTHER_ROLE; +GRANT CREATE DATABASE ON ACCOUNT TO ROLE CREATE_DATABASES_ROLE; +GRANT ROLE CREATE_DATABASES_ROLE TO USER ""; +``` + +then run the following configuration: + +```terraform +provider "snowflake" { + role = "CREATE_DATABASES_ROLE" +} + +resource "snowflake_database" "test" { + name = "TEST_DATABASE_NAME" +} + +resource "snowflake_grant_ownership" "transfer_ownership" { + account_role_name = "ANOTHER_ROLE" + on { + object_type = "DATABASE" + object_name = snowflake_database.test.name + } +} +``` + +After the first apply the provider will raise a warning and an error: +```text +╷ +│ Warning: Failed to retrieve grants. Marking the resource as removed. +│ +│ with snowflake_grant_ownership.transfer_ownership, +│ on main.tf line 18, in resource "snowflake_grant_ownership" "transfer_ownership": +│ 18: resource "snowflake_grant_ownership" "transfer_ownership" { +│ +│ Id: +│ Error: [errors.go:22] object does not exist or not authorized +╵ +╷ +│ Error: Provider produced inconsistent result after apply +│ +│ When applying changes to snowflake_grant_ownership.transfer_ownership, provider +│ "provider[\"registry.terraform.io/snowflake-labs/snowflake\"]" produced an unexpected new value: Root object was present, but now absent. +│ +│ This is a bug in the provider, which should be reported in the provider's own issue tracker. +╵ +``` + +What happened is after ownership transfers, the current role lost the ability to confirm that the ownership is granted to the correct role. +Because of that, the grant_ownership resource produces inconsistent results and database resource removed itself from the state because +from its perspective the database wasn't created (it couldn't find the database by calling SHOW DATABASES). + +To fix this issue, you have to firstly grant the ownership back to the original role. You have to do this from a role +that has at least MANAGE GRANTS privilege (e.g. ACCOUNTADMIN or a custom role with this privilege). + +```snowflake +GRANT OWNERSHIP ON DATABASE TEST_DATABASE_NAME TO ROLE CREATE_DATABASES_ROLE; +``` + +then you have to adjust the configuration, so the ownership is commented out (or completely removed), and import the database resource. + +```shell +terraform import snowflake_database.test '"TEST_DATABASE_NAME"' +``` + +At this point, your configuration should look similar to this: + +```terraform +provider "snowflake" { + role = "CREATE_DATABASES_ROLE" +} + +resource "snowflake_database" "test" { + name = "TEST_DATABASE_NAME" +} + +# resource "snowflake_grant_ownership" "transfer_ownership" { +# account_role_name = "ANOTHER_ROLE" +# on { +# object_type = "DATABASE" +# object_name = snowflake_database.test.name +# } +# } +``` + +After running `terraform plan` you should see no changes planned from the provider side, +and you can start over from this point to grant ownership again, but now apply it using one of the provided examples. diff --git a/templates/resources/grant_ownership.md.tmpl b/templates/resources/grant_ownership.md.tmpl index 5cdd787dbb..df270a1d7c 100644 --- a/templates/resources/grant_ownership.md.tmpl +++ b/templates/resources/grant_ownership.md.tmpl @@ -21,7 +21,7 @@ description: |- {{ if .HasExample -}} ## 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). +For more examples, head over to our usage guide where we present how to use the grant_ownership resource in [common use cases](../guides/grant_ownership_common_use_cases). {{ tffile .ExampleFile }} -> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). From 4d550a56128fd26120b33a031d71fe9b669be55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Thu, 30 Jan 2025 16:06:02 +0100 Subject: [PATCH 6/6] Add quoted identifiers ignore case parameter common issue --- CREATING_ISSUES.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CREATING_ISSUES.md b/CREATING_ISSUES.md index 740e3f56f8..b0da7e2732 100644 --- a/CREATING_ISSUES.md +++ b/CREATING_ISSUES.md @@ -24,6 +24,7 @@ * [Infinite diffs, empty privileges, errors when revoking on grant resources](#infinite-diffs-empty-privileges-errors-when-revoking-on-grant-resources) * [Granting PUBLIC role fails](#granting-public-role-fails) * [Issues with grant_ownership resource](#issues-with-grant_ownership) + * [Using QUOTED_IDENTIFIERS_IGNORE_CASE with the provider](#using-quoted_identifiers_ignore_case-with-the-provider) This guide was made to aid with creating the GitHub issues, so you can maximize your chances of getting help as quickly as possible. To correctly report the issue, we suggest going through the following steps. @@ -281,4 +282,13 @@ Terraform may fail with: ### Issues with grant_ownership Please read our [guide for grant_ownership](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/grant_ownership_common_use_cases) resource. -It contains common use cases and issues that you may encounter when dealing with ownership transfers. \ No newline at end of file +It contains common use cases and issues that you may encounter when dealing with ownership transfers. + +### Using QUOTED_IDENTIFIERS_IGNORE_CASE with the provider + +**Problem:** When `QUOTED_IDENTIFIERS_IGNORE_CASE` parameter is set to true, but resource identifier fields are filled with lowercase letters, +during `terrform apply` they may fail with the `Error: Provider produced inconsistent result after apply` error (removing themselves from the state in the meantime). + +**Related issues:** [#2967](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2967) + +**Solution:** Either turn off the parameter or adjust your configurations to use only upper-cased names for identifiers and import back the resources.