diff --git a/terraform/README.md b/terraform/README.md index 98d81fd..6d79119 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -133,7 +133,7 @@ The directory structure is organized to support deploying the extension app to d - `README.md`: The main documentation file. - `aws/`: Contains Terraform configuration files for deploying to Amazon Web Services. - `README.md`: Documentation specific to AWS deployment. - - `apprunner.tf`, `ecr.tf`, `image.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `terraform.tf`, `variables.tf`: Various Terraform configuration files for AWS resources. + - `ecr.tf`, `image.tf`, `lightsail.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `terraform.tf`, `variables.tf`: Various Terraform configuration files for AWS resources. - `azure/`: Contains Terraform configuration files for deploying to Microsoft Azure. - `README.md`: Documentation specific to Azure deployment. - `acr.tf`, `image.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `resource_group.tf`, `terraform.tf`, `variables.tf`, `webapp.tf`: Various Terraform configuration files for Azure resources. @@ -156,9 +156,9 @@ The directory structure is organized to support deploying the extension app to d ├── README.md ├── aws │ ├── README.md -│ ├── apprunner.tf │ ├── ecr.tf │ ├── image.tf +│ ├── lightsail.tf │ ├── main.tf │ ├── outputs.tf │ ├── providers.tf diff --git a/terraform/aws/.terraform.lock.hcl b/terraform/aws/.terraform.lock.hcl new file mode 100644 index 0000000..9376bff --- /dev/null +++ b/terraform/aws/.terraform.lock.hcl @@ -0,0 +1,106 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.100.0" + constraints = "~> 5.0" + hashes = [ + "h1:Ijt7pOlB7Tr7maGQIqtsLFbl7pSMIj06TVdkoSBcYOw=", + "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", + "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", + "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", + "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", + "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", + "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", + "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", + "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", + "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", + "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", + "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", + "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", + "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + ] +} + +provider "registry.terraform.io/hashicorp/local" { + version = "2.8.0" + constraints = "~> 2.5" + hashes = [ + "h1:3jWHVwO5QUIS9V1NsK10ZzdpkK2ABuB4G+UIWrVeGp4=", + "zh:05f18164beab4a84753e5fedf463771ee0c6eca8e90346b8766f1e1c186dec1e", + "zh:563a0702e3711e25ba8930120899b681378b50cbb957fd204b37745c7c9b5f40", + "zh:5b56ab2ed70ed92721febb4a070af0837f1084c44825c18e4b95f7efb1d45d26", + "zh:6cbedc09b67a5cdb9501ff1b18a315fa46a38e0530424cab1c7f4b3acc75f489", + "zh:71b3bd50f89fb385a42a436ba2ce2b8e00f9de53535ce956deff1477b0b117dc", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9d45ac0a00b85cabdd398b859349d17f124c598b6e6bf272f1bb01321ce708a8", + "zh:a453efe8641a8f31fe806b597bf2b34d7b78b971a8e3919061ea89d61fda7b8d", + "zh:ac692bacb8c3dca8b5b37e5383168aca1f87d3cd7b40615efd300defb76494f5", + "zh:bda9e90c8547d90c9c573206985c5675cc1406047605af037a5069942c3c5966", + "zh:c30a1967de040d00f5038086dd53cdbfb78cc05d1dbc75037410f011bf2a20d8", + "zh:c80bbd1c3f56b3c836d80cf93ac0e8809305c2642f0c98b54bf5d05d3b12718c", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.8.1" + constraints = "~> 3.6" + hashes = [ + "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", + "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", + "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", + "zh:229665ddf060aa0ed315597908483eee5b818a17d09b6417a0f52fd9405c4f57", + "zh:2469d2e48f28076254a2a3fc327f184914566d9e40c5780b8d96ebf7205f8bc0", + "zh:37d7eb334d9561f335e748280f5535a384a88675af9a9eac439d4cfd663bcb66", + "zh:741101426a2f2c52dee37122f0f4a2f2d6af6d852cb1db634480a86398fa3511", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a902473f08ef8df62cfe6116bd6c157070a93f66622384300de235a533e9d4a9", + "zh:b85c511a23e57a2147355932b3b6dce2a11e856b941165793a0c3d7578d94d05", + "zh:c5172226d18eaac95b1daac80172287b69d4ce32750c82ad77fa0768be4ea4b8", + "zh:dab4434dba34aad569b0bc243c2d3f3ff86dd7740def373f2a49816bd2ff819b", + "zh:f49fd62aa8c5525a5c17abd51e27ca5e213881d58882fd42fec4a545b53c9699", + ] +} + +provider "registry.terraform.io/hashicorp/time" { + version = "0.13.1" + constraints = "~> 0.12" + hashes = [ + "h1:ZT5ppCNIModqk3iOkVt5my8b8yBHmDpl663JtXAIRqM=", + "zh:02cb9aab1002f0f2a94a4f85acec8893297dc75915f7404c165983f720a54b74", + "zh:04429b2b31a492d19e5ecf999b116d396dac0b24bba0d0fb19ecaefe193fdb8f", + "zh:26f8e51bb7c275c404ba6028c1b530312066009194db721a8427a7bc5cdbc83a", + "zh:772ff8dbdbef968651ab3ae76d04afd355c32f8a868d03244db3f8496e462690", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:898db5d2b6bd6ca5457dccb52eedbc7c5b1a71e4a4658381bcbb38cedbbda328", + "zh:8de913bf09a3fa7bedc29fec18c47c571d0c7a3d0644322c46f3aa648cf30cd8", + "zh:9402102c86a87bdfe7e501ffbb9c685c32bbcefcfcf897fd7d53df414c36877b", + "zh:b18b9bb1726bb8cfbefc0a29cf3657c82578001f514bcf4c079839b6776c47f0", + "zh:b9d31fdc4faecb909d7c5ce41d2479dd0536862a963df434be4b16e8e4edc94d", + "zh:c951e9f39cca3446c060bd63933ebb89cedde9523904813973fbc3d11863ba75", + "zh:e5b773c0d07e962291be0e9b413c7a22c044b8c7b58c76e8aa91d1659990dfb5", + ] +} + +provider "registry.terraform.io/kreuzwerker/docker" { + version = "3.9.0" + constraints = "~> 3.0" + hashes = [ + "h1:p65AjYSOmmHPjKkIYlEnxSMyrprTHKf1qBzKhCnCtG8=", + "zh:0ead8281830e9b9496651282235d9a139ba1b1b6ff79e395eb8c78658dc446b9", + "zh:0f17d37d8d3872df3fb75c68b5272e0c981343f53b506a9675b4405191edd3ef", + "zh:11d50b37323874427c6d2a08b737d3c7707c8301fdd236c94485cf2828d0b14b", + "zh:32f6f9b847446054e2db3d72886ef2f1d1aa51a6d0dac42340b07dad18e3f28f", + "zh:5ea5c67668b5dcbda560dc6104b788a9bfc974d52f02f7886889b77cc0e5d248", + "zh:5fb19a0b07edc344cd3ddeeb9cfb3d183089deb7a6a94a7b22a583aa1712596b", + "zh:602a7ece444e2a142ec5245abb98e7a1a990a68afae2df63b6c85ec084f0c5d7", + "zh:693dce278524ad8a6d6c9dd7a01bcd63bb85189639198f8d0b044ab0e5099401", + "zh:72e9911568103576c6a78fa38841cfd45eeb88ad22a2c649eb140a377a5b3c26", + "zh:956b62b6857cbb467b50158601f01b1203daa34cbd447dcc7f044c327e878b68", + "zh:9d372bac0d4479868b34485fb4966ba7bb525938f818b6a625f4977004ea83f9", + "zh:e06658a51427f9f53dbdb06263406fc1bc56d1a4fb5e7eb660d7cdfc22f596bd", + "zh:eee38dadf672b946419af25160eae7c03fc2afbb14f39f2f1d2a7404d647e2f7", + ] +} diff --git a/terraform/aws/README.md b/terraform/aws/README.md index efdbe57..0091be8 100644 --- a/terraform/aws/README.md +++ b/terraform/aws/README.md @@ -40,7 +40,6 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | Name | Version | |------|---------| | [aws](#provider\_aws) | ~> 5.0 | -| [time](#provider\_time) | ~> 0.12 | ## Modules @@ -57,17 +56,12 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | Name | Type | |------|------| -| [aws_apprunner_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_service) | resource | | [aws_ecr_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource | -| [aws_iam_role.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy_attachment.apprunner](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [time_sleep.access_iam_role_propagation](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [aws_lightsail_container_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_container_service) | resource | +| [aws_lightsail_container_service_deployment_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_container_service_deployment_version) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ecr_authorization_token.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecr_authorization_token) | data source | -| [aws_iam_policy_document.app_role_assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apprunner](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | @@ -82,8 +76,8 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | [application\_build\_labels](#input\_application\_build\_labels) | The labels to apply to the application build image | `map(string)` |
{
"org.opencontainers.image.authors": "DocuSign Inc.",
"org.opencontainers.image.description": "This reference implementation models the implementation of connected fields functionalities in an extension app.",
"org.opencontainers.image.licenses": "MIT",
"org.opencontainers.image.source": "https://github.com/docusign/extension-app-connected-fields-reference-implementation",
"org.opencontainers.image.title": "Connected Fields Extension App Reference Implementation",
"org.opencontainers.image.vendor": "DocuSign Inc."
} | no |
| [application\_build\_paths](#input\_application\_build\_paths) | Paths of files relative to the build context, changes to which lead to a rebuild of the image. Supported pattern matches are the same as for the `fileset` Terraform function (https://developer.hashicorp.com/terraform/language/functions/fileset). | `list(string)` | [| no | | [application\_environment\_mode](#input\_application\_environment\_mode) | The environment mode for the application | `string` | `"production"` | no | -| [application\_instance\_cpu](#input\_application\_instance\_cpu) | The number of CPU units to allocate to the application instance | `string` | `"256"` | no | -| [application\_instance\_memory](#input\_application\_instance\_memory) | The amount of memory to allocate to the application instance | `string` | `"512"` | no | +| [application\_instance\_power](#input\_application\_instance\_power) | The power specification for the Lightsail container service instance | `string` | `"nano"` | no | +| [application\_instance\_scale](#input\_application\_instance\_scale) | The number of Lightsail container service instances to run | `number` | `1` | no | | [application\_jwt\_secret\_key](#input\_application\_jwt\_secret\_key) | The secret key to use for signing JWT tokens. If empty, a random key will be generated. | `string` | `""` | no | | [application\_name](#input\_application\_name) | The name of the application | `string` | `"extension-app-connected-fields"` | no | | [application\_oauth\_client\_id](#input\_application\_oauth\_client\_id) | The OAuth client ID for the application. If empty, a random client ID will be generated. | `string` | `""` | no | diff --git a/terraform/aws/apprunner.tf b/terraform/aws/apprunner.tf deleted file mode 100644 index 46fb6c7..0000000 --- a/terraform/aws/apprunner.tf +++ /dev/null @@ -1,86 +0,0 @@ -locals { - iam_role_name_separator = "-" - application_service_protocol = "https" - application_service_url = join("://", [local.application_service_protocol, aws_apprunner_service.this.service_url]) -} - -data "aws_iam_policy_document" "app_role_assume_role_policy" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["tasks.apprunner.amazonaws.com"] - } - } -} - -resource "aws_iam_role" "instance" { - name = join(local.iam_role_name_separator, compact([var.application_name, local.region, "instance"])) - assume_role_policy = data.aws_iam_policy_document.app_role_assume_role_policy.json -} - -data "aws_iam_policy_document" "apprunner" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = [ - "build.apprunner.amazonaws.com", - "tasks.apprunner.amazonaws.com", - ] - } - } -} - -resource "aws_iam_role" "access" { - name = join(local.iam_role_name_separator, [var.application_name, local.region, "access"]) - assume_role_policy = data.aws_iam_policy_document.apprunner.json -} - -# workaround for https://github.com/hashicorp/terraform-provider-aws/issues/6566 -resource "time_sleep" "access_iam_role_propagation" { - create_duration = "10s" - - triggers = { - name = aws_iam_role.access.name - } -} - -resource "aws_iam_role_policy_attachment" "apprunner" { - role = time_sleep.access_iam_role_propagation.triggers["name"] - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess" -} - -resource "aws_apprunner_service" "this" { - service_name = var.application_name - - source_configuration { - auto_deployments_enabled = false - - authentication_configuration { - access_role_arn = aws_iam_role.access.arn - } - - image_repository { - image_repository_type = "ECR" - image_identifier = module.image.app_image_name - image_configuration { - port = var.application_port - runtime_environment_variables = { - JWT_SECRET_KEY = local.application_jwt_secret_key - OAUTH_CLIENT_ID = local.application_oauth_client_id - OAUTH_CLIENT_SECRET = local.application_oauth_client_secret - AUTHORIZATION_CODE = local.application_authorization_code - } - } - } - } - - instance_configuration { - instance_role_arn = aws_iam_role.instance.arn - cpu = var.application_instance_cpu - memory = var.application_instance_memory - } -} diff --git a/terraform/aws/ecr.tf b/terraform/aws/ecr.tf index 66a749b..e8f1d9c 100644 --- a/terraform/aws/ecr.tf +++ b/terraform/aws/ecr.tf @@ -42,6 +42,20 @@ data "aws_iam_policy_document" "ecr" { ] } } + + statement { + actions = [ + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", + ] + + principals { + type = "AWS" + identifiers = [ + aws_lightsail_container_service.this.private_registry_access[0].ecr_image_puller_role[0].principal_arn, + ] + } + } } resource "aws_ecr_repository_policy" "this" { diff --git a/terraform/aws/lightsail.tf b/terraform/aws/lightsail.tf new file mode 100644 index 0000000..050ba00 --- /dev/null +++ b/terraform/aws/lightsail.tf @@ -0,0 +1,47 @@ +locals { + application_service_url = trimsuffix(aws_lightsail_container_service.this.url, "/") +} + +resource "aws_lightsail_container_service" "this" { + name = var.application_name + power = var.application_instance_power + scale = var.application_instance_scale + + private_registry_access { + ecr_image_puller_role { + is_active = true + } + } + + tags = local.tags +} + +resource "aws_lightsail_container_service_deployment_version" "this" { + container { + container_name = var.application_name + image = module.image.app_image_name + + environment = { + JWT_SECRET_KEY = local.application_jwt_secret_key + OAUTH_CLIENT_ID = local.application_oauth_client_id + OAUTH_CLIENT_SECRET = local.application_oauth_client_secret + AUTHORIZATION_CODE = local.application_authorization_code + } + + ports = { + (var.application_port) = "HTTP" + } + } + + public_endpoint { + container_name = var.application_name + container_port = var.application_port + + health_check { + path = "/" + success_codes = "200-499" + } + } + + service_name = aws_lightsail_container_service.this.name +} diff --git a/terraform/aws/variables.tf b/terraform/aws/variables.tf index 2960aea..f6364ff 100644 --- a/terraform/aws/variables.tf +++ b/terraform/aws/variables.tf @@ -103,59 +103,27 @@ variable "application_build_labels" { } } -variable "application_instance_cpu" { - description = "The number of CPU units to allocate to the application instance" +variable "application_instance_power" { + description = "The power specification for the Lightsail container service instance" type = string nullable = false - default = "256" + default = "nano" validation { - condition = contains( - [ - "256", - "512", - "1024", - "2048", - "4096", - "0.25 vCPU", - "0.5 vCPU", - "1 vCPU", - "2 vCPU", - "4 vCPU", - ], var.application_instance_cpu) - error_message = "The number of CPU units must be one of '256', '512', '1024', '2048', '4096', '0.25 vCPU', '0.5 vCPU', '1 vCPU', '2 vCPU', or '4 vCPU'" + condition = contains(["nano", "micro", "small", "medium", "large", "xlarge"], var.application_instance_power) + error_message = "The instance power must be one of 'nano', 'micro', 'small', 'medium', 'large', or 'xlarge'" } } -variable "application_instance_memory" { - description = "The amount of memory to allocate to the application instance" - type = string +variable "application_instance_scale" { + description = "The number of Lightsail container service instances to run" + type = number nullable = false - default = "512" + default = 1 validation { - condition = contains( - [ - "512", - "1024", - "2048", - "3072", - "4096", - "6144", - "8192", - "10240", - "12288", - "0.5 GB", - "1 GB", - "2 GB", - "3 GB", - "4 GB", - "6 GB", - "8 GB", - "10 GB", - "12 GB", - ], var.application_instance_memory) - error_message = "The amount of memory must be one of '512', '1024', '2048', '3072', '4096', '6144', '8192', '10240', '12288', '0.5 GB', '1 GB', '2 GB', '3 GB', '4 GB', '6 GB', '8 GB', '10 GB', or '12 GB'" + condition = var.application_instance_scale >= 1 && var.application_instance_scale <= 20 + error_message = "The instance scale must be between 1 and 20" } }
"public/**",
"src/**",
"views/**",
"package.json",
"tsconfig.json",
"Dockerfile",
".dockerignore"
]