Skip to content

Commit 87ff09b

Browse files
feat: Add support for relational database datasources (#58)
1 parent 8f658e4 commit 87ff09b

File tree

6 files changed

+107
-42
lines changed

6 files changed

+107
-42
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,16 @@ module "appsync" {
6767
}
6868
6969
eventbridge1 = {
70-
type = "AMAZON_EVENTBRIDGE"
71-
event_bus_arn = "aws:arn:events:us-west-1:135367859850:event-bus/eventbridge1"
70+
type = "AMAZON_EVENTBRIDGE"
71+
event_bus_arn = "arn:aws:events:us-west-1:135367859850:event-bus/eventbridge1"
72+
}
73+
74+
rds1 = {
75+
type = "RELATIONAL_DATABASE"
76+
cluster_arn = "arn:aws:rds:us-west-1:135367859850:cluster:rds1"
77+
secret_arn = "arn:aws:secretsmanager:us-west-1:135367859850:secret:rds-secret1"
78+
database_name = "mydb"
79+
schema = "myschema"
7280
}
7381
}
7482
@@ -198,9 +206,11 @@ No modules.
198206
| <a name="input_name"></a> [name](#input\_name) | Name of GraphQL API | `string` | `""` | no |
199207
| <a name="input_openid_connect_config"></a> [openid\_connect\_config](#input\_openid\_connect\_config) | Nested argument containing OpenID Connect configuration. | `map(string)` | `{}` | no |
200208
| <a name="input_opensearchservice_allowed_actions"></a> [opensearchservice\_allowed\_actions](#input\_opensearchservice\_allowed\_actions) | List of allowed IAM actions for datasources type AMAZON\_OPENSEARCH\_SERVICE | `list(string)` | <pre>[<br> "es:ESHttpDelete",<br> "es:ESHttpHead",<br> "es:ESHttpGet",<br> "es:ESHttpPost",<br> "es:ESHttpPut"<br>]</pre> | no |
209+
| <a name="input_relational_database_allowed_actions"></a> [relational\_database\_allowed\_actions](#input\_relational\_database\_allowed\_actions) | List of allowed IAM actions for datasources type RELATIONAL\_DATABASE | `list(string)` | <pre>[<br> "rds-data:BatchExecuteStatement",<br> "rds-data:BeginTransaction",<br> "rds-data:CommitTransaction",<br> "rds-data:ExecuteStatement",<br> "rds-data:RollbackTransaction"<br>]</pre> | no |
201210
| <a name="input_resolver_caching_ttl"></a> [resolver\_caching\_ttl](#input\_resolver\_caching\_ttl) | Default caching TTL for resolvers when caching is enabled | `number` | `60` | no |
202211
| <a name="input_resolvers"></a> [resolvers](#input\_resolvers) | Map of resolvers to create | `any` | `{}` | no |
203212
| <a name="input_schema"></a> [schema](#input\_schema) | The schema definition, in GraphQL schema language format. Terraform cannot perform drift detection of this configuration. | `string` | `""` | no |
213+
| <a name="input_secrets_manager_allowed_actions"></a> [secrets\_manager\_allowed\_actions](#input\_secrets\_manager\_allowed\_actions) | List of allowed IAM actions for secrets manager datasources type RELATIONAL\_DATABASE | `list(string)` | <pre>[<br> "secretsmanager:GetSecretValue"<br>]</pre> | no |
204214
| <a name="input_tags"></a> [tags](#input\_tags) | Map of tags to add to all GraphQL resources created by this module | `map(string)` | `{}` | no |
205215
| <a name="input_user_pool_config"></a> [user\_pool\_config](#input\_user\_pool\_config) | The Amazon Cognito User Pool configuration. | `map(string)` | `{}` | no |
206216
| <a name="input_visibility"></a> [visibility](#input\_visibility) | The API visibility. Valid values: GLOBAL, PRIVATE. | `string` | `null` | no |

examples/complete/main.tf

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,16 @@ module "appsync" {
224224
}
225225

226226
eventbridge1 = {
227-
type = "AMAZON_EVENTBRIDGE"
227+
type = "AMAZON_EVENTBRIDGE"
228+
event_bus_arn = "arn:aws:events:us-west-1:135367859850:event-bus/eventbridge1"
229+
}
228230

229-
event_bus_arn = "aws:arn:events:us-west-1:135367859850:event-bus/eventbridge1"
231+
rds1 = {
232+
type = "RELATIONAL_DATABASE"
233+
cluster_arn = "arn:aws:rds:us-west-1:135367859850:cluster:rds1"
234+
secret_arn = "arn:aws:secretsmanager:us-west-1:135367859850:secret:rds-secret1"
235+
database_name = "mydb"
236+
schema = "myschema"
230237
}
231238
}
232239

iam.tf

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
data "aws_partition" "this" {}
22

33
locals {
4-
service_roles_with_policies = var.create_graphql_api ? { for k, v in var.datasources : k => v if contains(["AWS_LAMBDA", "AMAZON_DYNAMODB", "AMAZON_ELASTICSEARCH", "AMAZON_OPENSEARCH_SERVICE", "AMAZON_EVENTBRIDGE"], v.type) && tobool(lookup(v, "create_service_role", true)) } : {}
4+
service_roles_with_policies = var.create_graphql_api ? { for k, v in var.datasources : k => v if contains(["AWS_LAMBDA", "AMAZON_DYNAMODB", "AMAZON_ELASTICSEARCH", "AMAZON_OPENSEARCH_SERVICE", "AMAZON_EVENTBRIDGE", "RELATIONAL_DATABASE"], v.type) && tobool(lookup(v, "create_service_role", true)) } : {}
55

66
service_roles_with_policies_lambda = { for k, v in local.service_roles_with_policies : k => merge(v,
77
{
@@ -63,12 +63,30 @@ locals {
6363
}
6464
) if v.type == "AMAZON_EVENTBRIDGE" }
6565

66+
service_roles_with_policies_relational_database = { for k, v in local.service_roles_with_policies : k => merge(v,
67+
{
68+
policy_statements = {
69+
relational_database = {
70+
effect = "Allow"
71+
actions = lookup(v, "policy_actions", null) == null ? var.relational_database_allowed_actions : v.policy_actions
72+
resources = [v.cluster_arn]
73+
}
74+
secrets_manager = {
75+
effect = "Allow"
76+
actions = lookup(v, "policy_actions", null) == null ? var.secrets_manager_allowed_actions : v.policy_actions
77+
resources = [v.secret_arn]
78+
}
79+
}
80+
}
81+
) if v.type == "RELATIONAL_DATABASE" }
82+
6683
service_roles_with_specific_policies = merge(
6784
local.service_roles_with_policies_lambda,
6885
local.service_roles_with_policies_dynamodb,
6986
local.service_roles_with_policies_elasticsearch,
7087
local.service_roles_with_policies_opensearchservice,
7188
local.service_roles_with_policies_eventbridge,
89+
local.service_roles_with_policies_relational_database,
7290
)
7391
}
7492

main.tf

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ resource "aws_appsync_datasource" "this" {
144144
name = each.key
145145
type = each.value.type
146146
description = lookup(each.value, "description", null)
147-
service_role_arn = lookup(each.value, "service_role_arn", tobool(lookup(each.value, "create_service_role", contains(["AWS_LAMBDA", "AMAZON_DYNAMODB", "AMAZON_ELASTICSEARCH", "AMAZON_OPENSEARCH_SERVICE", "AMAZON_EVENTBRIDGE"], each.value.type))) ? aws_iam_role.service_role[each.key].arn : null)
147+
service_role_arn = lookup(each.value, "service_role_arn", tobool(lookup(each.value, "create_service_role", contains(["AWS_LAMBDA", "AMAZON_DYNAMODB", "AMAZON_ELASTICSEARCH", "AMAZON_OPENSEARCH_SERVICE", "AMAZON_EVENTBRIDGE", "RELATIONAL_DATABASE"], each.value.type))) ? aws_iam_role.service_role[each.key].arn : null)
148148

149149
dynamic "http_config" {
150150
for_each = each.value.type == "HTTP" ? [true] : []
@@ -197,6 +197,22 @@ resource "aws_appsync_datasource" "this" {
197197
event_bus_arn = each.value.event_bus_arn
198198
}
199199
}
200+
201+
dynamic "relational_database_config" {
202+
for_each = each.value.type == "RELATIONAL_DATABASE" ? [true] : []
203+
204+
content {
205+
source_type = lookup(each.value, "source_type", "RDS_HTTP_ENDPOINT")
206+
207+
http_endpoint_config {
208+
db_cluster_identifier = each.value.cluster_arn
209+
aws_secret_store_arn = each.value.secret_arn
210+
database_name = lookup(each.value, "database_name", null)
211+
region = split(":", each.value.cluster_arn)[3]
212+
schema = lookup(each.value, "schema", null)
213+
}
214+
}
215+
}
200216
}
201217

202218
# Resolvers

variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,18 @@ variable "eventbridge_allowed_actions" {
242242
default = ["events:PutEvents"]
243243
}
244244

245+
variable "relational_database_allowed_actions" {
246+
description = "List of allowed IAM actions for datasources type RELATIONAL_DATABASE"
247+
type = list(string)
248+
default = ["rds-data:BatchExecuteStatement", "rds-data:BeginTransaction", "rds-data:CommitTransaction", "rds-data:ExecuteStatement", "rds-data:RollbackTransaction"]
249+
}
250+
251+
variable "secrets_manager_allowed_actions" {
252+
description = "List of allowed IAM actions for secrets manager datasources type RELATIONAL_DATABASE"
253+
type = list(string)
254+
default = ["secretsmanager:GetSecretValue"]
255+
}
256+
245257
variable "iam_permissions_boundary" {
246258
description = "ARN for iam permissions boundary"
247259
type = string

wrappers/main.tf

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,44 @@ module "wrapper" {
33

44
for_each = var.items
55

6-
create_graphql_api = try(each.value.create_graphql_api, var.defaults.create_graphql_api, true)
7-
logging_enabled = try(each.value.logging_enabled, var.defaults.logging_enabled, false)
8-
domain_name_association_enabled = try(each.value.domain_name_association_enabled, var.defaults.domain_name_association_enabled, false)
9-
caching_enabled = try(each.value.caching_enabled, var.defaults.caching_enabled, false)
10-
xray_enabled = try(each.value.xray_enabled, var.defaults.xray_enabled, false)
11-
name = try(each.value.name, var.defaults.name, "")
12-
schema = try(each.value.schema, var.defaults.schema, "")
13-
visibility = try(each.value.visibility, var.defaults.visibility, null)
14-
authentication_type = try(each.value.authentication_type, var.defaults.authentication_type, "API_KEY")
15-
create_logs_role = try(each.value.create_logs_role, var.defaults.create_logs_role, true)
16-
logs_role_name = try(each.value.logs_role_name, var.defaults.logs_role_name, null)
17-
log_cloudwatch_logs_role_arn = try(each.value.log_cloudwatch_logs_role_arn, var.defaults.log_cloudwatch_logs_role_arn, null)
18-
log_field_log_level = try(each.value.log_field_log_level, var.defaults.log_field_log_level, null)
19-
log_exclude_verbose_content = try(each.value.log_exclude_verbose_content, var.defaults.log_exclude_verbose_content, false)
20-
lambda_authorizer_config = try(each.value.lambda_authorizer_config, var.defaults.lambda_authorizer_config, {})
21-
openid_connect_config = try(each.value.openid_connect_config, var.defaults.openid_connect_config, {})
22-
user_pool_config = try(each.value.user_pool_config, var.defaults.user_pool_config, {})
23-
additional_authentication_provider = try(each.value.additional_authentication_provider, var.defaults.additional_authentication_provider, {})
24-
graphql_api_tags = try(each.value.graphql_api_tags, var.defaults.graphql_api_tags, {})
25-
logs_role_tags = try(each.value.logs_role_tags, var.defaults.logs_role_tags, {})
26-
tags = try(each.value.tags, var.defaults.tags, {})
27-
domain_name = try(each.value.domain_name, var.defaults.domain_name, "")
28-
domain_name_description = try(each.value.domain_name_description, var.defaults.domain_name_description, null)
29-
certificate_arn = try(each.value.certificate_arn, var.defaults.certificate_arn, "")
30-
caching_behavior = try(each.value.caching_behavior, var.defaults.caching_behavior, "FULL_REQUEST_CACHING")
31-
cache_type = try(each.value.cache_type, var.defaults.cache_type, "SMALL")
32-
cache_ttl = try(each.value.cache_ttl, var.defaults.cache_ttl, 1)
33-
cache_at_rest_encryption_enabled = try(each.value.cache_at_rest_encryption_enabled, var.defaults.cache_at_rest_encryption_enabled, false)
34-
cache_transit_encryption_enabled = try(each.value.cache_transit_encryption_enabled, var.defaults.cache_transit_encryption_enabled, false)
35-
api_keys = try(each.value.api_keys, var.defaults.api_keys, {})
36-
lambda_allowed_actions = try(each.value.lambda_allowed_actions, var.defaults.lambda_allowed_actions, ["lambda:invokeFunction"])
37-
dynamodb_allowed_actions = try(each.value.dynamodb_allowed_actions, var.defaults.dynamodb_allowed_actions, ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem", "dynamodb:UpdateItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem"])
38-
elasticsearch_allowed_actions = try(each.value.elasticsearch_allowed_actions, var.defaults.elasticsearch_allowed_actions, ["es:ESHttpDelete", "es:ESHttpHead", "es:ESHttpGet", "es:ESHttpPost", "es:ESHttpPut"])
39-
opensearchservice_allowed_actions = try(each.value.opensearchservice_allowed_actions, var.defaults.opensearchservice_allowed_actions, ["es:ESHttpDelete", "es:ESHttpHead", "es:ESHttpGet", "es:ESHttpPost", "es:ESHttpPut"])
40-
eventbridge_allowed_actions = try(each.value.eventbridge_allowed_actions, var.defaults.eventbridge_allowed_actions, ["events:PutEvents"])
41-
iam_permissions_boundary = try(each.value.iam_permissions_boundary, var.defaults.iam_permissions_boundary, null)
6+
create_graphql_api = try(each.value.create_graphql_api, var.defaults.create_graphql_api, true)
7+
logging_enabled = try(each.value.logging_enabled, var.defaults.logging_enabled, false)
8+
domain_name_association_enabled = try(each.value.domain_name_association_enabled, var.defaults.domain_name_association_enabled, false)
9+
caching_enabled = try(each.value.caching_enabled, var.defaults.caching_enabled, false)
10+
xray_enabled = try(each.value.xray_enabled, var.defaults.xray_enabled, false)
11+
name = try(each.value.name, var.defaults.name, "")
12+
schema = try(each.value.schema, var.defaults.schema, "")
13+
visibility = try(each.value.visibility, var.defaults.visibility, null)
14+
authentication_type = try(each.value.authentication_type, var.defaults.authentication_type, "API_KEY")
15+
create_logs_role = try(each.value.create_logs_role, var.defaults.create_logs_role, true)
16+
logs_role_name = try(each.value.logs_role_name, var.defaults.logs_role_name, null)
17+
log_cloudwatch_logs_role_arn = try(each.value.log_cloudwatch_logs_role_arn, var.defaults.log_cloudwatch_logs_role_arn, null)
18+
log_field_log_level = try(each.value.log_field_log_level, var.defaults.log_field_log_level, null)
19+
log_exclude_verbose_content = try(each.value.log_exclude_verbose_content, var.defaults.log_exclude_verbose_content, false)
20+
lambda_authorizer_config = try(each.value.lambda_authorizer_config, var.defaults.lambda_authorizer_config, {})
21+
openid_connect_config = try(each.value.openid_connect_config, var.defaults.openid_connect_config, {})
22+
user_pool_config = try(each.value.user_pool_config, var.defaults.user_pool_config, {})
23+
additional_authentication_provider = try(each.value.additional_authentication_provider, var.defaults.additional_authentication_provider, {})
24+
graphql_api_tags = try(each.value.graphql_api_tags, var.defaults.graphql_api_tags, {})
25+
logs_role_tags = try(each.value.logs_role_tags, var.defaults.logs_role_tags, {})
26+
tags = try(each.value.tags, var.defaults.tags, {})
27+
domain_name = try(each.value.domain_name, var.defaults.domain_name, "")
28+
domain_name_description = try(each.value.domain_name_description, var.defaults.domain_name_description, null)
29+
certificate_arn = try(each.value.certificate_arn, var.defaults.certificate_arn, "")
30+
caching_behavior = try(each.value.caching_behavior, var.defaults.caching_behavior, "FULL_REQUEST_CACHING")
31+
cache_type = try(each.value.cache_type, var.defaults.cache_type, "SMALL")
32+
cache_ttl = try(each.value.cache_ttl, var.defaults.cache_ttl, 1)
33+
cache_at_rest_encryption_enabled = try(each.value.cache_at_rest_encryption_enabled, var.defaults.cache_at_rest_encryption_enabled, false)
34+
cache_transit_encryption_enabled = try(each.value.cache_transit_encryption_enabled, var.defaults.cache_transit_encryption_enabled, false)
35+
api_keys = try(each.value.api_keys, var.defaults.api_keys, {})
36+
lambda_allowed_actions = try(each.value.lambda_allowed_actions, var.defaults.lambda_allowed_actions, ["lambda:invokeFunction"])
37+
dynamodb_allowed_actions = try(each.value.dynamodb_allowed_actions, var.defaults.dynamodb_allowed_actions, ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem", "dynamodb:UpdateItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem"])
38+
elasticsearch_allowed_actions = try(each.value.elasticsearch_allowed_actions, var.defaults.elasticsearch_allowed_actions, ["es:ESHttpDelete", "es:ESHttpHead", "es:ESHttpGet", "es:ESHttpPost", "es:ESHttpPut"])
39+
opensearchservice_allowed_actions = try(each.value.opensearchservice_allowed_actions, var.defaults.opensearchservice_allowed_actions, ["es:ESHttpDelete", "es:ESHttpHead", "es:ESHttpGet", "es:ESHttpPost", "es:ESHttpPut"])
40+
eventbridge_allowed_actions = try(each.value.eventbridge_allowed_actions, var.defaults.eventbridge_allowed_actions, ["events:PutEvents"])
41+
relational_database_allowed_actions = try(each.value.relational_database_allowed_actions, var.defaults.relational_database_allowed_actions, ["rds-data:BatchExecuteStatement", "rds-data:BeginTransaction", "rds-data:CommitTransaction", "rds-data:ExecuteStatement", "rds-data:RollbackTransaction"])
42+
secrets_manager_allowed_actions = try(each.value.secrets_manager_allowed_actions, var.defaults.secrets_manager_allowed_actions, ["secretsmanager:GetSecretValue"])
43+
iam_permissions_boundary = try(each.value.iam_permissions_boundary, var.defaults.iam_permissions_boundary, null)
4244
direct_lambda_request_template = try(each.value.direct_lambda_request_template, var.defaults.direct_lambda_request_template, <<-EOF
4345
{
4446
"version" : "2017-02-28",

0 commit comments

Comments
 (0)