Skip to content

Commit 1a159d7

Browse files
Antvirfbryantbiggs
andauthored
feat: Add support for runtime_environment_secrets (#5)
Co-authored-by: Bryant Biggs <bryantbiggs@gmail.com>
1 parent 1376acc commit 1a159d7

File tree

8 files changed

+189
-25
lines changed

8 files changed

+189
-25
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/antonbabenko/pre-commit-terraform
3-
rev: v1.77.0
3+
rev: v1.77.1
44
hooks:
55
- id: terraform_fmt
66
- id: terraform_validate

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,25 @@ module "app_runner_image_base" {
104104
# From shared configs
105105
auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
106106
107+
# IAM instance profile permissions to access secrets
108+
instance_policy_statements = {
109+
GetSecretValue = {
110+
actions = ["secretsmanager:GetSecretValue"]
111+
resources = [aws_secretsmanager_secret.this.arn]
112+
}
113+
}
114+
107115
source_configuration = {
108116
auto_deployments_enabled = false
109117
image_repository = {
110118
image_configuration = {
111119
port = 8000
120+
runtime_environment_variables = {
121+
MY_VARIABLE = "hello!"
122+
}
123+
runtime_environment_secrets = {
124+
MY_SECRET = aws_secretsmanager_secret.this.arn
125+
}
112126
}
113127
image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
114128
image_repository_type = "ECR_PUBLIC"
@@ -181,13 +195,13 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module
181195
| Name | Version |
182196
|------|---------|
183197
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
184-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.38 |
198+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.51 |
185199

186200
## Providers
187201

188202
| Name | Version |
189203
|------|---------|
190-
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.38 |
204+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.51 |
191205

192206
## Modules
193207

@@ -205,14 +219,17 @@ No modules.
205219
| [aws_apprunner_vpc_connector.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_vpc_connector) | resource |
206220
| [aws_apprunner_vpc_ingress_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_vpc_ingress_connection) | resource |
207221
| [aws_iam_policy.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
222+
| [aws_iam_policy.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
208223
| [aws_iam_role.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
209224
| [aws_iam_role.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
210225
| [aws_iam_role_policy_attachment.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
211226
| [aws_iam_role_policy_attachment.access_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
227+
| [aws_iam_role_policy_attachment.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
212228
| [aws_iam_role_policy_attachment.instance_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
213229
| [aws_iam_role_policy_attachment.instance_xray](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
214230
| [aws_iam_policy_document.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
215231
| [aws_iam_policy_document.access_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
232+
| [aws_iam_policy_document.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
216233
| [aws_iam_policy_document.instance_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
217234
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
218235

@@ -250,6 +267,7 @@ No modules.
250267
| <a name="input_instance_iam_role_permissions_boundary"></a> [instance\_iam\_role\_permissions\_boundary](#input\_instance\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no |
251268
| <a name="input_instance_iam_role_policies"></a> [instance\_iam\_role\_policies](#input\_instance\_iam\_role\_policies) | IAM policies to attach to the IAM role | `map(string)` | `{}` | no |
252269
| <a name="input_instance_iam_role_use_name_prefix"></a> [instance\_iam\_role\_use\_name\_prefix](#input\_instance\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no |
270+
| <a name="input_instance_policy_statements"></a> [instance\_policy\_statements](#input\_instance\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no |
253271
| <a name="input_network_configuration"></a> [network\_configuration](#input\_network\_configuration) | The network configuration for the service | `any` | `{}` | no |
254272
| <a name="input_observability_configuration"></a> [observability\_configuration](#input\_observability\_configuration) | The observability configuration for the service | `any` | `{}` | no |
255273
| <a name="input_private_ecr_arn"></a> [private\_ecr\_arn](#input\_private\_ecr\_arn) | The ARN of the private ECR repository that contains the service image to launch | `string` | `null` | no |

examples/complete/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Configuration in this directory creates:
1010
- An image based AppRunner service
1111
- Utilizes "mega" autoscaling configuration created in shared configs
1212
- Creates a VPC connector to the associated VPC private subnets
13+
- Creates an example runtime environment variable and secret
1314

1415
## Usage
1516

@@ -34,13 +35,13 @@ Note that this example may create resources which will incur monetary charges on
3435
| Name | Version |
3536
|------|---------|
3637
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
37-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.38 |
38+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.51 |
3839

3940
## Providers
4041

4142
| Name | Version |
4243
|------|---------|
43-
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.38 |
44+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.51 |
4445

4546
## Modules
4647

@@ -60,6 +61,8 @@ Note that this example may create resources which will incur monetary charges on
6061

6162
| Name | Type |
6263
|------|------|
64+
| [aws_secretsmanager_secret.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
65+
| [aws_secretsmanager_secret_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
6366
| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
6467

6568
## Inputs

examples/complete/main.tf

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ provider "aws" {
22
region = local.region
33
}
44

5+
data "aws_availability_zones" "available" {}
6+
57
locals {
68
region = "us-east-1"
7-
name = "ex-${replace(basename(path.cwd), "_", "-")}"
9+
name = "ex-${basename(path.cwd)}"
10+
11+
vpc_cidr = "10.0.0.0/16"
12+
azs = slice(data.aws_availability_zones.available.names, 0, 3)
813

914
tags = {
10-
Name = local.name
11-
Example = "complete"
12-
Repository = "https://github.com/terraform-aws-modules/terraform-aws-app-runner"
15+
Example = local.name
16+
GithubRepo = "terraform-aws-app-runner"
17+
GithubOrg = "terraform-aws-modules"
1318
}
1419
}
1520

@@ -96,11 +101,25 @@ module "app_runner_image_base" {
96101
# Pulling from shared configs
97102
auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
98103

104+
# IAM instance profile permissions to access secrets
105+
instance_policy_statements = {
106+
GetSecretValue = {
107+
actions = ["secretsmanager:GetSecretValue"]
108+
resources = [aws_secretsmanager_secret.this.arn]
109+
}
110+
}
111+
99112
source_configuration = {
100113
auto_deployments_enabled = false
101114
image_repository = {
102115
image_configuration = {
103116
port = 8000
117+
runtime_environment_variables = {
118+
MY_VARIABLE = "hello!"
119+
}
120+
runtime_environment_secrets = {
121+
MY_SECRET = aws_secretsmanager_secret.this.arn
122+
}
104123
}
105124
image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
106125
image_repository_type = "ECR_PUBLIC"
@@ -136,11 +155,25 @@ module "app_runner_private" {
136155
# Pulling from shared configs
137156
auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
138157

158+
# IAM instance profile permissions to access secrets
159+
instance_policy_statements = {
160+
GetSecretValue = {
161+
actions = ["secretsmanager:GetSecretValue"]
162+
resources = [aws_secretsmanager_secret.this.arn]
163+
}
164+
}
165+
139166
source_configuration = {
140167
auto_deployments_enabled = false
141168
image_repository = {
142169
image_configuration = {
143170
port = 8000
171+
runtime_environment_variables = {
172+
MY_VARIABLE = "hello!"
173+
}
174+
runtime_environment_secrets = {
175+
MY_SECRET = aws_secretsmanager_secret.this.arn
176+
}
144177
}
145178
image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
146179
image_repository_type = "ECR_PUBLIC"
@@ -179,13 +212,6 @@ module "app_runner_disabled" {
179212
# Supporting Resources
180213
################################################################################
181214

182-
data "aws_availability_zones" "available" {}
183-
184-
locals {
185-
vpc_cidr = "10.0.0.0/16"
186-
azs = slice(data.aws_availability_zones.available.names, 0, 3)
187-
}
188-
189215
module "vpc" {
190216
source = "terraform-aws-modules/vpc/aws"
191217
version = "~> 3.0"
@@ -250,3 +276,13 @@ module "vpc_endpoints_security_group" {
250276

251277
tags = local.tags
252278
}
279+
280+
resource "aws_secretsmanager_secret" "this" {
281+
name_prefix = local.name
282+
recovery_window_in_days = 0
283+
}
284+
285+
resource "aws_secretsmanager_secret_version" "this" {
286+
secret_id = aws_secretsmanager_secret.this.id
287+
secret_string = "example"
288+
}

examples/complete/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ terraform {
44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
7-
version = ">= 4.38"
7+
version = ">= 4.51"
88
}
99
}
1010
}

main.tf

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@ data "aws_partition" "current" {}
66

77
locals {
88
create_service = var.create && var.create_service
9+
10+
# Ensure instance role created is attached even if no values are provided via `var.instance_configuration`
11+
instance_configuration = local.create_instance_iam_role ? merge(
12+
var.instance_configuration,
13+
{ instance_role_arn = aws_iam_role.instance[0].arn }
14+
) : var.instance_configuration
15+
16+
# Ensure access role created is attached even if no values are provided via `var.source_configuration`
17+
source_configuration = local.create_access_iam_role ? merge(
18+
var.source_configuration,
19+
{ authentication_configuration = { access_role_arn = aws_iam_role.access[0].arn } }
20+
) : var.source_configuration
21+
22+
# Ensure VPC connector created is attached even if no values are provided via `var.network_configuration`
23+
network_configuration = local.create_vpc_connector ? merge(
24+
var.network_configuration,
25+
{
26+
egress_configuration = {
27+
egress_type = "VPC"
28+
vpc_connector_arn = aws_apprunner_vpc_connector.this[0].arn
29+
}
30+
}
31+
) : var.network_configuration
932
}
1033

1134
resource "aws_apprunner_service" "this" {
@@ -35,17 +58,17 @@ resource "aws_apprunner_service" "this" {
3558
}
3659

3760
dynamic "instance_configuration" {
38-
for_each = length(var.instance_configuration) > 0 ? [var.instance_configuration] : []
61+
for_each = length(local.instance_configuration) > 0 ? [local.instance_configuration] : []
3962

4063
content {
4164
cpu = try(instance_configuration.value.cpu, null)
42-
instance_role_arn = var.create_instance_iam_role ? aws_iam_role.instance[0].arn : lookup(instance_configuration.value, "instance_role_arn", null)
65+
instance_role_arn = lookup(instance_configuration.value, "instance_role_arn", null)
4366
memory = try(instance_configuration.value.memory, null)
4467
}
4568
}
4669

4770
dynamic "network_configuration" {
48-
for_each = length(var.network_configuration) > 0 ? [var.network_configuration] : []
71+
for_each = length(local.network_configuration) > 0 ? [local.network_configuration] : []
4972

5073
content {
5174
dynamic "ingress_configuration" {
@@ -61,7 +84,7 @@ resource "aws_apprunner_service" "this" {
6184

6285
content {
6386
egress_type = try(egress_configuration.value.egress_type, "VPC")
64-
vpc_connector_arn = try(egress_configuration.value.vpc_connector_arn, aws_apprunner_vpc_connector.this[0].arn, null)
87+
vpc_connector_arn = try(egress_configuration.value.vpc_connector_arn, null)
6588
}
6689
}
6790
}
@@ -78,16 +101,15 @@ resource "aws_apprunner_service" "this" {
78101

79102
service_name = var.service_name
80103

81-
82104
dynamic "source_configuration" {
83-
for_each = [var.source_configuration]
105+
for_each = [local.source_configuration]
84106

85107
content {
86108
dynamic "authentication_configuration" {
87109
for_each = try([source_configuration.value.authentication_configuration], [])
88110

89111
content {
90-
access_role_arn = var.create_access_iam_role ? aws_iam_role.access[0].arn : try(authentication_configuration.value.access_role_arn, null)
112+
access_role_arn = lookup(authentication_configuration.value, "access_role_arn", null)
91113
connection_arn = try(authentication_configuration.value.connection_arn, null)
92114
}
93115
}
@@ -111,6 +133,7 @@ resource "aws_apprunner_service" "this" {
111133
port = try(code_configuration_values.value.port, null)
112134
runtime = code_configuration_values.value.runtime
113135
runtime_environment_variables = try(code_configuration_values.value.runtime_environment_variables, {})
136+
runtime_environment_secrets = try(code_configuration_values.value.runtime_environment_secrets, {})
114137
start_command = try(code_configuration_values.value.start_command, null)
115138
}
116139
}
@@ -142,6 +165,7 @@ resource "aws_apprunner_service" "this" {
142165
content {
143166
port = try(image_configuration.value.port, null)
144167
runtime_environment_variables = try(image_configuration.value.runtime_environment_variables, {})
168+
runtime_environment_secrets = try(image_configuration.value.runtime_environment_secrets, {})
145169
start_command = try(image_configuration.value.start_command, null)
146170
}
147171
}
@@ -302,6 +326,79 @@ resource "aws_iam_role_policy_attachment" "instance_additional" {
302326
role = aws_iam_role.instance[0].name
303327
}
304328

329+
################################################################################
330+
# IAM Role Policy - Instance
331+
################################################################################
332+
333+
locals {
334+
create_instance_role_policy = local.create_instance_iam_role && length(var.instance_policy_statements) > 0
335+
}
336+
337+
data "aws_iam_policy_document" "instance" {
338+
count = local.create_instance_role_policy ? 1 : 0
339+
340+
dynamic "statement" {
341+
for_each = var.instance_policy_statements
342+
343+
content {
344+
sid = try(statement.value.sid, statement.key)
345+
actions = try(statement.value.actions, null)
346+
not_actions = try(statement.value.not_actions, null)
347+
effect = try(statement.value.effect, null)
348+
resources = try(statement.value.resources, null)
349+
not_resources = try(statement.value.not_resources, null)
350+
351+
dynamic "principals" {
352+
for_each = try(statement.value.principals, [])
353+
354+
content {
355+
type = principals.value.type
356+
identifiers = principals.value.identifiers
357+
}
358+
}
359+
360+
dynamic "not_principals" {
361+
for_each = try(statement.value.not_principals, [])
362+
363+
content {
364+
type = not_principals.value.type
365+
identifiers = not_principals.value.identifiers
366+
}
367+
}
368+
369+
dynamic "condition" {
370+
for_each = try(statement.value.conditions, [])
371+
372+
content {
373+
test = condition.value.test
374+
values = condition.value.values
375+
variable = condition.value.variable
376+
}
377+
}
378+
}
379+
}
380+
}
381+
382+
resource "aws_iam_policy" "instance" {
383+
count = local.create_instance_role_policy ? 1 : 0
384+
385+
name = var.instance_iam_role_use_name_prefix ? null : local.instance_iam_role_name
386+
name_prefix = var.instance_iam_role_use_name_prefix ? "${local.instance_iam_role_name}-" : null
387+
path = var.instance_iam_role_path
388+
description = var.instance_iam_role_description
389+
390+
policy = data.aws_iam_policy_document.instance[0].json
391+
392+
tags = var.tags
393+
}
394+
395+
resource "aws_iam_role_policy_attachment" "instance" {
396+
count = local.create_instance_role_policy ? 1 : 0
397+
398+
policy_arn = aws_iam_policy.instance[0].arn
399+
role = aws_iam_role.instance[0].name
400+
}
401+
305402
################################################################################
306403
# VPC Ingress Configuration
307404
################################################################################

0 commit comments

Comments
 (0)