├── .github ├── .gitkeep └── workflows │ ├── lock.yml │ ├── release.yml │ ├── stale-actions.yaml │ ├── pr-title.yml │ └── pre-commit.yml ├── modules ├── gitlab-repository-webhook │ ├── outputs.tf │ ├── versions.tf │ ├── main.tf │ ├── variables.tf │ └── README.md └── github-repository-webhook │ ├── outputs.tf │ ├── versions.tf │ ├── main.tf │ ├── variables.tf │ └── README.md ├── versions.tf ├── examples ├── github-separate │ ├── terraform.tfvars.sample │ ├── versions.tf │ ├── variables.tf │ ├── outputs.tf │ ├── README.md │ └── main.tf ├── github-complete │ ├── terraform.tfvars.sample │ ├── versions.tf │ ├── variables.tf │ ├── outputs.tf │ ├── README.md │ └── main.tf └── README.md ├── .editorconfig ├── .gitignore ├── .releaserc.json ├── outputs.tf ├── .pre-commit-config.yaml ├── docs ├── README.md └── UPGRADE-5.0.md ├── LICENSE ├── main.tf ├── variables.tf ├── README.md └── CHANGELOG.md /.github/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /modules/gitlab-repository-webhook/outputs.tf: -------------------------------------------------------------------------------- 1 | output "repository_webhook_urls" { 2 | description = "Webhook URL" 3 | value = gitlab_project_hook.this[*].url 4 | } 5 | -------------------------------------------------------------------------------- /modules/github-repository-webhook/outputs.tf: -------------------------------------------------------------------------------- 1 | output "repository_webhook_urls" { 2 | description = "Webhook URL" 3 | value = github_repository_webhook.this[*].url 4 | } 5 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.10" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.19" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/github-repository-webhook/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.10" 3 | 4 | required_providers { 5 | github = { 6 | source = "integrations/github" 7 | version = ">= 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/gitlab-repository-webhook/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.10" 3 | 4 | required_providers { 5 | gitlab = { 6 | source = "gitlabhq/gitlab" 7 | version = ">= 16.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/github-separate/terraform.tfvars.sample: -------------------------------------------------------------------------------- 1 | github_token = "ghp_aldkfjadkfjaldfjk" 2 | github_owner = "me" 3 | 4 | atlantis_github_user = "JohnDoe" 5 | # Format is {hostname}/{owner}/{repo} https://www.runatlantis.io/docs/server-configuration.html#repo-allowlist 6 | atlantis_repo_allowlist = ["github.com/johndoe/*"] 7 | repositories = ["myrepo"] 8 | -------------------------------------------------------------------------------- /examples/github-complete/terraform.tfvars.sample: -------------------------------------------------------------------------------- 1 | github_token = "ghp_aldkfjadkfjaldfjk" 2 | github_owner = "me" 3 | 4 | domain = "mydomain.com" 5 | 6 | atlantis_github_user = "JohnDoe" 7 | # Format is {hostname}/{owner}/{repo} https://www.runatlantis.io/docs/server-configuration.html#repo-allowlist 8 | atlantis_repo_allowlist = ["github.com/johndoe/*"] 9 | repositories = ["myrepo"] 10 | -------------------------------------------------------------------------------- /examples/github-complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.11" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.19" 8 | } 9 | github = { 10 | source = "integrations/github" 11 | version = ">= 5.0" 12 | } 13 | random = { 14 | source = "hashicorp/random" 15 | version = ">= 3.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/github-separate/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.11" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 6.19" 8 | } 9 | github = { 10 | source = "integrations/github" 11 | version = ">= 5.0" 12 | } 13 | random = { 14 | source = "hashicorp/random" 15 | version = ">= 3.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Please note - the examples provided serve two primary means: 4 | 5 | 1. Show users working examples of the various ways in which the module can be configured and features supported 6 | 2. A means of testing/validating module changes 7 | 8 | Please do not mistake the examples provided as "best practices". It is up to users to consult the AWS service documentation for best practices, usage recommendations, etc. 9 | -------------------------------------------------------------------------------- /modules/gitlab-repository-webhook/main.tf: -------------------------------------------------------------------------------- 1 | resource "gitlab_project_hook" "this" { 2 | count = var.create ? length(var.repositories) : 0 3 | 4 | project = var.repositories[count.index] 5 | url = var.webhook_url 6 | token = var.webhook_secret 7 | enable_ssl_verification = false 8 | 9 | merge_requests_events = true 10 | push_events = true 11 | note_events = true 12 | } 13 | -------------------------------------------------------------------------------- /modules/github-repository-webhook/main.tf: -------------------------------------------------------------------------------- 1 | resource "github_repository_webhook" "this" { 2 | count = var.create ? length(var.repositories) : 0 3 | 4 | repository = var.repositories[count.index] 5 | 6 | configuration { 7 | url = var.webhook_url 8 | content_type = "application/json" 9 | insecure_ssl = false 10 | secret = var.webhook_secret 11 | } 12 | 13 | events = [ 14 | "issue_comment", 15 | "pull_request", 16 | "pull_request_review", 17 | "pull_request_review_comment", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /modules/gitlab-repository-webhook/variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Whether to create Gitlab repository webhook for Atlantis" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "repositories" { 8 | description = "List of names of repositories which belong to the `gitlab_base_url` specified" 9 | type = list(string) 10 | default = [] 11 | } 12 | 13 | variable "webhook_url" { 14 | description = "Webhook URL" 15 | type = string 16 | default = "" 17 | } 18 | 19 | variable "webhook_secret" { 20 | description = "Webhook secret" 21 | type = string 22 | default = "" 23 | } 24 | -------------------------------------------------------------------------------- /modules/github-repository-webhook/variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Whether to create Github repository webhook for Atlantis" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "repositories" { 8 | description = "List of names of repositories which belong to the owner specified in `github_owner`" 9 | type = list(string) 10 | default = [] 11 | } 12 | 13 | variable "webhook_url" { 14 | description = "Webhook URL" 15 | type = string 16 | default = "" 17 | } 18 | 19 | variable "webhook_secret" { 20 | description = "Webhook secret" 21 | type = string 22 | default = "" 23 | } 24 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Uses editorconfig to maintain consistent coding styles 3 | 4 | # top-most EditorConfig file 5 | root = true 6 | 7 | # Unix-style newlines with a newline ending every file 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | indent_style = space 13 | insert_final_newline = true 14 | max_line_length = 80 15 | trim_trailing_whitespace = true 16 | 17 | [*.{tf,tfvars}] 18 | indent_size = 2 19 | indent_style = space 20 | 21 | [*.md] 22 | max_line_length = 0 23 | trim_trailing_whitespace = false 24 | 25 | [Makefile] 26 | tab_width = 2 27 | indent_style = tab 28 | 29 | [COMMIT_EDITMSG] 30 | max_line_length = 0 31 | -------------------------------------------------------------------------------- /examples/github-separate/variables.tf: -------------------------------------------------------------------------------- 1 | variable "github_token" { 2 | description = "Github token to use when creating webhook" 3 | type = string 4 | } 5 | 6 | variable "github_owner" { 7 | description = "Github owner to use when creating webhook" 8 | type = string 9 | } 10 | 11 | variable "atlantis_github_user" { 12 | description = "GitHub user or organization name" 13 | type = string 14 | } 15 | 16 | variable "atlantis_repo_allowlist" { 17 | description = "List of GitHub repositories that Atlantis will be allowed to access" 18 | type = list(string) 19 | } 20 | 21 | variable "repositories" { 22 | description = "List of GitHub repositories to create webhooks for. This is just the name of the repository, excluding the user or organization" 23 | type = list(string) 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # Terraform lockfile 5 | .terraform.lock.hcl 6 | 7 | # .tfstate files 8 | *.tfstate 9 | *.tfstate.* 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 15 | # password, private keys, and other secrets. These should not be part of version 16 | # control as they are data points which are potentially sensitive and subject 17 | # to change depending on the environment. 18 | *.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Ignore CLI configuration files 28 | .terraformrc 29 | terraform.rc 30 | 31 | # Lambda build artifacts 32 | builds/ 33 | __pycache__/ 34 | *.zip 35 | .tox 36 | 37 | # Local editors/macos files 38 | .DS_Store 39 | .idea 40 | -------------------------------------------------------------------------------- /examples/github-complete/variables.tf: -------------------------------------------------------------------------------- 1 | variable "github_token" { 2 | description = "Github token to use when creating webhook" 3 | type = string 4 | } 5 | 6 | variable "github_owner" { 7 | description = "Github owner to use when creating webhook" 8 | type = string 9 | } 10 | 11 | variable "domain" { 12 | description = "Route53 domain name to use for ACM certificate. Route53 zone for this domain should be created in advance" 13 | type = string 14 | } 15 | 16 | variable "atlantis_github_user" { 17 | description = "GitHub user or organization name" 18 | type = string 19 | } 20 | 21 | variable "atlantis_repo_allowlist" { 22 | description = "List of GitHub repositories that Atlantis will be allowed to access" 23 | type = list(string) 24 | } 25 | 26 | variable "repositories" { 27 | description = "List of GitHub repositories to create webhooks for. This is just the name of the repository, excluding the user or organization" 28 | type = list(string) 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '50 1 * * *' 6 | 7 | jobs: 8 | lock: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: dessant/lock-threads@v5 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | issue-comment: > 15 | I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 16 | If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 17 | issue-inactive-days: '30' 18 | pr-comment: > 19 | I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 20 | If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 21 | pr-inactive-days: '30' 22 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "main", 4 | "master" 5 | ], 6 | "ci": false, 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "conventionalcommits" 12 | } 13 | ], 14 | [ 15 | "@semantic-release/release-notes-generator", 16 | { 17 | "preset": "conventionalcommits" 18 | } 19 | ], 20 | [ 21 | "@semantic-release/github", 22 | { 23 | "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", 24 | "labels": false, 25 | "releasedLabels": false 26 | } 27 | ], 28 | [ 29 | "@semantic-release/changelog", 30 | { 31 | "changelogFile": "CHANGELOG.md", 32 | "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." 33 | } 34 | ], 35 | [ 36 | "@semantic-release/git", 37 | { 38 | "assets": [ 39 | "CHANGELOG.md" 40 | ], 41 | "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 42 | } 43 | ] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "url" { 2 | description = "URL of Atlantis" 3 | value = local.atlantis_url 4 | } 5 | 6 | ################################################################################ 7 | # Load Balancer 8 | ################################################################################ 9 | 10 | output "alb" { 11 | description = "ALB created and all of its associated outputs" 12 | value = module.alb 13 | } 14 | 15 | ################################################################################ 16 | # ECS 17 | ################################################################################ 18 | 19 | output "cluster" { 20 | description = "ECS cluster created and all of its associated outputs" 21 | value = module.ecs_cluster 22 | } 23 | 24 | output "service" { 25 | description = "ECS service created and all of its associated outputs" 26 | value = module.ecs_service 27 | } 28 | 29 | ################################################################################ 30 | # EFS 31 | ################################################################################ 32 | 33 | output "efs" { 34 | description = "EFS created and all of its associated outputs" 35 | value = module.efs 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - master 9 | paths: 10 | - '**/*.tpl' 11 | - '**/*.py' 12 | - '**/*.tf' 13 | - '.github/workflows/release.yml' 14 | 15 | jobs: 16 | release: 17 | name: Release 18 | runs-on: ubuntu-latest 19 | # Skip running release workflow on forks 20 | if: github.repository_owner == 'terraform-aws-modules' 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v5 24 | with: 25 | persist-credentials: false 26 | fetch-depth: 0 27 | 28 | - name: Set correct Node.js version 29 | uses: actions/setup-node@v6 30 | with: 31 | node-version: 24 32 | 33 | - name: Install dependencies 34 | run: | 35 | npm install \ 36 | @semantic-release/changelog@6.0.3 \ 37 | @semantic-release/git@10.0.1 \ 38 | conventional-changelog-conventionalcommits@9.1.0 39 | 40 | - name: Release 41 | uses: cycjimmy/semantic-release-action@v5 42 | with: 43 | semantic_version: 25.0.0 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} 46 | -------------------------------------------------------------------------------- /examples/github-complete/outputs.tf: -------------------------------------------------------------------------------- 1 | output "atlantis_url" { 2 | description = "URL of Atlantis" 3 | value = module.atlantis.url 4 | } 5 | 6 | ################################################################################ 7 | # Load Balancer 8 | ################################################################################ 9 | 10 | output "alb" { 11 | description = "ALB created and all of its associated outputs" 12 | value = module.atlantis.alb 13 | } 14 | 15 | ################################################################################ 16 | # ECS 17 | ################################################################################ 18 | 19 | output "cluster" { 20 | description = "ECS cluster created and all of its associated outputs" 21 | value = module.atlantis.cluster 22 | } 23 | 24 | output "service" { 25 | description = "ECS service created and all of its associated" 26 | value = module.atlantis.service 27 | } 28 | 29 | ################################################################################ 30 | # EFS 31 | ################################################################################ 32 | 33 | output "efs" { 34 | description = "EFS created and all of its associated outputs" 35 | value = module.atlantis.efs 36 | } 37 | -------------------------------------------------------------------------------- /examples/github-separate/outputs.tf: -------------------------------------------------------------------------------- 1 | output "atlantis_url" { 2 | description = "URL of Atlantis" 3 | value = module.atlantis.url 4 | } 5 | 6 | ################################################################################ 7 | # Load Balancer 8 | ################################################################################ 9 | 10 | output "alb" { 11 | description = "ALB created and all of its associated outputs" 12 | value = module.atlantis.alb 13 | } 14 | 15 | ################################################################################ 16 | # ECS 17 | ################################################################################ 18 | 19 | output "cluster" { 20 | description = "ECS cluster created and all of its associated outputs" 21 | value = module.atlantis.cluster 22 | } 23 | 24 | output "service" { 25 | description = "ECS service created and all of its associated" 26 | value = module.atlantis.service 27 | } 28 | 29 | ################################################################################ 30 | # EFS 31 | ################################################################################ 32 | 33 | output "efs" { 34 | description = "EFS created and all of its associated outputs" 35 | value = module.atlantis.efs 36 | } 37 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.103.0 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_docs 7 | args: 8 | - '--args=--lockfile=false' 9 | - id: terraform_tflint 10 | args: 11 | - '--args=--only=terraform_deprecated_interpolation' 12 | - '--args=--only=terraform_deprecated_index' 13 | - '--args=--only=terraform_unused_declarations' 14 | - '--args=--only=terraform_comment_syntax' 15 | - '--args=--only=terraform_documented_outputs' 16 | - '--args=--only=terraform_documented_variables' 17 | - '--args=--only=terraform_typed_variables' 18 | - '--args=--only=terraform_module_pinned_source' 19 | - '--args=--only=terraform_naming_convention' 20 | - '--args=--only=terraform_required_version' 21 | - '--args=--only=terraform_required_providers' 22 | - '--args=--only=terraform_standard_module_structure' 23 | - '--args=--only=terraform_workspace_remote' 24 | - id: terraform_validate 25 | - repo: https://github.com/pre-commit/pre-commit-hooks 26 | rev: v6.0.0 27 | hooks: 28 | - id: check-merge-conflict 29 | - id: end-of-file-fixer 30 | - id: trailing-whitespace 31 | -------------------------------------------------------------------------------- /.github/workflows/stale-actions.yaml: -------------------------------------------------------------------------------- 1 | name: 'Mark or close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v10 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | # Staling issues and PR's 14 | days-before-stale: 30 15 | stale-issue-label: stale 16 | stale-pr-label: stale 17 | stale-issue-message: | 18 | This issue has been automatically marked as stale because it has been open 30 days 19 | with no activity. Remove stale label or comment or this issue will be closed in 10 days 20 | stale-pr-message: | 21 | This PR has been automatically marked as stale because it has been open 30 days 22 | with no activity. Remove stale label or comment or this PR will be closed in 10 days 23 | # Not stale if have this labels or part of milestone 24 | exempt-issue-labels: bug,wip,on-hold 25 | exempt-pr-labels: bug,wip,on-hold 26 | exempt-all-milestones: true 27 | # Close issue operations 28 | # Label will be automatically removed if the issues are no longer closed nor locked. 29 | days-before-close: 10 30 | delete-branch: true 31 | close-issue-message: This issue was automatically closed because of stale in 10 days 32 | close-pr-message: This PR was automatically closed because of stale in 10 days 33 | -------------------------------------------------------------------------------- /modules/gitlab-repository-webhook/README.md: -------------------------------------------------------------------------------- 1 | # Gitlab repository webhook for Atlantis 2 | 3 | 4 | ## Requirements 5 | 6 | | Name | Version | 7 | |------|---------| 8 | | [terraform](#requirement\_terraform) | >= 1.10 | 9 | | [gitlab](#requirement\_gitlab) | >= 16.0 | 10 | 11 | ## Providers 12 | 13 | | Name | Version | 14 | |------|---------| 15 | | [gitlab](#provider\_gitlab) | >= 16.0 | 16 | 17 | ## Modules 18 | 19 | No modules. 20 | 21 | ## Resources 22 | 23 | | Name | Type | 24 | |------|------| 25 | | [gitlab_project_hook.this](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs/resources/project_hook) | resource | 26 | 27 | ## Inputs 28 | 29 | | Name | Description | Type | Default | Required | 30 | |------|-------------|------|---------|:--------:| 31 | | [create](#input\_create) | Whether to create Gitlab repository webhook for Atlantis | `bool` | `true` | no | 32 | | [repositories](#input\_repositories) | List of names of repositories which belong to the `gitlab_base_url` specified | `list(string)` | `[]` | no | 33 | | [webhook\_secret](#input\_webhook\_secret) | Webhook secret | `string` | `""` | no | 34 | | [webhook\_url](#input\_webhook\_url) | Webhook URL | `string` | `""` | no | 35 | 36 | ## Outputs 37 | 38 | | Name | Description | 39 | |------|-------------| 40 | | [repository\_webhook\_urls](#output\_repository\_webhook\_urls) | Webhook URL | 41 | 42 | -------------------------------------------------------------------------------- /modules/github-repository-webhook/README.md: -------------------------------------------------------------------------------- 1 | # Github repository webhook for Atlantis 2 | 3 | 4 | ## Requirements 5 | 6 | | Name | Version | 7 | |------|---------| 8 | | [terraform](#requirement\_terraform) | >= 1.10 | 9 | | [github](#requirement\_github) | >= 5.0 | 10 | 11 | ## Providers 12 | 13 | | Name | Version | 14 | |------|---------| 15 | | [github](#provider\_github) | >= 5.0 | 16 | 17 | ## Modules 18 | 19 | No modules. 20 | 21 | ## Resources 22 | 23 | | Name | Type | 24 | |------|------| 25 | | [github_repository_webhook.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_webhook) | resource | 26 | 27 | ## Inputs 28 | 29 | | Name | Description | Type | Default | Required | 30 | |------|-------------|------|---------|:--------:| 31 | | [create](#input\_create) | Whether to create Github repository webhook for Atlantis | `bool` | `true` | no | 32 | | [repositories](#input\_repositories) | List of names of repositories which belong to the owner specified in `github_owner` | `list(string)` | `[]` | no | 33 | | [webhook\_secret](#input\_webhook\_secret) | Webhook secret | `string` | `""` | no | 34 | | [webhook\_url](#input\_webhook\_url) | Webhook URL | `string` | `""` | no | 35 | 36 | ## Outputs 37 | 38 | | Name | Description | 39 | |------|-------------| 40 | | [repository\_webhook\_urls](#output\_repository\_webhook\_urls) | Webhook URL | 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: 'Validate PR title' 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | # Please look up the latest version from 16 | # https://github.com/amannn/action-semantic-pull-request/releases 17 | - uses: amannn/action-semantic-pull-request@v6.1.1 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Configure which types are allowed. 22 | # Default: https://github.com/commitizen/conventional-commit-types 23 | types: | 24 | fix 25 | feat 26 | docs 27 | ci 28 | chore 29 | # Configure that a scope must always be provided. 30 | requireScope: false 31 | # Configure additional validation for the subject based on a regex. 32 | # This example ensures the subject starts with an uppercase character. 33 | subjectPattern: ^[A-Z].+$ 34 | # If `subjectPattern` is configured, you can use this property to override 35 | # the default error message that is shown when the pattern doesn't match. 36 | # The variables `subject` and `title` can be used within the message. 37 | subjectPatternError: | 38 | The subject "{subject}" found in the pull request title "{title}" 39 | didn't match the configured pattern. Please ensure that the subject 40 | starts with an uppercase character. 41 | # For work-in-progress PRs you can typically use draft pull requests 42 | # from Github. However, private repositories on the free plan don't have 43 | # this option and therefore this action allows you to opt-in to using the 44 | # special "[WIP]" prefix to indicate this state. This will avoid the 45 | # validation of the PR title and the pull request checks remain pending. 46 | # Note that a second check will be reported if this is enabled. 47 | wip: true 48 | # When using "Squash and merge" on a PR with only one commit, GitHub 49 | # will suggest using that commit message instead of the PR title for the 50 | # merge commit, and it's easy to commit this by mistake. Enable this option 51 | # to also validate the commit message for one commit PRs. 52 | validateSingleCommit: false 53 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Supplemental Documentation 2 | 3 | ## GitHub 4 | 5 | ### Authenticated Access via GitHub App 6 | 7 | A [GitHub App](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) can be generated to provide Atlantis access instead of using a GitHub personal access token (PAT): 8 | 9 | 1. Create a GitHub App and give it a name - that name must be globally unique, and you can change it later if needed. 10 | 2. Provide a valid Homepage URL - this can be the atlantis server url, for instance `https://atlantis.mydomain.com` 11 | 3. Provide a valid [Webhook URL](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/using-webhooks-with-github-apps). The Atlantis webhook server path is located by default at `https://atlantis.mydomain.com/events`. 12 | 4. Generate a [Webhook Secret](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries). This is the value supplied to the `ATLANTIS_GH_WEBHOOK_SECRET` in the Atlantis server configuration. 13 | 5. Generate a Private Key. This is the value supplied to the `ATLANTIS_GH_APP_KEY` in the Atlantis server configuration. 14 | 6. On the App's settings page (at the top) you find the App ID. This is the value supplied to `ATLANTIS_GH_APP_ID` in the Atlantis server configuration. 15 | 7. On the Permissions & Events you need to setup all the permissions and events according to [Atlantis documentation](https://www.runatlantis.io/docs/access-credentials.html#github-app) 16 | 17 | Now you need to [install the App](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app) on your organization. 18 | 19 | A self-provisioned GitHub App usually has two parts: the App and the Installation. 20 | 21 | The App part is the first step and its where you setup all the requirements, such as authentication, webhook, permissions, etc... The Installation part is where you add the created App to an organization/personal-account. It is on the installation page where you setup which repositories the application can access and receive events from. 22 | 23 | Once you have your GitHub App registered you will be able to access/manage the required parameters either through `environment` or `secret` (we strongly suggest supplying these through `secret`): 24 | 25 | ```hcl 26 | module "atlantis" { 27 | source = "terraform-aws-modules/atlantis/aws" 28 | 29 | # Truncated for brevity ... 30 | 31 | # ECS Container Definition 32 | atlantis = { 33 | secrets = [ 34 | { 35 | name = "ATLANTIS_GH_APP_ID" 36 | valueFrom = "" 37 | }, 38 | { 39 | name = "ATLANTIS_GH_APP_KEY" 40 | valueFrom = "" 41 | }, 42 | { 43 | name = "ATLANTIS_GH_WEBHOOK_SECRET" 44 | valueFrom = "" 45 | }, 46 | ] 47 | } 48 | } 49 | ``` 50 | 51 | ## GitLab 52 | 53 | > TODO 54 | 55 | ## BitBucket 56 | 57 | > TODO 58 | -------------------------------------------------------------------------------- /examples/github-complete/README.md: -------------------------------------------------------------------------------- 1 | # Complete GitHub example 2 | 3 | Configuration in this directory provisions Atlantis on ECS with EFS storage, ALB, Route53 record and GitHub repository webhooks. 4 | 5 | ## Usage 6 | 7 | To run this code you need to copy `terraform.tfvars.sample` into `terraform.tfvars` and update the values locally or specify them using environment variables (`TF_VAR_github_app_id=xxx`, `TF_VAR_github_owner=xxx`, etc.). Ensure that `bootstrap_github_app` is `true`. Once ready, execute: 8 | 9 | ```bash 10 | terraform init 11 | terraform plan 12 | terraform apply 13 | ``` 14 | 15 | Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. 16 | 17 | 18 | ## Requirements 19 | 20 | | Name | Version | 21 | |------|---------| 22 | | [terraform](#requirement\_terraform) | >= 1.11 | 23 | | [aws](#requirement\_aws) | >= 6.19 | 24 | | [github](#requirement\_github) | >= 5.0 | 25 | | [random](#requirement\_random) | >= 3.0 | 26 | 27 | ## Providers 28 | 29 | | Name | Version | 30 | |------|---------| 31 | | [aws](#provider\_aws) | >= 6.19 | 32 | | [random](#provider\_random) | >= 3.0 | 33 | 34 | ## Modules 35 | 36 | | Name | Source | Version | 37 | |------|--------|---------| 38 | | [atlantis](#module\_atlantis) | ../../ | n/a | 39 | | [github\_repository\_webhooks](#module\_github\_repository\_webhooks) | ../../modules/github-repository-webhook | n/a | 40 | | [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 2.0 | 41 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 | 42 | 43 | ## Resources 44 | 45 | | Name | Type | 46 | |------|------| 47 | | [random_password.webhook_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | 48 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 49 | | [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | 50 | 51 | ## Inputs 52 | 53 | | Name | Description | Type | Default | Required | 54 | |------|-------------|------|---------|:--------:| 55 | | [atlantis\_github\_user](#input\_atlantis\_github\_user) | GitHub user or organization name | `string` | n/a | yes | 56 | | [atlantis\_repo\_allowlist](#input\_atlantis\_repo\_allowlist) | List of GitHub repositories that Atlantis will be allowed to access | `list(string)` | n/a | yes | 57 | | [domain](#input\_domain) | Route53 domain name to use for ACM certificate. Route53 zone for this domain should be created in advance | `string` | n/a | yes | 58 | | [github\_owner](#input\_github\_owner) | Github owner to use when creating webhook | `string` | n/a | yes | 59 | | [github\_token](#input\_github\_token) | Github token to use when creating webhook | `string` | n/a | yes | 60 | | [repositories](#input\_repositories) | List of GitHub repositories to create webhooks for. This is just the name of the repository, excluding the user or organization | `list(string)` | n/a | yes | 61 | 62 | ## Outputs 63 | 64 | | Name | Description | 65 | |------|-------------| 66 | | [alb](#output\_alb) | ALB created and all of its associated outputs | 67 | | [atlantis\_url](#output\_atlantis\_url) | URL of Atlantis | 68 | | [cluster](#output\_cluster) | ECS cluster created and all of its associated outputs | 69 | | [efs](#output\_efs) | EFS created and all of its associated outputs | 70 | | [service](#output\_service) | ECS service created and all of its associated | 71 | 72 | -------------------------------------------------------------------------------- /examples/github-separate/README.md: -------------------------------------------------------------------------------- 1 | # Separate GitHub example 2 | 3 | Configuration in this directory provisions Atlantis on ECS with EFS storage and GitHub repository webhooks. It demonstrates how users can deploy this module on an existing ECS Fargate cluster and with an existing ALB. 4 | 5 | ## Usage 6 | 7 | To run this code you need to copy `terraform.tfvars.sample` into `terraform.tfvars` and update the values locally or specify them using environment variables (`TF_VAR_github_app_id=xxx`, `TF_VAR_github_owner=xxx`, etc.). Once ready, execute: 8 | 9 | ```bash 10 | terraform init 11 | terraform plan 12 | terraform apply 13 | ``` 14 | 15 | Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. 16 | 17 | 18 | ## Requirements 19 | 20 | | Name | Version | 21 | |------|---------| 22 | | [terraform](#requirement\_terraform) | >= 1.11 | 23 | | [aws](#requirement\_aws) | >= 6.19 | 24 | | [github](#requirement\_github) | >= 5.0 | 25 | | [random](#requirement\_random) | >= 3.0 | 26 | 27 | ## Providers 28 | 29 | | Name | Version | 30 | |------|---------| 31 | | [aws](#provider\_aws) | >= 6.19 | 32 | | [random](#provider\_random) | >= 3.0 | 33 | 34 | ## Modules 35 | 36 | | Name | Source | Version | 37 | |------|--------|---------| 38 | | [alb](#module\_alb) | terraform-aws-modules/alb/aws | 10.2.0 | 39 | | [atlantis](#module\_atlantis) | ../../ | n/a | 40 | | [atlantis\_disabled](#module\_atlantis\_disabled) | ../../ | n/a | 41 | | [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 6.7.0 | 42 | | [github\_repository\_webhooks](#module\_github\_repository\_webhooks) | ../../modules/github-repository-webhook | n/a | 43 | | [secrets\_manager](#module\_secrets\_manager) | terraform-aws-modules/secrets-manager/aws | ~> 2.0 | 44 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 | 45 | 46 | ## Resources 47 | 48 | | Name | Type | 49 | |------|------| 50 | | [random_password.webhook_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | 51 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 52 | 53 | ## Inputs 54 | 55 | | Name | Description | Type | Default | Required | 56 | |------|-------------|------|---------|:--------:| 57 | | [atlantis\_github\_user](#input\_atlantis\_github\_user) | GitHub user or organization name | `string` | n/a | yes | 58 | | [atlantis\_repo\_allowlist](#input\_atlantis\_repo\_allowlist) | List of GitHub repositories that Atlantis will be allowed to access | `list(string)` | n/a | yes | 59 | | [github\_owner](#input\_github\_owner) | Github owner to use when creating webhook | `string` | n/a | yes | 60 | | [github\_token](#input\_github\_token) | Github token to use when creating webhook | `string` | n/a | yes | 61 | | [repositories](#input\_repositories) | List of GitHub repositories to create webhooks for. This is just the name of the repository, excluding the user or organization | `list(string)` | n/a | yes | 62 | 63 | ## Outputs 64 | 65 | | Name | Description | 66 | |------|-------------| 67 | | [alb](#output\_alb) | ALB created and all of its associated outputs | 68 | | [atlantis\_url](#output\_atlantis\_url) | URL of Atlantis | 69 | | [cluster](#output\_cluster) | ECS cluster created and all of its associated outputs | 70 | | [efs](#output\_efs) | EFS created and all of its associated outputs | 71 | | [service](#output\_service) | ECS service created and all of its associated | 72 | 73 | -------------------------------------------------------------------------------- /examples/github-complete/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | provider "github" { 6 | token = var.github_token 7 | owner = var.github_owner 8 | } 9 | 10 | data "aws_route53_zone" "this" { 11 | name = var.domain 12 | } 13 | 14 | data "aws_availability_zones" "available" {} 15 | 16 | locals { 17 | region = "eu-west-1" 18 | name = "ex-${basename(path.cwd)}" 19 | 20 | vpc_cidr = "10.0.0.0/16" 21 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 22 | 23 | tags = { 24 | Name = local.name 25 | Example = local.name 26 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-atlantis" 27 | } 28 | } 29 | 30 | ############################################################## 31 | # Atlantis 32 | ############################################################## 33 | 34 | module "atlantis" { 35 | source = "../../" 36 | 37 | name = local.name 38 | vpc_id = module.vpc.vpc_id 39 | 40 | # ECS Container Definition 41 | atlantis = { 42 | environment = [ 43 | { 44 | name = "ATLANTIS_GH_USER" 45 | value = var.atlantis_github_user 46 | }, 47 | { 48 | name = "ATLANTIS_REPO_ALLOWLIST" 49 | value = join(",", var.atlantis_repo_allowlist) 50 | }, 51 | { 52 | name = "ATLANTIS_ENABLE_DIFF_MARKDOWN_FORMAT" 53 | value = "true" 54 | }, 55 | ] 56 | secrets = [ 57 | { 58 | name = "ATLANTIS_GH_TOKEN" 59 | valueFrom = try(module.secrets_manager["github-token"].secret_arn, "") 60 | }, 61 | { 62 | name = "ATLANTIS_GH_WEBHOOK_SECRET" 63 | valueFrom = try(module.secrets_manager["github-webhook-secret"].secret_arn, "") 64 | }, 65 | ] 66 | } 67 | 68 | # ECS Service 69 | service = { 70 | subnet_ids = module.vpc.private_subnets 71 | 72 | task_exec_secret_arns = [for sec in module.secrets_manager : sec.secret_arn] 73 | # Provide Atlantis permission necessary to create/destroy resources 74 | tasks_iam_role_policies = { 75 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 76 | } 77 | } 78 | 79 | # ALB 80 | alb = { 81 | subnet_ids = module.vpc.public_subnets 82 | 83 | # For example only 84 | enable_deletion_protection = false 85 | } 86 | 87 | # ACM 88 | certificate_domain_name = "${local.name}.${var.domain}" 89 | route53_zone_id = data.aws_route53_zone.this.id 90 | 91 | # EFS 92 | enable_efs = true 93 | efs = { 94 | mount_targets = { 95 | "eu-west-1a" = { 96 | subnet_id = module.vpc.private_subnets[0] 97 | } 98 | "eu-west-1b" = { 99 | subnet_id = module.vpc.private_subnets[1] 100 | } 101 | "eu-west-1c" = { 102 | subnet_id = module.vpc.private_subnets[2] 103 | } 104 | } 105 | } 106 | 107 | tags = local.tags 108 | } 109 | 110 | module "github_repository_webhooks" { 111 | source = "../../modules/github-repository-webhook" 112 | 113 | repositories = var.repositories 114 | 115 | webhook_url = "${module.atlantis.url}/events" 116 | webhook_secret = random_password.webhook_secret.result 117 | } 118 | 119 | ################################################################################ 120 | # Supporting Resources 121 | ################################################################################ 122 | 123 | resource "random_password" "webhook_secret" { 124 | length = 32 125 | special = false 126 | } 127 | 128 | module "secrets_manager" { 129 | source = "terraform-aws-modules/secrets-manager/aws" 130 | version = "~> 2.0" 131 | 132 | for_each = { 133 | github-token = { 134 | secret_string = var.github_token 135 | } 136 | github-webhook-secret = { 137 | secret_string = random_password.webhook_secret.result 138 | } 139 | } 140 | 141 | # Secret 142 | name_prefix = each.key 143 | recovery_window_in_days = 0 # For example only 144 | secret_string_wo = each.value.secret_string 145 | secret_string_wo_version = 2 146 | 147 | tags = local.tags 148 | } 149 | 150 | module "vpc" { 151 | source = "terraform-aws-modules/vpc/aws" 152 | version = "~> 6.0" 153 | 154 | name = local.name 155 | cidr = local.vpc_cidr 156 | 157 | azs = local.azs 158 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 159 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 160 | 161 | enable_nat_gateway = true 162 | single_nat_gateway = true 163 | 164 | tags = local.tags 165 | } 166 | -------------------------------------------------------------------------------- /examples/github-separate/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | provider "github" { 6 | token = var.github_token 7 | owner = var.github_owner 8 | } 9 | 10 | data "aws_availability_zones" "available" {} 11 | 12 | locals { 13 | region = "eu-west-1" 14 | name = "ex-${basename(path.cwd)}" 15 | 16 | vpc_cidr = "10.0.0.0/16" 17 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 18 | 19 | tags = { 20 | Name = local.name 21 | Example = local.name 22 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-atlantis" 23 | } 24 | } 25 | 26 | ############################################################## 27 | # Atlantis 28 | ############################################################## 29 | 30 | module "atlantis" { 31 | source = "../../" 32 | 33 | name = local.name 34 | vpc_id = module.vpc.vpc_id 35 | 36 | # Existing cluster 37 | create_cluster = false 38 | cluster_arn = module.ecs_cluster.arn 39 | 40 | # Existing ALB 41 | create_alb = false 42 | alb_target_group_arn = module.alb.target_groups["atlantis"].arn 43 | alb_security_group_id = module.alb.security_group_id 44 | 45 | # ECS Container Definition 46 | atlantis = { 47 | environment = [ 48 | { 49 | name = "ATLANTIS_GH_USER" 50 | value = var.atlantis_github_user 51 | }, 52 | { 53 | name = "ATLANTIS_REPO_ALLOWLIST" 54 | value = join(",", var.atlantis_repo_allowlist) 55 | }, 56 | { 57 | name = "ATLANTIS_ENABLE_DIFF_MARKDOWN_FORMAT" 58 | value = "true" 59 | }, 60 | ] 61 | secrets = [ 62 | { 63 | name = "ATLANTIS_GH_TOKEN" 64 | valueFrom = try(module.secrets_manager["github-token"].secret_arn, "") 65 | }, 66 | { 67 | name = "ATLANTIS_GH_WEBHOOK_SECRET" 68 | valueFrom = try(module.secrets_manager["github-webhook-secret"].secret_arn, "") 69 | }, 70 | ] 71 | fqdn = module.alb.dns_name 72 | } 73 | 74 | # ECS Service 75 | service = { 76 | subnet_ids = module.vpc.private_subnets 77 | 78 | task_exec_secret_arns = [for sec in module.secrets_manager : sec.secret_arn] 79 | # Provide Atlantis permission necessary to create/destroy resources 80 | tasks_iam_role_policies = { 81 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 82 | } 83 | } 84 | 85 | tags = local.tags 86 | } 87 | 88 | module "github_repository_webhooks" { 89 | source = "../../modules/github-repository-webhook" 90 | 91 | repositories = var.repositories 92 | 93 | webhook_url = "http://${module.alb.dns_name}/events" 94 | webhook_secret = random_password.webhook_secret.result 95 | } 96 | 97 | module "atlantis_disabled" { 98 | source = "../../" 99 | 100 | create = false 101 | } 102 | 103 | ################################################################################ 104 | # Supporting Resources 105 | ################################################################################ 106 | 107 | module "ecs_cluster" { 108 | source = "terraform-aws-modules/ecs/aws//modules/cluster" 109 | version = "6.7.0" 110 | 111 | # Cluster 112 | name = local.name 113 | setting = [{ 114 | name = "containerInsights" 115 | value = "enabled" 116 | }] 117 | 118 | tags = local.tags 119 | } 120 | 121 | module "alb" { 122 | source = "terraform-aws-modules/alb/aws" 123 | version = "10.2.0" 124 | 125 | name = local.name 126 | 127 | # Load balancer 128 | enable_deletion_protection = false # For example only 129 | subnets = module.vpc.public_subnets 130 | 131 | # Listener(s) 132 | default_port = 80 133 | default_protocol = "HTTP" 134 | listeners = { 135 | http = { 136 | port = 80 137 | protocol = "HTTP" 138 | 139 | forward = { 140 | target_group_key = "atlantis" 141 | } 142 | } 143 | } 144 | 145 | # Target group(s) 146 | target_groups = { 147 | atlantis = { 148 | backend_protocol = "HTTP" 149 | backend_port = 4141 150 | create_attachment = false 151 | target_type = "ip" 152 | deregistration_delay = 10 153 | load_balancing_cross_zone_enabled = true 154 | 155 | health_check = { 156 | enabled = true 157 | healthy_threshold = 5 158 | interval = 30 159 | matcher = "200" 160 | path = "/healthz" 161 | port = "traffic-port" 162 | protocol = "HTTP" 163 | timeout = 5 164 | unhealthy_threshold = 2 165 | } 166 | } 167 | } 168 | 169 | # Security group 170 | vpc_id = module.vpc.vpc_id 171 | security_group_ingress_rules = { 172 | http = { 173 | from_port = 80 174 | to_port = 80 175 | ip_protocol = "tcp" 176 | cidr_ipv4 = "0.0.0.0/0" 177 | } 178 | } 179 | security_group_egress_rules = { 180 | all = { 181 | ip_protocol = "-1" 182 | cidr_ipv4 = "0.0.0.0/0" 183 | } 184 | } 185 | 186 | tags = local.tags 187 | } 188 | 189 | resource "random_password" "webhook_secret" { 190 | length = 32 191 | special = false 192 | } 193 | 194 | module "secrets_manager" { 195 | source = "terraform-aws-modules/secrets-manager/aws" 196 | version = "~> 2.0" 197 | 198 | for_each = { 199 | github-token = { 200 | secret_string = var.github_token 201 | } 202 | github-webhook-secret = { 203 | secret_string = random_password.webhook_secret.result 204 | } 205 | } 206 | 207 | # Secret 208 | name_prefix = each.key 209 | recovery_window_in_days = 0 # For example only 210 | secret_string_wo = each.value.secret_string 211 | secret_string_wo_version = 2 212 | 213 | tags = local.tags 214 | } 215 | 216 | module "vpc" { 217 | source = "terraform-aws-modules/vpc/aws" 218 | version = "~> 6.0" 219 | 220 | name = local.name 221 | cidr = local.vpc_cidr 222 | 223 | azs = local.azs 224 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 225 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 226 | 227 | enable_nat_gateway = true 228 | single_nat_gateway = true 229 | 230 | tags = local.tags 231 | } 232 | -------------------------------------------------------------------------------- /docs/UPGRADE-5.0.md: -------------------------------------------------------------------------------- 1 | # Upgrade from v4.x to v5.x 2 | 3 | Please consult the `examples` directory for reference example configurations. If you find a bug, please open an issue with supporting configuration to reproduce. 4 | 5 | ## List of backwards incompatible changes 6 | 7 | - Minimum supported version of Terraform AWS provider updated to `v6.19` to support the latest resources utilized 8 | - Minimum supported version of Terraform updated to `v1.10` (min supported version for ACM module used within this module) 9 | - 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. 10 | - 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. 11 | - `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. 12 | - `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. 13 | 14 | ## Additional changes 15 | 16 | ### Added 17 | 18 | - Support for `region` argument to specify the AWS region for the resources created if different from the provider region. 19 | 20 | ### Modified 21 | 22 | - The ALB module used within this module has been updated to `v10.2.0` 23 | - The ECS cluster and service modules used within this module have been updated to `v6.7.0` 24 | - The ACM module used within this module has been updated to `v6.1.1` 25 | - The EFS module used within this module has been updated to `v2.0.0` 26 | - Variable definitions now contain detailed object types in place of the previously used `any` type 27 | 28 | ### Removed 29 | 30 | - None 31 | 32 | ### Variable and output changes 33 | 34 | 1. Removed variables: 35 | 36 | - `atlantis_gid` -> is now `atlantis.group_id` within the `atlantis` object variable 37 | - `atlantis_uid` -> is now `atlantis.user_id` within the `atlantis` object variable 38 | - `alb_https_default_action` -> replaced by `alb.https_default_action` within the `alb` object variable 39 | - `alb_subnets` -> replaced by `alb.subnet_ids` within the `alb` object variable 40 | - `service_subnets` -> replaced by `service.subnet_ids` within the `service` object variable 41 | - From the `alb` object variable: 42 | - `customer_owned_ipv4_pool` 43 | - `desync_mitigation_mode` 44 | - `dns_record_client_routing_policy` 45 | - `enable_tls_version_and_cipher_suite_headers` 46 | - `enable_xff_client_port` 47 | - `load_balancer_type` 48 | - `xff_header_processing_mode` 49 | - From the `service` object variable: 50 | - `ignore_task_definition_changes` 51 | - `alarms` 52 | - `deployment_controller` 53 | - `deployment_maximum_percent` - Atlantis only supports 1 running instance 54 | - `deployment_minimum_healthy_percent` - Atlantis only supports 1 running instance 55 | - `desired_count` - Atlantis only supports 1 running instance 56 | - `enable_execute_command` 57 | - `ordered_placement_strategy` 58 | - `placement_constraints` 59 | - `scheduling_strategy` 60 | - `service_connect_configuration` 61 | - `service_registries` 62 | - `container_definition_defaults` 63 | - `inference_accelerator` 64 | - `ipc_mode` 65 | - `pid_mode` 66 | - `task_definition_placement_constraints` 67 | - `proxy_configuration` 68 | - `skip_destroy` 69 | - `external_id` 70 | - `scale` 71 | - `force_delete` 72 | - `wait_until_stable` 73 | - `wait_until_stable_timeout` 74 | - `enable_autoscaling` 75 | - `autoscaling_min_capacity` 76 | - `autoscaling_max_capacity` 77 | - `autoscaling_policies` 78 | - `autoscaling_scheduled_actions` 79 | - From the `atlantis` object variable: 80 | - `essential` - now always true 81 | - `extra_hosts` 82 | - `interactive` 83 | - `links` 84 | - `pseudo_terminal` 85 | - `system_controls` 86 | - From the `efs` object variable: 87 | - `create_backup_policy` 88 | - `enable_backup_policy` 89 | - `create_replication_configuration` 90 | - `replication_configuration_destination` 91 | 92 | 2. Renamed variables: 93 | 94 | - `cluster.settings` -> `cluster.setting` (singular) 95 | - `cluster.fargate_capacity_providers` -> replaced by `cluster.default_capacity_provider_strategy` 96 | 97 | 3. Added variables: 98 | 99 | - `region` 100 | 101 | 4. Removed outputs: 102 | 103 | - None 104 | 105 | 5. Renamed outputs: 106 | 107 | - None 108 | 109 | 6. Added outputs: 110 | 111 | - None 112 | 113 | ## Upgrade Migrations 114 | 115 | ### Diff of Before vs After 116 | 117 | ```diff 118 | module "atlantis" { 119 | source = "terraform-aws-modules/atlantis/aws" 120 | - version = "4.4.1" 121 | + version = "5.0.0" 122 | 123 | # Truncated for brevity, only the relevant changes shown 124 | 125 | - alb_subnets = module.vpc.public_subnets 126 | alb = { 127 | + subnet_ids = module.vpc.public_subnets 128 | ... 129 | } 130 | 131 | - service_subnets = module.vpc.private_subnets 132 | service = { 133 | + subnet_ids = module.vpc.private_subnets 134 | ... 135 | } 136 | ``` 137 | 138 | ### State Move Commands 139 | 140 | 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` 141 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: Pre-Commit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - master 8 | 9 | env: 10 | TERRAFORM_DOCS_VERSION: v0.20.0 11 | TFLINT_VERSION: v0.59.1 12 | 13 | jobs: 14 | collectInputs: 15 | name: Collect workflow inputs 16 | runs-on: ubuntu-latest 17 | outputs: 18 | directories: ${{ steps.dirs.outputs.directories }} 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v5 22 | 23 | - name: Get root directories 24 | id: dirs 25 | uses: clowdhaus/terraform-composite-actions/directories@v1.14.0 26 | 27 | preCommitMinVersions: 28 | name: Min TF pre-commit 29 | needs: collectInputs 30 | runs-on: ubuntu-latest 31 | strategy: 32 | matrix: 33 | directory: ${{ fromJson(needs.collectInputs.outputs.directories) }} 34 | steps: 35 | - name: Install rmz 36 | uses: jaxxstorm/action-install-gh-release@v2.1.0 37 | with: 38 | repo: SUPERCILEX/fuc 39 | asset-name: x86_64-unknown-linux-gnu-rmz 40 | rename-to: rmz 41 | chmod: 0755 42 | extension-matching: disable 43 | 44 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 45 | - name: Delete unnecessary files 46 | run: | 47 | formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } 48 | getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } 49 | 50 | BEFORE=$(getAvailableSpace) 51 | 52 | ln -s /opt/hostedtoolcache/SUPERCILEX/x86_64-unknown-linux-gnu-rmz/latest/linux-x64/rmz /usr/local/bin/rmz 53 | rmz -f /opt/hostedtoolcache/CodeQL & 54 | rmz -f /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk & 55 | rmz -f /opt/hostedtoolcache/PyPy & 56 | rmz -f /opt/hostedtoolcache/Ruby & 57 | rmz -f /opt/hostedtoolcache/go & 58 | 59 | wait 60 | 61 | AFTER=$(getAvailableSpace) 62 | SAVED=$((AFTER-BEFORE)) 63 | echo "=> Saved $(formatByteCount $SAVED)" 64 | 65 | - name: Checkout 66 | uses: actions/checkout@v5 67 | 68 | - name: Terraform min/max versions 69 | id: minMax 70 | uses: clowdhaus/terraform-min-max@v2.1.0 71 | with: 72 | directory: ${{ matrix.directory }} 73 | 74 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 75 | # Run only validate pre-commit check on min version supported 76 | if: ${{ matrix.directory != '.' }} 77 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 78 | with: 79 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 80 | tflint-version: ${{ env.TFLINT_VERSION }} 81 | args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*' 82 | 83 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 84 | # Run only validate pre-commit check on min version supported 85 | if: ${{ matrix.directory == '.' }} 86 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 87 | with: 88 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 89 | tflint-version: ${{ env.TFLINT_VERSION }} 90 | args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)' 91 | 92 | preCommitMaxVersion: 93 | name: Max TF pre-commit 94 | runs-on: ubuntu-latest 95 | needs: collectInputs 96 | steps: 97 | - name: Install rmz 98 | uses: jaxxstorm/action-install-gh-release@v2.1.0 99 | with: 100 | repo: SUPERCILEX/fuc 101 | asset-name: x86_64-unknown-linux-gnu-rmz 102 | rename-to: rmz 103 | chmod: 0755 104 | extension-matching: disable 105 | 106 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 107 | - name: Delete unnecessary files 108 | run: | 109 | formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } 110 | getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } 111 | 112 | BEFORE=$(getAvailableSpace) 113 | 114 | ln -s /opt/hostedtoolcache/SUPERCILEX/x86_64-unknown-linux-gnu-rmz/latest/linux-x64/rmz /usr/local/bin/rmz 115 | rmz -f /opt/hostedtoolcache/CodeQL & 116 | rmz -f /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk & 117 | rmz -f /opt/hostedtoolcache/PyPy & 118 | rmz -f /opt/hostedtoolcache/Ruby & 119 | rmz -f /opt/hostedtoolcache/go & 120 | sudo rmz -f /usr/local/lib/android & 121 | 122 | if [[ ${{ github.repository }} == terraform-aws-modules/terraform-aws-security-group ]]; then 123 | sudo rmz -f /usr/share/dotnet & 124 | sudo rmz -f /usr/local/.ghcup & 125 | sudo apt-get -qq remove -y 'azure-.*' 126 | sudo apt-get -qq remove -y 'cpp-.*' 127 | sudo apt-get -qq remove -y 'dotnet-runtime-.*' 128 | sudo apt-get -qq remove -y 'google-.*' 129 | sudo apt-get -qq remove -y 'libclang-.*' 130 | sudo apt-get -qq remove -y 'libllvm.*' 131 | sudo apt-get -qq remove -y 'llvm-.*' 132 | sudo apt-get -qq remove -y 'mysql-.*' 133 | sudo apt-get -qq remove -y 'postgresql-.*' 134 | sudo apt-get -qq remove -y 'php.*' 135 | sudo apt-get -qq remove -y 'temurin-.*' 136 | sudo apt-get -qq remove -y kubectl firefox mono-devel 137 | sudo apt-get -qq autoremove -y 138 | sudo apt-get -qq clean 139 | fi 140 | 141 | wait 142 | 143 | AFTER=$(getAvailableSpace) 144 | SAVED=$((AFTER-BEFORE)) 145 | echo "=> Saved $(formatByteCount $SAVED)" 146 | 147 | - name: Checkout 148 | uses: actions/checkout@v5 149 | with: 150 | ref: ${{ github.event.pull_request.head.ref }} 151 | repository: ${{github.event.pull_request.head.repo.full_name}} 152 | 153 | - name: Terraform min/max versions 154 | id: minMax 155 | uses: clowdhaus/terraform-min-max@v2.1.0 156 | 157 | - name: Hide template dir 158 | # Special to this repo, we don't want to check this dir 159 | if: ${{ github.repository == 'terraform-aws-modules/terraform-aws-security-group' }} 160 | run: rm -rf modules/_templates 161 | 162 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} 163 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.14.0 164 | with: 165 | terraform-version: ${{ steps.minMax.outputs.maxVersion }} 166 | tflint-version: ${{ env.TFLINT_VERSION }} 167 | terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }} 168 | install-hcledit: true 169 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # Atlantis 3 | atlantis_url = "https://${try( 4 | coalesce( 5 | var.atlantis.fqdn, 6 | try(module.alb.route53_records["A"].fqdn, null), 7 | module.alb.dns_name, 8 | ), 9 | "")}" 10 | } 11 | 12 | ################################################################################ 13 | # ALB 14 | ################################################################################ 15 | 16 | locals { 17 | route53_records = { 18 | A = { 19 | name = try(coalesce(var.route53_record_name, var.name), "") 20 | type = "A" 21 | zone_id = var.route53_zone_id 22 | } 23 | AAAA = { 24 | name = try(coalesce(var.route53_record_name, var.name), "") 25 | type = "AAAA" 26 | zone_id = var.route53_zone_id 27 | } 28 | } 29 | } 30 | 31 | module "alb" { 32 | source = "terraform-aws-modules/alb/aws" 33 | version = "10.2.0" 34 | 35 | region = var.region 36 | create = var.create && var.create_alb 37 | 38 | # Load balancer 39 | access_logs = var.alb.access_logs 40 | connection_logs = var.alb.connection_logs 41 | drop_invalid_header_fields = var.alb.drop_invalid_header_fields 42 | enable_cross_zone_load_balancing = var.alb.enable_cross_zone_load_balancing 43 | enable_deletion_protection = var.alb.enable_deletion_protection 44 | enable_http2 = var.alb.enable_http2 45 | enable_waf_fail_open = var.alb.enable_waf_fail_open 46 | enable_zonal_shift = var.alb.enable_zonal_shift 47 | idle_timeout = var.alb.idle_timeout 48 | internal = var.alb.internal 49 | ip_address_type = var.alb.ip_address_type 50 | load_balancer_type = "application" 51 | name = try(coalesce(var.alb.name, var.name), "") 52 | preserve_host_header = var.alb.preserve_host_header 53 | security_groups = var.alb.security_groups 54 | subnets = var.alb.subnet_ids 55 | 56 | # Listener(s) 57 | default_port = var.alb.default_port 58 | default_protocol = var.alb.default_protocol 59 | listeners = merge( 60 | { 61 | http-https-redirect = { 62 | port = 80 63 | protocol = "HTTP" 64 | 65 | redirect = { 66 | port = "443" 67 | protocol = "HTTPS" 68 | status_code = "HTTP_301" 69 | } 70 | } 71 | 72 | https = merge( 73 | { 74 | port = 443 75 | protocol = "HTTPS" 76 | ssl_policy = var.alb.https_listener_ssl_policy 77 | certificate_arn = var.create_certificate ? module.acm.acm_certificate_arn : var.certificate_arn 78 | }, 79 | var.alb.https_default_action, 80 | var.alb.https_listener, 81 | ) 82 | }, 83 | var.alb.listeners 84 | ) 85 | 86 | # Target group(s) 87 | target_groups = merge( 88 | { 89 | atlantis = { 90 | name = var.name 91 | protocol = "HTTP" 92 | port = var.atlantis.port 93 | create_attachment = false 94 | target_type = "ip" 95 | deregistration_delay = 10 96 | 97 | health_check = { 98 | enabled = true 99 | healthy_threshold = 5 100 | interval = 30 101 | matcher = "200" 102 | path = "/healthz" 103 | port = "traffic-port" 104 | protocol = "HTTP" 105 | timeout = 5 106 | unhealthy_threshold = 2 107 | } 108 | } 109 | }, 110 | var.alb.target_groups 111 | ) 112 | 113 | # Security group 114 | create_security_group = var.alb.create_security_group 115 | security_group_name = try(coalesce(var.alb.security_group_name, var.name), "") 116 | security_group_use_name_prefix = var.alb.security_group_use_name_prefix 117 | security_group_description = var.alb.security_group_description 118 | vpc_id = var.vpc_id 119 | security_group_ingress_rules = var.alb.security_group_ingress_rules 120 | security_group_egress_rules = var.alb.security_group_egress_rules 121 | security_group_tags = var.alb.security_group_tags 122 | 123 | # Route53 record(s) 124 | route53_records = merge( 125 | { for k, v in local.route53_records : k => v if var.create_route53_records }, 126 | var.alb.route53_records 127 | ) 128 | 129 | # WAF 130 | associate_web_acl = var.alb.associate_web_acl 131 | web_acl_arn = var.alb.web_acl_arn 132 | 133 | tags = merge( 134 | var.tags, 135 | var.alb.tags, 136 | ) 137 | } 138 | 139 | ################################################################################ 140 | # ACM 141 | ################################################################################ 142 | 143 | module "acm" { 144 | source = "terraform-aws-modules/acm/aws" 145 | version = "6.1.1" 146 | 147 | region = var.region 148 | create_certificate = var.create && var.create_certificate && var.create_alb 149 | 150 | domain_name = var.certificate_domain_name 151 | validate_certificate = var.validate_certificate 152 | validation_method = "DNS" 153 | zone_id = var.route53_zone_id 154 | 155 | tags = var.tags 156 | } 157 | 158 | ################################################################################ 159 | # ECS 160 | ################################################################################ 161 | 162 | locals { 163 | mount_path = "/home/atlantis" 164 | mount_points = var.enable_efs ? [{ 165 | containerPath = local.mount_path 166 | sourceVolume = "efs" 167 | readOnly = false 168 | }] : var.atlantis.mountPoints 169 | } 170 | 171 | module "ecs_cluster" { 172 | source = "terraform-aws-modules/ecs/aws//modules/cluster" 173 | version = "6.7.0" 174 | 175 | region = var.region 176 | create = var.create && var.create_cluster 177 | 178 | # Cluster 179 | name = try(coalesce(var.cluster.name, var.name)) 180 | configuration = var.cluster.configuration 181 | setting = var.cluster.setting 182 | 183 | # Cloudwatch log group 184 | create_cloudwatch_log_group = var.cluster.create_cloudwatch_log_group 185 | cloudwatch_log_group_retention_in_days = var.cluster.cloudwatch_log_group_retention_in_days 186 | cloudwatch_log_group_kms_key_id = var.cluster.cloudwatch_log_group_kms_key_id 187 | cloudwatch_log_group_class = var.cluster.cloudwatch_log_group_class 188 | cloudwatch_log_group_tags = var.cluster.cloudwatch_log_group_tags 189 | 190 | # Capacity providers 191 | default_capacity_provider_strategy = var.cluster.default_capacity_provider_strategy 192 | 193 | tags = var.tags 194 | } 195 | 196 | module "ecs_service" { 197 | source = "terraform-aws-modules/ecs/aws//modules/service" 198 | version = "6.7.0" 199 | 200 | region = var.region 201 | create = var.create 202 | 203 | # Service 204 | capacity_provider_strategy = var.service.capacity_provider_strategy 205 | cluster_arn = var.create_cluster && var.create ? module.ecs_cluster.arn : var.cluster_arn 206 | deployment_circuit_breaker = var.service.deployment_circuit_breaker 207 | deployment_maximum_percent = 100 208 | deployment_minimum_healthy_percent = 0 209 | desired_count = 1 210 | enable_ecs_managed_tags = var.service.enable_ecs_managed_tags 211 | enable_execute_command = false 212 | force_new_deployment = var.service.force_new_deployment 213 | health_check_grace_period_seconds = var.service.health_check_grace_period_seconds 214 | launch_type = var.service.launch_type 215 | load_balancer = merge( 216 | { 217 | service = { 218 | target_group_arn = var.create && var.create_alb ? module.alb.target_groups["atlantis"].arn : var.alb_target_group_arn 219 | container_name = "atlantis" 220 | container_port = var.atlantis.port 221 | } 222 | }, 223 | var.service.load_balancer 224 | ) 225 | name = try(coalesce(var.service.name, var.name)) 226 | assign_public_ip = var.service.assign_public_ip 227 | security_group_ids = var.service.security_group_ids 228 | subnet_ids = var.service.subnet_ids 229 | platform_version = var.service.platform_version 230 | propagate_tags = var.service.propagate_tags 231 | timeouts = var.service.timeouts 232 | triggers = var.service.triggers 233 | wait_for_steady_state = var.service.wait_for_steady_state 234 | 235 | # Service IAM role 236 | create_iam_role = var.service.create_iam_role 237 | iam_role_arn = var.service.iam_role_arn 238 | iam_role_name = var.service.iam_role_name 239 | iam_role_use_name_prefix = var.service.iam_role_use_name_prefix 240 | iam_role_path = var.service.iam_role_path 241 | iam_role_description = var.service.iam_role_description 242 | iam_role_permissions_boundary = var.service.iam_role_permissions_boundary 243 | iam_role_tags = var.service.iam_role_tags 244 | iam_role_statements = var.service.iam_role_statements 245 | 246 | # Task definition 247 | create_task_definition = var.service.create_task_definition 248 | task_definition_arn = var.service.task_definition_arn 249 | container_definitions = merge( 250 | { 251 | atlantis = { 252 | command = var.atlantis.command 253 | cpu = var.atlantis.cpu 254 | dependsOn = var.atlantis.dependsOn 255 | disableNetworking = var.atlantis.disableNetworking 256 | dnsSearchDomains = var.atlantis.dnsSearchDomains 257 | dnsServers = var.atlantis.dnsServers 258 | dockerLabels = var.atlantis.dockerLabels 259 | dockerSecurityOptions = var.atlantis.dockerSecurityOptions 260 | entrypoint = var.atlantis.entrypoint 261 | environment = concat( 262 | [ 263 | { 264 | name = "ATLANTIS_PORT" 265 | value = var.atlantis.port 266 | }, 267 | { 268 | name = "ATLANTIS_ATLANTIS_URL" 269 | value = local.atlantis_url 270 | }, 271 | ], 272 | var.atlantis.environment 273 | ) 274 | environmentFiles = var.atlantis.environmentFiles 275 | essential = true 276 | extraHosts = var.atlantis.extraHosts 277 | firelensConfiguration = var.atlantis.firelensConfiguration 278 | fqdn = var.atlantis.fqdn 279 | healthCheck = var.atlantis.healthCheck 280 | hostname = var.atlantis.hostname 281 | image = var.atlantis.image 282 | linuxParameters = var.atlantis.linuxParameters 283 | logConfiguration = var.atlantis.logConfiguration 284 | memory = var.atlantis.memory 285 | memoryReservation = var.atlantis.memoryReservation 286 | mountPoints = local.mount_points 287 | name = "atlantis" 288 | portMappings = [{ 289 | name = "atlantis" 290 | containerPort = var.atlantis.port 291 | protocol = "tcp" 292 | }] 293 | privileged = var.atlantis.privileged 294 | readonlyRootFilesystem = var.atlantis.readonlyRootFilesystem 295 | repositoryCredentials = var.atlantis.repositoryCredentials 296 | resourceRequirements = var.atlantis.resourceRequirements 297 | restartPolicy = var.atlantis.restartPolicy 298 | secrets = var.atlantis.secrets 299 | startTimeout = var.atlantis.startTimeout 300 | stopTimeout = var.atlantis.stopTimeout 301 | user = try(coalesce(var.atlantis.user, "${var.atlantis.uid}:${var.atlantis.gid}")) 302 | versionConsistency = "disabled" 303 | volumesFrom = var.atlantis.volumesFrom 304 | workingDirectory = var.atlantis.workingDirectory 305 | 306 | # CloudWatch Log Group 307 | service = try(coalesce(var.service.name, var.name)) 308 | enable_cloudwatch_logging = var.atlantis.enable_cloudwatch_logging 309 | create_cloudwatch_log_group = var.atlantis.create_cloudwatch_log_group 310 | cloudwatch_log_group_use_name_prefix = var.atlantis.cloudwatch_log_group_use_name_prefix 311 | cloudwatch_log_group_retention_in_days = var.atlantis.cloudwatch_log_group_retention_in_days 312 | cloudwatch_log_group_class = var.atlantis.cloudwatch_log_group_class 313 | cloudwatch_log_group_kms_key_id = var.atlantis.cloudwatch_log_group_kms_key_id 314 | }, 315 | }, 316 | var.service.container_definitions 317 | ) 318 | cpu = var.service.cpu 319 | ephemeral_storage = var.service.ephemeral_storage 320 | family = var.service.family 321 | memory = var.service.memory 322 | network_mode = "awsvpc" 323 | requires_compatibilities = var.service.requires_compatibilities 324 | runtime_platform = var.service.runtime_platform 325 | track_latest = true 326 | volume = merge( 327 | { for k, v in { 328 | efs = { 329 | efs_volume_configuration = { 330 | file_system_id = module.efs.id 331 | transit_encryption = "ENABLED" 332 | authorization_config = { 333 | access_point_id = try(module.efs.access_points["atlantis"].id, "") 334 | iam = "ENABLED" 335 | } 336 | } 337 | } 338 | } : k => v if var.enable_efs }, 339 | var.service.volume 340 | ) 341 | task_tags = var.service.task_tags 342 | 343 | # Task execution IAM role 344 | create_task_exec_iam_role = var.service.create_task_exec_iam_role 345 | task_exec_iam_role_arn = var.service.task_exec_iam_role_arn 346 | task_exec_iam_role_name = var.service.task_exec_iam_role_name 347 | task_exec_iam_role_use_name_prefix = var.service.task_exec_iam_role_use_name_prefix 348 | task_exec_iam_role_path = var.service.task_exec_iam_role_path 349 | task_exec_iam_role_description = var.service.task_exec_iam_role_description 350 | task_exec_iam_role_permissions_boundary = var.service.task_exec_iam_role_permissions_boundary 351 | task_exec_iam_role_tags = var.service.task_exec_iam_role_tags 352 | task_exec_iam_role_policies = var.service.task_exec_iam_role_policies 353 | task_exec_iam_role_max_session_duration = var.service.task_exec_iam_role_max_session_duration 354 | 355 | # Task execution IAM role policy 356 | create_task_exec_policy = var.service.create_task_exec_policy 357 | task_exec_ssm_param_arns = var.service.task_exec_ssm_param_arns 358 | task_exec_secret_arns = var.service.task_exec_secret_arns 359 | task_exec_iam_statements = var.service.task_exec_iam_statements 360 | 361 | # Tasks - IAM role 362 | create_tasks_iam_role = var.service.create_tasks_iam_role 363 | tasks_iam_role_arn = var.service.tasks_iam_role_arn 364 | tasks_iam_role_name = var.service.tasks_iam_role_name 365 | tasks_iam_role_use_name_prefix = var.service.tasks_iam_role_use_name_prefix 366 | tasks_iam_role_path = var.service.tasks_iam_role_path 367 | tasks_iam_role_description = var.service.tasks_iam_role_description 368 | tasks_iam_role_permissions_boundary = var.service.tasks_iam_role_permissions_boundary 369 | tasks_iam_role_tags = var.service.tasks_iam_role_tags 370 | tasks_iam_role_policies = var.service.tasks_iam_role_policies 371 | tasks_iam_role_statements = var.service.tasks_iam_role_statements 372 | 373 | # Autoscaling 374 | # Atlantis only supports a single instance 375 | enable_autoscaling = false 376 | 377 | # Security Group 378 | create_security_group = var.service.create_security_group 379 | security_group_name = var.service.security_group_name 380 | security_group_use_name_prefix = var.service.security_group_use_name_prefix 381 | security_group_description = var.service.security_group_description 382 | security_group_ingress_rules = merge( 383 | { 384 | atlantis = { 385 | from_port = var.atlantis.port 386 | protocol = "tcp" 387 | referenced_security_group_id = var.create_alb ? module.alb.security_group_id : var.alb_security_group_id 388 | } 389 | }, 390 | var.service.security_group_ingress_rules 391 | ) 392 | security_group_egress_rules = merge( 393 | { 394 | egress = { 395 | ip_protocol = "-1" 396 | cidr_ipv4 = "0.0.0.0/0" 397 | } 398 | } 399 | ) 400 | security_group_tags = var.service.security_group_tags 401 | 402 | tags = var.tags 403 | } 404 | 405 | ################################################################################ 406 | # EFS 407 | ################################################################################ 408 | 409 | module "efs" { 410 | source = "terraform-aws-modules/efs/aws" 411 | version = "2.0.0" 412 | 413 | region = var.region 414 | create = var.create && var.enable_efs 415 | 416 | name = try(coalesce(var.efs.name, var.name)) 417 | 418 | # File System 419 | availability_zone_name = var.efs.availability_zone_name 420 | creation_token = try(coalesce(var.efs.creation_token, var.name)) 421 | performance_mode = var.efs.performance_mode 422 | encrypted = var.efs.encrypted 423 | kms_key_arn = var.efs.kms_key_arn 424 | provisioned_throughput_in_mibps = var.efs.provisioned_throughput_in_mibps 425 | throughput_mode = var.efs.throughput_mode 426 | lifecycle_policy = var.efs.lifecycle_policy 427 | protection = var.efs.protection 428 | 429 | # File System Policy 430 | attach_policy = var.efs.attach_policy 431 | bypass_policy_lockout_safety_check = var.efs.bypass_policy_lockout_safety_check 432 | source_policy_documents = var.efs.source_policy_documents 433 | override_policy_documents = var.efs.override_policy_documents 434 | policy_statements = merge( 435 | { 436 | EFSMountWrite = { 437 | actions = [ 438 | "elasticfilesystem:ClientMount", 439 | "elasticfilesystem:ClientWrite", 440 | ] 441 | principals = [ 442 | { 443 | type = "AWS" 444 | identifiers = [module.ecs_service.tasks_iam_role_arn] 445 | } 446 | ] 447 | } 448 | }, 449 | var.efs.policy_statements 450 | ) 451 | deny_nonsecure_transport = var.efs.deny_nonsecure_transport 452 | deny_nonsecure_transport_via_mount_target = var.efs.deny_nonsecure_transport_via_mount_target 453 | 454 | # Mount targets 455 | mount_targets = var.efs.mount_targets 456 | 457 | # Security Group 458 | create_security_group = var.efs.create_security_group 459 | security_group_name = try(coalesce(var.efs.security_group_name, "${var.name}-efs-")) 460 | security_group_use_name_prefix = var.efs.security_group_use_name_prefix 461 | security_group_description = var.efs.security_group_description 462 | security_group_vpc_id = var.vpc_id 463 | security_group_ingress_rules = merge( 464 | { 465 | atlantis = { 466 | # relying on the defaults provdied for EFS/NFS (2049/TCP + ingress) 467 | description = "NFS ingress from Atlantis" 468 | referenced_security_group_id = module.ecs_service.security_group_id 469 | } 470 | }, 471 | var.efs.security_group_ingress_rules 472 | ) 473 | 474 | # Access Point(s) 475 | access_points = merge( 476 | { 477 | atlantis = { 478 | posix_user = { 479 | gid = var.atlantis.gid 480 | uid = var.atlantis.uid 481 | } 482 | root_directory = { 483 | path = local.mount_path 484 | creation_info = { 485 | owner_gid = var.atlantis.gid 486 | owner_uid = var.atlantis.uid 487 | permissions = "0750" 488 | } 489 | } 490 | } 491 | }, 492 | var.efs.access_points 493 | ) 494 | 495 | # Backup Policy 496 | create_backup_policy = false 497 | enable_backup_policy = false 498 | 499 | tags = var.tags 500 | } 501 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Controls if resources should be created (affects nearly all resources)" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "name" { 8 | description = "Common name to use on all resources created unless a more specific name is provided" 9 | type = string 10 | default = "atlantis" 11 | } 12 | 13 | variable "region" { 14 | description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration" 15 | type = string 16 | default = null 17 | } 18 | 19 | variable "tags" { 20 | description = "A map of tags to add to all resources" 21 | type = map(string) 22 | default = {} 23 | } 24 | 25 | variable "vpc_id" { 26 | description = "ID of the VPC where the resources will be provisioned" 27 | type = string 28 | default = "" 29 | } 30 | 31 | ################################################################################ 32 | # Atlantis 33 | ################################################################################ 34 | 35 | variable "atlantis" { 36 | 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" 37 | type = object({ 38 | uid = optional(string, 100) 39 | gid = optional(string, 1000) 40 | 41 | command = optional(list(string)) 42 | cpu = optional(number, 2048) 43 | dependsOn = optional(list(object({ 44 | condition = string 45 | containerName = string 46 | }))) 47 | disableNetworking = optional(bool) 48 | dnsSearchDomains = optional(list(string)) 49 | dnsServers = optional(list(string)) 50 | dockerLabels = optional(map(string)) 51 | dockerSecurityOptions = optional(list(string)) 52 | entrypoint = optional(list(string)) 53 | environment = optional(list(object({ 54 | name = string 55 | value = string 56 | })), []) 57 | environmentFiles = optional(list(object({ 58 | type = string 59 | value = string 60 | }))) 61 | extraHosts = optional(list(object({ 62 | hostname = string 63 | ipAddress = string 64 | }))) 65 | firelensConfiguration = optional(object({ 66 | type = string 67 | options = optional(map(string)) 68 | configFile = optional(object({ 69 | type = string 70 | content = string 71 | })) 72 | })) 73 | fqdn = optional(string) 74 | healthCheck = optional(object({ 75 | command = optional(list(string), []) 76 | interval = optional(number, 30) 77 | retries = optional(number, 3) 78 | startPeriod = optional(number) 79 | timeout = optional(number, 5) 80 | })) 81 | hostname = optional(string) 82 | image = optional(string, "ghcr.io/runatlantis/atlantis:latest") 83 | linuxParameters = optional(object({ 84 | capabilities = optional(object({ 85 | add = optional(list(string)) 86 | drop = optional(list(string)) 87 | })) 88 | devices = optional(list(object({ 89 | containerPath = optional(string) 90 | hostPath = optional(string) 91 | permissions = optional(list(string)) 92 | }))) 93 | initProcessEnabled = optional(bool) 94 | maxSwap = optional(number) 95 | sharedMemorySize = optional(number) 96 | swappiness = optional(number) 97 | tmpfs = optional(list(object({ 98 | containerPath = string 99 | mountOptions = optional(list(string)) 100 | size = number 101 | }))) 102 | })) 103 | logConfiguration = optional(object({ 104 | logDriver = optional(string) 105 | options = optional(map(string)) 106 | secretOptions = optional(list(object({ 107 | name = string 108 | valueFrom = string 109 | }))) 110 | })) 111 | memory = optional(number, 4096) 112 | memoryReservation = optional(number) 113 | mountPoints = optional(list(object({ 114 | containerPath = optional(string) 115 | readOnly = optional(bool) 116 | sourceVolume = optional(string) 117 | }))) 118 | port = optional(number, 4141) 119 | privileged = optional(bool, false) 120 | readonlyRootFilesystem = optional(bool, false) 121 | repositoryCredentials = optional(object({ 122 | credentialsParameter = optional(string) 123 | })) 124 | resourceRequirements = optional(list(object({ 125 | type = string 126 | value = string 127 | }))) 128 | restartPolicy = optional(object({ 129 | enabled = optional(bool, true) 130 | ignoredExitCodes = optional(list(number)) 131 | restartAttemptPeriod = optional(number) 132 | }), 133 | # Default 134 | { 135 | enabled = true 136 | } 137 | ) 138 | secrets = optional(list(object({ 139 | name = string 140 | valueFrom = string 141 | }))) 142 | startTimeout = optional(number, 30) 143 | stopTimeout = optional(number, 120) 144 | user = optional(string, "atlantis") 145 | volumesFrom = optional(list(object({ 146 | readOnly = optional(bool) 147 | sourceContainer = optional(string) 148 | }))) 149 | workingDirectory = optional(string) 150 | 151 | # CloudWatch Log Group 152 | enable_cloudwatch_logging = optional(bool, true) 153 | create_cloudwatch_log_group = optional(bool, true) 154 | cloudwatch_log_group_use_name_prefix = optional(bool, true) 155 | cloudwatch_log_group_retention_in_days = optional(number, 14) 156 | cloudwatch_log_group_class = optional(string) 157 | cloudwatch_log_group_kms_key_id = optional(string) 158 | }) 159 | default = {} 160 | nullable = false 161 | } 162 | 163 | ################################################################################ 164 | # Load Balancer 165 | ################################################################################ 166 | 167 | variable "create_alb" { 168 | description = "Determines whether to create an ALB or not" 169 | type = bool 170 | default = true 171 | } 172 | 173 | variable "alb_target_group_arn" { 174 | description = "ARN of an existing ALB target group that will be used to route traffic to the Atlantis service. Required if `create_alb` is `false`" 175 | type = string 176 | default = "" 177 | } 178 | 179 | variable "alb_security_group_id" { 180 | description = "ID of an existing security group that will be used by ALB. Required if `create_alb` is `false`" 181 | type = string 182 | default = "" 183 | } 184 | 185 | variable "alb" { 186 | 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" 187 | type = object({ 188 | # Load Balancer 189 | access_logs = optional(object({ 190 | bucket = string 191 | enabled = optional(bool, true) 192 | prefix = optional(string) 193 | })) 194 | connection_logs = optional(object({ 195 | bucket = string 196 | enabled = optional(bool, true) 197 | prefix = optional(string) 198 | })) 199 | drop_invalid_header_fields = optional(bool, true) 200 | enable_cross_zone_load_balancing = optional(bool, true) 201 | enable_deletion_protection = optional(bool, true) 202 | enable_http2 = optional(bool, true) 203 | enable_waf_fail_open = optional(bool) 204 | enable_zonal_shift = optional(bool, true) 205 | idle_timeout = optional(number) 206 | internal = optional(bool) 207 | ip_address_type = optional(string) 208 | name = optional(string) 209 | preserve_host_header = optional(bool) 210 | security_groups = optional(list(string), []) 211 | subnet_ids = optional(list(string), []) 212 | 213 | # Listener(s) 214 | default_port = optional(number, 80) 215 | default_protocol = optional(string, "HTTP") 216 | https_listener_ssl_policy = optional(string, "ELBSecurityPolicy-TLS13-1-2-2021-06") 217 | https_default_action = optional(any, { 218 | forward = { 219 | target_group_key = "atlantis" 220 | } 221 | }) 222 | https_listener = optional(any, {}) 223 | listeners = optional(any, {}) 224 | 225 | # Target Group(s) 226 | target_groups = optional(any, {}) 227 | 228 | # Securtity Group(s) 229 | create_security_group = optional(bool, true) 230 | security_group_name = optional(string) 231 | security_group_use_name_prefix = optional(bool, true) 232 | security_group_description = optional(string) 233 | security_group_ingress_rules = optional(map(object({ 234 | name = optional(string) 235 | cidr_ipv4 = optional(string) 236 | cidr_ipv6 = optional(string) 237 | description = optional(string) 238 | from_port = optional(string) 239 | ip_protocol = optional(string, "tcp") 240 | prefix_list_id = optional(string) 241 | referenced_security_group_id = optional(string) 242 | tags = optional(map(string), {}) 243 | to_port = optional(string) 244 | })), 245 | # Default 246 | { 247 | http = { 248 | from_port = 80 249 | cidr_ipv4 = "0.0.0.0/0" 250 | } 251 | https = { 252 | from_port = 443 253 | cidr_ipv4 = "0.0.0.0/0" 254 | } 255 | } 256 | ) 257 | security_group_egress_rules = optional( 258 | map(object({ 259 | name = optional(string) 260 | cidr_ipv4 = optional(string) 261 | cidr_ipv6 = optional(string) 262 | description = optional(string) 263 | from_port = optional(string) 264 | ip_protocol = optional(string, "tcp") 265 | prefix_list_id = optional(string) 266 | referenced_security_group_id = optional(string) 267 | tags = optional(map(string), {}) 268 | to_port = optional(string) 269 | })), 270 | # Default 271 | { 272 | all = { 273 | ip_protocol = "-1" 274 | cidr_ipv4 = "0.0.0.0/0" 275 | } 276 | } 277 | ) 278 | security_group_tags = optional(map(string), {}) 279 | 280 | # Route53 Record(s) 281 | route53_records = optional(map(object({ 282 | zone_id = string 283 | name = optional(string) 284 | type = string 285 | evaluate_target_health = optional(bool, true) 286 | }))) 287 | 288 | # WAF 289 | associate_web_acl = optional(bool, false) 290 | web_acl_arn = optional(string) 291 | 292 | tags = optional(map(string), {}) 293 | }) 294 | default = {} 295 | nullable = false 296 | } 297 | 298 | variable "create_route53_records" { 299 | description = "Determines whether to create Route53 `A` and `AAAA` records for the loadbalancer" 300 | type = bool 301 | default = true 302 | } 303 | 304 | ################################################################################ 305 | # ACM 306 | ################################################################################ 307 | 308 | variable "create_certificate" { 309 | description = "Determines whether to create an ACM certificate or not. If `false`, `certificate_arn` must be provided" 310 | type = bool 311 | default = true 312 | } 313 | 314 | variable "certificate_arn" { 315 | description = "ARN of certificate issued by AWS ACM. If empty, a new ACM certificate will be created and validated using Route53 DNS" 316 | type = string 317 | default = "" 318 | } 319 | 320 | variable "certificate_domain_name" { 321 | description = "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`" 322 | type = string 323 | default = "" 324 | } 325 | 326 | variable "validate_certificate" { 327 | description = "Determines whether to validate ACM certificate using Route53 DNS. If `false`, certificate will be created but not validated" 328 | type = bool 329 | default = true 330 | } 331 | 332 | variable "route53_zone_id" { 333 | description = "Route53 zone ID to use for ACM certificate and Route53 records" 334 | type = string 335 | default = "" 336 | } 337 | 338 | variable "route53_record_name" { 339 | description = "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." 340 | type = string 341 | default = null 342 | } 343 | 344 | ################################################################################ 345 | # ECS 346 | ################################################################################ 347 | 348 | variable "create_cluster" { 349 | description = "Whether to create an ECS cluster or not" 350 | type = bool 351 | default = true 352 | } 353 | 354 | variable "cluster_arn" { 355 | description = "ARN of an existing ECS cluster where resources will be created. Required when `create_cluster` is `false`" 356 | type = string 357 | default = "" 358 | } 359 | 360 | variable "cluster" { 361 | 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" 362 | type = object({ 363 | # Cluster 364 | name = optional(string) 365 | configuration = optional(object({ 366 | execute_command_configuration = optional(object({ 367 | kms_key_id = optional(string) 368 | log_configuration = optional(object({ 369 | cloud_watch_encryption_enabled = optional(bool) 370 | cloud_watch_log_group_name = optional(string) 371 | s3_bucket_encryption_enabled = optional(bool) 372 | s3_bucket_name = optional(string) 373 | s3_kms_key_id = optional(string) 374 | s3_key_prefix = optional(string) 375 | })) 376 | logging = optional(string, "OVERRIDE") 377 | })) 378 | managed_storage_configuration = optional(object({ 379 | fargate_ephemeral_storage_kms_key_id = optional(string) 380 | kms_key_id = optional(string) 381 | })) 382 | }), 383 | # Default 384 | { 385 | execute_command_configuration = { 386 | log_configuration = { 387 | cloud_watch_log_group_name = "placeholder" # will use CloudWatch log group created by module 388 | } 389 | } 390 | } 391 | ) 392 | setting = optional(list(object({ 393 | name = string 394 | value = string 395 | })), 396 | # Default 397 | [{ 398 | name = "containerInsights" 399 | value = "enabled" 400 | }] 401 | ) 402 | 403 | # Cloudwatch log group 404 | create_cloudwatch_log_group = optional(bool, true) 405 | cloudwatch_log_group_retention_in_days = optional(number, 90) 406 | cloudwatch_log_group_kms_key_id = optional(string) 407 | cloudwatch_log_group_class = optional(string) 408 | cloudwatch_log_group_tags = optional(map(string), {}) 409 | 410 | # Capacity providers 411 | default_capacity_provider_strategy = optional( 412 | map(object({ 413 | base = optional(number) 414 | name = optional(string) # Will fall back to use map key if not set 415 | weight = optional(number) 416 | })), 417 | # Default 418 | { 419 | FARGATE = { 420 | weight = 100 421 | } 422 | } 423 | ) 424 | }) 425 | default = {} 426 | } 427 | 428 | variable "service" { 429 | 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" 430 | type = object({ 431 | capacity_provider_strategy = optional(map(object({ 432 | base = optional(number) 433 | capacity_provider = string 434 | weight = optional(number) 435 | }))) 436 | deployment_circuit_breaker = optional(object({ 437 | enable = bool 438 | rollback = bool 439 | })) 440 | enable_ecs_managed_tags = optional(bool, true) 441 | force_new_deployment = optional(bool, true) 442 | health_check_grace_period_seconds = optional(number) 443 | launch_type = optional(string, "FARGATE") 444 | load_balancer = optional(any, {}) 445 | name = optional(string) 446 | assign_public_ip = optional(bool, false) 447 | security_group_ids = optional(list(string), []) 448 | subnet_ids = optional(list(string), []) 449 | platform_version = optional(string) 450 | propagate_tags = optional(string) 451 | timeouts = optional(object({ 452 | create = optional(string) 453 | delete = optional(string) 454 | update = optional(string) 455 | })) 456 | triggers = optional(map(string)) 457 | wait_for_steady_state = optional(bool) 458 | 459 | # Service IAM Role 460 | create_iam_role = optional(bool, true) 461 | iam_role_arn = optional(string) 462 | iam_role_name = optional(string) 463 | iam_role_use_name_prefix = optional(bool, true) 464 | iam_role_path = optional(string) 465 | iam_role_description = optional(string) 466 | iam_role_permissions_boundary = optional(string) 467 | iam_role_tags = optional(map(string), {}) 468 | iam_role_statements = optional(list(object({ 469 | sid = optional(string) 470 | actions = optional(list(string)) 471 | not_actions = optional(list(string)) 472 | effect = optional(string) 473 | resources = optional(list(string)) 474 | not_resources = optional(list(string)) 475 | principals = optional(list(object({ 476 | type = string 477 | identifiers = list(string) 478 | }))) 479 | not_principals = optional(list(object({ 480 | type = string 481 | identifiers = list(string) 482 | }))) 483 | condition = optional(list(object({ 484 | test = string 485 | values = list(string) 486 | variable = string 487 | }))) 488 | }))) 489 | 490 | # Task Definition 491 | create_task_definition = optional(bool, true) 492 | task_definition_arn = optional(string) 493 | container_definitions = optional(any, {}) 494 | cpu = optional(number, 2048) 495 | ephemeral_storage = optional(object({ 496 | size_in_gib = number 497 | })) 498 | family = optional(string) 499 | memory = optional(number, 4096) 500 | requires_compatibilities = optional(list(string), ["FARGATE"]) 501 | runtime_platform = optional( 502 | object({ 503 | cpu_architecture = optional(string) 504 | operating_system_family = optional(string) 505 | }), 506 | # Default 507 | { 508 | operating_system_family = "LINUX" 509 | cpu_architecture = "ARM64" 510 | } 511 | ) 512 | volume = optional(any, {}) 513 | task_tags = optional(map(string), {}) 514 | 515 | # Task Execution IAM Role 516 | create_task_exec_iam_role = optional(bool, true) 517 | task_exec_iam_role_arn = optional(string) 518 | task_exec_iam_role_name = optional(string) 519 | task_exec_iam_role_use_name_prefix = optional(bool, true) 520 | task_exec_iam_role_path = optional(string) 521 | task_exec_iam_role_description = optional(string) 522 | task_exec_iam_role_permissions_boundary = optional(string) 523 | task_exec_iam_role_tags = optional(map(string), {}) 524 | task_exec_iam_role_policies = optional(map(string), {}) 525 | task_exec_iam_role_max_session_duration = optional(number) 526 | 527 | # Task Execution IAM Role Policy 528 | create_task_exec_policy = optional(bool, true) 529 | task_exec_ssm_param_arns = optional(list(string), []) 530 | task_exec_secret_arns = optional(list(string), []) 531 | task_exec_iam_statements = optional(list(object({ 532 | sid = optional(string) 533 | actions = optional(list(string)) 534 | not_actions = optional(list(string)) 535 | effect = optional(string) 536 | resources = optional(list(string)) 537 | not_resources = optional(list(string)) 538 | principals = optional(list(object({ 539 | type = string 540 | identifiers = list(string) 541 | }))) 542 | not_principals = optional(list(object({ 543 | type = string 544 | identifiers = list(string) 545 | }))) 546 | condition = optional(list(object({ 547 | test = string 548 | values = list(string) 549 | variable = string 550 | }))) 551 | }))) 552 | 553 | # Tasks - IAM role 554 | create_tasks_iam_role = optional(bool, true) 555 | tasks_iam_role_arn = optional(string) 556 | tasks_iam_role_name = optional(string) 557 | tasks_iam_role_use_name_prefix = optional(bool, true) 558 | tasks_iam_role_path = optional(string) 559 | tasks_iam_role_description = optional(string) 560 | tasks_iam_role_permissions_boundary = optional(string) 561 | tasks_iam_role_tags = optional(map(string), {}) 562 | tasks_iam_role_policies = optional(map(string), {}) 563 | tasks_iam_role_statements = optional(list(object({ 564 | sid = optional(string) 565 | actions = optional(list(string)) 566 | not_actions = optional(list(string)) 567 | effect = optional(string) 568 | resources = optional(list(string)) 569 | not_resources = optional(list(string)) 570 | principals = optional(list(object({ 571 | type = string 572 | identifiers = list(string) 573 | }))) 574 | not_principals = optional(list(object({ 575 | type = string 576 | identifiers = list(string) 577 | }))) 578 | condition = optional(list(object({ 579 | test = string 580 | values = list(string) 581 | variable = string 582 | }))) 583 | }))) 584 | 585 | # Security Group 586 | create_security_group = optional(bool, true) 587 | security_group_name = optional(string) 588 | security_group_use_name_prefix = optional(bool, true) 589 | security_group_description = optional(string) 590 | security_group_ingress_rules = optional(any, {}) 591 | security_group_egress_rules = optional(any, 592 | { 593 | egress = { 594 | ip_protocol = "-1" 595 | cidr_ipv4 = "0.0.0.0/0" 596 | } 597 | } 598 | ) 599 | security_group_tags = optional(map(string), {}) 600 | }) 601 | default = {} 602 | } 603 | 604 | ################################################################################ 605 | # EFS 606 | ################################################################################ 607 | 608 | variable "enable_efs" { 609 | description = "Determines whether to create and utilize an EFS filesystem" 610 | type = bool 611 | default = false 612 | } 613 | 614 | variable "efs" { 615 | 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" 616 | type = object({ 617 | name = optional(string) 618 | 619 | # File System 620 | availability_zone_name = optional(string) 621 | creation_token = optional(string) 622 | performance_mode = optional(string) 623 | encrypted = optional(bool, true) 624 | kms_key_arn = optional(string) 625 | provisioned_throughput_in_mibps = optional(number) 626 | throughput_mode = optional(string) 627 | lifecycle_policy = optional(object({ 628 | transition_to_ia = optional(string) 629 | transition_to_archive = optional(string) 630 | transition_to_primary_storage_class = optional(string) 631 | })) 632 | protection = optional(object({ 633 | replication_overwrite = optional(string) 634 | })) 635 | 636 | # File System Policy 637 | attach_policy = optional(bool, true) 638 | bypass_policy_lockout_safety_check = optional(bool) 639 | source_policy_documents = optional(list(string), []) 640 | override_policy_documents = optional(list(string), []) 641 | policy_statements = optional(any, {}) 642 | deny_nonsecure_transport = optional(bool, true) 643 | deny_nonsecure_transport_via_mount_target = optional(bool, true) 644 | 645 | # Mount targets 646 | mount_targets = optional(map(object({ 647 | ip_address = optional(string) 648 | ip_address_type = optional(string) 649 | ipv6_address = optional(string) 650 | region = optional(string) 651 | security_groups = optional(list(string), []) 652 | subnet_id = string 653 | })), 654 | # Default 655 | {} 656 | ) 657 | 658 | # Security Group 659 | create_security_group = optional(bool, true) 660 | security_group_name = optional(string) 661 | security_group_use_name_prefix = optional(bool, true) 662 | security_group_description = optional(string) 663 | security_group_ingress_rules = optional(any, {}) 664 | 665 | # Access Point(s) 666 | access_points = optional(any, {}) 667 | }) 668 | default = {} 669 | } 670 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Atlantis on AWS Fargate Terraform Module 2 | 3 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) 4 | 5 | [Atlantis](https://www.runatlantis.io/) is tool which provides unified workflow for collaborating on Terraform through GitHub, GitLab and Bitbucket Cloud. 6 | 7 | > [!CAUTION] 8 | > 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). 9 | 10 | ## Usage 11 | 12 | GitHub is shown below in usage examples; however, any git provider supported by Atlantis can be used by simply using the correct Atlantis environment variables and configuring the respective webhook for the given git provider. 13 | 14 | See the [Supplemental Docs](https://github.com/terraform-aws-modules/terraform-aws-atlantis/blob/master/docs/README.md) for additional details on integrating with git providers. 15 | 16 | ### GitHub Complete 17 | 18 | The Atlantis module creates all resources required to run Atlantis on AWS Fargate. 19 | 20 | ```hcl 21 | module "atlantis" { 22 | source = "terraform-aws-modules/atlantis/aws" 23 | 24 | name = "atlantis" 25 | vpc_id = "vpc-1234556abcdef" 26 | 27 | # ECS Container Definition 28 | atlantis = { 29 | environment = [ 30 | { 31 | name = "ATLANTIS_GH_USER" 32 | value = "myuser" 33 | }, 34 | { 35 | name = "ATLANTIS_REPO_ALLOWLIST" 36 | value = "github.com/terraform-aws-modules/*" 37 | }, 38 | ] 39 | secrets = [ 40 | { 41 | name = "ATLANTIS_GH_TOKEN" 42 | valueFrom = "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i" 43 | }, 44 | { 45 | name = "ATLANTIS_GH_WEBHOOK_SECRET" 46 | valueFrom = "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F" 47 | }, 48 | ] 49 | } 50 | 51 | # ECS Service 52 | service = { 53 | subnet_ids = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] 54 | 55 | task_exec_secret_arns = [ 56 | "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i", 57 | "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F", 58 | ] 59 | # Provide Atlantis permission necessary to create/destroy resources 60 | tasks_iam_role_policies = { 61 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 62 | } 63 | } 64 | 65 | # ALB 66 | alb = { 67 | subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] 68 | } 69 | 70 | # ACM 71 | certificate_domain_name = "example.com" 72 | route53_zone_id = "Z2ES7B9AZ6SHAE" 73 | 74 | tags = { 75 | Environment = "dev" 76 | Terraform = "true" 77 | } 78 | } 79 | ``` 80 | 81 | ### GitHub Separate 82 | 83 | The Atlantis module creates most of resources required to run Atlantis on AWS Fargate, except for the ECS Cluster and ALB. This allows you to integrate Atlantis with your existing AWS infrastructure. 84 | 85 | ```hcl 86 | module "atlantis" { 87 | source = "terraform-aws-modules/atlantis/aws" 88 | 89 | name = "atlantis" 90 | vpc_id = "vpc-1234556abcdef" 91 | 92 | # Existing cluster 93 | create_cluster = false 94 | cluster_arn = "arn:aws:ecs:eu-west-1:123456789012:cluster/default" 95 | 96 | # Existing ALB 97 | create_alb = false 98 | alb_target_group_arn = "arn:aws:elasticloadbalancing:eu-west-1:1234567890:targetgroup/bluegreentarget1/209a844cd01825a4" 99 | alb_security_group_id = "sg-12345678" 100 | 101 | # ECS Container Definition 102 | atlantis = { 103 | environment = [ 104 | { 105 | name = "ATLANTIS_GH_USER" 106 | value = "myuser" 107 | }, 108 | { 109 | name = "ATLANTIS_REPO_ALLOWLIST" 110 | value = "github.com/terraform-aws-modules/*" 111 | }, 112 | ] 113 | secrets = [ 114 | { 115 | name = "ATLANTIS_GH_TOKEN" 116 | valueFrom = "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i" 117 | }, 118 | { 119 | name = "ATLANTIS_GH_WEBHOOK_SECRET" 120 | valueFrom = "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F" 121 | }, 122 | ] 123 | } 124 | 125 | # ECS Service 126 | service = { 127 | subnet_ids = ["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"] 128 | 129 | task_exec_secret_arns = [ 130 | "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes256-7g8H9i", 131 | "arn:aws:secretsmanager:eu-west-1:111122223333:secret:aes192-4D5e6F", 132 | ] 133 | # Provide Atlantis permission necessary to create/destroy resources 134 | tasks_iam_role_policies = { 135 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 136 | } 137 | } 138 | 139 | tags = { 140 | Environment = "dev" 141 | Terraform = "true" 142 | } 143 | } 144 | ``` 145 | 146 | ### Utilize EFS for Persistent Storage 147 | 148 | You can enable EFS to ensure that any plan outputs are persisted to EFS in the event that the Atlantis Task is replaced: 149 | 150 | ```hcl 151 | module "atlantis" { 152 | source = "terraform-aws-modules/atlantis/aws" 153 | 154 | # Truncated for brevity ... 155 | 156 | # EFS 157 | enable_efs = true 158 | efs = { 159 | mount_targets = { 160 | "eu-west-1a" = { 161 | subnet_id = "subnet-xyzde987" 162 | } 163 | "eu-west-1b" = { 164 | subnet_id = "subnet-slkjf456" 165 | } 166 | "eu-west-1c" = { 167 | subnet_id = "subnet-qeiru789" 168 | } 169 | } 170 | } 171 | } 172 | ``` 173 | 174 | ### Supply Atlantis server configuration 175 | 176 | `server-atlantis.yaml` 177 | 178 | ```yaml 179 | repos: 180 | - id: /.*/ 181 | allow_custom_workflows: true 182 | allowed_overrides: 183 | - apply_requirements 184 | - workflow 185 | apply_requirements: 186 | - approved 187 | workflow: default 188 | ``` 189 | 190 | `main.tf` 191 | 192 | ```hcl 193 | module "atlantis" { 194 | source = "terraform-aws-modules/atlantis/aws" 195 | 196 | # ... 197 | 198 | atlantis = { 199 | environment = [ 200 | { 201 | name : "ATLANTIS_REPO_CONFIG_JSON", 202 | value : jsonencode(yamldecode(file("${path.module}/server-atlantis.yaml"))), 203 | }, 204 | ] 205 | } 206 | } 207 | ``` 208 | 209 | ## Examples 210 | 211 | - [Complete Atlantis with GitHub webhook](https://github.com/terraform-aws-modules/terraform-aws-atlantis/tree/master/examples/github-complete) 212 | - [Separate Atlantis with GitHub webhook](https://github.com/terraform-aws-modules/terraform-aws-atlantis/tree/master/examples/github-separate) 213 | 214 | 215 | ## Requirements 216 | 217 | | Name | Version | 218 | |------|---------| 219 | | [terraform](#requirement\_terraform) | >= 1.10 | 220 | | [aws](#requirement\_aws) | >= 6.19 | 221 | 222 | ## Providers 223 | 224 | No providers. 225 | 226 | ## Modules 227 | 228 | | Name | Source | Version | 229 | |------|--------|---------| 230 | | [acm](#module\_acm) | terraform-aws-modules/acm/aws | 6.1.1 | 231 | | [alb](#module\_alb) | terraform-aws-modules/alb/aws | 10.2.0 | 232 | | [ecs\_cluster](#module\_ecs\_cluster) | terraform-aws-modules/ecs/aws//modules/cluster | 6.7.0 | 233 | | [ecs\_service](#module\_ecs\_service) | terraform-aws-modules/ecs/aws//modules/service | 6.7.0 | 234 | | [efs](#module\_efs) | terraform-aws-modules/efs/aws | 2.0.0 | 235 | 236 | ## Resources 237 | 238 | No resources. 239 | 240 | ## Inputs 241 | 242 | | Name | Description | Type | Default | Required | 243 | |------|-------------|------|---------|:--------:| 244 | | [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 | 245 | | [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 | 246 | | [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 | 247 | | [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
}))
}))
fqdn = optional(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 | 248 | | [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 | 249 | | [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 | 250 | | [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 | 251 | | [cluster\_arn](#input\_cluster\_arn) | ARN of an existing ECS cluster where resources will be created. Required when `create_cluster` is `false` | `string` | `""` | no | 252 | | [create](#input\_create) | Controls if resources should be created (affects nearly all resources) | `bool` | `true` | no | 253 | | [create\_alb](#input\_create\_alb) | Determines whether to create an ALB or not | `bool` | `true` | no | 254 | | [create\_certificate](#input\_create\_certificate) | Determines whether to create an ACM certificate or not. If `false`, `certificate_arn` must be provided | `bool` | `true` | no | 255 | | [create\_cluster](#input\_create\_cluster) | Whether to create an ECS cluster or not | `bool` | `true` | no | 256 | | [create\_route53\_records](#input\_create\_route53\_records) | Determines whether to create Route53 `A` and `AAAA` records for the loadbalancer | `bool` | `true` | no | 257 | | [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 | 258 | | [enable\_efs](#input\_enable\_efs) | Determines whether to create and utilize an EFS filesystem | `bool` | `false` | no | 259 | | [name](#input\_name) | Common name to use on all resources created unless a more specific name is provided | `string` | `"atlantis"` | no | 260 | | [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | 261 | | [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 | 262 | | [route53\_zone\_id](#input\_route53\_zone\_id) | Route53 zone ID to use for ACM certificate and Route53 records | `string` | `""` | no | 263 | | [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 | 264 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | 265 | | [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 | 266 | | [vpc\_id](#input\_vpc\_id) | ID of the VPC where the resources will be provisioned | `string` | `""` | no | 267 | 268 | ## Outputs 269 | 270 | | Name | Description | 271 | |------|-------------| 272 | | [alb](#output\_alb) | ALB created and all of its associated outputs | 273 | | [cluster](#output\_cluster) | ECS cluster created and all of its associated outputs | 274 | | [efs](#output\_efs) | EFS created and all of its associated outputs | 275 | | [service](#output\_service) | ECS service created and all of its associated outputs | 276 | | [url](#output\_url) | URL of Atlantis | 277 | 278 | 279 | ## Authors 280 | 281 | Module is maintained by [Anton Babenko](https://github.com/antonbabenko) with help from [these awesome contributors](https://github.com/terraform-aws-modules/terraform-aws-atlantis/graphs/contributors). 282 | 283 | ## License 284 | 285 | Apache 2 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-atlantis/tree/master/LICENSE) for full details. 286 | 287 | ## Additional information for users from Russia and Belarus 288 | 289 | - Russia has [illegally annexed Crimea in 2014](https://en.wikipedia.org/wiki/Annexation_of_Crimea_by_the_Russian_Federation) and [brought the war in Donbas](https://en.wikipedia.org/wiki/War_in_Donbas) followed by [full-scale invasion of Ukraine in 2022](https://en.wikipedia.org/wiki/2022_Russian_invasion_of_Ukraine). 290 | - Russia has brought sorrow and devastations to millions of Ukrainians, killed hundreds of innocent people, damaged thousands of buildings, and forced several million people to flee. 291 | - [Putin khuylo!](https://en.wikipedia.org/wiki/Putin_khuylo!) 292 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [5.0.2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v5.0.1...v5.0.2) (2025-11-12) 6 | 7 | ### Bug Fixes 8 | 9 | * Update lookup logic for Atlantis URL due to variable optional attributes ([#428](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/428)) ([fd00ee1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/fd00ee10329ce21223951ea035536d3bfb190afb)) 10 | 11 | ## [5.0.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v5.0.0...v5.0.1) (2025-11-11) 12 | 13 | ### Bug Fixes 14 | 15 | * Add missing `fqdn` attribute from the `atlantis` variable ([#427](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/427)) ([192da24](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/192da2497c5113f093f66e992586da77165316ed)) 16 | 17 | ## [5.0.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.4.1...v5.0.0) (2025-11-10) 18 | 19 | ### ⚠ BREAKING CHANGES 20 | 21 | * Upgrade Terraform and AWS min required providers to 1.10 and `6.19` respectively (#426) 22 | 23 | ### Features 24 | 25 | * Upgrade Terraform and AWS min required providers to 1.10 and `6.19` respectively ([#426](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/426)) ([2b456f8](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/2b456f884bedfb0b326a8c88fa3ac0354f33cf98)) 26 | 27 | ## [4.4.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.4.0...v4.4.1) (2025-10-21) 28 | 29 | ### Bug Fixes 30 | 31 | * Update CI workflow versions to latest ([#407](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/407)) ([0ee2a20](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/0ee2a20432d43d40c0a0921bca5a6131e531d562)) 32 | * Update CI workflow versions to latest ([#423](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/423)) ([864eaca](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/864eaca26591fa9e9eaf2c5f116134e1baa1c380)) 33 | 34 | ## [4.4.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.3.0...v4.4.0) (2024-07-05) 35 | 36 | 37 | ### Features 38 | 39 | * Allow setting ALB specific tags ([#404](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/404)) ([bbf63ba](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/bbf63baaefe89650eb61fce51babf54b5ae29208)) 40 | 41 | ## [4.3.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.2.2...v4.3.0) (2024-04-04) 42 | 43 | 44 | ### Features 45 | 46 | * Configure max_session_duration for the ECS Task Execution role ([#401](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/401)) ([c92654a](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/c92654a9dba29c67614a0864ce209ba6c7a1a420)) 47 | 48 | ## [4.2.2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.2.1...v4.2.2) (2024-03-07) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * Update CI workflow versions to remove deprecated runtime warnings ([#400](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/400)) ([8acee87](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/8acee87e001f3e3fce4b89406011e00803cbcf87)) 54 | 55 | ### [4.2.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.2.0...v4.2.1) (2024-03-04) 56 | 57 | 58 | ### Bug Fixes 59 | 60 | * Change default deployment percentages when using EFS to allow updates to succeed ([#399](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/399)) ([834bc0d](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/834bc0da151eabaa459ebe838fc1ca6e4184d11e)) 61 | 62 | ## [4.2.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.1.0...v4.2.0) (2024-01-18) 63 | 64 | 65 | ### Features 66 | 67 | * Add support for different name for EFS ([#392](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/392)) ([bf31af0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/bf31af0c27f0e060ec1e7735e365e82925e0e531)) 68 | 69 | ## [4.1.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.8...v4.1.0) (2024-01-18) 70 | 71 | 72 | ### Features 73 | 74 | * Configurable default action https listener ([#391](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/391)) ([7e75eec](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/7e75eec8a67bc428263e73320922a279081ac0bb)) 75 | 76 | ### [4.0.8](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.7...v4.0.8) (2023-12-22) 77 | 78 | 79 | ### Bug Fixes 80 | 81 | * Add ALB Target Group Name ([#389](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/389)) ([8e6599f](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/8e6599f0a03c4d0fd99359838a12518b77b087e2)) 82 | 83 | ### [4.0.7](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.6...v4.0.7) (2023-12-21) 84 | 85 | 86 | ### Bug Fixes 87 | 88 | * Add 'Name' Tag to EFS File System ([#387](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/387)) ([fb4acfc](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/fb4acfc252e15aa3c0a12df8f4e36de43621cdcc)) 89 | 90 | ### [4.0.6](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.5...v4.0.6) (2023-12-11) 91 | 92 | 93 | ### Bug Fixes 94 | 95 | * FQDN detection when using an existing ALB ([#379](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/379)) ([50ee855](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/50ee85553f7473c9d4e680b7cbb172de5304798d)) 96 | 97 | ### [4.0.5](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.4...v4.0.5) (2023-11-30) 98 | 99 | 100 | ### Bug Fixes 101 | 102 | * Correct ALB atlantis target group protocol and port arguments ([#375](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/375)) ([cc3e2c2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/cc3e2c282f009694d5ce69d3d7d40a0cf0748c7d)) 103 | 104 | ### [4.0.4](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.3...v4.0.4) (2023-11-30) 105 | 106 | 107 | ### Bug Fixes 108 | 109 | * Give Atlantis write permission to EFS ([#376](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/376)) ([1db4a44](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/1db4a445b4e3aab3a00995838273c3589d39ca17)) 110 | 111 | ### [4.0.3](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.2...v4.0.3) (2023-11-16) 112 | 113 | 114 | ### Bug Fixes 115 | 116 | * Correct security group egress rule lookup name ([#372](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/372)) ([a5e3f83](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/a5e3f837b7c1735690cb1439459461ff0c78614c)) 117 | 118 | ### [4.0.2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.1...v4.0.2) (2023-11-10) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * Ensure conditional creation of EFS and entire module are functioning as intended ([#370](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/370)) ([2a8d178](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/2a8d178773d1ec3b2cbae5bac4f1da99ba6a4963)) 124 | 125 | ### [4.0.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v4.0.0...v4.0.1) (2023-11-10) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * Correct EFS mount and correct listener authentication when value is not provided ([#368](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/368)) ([e031208](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/e0312088d38e4793673961069d2cf5bf22f2263f)) 131 | 132 | ## [4.0.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.28.0...v4.0.0) (2023-11-04) 133 | 134 | 135 | ### ⚠ BREAKING CHANGES 136 | 137 | * Refactor to use latest modules provided by `terraform-aws-modules` (#366) 138 | 139 | ### Features 140 | 141 | * Refactor to use latest modules provided by `terraform-aws-modules` ([#366](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/366)) ([65d1982](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/65d19824d9f30b7f0489a364c1be87e4046c1d93)) 142 | 143 | ## [3.28.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.27.0...v3.28.0) (2023-05-12) 144 | 145 | 146 | ### Features 147 | 148 | * Make the enable_nat_gateway and single_nat_gateway variables configurable ([#343](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/343)) ([375a926](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/375a926af8c5c9020e21861b45eb5cb9380cf776)) 149 | 150 | ## [3.27.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.26.1...v3.27.0) (2023-05-12) 151 | 152 | 153 | ### Features 154 | 155 | * Add EFS performance settings. ([#339](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/339)) ([ba3ecf9](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/ba3ecf96bcef5c32653219f06a3c373af1aca6bf)) 156 | 157 | ### [3.26.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.26.0...v3.26.1) (2023-05-12) 158 | 159 | 160 | ### Bug Fixes 161 | 162 | * Gitlab versioning errors with terraform 0.13 ([#344](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/344)) ([359ab38](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/359ab388ec9e34261268bd927e4013f8a7a230ea)) 163 | 164 | ## [3.26.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.25.0...v3.26.0) (2022-12-15) 165 | 166 | 167 | ### Features 168 | 169 | * Add ability to enable cross-zone load balancing ([#326](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/326)) ([1d1c75f](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/1d1c75f3396550920e4f55f2c2e10b99d39eecbb)) 170 | 171 | ## [3.25.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.24.1...v3.25.0) (2022-11-16) 172 | 173 | 174 | ### Features 175 | 176 | * Use base security-group module to remove duplicate EFS security group ([#325](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/325)) ([8433f55](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/8433f5562daba6a1bcf28a57982564827f7bfed8)) 177 | 178 | ### [3.24.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.24.0...v3.24.1) (2022-11-07) 179 | 180 | 181 | ### Bug Fixes 182 | 183 | * Update CI configuration files to use latest version ([#323](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/323)) ([cf975dd](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/cf975dd765b739ac9f3965ca81416c37f1f85c35)) 184 | 185 | ## [3.24.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.23.1...v3.24.0) (2022-11-03) 186 | 187 | 188 | ### Features 189 | 190 | * Add permissions to access repository credentials to `ecs_task_access_secrets` ([#306](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/306)) ([15e9d9b](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/15e9d9be786c74e7fda7aa621292500fc2e0dea4)) 191 | 192 | ### [3.23.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.23.0...v3.23.1) (2022-11-01) 193 | 194 | 195 | ### Bug Fixes 196 | 197 | * Remove unneeded ingress for EFS traffic from the entire VPC ([#318](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/318)) ([9e0c0ff](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/9e0c0ff1d3601d8e536b2d672cba4d1379286908)) 198 | 199 | ## [3.23.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.22.1...v3.23.0) (2022-10-31) 200 | 201 | 202 | ### Features 203 | 204 | * Added support for GitHub app ([#276](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/276)) ([27def83](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/27def8345252cbd17904f3a31188ed4f12aa7a88)) 205 | 206 | ### [3.22.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.22.0...v3.22.1) (2022-10-22) 207 | 208 | 209 | ### Bug Fixes 210 | 211 | * Cannot specify more than one extra_container_definitions ([#314](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/314)) ([7c1ad25](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/7c1ad25b53fb47db1c70086d2154a9532d320cd4)) 212 | 213 | ## [3.22.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.21.0...v3.22.0) (2022-10-13) 214 | 215 | 216 | ### Features 217 | 218 | * Add path option to IAM roles created under this module ([#311](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/311)) ([fe833a0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/fe833a0420e517ba2b63390c2063a49b6859ee62)) 219 | 220 | ## [3.21.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.20.0...v3.21.0) (2022-09-22) 221 | 222 | 223 | ### Features 224 | 225 | * Enable encrypt function on EFS ([#296](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/296)) ([792a685](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/792a685d8feea43e38d081d316c0b1915d656001)) 226 | 227 | ## [3.20.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.19.0...v3.20.0) (2022-09-21) 228 | 229 | 230 | ### Features 231 | 232 | * Add arguments in EFS file system ([#294](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/294)) ([089eb6c](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/089eb6c1e8dfeef45f4e9891714d86cb0783ac6b)) 233 | 234 | ## [3.19.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.18.0...v3.19.0) (2022-09-07) 235 | 236 | 237 | ### Features 238 | 239 | * Add output with public IP for whitelisting ([#309](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/309)) ([eb50e48](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/eb50e48854339969f480432d987ce4e1b3b69bee)) 240 | 241 | ## [3.18.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.17.1...v3.18.0) (2022-07-14) 242 | 243 | 244 | ### Features 245 | 246 | * Add `task_execution_session_duration` for task execution role ([#300](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/300)) ([16162ff](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/16162ff6b679f6d084aae81d016756c7165ff461)) 247 | 248 | ### [3.17.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.17.0...v3.17.1) (2022-06-22) 249 | 250 | 251 | ### Bug Fixes 252 | 253 | * set correct default for runtime_platform variable to ensure idempotence ([#291](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/291)) ([96c8613](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/96c861355985b81226c0119afab46fc8eb44ec30)) 254 | 255 | ## [3.17.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.16.0...v3.17.0) (2022-06-15) 256 | 257 | 258 | ### Features 259 | 260 | * Ensure EFS is owned by the posix_user to avoid permission issues ([#287](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/287)) ([61cdf8f](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/61cdf8fd3dec550c47f3b817ea301927e2f18473)) 261 | 262 | ## [3.16.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.15.1...v3.16.0) (2022-05-15) 263 | 264 | 265 | ### Features 266 | 267 | * Add support for runtime_platform config block ([#279](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/279)) ([4b93dee](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/4b93deee7032072811e9d5f8192154a58c40fb82)) 268 | 269 | ### [3.15.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.15.0...v3.15.1) (2022-05-09) 270 | 271 | 272 | ### Bug Fixes 273 | 274 | * Fix the GitHub complete example ([#277](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/277)) ([47bd5d4](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/47bd5d476cba1bcf716923bfdb110ae81555783c)) 275 | 276 | ## [3.15.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.14.0...v3.15.0) (2022-04-26) 277 | 278 | 279 | ### Features 280 | 281 | * Introduce IPv6 CIDR specific allow ALBs variables ([#275](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/275)) ([bc5ad7c](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/bc5ad7c88b631a9d00e1a88bfb9b45873cbce017)) 282 | 283 | ## [3.14.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.13.1...v3.14.0) (2022-04-01) 284 | 285 | 286 | ### Features 287 | 288 | * Add IPv6 support (ALB and Route53 AAAA record) ([#256](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/256)) ([6cefda0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/6cefda0c23ae3632a2198ca61b2fd7c4688c9c87)) 289 | 290 | ### [3.13.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.13.0...v3.13.1) (2022-04-01) 291 | 292 | 293 | ### Bug Fixes 294 | 295 | * Only create mount point for EFS when using EFS ([#261](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/261)) ([b1b61f3](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/b1b61f33081b17953a809645b7ed0a09f8c154c0)) 296 | 297 | ## [3.13.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.12.0...v3.13.0) (2022-03-12) 298 | 299 | 300 | ### Features 301 | 302 | * Made it clear that we stand with Ukraine ([e798c34](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/e798c34cb40e8e8041c55367b99a310c06a03d13)) 303 | 304 | ## [3.12.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.11.0...v3.12.0) (2022-02-11) 305 | 306 | 307 | ### Features 308 | 309 | * Allow for an existing ECS cluster to be used ([#233](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/233)) ([6b7594a](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/6b7594ae487472d4947518571209c2e380341d45)) 310 | 311 | ## [3.11.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.10.0...v3.11.0) (2022-02-10) 312 | 313 | 314 | ### Features 315 | 316 | * Added a possibility to allow private hosted zone usage ([#250](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/250)) ([5a53f39](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/5a53f39f0dc4942a2044451ef63752b7b9c807ab)) 317 | 318 | ## [3.10.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.9.0...v3.10.0) (2022-02-10) 319 | 320 | 321 | ### Features 322 | 323 | * Added support for persisting Atlantis state using EFS ([#247](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/247)) ([79d152e](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/79d152eeaea5fdf512c4d6ef3cb11143e38e0803)) 324 | 325 | ## [3.9.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.8.0...v3.9.0) (2022-02-08) 326 | 327 | 328 | ### Features 329 | 330 | * Remove not used parameter `atlantis_allowed_repo_names` ([#221](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/221)) ([6cbd47d](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/6cbd47dfe45fb45c0b5d99b238a7837a51e667f5)) 331 | 332 | ## [3.8.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.7.0...v3.8.0) (2022-01-19) 333 | 334 | 335 | ### Features 336 | 337 | * Allow CloudWatch Log Encryption and Default Security Group Management ([#246](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/246)) ([6a27fff](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/6a27fffbd64fc92e49ee6449b937498a9dc35856)) 338 | 339 | ## [3.7.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.6.0...v3.7.0) (2022-01-17) 340 | 341 | 342 | ### Features 343 | 344 | * Add base URL for GitHub Enterprise ([#244](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/244)) ([4195ea2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/4195ea27c69db0b1863be5cc479eea7bd9051dfe)) 345 | 346 | ## [3.6.0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.5.3...v3.6.0) (2022-01-07) 347 | 348 | 349 | ### Features 350 | 351 | * Allow more than 5 CIDRs in whitelist_unauthenticated_cidr_blocks ([#220](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/220)) ([df10f7b](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/df10f7bc3d703dacdca3de2dc2b773c730d72898)) 352 | 353 | ## [3.5.3](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.5.2...v3.5.3) (2021-12-06) 354 | 355 | 356 | ### Bug Fixes 357 | 358 | * atlantis health check path ([#242](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/242)) ([0b17a41](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/0b17a4102f5f21e7a6de72a3b9ed7760c4ca7c9a)) 359 | * ensure pre-commit is using latest version via HTTPS ([#240](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/240)) ([57935f0](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/57935f0530e4502ddc6da2621600d887488f4c76)) 360 | 361 | ## [3.5.2](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.5.1...v3.5.2) (2021-11-19) 362 | 363 | 364 | ### Bug Fixes 365 | 366 | * correct semantic-release message that is causing releases to fail ([#239](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/239)) ([ff0e47d](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/ff0e47d995e1f2b32b7dafeed78a8e706fc62857)) 367 | 368 | ## [3.5.1](https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.5.0...v3.5.1) (2021-11-19) 369 | 370 | 371 | ### Bug Fixes 372 | 373 | * update CI/CD process to enable auto-release workflow ([#237](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/237)) ([75b3376](https://github.com/terraform-aws-modules/terraform-aws-atlantis/commit/75b33768f7943474070feef5687aa3e147af9814)) 374 | 375 | 376 | ## [v3.5.0] - 2021-11-14 377 | 378 | - feat: Add ability to use Fargate Ephemeral Storage ([#229](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/229)) 379 | - docs: Added google oidc example to readme ([#234](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/234)) 380 | 381 | 382 | 383 | ## [v3.4.0] - 2021-11-01 384 | 385 | - feat: Added ability to add extra loadbalancer blocks to ECS task ([#232](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/232)) 386 | 387 | 388 | 389 | ## [v3.3.0] - 2021-09-24 390 | 391 | - feat: Allow unauthenticated access for webhooks to /events endpoint if needed ([#226](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/226)) 392 | - fix: Add missing netblock (143.55.64.0/20) to GitHub webhook IP ranges ([#225](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/225)) 393 | 394 | 395 | 396 | ## [v3.2.0] - 2021-09-16 397 | 398 | - feat: Add sensitive flag for webhook secret outputs ([#222](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/222)) 399 | 400 | 401 | 402 | ## [v3.1.0] - 2021-09-01 403 | 404 | - feat: update default image to ghcr.io one ([#219](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/219)) 405 | 406 | 407 | 408 | ## [v3.0.0] - 2021-08-31 409 | 410 | - BREAKING CHANGE: update internal modules to latest, replace `github_organization` with `github_owner`, bump Terraform version to >=0.13.1 ([#218](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/218)) 411 | 412 | 413 | 414 | ## [v2.43.0] - 2021-08-17 415 | 416 | - feat: Added outputs of ECS and ALB resources ([#216](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/216)) 417 | 418 | 419 | 420 | ## [v2.42.0] - 2021-06-29 421 | 422 | - feat: Add support for AWS ECS Exec ([#209](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/209)) 423 | 424 | 425 | 426 | ## [v2.41.0] - 2021-05-17 427 | 428 | - feat: Only tag ecs service if longer arns are enabled in the aws account ([#153](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/153)) 429 | - docs: Example of providing server yaml configuration ([#205](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/205)) 430 | - chore: update CI/CD to use stable `terraform-docs` release artifact and discoverable Apache2.0 license ([#203](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/203)) 431 | 432 | 433 | 434 | ## [v2.40.0] - 2021-04-15 435 | 436 | - feat: Renamed option to repo_allowlist ([#198](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/198)) 437 | 438 | 439 | 440 | ## [v2.39.0] - 2021-04-13 441 | 442 | - feat: Add `force_new_deployment` switch ([#196](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/196)) 443 | 444 | 445 | 446 | ## [v2.38.0] - 2021-04-13 447 | 448 | - feat: Add enable deletion protection and drop invalid header fields ([#195](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/195)) 449 | 450 | 451 | 452 | ## [v2.37.0] - 2021-04-07 453 | 454 | - feat: allow adding more trusted principals to task role ([#193](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/193)) 455 | - chore: update documentation and pin `terraform_docs` version to avoid future changes ([#191](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/191)) 456 | 457 | 458 | 459 | ## [v2.36.0] - 2021-03-16 460 | 461 | - fix: Optionally lookup for the latest task definition ([#163](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/163)) 462 | - chore: Add okta oidc details in README ([#188](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/188)) 463 | 464 | 465 | 466 | ## [v2.35.0] - 2021-03-02 467 | 468 | - fix: revert module Terraform 0.13.x version upgrade ([#186](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/186)) 469 | 470 | 471 | 472 | ## [v2.34.0] - 2021-03-01 473 | 474 | - fix: Update syntax for Terraform 0.15 ([#184](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/184)) 475 | 476 | 477 | 478 | ## [v2.33.0] - 2021-03-01 479 | 480 | - feat: allow setting container memory & cpu from task memory & cpu ([#169](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/169)) 481 | - chore: correct versions used and required versions ([#183](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/183)) 482 | - chore: add ci-cd workflow for pre-commit checks ([#182](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/182)) 483 | 484 | 485 | 486 | ## [v2.32.0] - 2021-02-20 487 | 488 | - chore: update documentation based on latest `terraform-docs` which includes module and resource sections ([#180](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/180)) 489 | 490 | 491 | 492 | ## [v2.31.0] - 2021-02-08 493 | 494 | - feat: Add enable_ecs_managed_tags and propagate_tags arguments to ecs_service ([#177](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/177)) 495 | 496 | 497 | 498 | ## [v2.30.0] - 2020-12-29 499 | 500 | - feat: Add permissions boundary to ecs task iam role ([#176](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/176)) 501 | 502 | 503 | 504 | ## [v2.29.0] - 2020-12-24 505 | 506 | - feat: support custom platform version ([#170](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/170)) 507 | 508 | 509 | 510 | ## [v2.28.0] - 2020-12-20 511 | 512 | - fix: Update module dependencies for TF 0.14 support ([#172](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/172)) 513 | 514 | 515 | 516 | ## [v2.27.0] - 2020-12-10 517 | 518 | - feat: allow adding more trusted principals to task role ([#155](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/155)) 519 | 520 | 521 | 522 | ## [v2.26.0] - 2020-11-13 523 | 524 | - feat: allow for extra_container_definitions ([#162](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/162)) 525 | 526 | 527 | 528 | ## [v2.25.0] - 2020-11-10 529 | 530 | - feat: Added support for Fargate Spot ([#164](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/164)) 531 | 532 | 533 | 534 | ## [v2.24.0] - 2020-09-01 535 | 536 | - feat: Use atlantis bot instead of a github user ([#151](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/151)) 537 | 538 | 539 | 540 | ## [v2.23.0] - 2020-08-18 541 | 542 | - feat: add variable to set SSL listener policy ([#150](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/150)) 543 | 544 | 545 | 546 | ## [v2.22.0] - 2020-08-17 547 | 548 | - feat: Additional tags to security groups ([#142](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/142)) 549 | 550 | 551 | 552 | ## [v2.21.0] - 2020-08-17 553 | 554 | - feat: update container definition including additional parameters to configure ([#148](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/148)) 555 | 556 | 557 | 558 | ## [v2.20.0] - 2020-06-29 559 | 560 | - feat: Allow hide-prev-plan-comments ([#138](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/138)) 561 | 562 | 563 | 564 | ## [v2.19.0] - 2020-06-23 565 | 566 | - feat: Add tags to aws_ecs_service resource ([#136](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/136)) 567 | 568 | 569 | 570 | ## [v2.18.0] - 2020-06-20 571 | 572 | - feat: Refactor to use SSM ARNs directly from resources ([#135](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/135)) 573 | - fix: cognito variables expect "user_pool_client_id" and "user_pool_domain" ([#134](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/134)) 574 | 575 | 576 | 577 | ## [v2.17.0] - 2020-05-27 578 | 579 | - feat: Support ALB authentication using AWS Cognito ([#102](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/102)) 580 | 581 | 582 | 583 | ## [v2.16.0] - 2020-05-13 584 | 585 | - feat: Added support for unauthenticated access (eg, Github webhook) ([#123](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/123)) 586 | 587 | 588 | 589 | ## [v2.15.0] - 2020-05-13 590 | 591 | - feat: Added ALB authentication feature with OpenID Connect (eg, Auth0) ([#122](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/122)) 592 | 593 | 594 | 595 | ## [v2.14.0] - 2020-05-12 596 | 597 | - fix: Revert deleted tags from many resources since release 2.7.0 ([#121](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/121)) 598 | 599 | 600 | 601 | ## [v2.13.0] - 2020-05-12 602 | 603 | - feat: Allow custom Route53 record name (including empty) ([#120](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/120)) 604 | 605 | 606 | 607 | ## [v2.12.0] - 2020-05-12 608 | 609 | - feat: Added atlantis_fqdn to override route53 and ALB dns name (closes [#94](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/94)) 610 | - fix: Expose ECS service security group as ouptut (closes [#87](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/87)) 611 | 612 | 613 | 614 | ## [v2.11.0] - 2020-05-12 615 | 616 | - feat: Allow setting of Atlantis log level ([#118](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/118)) 617 | 618 | 619 | 620 | ## [v2.10.0] - 2020-05-12 621 | 622 | - feat: Updated versions of VPC, SG, ACM modules ([#117](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/117)) 623 | 624 | 625 | 626 | ## [v2.9.0] - 2020-05-12 627 | 628 | - feat: Add support for internal load balancer, upgraded ALB module ([#99](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/99)) 629 | 630 | 631 | 632 | ## [v2.8.0] - 2020-05-11 633 | 634 | - fix: Update deprecated ALB listener rule format ([#89](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/89)) 635 | - docs: Minor doc edits ([#100](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/100)) 636 | 637 | 638 | 639 | ## [v2.7.0] - 2020-05-11 640 | 641 | - fix: Updated version of cloudposse/ecs-container-definition/aws to 0.23.0 (closed [#86](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/86)) 642 | 643 | 644 | 645 | ## [v2.6.0] - 2020-04-13 646 | 647 | - docs: Fixed README after terraform-docs was updated 648 | - feat: Added tags to cluster, task, ssm, role, and fmt ([#115](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/115)) 649 | 650 | 651 | 652 | ## [v2.5.0] - 2020-02-22 653 | 654 | - Updated pre-commit-terraform with README 655 | - feat: add support for bitbucket stash base url ([#79](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/79)) 656 | 657 | 658 | 659 | ## [v2.4.0] - 2019-11-15 660 | 661 | - Govcloud ([#84](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/84)) 662 | 663 | 664 | 665 | ## [v2.3.0] - 2019-11-12 666 | 667 | - Updated version of terraform-aws-acm module to v2.4.0 ([#81](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/81)) 668 | 669 | 670 | 671 | ## [v2.2.0] - 2019-07-21 672 | 673 | - Update documentation a bit after merge 674 | - Add capability to attach additional security groups to ALB ([#66](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/66)) 675 | 676 | 677 | 678 | ## [v2.1.0] - 2019-06-13 679 | 680 | - Fixed task creation when ECS task definition has not been created before ([#62](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/62)) 681 | 682 | 683 | 684 | ## [v2.0.0] - 2019-06-12 685 | 686 | - Upgraded module to support Terraform 0.12 ([#58](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/58)) 687 | 688 | 689 | 690 | ## [v1.18.0] - 2019-06-12 691 | 692 | - Add Task Definition Output ([#53](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/53)) 693 | 694 | 695 | 696 | ## [v1.17.0] - 2019-04-26 697 | 698 | - Add optional support for ALB logging ([#49](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/49)) 699 | 700 | 701 | 702 | ## [v1.16.0] - 2019-03-18 703 | 704 | - Fix github user token env to ATLANTIS_GH_TOKEN ([#46](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/46)) 705 | 706 | 707 | 708 | ## [v1.15.0] - 2019-03-16 709 | 710 | - Add support for Bitbucket Cloud ([#45](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/45)) 711 | 712 | 713 | 714 | ## [v1.14.0] - 2019-03-16 715 | 716 | - add alb dns name to outputs ([#44](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/44)) 717 | 718 | 719 | 720 | ## [v1.13.0] - 2019-03-07 721 | 722 | - workaround to not error on accessing value on data element that doesn't exist ([#42](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/42)) 723 | - replace /20 to /16 in README.md ([#40](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/40)) 724 | 725 | 726 | 727 | ## [v1.12.0] - 2019-02-14 728 | 729 | - Fixed documentation after [#38](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/38) 730 | - add vpc_id to outputs 731 | 732 | 733 | 734 | ## [v1.11.0] - 2019-02-07 735 | 736 | - Follow up for [#35](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/35) and [#36](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/36) 737 | - adding custom secrets and environment variables 738 | 739 | 740 | 741 | ## [v1.10.0] - 2019-02-01 742 | 743 | - Update acm module version for DNS validation issue 744 | - Update `cloudposse/ecs-container-definition/aws` to `v0.7.0` 745 | - Merge branch 'master' into refresh-module-versions 746 | - Refresh the underlying module to the latest release versions 747 | 748 | 749 | 750 | ## [v1.9.0] - 2019-01-18 751 | 752 | - Updated pre-commit 753 | - Adjust comments on ALB security groups 754 | - Add http -> https redirect on the ALB 755 | 756 | 757 | 758 | ## [v1.8.0] - 2019-01-07 759 | 760 | - Add variable to configure gitlab hostname 761 | 762 | 763 | 764 | ## [v1.7.1] - 2018-12-31 765 | 766 | - Removed obsolete tasks json files 767 | 768 | 769 | 770 | ## [v1.7.0] - 2018-12-31 771 | 772 | - Added secrets and refactored container definition section 773 | 774 | 775 | 776 | ## [v1.6.1] - 2018-12-14 777 | 778 | - Updated terraform.tfvars.sample 779 | 780 | 781 | 782 | ## [v1.6.0] - 2018-12-14 783 | 784 | - Cleanup before merge 785 | - Added support for gitlab and SSM parameter store 786 | - Fix README 787 | 788 | 789 | 790 | ## [v1.5.1] - 2018-09-28 791 | 792 | - Fixed README after merge 793 | 794 | 795 | 796 | ## [v1.5.0] - 2018-09-28 797 | 798 | - updates README 799 | - fixes typo variable name 800 | - allows custom value for alb ingress_cidr_blocks 801 | - mention about trailing dot of route53_zone_name in inputs 802 | - fix whitelist and zone_name example 803 | 804 | 805 | 806 | ## [v1.4.1] - 2018-09-14 807 | 808 | - Fixed example in README (thanks Giuseppe B.) 809 | 810 | 811 | 812 | ## [v1.4.0] - 2018-09-07 813 | 814 | - Fixes after [#18](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/18) 815 | - allow ECS task role to get multiple policiy attachments 816 | - [#7](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/7) updates README with policy_arn input 817 | - [#7](https://github.com/terraform-aws-modules/terraform-aws-atlantis/issues/7) pass ECs task exec. policy as input variable 818 | 819 | 820 | 821 | ## [v1.3.0] - 2018-08-19 822 | 823 | - Added a task role to the container 824 | - setthe maximum count to 200, and the minimum to 50%, so that there is no atlantis outage when deploying 825 | - added Task role output. Added the atlantis config in repo support 826 | - added Task role output. Added the atlantis config in repo support 827 | - Modified the atlantis definition to use a datasource that checks for the latest revision. 828 | - Modified the atlantis definition to use a datasource that checks for the latest revision. 829 | - Modified the atlantis definition to use a datasource that checks for the latest revision. 830 | - Modified the task definition to use the provided container name 831 | 832 | 833 | 834 | ## [v1.2.0] - 2018-06-03 835 | 836 | - Upgraded version of security-group 837 | 838 | 839 | 840 | ## [v1.1.1] - 2018-06-03 841 | 842 | - Added deregistration_delay=10 to update ALB faster 843 | 844 | 845 | 846 | ## [v1.1.0] - 2018-05-26 847 | 848 | - README fixes 849 | - README fixes 850 | - Allow reuse existing VPC and subnets 851 | - Format tfvars 852 | - Added github-repository-webhook 853 | 854 | 855 | 856 | ## v1.0.0 - 2018-05-25 857 | 858 | - Updated readme 859 | - Updated readme 860 | - Updated readme 861 | - Minor cleanup 862 | - Initial commit 863 | - Initial commit 864 | 865 | 866 | [Unreleased]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.5.0...HEAD 867 | [v3.5.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.4.0...v3.5.0 868 | [v3.4.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.3.0...v3.4.0 869 | [v3.3.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.2.0...v3.3.0 870 | [v3.2.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.1.0...v3.2.0 871 | [v3.1.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v3.0.0...v3.1.0 872 | [v3.0.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.43.0...v3.0.0 873 | [v2.43.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.42.0...v2.43.0 874 | [v2.42.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.41.0...v2.42.0 875 | [v2.41.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.40.0...v2.41.0 876 | [v2.40.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.39.0...v2.40.0 877 | [v2.39.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.38.0...v2.39.0 878 | [v2.38.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.37.0...v2.38.0 879 | [v2.37.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.36.0...v2.37.0 880 | [v2.36.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.35.0...v2.36.0 881 | [v2.35.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.34.0...v2.35.0 882 | [v2.34.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.33.0...v2.34.0 883 | [v2.33.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.32.0...v2.33.0 884 | [v2.32.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.31.0...v2.32.0 885 | [v2.31.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.30.0...v2.31.0 886 | [v2.30.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.29.0...v2.30.0 887 | [v2.29.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.28.0...v2.29.0 888 | [v2.28.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.27.0...v2.28.0 889 | [v2.27.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.26.0...v2.27.0 890 | [v2.26.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.25.0...v2.26.0 891 | [v2.25.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.24.0...v2.25.0 892 | [v2.24.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.23.0...v2.24.0 893 | [v2.23.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.22.0...v2.23.0 894 | [v2.22.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.21.0...v2.22.0 895 | [v2.21.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.20.0...v2.21.0 896 | [v2.20.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.19.0...v2.20.0 897 | [v2.19.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.18.0...v2.19.0 898 | [v2.18.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.17.0...v2.18.0 899 | [v2.17.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.16.0...v2.17.0 900 | [v2.16.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.15.0...v2.16.0 901 | [v2.15.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.14.0...v2.15.0 902 | [v2.14.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.13.0...v2.14.0 903 | [v2.13.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.12.0...v2.13.0 904 | [v2.12.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.11.0...v2.12.0 905 | [v2.11.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.10.0...v2.11.0 906 | [v2.10.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.9.0...v2.10.0 907 | [v2.9.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.8.0...v2.9.0 908 | [v2.8.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.7.0...v2.8.0 909 | [v2.7.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.6.0...v2.7.0 910 | [v2.6.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.5.0...v2.6.0 911 | [v2.5.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.4.0...v2.5.0 912 | [v2.4.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.3.0...v2.4.0 913 | [v2.3.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.2.0...v2.3.0 914 | [v2.2.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.1.0...v2.2.0 915 | [v2.1.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v2.0.0...v2.1.0 916 | [v2.0.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.18.0...v2.0.0 917 | [v1.18.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.17.0...v1.18.0 918 | [v1.17.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.16.0...v1.17.0 919 | [v1.16.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.15.0...v1.16.0 920 | [v1.15.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.14.0...v1.15.0 921 | [v1.14.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.13.0...v1.14.0 922 | [v1.13.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.12.0...v1.13.0 923 | [v1.12.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.11.0...v1.12.0 924 | [v1.11.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.10.0...v1.11.0 925 | [v1.10.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.9.0...v1.10.0 926 | [v1.9.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.8.0...v1.9.0 927 | [v1.8.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.7.1...v1.8.0 928 | [v1.7.1]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.7.0...v1.7.1 929 | [v1.7.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.6.1...v1.7.0 930 | [v1.6.1]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.6.0...v1.6.1 931 | [v1.6.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.5.1...v1.6.0 932 | [v1.5.1]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.5.0...v1.5.1 933 | [v1.5.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.4.1...v1.5.0 934 | [v1.4.1]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.4.0...v1.4.1 935 | [v1.4.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.3.0...v1.4.0 936 | [v1.3.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.2.0...v1.3.0 937 | [v1.2.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.1.1...v1.2.0 938 | [v1.1.1]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.1.0...v1.1.1 939 | [v1.1.0]: https://github.com/terraform-aws-modules/terraform-aws-atlantis/compare/v1.0.0...v1.1.0 940 | --------------------------------------------------------------------------------