├── .editorconfig
├── .github
└── workflows
│ ├── lock.yml
│ ├── pr-title.yml
│ ├── pre-commit.yml
│ ├── release.yml
│ └── stale-actions.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .releaserc.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── examples
├── README.md
└── complete
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── main.tf
├── outputs.tf
├── variables.tf
└── versions.tf
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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@v5.5.3
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 |
--------------------------------------------------------------------------------
/.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.19.0
11 | TFLINT_VERSION: v0.53.0
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@v4
22 |
23 | - name: Get root directories
24 | id: dirs
25 | uses: clowdhaus/terraform-composite-actions/directories@v1.9.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 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449
36 | - name: Delete huge unnecessary tools folder
37 | run: |
38 | rm -rf /opt/hostedtoolcache/CodeQL
39 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk
40 | rm -rf /opt/hostedtoolcache/Ruby
41 | rm -rf /opt/hostedtoolcache/go
42 |
43 | - name: Checkout
44 | uses: actions/checkout@v4
45 |
46 | - name: Terraform min/max versions
47 | id: minMax
48 | uses: clowdhaus/terraform-min-max@v1.3.1
49 | with:
50 | directory: ${{ matrix.directory }}
51 |
52 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }}
53 | # Run only validate pre-commit check on min version supported
54 | if: ${{ matrix.directory != '.' }}
55 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1
56 | with:
57 | terraform-version: ${{ steps.minMax.outputs.minVersion }}
58 | tflint-version: ${{ env.TFLINT_VERSION }}
59 | args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*'
60 |
61 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }}
62 | # Run only validate pre-commit check on min version supported
63 | if: ${{ matrix.directory == '.' }}
64 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1
65 | with:
66 | terraform-version: ${{ steps.minMax.outputs.minVersion }}
67 | tflint-version: ${{ env.TFLINT_VERSION }}
68 | args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)'
69 |
70 | preCommitMaxVersion:
71 | name: Max TF pre-commit
72 | runs-on: ubuntu-latest
73 | needs: collectInputs
74 | steps:
75 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449
76 | - name: Delete huge unnecessary tools folder
77 | run: |
78 | rm -rf /opt/hostedtoolcache/CodeQL
79 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk
80 | rm -rf /opt/hostedtoolcache/Ruby
81 | rm -rf /opt/hostedtoolcache/go
82 |
83 | - name: Checkout
84 | uses: actions/checkout@v4
85 | with:
86 | ref: ${{ github.event.pull_request.head.ref }}
87 | repository: ${{github.event.pull_request.head.repo.full_name}}
88 |
89 | - name: Terraform min/max versions
90 | id: minMax
91 | uses: clowdhaus/terraform-min-max@v1.3.1
92 |
93 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }}
94 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1
95 | with:
96 | terraform-version: ${{ steps.minMax.outputs.maxVersion }}
97 | tflint-version: ${{ env.TFLINT_VERSION }}
98 | terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }}
99 | install-hcledit: true
100 |
--------------------------------------------------------------------------------
/.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@v4
24 | with:
25 | persist-credentials: false
26 | fetch-depth: 0
27 |
28 | - name: Release
29 | uses: cycjimmy/semantic-release-action@v4
30 | with:
31 | semantic_version: 23.0.2
32 | extra_plugins: |
33 | @semantic-release/changelog@6.0.3
34 | @semantic-release/git@10.0.1
35 | conventional-changelog-conventionalcommits@7.0.2
36 | env:
37 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
38 |
--------------------------------------------------------------------------------
/.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@v9
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local .terraform directories
2 | **/.terraform/*
3 |
4 | # .tfstate files
5 | *.tfstate
6 | *.tfstate.*
7 |
8 | # terraform lockfile
9 | .terraform.lock.hcl
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 | #
19 | *.tfvars
20 |
21 | # Ignore override files as they are usually used to override resources locally and so
22 | # are not checked in
23 | override.tf
24 | override.tf.json
25 | *_override.tf
26 | *_override.tf.json
27 |
28 | # Include override files you do wish to add to version control using negated pattern
29 | #
30 | # !example_override.tf
31 |
32 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
33 | # example: *tfplan*
34 |
35 | # Ignore CLI configuration files
36 | .terraformrc
37 | terraform.rc
38 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/antonbabenko/pre-commit-terraform
3 | rev: v1.96.1
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: v5.0.0
27 | hooks:
28 | - id: check-merge-conflict
29 | - id: end-of-file-fixer
30 | - id: trailing-whitespace
31 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | ## [1.2.1](https://github.com/terraform-aws-modules/terraform-aws-app-runner/compare/v1.2.0...v1.2.1) (2024-03-06)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * Update CI workflow versions to remove deprecated runtime warnings ([#12](https://github.com/terraform-aws-modules/terraform-aws-app-runner/issues/12)) ([1f4ac9c](https://github.com/terraform-aws-modules/terraform-aws-app-runner/commit/1f4ac9c46f2a1cda7845ed93e1bb4792e7d0e768))
11 |
12 | ## [1.2.0](https://github.com/terraform-aws-modules/terraform-aws-app-runner/compare/v1.1.1...v1.2.0) (2023-03-07)
13 |
14 |
15 | ### Features
16 |
17 | * Add support for runtime_environment_secrets ([#5](https://github.com/terraform-aws-modules/terraform-aws-app-runner/issues/5)) ([1a159d7](https://github.com/terraform-aws-modules/terraform-aws-app-runner/commit/1a159d73c657b864eaf20e158db3dfb1f23a33ec))
18 |
19 | ### [1.1.1](https://github.com/terraform-aws-modules/terraform-aws-app-runner/compare/v1.1.0...v1.1.1) (2023-02-01)
20 |
21 |
22 | ### Bug Fixes
23 |
24 | * Use a version for to avoid GitHub API rate limiting on CI workflows ([#3](https://github.com/terraform-aws-modules/terraform-aws-app-runner/issues/3)) ([ec37cc4](https://github.com/terraform-aws-modules/terraform-aws-app-runner/commit/ec37cc4868874c15f6f2f6ec1eaaacc8319bdc0a))
25 |
26 | ## [1.1.0](https://github.com/terraform-aws-modules/terraform-aws-app-runner/compare/v1.0.1...v1.1.0) (2022-11-04)
27 |
28 |
29 | ### Features
30 |
31 | * Add support for creating private services with VPC ingress connection ([#2](https://github.com/terraform-aws-modules/terraform-aws-app-runner/issues/2)) ([214af5c](https://github.com/terraform-aws-modules/terraform-aws-app-runner/commit/214af5ceafc2f9c2f7edd1c91ffa076edd3075e0))
32 |
33 | ### [1.0.1](https://github.com/terraform-aws-modules/terraform-aws-app-runner/compare/v1.0.0...v1.0.1) (2022-10-29)
34 |
35 |
36 | ### Bug Fixes
37 |
38 | * Update CI configuration files to use latest version ([#1](https://github.com/terraform-aws-modules/terraform-aws-app-runner/issues/1)) ([042ff02](https://github.com/terraform-aws-modules/terraform-aws-app-runner/commit/042ff024ea330a0af33807a9d2a24b3c9cf14eec))
39 |
40 | ## 1.0.0 (2022-10-01)
41 |
42 |
43 | ### Features
44 |
45 | * add cloudwatch logs and IAM roles, update example ([e58982d](https://github.com/clowdhaus/terraform-aws-app-runner/commit/e58982df317e67302dccb22a18bc027f47965208))
46 | * Add X-Ray policy, VPC connectory security group, and ability to toggle resources independently ([bb47aa9](https://github.com/clowdhaus/terraform-aws-app-runner/commit/bb47aa9289e1debfbd579fa366f2966c15521068))
47 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS App Runner Terraform module
2 |
3 | Terraform module which creates AWS App Runner resources.
4 |
5 | [](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
6 |
7 | ## Usage
8 |
9 | See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-app-runner/tree/master/examples) directory for working examples to reference:
10 |
11 | ### AppRunner Common/Shared Configurations
12 |
13 | ```hcl
14 | module "app_runner_shared_configs" {
15 | source = "terraform-aws-modules/app-runner/aws"
16 |
17 | # Disable service resources
18 | create_service = false
19 |
20 | connections = {
21 | # The AWS Connector for GitHub connects to your GitHub account is a one-time setup,
22 | # You can reuse the connection for creating multiple App Runner services based on repositories in this account.
23 | # After creation, you must complete the authentication handshake using the App Runner console.
24 | github = {
25 | provider_type = "GITHUB"
26 | }
27 | }
28 |
29 | auto_scaling_configurations = {
30 | mini = {
31 | name = "mini"
32 | max_concurrency = 20
33 | max_size = 5
34 | min_size = 1
35 |
36 | tags = {
37 | Type = "Mini"
38 | }
39 | }
40 |
41 | mega = {
42 | name = "mega"
43 | max_concurrency = 200
44 | max_size = 25
45 | min_size = 5
46 |
47 | tags = {
48 | Type = "MEGA"
49 | }
50 | }
51 | }
52 |
53 | tags = {
54 | Terraform = "true"
55 | Environment = "dev"
56 | }
57 | }
58 | ```
59 |
60 | ### Code Based AppRunner Service
61 |
62 | ```hcl
63 | module "app_runner_code_base" {
64 | source = "terraform-aws-modules/app-runner/aws"
65 |
66 | service_name = "example-code-base"
67 |
68 | # From shared configs created above
69 | auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mini"].arn
70 |
71 | source_configuration = {
72 | authentication_configuration = {
73 | # From shared configs created above
74 | connection_arn = module.app_runner_shared_configs.connections["github"].arn
75 | }
76 | auto_deployments_enabled = false
77 | code_repository = {
78 | code_configuration = {
79 | configuration_source = "REPOSITORY"
80 | }
81 | repository_url = "https://github.com/aws-containers/hello-app-runner"
82 | source_code_version = {
83 | type = "BRANCH"
84 | value = "main"
85 | }
86 | }
87 | }
88 |
89 | tags = {
90 | Terraform = "true"
91 | Environment = "dev"
92 | }
93 | }
94 | ```
95 |
96 | ### Image Based AppRunner Service
97 |
98 | ```hcl
99 | module "app_runner_image_base" {
100 | source = "terraform-aws-modules/app-runner/aws"
101 |
102 | service_name = "example-image-base"
103 |
104 | # From shared configs
105 | auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
106 |
107 | # IAM instance profile permissions to access secrets
108 | instance_policy_statements = {
109 | GetSecretValue = {
110 | actions = ["secretsmanager:GetSecretValue"]
111 | resources = [aws_secretsmanager_secret.this.arn]
112 | }
113 | }
114 |
115 | source_configuration = {
116 | auto_deployments_enabled = false
117 | image_repository = {
118 | image_configuration = {
119 | port = 8000
120 | runtime_environment_variables = {
121 | MY_VARIABLE = "hello!"
122 | }
123 | runtime_environment_secrets = {
124 | MY_SECRET = aws_secretsmanager_secret.this.arn
125 | }
126 | }
127 | image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
128 | image_repository_type = "ECR_PUBLIC"
129 | }
130 | }
131 |
132 | create_vpc_connector = true
133 | vpc_connector_subnets = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]
134 | vpc_connector_security_groups = ["sg-12345678"]
135 | network_configuration = {
136 | egress_configuration = {
137 | egress_type = "VPC"
138 | }
139 | }
140 |
141 | enable_observability_configuration = true
142 |
143 | tags = {
144 | Terraform = "true"
145 | Environment = "dev"
146 | }
147 | }
148 | ```
149 |
150 | ### Private AppRunner Service
151 |
152 | ```hcl
153 | module "app_runner_private" {
154 | source = "terraform-aws-modules/app-runner/aws"
155 |
156 | service_name = "example-private"
157 |
158 | ...
159 |
160 | # Ingress
161 | create_ingress_vpc_connection = true
162 | ingress_vpc_id = "vpc-12345678"
163 | ingress_vpc_endpoint_id = "vpce-01234567890123456 s"
164 |
165 | # Egress
166 | create_vpc_connector = true
167 | vpc_connector_subnets = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]
168 | vpc_connector_security_groups = ["sg-12345678"]
169 |
170 | network_configuration = {
171 | ingress_configuration = {
172 | is_publicly_accessible = false
173 | }
174 | egress_configuration = {
175 | egress_type = "VPC"
176 | }
177 | }
178 |
179 | tags = {
180 | Terraform = "true"
181 | Environment = "dev"
182 | }
183 | }
184 | ```
185 |
186 | ## Examples
187 |
188 | Examples codified under the [`examples`](https://github.com/terraform-aws-modules/terraform-aws-app-runner/tree/master/examples) are intended to give users references for how to use the module(s) as well as testing/validating changes to the source code of the module. If contributing to the project, please be sure to make any appropriate updates to the relevant examples to allow maintainers to test your changes and to keep the examples up to date for users. Thank you!
189 |
190 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-app-runner/tree/master/examples/complete)
191 |
192 |
193 | ## Requirements
194 |
195 | | Name | Version |
196 | |------|---------|
197 | | [terraform](#requirement\_terraform) | >= 1.0 |
198 | | [aws](#requirement\_aws) | >= 4.51 |
199 |
200 | ## Providers
201 |
202 | | Name | Version |
203 | |------|---------|
204 | | [aws](#provider\_aws) | >= 4.51 |
205 |
206 | ## Modules
207 |
208 | No modules.
209 |
210 | ## Resources
211 |
212 | | Name | Type |
213 | |------|------|
214 | | [aws_apprunner_auto_scaling_configuration_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_auto_scaling_configuration_version) | resource |
215 | | [aws_apprunner_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_connection) | resource |
216 | | [aws_apprunner_custom_domain_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_custom_domain_association) | resource |
217 | | [aws_apprunner_observability_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_observability_configuration) | resource |
218 | | [aws_apprunner_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_service) | resource |
219 | | [aws_apprunner_vpc_connector.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_vpc_connector) | resource |
220 | | [aws_apprunner_vpc_ingress_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_vpc_ingress_connection) | resource |
221 | | [aws_iam_policy.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
222 | | [aws_iam_policy.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
223 | | [aws_iam_role.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
224 | | [aws_iam_role.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
225 | | [aws_iam_role_policy_attachment.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
226 | | [aws_iam_role_policy_attachment.access_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
227 | | [aws_iam_role_policy_attachment.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
228 | | [aws_iam_role_policy_attachment.instance_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
229 | | [aws_iam_role_policy_attachment.instance_xray](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
230 | | [aws_iam_policy_document.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
231 | | [aws_iam_policy_document.access_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
232 | | [aws_iam_policy_document.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
233 | | [aws_iam_policy_document.instance_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
234 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
235 |
236 | ## Inputs
237 |
238 | | Name | Description | Type | Default | Required |
239 | |------|-------------|------|---------|:--------:|
240 | | [access\_iam\_role\_description](#input\_access\_iam\_role\_description) | Description of the role | `string` | `null` | no |
241 | | [access\_iam\_role\_name](#input\_access\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no |
242 | | [access\_iam\_role\_path](#input\_access\_iam\_role\_path) | IAM role path | `string` | `null` | no |
243 | | [access\_iam\_role\_permissions\_boundary](#input\_access\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no |
244 | | [access\_iam\_role\_policies](#input\_access\_iam\_role\_policies) | IAM policies to attach to the IAM role | `map(string)` | `{}` | no |
245 | | [access\_iam\_role\_use\_name\_prefix](#input\_access\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no |
246 | | [auto\_scaling\_configuration\_arn](#input\_auto\_scaling\_configuration\_arn) | ARN of an App Runner automatic scaling configuration resource that you want to associate with your service. If not provided, App Runner associates the latest revision of a default auto scaling configuration | `string` | `null` | no |
247 | | [auto\_scaling\_configurations](#input\_auto\_scaling\_configurations) | Map of auto-scaling configuration definitions to create | `any` | `{}` | no |
248 | | [connections](#input\_connections) | Map of connection definitions to create | `any` | `{}` | no |
249 | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no |
250 | | [create\_access\_iam\_role](#input\_create\_access\_iam\_role) | Determines whether an IAM role is created or to use an existing IAM role | `bool` | `false` | no |
251 | | [create\_custom\_domain\_association](#input\_create\_custom\_domain\_association) | Determines whether a Custom Domain Association will be created | `bool` | `false` | no |
252 | | [create\_ingress\_vpc\_connection](#input\_create\_ingress\_vpc\_connection) | Determines whether a VPC ingress configuration will be created | `bool` | `false` | no |
253 | | [create\_instance\_iam\_role](#input\_create\_instance\_iam\_role) | Determines whether an IAM role is created or to use an existing IAM role | `bool` | `true` | no |
254 | | [create\_service](#input\_create\_service) | Determines whether the service will be created | `bool` | `true` | no |
255 | | [create\_vpc\_connector](#input\_create\_vpc\_connector) | Determines whether a VPC Connector will be created | `bool` | `false` | no |
256 | | [domain\_name](#input\_domain\_name) | The custom domain endpoint to association. Specify a base domain e.g., `example.com` or a subdomain e.g., `subdomain.example.com` | `string` | `""` | no |
257 | | [enable\_observability\_configuration](#input\_enable\_observability\_configuration) | Determines whether an X-Ray Observability Configuration will be created and assigned to the service | `bool` | `true` | no |
258 | | [enable\_www\_subdomain](#input\_enable\_www\_subdomain) | Whether to associate the subdomain with the App Runner service in addition to the base domain. Defaults to `true` | `bool` | `null` | no |
259 | | [encryption\_configuration](#input\_encryption\_configuration) | The encryption configuration for the service | `any` | `{}` | no |
260 | | [health\_check\_configuration](#input\_health\_check\_configuration) | The health check configuration for the service | `any` | `{}` | no |
261 | | [ingress\_vpc\_endpoint\_id](#input\_ingress\_vpc\_endpoint\_id) | The ID of the VPC endpoint that is used for the VPC ingress configuration | `string` | `""` | no |
262 | | [ingress\_vpc\_id](#input\_ingress\_vpc\_id) | The ID of the VPC that is used for the VPC ingress configuration | `string` | `""` | no |
263 | | [instance\_configuration](#input\_instance\_configuration) | The instance configuration for the service | `any` | `{}` | no |
264 | | [instance\_iam\_role\_description](#input\_instance\_iam\_role\_description) | Description of the role | `string` | `null` | no |
265 | | [instance\_iam\_role\_name](#input\_instance\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no |
266 | | [instance\_iam\_role\_path](#input\_instance\_iam\_role\_path) | IAM role path | `string` | `null` | no |
267 | | [instance\_iam\_role\_permissions\_boundary](#input\_instance\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no |
268 | | [instance\_iam\_role\_policies](#input\_instance\_iam\_role\_policies) | IAM policies to attach to the IAM role | `map(string)` | `{}` | no |
269 | | [instance\_iam\_role\_use\_name\_prefix](#input\_instance\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no |
270 | | [instance\_policy\_statements](#input\_instance\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no |
271 | | [network\_configuration](#input\_network\_configuration) | The network configuration for the service | `any` | `{}` | no |
272 | | [observability\_configuration](#input\_observability\_configuration) | The observability configuration for the service | `any` | `{}` | no |
273 | | [private\_ecr\_arn](#input\_private\_ecr\_arn) | The ARN of the private ECR repository that contains the service image to launch | `string` | `null` | no |
274 | | [service\_name](#input\_service\_name) | The name of the service | `string` | `""` | no |
275 | | [source\_configuration](#input\_source\_configuration) | The source configuration for the service | `any` | `{}` | no |
276 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no |
277 | | [vpc\_connector\_name](#input\_vpc\_connector\_name) | The name of the VPC Connector | `string` | `""` | no |
278 | | [vpc\_connector\_security\_groups](#input\_vpc\_connector\_security\_groups) | The security groups to use for the VPC Connector | `list(string)` | `[]` | no |
279 | | [vpc\_connector\_subnets](#input\_vpc\_connector\_subnets) | The subnets to use for the VPC Connector | `list(string)` | `[]` | no |
280 |
281 | ## Outputs
282 |
283 | | Name | Description |
284 | |------|-------------|
285 | | [access\_iam\_role\_arn](#output\_access\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
286 | | [access\_iam\_role\_name](#output\_access\_iam\_role\_name) | The name of the IAM role |
287 | | [access\_iam\_role\_unique\_id](#output\_access\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
288 | | [auto\_scaling\_configurations](#output\_auto\_scaling\_configurations) | Map of attribute maps for all autoscaling configurations created |
289 | | [connections](#output\_connections) | Map of attribute maps for all connections created |
290 | | [custom\_domain\_association\_certificate\_validation\_records](#output\_custom\_domain\_association\_certificate\_validation\_records) | A set of certificate CNAME records used for this domain name |
291 | | [custom\_domain\_association\_dns\_target](#output\_custom\_domain\_association\_dns\_target) | The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform |
292 | | [custom\_domain\_association\_id](#output\_custom\_domain\_association\_id) | The `domain_name` and `service_arn` separated by a comma (`,`) |
293 | | [instance\_iam\_role\_arn](#output\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
294 | | [instance\_iam\_role\_name](#output\_instance\_iam\_role\_name) | The name of the IAM role |
295 | | [instance\_iam\_role\_unique\_id](#output\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
296 | | [observability\_configuration\_arn](#output\_observability\_configuration\_arn) | ARN of this observability configuration |
297 | | [observability\_configuration\_latest](#output\_observability\_configuration\_latest) | Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name` |
298 | | [observability\_configuration\_revision](#output\_observability\_configuration\_revision) | The revision of the observability configuration |
299 | | [observability\_configuration\_status](#output\_observability\_configuration\_status) | The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion |
300 | | [service\_arn](#output\_service\_arn) | The Amazon Resource Name (ARN) of the service |
301 | | [service\_id](#output\_service\_id) | An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region |
302 | | [service\_status](#output\_service\_status) | The current state of the App Runner service |
303 | | [service\_url](#output\_service\_url) | A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application |
304 | | [vpc\_connector\_arn](#output\_vpc\_connector\_arn) | The Amazon Resource Name (ARN) of VPC connector |
305 | | [vpc\_connector\_revision](#output\_vpc\_connector\_revision) | The revision of VPC connector. It's unique among all the active connectors ("Status": "ACTIVE") that share the same Name |
306 | | [vpc\_connector\_status](#output\_vpc\_connector\_status) | The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted |
307 | | [vpc\_ingress\_connection\_arn](#output\_vpc\_ingress\_connection\_arn) | The Amazon Resource Name (ARN) of the VPC Ingress Connection |
308 | | [vpc\_ingress\_connection\_domain\_name](#output\_vpc\_ingress\_connection\_domain\_name) | The domain name associated with the VPC Ingress Connection resource |
309 |
310 |
311 | ## License
312 |
313 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-app-runner/blob/master/LICENSE).
314 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/examples/complete/README.md:
--------------------------------------------------------------------------------
1 | # Complete AWS App Runner Example
2 |
3 | Configuration in this directory creates:
4 |
5 | - AppRunner shared configurations for:
6 | - GitHub connection
7 | - Autoscaling configuration for a "min" and "max" examples
8 | - A code based AppRunner service
9 | - Utilizes "min" autoscaling configuration created in shared configs
10 | - An image based AppRunner service
11 | - Utilizes "mega" autoscaling configuration created in shared configs
12 | - Creates a VPC connector to the associated VPC private subnets
13 | - Creates an example runtime environment variable and secret
14 |
15 | ## Usage
16 |
17 | To run this example you need to execute:
18 |
19 | 1. Fork [this repository](https://github.com/aws-containers/hello-app-runner) to the account/organization associated with the GitHub connection that will be created
20 |
21 | 2.
22 | ```bash
23 | $ terraform init
24 | $ terraform plan
25 | $ terraform apply -var="repository_url="
26 | ```
27 |
28 | 3. Once you have entered `yes` at the prompt, you will need to navigate to the AppRunner console -> GitHub connections -> Complete the handshake for the connection created by this example.
29 |
30 | Note that this example may create resources which will incur monetary charges on your AWS bill. Run `terraform destroy` when you no longer need these resources.
31 |
32 |
33 | ## Requirements
34 |
35 | | Name | Version |
36 | |------|---------|
37 | | [terraform](#requirement\_terraform) | >= 1.0 |
38 | | [aws](#requirement\_aws) | >= 4.51 |
39 |
40 | ## Providers
41 |
42 | | Name | Version |
43 | |------|---------|
44 | | [aws](#provider\_aws) | >= 4.51 |
45 |
46 | ## Modules
47 |
48 | | Name | Source | Version |
49 | |------|--------|---------|
50 | | [app\_runner\_code\_base](#module\_app\_runner\_code\_base) | ../.. | n/a |
51 | | [app\_runner\_disabled](#module\_app\_runner\_disabled) | ../.. | n/a |
52 | | [app\_runner\_image\_base](#module\_app\_runner\_image\_base) | ../.. | n/a |
53 | | [app\_runner\_private](#module\_app\_runner\_private) | ../.. | n/a |
54 | | [app\_runner\_shared\_configs](#module\_app\_runner\_shared\_configs) | ../.. | n/a |
55 | | [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 5.0 |
56 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
57 | | [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 |
58 | | [vpc\_endpoints\_security\_group](#module\_vpc\_endpoints\_security\_group) | terraform-aws-modules/security-group/aws | ~> 5.0 |
59 |
60 | ## Resources
61 |
62 | | Name | Type |
63 | |------|------|
64 | | [aws_secretsmanager_secret.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
65 | | [aws_secretsmanager_secret_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
66 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
67 |
68 | ## Inputs
69 |
70 | | Name | Description | Type | Default | Required |
71 | |------|-------------|------|---------|:--------:|
72 | | [repository\_url](#input\_repository\_url) | Location of the repository that contains the source code. Repository must be located in same scope as the GitHub connection (user's profile or organization) | `string` | `"https://github.com/aws-containers/hello-app-runner"` | no |
73 |
74 | ## Outputs
75 |
76 | | Name | Description |
77 | |------|-------------|
78 | | [auto\_scaling\_configurations](#output\_auto\_scaling\_configurations) | Map of attribute maps for all autosclaing configurations created |
79 | | [code\_base\_access\_iam\_role\_arn](#output\_code\_base\_access\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
80 | | [code\_base\_access\_iam\_role\_name](#output\_code\_base\_access\_iam\_role\_name) | The name of the IAM role |
81 | | [code\_base\_access\_iam\_role\_unique\_id](#output\_code\_base\_access\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
82 | | [code\_base\_custom\_domain\_association\_certificate\_validation\_records](#output\_code\_base\_custom\_domain\_association\_certificate\_validation\_records) | A set of certificate CNAME records used for this domain name |
83 | | [code\_base\_custom\_domain\_association\_dns\_target](#output\_code\_base\_custom\_domain\_association\_dns\_target) | The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform |
84 | | [code\_base\_custom\_domain\_association\_id](#output\_code\_base\_custom\_domain\_association\_id) | The `domain_name` and `service_arn` separated by a comma (`,`) |
85 | | [code\_base\_instance\_iam\_role\_arn](#output\_code\_base\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
86 | | [code\_base\_instance\_iam\_role\_name](#output\_code\_base\_instance\_iam\_role\_name) | The name of the IAM role |
87 | | [code\_base\_instance\_iam\_role\_unique\_id](#output\_code\_base\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
88 | | [code\_base\_observability\_configuration\_arn](#output\_code\_base\_observability\_configuration\_arn) | ARN of this observability configuration |
89 | | [code\_base\_observability\_configuration\_latest](#output\_code\_base\_observability\_configuration\_latest) | Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name` |
90 | | [code\_base\_observability\_configuration\_revision](#output\_code\_base\_observability\_configuration\_revision) | The revision of the observability configuration |
91 | | [code\_base\_observability\_configuration\_status](#output\_code\_base\_observability\_configuration\_status) | The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion |
92 | | [code\_base\_service\_arn](#output\_code\_base\_service\_arn) | The Amazon Resource Name (ARN) of the service |
93 | | [code\_base\_service\_id](#output\_code\_base\_service\_id) | An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region |
94 | | [code\_base\_service\_status](#output\_code\_base\_service\_status) | The current state of the App Runner service |
95 | | [code\_base\_service\_url](#output\_code\_base\_service\_url) | A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application |
96 | | [code\_base\_vpc\_connector\_arn](#output\_code\_base\_vpc\_connector\_arn) | The Amazon Resource Name (ARN) of VPC connector |
97 | | [code\_base\_vpc\_connector\_revision](#output\_code\_base\_vpc\_connector\_revision) | The revision of VPC connector. It's unique among all the active connectors ("Status": "ACTIVE") that share the same Name |
98 | | [code\_base\_vpc\_connector\_status](#output\_code\_base\_vpc\_connector\_status) | The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted |
99 | | [code\_base\_vpc\_ingress\_connection\_arn](#output\_code\_base\_vpc\_ingress\_connection\_arn) | The Amazon Resource Name (ARN) of the VPC Ingress Connection |
100 | | [code\_base\_vpc\_ingress\_connection\_domain\_name](#output\_code\_base\_vpc\_ingress\_connection\_domain\_name) | The domain name associated with the VPC Ingress Connection resource |
101 | | [connections](#output\_connections) | Map of attribute maps for all connections created |
102 | | [image\_base\_access\_iam\_role\_arn](#output\_image\_base\_access\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
103 | | [image\_base\_access\_iam\_role\_name](#output\_image\_base\_access\_iam\_role\_name) | The name of the IAM role |
104 | | [image\_base\_access\_iam\_role\_unique\_id](#output\_image\_base\_access\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
105 | | [image\_base\_custom\_domain\_association\_certificate\_validation\_records](#output\_image\_base\_custom\_domain\_association\_certificate\_validation\_records) | A set of certificate CNAME records used for this domain name |
106 | | [image\_base\_custom\_domain\_association\_dns\_target](#output\_image\_base\_custom\_domain\_association\_dns\_target) | The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform |
107 | | [image\_base\_custom\_domain\_association\_id](#output\_image\_base\_custom\_domain\_association\_id) | The `domain_name` and `service_arn` separated by a comma (`,`) |
108 | | [image\_base\_instance\_iam\_role\_arn](#output\_image\_base\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
109 | | [image\_base\_instance\_iam\_role\_name](#output\_image\_base\_instance\_iam\_role\_name) | The name of the IAM role |
110 | | [image\_base\_instance\_iam\_role\_unique\_id](#output\_image\_base\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
111 | | [image\_base\_observability\_configuration\_arn](#output\_image\_base\_observability\_configuration\_arn) | ARN of this observability configuration |
112 | | [image\_base\_observability\_configuration\_latest](#output\_image\_base\_observability\_configuration\_latest) | Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name` |
113 | | [image\_base\_observability\_configuration\_revision](#output\_image\_base\_observability\_configuration\_revision) | The revision of the observability configuration |
114 | | [image\_base\_observability\_configuration\_status](#output\_image\_base\_observability\_configuration\_status) | The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion |
115 | | [image\_base\_service\_arn](#output\_image\_base\_service\_arn) | The Amazon Resource Name (ARN) of the service |
116 | | [image\_base\_service\_id](#output\_image\_base\_service\_id) | An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region |
117 | | [image\_base\_service\_status](#output\_image\_base\_service\_status) | The current state of the App Runner service |
118 | | [image\_base\_service\_url](#output\_image\_base\_service\_url) | A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application |
119 | | [image\_base\_vpc\_connector\_arn](#output\_image\_base\_vpc\_connector\_arn) | The Amazon Resource Name (ARN) of VPC connector |
120 | | [image\_base\_vpc\_connector\_revision](#output\_image\_base\_vpc\_connector\_revision) | The revision of VPC connector. It's unique among all the active connectors ("Status": "ACTIVE") that share the same Name |
121 | | [image\_base\_vpc\_connector\_status](#output\_image\_base\_vpc\_connector\_status) | The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted |
122 | | [image\_base\_vpc\_ingress\_connection\_arn](#output\_image\_base\_vpc\_ingress\_connection\_arn) | The Amazon Resource Name (ARN) of the VPC Ingress Connection |
123 | | [image\_base\_vpc\_ingress\_connection\_domain\_name](#output\_image\_base\_vpc\_ingress\_connection\_domain\_name) | The domain name associated with the VPC Ingress Connection resource |
124 | | [private\_access\_iam\_role\_arn](#output\_private\_access\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
125 | | [private\_access\_iam\_role\_name](#output\_private\_access\_iam\_role\_name) | The name of the IAM role |
126 | | [private\_access\_iam\_role\_unique\_id](#output\_private\_access\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
127 | | [private\_custom\_domain\_association\_certificate\_validation\_records](#output\_private\_custom\_domain\_association\_certificate\_validation\_records) | A set of certificate CNAME records used for this domain name |
128 | | [private\_custom\_domain\_association\_dns\_target](#output\_private\_custom\_domain\_association\_dns\_target) | The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform |
129 | | [private\_custom\_domain\_association\_id](#output\_private\_custom\_domain\_association\_id) | The `domain_name` and `service_arn` separated by a comma (`,`) |
130 | | [private\_instance\_iam\_role\_arn](#output\_private\_instance\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
131 | | [private\_instance\_iam\_role\_name](#output\_private\_instance\_iam\_role\_name) | The name of the IAM role |
132 | | [private\_instance\_iam\_role\_unique\_id](#output\_private\_instance\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
133 | | [private\_observability\_configuration\_arn](#output\_private\_observability\_configuration\_arn) | ARN of this observability configuration |
134 | | [private\_observability\_configuration\_latest](#output\_private\_observability\_configuration\_latest) | Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name` |
135 | | [private\_observability\_configuration\_revision](#output\_private\_observability\_configuration\_revision) | The revision of the observability configuration |
136 | | [private\_observability\_configuration\_status](#output\_private\_observability\_configuration\_status) | The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion |
137 | | [private\_service\_arn](#output\_private\_service\_arn) | The Amazon Resource Name (ARN) of the service |
138 | | [private\_service\_id](#output\_private\_service\_id) | An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region |
139 | | [private\_service\_status](#output\_private\_service\_status) | The current state of the App Runner service |
140 | | [private\_service\_url](#output\_private\_service\_url) | A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application |
141 | | [private\_vpc\_connector\_arn](#output\_private\_vpc\_connector\_arn) | The Amazon Resource Name (ARN) of VPC connector |
142 | | [private\_vpc\_connector\_revision](#output\_private\_vpc\_connector\_revision) | The revision of VPC connector. It's unique among all the active connectors ("Status": "ACTIVE") that share the same Name |
143 | | [private\_vpc\_connector\_status](#output\_private\_vpc\_connector\_status) | The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted |
144 | | [private\_vpc\_ingress\_connection\_arn](#output\_private\_vpc\_ingress\_connection\_arn) | The Amazon Resource Name (ARN) of the VPC Ingress Connection |
145 | | [private\_vpc\_ingress\_connection\_domain\_name](#output\_private\_vpc\_ingress\_connection\_domain\_name) | The domain name associated with the VPC Ingress Connection resource |
146 |
147 |
148 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-app-runner/blob/master/LICENSE).
149 |
--------------------------------------------------------------------------------
/examples/complete/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = local.region
3 | }
4 |
5 | data "aws_availability_zones" "available" {}
6 |
7 | locals {
8 | region = "us-east-1"
9 | name = "ex-${basename(path.cwd)}"
10 |
11 | vpc_cidr = "10.0.0.0/16"
12 | azs = slice(data.aws_availability_zones.available.names, 0, 3)
13 |
14 | tags = {
15 | Example = local.name
16 | GithubRepo = "terraform-aws-app-runner"
17 | GithubOrg = "terraform-aws-modules"
18 | }
19 | }
20 |
21 | ################################################################################
22 | # App Runner Module
23 | ################################################################################
24 |
25 | module "app_runner_shared_configs" {
26 | source = "../.."
27 |
28 | # Disable service resources
29 | create_service = false
30 |
31 | connections = {
32 | # The AWS Connector for GitHub connects to your GitHub account is a one-time setup,
33 | # You can reuse the connection for creating multiple App Runner services based on repositories in this account.
34 | # After creation, you must complete the authentication handshake using the App Runner console.
35 | github = {
36 | provider_type = "GITHUB"
37 | }
38 | }
39 |
40 | auto_scaling_configurations = {
41 | mini = {
42 | name = "mini"
43 | max_concurrency = 20
44 | max_size = 5
45 | min_size = 1
46 |
47 | tags = {
48 | Type = "Mini"
49 | }
50 | }
51 |
52 | mega = {
53 | name = "mega"
54 | max_concurrency = 200
55 | max_size = 25
56 | min_size = 5
57 |
58 | tags = {
59 | Type = "MEGA"
60 | }
61 | }
62 | }
63 |
64 | tags = local.tags
65 | }
66 |
67 | module "app_runner_code_base" {
68 | source = "../.."
69 |
70 | service_name = "${local.name}-code-base"
71 |
72 | # Pulling from shared configs
73 | auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mini"].arn
74 |
75 | source_configuration = {
76 | authentication_configuration = {
77 | # Pulling from shared configs
78 | connection_arn = module.app_runner_shared_configs.connections["github"].arn
79 | }
80 | auto_deployments_enabled = false
81 | code_repository = {
82 | code_configuration = {
83 | configuration_source = "REPOSITORY"
84 | }
85 | repository_url = var.repository_url
86 | source_code_version = {
87 | type = "BRANCH"
88 | value = "main"
89 | }
90 | }
91 | }
92 |
93 | tags = local.tags
94 | }
95 |
96 | module "app_runner_image_base" {
97 | source = "../.."
98 |
99 | service_name = "${local.name}-image-base"
100 |
101 | # Pulling from shared configs
102 | auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
103 |
104 | # IAM instance profile permissions to access secrets
105 | instance_policy_statements = {
106 | GetSecretValue = {
107 | actions = ["secretsmanager:GetSecretValue"]
108 | resources = [aws_secretsmanager_secret.this.arn]
109 | }
110 | }
111 |
112 | source_configuration = {
113 | auto_deployments_enabled = false
114 | image_repository = {
115 | image_configuration = {
116 | port = 8000
117 | runtime_environment_variables = {
118 | MY_VARIABLE = "hello!"
119 | }
120 | runtime_environment_secrets = {
121 | MY_SECRET = aws_secretsmanager_secret.this.arn
122 | }
123 | }
124 | image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
125 | image_repository_type = "ECR_PUBLIC"
126 | }
127 | }
128 |
129 | # # Requires manual intervention to validate records
130 | # # https://github.com/hashicorp/terraform-provider-aws/issues/23460
131 | # create_custom_domain_association = true
132 | # hosted_zone_id = ""
133 | # domain_name = ""
134 | # enable_www_subdomain = true
135 |
136 | create_vpc_connector = true
137 | vpc_connector_subnets = module.vpc.private_subnets
138 | vpc_connector_security_groups = [module.security_group.security_group_id]
139 | network_configuration = {
140 | egress_configuration = {
141 | egress_type = "VPC"
142 | }
143 | }
144 |
145 | enable_observability_configuration = true
146 |
147 | tags = local.tags
148 | }
149 |
150 | module "app_runner_private" {
151 | source = "../.."
152 |
153 | service_name = "${local.name}-private"
154 |
155 | # Pulling from shared configs
156 | auto_scaling_configuration_arn = module.app_runner_shared_configs.auto_scaling_configurations["mega"].arn
157 |
158 | # IAM instance profile permissions to access secrets
159 | instance_policy_statements = {
160 | GetSecretValue = {
161 | actions = ["secretsmanager:GetSecretValue"]
162 | resources = [aws_secretsmanager_secret.this.arn]
163 | }
164 | }
165 |
166 | source_configuration = {
167 | auto_deployments_enabled = false
168 | image_repository = {
169 | image_configuration = {
170 | port = 8000
171 | runtime_environment_variables = {
172 | MY_VARIABLE = "hello!"
173 | }
174 | runtime_environment_secrets = {
175 | MY_SECRET = aws_secretsmanager_secret.this.arn
176 | }
177 | }
178 | image_identifier = "public.ecr.aws/aws-containers/hello-app-runner:latest"
179 | image_repository_type = "ECR_PUBLIC"
180 | }
181 | }
182 |
183 | create_ingress_vpc_connection = true
184 | ingress_vpc_id = module.vpc.vpc_id
185 | ingress_vpc_endpoint_id = module.vpc_endpoints.endpoints["apprunner"].id
186 |
187 | create_vpc_connector = true
188 | vpc_connector_subnets = module.vpc.private_subnets
189 | vpc_connector_security_groups = [module.security_group.security_group_id]
190 |
191 | network_configuration = {
192 | ingress_configuration = {
193 | is_publicly_accessible = false
194 | }
195 | egress_configuration = {
196 | egress_type = "VPC"
197 | }
198 | }
199 |
200 | enable_observability_configuration = true
201 |
202 | tags = local.tags
203 | }
204 |
205 | module "app_runner_disabled" {
206 | source = "../.."
207 |
208 | create = false
209 | }
210 |
211 | ################################################################################
212 | # Supporting Resources
213 | ################################################################################
214 |
215 | module "vpc" {
216 | source = "terraform-aws-modules/vpc/aws"
217 | version = "~> 5.0"
218 |
219 | name = local.name
220 | cidr = local.vpc_cidr
221 |
222 | azs = local.azs
223 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
224 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
225 |
226 | enable_nat_gateway = false
227 |
228 | tags = local.tags
229 | }
230 |
231 | module "vpc_endpoints" {
232 | source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
233 | version = "~> 5.0"
234 |
235 | vpc_id = module.vpc.vpc_id
236 | security_group_ids = [module.vpc_endpoints_security_group.security_group_id]
237 |
238 | endpoints = {
239 | apprunner = {
240 | service = "apprunner.requests"
241 | # private_dns_enabled = true
242 | subnet_ids = module.vpc.private_subnets
243 | tags = { Name = "${local.name}-apprunner" }
244 | },
245 | }
246 |
247 | tags = local.tags
248 | }
249 |
250 | module "security_group" {
251 | source = "terraform-aws-modules/security-group/aws"
252 | version = "~> 5.0"
253 |
254 | name = local.name
255 | description = "Security group for AppRunner connector"
256 | vpc_id = module.vpc.vpc_id
257 |
258 | egress_rules = ["http-80-tcp"]
259 | egress_cidr_blocks = module.vpc.private_subnets_cidr_blocks
260 |
261 | tags = local.tags
262 | }
263 |
264 | module "vpc_endpoints_security_group" {
265 | source = "terraform-aws-modules/security-group/aws"
266 | version = "~> 5.0"
267 |
268 | name = "${local.name}-vpc-endpoints"
269 | description = "Security group for VPC Endpoints"
270 | vpc_id = module.vpc.vpc_id
271 |
272 | egress_rules = ["https-443-tcp"]
273 | egress_cidr_blocks = [module.vpc.vpc_cidr_block]
274 |
275 | tags = local.tags
276 | }
277 |
278 | resource "aws_secretsmanager_secret" "this" {
279 | name_prefix = local.name
280 | recovery_window_in_days = 0
281 | }
282 |
283 | resource "aws_secretsmanager_secret_version" "this" {
284 | secret_id = aws_secretsmanager_secret.this.id
285 | secret_string = "example"
286 | }
287 |
--------------------------------------------------------------------------------
/examples/complete/outputs.tf:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Shared Configurations
3 | ################################################################################
4 |
5 | output "connections" {
6 | description = "Map of attribute maps for all connections created"
7 | value = module.app_runner_shared_configs.connections
8 | }
9 |
10 | output "auto_scaling_configurations" {
11 | description = "Map of attribute maps for all autosclaing configurations created"
12 | value = module.app_runner_shared_configs.auto_scaling_configurations
13 | }
14 |
15 | ################################################################################
16 | # Code Base
17 | ################################################################################
18 |
19 | output "code_base_service_arn" {
20 | description = "The Amazon Resource Name (ARN) of the service"
21 | value = module.app_runner_code_base.service_arn
22 | }
23 |
24 | output "code_base_service_id" {
25 | description = "An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region"
26 | value = module.app_runner_code_base.service_id
27 | }
28 |
29 | output "code_base_service_url" {
30 | description = "A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application"
31 | value = module.app_runner_code_base.service_url
32 | }
33 |
34 | output "code_base_service_status" {
35 | description = "The current state of the App Runner service"
36 | value = module.app_runner_code_base.service_status
37 | }
38 |
39 | output "code_base_access_iam_role_name" {
40 | description = "The name of the IAM role"
41 | value = module.app_runner_code_base.access_iam_role_name
42 | }
43 |
44 | output "code_base_access_iam_role_arn" {
45 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
46 | value = module.app_runner_code_base.access_iam_role_arn
47 | }
48 |
49 | output "code_base_access_iam_role_unique_id" {
50 | description = "Stable and unique string identifying the IAM role"
51 | value = module.app_runner_code_base.access_iam_role_unique_id
52 | }
53 |
54 | output "code_base_instance_iam_role_name" {
55 | description = "The name of the IAM role"
56 | value = module.app_runner_code_base.instance_iam_role_name
57 | }
58 |
59 | output "code_base_instance_iam_role_arn" {
60 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
61 | value = module.app_runner_code_base.instance_iam_role_arn
62 | }
63 |
64 | output "code_base_instance_iam_role_unique_id" {
65 | description = "Stable and unique string identifying the IAM role"
66 | value = module.app_runner_code_base.instance_iam_role_unique_id
67 | }
68 |
69 | output "code_base_vpc_ingress_connection_arn" {
70 | description = "The Amazon Resource Name (ARN) of the VPC Ingress Connection"
71 | value = module.app_runner_code_base.vpc_ingress_connection_arn
72 | }
73 |
74 | output "code_base_vpc_ingress_connection_domain_name" {
75 | description = "The domain name associated with the VPC Ingress Connection resource"
76 | value = module.app_runner_code_base.vpc_ingress_connection_domain_name
77 | }
78 |
79 | output "code_base_custom_domain_association_id" {
80 | description = "The `domain_name` and `service_arn` separated by a comma (`,`)"
81 | value = module.app_runner_code_base.custom_domain_association_id
82 | }
83 |
84 | output "code_base_custom_domain_association_certificate_validation_records" {
85 | description = "A set of certificate CNAME records used for this domain name"
86 | value = module.app_runner_code_base.custom_domain_association_certificate_validation_records
87 | }
88 |
89 | output "code_base_custom_domain_association_dns_target" {
90 | description = "The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform"
91 | value = module.app_runner_code_base.custom_domain_association_dns_target
92 | }
93 |
94 | output "code_base_vpc_connector_arn" {
95 | description = "The Amazon Resource Name (ARN) of VPC connector"
96 | value = module.app_runner_code_base.vpc_connector_arn
97 | }
98 |
99 | output "code_base_vpc_connector_status" {
100 | description = "The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted"
101 | value = module.app_runner_code_base.vpc_connector_status
102 | }
103 |
104 | output "code_base_vpc_connector_revision" {
105 | description = "The revision of VPC connector. It's unique among all the active connectors (\"Status\": \"ACTIVE\") that share the same Name"
106 | value = module.app_runner_code_base.vpc_connector_revision
107 | }
108 |
109 | output "code_base_observability_configuration_arn" {
110 | description = "ARN of this observability configuration"
111 | value = module.app_runner_code_base.observability_configuration_arn
112 | }
113 |
114 | output "code_base_observability_configuration_revision" {
115 | description = "The revision of the observability configuration"
116 | value = module.app_runner_code_base.observability_configuration_revision
117 | }
118 |
119 | output "code_base_observability_configuration_latest" {
120 | description = "Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name`"
121 | value = module.app_runner_code_base.observability_configuration_latest
122 | }
123 |
124 | output "code_base_observability_configuration_status" {
125 | description = "The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion"
126 | value = module.app_runner_code_base.observability_configuration_status
127 | }
128 |
129 | ################################################################################
130 | # Image Base
131 | ################################################################################
132 |
133 | output "image_base_service_arn" {
134 | description = "The Amazon Resource Name (ARN) of the service"
135 | value = module.app_runner_image_base.service_arn
136 | }
137 |
138 | output "image_base_service_id" {
139 | description = "An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region"
140 | value = module.app_runner_image_base.service_id
141 | }
142 |
143 | output "image_base_service_url" {
144 | description = "A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application"
145 | value = module.app_runner_image_base.service_url
146 | }
147 |
148 | output "image_base_service_status" {
149 | description = "The current state of the App Runner service"
150 | value = module.app_runner_image_base.service_status
151 | }
152 |
153 | output "image_base_access_iam_role_name" {
154 | description = "The name of the IAM role"
155 | value = module.app_runner_image_base.access_iam_role_name
156 | }
157 |
158 | output "image_base_access_iam_role_arn" {
159 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
160 | value = module.app_runner_image_base.access_iam_role_arn
161 | }
162 |
163 | output "image_base_access_iam_role_unique_id" {
164 | description = "Stable and unique string identifying the IAM role"
165 | value = module.app_runner_image_base.access_iam_role_unique_id
166 | }
167 |
168 | output "image_base_instance_iam_role_name" {
169 | description = "The name of the IAM role"
170 | value = module.app_runner_image_base.instance_iam_role_name
171 | }
172 |
173 | output "image_base_instance_iam_role_arn" {
174 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
175 | value = module.app_runner_image_base.instance_iam_role_arn
176 | }
177 |
178 | output "image_base_instance_iam_role_unique_id" {
179 | description = "Stable and unique string identifying the IAM role"
180 | value = module.app_runner_image_base.instance_iam_role_unique_id
181 | }
182 |
183 | output "image_base_vpc_ingress_connection_arn" {
184 | description = "The Amazon Resource Name (ARN) of the VPC Ingress Connection"
185 | value = module.app_runner_image_base.vpc_ingress_connection_arn
186 | }
187 |
188 | output "image_base_vpc_ingress_connection_domain_name" {
189 | description = "The domain name associated with the VPC Ingress Connection resource"
190 | value = module.app_runner_image_base.vpc_ingress_connection_domain_name
191 | }
192 |
193 | output "image_base_custom_domain_association_id" {
194 | description = "The `domain_name` and `service_arn` separated by a comma (`,`)"
195 | value = module.app_runner_image_base.custom_domain_association_id
196 | }
197 |
198 | output "image_base_custom_domain_association_certificate_validation_records" {
199 | description = "A set of certificate CNAME records used for this domain name"
200 | value = module.app_runner_image_base.custom_domain_association_certificate_validation_records
201 | }
202 |
203 | output "image_base_custom_domain_association_dns_target" {
204 | description = "The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform"
205 | value = module.app_runner_image_base.custom_domain_association_dns_target
206 | }
207 |
208 | output "image_base_vpc_connector_arn" {
209 | description = "The Amazon Resource Name (ARN) of VPC connector"
210 | value = module.app_runner_image_base.vpc_connector_arn
211 | }
212 |
213 | output "image_base_vpc_connector_status" {
214 | description = "The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted"
215 | value = module.app_runner_image_base.vpc_connector_status
216 | }
217 |
218 | output "image_base_vpc_connector_revision" {
219 | description = "The revision of VPC connector. It's unique among all the active connectors (\"Status\": \"ACTIVE\") that share the same Name"
220 | value = module.app_runner_image_base.vpc_connector_revision
221 | }
222 |
223 | output "image_base_observability_configuration_arn" {
224 | description = "ARN of this observability configuration"
225 | value = module.app_runner_image_base.observability_configuration_arn
226 | }
227 |
228 | output "image_base_observability_configuration_revision" {
229 | description = "The revision of the observability configuration"
230 | value = module.app_runner_image_base.observability_configuration_revision
231 | }
232 |
233 | output "image_base_observability_configuration_latest" {
234 | description = "Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name`"
235 | value = module.app_runner_image_base.observability_configuration_latest
236 | }
237 |
238 | output "image_base_observability_configuration_status" {
239 | description = "The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion"
240 | value = module.app_runner_image_base.observability_configuration_status
241 | }
242 |
243 | ################################################################################
244 | # Private
245 | ################################################################################
246 |
247 | output "private_service_arn" {
248 | description = "The Amazon Resource Name (ARN) of the service"
249 | value = module.app_runner_private.service_arn
250 | }
251 |
252 | output "private_service_id" {
253 | description = "An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region"
254 | value = module.app_runner_private.service_id
255 | }
256 |
257 | output "private_service_url" {
258 | description = "A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application"
259 | value = module.app_runner_private.service_url
260 | }
261 |
262 | output "private_service_status" {
263 | description = "The current state of the App Runner service"
264 | value = module.app_runner_private.service_status
265 | }
266 |
267 | output "private_access_iam_role_name" {
268 | description = "The name of the IAM role"
269 | value = module.app_runner_private.access_iam_role_name
270 | }
271 |
272 | output "private_access_iam_role_arn" {
273 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
274 | value = module.app_runner_private.access_iam_role_arn
275 | }
276 |
277 | output "private_access_iam_role_unique_id" {
278 | description = "Stable and unique string identifying the IAM role"
279 | value = module.app_runner_private.access_iam_role_unique_id
280 | }
281 |
282 | output "private_instance_iam_role_name" {
283 | description = "The name of the IAM role"
284 | value = module.app_runner_private.instance_iam_role_name
285 | }
286 |
287 | output "private_instance_iam_role_arn" {
288 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
289 | value = module.app_runner_private.instance_iam_role_arn
290 | }
291 |
292 | output "private_instance_iam_role_unique_id" {
293 | description = "Stable and unique string identifying the IAM role"
294 | value = module.app_runner_private.instance_iam_role_unique_id
295 | }
296 |
297 | output "private_vpc_ingress_connection_arn" {
298 | description = "The Amazon Resource Name (ARN) of the VPC Ingress Connection"
299 | value = module.app_runner_private.vpc_ingress_connection_arn
300 | }
301 |
302 | output "private_vpc_ingress_connection_domain_name" {
303 | description = "The domain name associated with the VPC Ingress Connection resource"
304 | value = module.app_runner_private.vpc_ingress_connection_domain_name
305 | }
306 |
307 | output "private_custom_domain_association_id" {
308 | description = "The `domain_name` and `service_arn` separated by a comma (`,`)"
309 | value = module.app_runner_private.custom_domain_association_id
310 | }
311 |
312 | output "private_custom_domain_association_certificate_validation_records" {
313 | description = "A set of certificate CNAME records used for this domain name"
314 | value = module.app_runner_private.custom_domain_association_certificate_validation_records
315 | }
316 |
317 | output "private_custom_domain_association_dns_target" {
318 | description = "The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform"
319 | value = module.app_runner_private.custom_domain_association_dns_target
320 | }
321 |
322 | output "private_vpc_connector_arn" {
323 | description = "The Amazon Resource Name (ARN) of VPC connector"
324 | value = module.app_runner_private.vpc_connector_arn
325 | }
326 |
327 | output "private_vpc_connector_status" {
328 | description = "The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted"
329 | value = module.app_runner_private.vpc_connector_status
330 | }
331 |
332 | output "private_vpc_connector_revision" {
333 | description = "The revision of VPC connector. It's unique among all the active connectors (\"Status\": \"ACTIVE\") that share the same Name"
334 | value = module.app_runner_private.vpc_connector_revision
335 | }
336 |
337 | output "private_observability_configuration_arn" {
338 | description = "ARN of this observability configuration"
339 | value = module.app_runner_private.observability_configuration_arn
340 | }
341 |
342 | output "private_observability_configuration_revision" {
343 | description = "The revision of the observability configuration"
344 | value = module.app_runner_private.observability_configuration_revision
345 | }
346 |
347 | output "private_observability_configuration_latest" {
348 | description = "Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name`"
349 | value = module.app_runner_private.observability_configuration_latest
350 | }
351 |
352 | output "private_observability_configuration_status" {
353 | description = "The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion"
354 | value = module.app_runner_private.observability_configuration_status
355 | }
356 |
--------------------------------------------------------------------------------
/examples/complete/variables.tf:
--------------------------------------------------------------------------------
1 | variable "repository_url" {
2 | description = "Location of the repository that contains the source code. Repository must be located in same scope as the GitHub connection (user's profile or organization)"
3 | type = string
4 | default = "https://github.com/aws-containers/hello-app-runner" # clone to your account associated with the GitHub connection
5 | }
6 |
--------------------------------------------------------------------------------
/examples/complete/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0"
3 |
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = ">= 4.51"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | data "aws_partition" "current" {}
2 |
3 | ################################################################################
4 | # Service
5 | ################################################################################
6 |
7 | locals {
8 | create_service = var.create && var.create_service
9 |
10 | # Ensure instance role created is attached even if no values are provided via `var.instance_configuration`
11 | instance_configuration = local.create_instance_iam_role ? merge(
12 | var.instance_configuration,
13 | { instance_role_arn = aws_iam_role.instance[0].arn }
14 | ) : var.instance_configuration
15 |
16 | # Ensure access role created is attached even if no values are provided via `var.source_configuration`
17 | source_configuration = local.create_access_iam_role ? merge(
18 | var.source_configuration,
19 | { authentication_configuration = { access_role_arn = aws_iam_role.access[0].arn } }
20 | ) : var.source_configuration
21 |
22 | # Ensure VPC connector created is attached even if no values are provided via `var.network_configuration`
23 | network_configuration = local.create_vpc_connector ? merge(
24 | var.network_configuration,
25 | {
26 | egress_configuration = {
27 | egress_type = "VPC"
28 | vpc_connector_arn = aws_apprunner_vpc_connector.this[0].arn
29 | }
30 | }
31 | ) : var.network_configuration
32 | }
33 |
34 | resource "aws_apprunner_service" "this" {
35 | count = local.create_service ? 1 : 0
36 |
37 | auto_scaling_configuration_arn = var.auto_scaling_configuration_arn
38 |
39 | dynamic "encryption_configuration" {
40 | for_each = length(var.encryption_configuration) > 0 ? [var.encryption_configuration] : []
41 |
42 | content {
43 | kms_key = encryption_configuration.value.kms_key
44 | }
45 | }
46 |
47 | dynamic "health_check_configuration" {
48 | for_each = length(var.health_check_configuration) > 0 ? [var.health_check_configuration] : []
49 |
50 | content {
51 | healthy_threshold = try(health_check_configuration.value.healthy_threshold, null)
52 | interval = try(health_check_configuration.value.interval, null)
53 | path = try(health_check_configuration.value.path, null)
54 | protocol = try(health_check_configuration.value.protocol, null)
55 | timeout = try(health_check_configuration.value.timeout, null)
56 | unhealthy_threshold = try(health_check_configuration.value.unhealthy_threshold, null)
57 | }
58 | }
59 |
60 | dynamic "instance_configuration" {
61 | for_each = length(local.instance_configuration) > 0 ? [local.instance_configuration] : []
62 |
63 | content {
64 | cpu = try(instance_configuration.value.cpu, null)
65 | instance_role_arn = lookup(instance_configuration.value, "instance_role_arn", null)
66 | memory = try(instance_configuration.value.memory, null)
67 | }
68 | }
69 |
70 | dynamic "network_configuration" {
71 | for_each = length(local.network_configuration) > 0 ? [local.network_configuration] : []
72 |
73 | content {
74 | dynamic "ingress_configuration" {
75 | for_each = try([network_configuration.value.ingress_configuration], [])
76 |
77 | content {
78 | is_publicly_accessible = try(ingress_configuration.value.is_publicly_accessible, null)
79 | }
80 | }
81 |
82 | dynamic "egress_configuration" {
83 | for_each = try([network_configuration.value.egress_configuration], [])
84 |
85 | content {
86 | egress_type = try(egress_configuration.value.egress_type, "VPC")
87 | vpc_connector_arn = try(egress_configuration.value.vpc_connector_arn, null)
88 | }
89 | }
90 | }
91 | }
92 |
93 | dynamic "observability_configuration" {
94 | for_each = local.enable_observability_configuration ? [1] : []
95 |
96 | content {
97 | observability_configuration_arn = aws_apprunner_observability_configuration.this[0].arn
98 | observability_enabled = true
99 | }
100 | }
101 |
102 | service_name = var.service_name
103 |
104 | dynamic "source_configuration" {
105 | for_each = [local.source_configuration]
106 |
107 | content {
108 | dynamic "authentication_configuration" {
109 | for_each = try([source_configuration.value.authentication_configuration], [])
110 |
111 | content {
112 | access_role_arn = lookup(authentication_configuration.value, "access_role_arn", null)
113 | connection_arn = try(authentication_configuration.value.connection_arn, null)
114 | }
115 | }
116 |
117 | # Must be false when using public images or cross account images
118 | auto_deployments_enabled = try(source_configuration.value.auto_deployments_enabled, false)
119 |
120 | dynamic "code_repository" {
121 | for_each = try([source_configuration.value.code_repository], [])
122 |
123 | content {
124 | dynamic "code_configuration" {
125 | for_each = try([code_repository.value.code_configuration], [])
126 |
127 | content {
128 | dynamic "code_configuration_values" {
129 | for_each = try([code_configuration.value.code_configuration_values], [])
130 |
131 | content {
132 | build_command = try(code_configuration_values.value.build_command, null)
133 | port = try(code_configuration_values.value.port, null)
134 | runtime = code_configuration_values.value.runtime
135 | runtime_environment_variables = try(code_configuration_values.value.runtime_environment_variables, {})
136 | runtime_environment_secrets = try(code_configuration_values.value.runtime_environment_secrets, {})
137 | start_command = try(code_configuration_values.value.start_command, null)
138 | }
139 | }
140 |
141 | configuration_source = code_configuration.value.configuration_source
142 | }
143 | }
144 |
145 | repository_url = code_repository.value.repository_url
146 |
147 | dynamic "source_code_version" {
148 | for_each = [code_repository.value.source_code_version]
149 |
150 | content {
151 | type = try(source_code_version.value.type, "BRANCH")
152 | value = source_code_version.value.value
153 | }
154 | }
155 | }
156 | }
157 |
158 | dynamic "image_repository" {
159 | for_each = try([source_configuration.value.image_repository], [])
160 |
161 | content {
162 | dynamic "image_configuration" {
163 | for_each = try([image_repository.value.image_configuration], [])
164 |
165 | content {
166 | port = try(image_configuration.value.port, null)
167 | runtime_environment_variables = try(image_configuration.value.runtime_environment_variables, {})
168 | runtime_environment_secrets = try(image_configuration.value.runtime_environment_secrets, {})
169 | start_command = try(image_configuration.value.start_command, null)
170 | }
171 | }
172 |
173 | image_identifier = image_repository.value.image_identifier
174 | image_repository_type = image_repository.value.image_repository_type
175 | }
176 | }
177 | }
178 | }
179 |
180 | tags = var.tags
181 | }
182 |
183 | ################################################################################
184 | # IAM Role - Access
185 | ################################################################################
186 |
187 | locals {
188 | create_access_iam_role = local.create_service && var.create_access_iam_role
189 | access_iam_role_name = try(coalesce(var.access_iam_role_name, "${var.service_name}-access"), "")
190 | }
191 |
192 | data "aws_iam_policy_document" "access_assume_role" {
193 | count = local.create_access_iam_role ? 1 : 0
194 |
195 | statement {
196 | sid = "AccessAssumeRole"
197 | actions = ["sts:AssumeRole"]
198 |
199 | principals {
200 | type = "Service"
201 | identifiers = ["build.apprunner.${data.aws_partition.current.dns_suffix}"]
202 | }
203 | }
204 | }
205 |
206 | resource "aws_iam_role" "access" {
207 | count = local.create_access_iam_role ? 1 : 0
208 |
209 | name = var.access_iam_role_use_name_prefix ? null : local.access_iam_role_name
210 | name_prefix = var.access_iam_role_use_name_prefix ? "${local.access_iam_role_name}-" : null
211 | path = var.access_iam_role_path
212 | description = var.access_iam_role_description
213 |
214 | assume_role_policy = data.aws_iam_policy_document.access_assume_role[0].json
215 | permissions_boundary = var.access_iam_role_permissions_boundary
216 | force_detach_policies = true
217 |
218 | tags = var.tags
219 | }
220 |
221 | data "aws_iam_policy_document" "access" {
222 | count = local.create_access_iam_role && var.private_ecr_arn != null ? 1 : 0
223 |
224 | dynamic "statement" {
225 | for_each = var.private_ecr_arn != null ? [1] : []
226 |
227 | content {
228 | sid = "ReadPrivateEcr"
229 | actions = [
230 | "ecr:BatchGetImage",
231 | "ecr:DescribeImages",
232 | "ecr:GetDownloadUrlForLayer",
233 | ]
234 | resources = [var.private_ecr_arn]
235 | }
236 | }
237 |
238 | dynamic "statement" {
239 | for_each = var.private_ecr_arn != null ? [1] : []
240 |
241 | content {
242 | sid = "AuthPrivateEcr"
243 | actions = [
244 | "ecr:DescribeImages",
245 | "ecr:GetAuthorizationToken",
246 | ]
247 | resources = ["*"]
248 | }
249 | }
250 | }
251 |
252 | resource "aws_iam_policy" "access" {
253 | count = local.create_access_iam_role && var.private_ecr_arn != null ? 1 : 0
254 |
255 | name = var.access_iam_role_use_name_prefix ? null : local.access_iam_role_name
256 | name_prefix = var.access_iam_role_use_name_prefix ? "${local.access_iam_role_name}-" : null
257 | path = var.access_iam_role_path
258 | description = var.access_iam_role_description
259 |
260 | policy = data.aws_iam_policy_document.access[0].json
261 | }
262 |
263 | resource "aws_iam_role_policy_attachment" "access" {
264 | count = local.create_access_iam_role && var.private_ecr_arn != null ? 1 : 0
265 |
266 | policy_arn = aws_iam_policy.access[0].arn
267 | role = aws_iam_role.access[0].name
268 | }
269 |
270 | resource "aws_iam_role_policy_attachment" "access_additional" {
271 | for_each = { for k, v in var.access_iam_role_policies : k => v if local.create_access_iam_role }
272 |
273 | policy_arn = each.value
274 | role = aws_iam_role.access[0].name
275 | }
276 |
277 | ################################################################################
278 | # IAM Role - Instance
279 | ################################################################################
280 |
281 | locals {
282 | create_instance_iam_role = local.create_service && var.create_instance_iam_role
283 | instance_iam_role_name = try(coalesce(var.instance_iam_role_name, "${var.service_name}-instance"), "")
284 | }
285 |
286 | data "aws_iam_policy_document" "instance_assume_role" {
287 | count = var.create && var.create_instance_iam_role ? 1 : 0
288 |
289 | statement {
290 | sid = "InstanceAssumeRole"
291 | actions = ["sts:AssumeRole"]
292 |
293 | principals {
294 | type = "Service"
295 | identifiers = ["tasks.apprunner.${data.aws_partition.current.dns_suffix}"]
296 | }
297 | }
298 | }
299 |
300 | resource "aws_iam_role" "instance" {
301 | count = local.create_instance_iam_role ? 1 : 0
302 |
303 | name = var.instance_iam_role_use_name_prefix ? null : local.instance_iam_role_name
304 | name_prefix = var.instance_iam_role_use_name_prefix ? "${local.instance_iam_role_name}-" : null
305 | path = var.instance_iam_role_path
306 | description = var.instance_iam_role_description
307 |
308 | assume_role_policy = data.aws_iam_policy_document.instance_assume_role[0].json
309 | permissions_boundary = var.instance_iam_role_permissions_boundary
310 | force_detach_policies = true
311 |
312 | tags = var.tags
313 | }
314 |
315 | resource "aws_iam_role_policy_attachment" "instance_xray" {
316 | count = local.create_instance_iam_role && try(var.observability_configuration.value.observability_enabled, false) ? 1 : 0
317 |
318 | policy_arn = "arn:${data.aws_partition.current.id}:iam::aws:policy/AWSXRayDaemonWriteAccess"
319 | role = aws_iam_role.instance[0].name
320 | }
321 |
322 | resource "aws_iam_role_policy_attachment" "instance_additional" {
323 | for_each = { for k, v in var.instance_iam_role_policies : k => v if local.create_instance_iam_role }
324 |
325 | policy_arn = each.value
326 | role = aws_iam_role.instance[0].name
327 | }
328 |
329 | ################################################################################
330 | # IAM Role Policy - Instance
331 | ################################################################################
332 |
333 | locals {
334 | create_instance_role_policy = local.create_instance_iam_role && length(var.instance_policy_statements) > 0
335 | }
336 |
337 | data "aws_iam_policy_document" "instance" {
338 | count = local.create_instance_role_policy ? 1 : 0
339 |
340 | dynamic "statement" {
341 | for_each = var.instance_policy_statements
342 |
343 | content {
344 | sid = try(statement.value.sid, statement.key)
345 | actions = try(statement.value.actions, null)
346 | not_actions = try(statement.value.not_actions, null)
347 | effect = try(statement.value.effect, null)
348 | resources = try(statement.value.resources, null)
349 | not_resources = try(statement.value.not_resources, null)
350 |
351 | dynamic "principals" {
352 | for_each = try(statement.value.principals, [])
353 |
354 | content {
355 | type = principals.value.type
356 | identifiers = principals.value.identifiers
357 | }
358 | }
359 |
360 | dynamic "not_principals" {
361 | for_each = try(statement.value.not_principals, [])
362 |
363 | content {
364 | type = not_principals.value.type
365 | identifiers = not_principals.value.identifiers
366 | }
367 | }
368 |
369 | dynamic "condition" {
370 | for_each = try(statement.value.conditions, [])
371 |
372 | content {
373 | test = condition.value.test
374 | values = condition.value.values
375 | variable = condition.value.variable
376 | }
377 | }
378 | }
379 | }
380 | }
381 |
382 | resource "aws_iam_policy" "instance" {
383 | count = local.create_instance_role_policy ? 1 : 0
384 |
385 | name = var.instance_iam_role_use_name_prefix ? null : local.instance_iam_role_name
386 | name_prefix = var.instance_iam_role_use_name_prefix ? "${local.instance_iam_role_name}-" : null
387 | path = var.instance_iam_role_path
388 | description = var.instance_iam_role_description
389 |
390 | policy = data.aws_iam_policy_document.instance[0].json
391 |
392 | tags = var.tags
393 | }
394 |
395 | resource "aws_iam_role_policy_attachment" "instance" {
396 | count = local.create_instance_role_policy ? 1 : 0
397 |
398 | policy_arn = aws_iam_policy.instance[0].arn
399 | role = aws_iam_role.instance[0].name
400 | }
401 |
402 | ################################################################################
403 | # VPC Ingress Configuration
404 | ################################################################################
405 |
406 | resource "aws_apprunner_vpc_ingress_connection" "this" {
407 | count = local.create_service && var.create_ingress_vpc_connection ? 1 : 0
408 |
409 | name = var.service_name
410 | service_arn = aws_apprunner_service.this[0].arn
411 |
412 | ingress_vpc_configuration {
413 | vpc_id = var.ingress_vpc_id
414 | vpc_endpoint_id = var.ingress_vpc_endpoint_id
415 | }
416 |
417 | tags = var.tags
418 | }
419 |
420 | ################################################################################
421 | # Custom Domain Association
422 | ################################################################################
423 |
424 | locals {
425 | create_custom_domain_association = local.create_service && var.create_custom_domain_association
426 | }
427 |
428 | resource "aws_apprunner_custom_domain_association" "this" {
429 | count = local.create_custom_domain_association ? 1 : 0
430 |
431 | domain_name = var.domain_name
432 | enable_www_subdomain = var.enable_www_subdomain
433 | service_arn = aws_apprunner_service.this[0].arn
434 | }
435 |
436 | # # Requires manual intervention to validate records
437 | # # https://github.com/hashicorp/terraform-provider-aws/issues/23460
438 | # resource "aws_route53_record" "validation" {
439 | # count = length(aws_apprunner_custom_domain_association.this[0].certificate_validation_records)
440 |
441 | # allow_overwrite = true
442 | # name = aws_apprunner_custom_domain_association.this[0].certificate_validation_records.*.name[count.index]
443 | # records = [aws_apprunner_custom_domain_association.this[0].certificate_validation_records.*.value[count.index]]
444 | # ttl = 60
445 | # type = aws_apprunner_custom_domain_association.this[0].certificate_validation_records.*.type[count.index]
446 | # zone_id = var.hosted_zone_id
447 | # }
448 |
449 | # resource "aws_route53_record" "validation" {
450 | # for_each = {
451 | # for dvo in aws_apprunner_custom_domain_association.this[0].certificate_validation_records : dvo.name => {
452 | # name = dvo.name
453 | # record = dvo.value
454 | # type = dvo.type
455 | # } if local.create_custom_domain_association
456 | # }
457 |
458 | # allow_overwrite = true
459 | # name = each.value.name
460 | # records = [each.value.record]
461 | # ttl = 60
462 | # type = each.value.type
463 | # zone_id = var.hosted_zone_id
464 | # }
465 |
466 | # resource "aws_route53_record" "cname" {
467 | # count = local.create_custom_domain_association && var.domain_name_use_cname ? 1 : 0
468 |
469 | # allow_overwrite = true
470 | # name = var.domain_name
471 | # records = [aws_apprunner_custom_domain_association.this[0].dns_target]
472 | # ttl = 3600
473 | # type = "CNAME"
474 | # zone_id = var.hosted_zone_id
475 | # }
476 |
477 | # resource "aws_route53_record" "alias" {
478 | # for_each = { for k, v in toset(["A", "AAAA"]) : k => v if local.create_custom_domain_association && var.domain_name_use_cname }
479 |
480 | # zone_id = var.hosted_zone_id
481 | # name = var.domain_name
482 | # type = each.value
483 |
484 | # alias {
485 | # name = aws_apprunner_service.this[0].service_url
486 | # zone_id = ???
487 | # evaluate_target_health = true
488 | # }
489 | # }
490 |
491 | ################################################################################
492 | # VPC Connector
493 | ################################################################################
494 |
495 | locals {
496 | create_vpc_connector = local.create_service && var.create_vpc_connector
497 | vpc_connector_name = try(coalesce(var.vpc_connector_name, var.service_name), "")
498 | }
499 |
500 | resource "aws_apprunner_vpc_connector" "this" {
501 | count = local.create_vpc_connector ? 1 : 0
502 |
503 | vpc_connector_name = local.vpc_connector_name
504 | subnets = var.vpc_connector_subnets
505 | security_groups = var.vpc_connector_security_groups
506 |
507 | tags = var.tags
508 | }
509 |
510 | ################################################################################
511 | # Connection(s)
512 | ################################################################################
513 |
514 | resource "aws_apprunner_connection" "this" {
515 | for_each = { for k, v in var.connections : k => v if var.create }
516 |
517 | connection_name = try(each.value.name, each.key)
518 | provider_type = try(each.value.provider_type, "GITHUB")
519 |
520 | tags = merge(var.tags, try(each.value.tags, {}))
521 | }
522 |
523 | ################################################################################
524 | # Auto-Scaling Configuration(s)
525 | ################################################################################
526 |
527 | resource "aws_apprunner_auto_scaling_configuration_version" "this" {
528 | for_each = { for k, v in var.auto_scaling_configurations : k => v if var.create }
529 |
530 | auto_scaling_configuration_name = try(each.value.name, each.key)
531 | max_concurrency = try(each.value.max_concurrency, null)
532 | max_size = try(each.value.max_size, null)
533 | min_size = try(each.value.min_size, null)
534 |
535 | tags = merge(var.tags, try(each.value.tags, {}))
536 | }
537 |
538 | ################################################################################
539 | # Observability Configuration(s)
540 | ################################################################################
541 |
542 | locals {
543 | enable_observability_configuration = local.create_service && var.enable_observability_configuration
544 | }
545 |
546 | resource "aws_apprunner_observability_configuration" "this" {
547 | count = local.enable_observability_configuration ? 1 : 0
548 |
549 | observability_configuration_name = var.service_name
550 |
551 | trace_configuration {
552 | vendor = "AWSXRAY"
553 | }
554 |
555 | tags = var.tags
556 | }
557 |
--------------------------------------------------------------------------------
/outputs.tf:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Service
3 | ################################################################################
4 |
5 | output "service_arn" {
6 | description = "The Amazon Resource Name (ARN) of the service"
7 | value = try(aws_apprunner_service.this[0].arn, null)
8 | }
9 |
10 | output "service_id" {
11 | description = "An alphanumeric ID that App Runner generated for this service. Unique within the AWS Region"
12 | value = try(aws_apprunner_service.this[0].service_id, null)
13 | }
14 |
15 | output "service_url" {
16 | description = "A subdomain URL that App Runner generated for this service. You can use this URL to access your service web application"
17 | value = try("https://${aws_apprunner_service.this[0].service_url}", null)
18 | }
19 |
20 | output "service_status" {
21 | description = "The current state of the App Runner service"
22 | value = try(aws_apprunner_service.this[0].status, null)
23 | }
24 |
25 | ################################################################################
26 | # IAM Role - Access
27 | ################################################################################
28 |
29 | output "access_iam_role_name" {
30 | description = "The name of the IAM role"
31 | value = try(aws_iam_role.access[0].name, null)
32 | }
33 |
34 | output "access_iam_role_arn" {
35 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
36 | value = try(aws_iam_role.access[0].arn, null)
37 | }
38 |
39 | output "access_iam_role_unique_id" {
40 | description = "Stable and unique string identifying the IAM role"
41 | value = try(aws_iam_role.access[0].unique_id, null)
42 | }
43 |
44 | ################################################################################
45 | # IAM Role - Instance
46 | ################################################################################
47 |
48 | output "instance_iam_role_name" {
49 | description = "The name of the IAM role"
50 | value = try(aws_iam_role.instance[0].name, null)
51 | }
52 |
53 | output "instance_iam_role_arn" {
54 | description = "The Amazon Resource Name (ARN) specifying the IAM role"
55 | value = try(aws_iam_role.instance[0].arn, null)
56 | }
57 |
58 | output "instance_iam_role_unique_id" {
59 | description = "Stable and unique string identifying the IAM role"
60 | value = try(aws_iam_role.instance[0].unique_id, null)
61 | }
62 |
63 | ################################################################################
64 | # VPC Ingress Configuration
65 | ################################################################################
66 |
67 | output "vpc_ingress_connection_arn" {
68 | description = "The Amazon Resource Name (ARN) of the VPC Ingress Connection"
69 | value = try(aws_apprunner_vpc_ingress_connection.this[0].arn, null)
70 | }
71 |
72 | output "vpc_ingress_connection_domain_name" {
73 | description = "The domain name associated with the VPC Ingress Connection resource"
74 | value = try(aws_apprunner_vpc_ingress_connection.this[0].domain_name, null)
75 | }
76 |
77 | ################################################################################
78 | # Custom Domain Association
79 | ################################################################################
80 |
81 | output "custom_domain_association_id" {
82 | description = "The `domain_name` and `service_arn` separated by a comma (`,`)"
83 | value = try(aws_apprunner_custom_domain_association.this[0].id, null)
84 | }
85 |
86 | output "custom_domain_association_certificate_validation_records" {
87 | description = "A set of certificate CNAME records used for this domain name"
88 | value = try(aws_apprunner_custom_domain_association.this[0].certificate_validation_records, null)
89 | }
90 |
91 | output "custom_domain_association_dns_target" {
92 | description = "The App Runner subdomain of the App Runner service. The custom domain name is mapped to this target name. Attribute only available if resource created (not imported) with Terraform"
93 | value = try(aws_apprunner_custom_domain_association.this[0].dns_target, null)
94 | }
95 |
96 | ################################################################################
97 | # VPC Connector
98 | ################################################################################
99 |
100 | output "vpc_connector_arn" {
101 | description = "The Amazon Resource Name (ARN) of VPC connector"
102 | value = try(aws_apprunner_vpc_connector.this[0].arn, null)
103 | }
104 |
105 | output "vpc_connector_status" {
106 | description = "The current state of the VPC connector. If the status of a connector revision is INACTIVE, it was deleted and can't be used. Inactive connector revisions are permanently removed some time after they are deleted"
107 | value = try(aws_apprunner_vpc_connector.this[0].status, null)
108 | }
109 |
110 | output "vpc_connector_revision" {
111 | description = "The revision of VPC connector. It's unique among all the active connectors (\"Status\": \"ACTIVE\") that share the same Name"
112 | value = try(aws_apprunner_vpc_connector.this[0].vpc_connector_revision, null)
113 | }
114 |
115 | ################################################################################
116 | # Connection(s)
117 | ################################################################################
118 |
119 | output "connections" {
120 | description = "Map of attribute maps for all connections created"
121 | value = aws_apprunner_connection.this
122 | }
123 |
124 | ################################################################################
125 | # Auto-Scaling Configuration(s)
126 | ################################################################################
127 |
128 | output "auto_scaling_configurations" {
129 | description = "Map of attribute maps for all autoscaling configurations created"
130 | value = aws_apprunner_auto_scaling_configuration_version.this
131 | }
132 |
133 | ################################################################################
134 | # Observability Configuration
135 | ################################################################################
136 |
137 | output "observability_configuration_arn" {
138 | description = "ARN of this observability configuration"
139 | value = try(aws_apprunner_observability_configuration.this[0].arn, null)
140 | }
141 |
142 | output "observability_configuration_revision" {
143 | description = "The revision of the observability configuration"
144 | value = try(aws_apprunner_observability_configuration.this[0].observability_configuration_revision, null)
145 | }
146 |
147 | output "observability_configuration_latest" {
148 | description = "Whether the observability configuration has the highest `observability_configuration_revision` among all configurations that share the same `observability_configuration_name`"
149 | value = try(aws_apprunner_observability_configuration.this[0].latest, null)
150 | }
151 |
152 | output "observability_configuration_status" {
153 | description = "The current state of the observability configuration. An `INACTIVE` configuration revision has been deleted and can't be used. It is permanently removed some time after deletion"
154 | value = try(aws_apprunner_observability_configuration.this[0].status, null)
155 | }
156 |
--------------------------------------------------------------------------------
/variables.tf:
--------------------------------------------------------------------------------
1 | variable "create" {
2 | description = "Determines whether resources will be created (affects all resources)"
3 | type = bool
4 | default = true
5 | }
6 |
7 | variable "tags" {
8 | description = "A map of tags to add to all resources"
9 | type = map(string)
10 | default = {}
11 | }
12 |
13 | ################################################################################
14 | # Service
15 | ################################################################################
16 |
17 | variable "create_service" {
18 | description = "Determines whether the service will be created"
19 | type = bool
20 | default = true
21 | }
22 |
23 | variable "service_name" {
24 | description = "The name of the service"
25 | type = string
26 | default = ""
27 | }
28 |
29 | variable "auto_scaling_configuration_arn" {
30 | description = "ARN of an App Runner automatic scaling configuration resource that you want to associate with your service. If not provided, App Runner associates the latest revision of a default auto scaling configuration"
31 | type = string
32 | default = null
33 | }
34 |
35 | variable "encryption_configuration" {
36 | description = "The encryption configuration for the service"
37 | type = any
38 | default = {}
39 | }
40 |
41 | variable "health_check_configuration" {
42 | description = "The health check configuration for the service"
43 | type = any
44 | default = {}
45 | }
46 |
47 | variable "instance_configuration" {
48 | description = "The instance configuration for the service"
49 | type = any
50 | default = {}
51 | }
52 |
53 | variable "network_configuration" {
54 | description = "The network configuration for the service"
55 | type = any
56 | default = {}
57 | }
58 |
59 | variable "observability_configuration" {
60 | description = "The observability configuration for the service"
61 | type = any
62 | default = {}
63 | }
64 |
65 | variable "source_configuration" {
66 | description = "The source configuration for the service"
67 | type = any
68 | default = {}
69 | }
70 |
71 | ################################################################################
72 | # IAM Role - Access
73 | ################################################################################
74 |
75 | variable "create_access_iam_role" {
76 | description = "Determines whether an IAM role is created or to use an existing IAM role"
77 | type = bool
78 | default = false
79 | }
80 |
81 | variable "access_iam_role_name" {
82 | description = "Name to use on IAM role created"
83 | type = string
84 | default = null
85 | }
86 |
87 | variable "access_iam_role_use_name_prefix" {
88 | description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix"
89 | type = bool
90 | default = true
91 | }
92 |
93 | variable "access_iam_role_path" {
94 | description = "IAM role path"
95 | type = string
96 | default = null
97 | }
98 |
99 | variable "access_iam_role_description" {
100 | description = "Description of the role"
101 | type = string
102 | default = null
103 | }
104 |
105 | variable "access_iam_role_permissions_boundary" {
106 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role"
107 | type = string
108 | default = null
109 | }
110 |
111 | variable "private_ecr_arn" {
112 | description = "The ARN of the private ECR repository that contains the service image to launch"
113 | type = string
114 | default = null
115 | }
116 |
117 | variable "access_iam_role_policies" {
118 | description = "IAM policies to attach to the IAM role"
119 | type = map(string)
120 | default = {}
121 | }
122 |
123 | ################################################################################
124 | # IAM Role - Instance
125 | ################################################################################
126 |
127 | variable "create_instance_iam_role" {
128 | description = "Determines whether an IAM role is created or to use an existing IAM role"
129 | type = bool
130 | default = true
131 | }
132 |
133 | variable "instance_iam_role_name" {
134 | description = "Name to use on IAM role created"
135 | type = string
136 | default = null
137 | }
138 |
139 | variable "instance_iam_role_use_name_prefix" {
140 | description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix"
141 | type = bool
142 | default = true
143 | }
144 |
145 | variable "instance_iam_role_path" {
146 | description = "IAM role path"
147 | type = string
148 | default = null
149 | }
150 |
151 | variable "instance_iam_role_description" {
152 | description = "Description of the role"
153 | type = string
154 | default = null
155 | }
156 |
157 | variable "instance_iam_role_permissions_boundary" {
158 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role"
159 | type = string
160 | default = null
161 | }
162 |
163 | variable "instance_iam_role_policies" {
164 | description = "IAM policies to attach to the IAM role"
165 | type = map(string)
166 | default = {}
167 | }
168 |
169 | ################################################################################
170 | # IAM Role Policy - Instance
171 | ################################################################################
172 |
173 | variable "instance_policy_statements" {
174 | description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage"
175 | type = any
176 | default = {}
177 | }
178 |
179 | ################################################################################
180 | # VPC Ingress Configuration
181 | ################################################################################
182 |
183 | variable "create_ingress_vpc_connection" {
184 | description = "Determines whether a VPC ingress configuration will be created"
185 | type = bool
186 | default = false
187 | }
188 |
189 | variable "ingress_vpc_id" {
190 | description = "The ID of the VPC that is used for the VPC ingress configuration"
191 | type = string
192 | default = ""
193 | }
194 |
195 | variable "ingress_vpc_endpoint_id" {
196 | description = "The ID of the VPC endpoint that is used for the VPC ingress configuration"
197 | type = string
198 | default = ""
199 | }
200 |
201 | ################################################################################
202 | # Custom Domain Association
203 | ################################################################################
204 |
205 | variable "create_custom_domain_association" {
206 | description = "Determines whether a Custom Domain Association will be created"
207 | type = bool
208 | default = false
209 | }
210 |
211 | variable "domain_name" {
212 | description = "The custom domain endpoint to association. Specify a base domain e.g., `example.com` or a subdomain e.g., `subdomain.example.com`"
213 | type = string
214 | default = ""
215 | }
216 |
217 | variable "enable_www_subdomain" {
218 | description = "Whether to associate the subdomain with the App Runner service in addition to the base domain. Defaults to `true`"
219 | type = bool
220 | default = null
221 | }
222 |
223 | # variable "hosted_zone_id" {
224 | # description = "The ID of the Route53 hosted zone that contains the domain for the `domain_name`"
225 | # type = string
226 | # default = ""
227 | # }
228 |
229 | ################################################################################
230 | # VPC Connector
231 | ################################################################################
232 |
233 | variable "create_vpc_connector" {
234 | description = "Determines whether a VPC Connector will be created"
235 | type = bool
236 | default = false
237 | }
238 |
239 | variable "vpc_connector_name" {
240 | description = "The name of the VPC Connector"
241 | type = string
242 | default = ""
243 | }
244 |
245 | variable "vpc_connector_subnets" {
246 | description = "The subnets to use for the VPC Connector"
247 | type = list(string)
248 | default = []
249 | }
250 |
251 | variable "vpc_connector_security_groups" {
252 | description = "The security groups to use for the VPC Connector"
253 | type = list(string)
254 | default = []
255 | }
256 |
257 | ################################################################################
258 | # Connection(s)
259 | ################################################################################
260 |
261 | variable "connections" {
262 | description = "Map of connection definitions to create"
263 | type = any
264 | default = {}
265 | }
266 |
267 | ################################################################################
268 | # Autoscaling Configuration(s)
269 | ################################################################################
270 |
271 | variable "auto_scaling_configurations" {
272 | description = "Map of auto-scaling configuration definitions to create"
273 | type = any
274 | default = {}
275 | }
276 |
277 | ################################################################################
278 | # Observability Configuration
279 | ################################################################################
280 |
281 | variable "enable_observability_configuration" {
282 | description = "Determines whether an X-Ray Observability Configuration will be created and assigned to the service"
283 | type = bool
284 | default = true
285 | }
286 |
--------------------------------------------------------------------------------
/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0"
3 |
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = ">= 4.51"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------