From 8476a6df8bdee737be376314c52d4c87e70c1f8a Mon Sep 17 00:00:00 2001 From: Matthias Fuhrmeister Date: Wed, 21 Feb 2024 17:36:58 +0100 Subject: [PATCH] Allow cache though enabled repositories to fetch image from upstream (#117) * Allow cache though enabled repositories to fetch image from upstream Allow read only access "users" to use pull through cache feature for new images in the repository. why: We are using ecr-public pull through cache and we want also new images to be downloaded automatically to the cache. Therefore read only access users need to be able to do that. There is currently no support for the cache feature in this module and I wanted to keep the changes minimal. * use a principal list to allow pull through access * add a prefix list for pull through repos, which adds the pull through permissions just on these repos --- README.md | 72 ++++++++++++++++++----------------------------- docs/terraform.md | 3 ++ main.tf | 51 ++++++++++++++++++++++++++------- variables.tf | 12 ++++++++ 4 files changed, 84 insertions(+), 54 deletions(-) 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 = [] +}