Skip to content

Commit aa5a810

Browse files
authored
feat: Add transformer role and some chore actions (#4)
1 parent 621646a commit aa5a810

File tree

4 files changed

+70
-31
lines changed

4 files changed

+70
-31
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ Terraform module for Snowflake database management.
1717
* Creates Snowflake database
1818
* Can create custom Snowflake roles with role-to-role, role-to-user assignments
1919
* Can create a set of default roles to simplify access management:
20-
* `READONLY` - granted
21-
* `ADMIN` - Full access, including database options like `data_retention_time_in_days`
20+
* `READONLY` - granted `USAGE` privilege on the database
21+
* `TRANSFORMER` - allows creating schemas and some Snowflake objects in them
22+
* `ADMIN` - full access, including database options like `data_retention_time_in_days`
2223
* Can create number of schemas in the database with their specific access roles
2324

2425
## USAGE
@@ -73,8 +74,8 @@ module "snowflake_database" {
7374
| <a name="input_name"></a> [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.<br>This is the only ID element not also included as a `tag`.<br>The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no |
7475
| <a name="input_namespace"></a> [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |
7576
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.<br>Characters matching the regex will be removed from the ID elements.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
76-
| <a name="input_roles"></a> [roles](#input\_roles) | Roles created in the database scope | <pre>map(object({<br> enabled = optional(bool, true)<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> database_grants = optional(list(string))<br> schema_grants = optional(list(string))<br> }))</pre> | `{}` | no |
77-
| <a name="input_schemas"></a> [schemas](#input\_schemas) | Schemas to be created in the database | <pre>map(object({<br> descriptor_name = optional(string, "snowflake-schema")<br> comment = optional(string)<br> data_retention_days = optional(number, 1)<br> is_transient = optional(bool, false)<br> is_managed = optional(bool, false)<br> stages = optional(map(object({<br> enabled = optional(bool, true)<br> descriptor_name = optional(string, "snowflake-stage")<br> aws_external_id = optional(string)<br> comment = optional(string)<br> copy_options = optional(string)<br> credentials = optional(string)<br> directory = optional(string)<br> encryption = optional(string)<br> file_format = optional(string)<br> snowflake_iam_user = optional(string)<br> storage_integration = optional(string)<br> url = optional(string)<br> create_default_roles = optional(bool)<br> roles = optional(map(object({<br> enabled = optional(bool, true)<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> stage_grants = optional(list(string))<br> })), {})<br> })), {})<br> create_default_roles = optional(bool)<br> roles = optional(map(object({<br> enabled = optional(bool, true)<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> schema_grants = optional(list(string))<br> table_grants = optional(list(string))<br> external_table_grants = optional(list(string))<br> view_grants = optional(list(string))<br> materialized_view_grants = optional(list(string))<br> file_format_grants = optional(list(string))<br> function_grants = optional(list(string))<br> stage_grants = optional(list(string))<br> task_grants = optional(list(string))<br> procedure_grants = optional(list(string))<br> sequence_grants = optional(list(string))<br> stream_grants = optional(list(string))<br> })), {})<br> }))</pre> | `{}` | no |
77+
| <a name="input_roles"></a> [roles](#input\_roles) | Roles created in the database scope | <pre>map(object({<br> enabled = optional(bool, true)<br> descriptor_name = optional(string, "snowflake-role")<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> database_grants = optional(list(string))<br> schema_grants = optional(list(string))<br> }))</pre> | `{}` | no |
78+
| <a name="input_schemas"></a> [schemas](#input\_schemas) | Schemas to be created in the database | <pre>map(object({<br> enabled = optional(bool, true)<br> skip_schema_creation = optional(bool, false)<br> descriptor_name = optional(string, "snowflake-schema")<br> comment = optional(string)<br> data_retention_days = optional(number, 1)<br> is_transient = optional(bool, false)<br> is_managed = optional(bool, false)<br> stages = optional(map(object({<br> enabled = optional(bool, true)<br> descriptor_name = optional(string, "snowflake-stage")<br> aws_external_id = optional(string)<br> comment = optional(string)<br> copy_options = optional(string)<br> credentials = optional(string)<br> directory = optional(string)<br> encryption = optional(string)<br> file_format = optional(string)<br> snowflake_iam_user = optional(string)<br> storage_integration = optional(string)<br> url = optional(string)<br> create_default_roles = optional(bool)<br> roles = optional(map(object({<br> enabled = optional(bool, true)<br> descriptor_name = optional(string, "snowflake-role")<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> stage_grants = optional(list(string))<br> })), {})<br> })), {})<br> create_default_roles = optional(bool)<br> roles = optional(map(object({<br> enabled = optional(bool, true)<br> descriptor_name = optional(string, "snowflake-role")<br> comment = optional(string)<br> role_ownership_grant = optional(string)<br> granted_roles = optional(list(string))<br> granted_to_roles = optional(list(string))<br> granted_to_users = optional(list(string))<br> schema_grants = optional(list(string))<br> table_grants = optional(list(string))<br> external_table_grants = optional(list(string))<br> view_grants = optional(list(string))<br> materialized_view_grants = optional(list(string))<br> file_format_grants = optional(list(string))<br> function_grants = optional(list(string))<br> stage_grants = optional(list(string))<br> task_grants = optional(list(string))<br> procedure_grants = optional(list(string))<br> sequence_grants = optional(list(string))<br> stream_grants = optional(list(string))<br> })), {})<br> }))</pre> | `{}` | no |
7879
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
7980
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
8081
| <a name="input_tenant"></a> [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no |
@@ -87,7 +88,7 @@ module "snowflake_database" {
8788
| <a name="module_roles_deep_merge"></a> [roles\_deep\_merge](#module\_roles\_deep\_merge) | Invicton-Labs/deepmerge/null | 0.1.5 |
8889
| <a name="module_snowflake_custom_role"></a> [snowflake\_custom\_role](#module\_snowflake\_custom\_role) | getindata/role/snowflake | 1.0.3 |
8990
| <a name="module_snowflake_default_role"></a> [snowflake\_default\_role](#module\_snowflake\_default\_role) | getindata/role/snowflake | 1.0.3 |
90-
| <a name="module_snowflake_schema"></a> [snowflake\_schema](#module\_snowflake\_schema) | getindata/schema/snowflake | 1.1.0 |
91+
| <a name="module_snowflake_schema"></a> [snowflake\_schema](#module\_snowflake\_schema) | getindata/schema/snowflake | 1.3.0 |
9192
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.25.0 |
9293

9394
## Outputs

locals.tf

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,53 @@ locals {
55
lookup(module.database_label.descriptors, var.descriptor_name, module.database_label.id), "/${module.database_label.delimiter}${module.database_label.delimiter}+/", module.database_label.delimiter
66
), module.database_label.delimiter) : null
77

8+
enabled = module.this.enabled
89
create_default_roles = module.this.enabled && var.create_default_roles
910

11+
#This needs to be the same as an object in roles variable
12+
role_template = {
13+
enabled = true
14+
descriptor_name = "snowflake-role"
15+
comment = null
16+
role_ownership_grant = "SYSADMIN"
17+
granted_roles = []
18+
granted_to_roles = []
19+
granted_to_users = []
20+
database_grants = []
21+
schema_grants = []
22+
}
1023
default_roles_definition = {
1124
readonly = {
1225
database_grants = ["USAGE", "MONITOR"]
26+
database_grants = ["USAGE"]
27+
}
28+
transformer = {
29+
database_grants = ["USAGE", "MONITOR", "CREATE SCHEMA"]
30+
schema_grants = ["USAGE", "CREATE TEMPORARY TABLE", "CREATE TAG", "CREATE PIPE", "CREATE PROCEDURE", "CREATE MATERIALIZED VIEW", "CREATE TABLE", "CREATE FILE FORMAT", "CREATE STAGE", "CREATE TASK", "CREATE FUNCTION", "CREATE EXTERNAL TABLE", "CREATE SEQUENCE", "CREATE VIEW", "CREATE STREAM"]
1331
}
1432
admin = {
15-
database_grants = ["USAGE", "MONITOR", "MODIFY", "OWNERSHIP", "REFERENCE_USAGE", "CREATE SCHEMA"]
16-
schema_grants = ["MONITOR", "CREATE TEMPORARY TABLE", "CREATE TAG", "CREATE PIPE", "CREATE PROCEDURE", "CREATE MATERIALIZED VIEW", "CREATE ROW ACCESS POLICY", "USAGE", "CREATE TABLE", "CREATE FILE FORMAT", "CREATE STAGE", "CREATE TASK", "CREATE FUNCTION", "CREATE EXTERNAL TABLE", "ADD SEARCH OPTIMIZATION", "MODIFY", "OWNERSHIP", "CREATE SEQUENCE", "CREATE MASKING POLICY", "CREATE VIEW", "CREATE STREAM"]
33+
database_grants = ["USAGE", "MONITOR", "MODIFY", "REFERENCE_USAGE", "CREATE SCHEMA"]
34+
schema_grants = ["USAGE", "MONITOR", "MODIFY", "CREATE TEMPORARY TABLE", "CREATE TAG", "CREATE PIPE", "CREATE PROCEDURE", "CREATE MATERIALIZED VIEW", "CREATE ROW ACCESS POLICY", "CREATE TABLE", "CREATE FILE FORMAT", "CREATE STAGE", "CREATE TASK", "CREATE FUNCTION", "CREATE EXTERNAL TABLE", "ADD SEARCH OPTIMIZATION", "CREATE SEQUENCE", "CREATE MASKING POLICY", "CREATE VIEW", "CREATE STREAM"]
1735
}
1836
}
1937

2038
provided_roles = { for role_name, role in var.roles : role_name => {
2139
for k, v in role : k => v
2240
if v != null
2341
} }
24-
roles_definition = module.roles_deep_merge.merged
42+
43+
roles_definition = {
44+
for role_name, role in module.roles_deep_merge.merged : role_name => merge(
45+
local.role_template,
46+
role
47+
)
48+
}
2549

2650
default_roles = {
2751
for role_name, role in local.roles_definition : role_name => role
2852
if contains(keys(local.default_roles_definition), role_name)
2953
}
54+
3055
custom_roles = {
3156
for role_name, role in local.roles_definition : role_name => role
3257
if !contains(keys(local.default_roles_definition), role_name)
@@ -39,6 +64,8 @@ locals {
3964
) : role_name => role
4065
if role.name != null
4166
}
67+
68+
schemas = var.schemas
4269
}
4370

4471
module "roles_deep_merge" {

main.tf

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,49 +27,55 @@ module "snowflake_default_role" {
2727

2828
source = "getindata/role/snowflake"
2929
version = "1.0.3"
30-
context = module.this.context
31-
enabled = local.create_default_roles && lookup(each.value, "enabled", true)
30+
31+
context = module.this.context
32+
enabled = local.create_default_roles && each.value.enabled
33+
descriptor_name = each.value.descriptor_name
3234

3335
name = each.key
3436
attributes = [one(snowflake_database.this[*].name)]
3537

36-
role_ownership_grant = lookup(each.value, "role_ownership_grant", "SYSADMIN")
37-
granted_to_users = lookup(each.value, "granted_to_users", [])
38-
granted_to_roles = lookup(each.value, "granted_to_roles", [])
39-
granted_roles = lookup(each.value, "granted_roles", [])
38+
role_ownership_grant = each.value.role_ownership_grant
39+
granted_to_users = each.value.granted_to_users
40+
granted_to_roles = each.value.granted_to_roles
41+
granted_roles = each.value.granted_roles
4042
}
4143

42-
4344
module "snowflake_custom_role" {
4445
for_each = local.custom_roles
4546

4647
source = "getindata/role/snowflake"
4748
version = "1.0.3"
48-
context = module.this.context
49-
enabled = module.this.enabled && lookup(each.value, "enabled", true)
49+
50+
context = local.enabled
51+
enabled = module.this.enabled && each.value.enabled
52+
descriptor_name = each.value.descriptor_name
5053

5154
name = each.key
5255
attributes = [one(snowflake_database.this[*].name)]
5356

54-
role_ownership_grant = lookup(each.value, "role_ownership_grant", "SYSADMIN")
55-
granted_to_users = lookup(each.value, "granted_to_users", [])
56-
granted_to_roles = lookup(each.value, "granted_to_roles", [])
57-
granted_roles = lookup(each.value, "granted_roles", [])
57+
role_ownership_grant = each.value.role_ownership_grant
58+
granted_to_users = each.value.granted_to_users
59+
granted_to_roles = each.value.granted_to_roles
60+
granted_roles = each.value.granted_roles
5861
}
5962

6063
module "snowflake_schema" {
61-
for_each = var.schemas
64+
for_each = local.schemas
6265

6366
source = "getindata/schema/snowflake"
64-
version = "1.1.0"
67+
version = "1.3.0"
68+
6569
context = module.this.context
70+
enabled = each.value.enabled
6671

6772
name = each.key
6873
database = one(snowflake_database.this[*].name)
6974

70-
data_retention_days = each.value.data_retention_days
71-
is_transient = each.value.is_transient
72-
is_managed = each.value.is_managed
75+
skip_schema_creation = each.value.skip_schema_creation
76+
data_retention_days = each.value.data_retention_days
77+
is_transient = each.value.is_transient
78+
is_managed = each.value.is_managed
7379

7480
stages = each.value.stages
7581

variables.tf

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ variable "roles" {
5353
description = "Roles created in the database scope"
5454
type = map(object({
5555
enabled = optional(bool, true)
56+
descriptor_name = optional(string, "snowflake-role")
5657
comment = optional(string)
5758
role_ownership_grant = optional(string)
5859
granted_roles = optional(list(string))
@@ -67,11 +68,13 @@ variable "roles" {
6768
variable "schemas" {
6869
description = "Schemas to be created in the database"
6970
type = map(object({
70-
descriptor_name = optional(string, "snowflake-schema")
71-
comment = optional(string)
72-
data_retention_days = optional(number, 1)
73-
is_transient = optional(bool, false)
74-
is_managed = optional(bool, false)
71+
enabled = optional(bool, true)
72+
skip_schema_creation = optional(bool, false)
73+
descriptor_name = optional(string, "snowflake-schema")
74+
comment = optional(string)
75+
data_retention_days = optional(number, 1)
76+
is_transient = optional(bool, false)
77+
is_managed = optional(bool, false)
7578
stages = optional(map(object({
7679
enabled = optional(bool, true)
7780
descriptor_name = optional(string, "snowflake-stage")
@@ -88,6 +91,7 @@ variable "schemas" {
8891
create_default_roles = optional(bool)
8992
roles = optional(map(object({
9093
enabled = optional(bool, true)
94+
descriptor_name = optional(string, "snowflake-role")
9195
comment = optional(string)
9296
role_ownership_grant = optional(string)
9397
granted_roles = optional(list(string))
@@ -99,6 +103,7 @@ variable "schemas" {
99103
create_default_roles = optional(bool)
100104
roles = optional(map(object({
101105
enabled = optional(bool, true)
106+
descriptor_name = optional(string, "snowflake-role")
102107
comment = optional(string)
103108
role_ownership_grant = optional(string)
104109
granted_roles = optional(list(string))

0 commit comments

Comments
 (0)