diff --git a/README.md b/README.md index ae785f82..f90d1434 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [Atlantis](https://www.runatlantis.io/) is tool which provides unified workflow for collaborating on Terraform through GitHub, GitLab and Bitbucket Cloud. +> [!CAUTION] > Before using Atlantis and the code in this repository, please make sure that you have read and understood the security implications described in [the official Atlantis documentation](https://www.runatlantis.io/docs/security.html). ## Usage @@ -20,7 +21,8 @@ The Atlantis module creates all resources required to run Atlantis on AWS Fargat module "atlantis" { source = "terraform-aws-modules/atlantis/aws" - name = "atlantis" + name = "atlantis" + vpc_id = "vpc-1234556abcdef" # ECS Container Definition atlantis = { @@ -48,6 +50,8 @@ module "atlantis" { # ECS Service service = { + subnet_ids = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] + task_exec_secret_arns = [ "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i", "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F", @@ -57,11 +61,13 @@ module "atlantis" { AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" } } - service_subnets = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] - vpc_id = "vpc-1234556abcdef" # ALB - alb_subnets = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] + alb = { + subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] + } + + # ACM certificate_domain_name = "example.com" route53_zone_id = "Z2ES7B9AZ6SHAE" @@ -80,7 +86,8 @@ The Atlantis module creates most of resources required to run Atlantis on AWS Fa module "atlantis" { source = "terraform-aws-modules/atlantis/aws" - name = "atlantis" + name = "atlantis" + vpc_id = "vpc-1234556abcdef" # Existing cluster create_cluster = false @@ -117,6 +124,8 @@ module "atlantis" { # ECS Service service = { + subnet_ids = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] + task_exec_secret_arns = [ "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i", "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F", @@ -126,8 +135,6 @@ module "atlantis" { AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" } } - service_subnets = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] - vpc_id = "vpc-1234556abcdef" tags = { Environment = "dev" @@ -210,8 +217,8 @@ module "atlantis" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | ~> 5.0 | +| [terraform](#requirement\_terraform) | >= 1.10 | +| [aws](#requirement\_aws) | >= 6.19 | ## Providers @@ -221,11 +228,11 @@ No providers. | Name | Source | Version | |------|--------|---------| -| [acm](#module\_acm) | terraform-aws-modules/acm/aws | 5.0.0 | -| [alb](#module\_alb) | terraform-aws-modules/alb/aws | 9.1.0 | -| [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 5.11.0 | -| [ecs\_service](#module\_ecs\_service) | terraform-aws-modules/ecs/aws//modules/service | 5.11.0 | -| [efs](#module\_efs) | terraform-aws-modules/efs/aws | 1.3.1 | +| [acm](#module\_acm) | terraform-aws-modules/acm/aws | 6.1.1 | +| [alb](#module\_alb) | terraform-aws-modules/alb/aws | 10.2.0 | +| [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 6.7.0 | +| [ecs\_service](#module\_ecs\_service) | terraform-aws-modules/ecs/aws//modules/service | 6.7.0 | +| [efs](#module\_efs) | terraform-aws-modules/efs/aws | 2.0.0 | ## Resources @@ -235,30 +242,26 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [alb](#input\_alb) | Map of values passed to ALB module definition. See the [ALB module](https://github.com/terraform-aws-modules/terraform-aws-alb) for full list of arguments supported | `any` | `{}` | no | -| [alb\_https\_default\_action](#input\_alb\_https\_default\_action) | Default action for the ALB https listener | `any` |
{
"forward": {
"target_group_key": "atlantis"
}
} | no |
+| [alb](#input\_alb) | Map of values passed to ALB module definition. See the [ALB module](https://github.com/terraform-aws-modules/terraform-aws-alb) for full list of arguments supported | object({
# Load Balancer
access_logs = optional(object({
bucket = string
enabled = optional(bool, true)
prefix = optional(string)
}))
connection_logs = optional(object({
bucket = string
enabled = optional(bool, true)
prefix = optional(string)
}))
drop_invalid_header_fields = optional(bool, true)
enable_cross_zone_load_balancing = optional(bool, true)
enable_deletion_protection = optional(bool, true)
enable_http2 = optional(bool, true)
enable_waf_fail_open = optional(bool)
enable_zonal_shift = optional(bool, true)
idle_timeout = optional(number)
internal = optional(bool)
ip_address_type = optional(string)
name = optional(string)
preserve_host_header = optional(bool)
security_groups = optional(list(string), [])
subnet_ids = optional(list(string), [])
# Listener(s)
default_port = optional(number, 80)
default_protocol = optional(string, "HTTP")
https_listener_ssl_policy = optional(string, "ELBSecurityPolicy-TLS13-1-2-2021-06")
https_default_action = optional(any, {
forward = {
target_group_key = "atlantis"
}
})
https_listener = optional(any, {})
listeners = optional(any, {})
# Target Group(s)
target_groups = optional(any, {})
# Securtity Group(s)
create_security_group = optional(bool, true)
security_group_name = optional(string)
security_group_use_name_prefix = optional(bool, true)
security_group_description = optional(string)
security_group_ingress_rules = optional(map(object({
name = optional(string)
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(string)
ip_protocol = optional(string, "tcp")
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(string)
})),
# Default
{
http = {
from_port = 80
cidr_ipv4 = "0.0.0.0/0"
}
https = {
from_port = 443
cidr_ipv4 = "0.0.0.0/0"
}
}
)
security_group_egress_rules = optional(
map(object({
name = optional(string)
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(string)
ip_protocol = optional(string, "tcp")
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(string)
})),
# Default
{
all = {
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
)
security_group_tags = optional(map(string), {})
# Route53 Record(s)
route53_records = optional(map(object({
zone_id = string
name = optional(string)
type = string
evaluate_target_health = optional(bool, true)
})))
# WAF
associate_web_acl = optional(bool, false)
web_acl_arn = optional(string)
tags = optional(map(string), {})
}) | `{}` | no |
| [alb\_security\_group\_id](#input\_alb\_security\_group\_id) | ID of an existing security group that will be used by ALB. Required if `create_alb` is `false` | `string` | `""` | no |
-| [alb\_subnets](#input\_alb\_subnets) | List of subnets to place ALB in. Required if `create_alb` is `true` | `list(string)` | `[]` | no |
| [alb\_target\_group\_arn](#input\_alb\_target\_group\_arn) | ARN of an existing ALB target group that will be used to route traffic to the Atlantis service. Required if `create_alb` is `false` | `string` | `""` | no |
-| [atlantis](#input\_atlantis) | Map of values passed to Atlantis container definition. See the [ECS container definition module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/container-definition) for full list of arguments supported | `any` | `{}` | no |
-| [atlantis\_gid](#input\_atlantis\_gid) | GID of the atlantis user | `number` | `1000` | no |
-| [atlantis\_uid](#input\_atlantis\_uid) | UID of the atlantis user | `number` | `100` | no |
+| [atlantis](#input\_atlantis) | Map of values passed to Atlantis container definition. See the [ECS container definition module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/container-definition) for full list of arguments supported | object({
uid = optional(string, 100)
gid = optional(string, 1000)
command = optional(list(string))
cpu = optional(number, 2048)
dependsOn = optional(list(object({
condition = string
containerName = string
})))
disableNetworking = optional(bool)
dnsSearchDomains = optional(list(string))
dnsServers = optional(list(string))
dockerLabels = optional(map(string))
dockerSecurityOptions = optional(list(string))
entrypoint = optional(list(string))
environment = optional(list(object({
name = string
value = string
})), [])
environmentFiles = optional(list(object({
type = string
value = string
})))
extraHosts = optional(list(object({
hostname = string
ipAddress = string
})))
firelensConfiguration = optional(object({
type = string
options = optional(map(string))
configFile = optional(object({
type = string
content = string
}))
}))
healthCheck = optional(object({
command = optional(list(string), [])
interval = optional(number, 30)
retries = optional(number, 3)
startPeriod = optional(number)
timeout = optional(number, 5)
}))
hostname = optional(string)
image = optional(string, "ghcr.io/runatlantis/atlantis:latest")
linuxParameters = optional(object({
capabilities = optional(object({
add = optional(list(string))
drop = optional(list(string))
}))
devices = optional(list(object({
containerPath = optional(string)
hostPath = optional(string)
permissions = optional(list(string))
})))
initProcessEnabled = optional(bool)
maxSwap = optional(number)
sharedMemorySize = optional(number)
swappiness = optional(number)
tmpfs = optional(list(object({
containerPath = string
mountOptions = optional(list(string))
size = number
})))
}))
logConfiguration = optional(object({
logDriver = optional(string)
options = optional(map(string))
secretOptions = optional(list(object({
name = string
valueFrom = string
})))
}))
memory = optional(number, 4096)
memoryReservation = optional(number)
mountPoints = optional(list(object({
containerPath = optional(string)
readOnly = optional(bool)
sourceVolume = optional(string)
})))
port = optional(number, 4141)
privileged = optional(bool, false)
readonlyRootFilesystem = optional(bool, false)
repositoryCredentials = optional(object({
credentialsParameter = optional(string)
}))
resourceRequirements = optional(list(object({
type = string
value = string
})))
restartPolicy = optional(object({
enabled = optional(bool, true)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
}),
# Default
{
enabled = true
}
)
secrets = optional(list(object({
name = string
valueFrom = string
})))
startTimeout = optional(number, 30)
stopTimeout = optional(number, 120)
user = optional(string, "atlantis")
volumesFrom = optional(list(object({
readOnly = optional(bool)
sourceContainer = optional(string)
})))
workingDirectory = optional(string)
# CloudWatch Log Group
enable_cloudwatch_logging = optional(bool, true)
create_cloudwatch_log_group = optional(bool, true)
cloudwatch_log_group_use_name_prefix = optional(bool, true)
cloudwatch_log_group_retention_in_days = optional(number, 14)
cloudwatch_log_group_class = optional(string)
cloudwatch_log_group_kms_key_id = optional(string)
}) | `{}` | no |
| [certificate\_arn](#input\_certificate\_arn) | ARN of certificate issued by AWS ACM. If empty, a new ACM certificate will be created and validated using Route53 DNS | `string` | `""` | no |
| [certificate\_domain\_name](#input\_certificate\_domain\_name) | Route53 domain name to use for ACM certificate. Route53 zone for this domain should be created in advance. Specify if it is different from value in `route53_zone_name` | `string` | `""` | no |
-| [cluster](#input\_cluster) | Map of values passed to ECS cluster module definition. See the [ECS cluster module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/cluster) for full list of arguments supported | `any` | `{}` | no |
+| [cluster](#input\_cluster) | Map of values passed to ECS cluster module definition. See the [ECS cluster module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/cluster) for full list of arguments supported | object({
# Cluster
name = optional(string)
configuration = optional(object({
execute_command_configuration = optional(object({
kms_key_id = optional(string)
log_configuration = optional(object({
cloud_watch_encryption_enabled = optional(bool)
cloud_watch_log_group_name = optional(string)
s3_bucket_encryption_enabled = optional(bool)
s3_bucket_name = optional(string)
s3_kms_key_id = optional(string)
s3_key_prefix = optional(string)
}))
logging = optional(string, "OVERRIDE")
}))
managed_storage_configuration = optional(object({
fargate_ephemeral_storage_kms_key_id = optional(string)
kms_key_id = optional(string)
}))
}),
# Default
{
execute_command_configuration = {
log_configuration = {
cloud_watch_log_group_name = "placeholder" # will use CloudWatch log group created by module
}
}
}
)
setting = optional(list(object({
name = string
value = string
})),
# Default
[{
name = "containerInsights"
value = "enabled"
}]
)
# Cloudwatch log group
create_cloudwatch_log_group = optional(bool, true)
cloudwatch_log_group_retention_in_days = optional(number, 90)
cloudwatch_log_group_kms_key_id = optional(string)
cloudwatch_log_group_class = optional(string)
cloudwatch_log_group_tags = optional(map(string), {})
# Capacity providers
default_capacity_provider_strategy = optional(
map(object({
base = optional(number)
name = optional(string) # Will fall back to use map key if not set
weight = optional(number)
})),
# Default
{
FARGATE = {
weight = 100
}
}
)
}) | `{}` | no |
| [cluster\_arn](#input\_cluster\_arn) | ARN of an existing ECS cluster where resources will be created. Required when `create_cluster` is `false` | `string` | `""` | no |
| [create](#input\_create) | Controls if resources should be created (affects nearly all resources) | `bool` | `true` | no |
| [create\_alb](#input\_create\_alb) | Determines whether to create an ALB or not | `bool` | `true` | no |
| [create\_certificate](#input\_create\_certificate) | Determines whether to create an ACM certificate or not. If `false`, `certificate_arn` must be provided | `bool` | `true` | no |
| [create\_cluster](#input\_create\_cluster) | Whether to create an ECS cluster or not | `bool` | `true` | no |
| [create\_route53\_records](#input\_create\_route53\_records) | Determines whether to create Route53 `A` and `AAAA` records for the loadbalancer | `bool` | `true` | no |
-| [efs](#input\_efs) | Map of values passed to EFS module definition. See the [EFS module](https://github.com/terraform-aws-modules/terraform-aws-efs) for full list of arguments supported | `any` | `{}` | no |
+| [efs](#input\_efs) | Map of values passed to EFS module definition. See the [EFS module](https://github.com/terraform-aws-modules/terraform-aws-efs) for full list of arguments supported | object({
name = optional(string)
# File System
availability_zone_name = optional(string)
creation_token = optional(string)
performance_mode = optional(string)
encrypted = optional(bool, true)
kms_key_arn = optional(string)
provisioned_throughput_in_mibps = optional(number)
throughput_mode = optional(string)
lifecycle_policy = optional(object({
transition_to_ia = optional(string)
transition_to_archive = optional(string)
transition_to_primary_storage_class = optional(string)
}))
protection = optional(object({
replication_overwrite = optional(string)
}))
# File System Policy
attach_policy = optional(bool, true)
bypass_policy_lockout_safety_check = optional(bool)
source_policy_documents = optional(list(string), [])
override_policy_documents = optional(list(string), [])
policy_statements = optional(any, {})
deny_nonsecure_transport = optional(bool, true)
deny_nonsecure_transport_via_mount_target = optional(bool, true)
# Mount targets
mount_targets = optional(map(object({
ip_address = optional(string)
ip_address_type = optional(string)
ipv6_address = optional(string)
region = optional(string)
security_groups = optional(list(string), [])
subnet_id = string
})),
# Default
{}
)
# Security Group
create_security_group = optional(bool, true)
security_group_name = optional(string)
security_group_use_name_prefix = optional(bool, true)
security_group_description = optional(string)
security_group_ingress_rules = optional(any, {})
# Access Point(s)
access_points = optional(any, {})
}) | `{}` | no |
| [enable\_efs](#input\_enable\_efs) | Determines whether to create and utilize an EFS filesystem | `bool` | `false` | no |
| [name](#input\_name) | Common name to use on all resources created unless a more specific name is provided | `string` | `"atlantis"` | no |
+| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no |
| [route53\_record\_name](#input\_route53\_record\_name) | Name of Route53 record to create ACM certificate in and main A-record. If null is specified, var.name is used instead. Provide empty string to point root domain name to ALB. | `string` | `null` | no |
| [route53\_zone\_id](#input\_route53\_zone\_id) | Route53 zone ID to use for ACM certificate and Route53 records | `string` | `""` | no |
-| [service](#input\_service) | Map of values passed to ECS service module definition. See the [ECS service module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/service) for full list of arguments supported | `any` | `{}` | no |
-| [service\_subnets](#input\_service\_subnets) | List of subnets to place ECS service within | `list(string)` | `[]` | no |
+| [service](#input\_service) | Map of values passed to ECS service module definition. See the [ECS service module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/service) for full list of arguments supported | object({
capacity_provider_strategy = optional(map(object({
base = optional(number)
capacity_provider = string
weight = optional(number)
})))
deployment_circuit_breaker = optional(object({
enable = bool
rollback = bool
}))
enable_ecs_managed_tags = optional(bool, true)
force_new_deployment = optional(bool, true)
health_check_grace_period_seconds = optional(number)
launch_type = optional(string, "FARGATE")
load_balancer = optional(any, {})
name = optional(string)
assign_public_ip = optional(bool, false)
security_group_ids = optional(list(string), [])
subnet_ids = optional(list(string), [])
platform_version = optional(string)
propagate_tags = optional(string)
timeouts = optional(object({
create = optional(string)
delete = optional(string)
update = optional(string)
}))
triggers = optional(map(string))
wait_for_steady_state = optional(bool)
# Service IAM Role
create_iam_role = optional(bool, true)
iam_role_arn = optional(string)
iam_role_name = optional(string)
iam_role_use_name_prefix = optional(bool, true)
iam_role_path = optional(string)
iam_role_description = optional(string)
iam_role_permissions_boundary = optional(string)
iam_role_tags = optional(map(string), {})
iam_role_statements = optional(list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
})))
# Task Definition
create_task_definition = optional(bool, true)
task_definition_arn = optional(string)
container_definitions = optional(any, {})
cpu = optional(number, 2048)
ephemeral_storage = optional(object({
size_in_gib = number
}))
family = optional(string)
memory = optional(number, 4096)
requires_compatibilities = optional(list(string), ["FARGATE"])
runtime_platform = optional(
object({
cpu_architecture = optional(string)
operating_system_family = optional(string)
}),
# Default
{
operating_system_family = "LINUX"
cpu_architecture = "ARM64"
}
)
volume = optional(any, {})
task_tags = optional(map(string), {})
# Task Execution IAM Role
create_task_exec_iam_role = optional(bool, true)
task_exec_iam_role_arn = optional(string)
task_exec_iam_role_name = optional(string)
task_exec_iam_role_use_name_prefix = optional(bool, true)
task_exec_iam_role_path = optional(string)
task_exec_iam_role_description = optional(string)
task_exec_iam_role_permissions_boundary = optional(string)
task_exec_iam_role_tags = optional(map(string), {})
task_exec_iam_role_policies = optional(map(string), {})
task_exec_iam_role_max_session_duration = optional(number)
# Task Execution IAM Role Policy
create_task_exec_policy = optional(bool, true)
task_exec_ssm_param_arns = optional(list(string), [])
task_exec_secret_arns = optional(list(string), [])
task_exec_iam_statements = optional(list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
})))
# Tasks - IAM role
create_tasks_iam_role = optional(bool, true)
tasks_iam_role_arn = optional(string)
tasks_iam_role_name = optional(string)
tasks_iam_role_use_name_prefix = optional(bool, true)
tasks_iam_role_path = optional(string)
tasks_iam_role_description = optional(string)
tasks_iam_role_permissions_boundary = optional(string)
tasks_iam_role_tags = optional(map(string), {})
tasks_iam_role_policies = optional(map(string), {})
tasks_iam_role_statements = optional(list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
})))
# Security Group
create_security_group = optional(bool, true)
security_group_name = optional(string)
security_group_use_name_prefix = optional(bool, true)
security_group_description = optional(string)
security_group_ingress_rules = optional(any, {})
security_group_egress_rules = optional(any,
{
egress = {
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
)
security_group_tags = optional(map(string), {})
}) | `{}` | no |
| [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no |
| [validate\_certificate](#input\_validate\_certificate) | Determines whether to validate ACM certificate using Route53 DNS. If `false`, certificate will be created but not validated | `bool` | `true` | no |
| [vpc\_id](#input\_vpc\_id) | ID of the VPC where the resources will be provisioned | `string` | `""` | no |
diff --git a/docs/UPGRADE-5.0.md b/docs/UPGRADE-5.0.md
new file mode 100644
index 00000000..daef62ee
--- /dev/null
+++ b/docs/UPGRADE-5.0.md
@@ -0,0 +1,140 @@
+# Upgrade from v4.x to v5.x
+
+Please consult the `examples` directory for reference example configurations. If you find a bug, please open an issue with supporting configuration to reproduce.
+
+## List of backwards incompatible changes
+
+- Minimum supported version of Terraform AWS provider updated to `v6.19` to support the latest resources utilized
+- Minimum supported version of Terraform updated to `v1.10` (min supported version for ACM module used within this module)
+- The underlying `aws_security_group_rule` have been replaced with `aws_vpc_security_group_ingress_rule` and `aws_vpc_security_group_egress_rule` to allow for more flexibility in defining security group rules.
+- The attributes used to construct the container definition(s) have been changed from HCL's norm of `snake_case` to `camelCase` to match the AWS API. There currently isn't a [resource nor data source for the container definition](https://github.com/hashicorp/terraform-provider-aws/issues/17988), so one is constructed entirely from HCL in the `container-definition` sub-module. This definition is then rendered as JSON when presented to the task definition (or task set) APIs. Previously, the variable names used were `snake_case` and then internally converted to `camelCase`. However, this does not allow for [using the `container-definition` sub-module on its own](https://github.com/terraform-aws-modules/terraform-aws-ecs/issues/147) due to the mismatch between casing. Its probably going to trip a few folks up, but hopefully we'll remove this for a data source in the future.
+- `service.task_exec_ssm_param_arns` default of `["arn:aws:ssm:*:*:parameter/*"]` has been removed to prevent unintended permission grants. If you were relying on this default, you will need to explicitly set this variable in your configuration.
+- `service.task_exec_secret_arns` default of `["arn:aws:secretsmanager:*:*:secret:*"]` has been removed to prevent unintended permission grants. If you were relying on this default, you will need to explicitly set this variable in your configuration.
+
+## Additional changes
+
+### Added
+
+- Support for `region` argument to specify the AWS region for the resources created if different from the provider region.
+
+### Modified
+
+- The ALB module used within this module has been updated to `v10.2.0`
+- The ECS cluster and service modules used within this module have been updated to `v6.7.0`
+- The ACM module used within this module has been updated to `v6.1.1`
+- The EFS module used within this module has been updated to `v2.0.0`
+- Variable definitions now contain detailed object types in place of the previously used `any` type
+
+### Removed
+
+- None
+
+### Variable and output changes
+
+1. Removed variables:
+
+ - `atlantis_gid` -> is now `atlantis.group_id` within the `atlantis` object variable
+ - `atlantis_uid` -> is now `atlantis.user_id` within the `atlantis` object variable
+ - `alb_https_default_action` -> replaced by `alb.https_default_action` within the `alb` object variable
+ - `alb_subnets` -> replaced by `alb.subnet_ids` within the `alb` object variable
+ - `service_subnets` -> replaced by `service.subnet_ids` within the `service` object variable
+ - From the `alb` object variable:
+ - `customer_owned_ipv4_pool`
+ - `desync_mitigation_mode`
+ - `dns_record_client_routing_policy`
+ - `enable_tls_version_and_cipher_suite_headers`
+ - `enable_xff_client_port`
+ - `load_balancer_type`
+ - `xff_header_processing_mode`
+ - From the `service` object variable:
+ - `ignore_task_definition_changes`
+ - `alarms`
+ - `deployment_controller`
+ - `deployment_maximum_percent` - Atlantis only supports 1 running instance
+ - `deployment_minimum_healthy_percent` - Atlantis only supports 1 running instance
+ - `desired_count` - Atlantis only supports 1 running instance
+ - `enable_execute_command`
+ - `ordered_placement_strategy`
+ - `placement_constraints`
+ - `scheduling_strategy`
+ - `service_connect_configuration`
+ - `service_registries`
+ - `container_definition_defaults`
+ - `inference_accelerator`
+ - `ipc_mode`
+ - `pid_mode`
+ - `task_definition_placement_constraints`
+ - `proxy_configuration`
+ - `skip_destroy`
+ - `external_id`
+ - `scale`
+ - `force_delete`
+ - `wait_until_stable`
+ - `wait_until_stable_timeout`
+ - `enable_autoscaling`
+ - `autoscaling_min_capacity`
+ - `autoscaling_max_capacity`
+ - `autoscaling_policies`
+ - `autoscaling_scheduled_actions`
+ - From the `atlantis` object variable:
+ - `essential` - now always true
+ - `extra_hosts`
+ - `interactive`
+ - `links`
+ - `pseudo_terminal`
+ - `system_controls`
+ - From the `efs` object variable:
+ - `create_backup_policy`
+ - `enable_backup_policy`
+ - `create_replication_configuration`
+ - `replication_configuration_destination`
+
+2. Renamed variables:
+
+ - `cluster.settings` -> `cluster.setting` (singular)
+ - `cluster.fargate_capacity_providers` -> replaced by `cluster.default_capacity_provider_strategy`
+
+3. Added variables:
+
+ - `region`
+
+4. Removed outputs:
+
+ - None
+
+5. Renamed outputs:
+
+ - None
+
+6. Added outputs:
+
+ - None
+
+## Upgrade Migrations
+
+### Diff of Before vs After
+
+```diff
+ module "atlantis" {
+ source = "terraform-aws-modules/atlantis/aws"
+- version = "4.4.1"
++ version = "5.0.0"
+
+# Truncated for brevity, only the relevant changes shown
+
+- alb_subnets = module.vpc.public_subnets
+alb = {
++ subnet_ids = module.vpc.public_subnets
+ ...
+}
+
+- service_subnets = module.vpc.private_subnets
+service = {
++ subnet_ids = module.vpc.private_subnets
+ ...
+}
+```
+
+### State Move Commands
+
+None - the security group rules will be replaced on apply due to the change from `aws_security_group_rule` to `aws_vpc_security_group_ingress_rule` and `aws_vpc_security_group_egress_rule`
diff --git a/examples/github-complete/README.md b/examples/github-complete/README.md
index 0713a7e0..f1fb3158 100644
--- a/examples/github-complete/README.md
+++ b/examples/github-complete/README.md
@@ -19,8 +19,8 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
-| [aws](#requirement\_aws) | ~> 5.0 |
+| [terraform](#requirement\_terraform) | >= 1.11 |
+| [aws](#requirement\_aws) | >= 6.19 |
| [github](#requirement\_github) | >= 5.0 |
| [random](#requirement\_random) | >= 3.0 |
@@ -28,7 +28,7 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | ~> 5.0 |
+| [aws](#provider\_aws) | >= 6.19 |
| [random](#provider\_random) | >= 3.0 |
## Modules
@@ -37,8 +37,8 @@ Note that this example may create resources which cost money. Run `terraform des
|------|--------|---------|
| [atlantis](#module\_atlantis) | ../../ | n/a |
| [github\_repository\_webhooks](#module\_github\_repository\_webhooks) | ../../modules/github-repository-webhook | n/a |
-| [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 1.0 |
-| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
+| [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 2.0 |
+| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 |
## Resources
diff --git a/examples/github-complete/main.tf b/examples/github-complete/main.tf
index cb387c72..8381399f 100644
--- a/examples/github-complete/main.tf
+++ b/examples/github-complete/main.tf
@@ -34,9 +34,10 @@ locals {
module "atlantis" {
source = "../../"
- name = local.name
+ name = local.name
+ vpc_id = module.vpc.vpc_id
- # ECS
+ # ECS Container Definition
atlantis = {
environment = [
{
@@ -64,7 +65,10 @@ module "atlantis" {
]
}
+ # ECS Service
service = {
+ subnet_ids = module.vpc.private_subnets
+
task_exec_secret_arns = [for sec in module.secrets_manager : sec.secret_arn]
# Provide Atlantis permission necessary to create/destroy resources
tasks_iam_role_policies = {
@@ -74,14 +78,12 @@ module "atlantis" {
# ALB
alb = {
+ subnet_ids = module.vpc.public_subnets
+
# For example only
enable_deletion_protection = false
}
- alb_subnets = module.vpc.public_subnets
- service_subnets = module.vpc.private_subnets
- vpc_id = module.vpc.vpc_id
-
# ACM
certificate_domain_name = "${local.name}.${var.domain}"
route53_zone_id = data.aws_route53_zone.this.id
@@ -125,7 +127,7 @@ resource "random_password" "webhook_secret" {
module "secrets_manager" {
source = "terraform-aws-modules/secrets-manager/aws"
- version = "~> 1.0"
+ version = "~> 2.0"
for_each = {
github-token = {
@@ -137,16 +139,17 @@ module "secrets_manager" {
}
# Secret
- name_prefix = each.key
- recovery_window_in_days = 0 # For example only
- secret_string = each.value.secret_string
+ name_prefix = each.key
+ recovery_window_in_days = 0 # For example only
+ secret_string_wo = each.value.secret_string
+ secret_string_wo_version = 2
tags = local.tags
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
- version = "~> 5.0"
+ version = "~> 6.0"
name = local.name
cidr = local.vpc_cidr
diff --git a/examples/github-complete/versions.tf b/examples/github-complete/versions.tf
index 0b115f06..8427c067 100644
--- a/examples/github-complete/versions.tf
+++ b/examples/github-complete/versions.tf
@@ -1,17 +1,15 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.11"
required_providers {
aws = {
source = "hashicorp/aws"
- version = "~> 5.0"
+ version = ">= 6.19"
}
-
github = {
source = "integrations/github"
version = ">= 5.0"
}
-
random = {
source = "hashicorp/random"
version = ">= 3.0"
diff --git a/examples/github-separate/README.md b/examples/github-separate/README.md
index a0720588..04812ad3 100644
--- a/examples/github-separate/README.md
+++ b/examples/github-separate/README.md
@@ -19,8 +19,8 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
-| [aws](#requirement\_aws) | ~> 5.0 |
+| [terraform](#requirement\_terraform) | >= 1.11 |
+| [aws](#requirement\_aws) | >= 6.19 |
| [github](#requirement\_github) | >= 5.0 |
| [random](#requirement\_random) | >= 3.0 |
@@ -28,20 +28,20 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | ~> 5.0 |
+| [aws](#provider\_aws) | >= 6.19 |
| [random](#provider\_random) | >= 3.0 |
## Modules
| Name | Source | Version |
|------|--------|---------|
-| [alb](#module\_alb) | terraform-aws-modules/alb/aws | 9.1.0 |
+| [alb](#module\_alb) | terraform-aws-modules/alb/aws | 10.2.0 |
| [atlantis](#module\_atlantis) | ../../ | n/a |
| [atlantis\_disabled](#module\_atlantis\_disabled) | ../../ | n/a |
-| [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 5.6.0 |
+| [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 6.7.0 |
| [github\_repository\_webhooks](#module\_github\_repository\_webhooks) | ../../modules/github-repository-webhook | n/a |
-| [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 1.0 |
-| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
+| [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 2.0 |
+| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 |
## Resources
diff --git a/examples/github-separate/main.tf b/examples/github-separate/main.tf
index 4d25ea28..35f89b4d 100644
--- a/examples/github-separate/main.tf
+++ b/examples/github-separate/main.tf
@@ -30,7 +30,8 @@ locals {
module "atlantis" {
source = "../../"
- name = local.name
+ name = local.name
+ vpc_id = module.vpc.vpc_id
# Existing cluster
create_cluster = false
@@ -41,7 +42,7 @@ module "atlantis" {
alb_target_group_arn = module.alb.target_groups["atlantis"].arn
alb_security_group_id = module.alb.security_group_id
- # ECS
+ # ECS Container Definition
atlantis = {
environment = [
{
@@ -70,7 +71,10 @@ module "atlantis" {
fqdn = module.alb.dns_name
}
+ # ECS Service
service = {
+ subnet_ids = module.vpc.private_subnets
+
task_exec_secret_arns = [for sec in module.secrets_manager : sec.secret_arn]
# Provide Atlantis permission necessary to create/destroy resources
tasks_iam_role_policies = {
@@ -78,9 +82,6 @@ module "atlantis" {
}
}
- service_subnets = module.vpc.private_subnets
- vpc_id = module.vpc.vpc_id
-
tags = local.tags
}
@@ -105,21 +106,21 @@ module "atlantis_disabled" {
module "ecs_cluster" {
source = "terraform-aws-modules/ecs/aws//modules/cluster"
- version = "5.6.0"
+ version = "6.7.0"
# Cluster
- cluster_name = local.name
- cluster_settings = {
+ name = local.name
+ setting = [{
name = "containerInsights"
value = "enabled"
- }
+ }]
tags = local.tags
}
module "alb" {
source = "terraform-aws-modules/alb/aws"
- version = "9.1.0"
+ version = "10.2.0"
name = local.name
@@ -192,7 +193,7 @@ resource "random_password" "webhook_secret" {
module "secrets_manager" {
source = "terraform-aws-modules/secrets-manager/aws"
- version = "~> 1.0"
+ version = "~> 2.0"
for_each = {
github-token = {
@@ -204,16 +205,17 @@ module "secrets_manager" {
}
# Secret
- name_prefix = each.key
- recovery_window_in_days = 0 # For example only
- secret_string = each.value.secret_string
+ name_prefix = each.key
+ recovery_window_in_days = 0 # For example only
+ secret_string_wo = each.value.secret_string
+ secret_string_wo_version = 2
tags = local.tags
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
- version = "~> 5.0"
+ version = "~> 6.0"
name = local.name
cidr = local.vpc_cidr
diff --git a/examples/github-separate/versions.tf b/examples/github-separate/versions.tf
index 0b115f06..8427c067 100644
--- a/examples/github-separate/versions.tf
+++ b/examples/github-separate/versions.tf
@@ -1,17 +1,15 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.11"
required_providers {
aws = {
source = "hashicorp/aws"
- version = "~> 5.0"
+ version = ">= 6.19"
}
-
github = {
source = "integrations/github"
version = ">= 5.0"
}
-
random = {
source = "hashicorp/random"
version = ">= 3.0"
diff --git a/main.tf b/main.tf
index 84317650..0eb5bf03 100644
--- a/main.tf
+++ b/main.tf
@@ -4,8 +4,6 @@ locals {
try(var.atlantis.fqdn, module.alb.route53_records["A"].fqdn, null),
module.alb.dns_name,
), "")}"
-
- atlantis_port = try(var.atlantis.port, 4141)
}
################################################################################
@@ -29,36 +27,32 @@ locals {
module "alb" {
source = "terraform-aws-modules/alb/aws"
- version = "9.1.0"
+ version = "10.2.0"
+ region = var.region
create = var.create && var.create_alb
# Load balancer
- access_logs = lookup(var.alb, "access_logs", {})
- customer_owned_ipv4_pool = try(var.alb.customer_owned_ipv4_pool, null)
- desync_mitigation_mode = try(var.alb.desync_mitigation_mode, null)
- dns_record_client_routing_policy = try(var.alb.dns_record_client_routing_policy, null)
- drop_invalid_header_fields = try(var.alb.drop_invalid_header_fields, true)
- enable_cross_zone_load_balancing = try(var.alb.enable_cross_zone_load_balancing, true)
- enable_deletion_protection = try(var.alb.enable_deletion_protection, true)
- enable_http2 = try(var.alb.enable_http2, null)
- enable_tls_version_and_cipher_suite_headers = try(var.alb.enable_tls_version_and_cipher_suite_headers, null)
- enable_waf_fail_open = try(var.alb.enable_waf_fail_open, null)
- enable_xff_client_port = try(var.alb.enable_xff_client_port, null)
- idle_timeout = try(var.alb.idle_timeout, null)
- internal = try(var.alb.internal, false)
- ip_address_type = try(var.alb.ip_address_type, null)
- load_balancer_type = try(var.alb.load_balancer_type, "application")
- name = try(var.alb.name, var.name)
- preserve_host_header = try(var.alb.preserve_host_header, null)
- security_groups = try(var.alb.security_groups, [])
- subnets = try(var.alb.subnets, var.alb_subnets)
- xff_header_processing_mode = try(var.alb.xff_header_processing_mode, null)
- timeouts = try(var.alb.timeouts, {})
+ access_logs = var.alb.access_logs
+ connection_logs = var.alb.connection_logs
+ drop_invalid_header_fields = var.alb.drop_invalid_header_fields
+ enable_cross_zone_load_balancing = var.alb.enable_cross_zone_load_balancing
+ enable_deletion_protection = var.alb.enable_deletion_protection
+ enable_http2 = var.alb.enable_http2
+ enable_waf_fail_open = var.alb.enable_waf_fail_open
+ enable_zonal_shift = var.alb.enable_zonal_shift
+ idle_timeout = var.alb.idle_timeout
+ internal = var.alb.internal
+ ip_address_type = var.alb.ip_address_type
+ load_balancer_type = "application"
+ name = try(coalesce(var.alb.name, var.name), "")
+ preserve_host_header = var.alb.preserve_host_header
+ security_groups = var.alb.security_groups
+ subnets = var.alb.subnet_ids
# Listener(s)
- default_port = try(var.alb.default_port, 80)
- default_protocol = try(var.alb.default_protocol, "HTTP")
+ default_port = var.alb.default_port
+ default_protocol = var.alb.default_protocol
listeners = merge(
{
http-https-redirect = {
@@ -76,27 +70,26 @@ module "alb" {
{
port = 443
protocol = "HTTPS"
- ssl_policy = try(var.alb.https_listener_ssl_policy, "ELBSecurityPolicy-TLS13-1-2-Res-2021-06")
+ ssl_policy = var.alb.https_listener_ssl_policy
certificate_arn = var.create_certificate ? module.acm.acm_certificate_arn : var.certificate_arn
},
- var.alb_https_default_action,
- lookup(var.alb, "https_listener", {})
+ var.alb.https_default_action,
+ var.alb.https_listener,
)
},
- lookup(var.alb, "listeners", {})
+ var.alb.listeners
)
# Target group(s)
target_groups = merge(
{
atlantis = {
- name = var.name
- protocol = "HTTP"
- port = local.atlantis_port
- create_attachment = false
- target_type = "ip"
- deregistration_delay = 10
- load_balancing_cross_zone_enabled = true
+ name = var.name
+ protocol = "HTTP"
+ port = var.atlantis.port
+ create_attachment = false
+ target_type = "ip"
+ deregistration_delay = 10
health_check = {
enabled = true
@@ -111,54 +104,32 @@ module "alb" {
}
}
},
- lookup(var.alb, "target_groups", {})
+ var.alb.target_groups
)
# Security group
- create_security_group = try(var.alb.create_security_group, true)
- security_group_name = try(var.alb.security_group_name, var.name)
- security_group_use_name_prefix = try(var.alb.security_group_use_name_prefix, true)
- security_group_description = try(var.alb.security_group_description, null)
+ create_security_group = var.alb.create_security_group
+ security_group_name = try(coalesce(var.alb.security_group_name, var.name), "")
+ security_group_use_name_prefix = var.alb.security_group_use_name_prefix
+ security_group_description = var.alb.security_group_description
vpc_id = var.vpc_id
- security_group_ingress_rules = lookup(var.alb, "security_group_ingress_rules",
- {
- http = {
- from_port = 80
- to_port = 80
- ip_protocol = "tcp"
- cidr_ipv4 = "0.0.0.0/0"
- }
- https = {
- from_port = 443
- to_port = 443
- ip_protocol = "tcp"
- cidr_ipv4 = "0.0.0.0/0"
- }
- }
- )
- security_group_egress_rules = lookup(var.alb, "security_group_egress_rules",
- {
- all = {
- ip_protocol = "-1"
- cidr_ipv4 = "0.0.0.0/0"
- }
- }
- )
- security_group_tags = try(var.alb.security_group_tags, {})
+ security_group_ingress_rules = var.alb.security_group_ingress_rules
+ security_group_egress_rules = var.alb.security_group_egress_rules
+ security_group_tags = var.alb.security_group_tags
# Route53 record(s)
route53_records = merge(
{ for k, v in local.route53_records : k => v if var.create_route53_records },
- lookup(var.alb, "route53_records", {})
+ var.alb.route53_records
)
# WAF
- associate_web_acl = try(var.alb.associate_web_acl, false)
- web_acl_arn = try(var.alb.web_acl_arn, null)
+ associate_web_acl = var.alb.associate_web_acl
+ web_acl_arn = var.alb.web_acl_arn
tags = merge(
- try(var.alb.tags, {}),
- var.tags
+ var.tags,
+ var.alb.tags,
)
}
@@ -168,8 +139,9 @@ module "alb" {
module "acm" {
source = "terraform-aws-modules/acm/aws"
- version = "5.0.0"
+ version = "6.1.1"
+ region = var.region
create_certificate = var.create && var.create_certificate && var.create_alb
domain_name = var.certificate_domain_name
@@ -190,275 +162,238 @@ locals {
containerPath = local.mount_path
sourceVolume = "efs"
readOnly = false
- }] : try(var.atlantis.mount_points, [])
-
- # Ref https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/383
- deployment_maximum_percent = var.enable_efs ? 100 : 200
- deployment_minimum_healthy_percent = var.enable_efs ? 0 : 66
+ }] : var.atlantis.mountPoints
}
module "ecs_cluster" {
source = "terraform-aws-modules/ecs/aws//modules/cluster"
- version = "5.11.0"
+ version = "6.7.0"
+ region = var.region
create = var.create && var.create_cluster
# Cluster
- cluster_name = try(var.cluster.name, var.name)
- cluster_configuration = try(var.cluster.configuration, {})
- cluster_settings = try(var.cluster.settings, {
- name = "containerInsights"
- value = "enabled"
- }
- )
+ name = try(coalesce(var.cluster.name, var.name))
+ configuration = var.cluster.configuration
+ setting = var.cluster.setting
# Cloudwatch log group
- create_cloudwatch_log_group = try(var.cluster.create_cloudwatch_log_group, true)
- cloudwatch_log_group_retention_in_days = try(var.cluster.cloudwatch_log_group_retention_in_days, 90)
- cloudwatch_log_group_kms_key_id = try(var.cluster.cloudwatch_log_group_kms_key_id, null)
- cloudwatch_log_group_tags = try(var.cluster.cloudwatch_log_group_tags, {})
+ create_cloudwatch_log_group = var.cluster.create_cloudwatch_log_group
+ cloudwatch_log_group_retention_in_days = var.cluster.cloudwatch_log_group_retention_in_days
+ cloudwatch_log_group_kms_key_id = var.cluster.cloudwatch_log_group_kms_key_id
+ cloudwatch_log_group_class = var.cluster.cloudwatch_log_group_class
+ cloudwatch_log_group_tags = var.cluster.cloudwatch_log_group_tags
# Capacity providers
- fargate_capacity_providers = try(var.cluster.fargate_capacity_providers, {})
+ default_capacity_provider_strategy = var.cluster.default_capacity_provider_strategy
tags = var.tags
}
module "ecs_service" {
source = "terraform-aws-modules/ecs/aws//modules/service"
- version = "5.11.0"
+ version = "6.7.0"
+ region = var.region
create = var.create
# Service
- ignore_task_definition_changes = try(var.service.ignore_task_definition_changes, false)
- alarms = try(var.service.alarms, {})
- capacity_provider_strategy = try(var.service.capacity_provider_strategy, {})
+ capacity_provider_strategy = var.service.capacity_provider_strategy
cluster_arn = var.create_cluster && var.create ? module.ecs_cluster.arn : var.cluster_arn
- deployment_controller = try(var.service.deployment_controller, {})
- deployment_maximum_percent = try(var.service.deployment_maximum_percent, local.deployment_maximum_percent)
- deployment_minimum_healthy_percent = try(var.service.deployment_minimum_healthy_percent, local.deployment_minimum_healthy_percent)
- desired_count = try(var.service.desired_count, 1)
- enable_ecs_managed_tags = try(var.service.enable_ecs_managed_tags, true)
- enable_execute_command = try(var.service.enable_execute_command, false)
- force_new_deployment = try(var.service.force_new_deployment, true)
- health_check_grace_period_seconds = try(var.service.health_check_grace_period_seconds, null)
- launch_type = try(var.service.launch_type, "FARGATE")
+ deployment_circuit_breaker = var.service.deployment_circuit_breaker
+ deployment_maximum_percent = 100
+ deployment_minimum_healthy_percent = 0
+ desired_count = 1
+ enable_ecs_managed_tags = var.service.enable_ecs_managed_tags
+ enable_execute_command = false
+ force_new_deployment = var.service.force_new_deployment
+ health_check_grace_period_seconds = var.service.health_check_grace_period_seconds
+ launch_type = var.service.launch_type
load_balancer = merge(
{
service = {
- target_group_arn = var.create_alb && var.create ? module.alb.target_groups["atlantis"].arn : var.alb_target_group_arn
+ target_group_arn = var.create && var.create_alb ? module.alb.target_groups["atlantis"].arn : var.alb_target_group_arn
container_name = "atlantis"
- container_port = local.atlantis_port
+ container_port = var.atlantis.port
}
},
- lookup(var.service, "load_balancer", {})
+ var.service.load_balancer
)
- name = try(var.service.name, var.name)
- assign_public_ip = try(var.service.assign_public_ip, false)
- security_group_ids = try(var.service.security_group_ids, [])
- subnet_ids = try(var.service.subnet_ids, var.service_subnets)
- ordered_placement_strategy = try(var.service.ordered_placement_strategy, {})
- placement_constraints = try(var.service.placement_constraints, {})
- platform_version = try(var.service.platform_version, null)
- propagate_tags = try(var.service.propagate_tags, null)
- scheduling_strategy = try(var.service.scheduling_strategy, null)
- service_connect_configuration = lookup(var.service, "service_connect_configuration", {})
- service_registries = lookup(var.service, "service_registries", {})
- timeouts = try(var.service.timeouts, {})
- triggers = try(var.service.triggers, {})
- wait_for_steady_state = try(var.service.wait_for_steady_state, null)
+ name = try(coalesce(var.service.name, var.name))
+ assign_public_ip = var.service.assign_public_ip
+ security_group_ids = var.service.security_group_ids
+ subnet_ids = var.service.subnet_ids
+ platform_version = var.service.platform_version
+ propagate_tags = var.service.propagate_tags
+ timeouts = var.service.timeouts
+ triggers = var.service.triggers
+ wait_for_steady_state = var.service.wait_for_steady_state
# Service IAM role
- create_iam_role = try(var.service.create_iam_role, true)
- iam_role_arn = try(var.service.iam_role_arn, null)
- iam_role_name = try(var.service.iam_role_name, null)
- iam_role_use_name_prefix = try(var.service.iam_role_use_name_prefix, true)
- iam_role_path = try(var.service.iam_role_path, null)
- iam_role_description = try(var.service.iam_role_description, null)
- iam_role_permissions_boundary = try(var.service.iam_role_permissions_boundary, null)
- iam_role_tags = try(var.service.iam_role_tags, {})
- iam_role_statements = lookup(var.service, "iam_role_statements", {})
+ create_iam_role = var.service.create_iam_role
+ iam_role_arn = var.service.iam_role_arn
+ iam_role_name = var.service.iam_role_name
+ iam_role_use_name_prefix = var.service.iam_role_use_name_prefix
+ iam_role_path = var.service.iam_role_path
+ iam_role_description = var.service.iam_role_description
+ iam_role_permissions_boundary = var.service.iam_role_permissions_boundary
+ iam_role_tags = var.service.iam_role_tags
+ iam_role_statements = var.service.iam_role_statements
# Task definition
- create_task_definition = try(var.service.create_task_definition, true)
- task_definition_arn = try(var.service.task_definition_arn, null)
+ create_task_definition = var.service.create_task_definition
+ task_definition_arn = var.service.task_definition_arn
container_definitions = merge(
{
atlantis = {
- command = try(var.atlantis.command, [])
- cpu = try(var.atlantis.cpu, 1024)
- dependencies = try(var.atlantis.dependencies, []) # depends_on is a reserved word
- disable_networking = try(var.atlantis.disable_networking, null)
- dns_search_domains = try(var.atlantis.dns_search_domains, [])
- dns_servers = try(var.atlantis.dns_servers, [])
- docker_labels = try(var.atlantis.docker_labels, {})
- docker_security_options = try(var.atlantis.docker_security_options, [])
- enable_execute_command = try(var.atlantis.enable_execute_command, try(var.service.enable_execute_command, false))
- entrypoint = try(var.atlantis.entrypoint, [])
+ command = var.atlantis.command
+ cpu = var.atlantis.cpu
+ dependsOn = var.atlantis.dependsOn
+ disableNetworking = var.atlantis.disableNetworking
+ dnsSearchDomains = var.atlantis.dnsSearchDomains
+ dnsServers = var.atlantis.dnsServers
+ dockerLabels = var.atlantis.dockerLabels
+ dockerSecurityOptions = var.atlantis.dockerSecurityOptions
+ entrypoint = var.atlantis.entrypoint
environment = concat(
[
{
name = "ATLANTIS_PORT"
- value = local.atlantis_port
+ value = var.atlantis.port
},
{
name = "ATLANTIS_ATLANTIS_URL"
value = local.atlantis_url
},
],
- lookup(var.atlantis, "environment", [])
+ var.atlantis.environment
)
- environment_files = try(var.atlantis.environment_files, [])
- essential = try(var.atlantis.essential, true)
- extra_hosts = try(var.atlantis.extra_hosts, [])
- firelens_configuration = try(var.atlantis.firelens_configuration, {})
- health_check = try(var.atlantis.health_check, {})
- hostname = try(var.atlantis.hostname, null)
- image = try(var.atlantis.image, "ghcr.io/runatlantis/atlantis:latest")
- interactive = try(var.atlantis.interactive, false)
- links = try(var.atlantis.links, [])
- linux_parameters = try(var.atlantis.linux_parameters, {})
- log_configuration = lookup(var.atlantis, "log_configuration", {})
- memory = try(var.atlantis.memory, 2048)
- memory_reservation = try(var.atlantis.memory_reservation, null)
- mount_points = local.mount_points
- name = "atlantis"
- port_mappings = [{
+ environmentFiles = var.atlantis.environmentFiles
+ essential = true
+ extraHosts = var.atlantis.extraHosts
+ firelensConfiguration = var.atlantis.firelensConfiguration
+ healthCheck = var.atlantis.healthCheck
+ hostname = var.atlantis.hostname
+ image = var.atlantis.image
+ linuxParameters = var.atlantis.linuxParameters
+ logConfiguration = var.atlantis.logConfiguration
+ memory = var.atlantis.memory
+ memoryReservation = var.atlantis.memoryReservation
+ mountPoints = local.mount_points
+ name = "atlantis"
+ portMappings = [{
name = "atlantis"
- containerPort = local.atlantis_port
- hostPort = local.atlantis_port
+ containerPort = var.atlantis.port
protocol = "tcp"
}]
- privileged = try(var.atlantis.privileged, false)
- pseudo_terminal = try(var.atlantis.pseudo_terminal, false)
- readonly_root_filesystem = try(var.atlantis.readonly_root_filesystem, false)
- repository_credentials = try(var.atlantis.repository_credentials, {})
- resource_requirements = try(var.atlantis.resource_requirements, [])
- secrets = try(var.atlantis.secrets, [])
- start_timeout = try(var.atlantis.start_timeout, 30)
- stop_timeout = try(var.atlantis.stop_timeout, 120)
- system_controls = try(var.atlantis.system_controls, [])
- ulimits = try(var.atlantis.ulimits, [])
- user = try(var.atlantis.user, "${var.atlantis_uid}:${var.atlantis_gid}")
- volumes_from = try(var.atlantis.volumes_from, [])
- working_directory = try(var.atlantis.working_directory, null)
+ privileged = var.atlantis.privileged
+ readonlyRootFilesystem = var.atlantis.readonlyRootFilesystem
+ repositoryCredentials = var.atlantis.repositoryCredentials
+ resourceRequirements = var.atlantis.resourceRequirements
+ restartPolicy = var.atlantis.restartPolicy
+ secrets = var.atlantis.secrets
+ startTimeout = var.atlantis.startTimeout
+ stopTimeout = var.atlantis.stopTimeout
+ user = try(coalesce(var.atlantis.user, "${var.atlantis.uid}:${var.atlantis.gid}"))
+ versionConsistency = "disabled"
+ volumesFrom = var.atlantis.volumesFrom
+ workingDirectory = var.atlantis.workingDirectory
# CloudWatch Log Group
- service = var.name
- enable_cloudwatch_logging = try(var.atlantis.enable_cloudwatch_logging, true)
- create_cloudwatch_log_group = try(var.atlantis.create_cloudwatch_log_group, true)
- cloudwatch_log_group_use_name_prefix = try(var.atlantis.cloudwatch_log_group_use_name_prefix, true)
- cloudwatch_log_group_retention_in_days = try(var.atlantis.cloudwatch_log_group_retention_in_days, 14)
- cloudwatch_log_group_kms_key_id = try(var.atlantis.cloudwatch_log_group_kms_key_id, null)
+ service = try(coalesce(var.service.name, var.name))
+ enable_cloudwatch_logging = var.atlantis.enable_cloudwatch_logging
+ create_cloudwatch_log_group = var.atlantis.create_cloudwatch_log_group
+ cloudwatch_log_group_use_name_prefix = var.atlantis.cloudwatch_log_group_use_name_prefix
+ cloudwatch_log_group_retention_in_days = var.atlantis.cloudwatch_log_group_retention_in_days
+ cloudwatch_log_group_class = var.atlantis.cloudwatch_log_group_class
+ cloudwatch_log_group_kms_key_id = var.atlantis.cloudwatch_log_group_kms_key_id
},
},
- lookup(var.service, "container_definitions", {})
+ var.service.container_definitions
)
- container_definition_defaults = lookup(var.service, "container_definition_defaults", {})
- cpu = try(var.service.cpu, 1024)
- ephemeral_storage = try(var.service.ephemeral_storage, {})
- family = try(var.service.family, null)
- inference_accelerator = try(var.service.inference_accelerator, {})
- ipc_mode = try(var.service.ipc_mode, null)
- memory = try(var.service.memory, 2048)
- network_mode = try(var.service.network_mode, "awsvpc")
- pid_mode = try(var.service.pid_mode, null)
- task_definition_placement_constraints = try(var.service.task_definition_placement_constraints, {})
- proxy_configuration = try(var.service.proxy_configuration, {})
- requires_compatibilities = try(var.service.requires_compatibilities, ["FARGATE"])
- runtime_platform = try(var.service.runtime_platform, {
- operating_system_family = "LINUX"
- cpu_architecture = "X86_64"
- })
- skip_destroy = try(var.service.skip_destroy, null)
- volume = { for k, v in merge(
- {
+ cpu = var.service.cpu
+ ephemeral_storage = var.service.ephemeral_storage
+ family = var.service.family
+ memory = var.service.memory
+ network_mode = "awsvpc"
+ requires_compatibilities = var.service.requires_compatibilities
+ runtime_platform = var.service.runtime_platform
+ track_latest = true
+ volume = merge(
+ { for k, v in {
efs = {
efs_volume_configuration = {
file_system_id = module.efs.id
transit_encryption = "ENABLED"
authorization_config = {
- access_point_id = try(module.efs.access_points["atlantis"].id, null)
+ access_point_id = try(module.efs.access_points["atlantis"].id, "")
iam = "ENABLED"
}
}
}
- },
- lookup(var.service, "volume", {})
- ) : k => v if var.enable_efs }
- task_tags = try(var.service.task_tags, {})
+ } : k => v if var.enable_efs },
+ var.service.volume
+ )
+ task_tags = var.service.task_tags
# Task execution IAM role
- create_task_exec_iam_role = try(var.service.create_task_exec_iam_role, true)
- task_exec_iam_role_arn = try(var.service.task_exec_iam_role_arn, null)
- task_exec_iam_role_name = try(var.service.task_exec_iam_role_name, null)
- task_exec_iam_role_use_name_prefix = try(var.service.task_exec_iam_role_use_name_prefix, true)
- task_exec_iam_role_path = try(var.service.task_exec_iam_role_path, null)
- task_exec_iam_role_description = try(var.service.task_exec_iam_role_description, null)
- task_exec_iam_role_permissions_boundary = try(var.service.task_exec_iam_role_permissions_boundary, null)
- task_exec_iam_role_tags = try(var.service.task_exec_iam_role_tags, {})
- task_exec_iam_role_policies = lookup(var.service, "task_exec_iam_role_policies", {})
- task_exec_iam_role_max_session_duration = try(var.service.task_exec_iam_role_max_session_duration, null)
+ create_task_exec_iam_role = var.service.create_task_exec_iam_role
+ task_exec_iam_role_arn = var.service.task_exec_iam_role_arn
+ task_exec_iam_role_name = var.service.task_exec_iam_role_name
+ task_exec_iam_role_use_name_prefix = var.service.task_exec_iam_role_use_name_prefix
+ task_exec_iam_role_path = var.service.task_exec_iam_role_path
+ task_exec_iam_role_description = var.service.task_exec_iam_role_description
+ task_exec_iam_role_permissions_boundary = var.service.task_exec_iam_role_permissions_boundary
+ task_exec_iam_role_tags = var.service.task_exec_iam_role_tags
+ task_exec_iam_role_policies = var.service.task_exec_iam_role_policies
+ task_exec_iam_role_max_session_duration = var.service.task_exec_iam_role_max_session_duration
# Task execution IAM role policy
- create_task_exec_policy = try(var.service.create_task_exec_policy, true)
- task_exec_ssm_param_arns = try(var.service.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"])
- task_exec_secret_arns = try(var.service.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"])
- task_exec_iam_statements = lookup(var.service, "task_exec_iam_statements", {})
+ create_task_exec_policy = var.service.create_task_exec_policy
+ task_exec_ssm_param_arns = var.service.task_exec_ssm_param_arns
+ task_exec_secret_arns = var.service.task_exec_secret_arns
+ task_exec_iam_statements = var.service.task_exec_iam_statements
# Tasks - IAM role
- create_tasks_iam_role = try(var.service.create_tasks_iam_role, true)
- tasks_iam_role_arn = try(var.service.tasks_iam_role_arn, null)
- tasks_iam_role_name = try(var.service.tasks_iam_role_name, null)
- tasks_iam_role_use_name_prefix = try(var.service.tasks_iam_role_use_name_prefix, true)
- tasks_iam_role_path = try(var.service.tasks_iam_role_path, null)
- tasks_iam_role_description = try(var.service.tasks_iam_role_description, null)
- tasks_iam_role_permissions_boundary = try(var.service.tasks_iam_role_permissions_boundary, null)
- tasks_iam_role_tags = try(var.service.tasks_iam_role_tags, {})
- tasks_iam_role_policies = lookup(var.service, "tasks_iam_role_policies", {})
- tasks_iam_role_statements = lookup(var.service, "tasks_iam_role_statements", {})
-
- # Task set
- external_id = try(var.service.external_id, null)
- scale = try(var.service.scale, {})
- force_delete = try(var.service.force_delete, null)
- wait_until_stable = try(var.service.wait_until_stable, null)
- wait_until_stable_timeout = try(var.service.wait_until_stable_timeout, null)
+ create_tasks_iam_role = var.service.create_tasks_iam_role
+ tasks_iam_role_arn = var.service.tasks_iam_role_arn
+ tasks_iam_role_name = var.service.tasks_iam_role_name
+ tasks_iam_role_use_name_prefix = var.service.tasks_iam_role_use_name_prefix
+ tasks_iam_role_path = var.service.tasks_iam_role_path
+ tasks_iam_role_description = var.service.tasks_iam_role_description
+ tasks_iam_role_permissions_boundary = var.service.tasks_iam_role_permissions_boundary
+ tasks_iam_role_tags = var.service.tasks_iam_role_tags
+ tasks_iam_role_policies = var.service.tasks_iam_role_policies
+ tasks_iam_role_statements = var.service.tasks_iam_role_statements
# Autoscaling
- enable_autoscaling = try(var.service.enable_autoscaling, false)
- autoscaling_min_capacity = try(var.service.autoscaling_min_capacity, 1)
- autoscaling_max_capacity = try(var.service.autoscaling_max_capacity, 10)
- autoscaling_policies = try(var.service.autoscaling_policies, {})
- autoscaling_scheduled_actions = try(var.service.autoscaling_scheduled_actions, {})
+ # Atlantis only supports a single instance
+ enable_autoscaling = false
# Security Group
- create_security_group = try(var.service.create_security_group, true)
- security_group_name = try(var.service.security_group_name, null)
- security_group_use_name_prefix = try(var.service.security_group_use_name_prefix, true)
- security_group_description = try(var.service.security_group_description, null)
- security_group_rules = merge(
+ create_security_group = var.service.create_security_group
+ security_group_name = var.service.security_group_name
+ security_group_use_name_prefix = var.service.security_group_use_name_prefix
+ security_group_description = var.service.security_group_description
+ security_group_ingress_rules = merge(
{
atlantis = {
- type = "ingress"
- from_port = local.atlantis_port
- to_port = local.atlantis_port
- protocol = "tcp"
- source_security_group_id = var.create_alb ? module.alb.security_group_id : var.alb_security_group_id
+ from_port = var.atlantis.port
+ protocol = "tcp"
+ referenced_security_group_id = var.create_alb ? module.alb.security_group_id : var.alb_security_group_id
}
},
- lookup(var.service, "security_group_rules", {
+ var.service.security_group_ingress_rules
+ )
+ security_group_egress_rules = merge(
+ {
egress = {
- type = "egress"
- from_port = 0
- to_port = 0
- protocol = "-1"
- cidr_blocks = ["0.0.0.0/0"]
+ ip_protocol = "-1"
+ cidr_ipv4 = "0.0.0.0/0"
}
- })
+ }
)
- security_group_tags = try(var.service.security_group_tags, {})
+ security_group_tags = var.service.security_group_tags
tags = var.tags
}
@@ -469,91 +404,93 @@ module "ecs_service" {
module "efs" {
source = "terraform-aws-modules/efs/aws"
- version = "1.3.1"
+ version = "2.0.0"
+ region = var.region
create = var.create && var.enable_efs
- name = try(var.efs.name, var.name)
-
- # File system
- availability_zone_name = try(var.efs.availability_zone_name, null)
- creation_token = try(var.efs.creation_token, var.name)
- performance_mode = try(var.efs.performance_mode, null)
- encrypted = try(var.efs.encrypted, true)
- kms_key_arn = try(var.efs.kms_key_arn, null)
- provisioned_throughput_in_mibps = try(var.efs.provisioned_throughput_in_mibps, null)
- throughput_mode = try(var.efs.throughput_mode, null)
- lifecycle_policy = try(var.efs.lifecycle_policy, {})
-
- # File system policy
- attach_policy = try(var.efs.attach_policy, true)
- bypass_policy_lockout_safety_check = try(var.efs.bypass_policy_lockout_safety_check, null)
- source_policy_documents = try(var.efs.source_policy_documents, [])
- override_policy_documents = try(var.efs.override_policy_documents, [])
- policy_statements = concat(
- [{
- actions = [
- "elasticfilesystem:ClientMount",
- "elasticfilesystem:ClientWrite",
- ]
- principals = [
- {
- type = "AWS"
- identifiers = [module.ecs_service.tasks_iam_role_arn]
- }
- ]
- }],
- lookup(var.efs, "policy_statements", [])
+
+ name = try(coalesce(var.efs.name, var.name))
+
+ # File System
+ availability_zone_name = var.efs.availability_zone_name
+ creation_token = try(coalesce(var.efs.creation_token, var.name))
+ performance_mode = var.efs.performance_mode
+ encrypted = var.efs.encrypted
+ kms_key_arn = var.efs.kms_key_arn
+ provisioned_throughput_in_mibps = var.efs.provisioned_throughput_in_mibps
+ throughput_mode = var.efs.throughput_mode
+ lifecycle_policy = var.efs.lifecycle_policy
+ protection = var.efs.protection
+
+ # File System Policy
+ attach_policy = var.efs.attach_policy
+ bypass_policy_lockout_safety_check = var.efs.bypass_policy_lockout_safety_check
+ source_policy_documents = var.efs.source_policy_documents
+ override_policy_documents = var.efs.override_policy_documents
+ policy_statements = merge(
+ {
+ EFSMountWrite = {
+ actions = [
+ "elasticfilesystem:ClientMount",
+ "elasticfilesystem:ClientWrite",
+ ]
+ principals = [
+ {
+ type = "AWS"
+ identifiers = [module.ecs_service.tasks_iam_role_arn]
+ }
+ ]
+ }
+ },
+ var.efs.policy_statements
)
- deny_nonsecure_transport = try(var.efs.deny_nonsecure_transport, true)
+ deny_nonsecure_transport = var.efs.deny_nonsecure_transport
+ deny_nonsecure_transport_via_mount_target = var.efs.deny_nonsecure_transport_via_mount_target
# Mount targets
- mount_targets = lookup(var.efs, "mount_targets", {})
+ mount_targets = var.efs.mount_targets
- # Security group
- create_security_group = try(var.efs.create_security_group, true)
- security_group_name = try(var.efs.security_group_name, "${var.name}-efs-")
- security_group_use_name_prefix = try(var.efs.security_group_use_name_prefix, true)
- security_group_description = try(var.efs.security_group_description, null)
- security_group_vpc_id = try(var.efs.security_group_vpc_id, var.vpc_id)
- security_group_rules = merge(
+ # Security Group
+ create_security_group = var.efs.create_security_group
+ security_group_name = try(coalesce(var.efs.security_group_name, "${var.name}-efs-"))
+ security_group_use_name_prefix = var.efs.security_group_use_name_prefix
+ security_group_description = var.efs.security_group_description
+ security_group_vpc_id = var.vpc_id
+ security_group_ingress_rules = merge(
{
atlantis = {
# relying on the defaults provdied for EFS/NFS (2049/TCP + ingress)
- description = "NFS ingress from Atlantis"
- source_security_group_id = module.ecs_service.security_group_id
+ description = "NFS ingress from Atlantis"
+ referenced_security_group_id = module.ecs_service.security_group_id
}
},
- lookup(var.efs, "security_group_rules", {})
+ var.efs.security_group_ingress_rules
)
- # Access point(s)
+ # Access Point(s)
access_points = merge(
{
atlantis = {
posix_user = {
- gid = var.atlantis_gid
- uid = var.atlantis_uid
+ gid = var.atlantis.gid
+ uid = var.atlantis.uid
}
root_directory = {
path = local.mount_path
creation_info = {
- owner_gid = var.atlantis_gid
- owner_uid = var.atlantis_uid
+ owner_gid = var.atlantis.gid
+ owner_uid = var.atlantis.uid
permissions = "0750"
}
}
}
},
- lookup(var.efs, "access_points", {})
+ var.efs.access_points
)
- # Backup policy
- create_backup_policy = try(var.efs.create_backup_policy, false)
- enable_backup_policy = try(var.efs.enable_backup_policy, false)
-
- # Replication configuration
- create_replication_configuration = try(var.efs.create_replication_configuration, false)
- replication_configuration_destination = try(var.efs.replication_configuration_destination, {})
+ # Backup Policy
+ create_backup_policy = false
+ enable_backup_policy = false
tags = var.tags
}
diff --git a/modules/github-repository-webhook/README.md b/modules/github-repository-webhook/README.md
index f7c2fca9..f9c7b16e 100644
--- a/modules/github-repository-webhook/README.md
+++ b/modules/github-repository-webhook/README.md
@@ -5,7 +5,7 @@
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
+| [terraform](#requirement\_terraform) | >= 1.10 |
| [github](#requirement\_github) | >= 5.0 |
## Providers
diff --git a/modules/github-repository-webhook/versions.tf b/modules/github-repository-webhook/versions.tf
index 51af6b4f..59c89df8 100644
--- a/modules/github-repository-webhook/versions.tf
+++ b/modules/github-repository-webhook/versions.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
github = {
diff --git a/modules/gitlab-repository-webhook/README.md b/modules/gitlab-repository-webhook/README.md
index e6ebc843..68ddb267 100644
--- a/modules/gitlab-repository-webhook/README.md
+++ b/modules/gitlab-repository-webhook/README.md
@@ -5,7 +5,7 @@
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.1 |
+| [terraform](#requirement\_terraform) | >= 1.10 |
| [gitlab](#requirement\_gitlab) | >= 16.0 |
## Providers
diff --git a/modules/gitlab-repository-webhook/versions.tf b/modules/gitlab-repository-webhook/versions.tf
index d5e390fe..8700516a 100644
--- a/modules/gitlab-repository-webhook/versions.tf
+++ b/modules/gitlab-repository-webhook/versions.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 1.1"
+ required_version = ">= 1.10"
required_providers {
gitlab = {
diff --git a/variables.tf b/variables.tf
index f18e1867..3768eb5b 100644
--- a/variables.tf
+++ b/variables.tf
@@ -4,34 +4,22 @@ variable "create" {
default = true
}
-variable "tags" {
- description = "A map of tags to add to all resources"
- type = map(string)
- default = {}
-}
-
variable "name" {
description = "Common name to use on all resources created unless a more specific name is provided"
type = string
default = "atlantis"
}
-variable "atlantis" {
- description = "Map of values passed to Atlantis container definition. See the [ECS container definition module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/container-definition) for full list of arguments supported"
- type = any
- default = {}
-}
-
-variable "atlantis_gid" {
- description = "GID of the atlantis user"
- type = number
- default = 1000
+variable "region" {
+ description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration"
+ type = string
+ default = null
}
-variable "atlantis_uid" {
- description = "UID of the atlantis user"
- type = number
- default = 100
+variable "tags" {
+ description = "A map of tags to add to all resources"
+ type = map(string)
+ default = {}
}
variable "vpc_id" {
@@ -40,6 +28,137 @@ variable "vpc_id" {
default = ""
}
+################################################################################
+# Atlantis
+################################################################################
+
+variable "atlantis" {
+ description = "Map of values passed to Atlantis container definition. See the [ECS container definition module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/container-definition) for full list of arguments supported"
+ type = object({
+ uid = optional(string, 100)
+ gid = optional(string, 1000)
+
+ command = optional(list(string))
+ cpu = optional(number, 2048)
+ dependsOn = optional(list(object({
+ condition = string
+ containerName = string
+ })))
+ disableNetworking = optional(bool)
+ dnsSearchDomains = optional(list(string))
+ dnsServers = optional(list(string))
+ dockerLabels = optional(map(string))
+ dockerSecurityOptions = optional(list(string))
+ entrypoint = optional(list(string))
+ environment = optional(list(object({
+ name = string
+ value = string
+ })), [])
+ environmentFiles = optional(list(object({
+ type = string
+ value = string
+ })))
+ extraHosts = optional(list(object({
+ hostname = string
+ ipAddress = string
+ })))
+ firelensConfiguration = optional(object({
+ type = string
+ options = optional(map(string))
+ configFile = optional(object({
+ type = string
+ content = string
+ }))
+ }))
+ healthCheck = optional(object({
+ command = optional(list(string), [])
+ interval = optional(number, 30)
+ retries = optional(number, 3)
+ startPeriod = optional(number)
+ timeout = optional(number, 5)
+ }))
+ hostname = optional(string)
+ image = optional(string, "ghcr.io/runatlantis/atlantis:latest")
+ linuxParameters = optional(object({
+ capabilities = optional(object({
+ add = optional(list(string))
+ drop = optional(list(string))
+ }))
+ devices = optional(list(object({
+ containerPath = optional(string)
+ hostPath = optional(string)
+ permissions = optional(list(string))
+ })))
+ initProcessEnabled = optional(bool)
+ maxSwap = optional(number)
+ sharedMemorySize = optional(number)
+ swappiness = optional(number)
+ tmpfs = optional(list(object({
+ containerPath = string
+ mountOptions = optional(list(string))
+ size = number
+ })))
+ }))
+ logConfiguration = optional(object({
+ logDriver = optional(string)
+ options = optional(map(string))
+ secretOptions = optional(list(object({
+ name = string
+ valueFrom = string
+ })))
+ }))
+ memory = optional(number, 4096)
+ memoryReservation = optional(number)
+ mountPoints = optional(list(object({
+ containerPath = optional(string)
+ readOnly = optional(bool)
+ sourceVolume = optional(string)
+ })))
+ port = optional(number, 4141)
+ privileged = optional(bool, false)
+ readonlyRootFilesystem = optional(bool, false)
+ repositoryCredentials = optional(object({
+ credentialsParameter = optional(string)
+ }))
+ resourceRequirements = optional(list(object({
+ type = string
+ value = string
+ })))
+ restartPolicy = optional(object({
+ enabled = optional(bool, true)
+ ignoredExitCodes = optional(list(number))
+ restartAttemptPeriod = optional(number)
+ }),
+ # Default
+ {
+ enabled = true
+ }
+ )
+ secrets = optional(list(object({
+ name = string
+ valueFrom = string
+ })))
+ startTimeout = optional(number, 30)
+ stopTimeout = optional(number, 120)
+ user = optional(string, "atlantis")
+ volumesFrom = optional(list(object({
+ readOnly = optional(bool)
+ sourceContainer = optional(string)
+ })))
+ workingDirectory = optional(string)
+
+ # CloudWatch Log Group
+ enable_cloudwatch_logging = optional(bool, true)
+ create_cloudwatch_log_group = optional(bool, true)
+ cloudwatch_log_group_use_name_prefix = optional(bool, true)
+ cloudwatch_log_group_retention_in_days = optional(number, 14)
+ cloudwatch_log_group_class = optional(string)
+ cloudwatch_log_group_kms_key_id = optional(string)
+ })
+ default = {}
+ nullable = false
+}
+
################################################################################
# Load Balancer
################################################################################
@@ -64,64 +183,121 @@ variable "alb_security_group_id" {
variable "alb" {
description = "Map of values passed to ALB module definition. See the [ALB module](https://github.com/terraform-aws-modules/terraform-aws-alb) for full list of arguments supported"
- type = any
- default = {}
-}
+ type = object({
+ # Load Balancer
+ access_logs = optional(object({
+ bucket = string
+ enabled = optional(bool, true)
+ prefix = optional(string)
+ }))
+ connection_logs = optional(object({
+ bucket = string
+ enabled = optional(bool, true)
+ prefix = optional(string)
+ }))
+ drop_invalid_header_fields = optional(bool, true)
+ enable_cross_zone_load_balancing = optional(bool, true)
+ enable_deletion_protection = optional(bool, true)
+ enable_http2 = optional(bool, true)
+ enable_waf_fail_open = optional(bool)
+ enable_zonal_shift = optional(bool, true)
+ idle_timeout = optional(number)
+ internal = optional(bool)
+ ip_address_type = optional(string)
+ name = optional(string)
+ preserve_host_header = optional(bool)
+ security_groups = optional(list(string), [])
+ subnet_ids = optional(list(string), [])
-variable "alb_https_default_action" {
- description = "Default action for the ALB https listener"
- type = any
- default = {
- forward = {
- target_group_key = "atlantis"
- }
- }
-}
+ # Listener(s)
+ default_port = optional(number, 80)
+ default_protocol = optional(string, "HTTP")
+ https_listener_ssl_policy = optional(string, "ELBSecurityPolicy-TLS13-1-2-2021-06")
+ https_default_action = optional(any, {
+ forward = {
+ target_group_key = "atlantis"
+ }
+ })
+ https_listener = optional(any, {})
+ listeners = optional(any, {})
-variable "alb_subnets" {
- description = "List of subnets to place ALB in. Required if `create_alb` is `true`"
- type = list(string)
- default = []
-}
+ # Target Group(s)
+ target_groups = optional(any, {})
-variable "create_route53_records" {
- description = "Determines whether to create Route53 `A` and `AAAA` records for the loadbalancer"
- type = bool
- default = true
-}
+ # Securtity Group(s)
+ create_security_group = optional(bool, true)
+ security_group_name = optional(string)
+ security_group_use_name_prefix = optional(bool, true)
+ security_group_description = optional(string)
+ security_group_ingress_rules = optional(map(object({
+ name = optional(string)
+ cidr_ipv4 = optional(string)
+ cidr_ipv6 = optional(string)
+ description = optional(string)
+ from_port = optional(string)
+ ip_protocol = optional(string, "tcp")
+ prefix_list_id = optional(string)
+ referenced_security_group_id = optional(string)
+ tags = optional(map(string), {})
+ to_port = optional(string)
+ })),
+ # Default
+ {
+ http = {
+ from_port = 80
+ cidr_ipv4 = "0.0.0.0/0"
+ }
+ https = {
+ from_port = 443
+ cidr_ipv4 = "0.0.0.0/0"
+ }
+ }
+ )
+ security_group_egress_rules = optional(
+ map(object({
+ name = optional(string)
+ cidr_ipv4 = optional(string)
+ cidr_ipv6 = optional(string)
+ description = optional(string)
+ from_port = optional(string)
+ ip_protocol = optional(string, "tcp")
+ prefix_list_id = optional(string)
+ referenced_security_group_id = optional(string)
+ tags = optional(map(string), {})
+ to_port = optional(string)
+ })),
+ # Default
+ {
+ all = {
+ ip_protocol = "-1"
+ cidr_ipv4 = "0.0.0.0/0"
+ }
+ }
+ )
+ security_group_tags = optional(map(string), {})
-################################################################################
-# ECS
-################################################################################
+ # Route53 Record(s)
+ route53_records = optional(map(object({
+ zone_id = string
+ name = optional(string)
+ type = string
+ evaluate_target_health = optional(bool, true)
+ })))
-variable "create_cluster" {
- description = "Whether to create an ECS cluster or not"
- type = bool
- default = true
-}
+ # WAF
+ associate_web_acl = optional(bool, false)
+ web_acl_arn = optional(string)
-variable "cluster_arn" {
- description = "ARN of an existing ECS cluster where resources will be created. Required when `create_cluster` is `false`"
- type = string
- default = ""
+ tags = optional(map(string), {})
+ })
+ default = {}
+ nullable = false
}
-variable "cluster" {
- description = "Map of values passed to ECS cluster module definition. See the [ECS cluster module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/cluster) for full list of arguments supported"
- type = any
- default = {}
-}
-
-variable "service" {
- description = "Map of values passed to ECS service module definition. See the [ECS service module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/service) for full list of arguments supported"
- type = any
- default = {}
-}
-
-variable "service_subnets" {
- description = "List of subnets to place ECS service within"
- type = list(string)
- default = []
+variable "create_route53_records" {
+ description = "Determines whether to create Route53 `A` and `AAAA` records for the loadbalancer"
+ type = bool
+ default = true
}
################################################################################
@@ -164,6 +340,266 @@ variable "route53_record_name" {
default = null
}
+################################################################################
+# ECS
+################################################################################
+
+variable "create_cluster" {
+ description = "Whether to create an ECS cluster or not"
+ type = bool
+ default = true
+}
+
+variable "cluster_arn" {
+ description = "ARN of an existing ECS cluster where resources will be created. Required when `create_cluster` is `false`"
+ type = string
+ default = ""
+}
+
+variable "cluster" {
+ description = "Map of values passed to ECS cluster module definition. See the [ECS cluster module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/cluster) for full list of arguments supported"
+ type = object({
+ # Cluster
+ name = optional(string)
+ configuration = optional(object({
+ execute_command_configuration = optional(object({
+ kms_key_id = optional(string)
+ log_configuration = optional(object({
+ cloud_watch_encryption_enabled = optional(bool)
+ cloud_watch_log_group_name = optional(string)
+ s3_bucket_encryption_enabled = optional(bool)
+ s3_bucket_name = optional(string)
+ s3_kms_key_id = optional(string)
+ s3_key_prefix = optional(string)
+ }))
+ logging = optional(string, "OVERRIDE")
+ }))
+ managed_storage_configuration = optional(object({
+ fargate_ephemeral_storage_kms_key_id = optional(string)
+ kms_key_id = optional(string)
+ }))
+ }),
+ # Default
+ {
+ execute_command_configuration = {
+ log_configuration = {
+ cloud_watch_log_group_name = "placeholder" # will use CloudWatch log group created by module
+ }
+ }
+ }
+ )
+ setting = optional(list(object({
+ name = string
+ value = string
+ })),
+ # Default
+ [{
+ name = "containerInsights"
+ value = "enabled"
+ }]
+ )
+
+ # Cloudwatch log group
+ create_cloudwatch_log_group = optional(bool, true)
+ cloudwatch_log_group_retention_in_days = optional(number, 90)
+ cloudwatch_log_group_kms_key_id = optional(string)
+ cloudwatch_log_group_class = optional(string)
+ cloudwatch_log_group_tags = optional(map(string), {})
+
+ # Capacity providers
+ default_capacity_provider_strategy = optional(
+ map(object({
+ base = optional(number)
+ name = optional(string) # Will fall back to use map key if not set
+ weight = optional(number)
+ })),
+ # Default
+ {
+ FARGATE = {
+ weight = 100
+ }
+ }
+ )
+ })
+ default = {}
+}
+
+variable "service" {
+ description = "Map of values passed to ECS service module definition. See the [ECS service module](https://github.com/terraform-aws-modules/terraform-aws-ecs/tree/master/modules/service) for full list of arguments supported"
+ type = object({
+ capacity_provider_strategy = optional(map(object({
+ base = optional(number)
+ capacity_provider = string
+ weight = optional(number)
+ })))
+ deployment_circuit_breaker = optional(object({
+ enable = bool
+ rollback = bool
+ }))
+ enable_ecs_managed_tags = optional(bool, true)
+ force_new_deployment = optional(bool, true)
+ health_check_grace_period_seconds = optional(number)
+ launch_type = optional(string, "FARGATE")
+ load_balancer = optional(any, {})
+ name = optional(string)
+ assign_public_ip = optional(bool, false)
+ security_group_ids = optional(list(string), [])
+ subnet_ids = optional(list(string), [])
+ platform_version = optional(string)
+ propagate_tags = optional(string)
+ timeouts = optional(object({
+ create = optional(string)
+ delete = optional(string)
+ update = optional(string)
+ }))
+ triggers = optional(map(string))
+ wait_for_steady_state = optional(bool)
+
+ # Service IAM Role
+ create_iam_role = optional(bool, true)
+ iam_role_arn = optional(string)
+ iam_role_name = optional(string)
+ iam_role_use_name_prefix = optional(bool, true)
+ iam_role_path = optional(string)
+ iam_role_description = optional(string)
+ iam_role_permissions_boundary = optional(string)
+ iam_role_tags = optional(map(string), {})
+ iam_role_statements = optional(list(object({
+ sid = optional(string)
+ actions = optional(list(string))
+ not_actions = optional(list(string))
+ effect = optional(string)
+ resources = optional(list(string))
+ not_resources = optional(list(string))
+ principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ not_principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ condition = optional(list(object({
+ test = string
+ values = list(string)
+ variable = string
+ })))
+ })))
+
+ # Task Definition
+ create_task_definition = optional(bool, true)
+ task_definition_arn = optional(string)
+ container_definitions = optional(any, {})
+ cpu = optional(number, 2048)
+ ephemeral_storage = optional(object({
+ size_in_gib = number
+ }))
+ family = optional(string)
+ memory = optional(number, 4096)
+ requires_compatibilities = optional(list(string), ["FARGATE"])
+ runtime_platform = optional(
+ object({
+ cpu_architecture = optional(string)
+ operating_system_family = optional(string)
+ }),
+ # Default
+ {
+ operating_system_family = "LINUX"
+ cpu_architecture = "ARM64"
+ }
+ )
+ volume = optional(any, {})
+ task_tags = optional(map(string), {})
+
+ # Task Execution IAM Role
+ create_task_exec_iam_role = optional(bool, true)
+ task_exec_iam_role_arn = optional(string)
+ task_exec_iam_role_name = optional(string)
+ task_exec_iam_role_use_name_prefix = optional(bool, true)
+ task_exec_iam_role_path = optional(string)
+ task_exec_iam_role_description = optional(string)
+ task_exec_iam_role_permissions_boundary = optional(string)
+ task_exec_iam_role_tags = optional(map(string), {})
+ task_exec_iam_role_policies = optional(map(string), {})
+ task_exec_iam_role_max_session_duration = optional(number)
+
+ # Task Execution IAM Role Policy
+ create_task_exec_policy = optional(bool, true)
+ task_exec_ssm_param_arns = optional(list(string), [])
+ task_exec_secret_arns = optional(list(string), [])
+ task_exec_iam_statements = optional(list(object({
+ sid = optional(string)
+ actions = optional(list(string))
+ not_actions = optional(list(string))
+ effect = optional(string)
+ resources = optional(list(string))
+ not_resources = optional(list(string))
+ principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ not_principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ condition = optional(list(object({
+ test = string
+ values = list(string)
+ variable = string
+ })))
+ })))
+
+ # Tasks - IAM role
+ create_tasks_iam_role = optional(bool, true)
+ tasks_iam_role_arn = optional(string)
+ tasks_iam_role_name = optional(string)
+ tasks_iam_role_use_name_prefix = optional(bool, true)
+ tasks_iam_role_path = optional(string)
+ tasks_iam_role_description = optional(string)
+ tasks_iam_role_permissions_boundary = optional(string)
+ tasks_iam_role_tags = optional(map(string), {})
+ tasks_iam_role_policies = optional(map(string), {})
+ tasks_iam_role_statements = optional(list(object({
+ sid = optional(string)
+ actions = optional(list(string))
+ not_actions = optional(list(string))
+ effect = optional(string)
+ resources = optional(list(string))
+ not_resources = optional(list(string))
+ principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ not_principals = optional(list(object({
+ type = string
+ identifiers = list(string)
+ })))
+ condition = optional(list(object({
+ test = string
+ values = list(string)
+ variable = string
+ })))
+ })))
+
+ # Security Group
+ create_security_group = optional(bool, true)
+ security_group_name = optional(string)
+ security_group_use_name_prefix = optional(bool, true)
+ security_group_description = optional(string)
+ security_group_ingress_rules = optional(any, {})
+ security_group_egress_rules = optional(any,
+ {
+ egress = {
+ ip_protocol = "-1"
+ cidr_ipv4 = "0.0.0.0/0"
+ }
+ }
+ )
+ security_group_tags = optional(map(string), {})
+ })
+ default = {}
+}
+
################################################################################
# EFS
################################################################################
@@ -176,6 +612,57 @@ variable "enable_efs" {
variable "efs" {
description = "Map of values passed to EFS module definition. See the [EFS module](https://github.com/terraform-aws-modules/terraform-aws-efs) for full list of arguments supported"
- type = any
- default = {}
+ type = object({
+ name = optional(string)
+
+ # File System
+ availability_zone_name = optional(string)
+ creation_token = optional(string)
+ performance_mode = optional(string)
+ encrypted = optional(bool, true)
+ kms_key_arn = optional(string)
+ provisioned_throughput_in_mibps = optional(number)
+ throughput_mode = optional(string)
+ lifecycle_policy = optional(object({
+ transition_to_ia = optional(string)
+ transition_to_archive = optional(string)
+ transition_to_primary_storage_class = optional(string)
+ }))
+ protection = optional(object({
+ replication_overwrite = optional(string)
+ }))
+
+ # File System Policy
+ attach_policy = optional(bool, true)
+ bypass_policy_lockout_safety_check = optional(bool)
+ source_policy_documents = optional(list(string), [])
+ override_policy_documents = optional(list(string), [])
+ policy_statements = optional(any, {})
+ deny_nonsecure_transport = optional(bool, true)
+ deny_nonsecure_transport_via_mount_target = optional(bool, true)
+
+ # Mount targets
+ mount_targets = optional(map(object({
+ ip_address = optional(string)
+ ip_address_type = optional(string)
+ ipv6_address = optional(string)
+ region = optional(string)
+ security_groups = optional(list(string), [])
+ subnet_id = string
+ })),
+ # Default
+ {}
+ )
+
+ # Security Group
+ create_security_group = optional(bool, true)
+ security_group_name = optional(string)
+ security_group_use_name_prefix = optional(bool, true)
+ security_group_description = optional(string)
+ security_group_ingress_rules = optional(any, {})
+
+ # Access Point(s)
+ access_points = optional(any, {})
+ })
+ default = {}
}
diff --git a/versions.tf b/versions.tf
index a8de733f..e3e52642 100644
--- a/versions.tf
+++ b/versions.tf
@@ -1,10 +1,10 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
- version = "~> 5.0"
+ version = ">= 6.19"
}
}
}