diff --git a/README.md b/README.md index 01d1ca3..b4fb6c6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ - -# terraform-aws-ecr +# terraform-aws-ecr Latest ReleaseSlack Community @@ -30,9 +29,9 @@ Terraform module to provision an [`AWS ECR Docker Container registry`](https://a --- > [!NOTE] -> This project is part of Cloud Posse's comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. ->
Learn More -> +> This project is part of Cloud Posse's comprehensive ["SweetOps"](https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=) approach towards DevOps. +>
Learn More +> > > > @@ -43,10 +42,10 @@ Terraform module to provision an [`AWS ECR Docker Container registry`](https://a > > It's 100% Open Source and licensed under the [APACHE2](LICENSE). > -> We literally have [*hundreds of terraform modules*][terraform_modules] that are Open Source and well-maintained. Check them out! +> We literally have [*hundreds of terraform modules*](https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=terraform_modules) that are Open Source and well-maintained. Check them out! >
-[![README Header][readme_header_img]][readme_header_link] + @@ -152,6 +151,7 @@ Available targets: | [aws_iam_policy_document.organizations_readonly_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_full_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.resource_pull_through_cache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_push_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_readonly_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | @@ -183,8 +183,10 @@ Available targets: | [organizations\_full\_access](#input\_organizations\_full\_access) | Organization IDs to provide with full access to the ECR. | `list(string)` | `[]` | no | | [organizations\_push\_access](#input\_organizations\_push\_access) | Organization IDs to provide with push access to the ECR | `list(string)` | `[]` | no | | [organizations\_readonly\_access](#input\_organizations\_readonly\_access) | Organization IDs to provide with readonly access to the ECR. | `list(string)` | `[]` | no | +| [prefixes\_pull\_through\_repositories](#input\_prefixes\_pull\_through\_repositories) | Organization IDs to provide with push access to the ECR | `list(string)` | `[]` | no | | [principals\_full\_access](#input\_principals\_full\_access) | Principal ARNs to provide with full access to the ECR | `list(string)` | `[]` | no | | [principals\_lambda](#input\_principals\_lambda) | Principal account IDs of Lambdas allowed to consume ECR | `list(string)` | `[]` | no | +| [principals\_pull\_though\_access](#input\_principals\_pull\_though\_access) | Principal ARNs to provide with pull though access to the ECR | `list(string)` | `[]` | no | | [principals\_push\_access](#input\_principals\_push\_access) | Principal ARNs to provide with push access to the ECR | `list(string)` | `[]` | no | | [principals\_readonly\_access](#input\_principals\_readonly\_access) | Principal ARNs to provide with readonly access to the ECR | `list(string)` | `[]` | no | | [protected\_tags](#input\_protected\_tags) | Name of image tags prefixes that should not be destroyed. Useful if you tag images with names like `dev`, `staging`, and `prod` | `set(string)` | `[]` | no | @@ -231,7 +233,7 @@ Please use the [issue tracker](https://github.com/cloudposse/terraform-aws-ecr/i ### πŸ’» Developing If you are interested in being a contributor and want to get involved in developing this project or help out with Cloud Posse's other projects, we would love to hear from you! -Hit us up in [Slack][slack], in the `#cloudposse` channel. +Hit us up in [Slack](https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=slack), in the `#cloudposse` channel. In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. 1. Review our [Code of Conduct](https://github.com/cloudposse/terraform-aws-ecr/?tab=coc-ov-file#code-of-conduct) and [Contributor Guidelines](https://github.com/cloudposse/.github/blob/main/CONTRIBUTING.md). @@ -245,35 +247,35 @@ In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. ### 🌎 Slack Community -Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. +Join our [Open Source Community](https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=slack) on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. ### πŸ“° Newsletter -Sign up for [our newsletter][newsletter] and join 3,000+ DevOps engineers, CTOs, and founders who get insider access to the latest DevOps trends, so you can always stay in the know. +Sign up for [our newsletter](https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=newsletter) and join 3,000+ DevOps engineers, CTOs, and founders who get insider access to the latest DevOps trends, so you can always stay in the know. Dropped straight into your Inbox every week β€” and usually a 5-minute read. -### πŸ“† Office Hours +### πŸ“† Office Hours -[Join us every Wednesday via Zoom][office_hours] for your weekly dose of insider DevOps trends, AWS news and Terraform insights, all sourced from our SweetOps community, plus a _live Q&A_ that you can’t find anywhere else. +[Join us every Wednesday via Zoom](https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=office_hours) for your weekly dose of insider DevOps trends, AWS news and Terraform insights, all sourced from our SweetOps community, plus a _live Q&A_ that you can’t find anywhere else. It's **FREE** for everyone! ## About -This project is maintained by [Cloud Posse, LLC][website]. - +This project is maintained by Cloud Posse, LLC. + -We are a [**DevOps Accelerator**][commercial_support] for funded startups and enterprises. +We are a [**DevOps Accelerator**](https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=commercial_support) for funded startups and enterprises. Use our ready-to-go terraform architecture blueprints for AWS to get up and running quickly. We build it with you. You own everything. Your team wins. Plus, we stick around until you succeed. -[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] +Learn More *Your team can operate like a pro today.* Ensure that your team succeeds by using our proven process and turnkey blueprints. Plus, we stick around until you succeed.
- πŸ“š What's included? + πŸ“š See What's Included - **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. - **Deployment Strategy.** You'll have a battle-tested deployment strategy using GitHub Actions that's automated and repeatable. @@ -287,16 +289,18 @@ Ensure that your team succeeds by using our proven process and turnkey blueprint - **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects.
-[![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] + ## License -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) +License
Preamble to the Apache License, Version 2.0

+ Complete license is available in the [`LICENSE`](LICENSE) file. + ```text Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -322,28 +326,8 @@ under the License. All other trademarks referenced herein are the property of their respective owners. --- Copyright Β© 2017-2024 [Cloud Posse, LLC](https://cpco.io/copyright) -[![README Footer][readme_footer_img]][readme_footer_link] -[![Beacon][beacon]][website] - - [logo]: https://cloudposse.com/logo-300x69.svg - [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=docs - [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=website - [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=github - [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=jobs - [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=hire - [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=slack - [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=twitter - [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=office_hours - [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=newsletter - [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=email - [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=commercial_support - [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=we_love_open_source - [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=terraform_modules - [readme_header_img]: https://cloudposse.com/readme/header/img - [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=readme_header_link - [readme_footer_img]: https://cloudposse.com/readme/footer/img - [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=readme_footer_link - [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img - [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-ecr&utm_content=readme_commercial_support_link - [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-aws-ecr?pixel&cs=github&cm=readme&an=terraform-aws-ecr - + + +README footer + +Beacon diff --git a/docs/terraform.md b/docs/terraform.md index 2410af5..1044b87 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -32,6 +32,7 @@ | [aws_iam_policy_document.organizations_readonly_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_full_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.resource_pull_through_cache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_push_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.resource_readonly_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | @@ -63,8 +64,10 @@ | [organizations\_full\_access](#input\_organizations\_full\_access) | Organization IDs to provide with full access to the ECR. | `list(string)` | `[]` | no | | [organizations\_push\_access](#input\_organizations\_push\_access) | Organization IDs to provide with push access to the ECR | `list(string)` | `[]` | no | | [organizations\_readonly\_access](#input\_organizations\_readonly\_access) | Organization IDs to provide with readonly access to the ECR. | `list(string)` | `[]` | no | +| [prefixes\_pull\_through\_repositories](#input\_prefixes\_pull\_through\_repositories) | Organization IDs to provide with push access to the ECR | `list(string)` | `[]` | no | | [principals\_full\_access](#input\_principals\_full\_access) | Principal ARNs to provide with full access to the ECR | `list(string)` | `[]` | no | | [principals\_lambda](#input\_principals\_lambda) | Principal account IDs of Lambdas allowed to consume ECR | `list(string)` | `[]` | no | +| [principals\_pull\_though\_access](#input\_principals\_pull\_though\_access) | Principal ARNs to provide with pull though access to the ECR | `list(string)` | `[]` | no | | [principals\_push\_access](#input\_principals\_push\_access) | Principal ARNs to provide with push access to the ECR | `list(string)` | `[]` | no | | [principals\_readonly\_access](#input\_principals\_readonly\_access) | Principal ARNs to provide with readonly access to the ECR | `list(string)` | `[]` | no | | [protected\_tags](#input\_protected\_tags) | Name of image tags prefixes that should not be destroyed. Useful if you tag images with names like `dev`, `staging`, and `prod` | `set(string)` | `[]` | no | diff --git a/main.tf b/main.tf index 8b0d1cc..d320ea5 100644 --- a/main.tf +++ b/main.tf @@ -1,12 +1,23 @@ locals { - principals_readonly_access_non_empty = length(var.principals_readonly_access) > 0 - principals_push_access_non_empty = length(var.principals_push_access) > 0 - principals_full_access_non_empty = length(var.principals_full_access) > 0 - principals_lambda_non_empty = length(var.principals_lambda) > 0 - organizations_readonly_access_non_empty = length(var.organizations_readonly_access) > 0 - organizations_full_access_non_empty = length(var.organizations_full_access) > 0 - organizations_push_non_empty = length(var.organizations_push_access) > 0 - ecr_need_policy = length(var.principals_full_access) + length(var.principals_readonly_access) + length(var.principals_push_access) + length(var.principals_lambda) + length(var.organizations_readonly_access) + length(var.organizations_full_access) + length(var.organizations_push_access) > 0 + principals_readonly_access_non_empty = length(var.principals_readonly_access) > 0 + principals_pull_through_access_non_empty = length(var.principals_pull_though_access) > 0 + principals_push_access_non_empty = length(var.principals_push_access) > 0 + principals_full_access_non_empty = length(var.principals_full_access) > 0 + principals_lambda_non_empty = length(var.principals_lambda) > 0 + organizations_readonly_access_non_empty = length(var.organizations_readonly_access) > 0 + organizations_full_access_non_empty = length(var.organizations_full_access) > 0 + organizations_push_non_empty = length(var.organizations_push_access) > 0 + + ecr_need_policy = ( + length(var.principals_full_access) + + length(var.principals_readonly_access) + + length(var.principals_pull_though_access) + + length(var.principals_push_access) + + length(var.principals_lambda) + + length(var.organizations_readonly_access) + + length(var.organizations_full_access) + + length(var.organizations_push_access) > 0 + ) } locals { @@ -127,6 +138,25 @@ data "aws_iam_policy_document" "resource_readonly_access" { } } +data "aws_iam_policy_document" "resource_pull_through_cache" { + count = module.this.enabled ? 1 : 0 + + statement { + sid = "PullThroughAccess" + effect = "Allow" + + principals { + type = "AWS" + identifiers = var.principals_pull_though_access + } + + actions = [ + "ecr:BatchImportUpstreamImage", + "ecr:TagResource" + ] + } +} + data "aws_iam_policy_document" "resource_push_access" { count = module.this.enabled ? 1 : 0 @@ -292,11 +322,12 @@ data "aws_iam_policy_document" "organization_push_access" { } data "aws_iam_policy_document" "resource" { - count = module.this.enabled ? 1 : 0 + for_each = toset(local.ecr_need_policy && module.this.enabled ? local.image_names : []) source_policy_documents = local.principals_readonly_access_non_empty ? [ data.aws_iam_policy_document.resource_readonly_access[0].json ] : [data.aws_iam_policy_document.empty[0].json] override_policy_documents = distinct([ + local.principals_pull_through_access_non_empty && contains(var.prefixes_pull_through_repositories, regex("^[a-z][a-z0-9\\-\\.\\_]+", each.value)) ? data.aws_iam_policy_document.resource_pull_through_cache[0].json : data.aws_iam_policy_document.empty[0].json, local.principals_push_access_non_empty ? data.aws_iam_policy_document.resource_push_access[0].json : data.aws_iam_policy_document.empty[0].json, local.principals_full_access_non_empty ? data.aws_iam_policy_document.resource_full_access[0].json : data.aws_iam_policy_document.empty[0].json, local.principals_lambda_non_empty ? data.aws_iam_policy_document.lambda_access[0].json : data.aws_iam_policy_document.empty[0].json, @@ -309,5 +340,5 @@ data "aws_iam_policy_document" "resource" { resource "aws_ecr_repository_policy" "name" { for_each = toset(local.ecr_need_policy && module.this.enabled ? local.image_names : []) repository = aws_ecr_repository.name[each.value].name - policy = join("", data.aws_iam_policy_document.resource[*].json) + policy = data.aws_iam_policy_document.resource[each.value].json } diff --git a/variables.tf b/variables.tf index 9ecfd87..132ad0a 100644 --- a/variables.tf +++ b/variables.tf @@ -22,6 +22,12 @@ variable "principals_readonly_access" { default = [] } +variable "principals_pull_though_access" { + type = list(string) + description = "Principal ARNs to provide with pull though access to the ECR" + default = [] +} + variable "principals_lambda" { type = list(string) description = "Principal account IDs of Lambdas allowed to consume ECR" @@ -95,3 +101,9 @@ variable "organizations_push_access" { description = "Organization IDs to provide with push access to the ECR" default = [] } + +variable "prefixes_pull_through_repositories" { + type = list(string) + description = "Organization IDs to provide with push access to the ECR" + default = [] +}