From c149c4530eccb11c46d2ab915abe662055269ecf Mon Sep 17 00:00:00 2001 From: badra001 Date: Tue, 14 Nov 2023 14:15:35 -0500 Subject: [PATCH] * 2.0.3 -- 2023-11-14 - add output repository_names --- .pre-commit-config.yaml | 12 ++-- .terraform-docs.yml | 46 ++++++++++++ CHANGELOG.md | 3 + README.md | 150 ++++++++++++++++++++++++++++++++++++++++ outputs.tf | 5 ++ policy.tf.txt | 138 ++++++++++++++++++++++++++++++++++++ version.tf | 2 +- 7 files changed, 351 insertions(+), 5 deletions(-) create mode 100644 .terraform-docs.yml create mode 100644 policy.tf.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7f9f794..fcb9d68 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,20 +1,24 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.48.0 + rev: v1.83.5 hooks: # - id: terraform_validate - id: terraform_fmt - - id: terraform_docs_replace - args: ['table'] +# - id: terraform_docs_replace + - id: terraform_docs +# args: ['table'] exclude: common/*.tf exclude: version.tf exclude: examples + args: + - --args=--config=.terraform-docs.yml # - id: terraform_tflint # args: [ "--args=--config=__GIT_WORKING_DIR__/.tflint.hcl"] # exclude: examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.5.0 hooks: - id: check-symlinks - id: detect-aws-credentials + args: [ "--allow-missing-credentials" ] - id: detect-private-key diff --git a/.terraform-docs.yml b/.terraform-docs.yml new file mode 100644 index 0000000..227afcc --- /dev/null +++ b/.terraform-docs.yml @@ -0,0 +1,46 @@ +## https://github.com/antonbabenko/pre-commit-terraform/issues/248#issuecomment-1290829226 +formatter: "markdown table" + +header-from: main.tf +footer-from: "" + +sections: +## hide: [] + show: + - data-sources + - header + - footer + - inputs + - modules + - outputs + - providers + - requirements + - resources + +output: + file: README.md + mode: inject + template: |- + + {{ .Content }} + + +## output-values: +## enabled: false +## from: "" +## +## sort: +## enabled: true +## by: name +## +## settings: +## anchor: true +## color: true +## default: true +## description: false +## escape: true +## indent: 2 +## required: true +## sensitive: true +## type: true + diff --git a/CHANGELOG.md b/CHANGELOG.md index fab04d0..11636ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,3 +19,6 @@ * 2.0.2 -- 2023-08-29 - add repository_urls output (per app_name => URL) + +* 2.0.3 -- 2023-11-14 + - add output repository_names diff --git a/README.md b/README.md index 7c43ea8..a693792 100644 --- a/README.md +++ b/README.md @@ -142,4 +142,154 @@ No modules. | [availability\_zone\_names](#output\_availability\_zone\_names) | VPC Availability zone name list (3) | | [availability\_zone\_suffixes](#output\_availability\_zone\_suffixes) | VPC Availability zone suffix list (3) | | [images](#output\_images) | Final full merge of images with extra details | +| [repository\_names](#output\_repository\_names) | ECR Respository Names | | [repository\_urls](#output\_repository\_urls) | ECR Respository URLs | + + +# About aws-ecr-copy-images +This module will create ECR repositories with the prefix of {application\_name} for the list of +repositories in {application\_list}. This allows for a project to upload their images into +/{application\_name}/{sub\_app}/{image}:{tag}. + +Also, if provided a list of source image configurations, it will download them from their location +and upload them to the prefix of {application\_name} followed by the {name} in the `image_config` +object. + +# Usage + +```hcl +locals { + image_config = [ + { + enabled = true + dest_path = null + name = "openjdk-8" + source_image = "ubi8/openjdk-8" + source_registry = "registry.access.redhat.com" + source_tag = null + tag = "latest" + }, + { + enabled = true + name = "nginx-118" + dest_path = null + source_image = "ubi8/nginx-118" + source_registry = "registry.access.redhat.com" + source_tag = null + tag = "latest" + }, + { + enabled = true + name = "nodejs-14" + dest_path = null + source_image = "ubi8/nodejs-14" + source_registry = "registry.access.redhat.com" + source_tag = null + tag = "latest" + }, + ] +} + +module "images" { + source = "git@github.e.it.census.gov:terraform-modules/aws-ecr-copy-images.git" + + profile = var.profile + application_list = ["app1", "app2"] + application_name = "org-project" + image_config = local.image_config + tags = {} + + ### optional + ## account_alias = "" + ## account_id = "" + ## destination_password = "" + ## destination_username = "" + ## override_prefixes = {} + ## region = "" + ## source_password = "" + ## source_username = "" +} +``` + +This creates the following ECR images + +``` +Repository name URI Created at Tag immutability Scan on push Encryption type + +org-project/app1 817869416306.dkr.ecr.us-gov-east-1.amazonaws.com/org-project/app1 August 22, 2022, 13:12:06 (UTC-04) Enabled Enabled KMS +org-project/app2 817869416306.dkr.ecr.us-gov-east-1.amazonaws.com/org-project/app2 August 22, 2022, 13:12:06 (UTC-04) Enabled Enabled KMS +org-project/nginx-118 817869416306.dkr.ecr.us-gov-east-1.amazonaws.com/org-project/nginx-118 August 22, 2022, 12:43:57 (UTC-04) Enabled Enabled KMS +org-project/nodejs-14 817869416306.dkr.ecr.us-gov-east-1.amazonaws.com/org-project/nodejs-14 August 22, 2022, 12:43:57 (UTC-04) Enabled Enabled KMS +org-project/openjdk-8 817869416306.dkr.ecr.us-gov-east-1.amazonaws.com/org-project/openjdk-8 August 22, 2022, 12:43:57 (UTC-04) Enabled Enabled KMS +``` + +# Variables +## profile +This variable is required because this module calls a script, and it uses `aws` CLI commands. As such, it needs to set the `AWS_PROFILE` environment +variable to call the script properly. + +# Caveats +Currently, a destroy of the images (null\_resources) does **NOT** remove the repository. That is a work in progress. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.13 | +| [aws](#requirement\_aws) | >= 3.0 | +| [null](#requirement\_null) | >= 1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 3.0 | +| [null](#provider\_null) | >= 1.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_ecr_repository.apps_repos](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | +| [null_resource.copy_images](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [aws_arn.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | data source | +| [aws_availability_zone.zone](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zone) | data source | +| [aws_availability_zones.zones](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_ecr_authorization_token.token](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecr_authorization_token) | data source | +| [aws_iam_account_alias.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_account_alias) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [account\_alias](#input\_account\_alias) | AWS Account Alias | `string` | `""` | no | +| [account\_id](#input\_account\_id) | AWS Account ID (default will pull from current user) | `string` | `""` | no | +| [application\_list](#input\_application\_list) | List of application repositories to create for /{application\_name}/{image\_name} for those not in image\_config | `list(string)` | `[]` | no | +| [application\_name](#input\_application\_name) | Appliication name, usually {org}-{project}, which is likely a prefix to the EKS cluster name | `string` | n/a | yes | +| [destination\_password](#input\_destination\_password) | OCI destination repository password | `string` | `null` | no | +| [destination\_username](#input\_destination\_username) | OCI destination repository username | `string` | `null` | no | +| [image\_config](#input\_image\_config) | List of image configuration objects to copy from SOURCE to DESTINATION |
list(object({
name = string,
tag = string,
dest_path = string,
source_registry = string,
source_image = string,
source_tag = string,
enabled = bool,
}))
| `[]` | no | +| [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component. This should be used primarily for common infrastructure things | `map(string)` | `{}` | no | +| [profile](#input\_profile) | AWS Profile Name, used generating key rotation file | `string` | n/a | yes | +| [region](#input\_region) | Region in which to create the ECR repositories (default of current region) | `string` | `null` | no | +| [source\_password](#input\_source\_password) | OCI source repository password | `string` | `null` | no | +| [source\_username](#input\_source\_username) | OCI source repository username | `string` | `null` | no | +| [tags](#input\_tags) | AWS Tags to apply to appropriate resources | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [availability\_zone\_ids](#output\_availability\_zone\_ids) | VPC Availability zone id list (3) | +| [availability\_zone\_names](#output\_availability\_zone\_names) | VPC Availability zone name list (3) | +| [availability\_zone\_suffixes](#output\_availability\_zone\_suffixes) | VPC Availability zone suffix list (3) | +| [images](#output\_images) | Final full merge of images with extra details | +| [repository\_names](#output\_repository\_names) | ECR Respository Names | +| [repository\_urls](#output\_repository\_urls) | ECR Respository URLs | + \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index ab733d1..0acf994 100644 --- a/outputs.tf +++ b/outputs.tf @@ -7,3 +7,8 @@ output "repository_urls" { description = "ECR Respository URLs" value = { for k, v in aws_ecr_repository.apps_repos : k => v.repository_url } } + +output "repository_names" { + description = "ECR Respository Names" + value = { for k, v in aws_ecr_repository.apps_repos : k => v.name } +} diff --git a/policy.tf.txt b/policy.tf.txt new file mode 100644 index 0000000..a12a887 --- /dev/null +++ b/policy.tf.txt @@ -0,0 +1,138 @@ + admin_policy_statements = { + ECRRead = { + actions = [ + "ecr:Describe*", + "ecr:Get*", + "ecr:ListImages", + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + ] + resources = ["*"] + } + ECRWrite = { + actions = [ + "ecr:BatchDeleteImage", + "ecr:CompleteLayerUpload", + "ecr:CreateRepository", + "ecr:DeleteRepository", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" + ] + resources = [format(local.common_arn, "ecr", format("repository/eks/%v/*", var.cluster_name))] + } + EKSRead = { + actions = [ + "eks:ListClusters", + "eks:ListAddons", + "eks:ListNodegroups", + "eks:DescribeCluster", + "eks:DescribeAddon*", + "eks:DescribeNodegroup", + ] + resources = [ + format(local.common_arn, "eks", "cluster/*"), + format(local.common_arn, "eks", "addon/*"), + format(local.common_arn, "eks", "addons/*"), + format(local.common_arn, "eks", "/addons/*"), + format(local.common_arn, "eks", "nodegroup/*"), + ] + } + + + + +data "aws_iam_policy_document" "shared_access" { + statement { + sid = "SharedECRAccess" + effect = "Allow" + resources = [ "*" ] + principals = * + actions = [ + “ecr:BatchCheckLayerAvailability”, + “ecr:BatchGetImage”, + “ecr:DescribeImages”, + “ecr:DescribeRepositories”, + “ecr:GetDownloadUrlForLayer”, + ] + conditions { + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgID" + values = [data.aws_organizations_organization.org.id] + + + “Condition”: { + + “ForAnyValue:StringLike”: { + + “aws:PrincipalOrgPaths”: “o-xxxxxxxxxx/*/ou-xxxx-xxxxxxxx/*” + + } + + } + + } + + ] + +} + + +locals { + # org_paths = [for c in data.aws_organizations_organizational_units.ou.children : format("%v/%v/%v", data.aws_organizations_organization.org.id, data.aws_organizations_organizational_units.ou.id, c.id)] + org_paths = [for k, v in local.share_organizational_units : format("%v/%v/%v", data.aws_organizations_organization.org.id, data.aws_organizations_organizational_units.ou.id, k)] + templates = [ + "EndEntityCertificate/V1", + "SubordinateCACertificate_PathLen0/V1", + ] + template_arns = [for t in local.templates : format("arn:%v:acm-pca:::template/%v", data.aws_arn.current.partition, t)] +} + + + + +i # # share to whole org, not to path + # condition { + # test = "ForAnyValue:StringLike" + # variable = "aws:PrincipalOrgPaths" + # values = formatlist("%v/*", local.org_paths) + # } + + + +data "aws_iam_policy_document" "foopolicy" { + statement { + sid = "new policy" + effect = "Allow" + + principals { + type = "AWS" + identifiers = ["123456789012"] + } + + actions = [ + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability", + "ecr:PutImage", + "ecr:InitiateLayerUpload", + "ecr:UploadLayerPart", + "ecr:CompleteLayerUpload", + "ecr:DescribeRepositories", + "ecr:GetRepositoryPolicy", + "ecr:ListImages", + "ecr:DeleteRepository", + "ecr:BatchDeleteImage", + "ecr:SetRepositoryPolicy", + "ecr:DeleteRepositoryPolicy", + ] + } +} + +resource "aws_ecr_repository_policy" "foopolicy" { + repository = aws_ecr_repository.foo.name + policy = data.aws_iam_policy_document.foopolicy.json +} + diff --git a/version.tf b/version.tf index fed7410..66cbccb 100644 --- a/version.tf +++ b/version.tf @@ -1,4 +1,4 @@ locals { _module_name = "aws-ecr-copy-images" - _module_version = "2.0.2" + _module_version = "2.0.3" }