├── .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 │ ├── files │ │ ├── ABOUT.md │ │ ├── USAGE.md │ │ └── clowd.png │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── repository-template │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── main.tf ├── modules └── repository-template │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── outputs.tf ├── variables.tf ├── versions.tf └── wrappers ├── README.md ├── main.tf ├── outputs.tf ├── repository-template ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.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 | 39 | .DS_Store 40 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.96.2 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_wrapper_module_for_each 7 | - id: terraform_docs 8 | args: 9 | - '--args=--lockfile=false' 10 | - id: terraform_tflint 11 | args: 12 | - '--args=--only=terraform_deprecated_interpolation' 13 | - '--args=--only=terraform_deprecated_index' 14 | - '--args=--only=terraform_unused_declarations' 15 | - '--args=--only=terraform_comment_syntax' 16 | - '--args=--only=terraform_documented_outputs' 17 | - '--args=--only=terraform_documented_variables' 18 | - '--args=--only=terraform_typed_variables' 19 | - '--args=--only=terraform_module_pinned_source' 20 | - '--args=--only=terraform_naming_convention' 21 | - '--args=--only=terraform_required_version' 22 | - '--args=--only=terraform_required_providers' 23 | - '--args=--only=terraform_standard_module_structure' 24 | - '--args=--only=terraform_workspace_remote' 25 | - id: terraform_validate 26 | - repo: https://github.com/pre-commit/pre-commit-hooks 27 | rev: v5.0.0 28 | hooks: 29 | - id: check-merge-conflict 30 | - id: end-of-file-fixer 31 | - id: trailing-whitespace 32 | -------------------------------------------------------------------------------- /.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 | ## [2.4.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.3.1...v2.4.0) (2025-03-30) 6 | 7 | 8 | ### Features 9 | 10 | * Support private ecr pull through cache ([#55](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/55)) ([2764bd8](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/2764bd8242d9f0a268ef500364bed8486a281f14)) 11 | 12 | ## [2.3.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.3.0...v2.3.1) (2024-11-27) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * Remove Public ECR permissions from repository template permissions ([#51](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/51)) ([1ef222b](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/1ef222bf4744412f5ab343d7b8ebd021d94652a6)) 18 | * Update CI workflow versions to latest ([#48](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/48)) ([124c139](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/124c13976f4cdc061f5b1ddb38bff715eeba2ad5)) 19 | 20 | ## [2.3.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.2.1...v2.3.0) (2024-09-04) 21 | 22 | 23 | ### Features 24 | 25 | * Add support for repository creation template ([#46](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/46)) ([4e93036](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/4e930363ba48a676c7b1a5a4ff492567f77e75c1)) 26 | 27 | ## [2.2.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.2.0...v2.2.1) (2024-04-17) 28 | 29 | 30 | ### Bug Fixes 31 | 32 | * Add tags variable to public registry resource ([#40](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/40)) ([27f4867](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/27f48679600c7bc86528e0a95a9f221a5e1c5854)) 33 | 34 | ## [2.2.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.1.1...v2.2.0) (2024-04-05) 35 | 36 | 37 | ### Features 38 | 39 | * Added repository_name as output ([#37](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/37)) ([d704c6e](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/d704c6e6b88726a9f24c466d38654ab9470de181)) 40 | 41 | ## [2.1.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.1.0...v2.1.1) (2024-04-03) 42 | 43 | 44 | ### Bug Fixes 45 | 46 | * Correct typo `credentials_arn` -> `credential_arn` ([#36](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/36)) ([b5bd6a4](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/b5bd6a4cadf0e9f66ea144ba16f6e7455c778416)) 47 | 48 | ## [2.1.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v2.0.0...v2.1.0) (2024-03-25) 49 | 50 | 51 | ### Features 52 | 53 | * Add `credentials_arn` to support ECR pull through cache ([#30](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/30)) ([05e6fd0](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/05e6fd073519aa61e880e6a3b4712d67087ea77f)) 54 | 55 | ## [2.0.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.7.1...v2.0.0) (2024-03-15) 56 | 57 | 58 | ### ⚠ BREAKING CHANGES 59 | 60 | * Allow multiple scan filters per scan type in registry; Raise MSV of Terraform and AWS provider to 1.0 and 5.0 respectively (#29) 61 | 62 | ### Features 63 | 64 | * Allow multiple scan filters per scan type in registry; Raise MSV of Terraform and AWS provider to 1.0 and 5.0 respectively ([#29](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/29)) ([cbba4fd](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/cbba4fd31f5a7a04b3d57666c409996bf5eb2bdd)) 65 | 66 | ## [1.7.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.7.0...v1.7.1) (2024-03-07) 67 | 68 | 69 | ### Bug Fixes 70 | 71 | * Update CI workflow versions to remove deprecated runtime warnings ([#28](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/28)) ([1f74cc5](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/1f74cc5b0b5982bb4be0faed117faba1d3b92773)) 72 | 73 | ## [1.7.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.6.0...v1.7.0) (2024-03-04) 74 | 75 | 76 | ### Features 77 | 78 | * Add support for creating custom repository policy statements ([#27](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/27)) ([fb9126c](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/fb9126ca4c9a5c2d3213f525e040d4a84ff6e71c)) 79 | 80 | ## [1.6.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.5.1...v1.6.0) (2023-02-16) 81 | 82 | 83 | ### Features 84 | 85 | * Add new variable for allowing ECR image sharing to lambda service in external account ([#16](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/16)) ([be2edd1](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/be2edd1b481e14e45d5d548ca47e04c41dce2058)) 86 | 87 | ### [1.5.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.5.0...v1.5.1) (2022-11-12) 88 | 89 | 90 | ### Bug Fixes 91 | 92 | * Update CI configuration files to use latest version ([#13](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/13)) ([885f800](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/885f800769f2616aa8306190aa664f6f88633404)) 93 | 94 | ## [1.5.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.4.0...v1.5.0) (2022-10-31) 95 | 96 | 97 | ### Features 98 | 99 | * Added ecr:GetAuthorizationToken for private ECR with Docker capabilities ([#12](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/12)) ([0a087ca](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/0a087ca8c2d9097fe2b73e112549739962114c9f)) 100 | 101 | ## [1.4.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.3.2...v1.4.0) (2022-07-14) 102 | 103 | 104 | ### Features 105 | 106 | * Add support for `force_delete` attribute ([#9](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/9)) ([850ddb0](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/850ddb0a35188785b3dee3e64ad8833175f7376e)) 107 | 108 | ### [1.3.2](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.3.1...v1.3.2) (2022-06-26) 109 | 110 | 111 | ### Bug Fixes 112 | 113 | * Add new variable to control whether a repository policy is attached to the repository ([#8](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/8)) ([4706acf](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/4706acfd9137a1bd2ccf918767c48ec73b99dfbd)) 114 | 115 | ### [1.3.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.3.0...v1.3.1) (2022-06-26) 116 | 117 | 118 | ### Bug Fixes 119 | 120 | * Update the permission for the public ecr ([#7](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/7)) ([70f3252](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/70f3252311f29bc9dc3ea6e72ec2abb70c387eb1)) 121 | 122 | ## [1.3.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.2.0...v1.3.0) (2022-06-13) 123 | 124 | 125 | ### Features 126 | 127 | * Add a new variable to control the creation of a lifecycle policy ([#4](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/4)) ([18c0515](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/18c05151fa481a02a93ba2ab549842b0e5bddf1a)) 128 | 129 | ## [1.2.0](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.1.1...v1.2.0) (2022-06-07) 130 | 131 | 132 | ### Features 133 | 134 | * Add wrapper module and pre-commit hook ([#3](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/3)) ([c2284be](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/c2284be33c572839d178bcbcf53f1eaaebe5016c)) 135 | 136 | ### [1.1.1](https://github.com/terraform-aws-modules/terraform-aws-ecr/compare/v1.1.0...v1.1.1) (2022-04-21) 137 | 138 | 139 | ### Bug Fixes 140 | 141 | * Update documentation to remove prior notice and deprecated workflow ([#1](https://github.com/terraform-aws-modules/terraform-aws-ecr/issues/1)) ([4de4770](https://github.com/terraform-aws-modules/terraform-aws-ecr/commit/4de4770117a8574b28f9ebe99b8823137e3e2ff0)) 142 | 143 | ## [1.1.0](https://github.com/clowdhaus/terraform-aws-ecr/compare/v1.0.0...v1.1.0) (2022-04-20) 144 | 145 | 146 | ### Features 147 | 148 | * Repo has moved to [terraform-aws-modules](https://github.com/terraform-aws-modules/terraform-aws-ecr) organization ([8e15f9a](https://github.com/clowdhaus/terraform-aws-ecr/commit/8e15f9aa955e5f7ce7832bf9514ac149c0f8d631)) 149 | -------------------------------------------------------------------------------- /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 | # Amazon ECR Terraform module 2 | 3 | Terraform module which creates Amazon ECR resources. 4 | 5 | ## Usage 6 | 7 | See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples) directory for working examples to reference: 8 | 9 | ### Private Repository 10 | 11 | ```hcl 12 | module "ecr" { 13 | source = "terraform-aws-modules/ecr/aws" 14 | 15 | repository_name = "private-example" 16 | 17 | repository_read_write_access_arns = ["arn:aws:iam::012345678901:role/terraform"] 18 | repository_lifecycle_policy = jsonencode({ 19 | rules = [ 20 | { 21 | rulePriority = 1, 22 | description = "Keep last 30 images", 23 | selection = { 24 | tagStatus = "tagged", 25 | tagPrefixList = ["v"], 26 | countType = "imageCountMoreThan", 27 | countNumber = 30 28 | }, 29 | action = { 30 | type = "expire" 31 | } 32 | } 33 | ] 34 | }) 35 | 36 | tags = { 37 | Terraform = "true" 38 | Environment = "dev" 39 | } 40 | } 41 | ``` 42 | 43 | ### Public Repository 44 | 45 | ```hcl 46 | module "public_ecr" { 47 | source = "terraform-aws-modules/ecr/aws" 48 | 49 | repository_name = "public-example" 50 | repository_type = "public" 51 | 52 | repository_read_write_access_arns = ["arn:aws:iam::012345678901:role/terraform"] 53 | 54 | public_repository_catalog_data = { 55 | description = "Docker container for some things" 56 | about_text = file("${path.module}/files/ABOUT.md") 57 | usage_text = file("${path.module}/files/USAGE.md") 58 | operating_systems = ["Linux"] 59 | architectures = ["x86"] 60 | logo_image_blob = filebase64("${path.module}/files/clowd.png") 61 | } 62 | 63 | tags = { 64 | Terraform = "true" 65 | Environment = "dev" 66 | } 67 | } 68 | ``` 69 | 70 | ### Registry Management 71 | 72 | ```hcl 73 | module "ecr_registry" { 74 | source = "terraform-aws-modules/ecr/aws" 75 | 76 | repository_name = "registry-example" 77 | 78 | create_repository = false 79 | 80 | # Registry Policy 81 | create_registry_policy = true 82 | registry_policy = jsonencode({ 83 | Version = "2012-10-17", 84 | Statement = [ 85 | { 86 | Sid = "testpolicy", 87 | Effect = "Allow", 88 | Principal = { 89 | "AWS" : "arn:aws:iam::012345678901:root" 90 | }, 91 | Action = [ 92 | "ecr:ReplicateImage" 93 | ], 94 | Resource = [ 95 | "arn:aws:ecr:us-east-1:012345678901:repository/*" 96 | ] 97 | }, { 98 | Sid = "dockerhub", 99 | Effect = "Allow", 100 | Principal = { 101 | "AWS" : "arn:aws:iam::012345678901:root" 102 | }, 103 | Action = [ 104 | "ecr:CreateRepository", 105 | "ecr:BatchImportUpstreamImage" 106 | ], 107 | Resource = [ 108 | "arn:aws:ecr:us-east-1:012345678901:repository/dockerhub/*" 109 | ] 110 | } 111 | ] 112 | }) 113 | 114 | # Registry Pull Through Cache Rules 115 | registry_pull_through_cache_rules = { 116 | pub = { 117 | ecr_repository_prefix = "ecr-public" 118 | upstream_registry_url = "public.ecr.aws" 119 | } 120 | dockerhub = { 121 | ecr_repository_prefix = "dockerhub" 122 | upstream_registry_url = "registry-1.docker.io" 123 | credential_arn = "arn:aws:secretsmanager:us-east-1:123456789:secret:ecr-pullthroughcache/dockerhub" 124 | } 125 | } 126 | 127 | # Registry Scanning Configuration 128 | manage_registry_scanning_configuration = true 129 | registry_scan_type = "ENHANCED" 130 | registry_scan_rules = [ 131 | { 132 | scan_frequency = "SCAN_ON_PUSH" 133 | filter = [ 134 | { 135 | filter = "example1" 136 | filter_type = "WILDCARD" 137 | }, 138 | { filter = "example2" 139 | filter_type = "WILDCARD" 140 | } 141 | ] 142 | }, { 143 | scan_frequency = "CONTINUOUS_SCAN" 144 | filter = [ 145 | { 146 | filter = "example" 147 | filter_type = "WILDCARD" 148 | } 149 | ] 150 | } 151 | ] 152 | 153 | # Registry Replication Configuration 154 | create_registry_replication_configuration = true 155 | registry_replication_rules = [ 156 | { 157 | destinations = [{ 158 | region = "us-west-2" 159 | registry_id = "012345678901" 160 | }, { 161 | region = "eu-west-1" 162 | registry_id = "012345678901" 163 | }] 164 | 165 | repository_filters = [{ 166 | filter = "prod-microservice" 167 | filter_type = "PREFIX_MATCH" 168 | }] 169 | } 170 | ] 171 | 172 | tags = { 173 | Terraform = "true" 174 | Environment = "dev" 175 | } 176 | } 177 | ``` 178 | 179 | ## Module wrappers 180 | 181 | Users of this Terraform module can create multiple similar resources by using [`for_each` meta-argument within `module` block](https://www.terraform.io/language/meta-arguments/for_each) which became available in Terraform 0.13. 182 | 183 | Users of Terragrunt can achieve similar results by using modules provided in the [wrappers](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/wrappers) directory, if they prefer to reduce amount of configuration files. 184 | 185 | ## Examples 186 | 187 | Examples codified under the [`examples`](https://github.com/terraform-aws-modules/terraform-aws-ecr/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! 188 | 189 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/complete) 190 | - [Repository Template](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/repository-template) 191 | 192 | 193 | ## Requirements 194 | 195 | | Name | Version | 196 | |------|---------| 197 | | [terraform](#requirement\_terraform) | >= 1.0 | 198 | | [aws](#requirement\_aws) | >= 5.93 | 199 | 200 | ## Providers 201 | 202 | | Name | Version | 203 | |------|---------| 204 | | [aws](#provider\_aws) | >= 5.93 | 205 | 206 | ## Modules 207 | 208 | No modules. 209 | 210 | ## Resources 211 | 212 | | Name | Type | 213 | |------|------| 214 | | [aws_ecr_lifecycle_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource | 215 | | [aws_ecr_pull_through_cache_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_pull_through_cache_rule) | resource | 216 | | [aws_ecr_registry_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_registry_policy) | resource | 217 | | [aws_ecr_registry_scanning_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_registry_scanning_configuration) | resource | 218 | | [aws_ecr_replication_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration) | resource | 219 | | [aws_ecr_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | 220 | | [aws_ecr_repository_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource | 221 | | [aws_ecrpublic_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecrpublic_repository) | resource | 222 | | [aws_ecrpublic_repository_policy.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecrpublic_repository_policy) | resource | 223 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 224 | | [aws_iam_policy_document.repository](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 225 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | 226 | 227 | ## Inputs 228 | 229 | | Name | Description | Type | Default | Required | 230 | |------|-------------|------|---------|:--------:| 231 | | [attach\_repository\_policy](#input\_attach\_repository\_policy) | Determines whether a repository policy will be attached to the repository | `bool` | `true` | no | 232 | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | 233 | | [create\_lifecycle\_policy](#input\_create\_lifecycle\_policy) | Determines whether a lifecycle policy will be created | `bool` | `true` | no | 234 | | [create\_registry\_policy](#input\_create\_registry\_policy) | Determines whether a registry policy will be created | `bool` | `false` | no | 235 | | [create\_registry\_replication\_configuration](#input\_create\_registry\_replication\_configuration) | Determines whether a registry replication configuration will be created | `bool` | `false` | no | 236 | | [create\_repository](#input\_create\_repository) | Determines whether a repository will be created | `bool` | `true` | no | 237 | | [create\_repository\_policy](#input\_create\_repository\_policy) | Determines whether a repository policy will be created | `bool` | `true` | no | 238 | | [manage\_registry\_scanning\_configuration](#input\_manage\_registry\_scanning\_configuration) | Determines whether the registry scanning configuration will be managed | `bool` | `false` | no | 239 | | [public\_repository\_catalog\_data](#input\_public\_repository\_catalog\_data) | Catalog data configuration for the repository | `any` | `{}` | no | 240 | | [registry\_policy](#input\_registry\_policy) | The policy document. This is a JSON formatted string | `string` | `null` | no | 241 | | [registry\_pull\_through\_cache\_rules](#input\_registry\_pull\_through\_cache\_rules) | List of pull through cache rules to create | `map(map(string))` | `{}` | no | 242 | | [registry\_replication\_rules](#input\_registry\_replication\_rules) | The replication rules for a replication configuration. A maximum of 10 are allowed | `any` | `[]` | no | 243 | | [registry\_scan\_rules](#input\_registry\_scan\_rules) | One or multiple blocks specifying scanning rules to determine which repository filters are used and at what frequency scanning will occur | `any` | `[]` | no | 244 | | [registry\_scan\_type](#input\_registry\_scan\_type) | the scanning type to set for the registry. Can be either `ENHANCED` or `BASIC` | `string` | `"ENHANCED"` | no | 245 | | [repository\_encryption\_type](#input\_repository\_encryption\_type) | The encryption type for the repository. Must be one of: `KMS` or `AES256`. Defaults to `AES256` | `string` | `null` | no | 246 | | [repository\_force\_delete](#input\_repository\_force\_delete) | If `true`, will delete the repository even if it contains images. Defaults to `false` | `bool` | `null` | no | 247 | | [repository\_image\_scan\_on\_push](#input\_repository\_image\_scan\_on\_push) | Indicates whether images are scanned after being pushed to the repository (`true`) or not scanned (`false`) | `bool` | `true` | no | 248 | | [repository\_image\_tag\_mutability](#input\_repository\_image\_tag\_mutability) | The tag mutability setting for the repository. Must be one of: `MUTABLE` or `IMMUTABLE`. Defaults to `IMMUTABLE` | `string` | `"IMMUTABLE"` | no | 249 | | [repository\_kms\_key](#input\_repository\_kms\_key) | The ARN of the KMS key to use when encryption\_type is `KMS`. If not specified, uses the default AWS managed key for ECR | `string` | `null` | no | 250 | | [repository\_lambda\_read\_access\_arns](#input\_repository\_lambda\_read\_access\_arns) | The ARNs of the Lambda service roles that have read access to the repository | `list(string)` | `[]` | no | 251 | | [repository\_lifecycle\_policy](#input\_repository\_lifecycle\_policy) | The policy document. This is a JSON formatted string. See more details about [Policy Parameters](http://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lifecycle_policy_parameters) in the official AWS docs | `string` | `""` | no | 252 | | [repository\_name](#input\_repository\_name) | The name of the repository | `string` | `""` | no | 253 | | [repository\_policy](#input\_repository\_policy) | The JSON policy to apply to the repository. If not specified, uses the default policy | `string` | `null` | no | 254 | | [repository\_policy\_statements](#input\_repository\_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 | 255 | | [repository\_read\_access\_arns](#input\_repository\_read\_access\_arns) | The ARNs of the IAM users/roles that have read access to the repository | `list(string)` | `[]` | no | 256 | | [repository\_read\_write\_access\_arns](#input\_repository\_read\_write\_access\_arns) | The ARNs of the IAM users/roles that have read/write access to the repository | `list(string)` | `[]` | no | 257 | | [repository\_type](#input\_repository\_type) | The type of repository to create. Either `public` or `private` | `string` | `"private"` | no | 258 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | 259 | 260 | ## Outputs 261 | 262 | | Name | Description | 263 | |------|-------------| 264 | | [repository\_arn](#output\_repository\_arn) | Full ARN of the repository | 265 | | [repository\_name](#output\_repository\_name) | Name of the repository | 266 | | [repository\_registry\_id](#output\_repository\_registry\_id) | The registry ID where the repository was created | 267 | | [repository\_url](#output\_repository\_url) | The URL of the repository | 268 | 269 | 270 | ## License 271 | 272 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-ecr/blob/master/LICENSE). 273 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Amazon ECR Examples 2 | 3 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/complete) 4 | - [Repository Template](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/repository-template) 5 | -------------------------------------------------------------------------------- /examples/complete/README.md: -------------------------------------------------------------------------------- 1 | # Amazon ECR Complete Example 2 | 3 | Configuration in this directory creates: 4 | 5 | - Private ECR repository 6 | - Public ECR repository 7 | - Registry settings 8 | - Registry policy 9 | - Pull through cache rules 10 | - Scanning configuration 11 | - Replication configuration 12 | 13 | ## Usage 14 | 15 | To run this example you need to execute: 16 | 17 | ```bash 18 | $ terraform init 19 | $ terraform plan 20 | $ terraform apply 21 | ``` 22 | 23 | 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. 24 | 25 | 26 | ## Requirements 27 | 28 | | Name | Version | 29 | |------|---------| 30 | | [terraform](#requirement\_terraform) | >= 1.0 | 31 | | [aws](#requirement\_aws) | >= 5.93 | 32 | 33 | ## Providers 34 | 35 | | Name | Version | 36 | |------|---------| 37 | | [aws](#provider\_aws) | >= 5.93 | 38 | 39 | ## Modules 40 | 41 | | Name | Source | Version | 42 | |------|--------|---------| 43 | | [ecr](#module\_ecr) | ../.. | n/a | 44 | | [ecr\_disabled](#module\_ecr\_disabled) | ../.. | n/a | 45 | | [ecr\_registry](#module\_ecr\_registry) | ../.. | n/a | 46 | | [public\_ecr](#module\_public\_ecr) | ../.. | n/a | 47 | | [secrets\_manager\_dockerhub\_credentials](#module\_secrets\_manager\_dockerhub\_credentials) | terraform-aws-modules/secrets-manager/aws | ~> 1.0 | 48 | 49 | ## Resources 50 | 51 | | Name | Type | 52 | |------|------| 53 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 54 | | [aws_iam_policy_document.registry](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 55 | 56 | ## Inputs 57 | 58 | No inputs. 59 | 60 | ## Outputs 61 | 62 | | Name | Description | 63 | |------|-------------| 64 | | [public\_repository\_arn](#output\_public\_repository\_arn) | Full ARN of the repository | 65 | | [public\_repository\_name](#output\_public\_repository\_name) | Name of the repository | 66 | | [public\_repository\_registry\_id](#output\_public\_repository\_registry\_id) | The registry ID where the repository was created | 67 | | [public\_repository\_url](#output\_public\_repository\_url) | The URL of the repository (in the form `aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName`) | 68 | | [repository\_arn](#output\_repository\_arn) | Full ARN of the repository | 69 | | [repository\_name](#output\_repository\_name) | Name of the repository | 70 | | [repository\_registry\_id](#output\_repository\_registry\_id) | The registry ID where the repository was created | 71 | | [repository\_url](#output\_repository\_url) | The URL of the repository (in the form `aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName`) | 72 | 73 | 74 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-ecr/blob/master/LICENSE). 75 | -------------------------------------------------------------------------------- /examples/complete/files/ABOUT.md: -------------------------------------------------------------------------------- 1 | # About This Image 2 | 3 | This image is based used for things. 4 | -------------------------------------------------------------------------------- /examples/complete/files/USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Here is how you use this image. 4 | -------------------------------------------------------------------------------- /examples/complete/files/clowd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ecr/f475c99a68f1f3b0e0bf996d098d94c68570eab8/examples/complete/files/clowd.png -------------------------------------------------------------------------------- /examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | locals { 6 | region = "us-east-1" 7 | name = "ecr-ex-${replace(basename(path.cwd), "_", "-")}" 8 | 9 | account_id = data.aws_caller_identity.current.account_id 10 | 11 | tags = { 12 | Name = local.name 13 | Example = local.name 14 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-ecr" 15 | } 16 | } 17 | 18 | data "aws_caller_identity" "current" {} 19 | 20 | ################################################################################ 21 | # ECR Repository 22 | ################################################################################ 23 | 24 | module "ecr_disabled" { 25 | source = "../.." 26 | 27 | create = false 28 | } 29 | 30 | module "ecr" { 31 | source = "../.." 32 | 33 | repository_name = local.name 34 | 35 | repository_read_write_access_arns = [data.aws_caller_identity.current.arn] 36 | create_lifecycle_policy = true 37 | repository_lifecycle_policy = jsonencode({ 38 | rules = [ 39 | { 40 | rulePriority = 1, 41 | description = "Keep last 30 images", 42 | selection = { 43 | tagStatus = "tagged", 44 | tagPrefixList = ["v"], 45 | countType = "imageCountMoreThan", 46 | countNumber = 30 47 | }, 48 | action = { 49 | type = "expire" 50 | } 51 | } 52 | ] 53 | }) 54 | 55 | repository_force_delete = true 56 | 57 | tags = local.tags 58 | } 59 | 60 | module "public_ecr" { 61 | source = "../.." 62 | 63 | repository_name = local.name 64 | repository_type = "public" 65 | 66 | repository_read_write_access_arns = [data.aws_caller_identity.current.arn] 67 | 68 | public_repository_catalog_data = { 69 | description = "Docker container for some things" 70 | about_text = file("${path.module}/files/ABOUT.md") 71 | usage_text = file("${path.module}/files/USAGE.md") 72 | operating_systems = ["Linux"] 73 | architectures = ["x86"] 74 | logo_image_blob = filebase64("${path.module}/files/clowd.png") 75 | } 76 | 77 | tags = local.tags 78 | } 79 | 80 | ################################################################################ 81 | # ECR Registry 82 | ################################################################################ 83 | 84 | data "aws_iam_policy_document" "registry" { 85 | statement { 86 | principals { 87 | type = "AWS" 88 | identifiers = ["arn:aws:iam::${local.account_id}:root"] 89 | } 90 | 91 | actions = ["ecr:ReplicateImage"] 92 | resources = [module.ecr.repository_arn] 93 | } 94 | 95 | statement { 96 | sid = "dockerhub" 97 | 98 | principals { 99 | type = "AWS" 100 | identifiers = ["arn:aws:iam::${local.account_id}:root"] 101 | } 102 | actions = [ 103 | "ecr:CreateRepository", 104 | "ecr:BatchImportUpstreamImage" 105 | ] 106 | resources = ["arn:aws:ecr-public::${local.account_id}:repository/dockerhub/*"] 107 | } 108 | } 109 | 110 | module "ecr_registry" { 111 | source = "../.." 112 | 113 | create_repository = false 114 | 115 | # Registry Policy 116 | create_registry_policy = true 117 | registry_policy = data.aws_iam_policy_document.registry.json 118 | 119 | # Registry Pull Through Cache Rules 120 | registry_pull_through_cache_rules = { 121 | pub = { 122 | ecr_repository_prefix = "ecr-public" 123 | upstream_registry_url = "public.ecr.aws" 124 | } 125 | dockerhub = { 126 | ecr_repository_prefix = "dockerhub" 127 | upstream_registry_url = "registry-1.docker.io" 128 | credential_arn = module.secrets_manager_dockerhub_credentials.secret_arn 129 | } 130 | priv = { 131 | ecr_repository_prefix = local.name 132 | upstream_registry_url = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-west-2.amazonaws.com" 133 | upstream_repository_prefix = "myapp" 134 | } 135 | } 136 | 137 | # Registry Scanning Configuration 138 | manage_registry_scanning_configuration = true 139 | registry_scan_type = "ENHANCED" 140 | registry_scan_rules = [ 141 | { 142 | scan_frequency = "SCAN_ON_PUSH" 143 | filter = [ 144 | { 145 | filter = "example1" 146 | filter_type = "WILDCARD" 147 | }, 148 | { filter = "example2" 149 | filter_type = "WILDCARD" 150 | } 151 | ] 152 | }, { 153 | scan_frequency = "CONTINUOUS_SCAN" 154 | filter = [ 155 | { 156 | filter = "example" 157 | filter_type = "WILDCARD" 158 | } 159 | ] 160 | } 161 | ] 162 | 163 | # Registry Replication Configuration 164 | create_registry_replication_configuration = true 165 | registry_replication_rules = [{ 166 | destinations = [{ 167 | region = "us-west-2" 168 | registry_id = local.account_id 169 | }, { 170 | region = "eu-west-1" 171 | registry_id = local.account_id 172 | }] 173 | 174 | repository_filters = [{ 175 | filter = "prod-microservice" 176 | filter_type = "PREFIX_MATCH" 177 | }] 178 | }] 179 | 180 | tags = local.tags 181 | } 182 | 183 | module "secrets_manager_dockerhub_credentials" { 184 | source = "terraform-aws-modules/secrets-manager/aws" 185 | version = "~> 1.0" 186 | 187 | # Secret names must contain 1-512 Unicode characters and be prefixed with ecr-pullthroughcache/ 188 | name_prefix = "ecr-pullthroughcache/dockerhub-credentials" 189 | description = "Dockerhub credentials" 190 | 191 | # For example only 192 | recovery_window_in_days = 0 193 | secret_string = jsonencode({ 194 | username = "example" 195 | accessToken = "YouShouldNotStoreThisInPlainText" 196 | }) 197 | 198 | # Policy 199 | create_policy = true 200 | block_public_policy = true 201 | policy_statements = { 202 | read = { 203 | sid = "AllowAccountRead" 204 | principals = [{ 205 | type = "AWS" 206 | identifiers = ["arn:aws:iam::${local.account_id}:root"] 207 | }] 208 | actions = ["secretsmanager:GetSecretValue"] 209 | resources = ["*"] 210 | } 211 | } 212 | 213 | tags = local.tags 214 | } 215 | -------------------------------------------------------------------------------- /examples/complete/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Private Repository 3 | ################################################################################ 4 | 5 | output "repository_name" { 6 | description = "Name of the repository" 7 | value = module.ecr.repository_name 8 | } 9 | 10 | output "repository_arn" { 11 | description = "Full ARN of the repository" 12 | value = module.ecr.repository_arn 13 | } 14 | 15 | output "repository_registry_id" { 16 | description = "The registry ID where the repository was created" 17 | value = module.ecr.repository_registry_id 18 | } 19 | 20 | output "repository_url" { 21 | description = "The URL of the repository (in the form `aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName`)" 22 | value = module.ecr.repository_url 23 | } 24 | 25 | ################################################################################ 26 | # Public Repository 27 | ################################################################################ 28 | 29 | output "public_repository_name" { 30 | description = "Name of the repository" 31 | value = module.public_ecr.repository_name 32 | } 33 | 34 | output "public_repository_arn" { 35 | description = "Full ARN of the repository" 36 | value = module.public_ecr.repository_arn 37 | } 38 | 39 | output "public_repository_registry_id" { 40 | description = "The registry ID where the repository was created" 41 | value = module.public_ecr.repository_registry_id 42 | } 43 | 44 | output "public_repository_url" { 45 | description = "The URL of the repository (in the form `aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName`)" 46 | value = module.public_ecr.repository_url 47 | } 48 | -------------------------------------------------------------------------------- /examples/complete/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ecr/f475c99a68f1f3b0e0bf996d098d94c68570eab8/examples/complete/variables.tf -------------------------------------------------------------------------------- /examples/complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/repository-template/README.md: -------------------------------------------------------------------------------- 1 | # Amazon ECR Repository Template Example 2 | 3 | ## Usage 4 | 5 | To run this example you need to execute: 6 | 7 | ```bash 8 | $ terraform init 9 | $ terraform plan 10 | $ terraform apply 11 | ``` 12 | 13 | You can validate this example by running the commands generated in the `example_docker_pull_commands` output value. 14 | 15 | 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. 16 | 17 | If you validate the example by using the pull-through cache, you will need to manually clean up these repositories within ECR since they are not manage by Terraform. 18 | 19 | 20 | ## Requirements 21 | 22 | | Name | Version | 23 | |------|---------| 24 | | [terraform](#requirement\_terraform) | >= 1.0 | 25 | | [aws](#requirement\_aws) | >= 5.93 | 26 | 27 | ## Providers 28 | 29 | | Name | Version | 30 | |------|---------| 31 | | [aws](#provider\_aws) | >= 5.93 | 32 | 33 | ## Modules 34 | 35 | | Name | Source | Version | 36 | |------|--------|---------| 37 | | [disabled](#module\_disabled) | ../../modules/repository-template | n/a | 38 | | [dockerhub\_pull\_through\_cache\_repository\_template](#module\_dockerhub\_pull\_through\_cache\_repository\_template) | ../../modules/repository-template | n/a | 39 | | [public\_ecr\_pull\_through\_cache\_repository\_template](#module\_public\_ecr\_pull\_through\_cache\_repository\_template) | ../../modules/repository-template | n/a | 40 | | [secrets\_manager\_dockerhub\_credentials](#module\_secrets\_manager\_dockerhub\_credentials) | terraform-aws-modules/secrets-manager/aws | ~> 1.0 | 41 | 42 | ## Resources 43 | 44 | | Name | Type | 45 | |------|------| 46 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 47 | 48 | ## Inputs 49 | 50 | No inputs. 51 | 52 | ## Outputs 53 | 54 | | Name | Description | 55 | |------|-------------| 56 | | [example\_docker\_pull\_commands](#output\_example\_docker\_pull\_commands) | Example docker pull commands to test and validate the example | 57 | | [iam\_role\_arn](#output\_iam\_role\_arn) | IAM role ARN | 58 | | [iam\_role\_name](#output\_iam\_role\_name) | IAM role name | 59 | | [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 60 | 61 | 62 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-ecr/blob/master/LICENSE). 63 | -------------------------------------------------------------------------------- /examples/repository-template/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | locals { 6 | region = "us-east-1" 7 | name = "ecr-ex-${basename(path.cwd)}" 8 | 9 | account_id = data.aws_caller_identity.current.account_id 10 | 11 | tags = { 12 | Name = local.name 13 | Example = local.name 14 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-ecr" 15 | } 16 | } 17 | 18 | data "aws_caller_identity" "current" {} 19 | 20 | ################################################################################ 21 | # ECR Repository Template 22 | ################################################################################ 23 | 24 | module "public_ecr_pull_through_cache_repository_template" { 25 | source = "../../modules/repository-template" 26 | 27 | # Template 28 | description = "Pull through cache repository template for Public ECR artifacts" 29 | prefix = "ecr-public" 30 | resource_tags = local.tags 31 | lifecycle_policy = jsonencode({ 32 | rules = [ 33 | { 34 | rulePriority = 1, 35 | description = "Keep last 30 images", 36 | selection = { 37 | tagStatus = "tagged", 38 | tagPrefixList = ["v"], 39 | countType = "imageCountMoreThan", 40 | countNumber = 30 41 | }, 42 | action = { 43 | type = "expire" 44 | } 45 | } 46 | ] 47 | }) 48 | 49 | # Pull through cache rule 50 | create_pull_through_cache_rule = true 51 | upstream_registry_url = "public.ecr.aws" 52 | 53 | tags = local.tags 54 | } 55 | 56 | module "dockerhub_pull_through_cache_repository_template" { 57 | source = "../../modules/repository-template" 58 | 59 | # Template 60 | description = "Pull through cache repository template for Dockerhub artifacts" 61 | prefix = "docker-hub" 62 | resource_tags = local.tags 63 | 64 | # Pull through cache rule 65 | create_pull_through_cache_rule = true 66 | upstream_registry_url = "registry-1.docker.io" 67 | credential_arn = module.secrets_manager_dockerhub_credentials.secret_arn 68 | 69 | tags = local.tags 70 | } 71 | 72 | module "disabled" { 73 | source = "../../modules/repository-template" 74 | 75 | create = false 76 | } 77 | 78 | ################################################################################ 79 | # Supporting Resources 80 | ################################################################################ 81 | 82 | module "secrets_manager_dockerhub_credentials" { 83 | source = "terraform-aws-modules/secrets-manager/aws" 84 | version = "~> 1.0" 85 | 86 | # Secret names must contain 1-512 Unicode characters and be prefixed with ecr-pullthroughcache/ 87 | name_prefix = "ecr-pullthroughcache/dockerhub-credentials" 88 | description = "Dockerhub credentials" 89 | 90 | # For example only 91 | recovery_window_in_days = 0 92 | secret_string = jsonencode({ 93 | username = "example" 94 | accessToken = "YouShouldNotStoreThisInPlainText" 95 | }) 96 | 97 | # Policy 98 | create_policy = true 99 | block_public_policy = true 100 | policy_statements = { 101 | read = { 102 | sid = "AllowAccountRead" 103 | principals = [{ 104 | type = "AWS" 105 | identifiers = ["arn:aws:iam::${local.account_id}:root"] 106 | }] 107 | actions = ["secretsmanager:GetSecretValue"] 108 | resources = ["*"] 109 | } 110 | } 111 | 112 | tags = local.tags 113 | } 114 | -------------------------------------------------------------------------------- /examples/repository-template/outputs.tf: -------------------------------------------------------------------------------- 1 | output "iam_role_name" { 2 | description = "IAM role name" 3 | value = module.dockerhub_pull_through_cache_repository_template.iam_role_name 4 | } 5 | 6 | output "iam_role_arn" { 7 | description = "IAM role ARN" 8 | value = module.dockerhub_pull_through_cache_repository_template.iam_role_arn 9 | } 10 | 11 | output "iam_role_unique_id" { 12 | description = "Stable and unique string identifying the IAM role" 13 | value = module.public_ecr_pull_through_cache_repository_template.iam_role_unique_id 14 | } 15 | 16 | output "example_docker_pull_commands" { 17 | description = "Example docker pull commands to test and validate the example" 18 | value = <<-EOT 19 | # Ensure your local CLI is authenticated with ECR 20 | aws ecr get-login-password --region ${local.region} | docker login --username AWS --password-stdin ${local.account_id}.dkr.ecr.${local.region}.amazonaws.com 21 | 22 | # Dockerhub pull through cache and repo creation 23 | docker pull ${local.account_id}.dkr.ecr.${local.region}.amazonaws.com/docker-hub/library/nginx:latest 24 | 25 | # Public ECR pull through cache and repo creation 26 | docker pull ${local.account_id}.dkr.ecr.${local.region}.amazonaws.com/ecr-public/docker/library/nginx:latest 27 | EOT 28 | } 29 | -------------------------------------------------------------------------------- /examples/repository-template/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ecr/f475c99a68f1f3b0e0bf996d098d94c68570eab8/examples/repository-template/variables.tf -------------------------------------------------------------------------------- /examples/repository-template/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | create_private_repository = var.create && var.create_repository && var.repository_type == "private" 3 | create_public_repository = var.create && var.create_repository && var.repository_type == "public" 4 | } 5 | 6 | data "aws_caller_identity" "current" {} 7 | data "aws_partition" "current" {} 8 | 9 | # Policy used by both private and public repositories 10 | data "aws_iam_policy_document" "repository" { 11 | count = var.create && var.create_repository && var.create_repository_policy ? 1 : 0 12 | 13 | dynamic "statement" { 14 | for_each = var.repository_type == "public" ? [1] : [] 15 | 16 | content { 17 | sid = "PublicReadOnly" 18 | 19 | principals { 20 | type = "AWS" 21 | identifiers = coalescelist( 22 | var.repository_read_access_arns, 23 | ["*"], 24 | ) 25 | } 26 | 27 | actions = [ 28 | "ecr-public:BatchGetImage", 29 | "ecr-public:GetDownloadUrlForLayer", 30 | ] 31 | } 32 | } 33 | 34 | dynamic "statement" { 35 | for_each = var.repository_type == "private" ? [1] : [] 36 | 37 | content { 38 | sid = "PrivateReadOnly" 39 | 40 | principals { 41 | type = "AWS" 42 | identifiers = coalescelist( 43 | concat(var.repository_read_access_arns, var.repository_read_write_access_arns), 44 | ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"], 45 | ) 46 | } 47 | 48 | actions = [ 49 | "ecr:GetAuthorizationToken", 50 | "ecr:BatchCheckLayerAvailability", 51 | "ecr:BatchGetImage", 52 | "ecr:DescribeImageScanFindings", 53 | "ecr:DescribeImages", 54 | "ecr:DescribeRepositories", 55 | "ecr:GetDownloadUrlForLayer", 56 | "ecr:GetLifecyclePolicy", 57 | "ecr:GetLifecyclePolicyPreview", 58 | "ecr:GetRepositoryPolicy", 59 | "ecr:ListImages", 60 | "ecr:ListTagsForResource", 61 | ] 62 | } 63 | } 64 | 65 | dynamic "statement" { 66 | for_each = var.repository_type == "private" && length(var.repository_lambda_read_access_arns) > 0 ? [1] : [] 67 | 68 | content { 69 | sid = "PrivateLambdaReadOnly" 70 | 71 | principals { 72 | type = "Service" 73 | identifiers = ["lambda.amazonaws.com"] 74 | } 75 | 76 | actions = [ 77 | "ecr:BatchGetImage", 78 | "ecr:GetDownloadUrlForLayer", 79 | ] 80 | 81 | condition { 82 | test = "StringLike" 83 | variable = "aws:sourceArn" 84 | 85 | values = var.repository_lambda_read_access_arns 86 | } 87 | } 88 | } 89 | 90 | dynamic "statement" { 91 | for_each = length(var.repository_read_write_access_arns) > 0 && var.repository_type == "private" ? [var.repository_read_write_access_arns] : [] 92 | 93 | content { 94 | sid = "ReadWrite" 95 | 96 | principals { 97 | type = "AWS" 98 | identifiers = statement.value 99 | } 100 | 101 | actions = [ 102 | "ecr:PutImage", 103 | "ecr:InitiateLayerUpload", 104 | "ecr:UploadLayerPart", 105 | "ecr:CompleteLayerUpload", 106 | ] 107 | } 108 | } 109 | 110 | dynamic "statement" { 111 | for_each = length(var.repository_read_write_access_arns) > 0 && var.repository_type == "public" ? [var.repository_read_write_access_arns] : [] 112 | 113 | content { 114 | sid = "ReadWrite" 115 | 116 | principals { 117 | type = "AWS" 118 | identifiers = statement.value 119 | } 120 | 121 | actions = [ 122 | "ecr-public:BatchCheckLayerAvailability", 123 | "ecr-public:CompleteLayerUpload", 124 | "ecr-public:InitiateLayerUpload", 125 | "ecr-public:PutImage", 126 | "ecr-public:UploadLayerPart", 127 | ] 128 | } 129 | } 130 | 131 | dynamic "statement" { 132 | for_each = var.repository_policy_statements 133 | 134 | content { 135 | sid = try(statement.value.sid, null) 136 | actions = try(statement.value.actions, null) 137 | not_actions = try(statement.value.not_actions, null) 138 | effect = try(statement.value.effect, null) 139 | resources = try(statement.value.resources, null) 140 | not_resources = try(statement.value.not_resources, null) 141 | 142 | dynamic "principals" { 143 | for_each = try(statement.value.principals, []) 144 | 145 | content { 146 | type = principals.value.type 147 | identifiers = principals.value.identifiers 148 | } 149 | } 150 | 151 | dynamic "not_principals" { 152 | for_each = try(statement.value.not_principals, []) 153 | 154 | content { 155 | type = not_principals.value.type 156 | identifiers = not_principals.value.identifiers 157 | } 158 | } 159 | 160 | dynamic "condition" { 161 | for_each = try(statement.value.conditions, []) 162 | 163 | content { 164 | test = condition.value.test 165 | values = condition.value.values 166 | variable = condition.value.variable 167 | } 168 | } 169 | } 170 | } 171 | } 172 | 173 | ################################################################################ 174 | # Repository 175 | ################################################################################ 176 | 177 | resource "aws_ecr_repository" "this" { 178 | count = local.create_private_repository ? 1 : 0 179 | 180 | name = var.repository_name 181 | image_tag_mutability = var.repository_image_tag_mutability 182 | 183 | encryption_configuration { 184 | encryption_type = var.repository_encryption_type 185 | kms_key = var.repository_kms_key 186 | } 187 | 188 | force_delete = var.repository_force_delete 189 | 190 | image_scanning_configuration { 191 | scan_on_push = var.repository_image_scan_on_push 192 | } 193 | 194 | tags = var.tags 195 | } 196 | 197 | ################################################################################ 198 | # Repository Policy 199 | ################################################################################ 200 | 201 | resource "aws_ecr_repository_policy" "this" { 202 | count = local.create_private_repository && var.attach_repository_policy ? 1 : 0 203 | 204 | repository = aws_ecr_repository.this[0].name 205 | policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy 206 | } 207 | 208 | ################################################################################ 209 | # Lifecycle Policy 210 | ################################################################################ 211 | 212 | resource "aws_ecr_lifecycle_policy" "this" { 213 | count = local.create_private_repository && var.create_lifecycle_policy ? 1 : 0 214 | 215 | repository = aws_ecr_repository.this[0].name 216 | policy = var.repository_lifecycle_policy 217 | } 218 | 219 | ################################################################################ 220 | # Public Repository 221 | ################################################################################ 222 | 223 | resource "aws_ecrpublic_repository" "this" { 224 | count = local.create_public_repository ? 1 : 0 225 | 226 | repository_name = var.repository_name 227 | 228 | dynamic "catalog_data" { 229 | for_each = length(var.public_repository_catalog_data) > 0 ? [var.public_repository_catalog_data] : [] 230 | 231 | content { 232 | about_text = try(catalog_data.value.about_text, null) 233 | architectures = try(catalog_data.value.architectures, null) 234 | description = try(catalog_data.value.description, null) 235 | logo_image_blob = try(catalog_data.value.logo_image_blob, null) 236 | operating_systems = try(catalog_data.value.operating_systems, null) 237 | usage_text = try(catalog_data.value.usage_text, null) 238 | } 239 | } 240 | 241 | tags = var.tags 242 | } 243 | 244 | ################################################################################ 245 | # Public Repository Policy 246 | ################################################################################ 247 | 248 | resource "aws_ecrpublic_repository_policy" "example" { 249 | count = local.create_public_repository ? 1 : 0 250 | 251 | repository_name = aws_ecrpublic_repository.this[0].repository_name 252 | policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy 253 | } 254 | 255 | ################################################################################ 256 | # Registry Policy 257 | ################################################################################ 258 | 259 | resource "aws_ecr_registry_policy" "this" { 260 | count = var.create && var.create_registry_policy ? 1 : 0 261 | 262 | policy = var.registry_policy 263 | } 264 | 265 | ################################################################################ 266 | # Registry Pull Through Cache Rule 267 | ################################################################################ 268 | 269 | resource "aws_ecr_pull_through_cache_rule" "this" { 270 | for_each = { for k, v in var.registry_pull_through_cache_rules : k => v if var.create } 271 | 272 | ecr_repository_prefix = each.value.ecr_repository_prefix 273 | upstream_registry_url = each.value.upstream_registry_url 274 | credential_arn = try(each.value.credential_arn, null) 275 | custom_role_arn = try(each.value.custom_role_arn, null) 276 | upstream_repository_prefix = try(each.value.upstream_repository_prefix, null) 277 | } 278 | 279 | ################################################################################ 280 | # Registry Scanning Configuration 281 | ################################################################################ 282 | 283 | resource "aws_ecr_registry_scanning_configuration" "this" { 284 | count = var.create && var.manage_registry_scanning_configuration ? 1 : 0 285 | 286 | scan_type = var.registry_scan_type 287 | 288 | dynamic "rule" { 289 | for_each = var.registry_scan_rules 290 | 291 | content { 292 | scan_frequency = rule.value.scan_frequency 293 | 294 | dynamic "repository_filter" { 295 | for_each = rule.value.filter 296 | 297 | content { 298 | filter = repository_filter.value.filter 299 | filter_type = try(repository_filter.value.filter_type, "WILDCARD") 300 | } 301 | } 302 | } 303 | } 304 | } 305 | 306 | ################################################################################ 307 | # Registry Replication Configuration 308 | ################################################################################ 309 | 310 | resource "aws_ecr_replication_configuration" "this" { 311 | count = var.create && var.create_registry_replication_configuration ? 1 : 0 312 | 313 | replication_configuration { 314 | 315 | dynamic "rule" { 316 | for_each = var.registry_replication_rules 317 | 318 | content { 319 | dynamic "destination" { 320 | for_each = rule.value.destinations 321 | 322 | content { 323 | region = destination.value.region 324 | registry_id = destination.value.registry_id 325 | } 326 | } 327 | 328 | dynamic "repository_filter" { 329 | for_each = try(rule.value.repository_filters, []) 330 | 331 | content { 332 | filter = repository_filter.value.filter 333 | filter_type = repository_filter.value.filter_type 334 | } 335 | } 336 | } 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /modules/repository-template/README.md: -------------------------------------------------------------------------------- 1 | # Amazon ECR Repository Template Terraform module 2 | 3 | Terraform module which creates Amazon ECR repository template resources. 4 | 5 | ## Usage 6 | 7 | See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples) directory for working examples to reference: 8 | 9 | ### Pull Through Cache Rule 10 | 11 | #### Public ECR 12 | 13 | ```hcl 14 | module "ecr-repository-template" { 15 | source = "terraform-aws-modules/ecr/aws//modules/repository-template" 16 | 17 | # Template 18 | description = "Pull through cache repository template for Karpenter public ECR artifacts" 19 | prefix = "ecr-public" 20 | create_repository_policy = true 21 | 22 | # Pull through cache rule 23 | upstream_registry_url = "public.ecr.aws" 24 | 25 | tags = { 26 | Terraform = "true" 27 | Environment = "dev" 28 | } 29 | } 30 | ``` 31 | 32 | #### Private Registry 33 | 34 | ```hcl 35 | module "ecr-repository-template" { 36 | source = "terraform-aws-modules/ecr/aws//modules/repository-template" 37 | 38 | # Template 39 | description = "Pull through cache repository template for NGINX Dockerhub artifacts" 40 | prefix = "docker-hub" 41 | 42 | # Pull through cache rule 43 | upstream_registry_url = "registry-1.docker.io" 44 | credential_arn = aws_secretsmanager_secret.ecr_pull_through_cache.arn 45 | 46 | tags = { 47 | Terraform = "true" 48 | Environment = "dev" 49 | } 50 | } 51 | ``` 52 | 53 | ### Replication 54 | 55 | ```hcl 56 | module "ecr" { 57 | source = "terraform-aws-modules/ecr/aws//modules/repository-template" 58 | 59 | # Template 60 | description = "Replication repository template for production ECR artifacts" 61 | prefix = "prod" 62 | create_repository_policy = true 63 | lifecycle_policy = jsonencode({ 64 | rules = [ 65 | { 66 | rulePriority = 1, 67 | description = "Keep last 30 images", 68 | selection = { 69 | tagStatus = "tagged", 70 | tagPrefixList = ["v"], 71 | countType = "imageCountMoreThan", 72 | countNumber = 30 73 | }, 74 | action = { 75 | type = "expire" 76 | } 77 | } 78 | ] 79 | }) 80 | 81 | tags = { 82 | Terraform = "true" 83 | Environment = "dev" 84 | } 85 | } 86 | ``` 87 | 88 | ## Examples 89 | 90 | Examples codified under the [`examples`](https://github.com/terraform-aws-modules/terraform-aws-ecr/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! 91 | 92 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/complete) 93 | - [Repository Template](https://github.com/terraform-aws-modules/terraform-aws-ecr/tree/master/examples/repository-template) 94 | 95 | 96 | ## Requirements 97 | 98 | | Name | Version | 99 | |------|---------| 100 | | [terraform](#requirement\_terraform) | >= 1.0 | 101 | | [aws](#requirement\_aws) | >= 5.93 | 102 | 103 | ## Providers 104 | 105 | | Name | Version | 106 | |------|---------| 107 | | [aws](#provider\_aws) | >= 5.93 | 108 | 109 | ## Modules 110 | 111 | No modules. 112 | 113 | ## Resources 114 | 115 | | Name | Type | 116 | |------|------| 117 | | [aws_ecr_pull_through_cache_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_pull_through_cache_rule) | resource | 118 | | [aws_ecr_repository_creation_template.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_creation_template) | resource | 119 | | [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | 120 | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 121 | | [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 122 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 123 | | [aws_iam_policy_document.assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 124 | | [aws_iam_policy_document.repository](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 125 | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 126 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | 127 | 128 | ## Inputs 129 | 130 | | Name | Description | Type | Default | Required | 131 | |------|-------------|------|---------|:--------:| 132 | | [applied\_for](#input\_applied\_for) | Which features this template applies to. Must contain one or more of `PULL_THROUGH_CACHE` or `REPLICATION`. Defaults to `PULL_THROUGH_CACHE` | `list(string)` |
[
"PULL_THROUGH_CACHE"
]
| no | 133 | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | 134 | | [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECR service IAM role should be created | `bool` | `true` | no | 135 | | [create\_pull\_through\_cache\_rule](#input\_create\_pull\_through\_cache\_rule) | Determines whether a pull through cache rule will be created | `bool` | `false` | no | 136 | | [create\_repository\_policy](#input\_create\_repository\_policy) | Determines whether a repository policy will be created | `bool` | `true` | no | 137 | | [credential\_arn](#input\_credential\_arn) | ARN of the Secret which will be used to authenticate against the registry to use for the pull through cache rule | `string` | `null` | no | 138 | | [custom\_role\_arn](#input\_custom\_role\_arn) | A custom IAM role to use for repository creation. Required if using repository tags or KMS encryption | `string` | `null` | no | 139 | | [description](#input\_description) | The description for this template | `string` | `null` | no | 140 | | [encryption\_type](#input\_encryption\_type) | The type of encryption to use for any created repositories. Must be one of: `AES256` or `KMS`. Defaults to `AES256` | `string` | `"AES256"` | no | 141 | | [iam\_role\_description](#input\_iam\_role\_description) | Description of the role | `string` | `null` | no | 142 | | [iam\_role\_name](#input\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | 143 | | [iam\_role\_path](#input\_iam\_role\_path) | IAM role path | `string` | `null` | no | 144 | | [iam\_role\_permissions\_boundary](#input\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | 145 | | [iam\_role\_tags](#input\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | 146 | | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | 147 | | [image\_tag\_mutability](#input\_image\_tag\_mutability) | The tag mutability setting for any created repositories. Must be one of: `MUTABLE` or `IMMUTABLE`. Defaults to `IMMUTABLE` | `string` | `"IMMUTABLE"` | no | 148 | | [kms\_key\_arn](#input\_kms\_key\_arn) | The ARN of the KMS key used to encrypt the repositories created | `string` | `null` | no | 149 | | [lifecycle\_policy](#input\_lifecycle\_policy) | The lifecycle policy document to apply to any created repositories | `string` | `null` | no | 150 | | [prefix](#input\_prefix) | (Required) The repository name prefix to match against. Use `ROOT` to match any prefix that doesn't explicitly match another template | `string` | `""` | no | 151 | | [repository\_lambda\_read\_access\_arns](#input\_repository\_lambda\_read\_access\_arns) | The ARNs of the Lambda service roles that have read access to the repository | `list(string)` | `[]` | no | 152 | | [repository\_policy](#input\_repository\_policy) | The JSON policy to apply to the repository. If not specified, uses the default policy | `string` | `null` | no | 153 | | [repository\_policy\_statements](#input\_repository\_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 | 154 | | [repository\_read\_access\_arns](#input\_repository\_read\_access\_arns) | The ARNs of the IAM users/roles that have read access to the repository | `list(string)` | `[]` | no | 155 | | [repository\_read\_write\_access\_arns](#input\_repository\_read\_write\_access\_arns) | The ARNs of the IAM users/roles that have read/write access to the repository | `list(string)` | `[]` | no | 156 | | [resource\_tags](#input\_resource\_tags) | A map of tags to assign to any created repositories | `map(string)` | `{}` | no | 157 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | 158 | | [upstream\_registry\_url](#input\_upstream\_registry\_url) | The registry URL of the upstream public registry to use as the source for the pull through cache rule | `string` | `null` | no | 159 | 160 | ## Outputs 161 | 162 | | Name | Description | 163 | |------|-------------| 164 | | [iam\_role\_arn](#output\_iam\_role\_arn) | IAM role ARN | 165 | | [iam\_role\_name](#output\_iam\_role\_name) | IAM role name | 166 | | [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 167 | 168 | 169 | ## License 170 | 171 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-ecr/blob/master/LICENSE). 172 | -------------------------------------------------------------------------------- /modules/repository-template/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" { 2 | count = var.create ? 1 : 0 3 | } 4 | 5 | data "aws_partition" "current" { 6 | count = var.create ? 1 : 0 7 | } 8 | 9 | ################################################################################ 10 | # Repository Template 11 | ################################################################################ 12 | 13 | locals { 14 | kms_encrypt = var.encryption_type == "KMS" 15 | } 16 | 17 | resource "aws_ecr_repository_creation_template" "this" { 18 | count = var.create ? 1 : 0 19 | 20 | applied_for = var.applied_for 21 | custom_role_arn = local.create_iam_role ? aws_iam_role.this[0].arn : var.custom_role_arn 22 | description = var.description 23 | 24 | dynamic "encryption_configuration" { 25 | for_each = var.encryption_type != null ? [1] : [] 26 | 27 | content { 28 | encryption_type = var.encryption_type 29 | kms_key = local.kms_encrypt ? var.kms_key_arn : null 30 | } 31 | } 32 | 33 | image_tag_mutability = var.image_tag_mutability 34 | lifecycle_policy = var.lifecycle_policy 35 | prefix = var.prefix 36 | repository_policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy 37 | 38 | resource_tags = var.resource_tags 39 | } 40 | 41 | ################################################################################ 42 | # Repository Policy Document 43 | ################################################################################ 44 | 45 | data "aws_iam_policy_document" "repository" { 46 | count = var.create && var.create_repository_policy ? 1 : 0 47 | 48 | statement { 49 | sid = "PrivateReadOnly" 50 | 51 | principals { 52 | type = "AWS" 53 | identifiers = coalescelist( 54 | concat(var.repository_read_access_arns, var.repository_read_write_access_arns), 55 | ["arn:${data.aws_partition.current[0].partition}:iam::${data.aws_caller_identity.current[0].account_id}:root"], 56 | ) 57 | } 58 | 59 | actions = [ 60 | "ecr:GetAuthorizationToken", 61 | "ecr:BatchCheckLayerAvailability", 62 | "ecr:BatchGetImage", 63 | "ecr:DescribeImageScanFindings", 64 | "ecr:DescribeImages", 65 | "ecr:DescribeRepositories", 66 | "ecr:GetDownloadUrlForLayer", 67 | "ecr:GetLifecyclePolicy", 68 | "ecr:GetLifecyclePolicyPreview", 69 | "ecr:GetRepositoryPolicy", 70 | "ecr:ListImages", 71 | "ecr:ListTagsForResource", 72 | ] 73 | } 74 | 75 | dynamic "statement" { 76 | for_each = length(var.repository_lambda_read_access_arns) > 0 ? [1] : [] 77 | 78 | content { 79 | sid = "PrivateLambdaReadOnly" 80 | 81 | principals { 82 | type = "Service" 83 | identifiers = ["lambda.amazonaws.com"] 84 | } 85 | 86 | actions = [ 87 | "ecr:BatchGetImage", 88 | "ecr:GetDownloadUrlForLayer", 89 | ] 90 | 91 | condition { 92 | test = "StringLike" 93 | variable = "aws:sourceArn" 94 | 95 | values = var.repository_lambda_read_access_arns 96 | } 97 | } 98 | } 99 | 100 | dynamic "statement" { 101 | for_each = length(var.repository_read_write_access_arns) > 0 ? [var.repository_read_write_access_arns] : [] 102 | 103 | content { 104 | sid = "ReadWrite" 105 | 106 | principals { 107 | type = "AWS" 108 | identifiers = statement.value 109 | } 110 | 111 | actions = [ 112 | "ecr:PutImage", 113 | "ecr:InitiateLayerUpload", 114 | "ecr:UploadLayerPart", 115 | "ecr:CompleteLayerUpload", 116 | ] 117 | } 118 | } 119 | 120 | dynamic "statement" { 121 | for_each = var.repository_policy_statements 122 | 123 | content { 124 | sid = try(statement.value.sid, null) 125 | actions = try(statement.value.actions, null) 126 | not_actions = try(statement.value.not_actions, null) 127 | effect = try(statement.value.effect, null) 128 | resources = try(statement.value.resources, null) 129 | not_resources = try(statement.value.not_resources, null) 130 | 131 | dynamic "principals" { 132 | for_each = try(statement.value.principals, []) 133 | 134 | content { 135 | type = principals.value.type 136 | identifiers = principals.value.identifiers 137 | } 138 | } 139 | 140 | dynamic "not_principals" { 141 | for_each = try(statement.value.not_principals, []) 142 | 143 | content { 144 | type = not_principals.value.type 145 | identifiers = not_principals.value.identifiers 146 | } 147 | } 148 | 149 | dynamic "condition" { 150 | for_each = try(statement.value.conditions, []) 151 | 152 | content { 153 | test = condition.value.test 154 | values = condition.value.values 155 | variable = condition.value.variable 156 | } 157 | } 158 | } 159 | } 160 | } 161 | 162 | ################################################################################ 163 | # Registry Pull Through Cache Rule 164 | ################################################################################ 165 | 166 | resource "aws_ecr_pull_through_cache_rule" "this" { 167 | count = var.create && var.create_pull_through_cache_rule ? 1 : 0 168 | 169 | credential_arn = var.credential_arn 170 | ecr_repository_prefix = var.prefix 171 | upstream_registry_url = var.upstream_registry_url 172 | } 173 | 174 | ################################################################################ 175 | # IAM Role 176 | ################################################################################ 177 | 178 | locals { 179 | create_iam_role = var.create && var.create_iam_role && (local.kms_encrypt || length(var.resource_tags) > 0) 180 | iam_role_name = try(coalesce(var.iam_role_name, var.prefix), "") 181 | 182 | perm_prefix = var.prefix != "ROOT" ? "${var.prefix}/*" : "*" 183 | } 184 | 185 | data "aws_iam_policy_document" "assume" { 186 | count = local.create_iam_role ? 1 : 0 187 | 188 | statement { 189 | sid = "ECRServiceAssumeRole" 190 | actions = ["sts:AssumeRole"] 191 | 192 | principals { 193 | type = "Service" 194 | identifiers = ["ecr.amazonaws.com"] 195 | } 196 | } 197 | } 198 | 199 | resource "aws_iam_role" "this" { 200 | count = local.create_iam_role ? 1 : 0 201 | 202 | name = var.iam_role_use_name_prefix ? null : local.iam_role_name 203 | name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null 204 | path = var.iam_role_path 205 | description = var.iam_role_description 206 | 207 | assume_role_policy = data.aws_iam_policy_document.assume[0].json 208 | permissions_boundary = var.iam_role_permissions_boundary 209 | force_detach_policies = true 210 | 211 | tags = merge(var.tags, var.iam_role_tags) 212 | } 213 | 214 | data "aws_iam_policy_document" "this" { 215 | count = local.create_iam_role ? 1 : 0 216 | 217 | statement { 218 | sid = "TagResource" 219 | actions = [ 220 | "ecr:CreateRepository", 221 | "ecr:ReplicateImage", 222 | "ecr:TagResource" 223 | ] 224 | resources = [ 225 | "arn:${data.aws_partition.current[0].partition}:ecr:*:${data.aws_caller_identity.current[0].account_id}:repository/${local.perm_prefix}" 226 | ] 227 | } 228 | 229 | dynamic "statement" { 230 | for_each = local.kms_encrypt ? [1] : [] 231 | 232 | content { 233 | sid = "KMSUsage" 234 | actions = [ 235 | "kms:CreateGrant", 236 | "kms:RetireGrant", 237 | "kms:DescribeKey", 238 | ] 239 | resources = [var.kms_key_arn] 240 | } 241 | } 242 | } 243 | 244 | resource "aws_iam_policy" "this" { 245 | count = local.create_iam_role ? 1 : 0 246 | 247 | name = var.iam_role_use_name_prefix ? null : local.iam_role_name 248 | name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null 249 | description = coalesce(var.iam_role_description, "ECR service policy that allows Amazon ECR to make calls to tag resources and use KMS encryption key(s) on your behalf") 250 | policy = data.aws_iam_policy_document.this[0].json 251 | 252 | tags = merge(var.tags, var.iam_role_tags) 253 | } 254 | 255 | resource "aws_iam_role_policy_attachment" "this" { 256 | count = local.create_iam_role ? 1 : 0 257 | 258 | role = aws_iam_role.this[0].name 259 | policy_arn = aws_iam_policy.this[0].arn 260 | } 261 | -------------------------------------------------------------------------------- /modules/repository-template/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # IAM Role 3 | ################################################################################ 4 | 5 | output "iam_role_name" { 6 | description = "IAM role name" 7 | value = try(aws_iam_role.this[0].name, null) 8 | } 9 | 10 | output "iam_role_arn" { 11 | description = "IAM role ARN" 12 | value = try(aws_iam_role.this[0].arn, var.custom_role_arn) 13 | } 14 | 15 | output "iam_role_unique_id" { 16 | description = "Stable and unique string identifying the IAM role" 17 | value = try(aws_iam_role.this[0].unique_id, null) 18 | } 19 | -------------------------------------------------------------------------------- /modules/repository-template/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 | # Repository Template 15 | ################################################################################ 16 | 17 | variable "applied_for" { 18 | description = "Which features this template applies to. Must contain one or more of `PULL_THROUGH_CACHE` or `REPLICATION`. Defaults to `PULL_THROUGH_CACHE`" 19 | type = list(string) 20 | default = ["PULL_THROUGH_CACHE"] 21 | } 22 | 23 | variable "custom_role_arn" { 24 | description = "A custom IAM role to use for repository creation. Required if using repository tags or KMS encryption" 25 | type = string 26 | default = null 27 | } 28 | 29 | variable "description" { 30 | description = "The description for this template" 31 | type = string 32 | default = null 33 | } 34 | 35 | variable "encryption_type" { 36 | description = "The type of encryption to use for any created repositories. Must be one of: `AES256` or `KMS`. Defaults to `AES256`" 37 | type = string 38 | default = "AES256" 39 | } 40 | 41 | variable "kms_key_arn" { 42 | description = "The ARN of the KMS key used to encrypt the repositories created" 43 | type = string 44 | default = null 45 | } 46 | 47 | variable "image_tag_mutability" { 48 | description = "The tag mutability setting for any created repositories. Must be one of: `MUTABLE` or `IMMUTABLE`. Defaults to `IMMUTABLE`" 49 | type = string 50 | default = "IMMUTABLE" 51 | } 52 | 53 | variable "lifecycle_policy" { 54 | description = "The lifecycle policy document to apply to any created repositories" 55 | type = string 56 | default = null 57 | } 58 | 59 | variable "prefix" { 60 | description = "(Required) The repository name prefix to match against. Use `ROOT` to match any prefix that doesn't explicitly match another template" 61 | type = string 62 | default = "" 63 | } 64 | 65 | variable "repository_policy" { 66 | description = "The JSON policy to apply to the repository. If not specified, uses the default policy" 67 | type = string 68 | default = null 69 | } 70 | 71 | variable "resource_tags" { 72 | description = "A map of tags to assign to any created repositories" 73 | type = map(string) 74 | default = {} 75 | } 76 | 77 | ################################################################################ 78 | # Registry Pull Through Cache Rule 79 | ################################################################################ 80 | 81 | variable "create_pull_through_cache_rule" { 82 | description = "Determines whether a pull through cache rule will be created" 83 | type = bool 84 | default = false 85 | } 86 | 87 | variable "credential_arn" { 88 | description = "ARN of the Secret which will be used to authenticate against the registry to use for the pull through cache rule" 89 | type = string 90 | default = null 91 | } 92 | 93 | variable "upstream_registry_url" { 94 | description = "The registry URL of the upstream public registry to use as the source for the pull through cache rule" 95 | type = string 96 | default = null 97 | } 98 | 99 | ################################################################################ 100 | # Repository Policy 101 | ################################################################################ 102 | 103 | variable "create_repository_policy" { 104 | description = "Determines whether a repository policy will be created" 105 | type = bool 106 | default = true 107 | } 108 | 109 | variable "repository_read_access_arns" { 110 | description = "The ARNs of the IAM users/roles that have read access to the repository" 111 | type = list(string) 112 | default = [] 113 | } 114 | 115 | variable "repository_lambda_read_access_arns" { 116 | description = "The ARNs of the Lambda service roles that have read access to the repository" 117 | type = list(string) 118 | default = [] 119 | } 120 | 121 | variable "repository_read_write_access_arns" { 122 | description = "The ARNs of the IAM users/roles that have read/write access to the repository" 123 | type = list(string) 124 | default = [] 125 | } 126 | 127 | variable "repository_policy_statements" { 128 | 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" 129 | type = any 130 | default = {} 131 | } 132 | 133 | ################################################################################ 134 | # IAM Role 135 | ################################################################################ 136 | 137 | variable "create_iam_role" { 138 | description = "Determines whether the ECR service IAM role should be created" 139 | type = bool 140 | default = true 141 | } 142 | 143 | variable "iam_role_name" { 144 | description = "Name to use on IAM role created" 145 | type = string 146 | default = null 147 | } 148 | 149 | variable "iam_role_use_name_prefix" { 150 | description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix" 151 | type = bool 152 | default = true 153 | } 154 | 155 | variable "iam_role_path" { 156 | description = "IAM role path" 157 | type = string 158 | default = null 159 | } 160 | 161 | variable "iam_role_description" { 162 | description = "Description of the role" 163 | type = string 164 | default = null 165 | } 166 | 167 | variable "iam_role_permissions_boundary" { 168 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role" 169 | type = string 170 | default = null 171 | } 172 | 173 | variable "iam_role_tags" { 174 | description = "A map of additional tags to add to the IAM role created" 175 | type = map(string) 176 | default = {} 177 | } 178 | -------------------------------------------------------------------------------- /modules/repository-template/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Repository (Public and Private) 3 | ################################################################################ 4 | 5 | output "repository_name" { 6 | description = "Name of the repository" 7 | value = try(aws_ecr_repository.this[0].name, aws_ecrpublic_repository.this[0].id, null) 8 | } 9 | 10 | output "repository_arn" { 11 | description = "Full ARN of the repository" 12 | value = try(aws_ecr_repository.this[0].arn, aws_ecrpublic_repository.this[0].arn, null) 13 | } 14 | 15 | output "repository_registry_id" { 16 | description = "The registry ID where the repository was created" 17 | value = try(aws_ecr_repository.this[0].registry_id, aws_ecrpublic_repository.this[0].registry_id, null) 18 | } 19 | 20 | output "repository_url" { 21 | description = "The URL of the repository" 22 | value = try(aws_ecr_repository.this[0].repository_url, aws_ecrpublic_repository.this[0].repository_uri, null) 23 | } 24 | -------------------------------------------------------------------------------- /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 | variable "repository_type" { 14 | description = "The type of repository to create. Either `public` or `private`" 15 | type = string 16 | default = "private" 17 | } 18 | 19 | ################################################################################ 20 | # Repository 21 | ################################################################################ 22 | 23 | variable "create_repository" { 24 | description = "Determines whether a repository will be created" 25 | type = bool 26 | default = true 27 | } 28 | 29 | variable "repository_name" { 30 | description = "The name of the repository" 31 | type = string 32 | default = "" 33 | } 34 | 35 | variable "repository_image_tag_mutability" { 36 | description = "The tag mutability setting for the repository. Must be one of: `MUTABLE` or `IMMUTABLE`. Defaults to `IMMUTABLE`" 37 | type = string 38 | default = "IMMUTABLE" 39 | } 40 | 41 | variable "repository_encryption_type" { 42 | description = "The encryption type for the repository. Must be one of: `KMS` or `AES256`. Defaults to `AES256`" 43 | type = string 44 | default = null 45 | } 46 | 47 | variable "repository_kms_key" { 48 | description = "The ARN of the KMS key to use when encryption_type is `KMS`. If not specified, uses the default AWS managed key for ECR" 49 | type = string 50 | default = null 51 | } 52 | 53 | variable "repository_image_scan_on_push" { 54 | description = "Indicates whether images are scanned after being pushed to the repository (`true`) or not scanned (`false`)" 55 | type = bool 56 | default = true 57 | } 58 | 59 | variable "repository_policy" { 60 | description = "The JSON policy to apply to the repository. If not specified, uses the default policy" 61 | type = string 62 | default = null 63 | } 64 | 65 | variable "repository_force_delete" { 66 | description = "If `true`, will delete the repository even if it contains images. Defaults to `false`" 67 | type = bool 68 | default = null 69 | } 70 | 71 | ################################################################################ 72 | # Repository Policy 73 | ################################################################################ 74 | 75 | variable "attach_repository_policy" { 76 | description = "Determines whether a repository policy will be attached to the repository" 77 | type = bool 78 | default = true 79 | } 80 | 81 | variable "create_repository_policy" { 82 | description = "Determines whether a repository policy will be created" 83 | type = bool 84 | default = true 85 | } 86 | 87 | variable "repository_read_access_arns" { 88 | description = "The ARNs of the IAM users/roles that have read access to the repository" 89 | type = list(string) 90 | default = [] 91 | } 92 | 93 | variable "repository_lambda_read_access_arns" { 94 | description = "The ARNs of the Lambda service roles that have read access to the repository" 95 | type = list(string) 96 | default = [] 97 | } 98 | 99 | variable "repository_read_write_access_arns" { 100 | description = "The ARNs of the IAM users/roles that have read/write access to the repository" 101 | type = list(string) 102 | default = [] 103 | } 104 | 105 | variable "repository_policy_statements" { 106 | 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" 107 | type = any 108 | default = {} 109 | } 110 | 111 | ################################################################################ 112 | # Lifecycle Policy 113 | ################################################################################ 114 | 115 | variable "create_lifecycle_policy" { 116 | description = "Determines whether a lifecycle policy will be created" 117 | type = bool 118 | default = true 119 | } 120 | 121 | variable "repository_lifecycle_policy" { 122 | description = "The policy document. This is a JSON formatted string. See more details about [Policy Parameters](http://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lifecycle_policy_parameters) in the official AWS docs" 123 | type = string 124 | default = "" 125 | } 126 | 127 | ################################################################################ 128 | # Public Repository 129 | ################################################################################ 130 | 131 | variable "public_repository_catalog_data" { 132 | description = "Catalog data configuration for the repository" 133 | type = any 134 | default = {} 135 | } 136 | 137 | ################################################################################ 138 | # Registry Policy 139 | ################################################################################ 140 | 141 | variable "create_registry_policy" { 142 | description = "Determines whether a registry policy will be created" 143 | type = bool 144 | default = false 145 | } 146 | 147 | variable "registry_policy" { 148 | description = "The policy document. This is a JSON formatted string" 149 | type = string 150 | default = null 151 | } 152 | 153 | ################################################################################ 154 | # Registry Pull Through Cache Rule 155 | ################################################################################ 156 | 157 | variable "registry_pull_through_cache_rules" { 158 | description = "List of pull through cache rules to create" 159 | type = map(map(string)) 160 | default = {} 161 | } 162 | 163 | ################################################################################ 164 | # Registry Scanning Configuration 165 | ################################################################################ 166 | 167 | variable "manage_registry_scanning_configuration" { 168 | description = "Determines whether the registry scanning configuration will be managed" 169 | type = bool 170 | default = false 171 | } 172 | 173 | variable "registry_scan_type" { 174 | description = "the scanning type to set for the registry. Can be either `ENHANCED` or `BASIC`" 175 | type = string 176 | default = "ENHANCED" 177 | } 178 | 179 | variable "registry_scan_rules" { 180 | description = "One or multiple blocks specifying scanning rules to determine which repository filters are used and at what frequency scanning will occur" 181 | type = any 182 | default = [] 183 | } 184 | 185 | ################################################################################ 186 | # Registry Replication Configuration 187 | ################################################################################ 188 | 189 | variable "create_registry_replication_configuration" { 190 | description = "Determines whether a registry replication configuration will be created" 191 | type = bool 192 | default = false 193 | } 194 | 195 | variable "registry_replication_rules" { 196 | description = "The replication rules for a replication configuration. A maximum of 10 are allowed" 197 | type = any 198 | default = [] 199 | } 200 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wrappers/README.md: -------------------------------------------------------------------------------- 1 | # Wrapper for the root module 2 | 3 | The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). 4 | 5 | You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. 6 | 7 | This wrapper does not implement any extra functionality. 8 | 9 | ## Usage with Terragrunt 10 | 11 | `terragrunt.hcl`: 12 | 13 | ```hcl 14 | terraform { 15 | source = "tfr:///terraform-aws-modules/ecr/aws//wrappers" 16 | # Alternative source: 17 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecr.git//wrappers?ref=master" 18 | } 19 | 20 | inputs = { 21 | defaults = { # Default values 22 | create = true 23 | tags = { 24 | Terraform = "true" 25 | Environment = "dev" 26 | } 27 | } 28 | 29 | items = { 30 | my-item = { 31 | # omitted... can be any argument supported by the module 32 | } 33 | my-second-item = { 34 | # omitted... can be any argument supported by the module 35 | } 36 | # omitted... 37 | } 38 | } 39 | ``` 40 | 41 | ## Usage with Terraform 42 | 43 | ```hcl 44 | module "wrapper" { 45 | source = "terraform-aws-modules/ecr/aws//wrappers" 46 | 47 | defaults = { # Default values 48 | create = true 49 | tags = { 50 | Terraform = "true" 51 | Environment = "dev" 52 | } 53 | } 54 | 55 | items = { 56 | my-item = { 57 | # omitted... can be any argument supported by the module 58 | } 59 | my-second-item = { 60 | # omitted... can be any argument supported by the module 61 | } 62 | # omitted... 63 | } 64 | } 65 | ``` 66 | 67 | ## Example: Manage multiple S3 buckets in one Terragrunt layer 68 | 69 | `eu-west-1/s3-buckets/terragrunt.hcl`: 70 | 71 | ```hcl 72 | terraform { 73 | source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" 74 | # Alternative source: 75 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" 76 | } 77 | 78 | inputs = { 79 | defaults = { 80 | force_destroy = true 81 | 82 | attach_elb_log_delivery_policy = true 83 | attach_lb_log_delivery_policy = true 84 | attach_deny_insecure_transport_policy = true 85 | attach_require_latest_tls_policy = true 86 | } 87 | 88 | items = { 89 | bucket1 = { 90 | bucket = "my-random-bucket-1" 91 | } 92 | bucket2 = { 93 | bucket = "my-random-bucket-2" 94 | tags = { 95 | Secure = "probably" 96 | } 97 | } 98 | } 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /wrappers/main.tf: -------------------------------------------------------------------------------- 1 | module "wrapper" { 2 | source = "../" 3 | 4 | for_each = var.items 5 | 6 | attach_repository_policy = try(each.value.attach_repository_policy, var.defaults.attach_repository_policy, true) 7 | create = try(each.value.create, var.defaults.create, true) 8 | create_lifecycle_policy = try(each.value.create_lifecycle_policy, var.defaults.create_lifecycle_policy, true) 9 | create_registry_policy = try(each.value.create_registry_policy, var.defaults.create_registry_policy, false) 10 | create_registry_replication_configuration = try(each.value.create_registry_replication_configuration, var.defaults.create_registry_replication_configuration, false) 11 | create_repository = try(each.value.create_repository, var.defaults.create_repository, true) 12 | create_repository_policy = try(each.value.create_repository_policy, var.defaults.create_repository_policy, true) 13 | manage_registry_scanning_configuration = try(each.value.manage_registry_scanning_configuration, var.defaults.manage_registry_scanning_configuration, false) 14 | public_repository_catalog_data = try(each.value.public_repository_catalog_data, var.defaults.public_repository_catalog_data, {}) 15 | registry_policy = try(each.value.registry_policy, var.defaults.registry_policy, null) 16 | registry_pull_through_cache_rules = try(each.value.registry_pull_through_cache_rules, var.defaults.registry_pull_through_cache_rules, {}) 17 | registry_replication_rules = try(each.value.registry_replication_rules, var.defaults.registry_replication_rules, []) 18 | registry_scan_rules = try(each.value.registry_scan_rules, var.defaults.registry_scan_rules, []) 19 | registry_scan_type = try(each.value.registry_scan_type, var.defaults.registry_scan_type, "ENHANCED") 20 | repository_encryption_type = try(each.value.repository_encryption_type, var.defaults.repository_encryption_type, null) 21 | repository_force_delete = try(each.value.repository_force_delete, var.defaults.repository_force_delete, null) 22 | repository_image_scan_on_push = try(each.value.repository_image_scan_on_push, var.defaults.repository_image_scan_on_push, true) 23 | repository_image_tag_mutability = try(each.value.repository_image_tag_mutability, var.defaults.repository_image_tag_mutability, "IMMUTABLE") 24 | repository_kms_key = try(each.value.repository_kms_key, var.defaults.repository_kms_key, null) 25 | repository_lambda_read_access_arns = try(each.value.repository_lambda_read_access_arns, var.defaults.repository_lambda_read_access_arns, []) 26 | repository_lifecycle_policy = try(each.value.repository_lifecycle_policy, var.defaults.repository_lifecycle_policy, "") 27 | repository_name = try(each.value.repository_name, var.defaults.repository_name, "") 28 | repository_policy = try(each.value.repository_policy, var.defaults.repository_policy, null) 29 | repository_policy_statements = try(each.value.repository_policy_statements, var.defaults.repository_policy_statements, {}) 30 | repository_read_access_arns = try(each.value.repository_read_access_arns, var.defaults.repository_read_access_arns, []) 31 | repository_read_write_access_arns = try(each.value.repository_read_write_access_arns, var.defaults.repository_read_write_access_arns, []) 32 | repository_type = try(each.value.repository_type, var.defaults.repository_type, "private") 33 | tags = try(each.value.tags, var.defaults.tags, {}) 34 | } 35 | -------------------------------------------------------------------------------- /wrappers/outputs.tf: -------------------------------------------------------------------------------- 1 | output "wrapper" { 2 | description = "Map of outputs of a wrapper." 3 | value = module.wrapper 4 | # sensitive = false # No sensitive module output found 5 | } 6 | -------------------------------------------------------------------------------- /wrappers/repository-template/README.md: -------------------------------------------------------------------------------- 1 | # Wrapper for module: `modules/repository-template` 2 | 3 | The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). 4 | 5 | You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. 6 | 7 | This wrapper does not implement any extra functionality. 8 | 9 | ## Usage with Terragrunt 10 | 11 | `terragrunt.hcl`: 12 | 13 | ```hcl 14 | terraform { 15 | source = "tfr:///terraform-aws-modules/ecr/aws//wrappers/repository-template" 16 | # Alternative source: 17 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecr.git//wrappers/repository-template?ref=master" 18 | } 19 | 20 | inputs = { 21 | defaults = { # Default values 22 | create = true 23 | tags = { 24 | Terraform = "true" 25 | Environment = "dev" 26 | } 27 | } 28 | 29 | items = { 30 | my-item = { 31 | # omitted... can be any argument supported by the module 32 | } 33 | my-second-item = { 34 | # omitted... can be any argument supported by the module 35 | } 36 | # omitted... 37 | } 38 | } 39 | ``` 40 | 41 | ## Usage with Terraform 42 | 43 | ```hcl 44 | module "wrapper" { 45 | source = "terraform-aws-modules/ecr/aws//wrappers/repository-template" 46 | 47 | defaults = { # Default values 48 | create = true 49 | tags = { 50 | Terraform = "true" 51 | Environment = "dev" 52 | } 53 | } 54 | 55 | items = { 56 | my-item = { 57 | # omitted... can be any argument supported by the module 58 | } 59 | my-second-item = { 60 | # omitted... can be any argument supported by the module 61 | } 62 | # omitted... 63 | } 64 | } 65 | ``` 66 | 67 | ## Example: Manage multiple S3 buckets in one Terragrunt layer 68 | 69 | `eu-west-1/s3-buckets/terragrunt.hcl`: 70 | 71 | ```hcl 72 | terraform { 73 | source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" 74 | # Alternative source: 75 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" 76 | } 77 | 78 | inputs = { 79 | defaults = { 80 | force_destroy = true 81 | 82 | attach_elb_log_delivery_policy = true 83 | attach_lb_log_delivery_policy = true 84 | attach_deny_insecure_transport_policy = true 85 | attach_require_latest_tls_policy = true 86 | } 87 | 88 | items = { 89 | bucket1 = { 90 | bucket = "my-random-bucket-1" 91 | } 92 | bucket2 = { 93 | bucket = "my-random-bucket-2" 94 | tags = { 95 | Secure = "probably" 96 | } 97 | } 98 | } 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /wrappers/repository-template/main.tf: -------------------------------------------------------------------------------- 1 | module "wrapper" { 2 | source = "../../modules/repository-template" 3 | 4 | for_each = var.items 5 | 6 | applied_for = try(each.value.applied_for, var.defaults.applied_for, ["PULL_THROUGH_CACHE"]) 7 | create = try(each.value.create, var.defaults.create, true) 8 | create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) 9 | create_pull_through_cache_rule = try(each.value.create_pull_through_cache_rule, var.defaults.create_pull_through_cache_rule, false) 10 | create_repository_policy = try(each.value.create_repository_policy, var.defaults.create_repository_policy, true) 11 | credential_arn = try(each.value.credential_arn, var.defaults.credential_arn, null) 12 | custom_role_arn = try(each.value.custom_role_arn, var.defaults.custom_role_arn, null) 13 | description = try(each.value.description, var.defaults.description, null) 14 | encryption_type = try(each.value.encryption_type, var.defaults.encryption_type, "AES256") 15 | iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) 16 | iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) 17 | iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) 18 | iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) 19 | iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) 20 | iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) 21 | image_tag_mutability = try(each.value.image_tag_mutability, var.defaults.image_tag_mutability, "IMMUTABLE") 22 | kms_key_arn = try(each.value.kms_key_arn, var.defaults.kms_key_arn, null) 23 | lifecycle_policy = try(each.value.lifecycle_policy, var.defaults.lifecycle_policy, null) 24 | prefix = try(each.value.prefix, var.defaults.prefix, "") 25 | repository_lambda_read_access_arns = try(each.value.repository_lambda_read_access_arns, var.defaults.repository_lambda_read_access_arns, []) 26 | repository_policy = try(each.value.repository_policy, var.defaults.repository_policy, null) 27 | repository_policy_statements = try(each.value.repository_policy_statements, var.defaults.repository_policy_statements, {}) 28 | repository_read_access_arns = try(each.value.repository_read_access_arns, var.defaults.repository_read_access_arns, []) 29 | repository_read_write_access_arns = try(each.value.repository_read_write_access_arns, var.defaults.repository_read_write_access_arns, []) 30 | resource_tags = try(each.value.resource_tags, var.defaults.resource_tags, {}) 31 | tags = try(each.value.tags, var.defaults.tags, {}) 32 | upstream_registry_url = try(each.value.upstream_registry_url, var.defaults.upstream_registry_url, null) 33 | } 34 | -------------------------------------------------------------------------------- /wrappers/repository-template/outputs.tf: -------------------------------------------------------------------------------- 1 | output "wrapper" { 2 | description = "Map of outputs of a wrapper." 3 | value = module.wrapper 4 | # sensitive = false # No sensitive module output found 5 | } 6 | -------------------------------------------------------------------------------- /wrappers/repository-template/variables.tf: -------------------------------------------------------------------------------- 1 | variable "defaults" { 2 | description = "Map of default values which will be used for each item." 3 | type = any 4 | default = {} 5 | } 6 | 7 | variable "items" { 8 | description = "Maps of items to create a wrapper from. Values are passed through to the module." 9 | type = any 10 | default = {} 11 | } 12 | -------------------------------------------------------------------------------- /wrappers/repository-template/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wrappers/variables.tf: -------------------------------------------------------------------------------- 1 | variable "defaults" { 2 | description = "Map of default values which will be used for each item." 3 | type = any 4 | default = {} 5 | } 6 | 7 | variable "items" { 8 | description = "Maps of items to create a wrapper from. Values are passed through to the module." 9 | type = any 10 | default = {} 11 | } 12 | -------------------------------------------------------------------------------- /wrappers/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.93" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------