Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reinvent permissions to ECR #21

Merged
merged 19 commits into from
Jan 29, 2019
241 changes: 109 additions & 132 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,60 @@
data "aws_iam_role" "default" {
count = "${signum(length(var.roles)) == 1 ? length(var.roles) : 0}"
name = "${element(var.roles, count.index)}"
locals {
principals_readonly_access_count = "${length(var.principals_readonly_access)}"
principals_readonly_access_non_empty = "${signum(length(var.principals_readonly_access))}"
principals_readonly_access_empty = "${signum(length(var.principals_readonly_access)) == 0 ? 1 : 0}"

principals_full_access_count = "${length(var.principals_full_access)}"
principals_full_access_non_empty = "${signum(length(var.principals_full_access))}"
principals_full_access_empty = "${signum(length(var.principals_full_access)) == 0 ? 1 : 0}"

principals_total_count = "${length(var.principals_readonly_access) + length(var.principals_full_access)}"
principals_total_non_empty = "${signum(length(var.principals_readonly_access) + length(var.principals_full_access))}"
principals_total_empty = "${signum(length(var.principals_readonly_access) + length(var.principals_full_access)) == 0 ? 1 : 0}"
}

module "label" {
source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.3.3"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
delimiter = "${var.delimiter}"
attributes = "${var.attributes}"
tags = "${var.tags}"
}

resource "aws_ecr_repository" "default" {
name = "${var.use_fullname == "true" ? module.label.id : module.label.name}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be better to introduce a new var ecr_repository_name because label.name could be insufficient

name = "${var.ecr_repository_name == "" ? module.label.id : var.ecr_repository_name}"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes is not the point of PR

}

resource "aws_ecr_lifecycle_policy" "default" {
repository = "${aws_ecr_repository.default.name}"

policy = <<EOF
{
"rules": [{
"rulePriority": 1,
"description": "Rotate images when reach ${var.max_image_count} images stored",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["${var.stage}"],
"countType": "imageCountMoreThan",
"countNumber": ${var.max_image_count}
},
"action": {
"type": "expire"
}
}]
}
EOF
}

## If roles are empty
## Create default role to provide full access.
## The role can be attached or assumed

data "aws_iam_policy_document" "assume_role" {
count = "${local.principals_total_empty}"

statement {
sid = "EC2AssumeRole"
effect = "Allow"
Expand All @@ -16,199 +67,125 @@ data "aws_iam_policy_document" "assume_role" {
}
}

data "aws_iam_policy_document" "login" {
statement {
sid = "ECRGetAuthorizationToken"
effect = "Allow"
actions = ["ecr:GetAuthorizationToken"]
resource "aws_iam_role" "default" {
count = "${local.principals_total_empty}"
name = "${module.label.id}"
assume_role_policy = "${data.aws_iam_policy_document.assume_role.json}"
}

resources = ["*"]
}
resource "aws_iam_instance_profile" "default" {
count = "${local.principals_total_empty}"
name = "${module.label.id}"
role = "${aws_iam_role.default.name}"
}

data "aws_iam_policy_document" "write" {
## Grant access to default role
data "aws_iam_policy_document" "default_ecr" {
count = "${local.principals_total_empty}"

statement {
sid = "ECRGetAuthorizationToken"
sid = "ECR"
effect = "Allow"

actions = [
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
]

resources = ["${aws_ecr_repository.default.arn}"]
}
}
principals = {
type = "AWS"

data "aws_iam_policy_document" "read" {
statement {
sid = "ECRGetAuthorizationToken"
effect = "Allow"
identifiers = [
"${aws_iam_role.default.arn}",
]
}

actions = [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DescribeImages",
"ecr:BatchGetImage",
]

resources = ["${aws_ecr_repository.default.arn}"]
}
}

data "aws_iam_policy_document" "default_ecr" {
count = "${signum(length(var.roles)) == 1 ? 0 : 1}"
resource "aws_ecr_repository_policy" "default_ecr" {
count = "${local.principals_total_empty}"
repository = "${aws_ecr_repository.default.name}"
policy = "${data.aws_iam_policy_document.default_ecr.json}"
}

## If any roles provided
## Grant access to them

data "aws_iam_policy_document" "empty" {}

data "aws_iam_policy_document" "resource_readonly_access" {
statement {
sid = "ecr"
sid = "ReadonlyAccess"
effect = "Allow"

principals = {
type = "AWS"

identifiers = [
"${aws_iam_role.default.arn}",
"${var.principals_readonly_access}",
]
}

actions = [
"ecr:GetAuthorizationToken",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DescribeImages",
"ecr:BatchGetImage",
]
}
}

data "aws_iam_policy_document" "resource" {
count = "${signum(length(var.roles))}"

data "aws_iam_policy_document" "resource_full_access" {
statement {
sid = "ecr"
sid = "FullAccess"
effect = "Allow"

principals = {
type = "AWS"

identifiers = [
"${data.aws_iam_role.default.*.arn}",
"${var.principals_full_access}",
]
}

actions = [
"ecr:GetAuthorizationToken",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DescribeImages",
"ecr:BatchGetImage",
]
}
}

module "label" {
source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.3.1"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
delimiter = "${var.delimiter}"
attributes = "${var.attributes}"
tags = "${var.tags}"
}
data "aws_iam_policy_document" "resource" {
count = "${local.principals_total_non_empty}"

resource "aws_ecr_repository" "default" {
name = "${var.use_fullname == "true" ? module.label.id : module.label.name}"
source_json = "${local.principals_readonly_access_non_empty ? data.aws_iam_policy_document.resource_readonly_access.json : data.aws_iam_policy_document.empty.json}"
override_json = "${local.principals_full_access_non_empty ? data.aws_iam_policy_document.resource_full_access.json : data.aws_iam_policy_document.empty.json}"
}

resource "aws_ecr_repository_policy" "default" {
count = "${signum(length(var.roles))}"
count = "${local.principals_total_non_empty}"
repository = "${aws_ecr_repository.default.name}"
policy = "${data.aws_iam_policy_document.resource.json}"
}

resource "aws_ecr_repository_policy" "default_ecr" {
count = "${signum(length(var.roles)) == 1 ? 0 : 1}"
repository = "${aws_ecr_repository.default.name}"
policy = "${data.aws_iam_policy_document.default_ecr.json}"
}

resource "aws_iam_policy" "login" {
name = "${module.label.id}${var.delimiter}login"
description = "Allow IAM Users to call ecr:GetAuthorizationToken"
policy = "${data.aws_iam_policy_document.login.json}"
}

resource "aws_iam_policy" "read" {
name = "${module.label.id}${var.delimiter}read"
description = "Allow IAM Users to pull from ECR"
policy = "${data.aws_iam_policy_document.read.json}"
}

resource "aws_iam_policy" "write" {
name = "${module.label.id}${var.delimiter}write"
description = "Allow IAM Users to push into ECR"
policy = "${data.aws_iam_policy_document.write.json}"
}

resource "aws_iam_role" "default" {
count = "${signum(length(var.roles)) == 1 ? 0 : 1}"
name = "${module.label.id}"
assume_role_policy = "${data.aws_iam_policy_document.assume_role.json}"
}

resource "aws_iam_role_policy_attachment" "default_ecr" {
count = "${signum(length(var.roles)) == 1 ? 0 : 1}"
role = "${aws_iam_role.default.name}"
policy_arn = "${aws_iam_policy.login.arn}"
}

resource "aws_iam_role_policy_attachment" "default" {
count = "${signum(length(var.roles)) == 1 ? length(var.roles) : 0}"
role = "${element(var.roles, count.index)}"
policy_arn = "${aws_iam_policy.login.arn}"
}

resource "aws_iam_instance_profile" "default" {
count = "${signum(length(var.roles)) == 1 ? 0 : 1}"
name = "${module.label.id}"
role = "${aws_iam_role.default.name}"
}

resource "aws_ecr_lifecycle_policy" "default" {
repository = "${aws_ecr_repository.default.name}"

policy = <<EOF
{
"rules": [{
"rulePriority": 1,
"description": "Rotate images when reach ${var.max_image_count} images stored",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["${var.stage}"],
"countType": "imageCountMoreThan",
"countNumber": ${var.max_image_count}
},
"action": {
"type": "expire"
}
}]
}
EOF
}
30 changes: 0 additions & 30 deletions output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,3 @@ output "role_arn" {
value = "${join("", aws_iam_role.default.*.arn)}"
description = "Assume Role ARN to get registry access"
}

output "policy_login_name" {
value = "${aws_iam_policy.login.name}"
description = "The IAM Policy name to be given access to login in ECR"
}

output "policy_login_arn" {
value = "${aws_iam_policy.login.arn}"
description = "The IAM Policy ARN to be given access to login in ECR"
}

output "policy_read_name" {
value = "${aws_iam_policy.read.name}"
description = "The IAM Policy name to be given access to pull images from ECR"
}

output "policy_read_arn" {
value = "${aws_iam_policy.read.arn}"
description = "The IAM Policy ARN to be given access to pull images from ECR"
}

output "policy_write_name" {
value = "${aws_iam_policy.write.name}"
description = "The IAM Policy name to be given access to push images to ECR"
}

output "policy_write_arn" {
value = "${aws_iam_policy.write.arn}"
description = "The IAM Policy ARN to be given access to push images to ECR"
}
10 changes: 8 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ variable "use_fullname" {
description = "Set 'true' to use `namespace-stage-name` for ecr repository name, else `name`"
}

variable "roles" {
variable "principals_full_access" {
type = "list"
description = "Principal IAM roles to provide with access to the ECR"
description = "Principal ARN to provide with full access to the ECR"
default = []
}

variable "principals_readonly_access" {
type = "list"
description = "Principal ARN to provide with readonly access to the ECR"
default = []
}

Expand Down