Skip to content

Commit c0a605d

Browse files
Merge commit '75a5b16f208bb639ce8eb379adb125bd4cab3230' into release
2 parents 0963ca5 + 75a5b16 commit c0a605d

File tree

8 files changed

+188
-46
lines changed

8 files changed

+188
-46
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
## [Unreleased]
44

5+
## [1.0.0-canary.3] - 2022-06-07
6+
7+
- Fixes deployments without Lambdas ([#325](https://github.com/milliHQ/terraform-aws-next-js/pull/325))
8+
- Use CloudFormation role ([#324](https://github.com/milliHQ/terraform-aws-next-js/pull/324))
9+
- Improve CLI ([#323](https://github.com/milliHQ/terraform-aws-next-js/pull/323))
10+
- Fix runtime bundle ([#322](https://github.com/milliHQ/terraform-aws-next-js/pull/322))
11+
512
## [1.0.0-canary.2] - 2022-05-31
613

714
- Adds static prefix to files served from S3 ([#321](https://github.com/milliHQ/terraform-aws-next-js/pull/321))

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ For building and deploying Next.js apps to the system we created a CLI tool call
217217
It is a npm package that can be installed with:
218218

219219
```sh
220-
npm i -g tf-next
220+
npm i -g tf-next@canary
221221
```
222222

223223
Next, we need to build the Next.js so that it can run in a serverless environment (with AWS Lambda).

main.tf

+110
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,109 @@ resource "aws_dynamodb_table" "deployments" {
8484
projection_type = "INCLUDE"
8585
non_key_attributes = ["CreateDate", "DeploymentAlias", "DeploymentId", "Status"]
8686
}
87+
88+
tags = var.tags
89+
}
90+
91+
#####################
92+
# CloudFormation Role
93+
#####################
94+
95+
# Policy that controls which actions can be performed when CloudFormation
96+
# creates a substack (from CDK)
97+
data "aws_iam_policy_document" "cloudformation_permission" {
98+
# Allow CloudFormation to publish status changes to the SNS queue
99+
statement {
100+
effect = "Allow"
101+
actions = [
102+
"sns:Publish"
103+
]
104+
resources = [module.deploy_controller.sns_topic_arn]
105+
}
106+
107+
# Allow CloudFormation to access the lambda content
108+
statement {
109+
effect = "Allow"
110+
actions = [
111+
"s3:GetObject"
112+
]
113+
resources = [
114+
module.statics_deploy.static_bucket_arn,
115+
"${module.statics_deploy.static_bucket_arn}/*"
116+
]
117+
}
118+
119+
# Stack creation
120+
statement {
121+
effect = "Allow"
122+
actions = [
123+
# TODO: Restrict the API Gateway action more
124+
"apigateway:*",
125+
"iam:CreateRole",
126+
"iam:GetRole",
127+
"iam:GetRolePolicy",
128+
"iam:PassRole",
129+
"iam:PutRolePolicy",
130+
"iam:TagRole",
131+
"lambda:AddPermission",
132+
"lambda:CreateFunction",
133+
"lambda:CreateFunctionUrlConfig",
134+
"lambda:GetFunctionUrlConfig",
135+
"lambda:GetFunction",
136+
"lambda:TagResource",
137+
"logs:CreateLogGroup",
138+
"logs:PutRetentionPolicy",
139+
"logs:TagLogGroup"
140+
]
141+
resources = ["*"]
142+
}
143+
144+
# Stack deletion
145+
statement {
146+
effect = "Allow"
147+
actions = [
148+
"apigateway:*",
149+
"iam:DeleteRole",
150+
"iam:DeleteRolePolicy",
151+
"iam:UntagRole",
152+
"lambda:DeleteFunction",
153+
"lambda:DeleteFunctionUrlConfig",
154+
"lambda:RemovePermission",
155+
"lambda:UntagResource",
156+
"logs:DeleteLogGroup",
157+
"logs:DeleteRetentionPolicy",
158+
"logs:UntagLogGroup"
159+
]
160+
resources = ["*"]
161+
}
162+
}
163+
164+
data "aws_iam_policy_document" "cloudformation_permission_assume_role" {
165+
statement {
166+
effect = "Allow"
167+
actions = ["sts:AssumeRole"]
168+
169+
principals {
170+
type = "Service"
171+
identifiers = ["cloudformation.amazonaws.com"]
172+
}
173+
}
174+
}
175+
176+
resource "aws_iam_policy" "cloudformation_permission" {
177+
name = "${var.deployment_name}_cf-control"
178+
description = "Managed by Terraform Next.js"
179+
policy = data.aws_iam_policy_document.cloudformation_permission.json
180+
181+
tags = var.tags
182+
}
183+
184+
resource "aws_iam_role" "cloudformation_permission" {
185+
name = "${var.deployment_name}_cf-control"
186+
assume_role_policy = data.aws_iam_policy_document.cloudformation_permission_assume_role.json
187+
managed_policy_arns = [
188+
aws_iam_policy.cloudformation_permission.arn
189+
]
87190
}
88191

89192
###################
@@ -122,9 +225,16 @@ module "statics_deploy" {
122225
deploy_status_sns_topic_arn = module.deploy_controller.sns_topic_arn
123226

124227
dynamodb_region = data.aws_region.current.name
228+
dynamodb_table_aliases_arn = aws_dynamodb_table.aliases.arn
229+
dynamodb_table_aliases_name = aws_dynamodb_table.aliases.id
125230
dynamodb_table_deployments_arn = aws_dynamodb_table.deployments.arn
126231
dynamodb_table_deployments_name = aws_dynamodb_table.deployments.id
127232

233+
cloudformation_role_arn = aws_iam_role.cloudformation_permission.arn
234+
235+
enable_multiple_deployments = var.enable_multiple_deployments
236+
multiple_deployments_base_domain = var.multiple_deployments_base_domain
237+
128238
lambda_role_permissions_boundary = var.lambda_role_permissions_boundary
129239

130240
deployment_name = var.deployment_name

modules/api/main.tf

+16-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ data "aws_iam_policy_document" "access_upload_bucket" {
3535
}
3636
}
3737

38+
# Initiate deletion of CloudFormation stacks
39+
data "aws_iam_policy_document" "delete_cloudformation_stack" {
40+
statement {
41+
effect = "Allow"
42+
actions = [
43+
"cloudformation:DeleteStack"
44+
]
45+
resources = [
46+
"arn:aws:cloudformation:*:*:stack/*/*"
47+
]
48+
}
49+
}
50+
3851
module "lambda" {
3952
source = "../lambda-worker"
4053

@@ -49,10 +62,11 @@ module "lambda" {
4962
memory_size = 128
5063

5164
attach_policy_jsons = true
52-
number_of_policy_jsons = 2
65+
number_of_policy_jsons = 3
5366
policy_jsons = [
5467
data.aws_iam_policy_document.access_dynamodb_tables.json,
5568
data.aws_iam_policy_document.access_upload_bucket.json,
69+
data.aws_iam_policy_document.delete_cloudformation_stack.json,
5670
]
5771

5872
environment_variables = {
@@ -129,8 +143,7 @@ data "aws_iam_policy_document" "access_api" {
129143
}
130144

131145
resource "aws_iam_policy" "access_api" {
132-
name = "api-access"
133-
path = "/${var.deployment_name}/"
146+
name = "${var.deployment_name}_api-access"
134147

135148
description = "Managed by Terraform Next.js"
136149

modules/deploy-controller/main.tf

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ data "aws_iam_policy_document" "access_dynamodb_tables" {
3636
"dynamodb:GetItem",
3737
"dynamodb:PutItem",
3838
"dynamodb:Query",
39-
"dynamodb:UpdateItem"
39+
"dynamodb:UpdateItem",
40+
"dynamodb:DeleteItem"
4041
]
4142
resources = [
4243
var.dynamodb_table_deployments_arn,

modules/proxy/variables.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
variable "proxy_module_version" {
66
type = string
7-
default = "1.0.0-canary.2"
7+
default = "1.0.0-canary.3"
88
}
99

1010
variable "lambda_default_runtime" {

modules/statics-deploy/main.tf

+20-39
Original file line numberDiff line numberDiff line change
@@ -112,46 +112,20 @@ data "aws_iam_policy_document" "access_static_deploy" {
112112
resources = [var.cloudfront_arn]
113113
}
114114

115-
# Permissions for CloudFormation to create resources
115+
# Create new substacks from CDK templates
116116
statement {
117117
actions = [
118-
"apigateway:*",
119-
"cloudformation:CreateStack",
120-
"iam:CreateRole",
121-
"iam:DeleteRole",
122-
"iam:DeleteRolePolicy",
123-
"iam:GetRole",
124-
"iam:GetRolePolicy",
125-
"iam:PassRole",
126-
"iam:PutRolePolicy",
127-
"iam:TagRole",
128-
"iam:UntagRole",
129-
"lambda:AddPermission",
130-
"lambda:CreateFunction",
131-
"lambda:DeleteFunction",
132-
"lambda:CreateFunctionUrlConfig",
133-
"lambda:GetFunctionUrlConfig",
134-
"lambda:GetFunction",
135-
"lambda:RemovePermission",
136-
"lambda:TagResource",
137-
"lambda:UntagResource",
138-
"logs:CreateLogGroup",
139-
"logs:DeleteLogGroup",
140-
"logs:DeleteRetentionPolicy",
141-
"logs:PutRetentionPolicy",
142-
"logs:TagLogGroup",
143-
"logs:UntagLogGroup",
118+
"cloudformation:CreateStack"
144119
]
145120
resources = ["*"]
146121
}
147122

148-
# Allow CloudFormation to publish status changes to the SNS queue
123+
# Allow to pass the cloudfront role to the cloudformation stack
149124
statement {
150-
effect = "Allow"
151125
actions = [
152-
"sns:Publish"
126+
"iam:PassRole"
153127
]
154-
resources = [var.deploy_status_sns_topic_arn]
128+
resources = [var.cloudformation_role_arn]
155129
}
156130
}
157131

@@ -179,7 +153,10 @@ data "aws_iam_policy_document" "access_dynamodb_table_deployments" {
179153
"dynamodb:PutItem",
180154
"dynamodb:UpdateItem"
181155
]
182-
resources = [var.dynamodb_table_deployments_arn]
156+
resources = [
157+
var.dynamodb_table_aliases_arn,
158+
var.dynamodb_table_deployments_arn
159+
]
183160
}
184161
}
185162

@@ -254,13 +231,17 @@ module "deploy_trigger" {
254231
]
255232

256233
environment_variables = {
257-
NODE_ENV = "production"
258-
TARGET_BUCKET = aws_s3_bucket.static_deploy.id
259-
DISTRIBUTION_ID = var.cloudfront_id
260-
SQS_QUEUE_URL = aws_sqs_queue.this.id
261-
DEPLOY_STATUS_SNS_ARN = var.deploy_status_sns_topic_arn
262-
TABLE_REGION = var.dynamodb_region
263-
TABLE_NAME_DEPLOYMENTS = var.dynamodb_table_deployments_name
234+
NODE_ENV = "production"
235+
TARGET_BUCKET = aws_s3_bucket.static_deploy.id
236+
DISTRIBUTION_ID = var.cloudfront_id
237+
SQS_QUEUE_URL = aws_sqs_queue.this.id
238+
DEPLOY_STATUS_SNS_ARN = var.deploy_status_sns_topic_arn
239+
TABLE_REGION = var.dynamodb_region
240+
TABLE_NAME_ALIASES = var.dynamodb_table_aliases_name
241+
TABLE_NAME_DEPLOYMENTS = var.dynamodb_table_deployments_name
242+
CLOUDFORMATION_ROLE_ARN = var.cloudformation_role_arn
243+
# Remove the * from the base domain (e.g. *.example.com -> .example.com)
244+
MULTI_DEPLOYMENTS_BASE_DOMAIN = var.enable_multiple_deployments ? replace(var.multiple_deployments_base_domain, "/^\\*/", "") : null
264245
}
265246

266247
event_source_mapping = {

modules/statics-deploy/variables.tf

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
variable "deploy_trigger_module_version" {
22
type = string
3-
default = "1.0.0-canary.2"
3+
default = "1.0.0-canary.3"
44
}
55

66
variable "cloudfront_id" {
@@ -18,6 +18,28 @@ variable "lambda_role_permissions_boundary" {
1818
default = null
1919
}
2020

21+
################
22+
# CloudFormation
23+
################
24+
25+
variable "cloudformation_role_arn" {
26+
description = "Role ARN that should be assigned to the CloudFormation substacks created by CDK."
27+
type = string
28+
}
29+
30+
######################
31+
# Multiple deployments
32+
######################
33+
34+
variable "enable_multiple_deployments" {
35+
type = bool
36+
}
37+
38+
variable "multiple_deployments_base_domain" {
39+
type = string
40+
default = null
41+
}
42+
2143
#####################
2244
# Deployment database
2345
#####################
@@ -26,6 +48,14 @@ variable "dynamodb_region" {
2648
type = string
2749
}
2850

51+
variable "dynamodb_table_aliases_arn" {
52+
type = string
53+
}
54+
55+
variable "dynamodb_table_aliases_name" {
56+
type = string
57+
}
58+
2959
variable "dynamodb_table_deployments_arn" {
3060
type = string
3161
}

0 commit comments

Comments
 (0)