how to identify an element in a collection value - amazon-web-services

I am getting this error messages when i run terragrunt apply.I need to be able to specify each element when creating SQS and DeadLetterQueue with the policy.I am unsure how to fix this issue.I want to find a way to reference individual DLQ directly with corresponding SQS to create the required resources
resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy" {
for_each = toset(var.sqs_queue_names)
queue_url = aws_sqs_queue.CloudTrail_SQS[each.key].id
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "AllowSQSInvocation",
"Effect": "Allow",
"Principal": {"AWS":"*"},
"Action": "sqs:*",
"Resource": "${aws_sqs_queue.CloudTrail_SQS[each.key].arn}"
resource "aws_sqs_queue_policy" "CloudTrail_SQS_DLQ"{
for_each = toset(var.dead_queue_names)
queue_url = aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].id
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "DLQ Policy",
"Effect": "Allow",
"Principal": {"AWS":"*"},
"Action": "sqs:*",
"Resource": "${aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].arn}
Error Messages:
Error: Invalid index
│
│ on iam.tf line 3, in resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy":
│ 3: queue_url = aws_sqs_queue.CloudTrail_SQS[each.key].id
│ ├────────────────
│ │ aws_sqs_queue.CloudTrail_SQS is object with 2 attributes
│ │ each.key is "CloudTrail_SQS_Management_Event"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on iam.tf line 15, in resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy":
│ 15: "Resource": "${aws_sqs_queue.CloudTrail_SQS[each.key].arn}",
│ ├────────────────
│ │ aws_sqs_queue.CloudTrail_SQS is object with 2 attributes
│ │ each.key is "CloudTrail_SQS_Data_Event"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on iam.tf line 15, in resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy":
│ 15: "Resource": "${aws_sqs_queue.CloudTrail_SQS[each.key].arn}",
│ ├────────────────
│ │ aws_sqs_queue.CloudTrail_SQS is object with 2 attributes
│ │ each.key is "CloudTrail_SQS_Management_Event"
│
│ The given key does not identify an element in this collection value.

I refactored your entire code, as any changes will cascade to more errors. In your case, the best way to deal with your requirement is to use map, not list or set. You don't have to make your input variables a map if you don't want, though it would be easier. But keeping your input variables as they are, you can create local.sqs_dlq_map and use that:
locals {
sqs_dlq_map = zipmap(var.sqs_queue_names, var.dead_queue_names)
}
resource "aws_sqs_queue" "CloudTrail_SQS"{
for_each = local.sqs_dlq_map
name = each.key
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].arn
maxReceiveCount = 2 #var.max_receive_count
})
#tags = var.default_tags
}
resource "aws_sqs_queue" "CloudTrail_SQS_DLQ"{
for_each = local.sqs_dlq_map
name = each.value
#tags = var.default_tags
}
resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy" {
for_each = local.sqs_dlq_map
queue_url = aws_sqs_queue.CloudTrail_SQS[each.key].id
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "AllowSQSInvocation",
"Effect": "Allow",
"Principal": {"AWS":"*"},
"Action": "sqs:*",
"Resource": "${aws_sqs_queue.CloudTrail_SQS[each.key].arn}"
}]
}
POLICY
}
resource "aws_sqs_queue_policy" "CloudTrail_SQS_DLQ"{
for_each = local.sqs_dlq_map
queue_url = aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].id
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "DLQ Policy",
"Effect": "Allow",
"Principal": {"AWS":"*"},
"Action": "sqs:*",
"Resource": "${aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].arn}"
}]
}
POLICY
}

Related

Granting cloudtrails access to kms keys in terraform

My first attempt at doing this resulted in a circular reference:
resource "aws_kms_key" "cloudtrails-key" {
description = "KMS Master Key for trails logs"
key_usage = "ENCRYPT_DECRYPT"
customer_master_key_spec = "SYMMETRIC_DEFAULT"
deletion_window_in_days = 30
is_enabled = true
enable_key_rotation = false
policy = data.aws_iam_policy_document.cloudtrails-key-policy.json
multi_region = true
tags = {
ManagedBy = "terraform"
Name = "${var.project_name}-${var.environment}-${var.aws_account_id}-cloudtrails-key"
Environment = var.environment
Usage = "monitoring"
}
}
data "aws_iam_policy_document" "cloudtrails-key-policy" {
statement {
principals {
type = "Service"
identifiers = [ "cloudtrail.amazonaws.com" ]
}
actions = [
"kms:CallerAccount",
"kms:EncryptionAlgorithm",
"kms:EncryptionContext:*",
"kms:EncryptionContextKeys",
"kms:RequestAlias",
"kms:ViaService"
]
resources = [ aws_kms_key.cloudtrails-key.arn ]
condition {
test = "ForAnyValue:StringLike"
variable = "aws:SourceArn"
values = toset([for k, v in var.all_account_ids : "arn:aws:cloudtrail:*:${v}:trail/full-cloudtrails"])
}
}
}
As I couldn't determine how to remove the circular reference, I decided to try using grants instead:
resource "aws_kms_grant" "cloudtrails-key-grant" {
depends_on = [ aws_kms_key.cloudtrails-key ]
for_each = var.all_account_ids
name = "${each.key}-cloudtrails-key-grant"
key_id = aws_kms_key.cloudtrails-key.key_id
grantee_principal = "arn:aws:cloudtrail::${each.value}:trail/full-cloudtrails"
operations = [ "Encrypt" ]
}
var.all_account_ids refers to a map of account names and account IDs.
I then updated the aws_kms_key block to remove the policy argument. However, this resulted instead in the following output on apply:
Terraform v1.3.8
on linux_amd64
aws_kms_grant.cloudtrails-key-grant["users"]: Creating...
aws_kms_grant.cloudtrails-key-grant["root"]: Creating...
aws_kms_grant.cloudtrails-key-grant["dev"]: Creating...
aws_kms_grant.cloudtrails-key-grant["shared"]: Creating...
aws_kms_grant.cloudtrails-key-grant["monitoring"]: Creating...
aws_cloudtrail.full-cloudtrails: Modifying... [id=full-cloudtrails]
...
aws_kms_grant.cloudtrails-key-grant["users"]: Still creating... [2m50s elapsed]
aws_kms_grant.cloudtrails-key-grant["monitoring"]: Still creating... [2m50s elapsed]
╷
│ Error: updating CloudTrail Trail (full-cloudtrails): InsufficientEncryptionPolicyException: Insufficient permissions to access S3 bucket full-cloudtrails or KMS key arn:aws:kms:us-east-1:703617067304:key/mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b.
│
│ with aws_cloudtrail.full-cloudtrails,
│ on monitoring.tf line 1, in resource "aws_cloudtrail" "full-cloudtrails":
│ 1: resource "aws_cloudtrail" "full-cloudtrails" {
│
╵
╷
│ Error: creating KMS Grant for Key (mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b): InvalidArnException: ARN is not valid: arn:aws:cloudtrail:us-east-1:323924548037:trail/full-cloudtrails
│
│ with aws_kms_grant.cloudtrails-key-grant["root"],
│ on security.tf line 19, in resource "aws_kms_grant" "cloudtrails-key-grant":
│ 19: resource "aws_kms_grant" "cloudtrails-key-grant" {
│
╵
╷
│ Error: creating KMS Grant for Key (mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b): InvalidArnException: ARN is not valid: arn:aws:cloudtrail:us-east-1:739800733271:trail/full-cloudtrails
│
│ with aws_kms_grant.cloudtrails-key-grant["shared"],
│ on security.tf line 19, in resource "aws_kms_grant" "cloudtrails-key-grant":
│ 19: resource "aws_kms_grant" "cloudtrails-key-grant" {
│
╵
╷
│ Error: creating KMS Grant for Key (mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b): InvalidArnException: ARN is not valid: arn:aws:cloudtrail:us-east-1:703617067304:trail/full-cloudtrails
│
│ with aws_kms_grant.cloudtrails-key-grant["monitoring"],
│ on security.tf line 19, in resource "aws_kms_grant" "cloudtrails-key-grant":
│ 19: resource "aws_kms_grant" "cloudtrails-key-grant" {
│
╵
╷
│ Error: creating KMS Grant for Key (mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b): InvalidArnException: ARN is not valid: arn:aws:cloudtrail:us-east-1:457407591303:trail/full-cloudtrails
│
│ with aws_kms_grant.cloudtrails-key-grant["dev"],
│ on security.tf line 19, in resource "aws_kms_grant" "cloudtrails-key-grant":
│ 19: resource "aws_kms_grant" "cloudtrails-key-grant" {
│
╵
╷
│ Error: creating KMS Grant for Key (mrk-c0a4616ba4f74ae9b5ac4ecd1f96e95b): InvalidArnException: ARN is not valid: arn:aws:cloudtrail:us-east-1:158889104371:trail/full-cloudtrails
│
│ with aws_kms_grant.cloudtrails-key-grant["users"],
│ on security.tf line 19, in resource "aws_kms_grant" "cloudtrails-key-grant":
│ 19: resource "aws_kms_grant" "cloudtrails-key-grant" {
│
╵
I tried adding the region (though I would prefer multi-region), taking off the trail name after the slash, using wildcards for region, but everything resulted in the above invalid ARN exception.
I was curious to know if anyone has any working recipes for granting cloudtrails encryption access to a KMS key, as I'm unsure what I'm doing wrong with either method (policy or grant)
The solution for the cyclical reference was to broaden the resource scope to all keys, and not just the one key. This was done on all examples in AWS documentation. I also had to add the default key policy offered by AWS otherwise I got a warning that I would be locking myself out.
The Default Key Policy can be found documented here. The specific key policy required for CloudTrail is found here. Using these two resources, the final working configuration is below:
data "aws_iam_policy_document" "cloudtrail-key-policy" {
statement {
principals {
type = "Service"
identifiers = [ "cloudtrail.amazonaws.com" ]
}
actions = [
"kms:DescribeKey",
"kms:GenerateDataKey*"
]
resources = [ "*" ]
condition {
test = "ForAnyValue:StringLike"
variable = "kms:EncryptionContext:aws:cloudtrail:arn"
values = toset([for k, v in var.all_account_ids : "arn:aws:cloudtrail:*:${v}:trail/${k}-full-cloudtrail"])
}
condition {
test = "ForAnyValue:StringLike"
variable = "aws:SourceArn"
values = toset([for k, v in var.all_account_ids : "arn:aws:cloudtrail:*:${v}:trail/${k}-full-cloudtrail"])
}
}
statement {
principals {
type = "AWS"
identifiers = [ "arn:aws:iam::${var.aws_account_id}:role/terraform-${var.environment}" ]
}
actions = [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
]
resources = [ "*" ]
}
statement {
principals {
type = "AWS"
identifiers = [ "arn:aws:iam::${var.aws_account_id}:root" ]
}
actions = [ "kms:*" ]
resources = [ "*" ]
}
}
Additionally, no grants were needed as we're doing this for a service. According to the documentation, service ARNs are excluded:
The grantee principal can be any AWS principal, including an AWS
account (root), an IAM user, an IAM role, a federated role or user, or
an assumed role user. The grantee principal can be in the same account
as the KMS key or a different account. However, the grantee principal
cannot be a service principal, an IAM group, or an AWS organization
The above text can be found here
Hopefully this helps future readers with the same issue.
EDIT: Updated with final working config

how to create an aws lambda function from a file uploaded in s3

I have uploaded a zip file to a private aws s3 bucket, which has the following contents:
zipped filename: 'data.zip'
__init__.py
lambda_handler.py (where 'handler' is the name of the function)
data.zip (same zip file as the parent)
now i want to create a terraform aws lambda function:
the way the s3 bucket was created
resource "aws_s3_bucket" "bucket_for_lambda" {
bucket = "bucket-for-lambda"
acl = "private"
lifecycle {
prevent_destroy = true
}
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
resource "aws_iam_policy" "iam_policy_lambda" {
name = "iam-policy-lambda"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::${aws_s3_bucket.bucket_for_lambda.arn}/*"
}
]
}
EOF
}
After creating the bucket i have uploaded the zipped filed above manually to the bucket using aws cli.
Now when i try to create a lambda function:
resource "aws_lambda_function" "lambda_test" {
function_name = "lambda-test"
s3_bucket = aws_s3_bucket.bucket_for_lambda.id
s3_key = "data.zip"
role = aws_iam_role.iam_role_for_lambda.arn
depends_on = [aws_iam_role.iam_role_for_lambda]
handler = "lambda_handler.handler"
runtime = "python3.7"
}
resource "aws_iam_role" "iam_role_for_lambda" {
name = "iam-role-for-lambda"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
policy_arn = aws_iam_policy.iam_policy_lambda.arn
role = aws_iam_role.iam_role_for_lambda.name
}
I know the lambda codes above does not track changes with source_code_hash,and that is not creating an aws lambda layer nor creating aws_s3_bucket_object so terraform can take care of uploading the file but what i want to understand is why, with the simple configuration above, i am seeing this error when i do terraform apply (which does not return anything wrong) but afterwards when i want to apply the changes by typing yes:
aws_lambda_function.merchant_tracker_version_one: Creating...
╷
│ Error: error creating Lambda Function (1): ValidationException:
│ status code: 400, request id: SOME-ID
│
│ with aws_lambda_function.lambda_test,
│ on main.tf line 994, in resource "aws_lambda_function" "lambda_test":
│ 994: resource "aws_lambda_function" "lambda_test" {
Any help would be much appreciated, i already spent two hours trying to google or stackoverflow the solution... still failing!

Terraform 'aws_secretsmanager_secret' pass arn error: Invalid template interpolation value

I have a Lambda which will read a secret from Secret Manager, they all managed by Terraform.
So in Terraform I have a definition for this secret:
resource "aws_secretsmanager_secret" "example" {
name = "example"
}
and for Lambda, I have attached a permission to get the secret:
resource "aws_iam_role_policy" "example_role_policy" {
name = "example-role-policy"
role = aws_iam_role.example_lambda_role.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
.....(other needed permissions)
},
{
"Sid": "GetDatabaseSecret",
"Effect":"Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "${local.secret_arn}"
}
]
}
POLICY
}
I have secret_arn defined in variables:
locals{
secret_arn = "arn:aws:secretsmanager:::us-east-1:${local.account_number}:secret:${aws_secretsmanager_secret.example}-*"
}
When I apply Terraform, it gave me error:
Error: Invalid template interpolation value
on ..\..\xxx\terraform\variables.tf line 39, in locals:
39: secret_arn = "arn:aws:secretsmanager:::us-east-1:${local.account_number}:secret:${aws_secretsmanager_secret.example}-*"
|----------------
| aws_secretsmanager_secret.example is object with 12 attributes
Cannot include the given value in a string template: string required.
I tried to replae *with ?????? in the secrect_arn but still not working, couldn't find anything useful online, might someone be able to help? Many thanks.
Your local.secret_arn should be using ${aws_secretsmanager_secret.example.name}-*", not ${aws_secretsmanager_secret.example}-*".
But the easiest way to get the arn in your policy it would be simply:
resource "aws_iam_role_policy" "example_role_policy" {
name = "example-role-policy"
role = aws_iam_role.example_lambda_role.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
.....(other needed permissions)
},
{
"Sid": "GetDatabaseSecret",
"Effect":"Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "${aws_secretsmanager_secret.example.arn}"
}
]
}
POLICY
}
I could be wrong, but I think you're overthinking it.
Try this:
secret_arn = aws_secretsmanager_secret.example.arn
Remember you're setting the account ID and region when you setup the AWS provider with:
provider "aws" {
alias = "ireland" # Your is in america but you get what I mean :)
version = "2.70.0"
region = "eu-west-1"
...

Send message to encrypted SQS queue from Lambda

I have a AWS Lambda function that needs to send messages to an encrypted SQS queue. At one point I got it working that my AWS Lambda function could send messages to this encrypted SQS queue. After I got it working I made some adjustments to the permissions so they are more specific. Then it suddenly stopped working even after I reverted back to the really broad permissions.
Now I always get this following error:
KMS.AccessDeniedException: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.
My CMK has the following policy and ONLY allows in it:
{
"Sid": "Allow specific lambda to use this key",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "arn:aws:lambda:XXXXXX:function:XXXXXX"
}
I redacted the resource but I triple checked the ARN and it is correct.
My Lambda function has the following policy attached to it:
{
"Action": "sqs:*",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "kms:*",
"Resource": "*",
"Effect": "Allow"
},
Shouldn't this be enough for my Lambda to send a message to this SQS queue? Like I mentioned above at one point this worked than I tried to restrict the policies on my Lambda and then it stopped working even after I changed it back.
What am I missing here? I'm not sure what else I could change and why it worked and then it stopped working...
Edit
Permissions that seemed to work and now doesn't:
CMK policy
{
"Sid": "Allow AWS Lambda to use this key",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "*"
}
Lambda Policy
{
"Action": "sqs:*",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "kms:*",
"Resource": "*",
"Effect": "Allow"
}
Edit 2
There has to be something in play that I don't understand because this doesn't behave predictable...
I made the following changes with CDK:
First change:
IAM Statement Changes
┌───┬──────────┬────────┬─────────────────────┬──────────────────────────────────────────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────┼────────┼─────────────────────┼──────────────────────────────────────────────────────────────────┼───────────┤
│ + │ * │ Allow │ kms:GenerateDataKey │ AWS:${lambda---------------------------------------/ServiceRole} │ │
└───┴──────────┴────────┴─────────────────────┴──────────────────────────────────────────────────────────────────┴───────────┘
Result: I can send messages to the SQS queue again
Second change:
IAM Statement Changes
┌───┬──────────┬────────┬─────────────────────┬──────────────────────────────────────────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────┼────────┼─────────────────────┼──────────────────────────────────────────────────────────────────┼───────────┤
│ - │ * │ Allow │ kms:GenerateDataKey │ AWS:${lambda---------------------------------------/ServiceRole} │ │
├───┼──────────┼────────┼─────────────────────┼──────────────────────────────────────────────────────────────────┼───────────┤
│ + │ * │ Allow │ kms:* │ AWS:${lambda---------------------------------------/ServiceRole} │ │
└───┴──────────┴────────┴─────────────────────┴──────────────────────────────────────────────────────────────────┴───────────┘
Result: I can't send messages to the SQS queue anymore ?!? Why?
Third change:
IAM Statement Changes
┌───┬──────────┬────────┬─────────────────────┬──────────────────────────────────────────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────┼────────┼─────────────────────┼──────────────────────────────────────────────────────────────────┼───────────┤
│ - │ * │ Allow │ kms:* │ AWS:${lambda---------------------------------------/ServiceRole} │ │
├───┼──────────┼────────┼─────────────────────┼──────────────────────────────────────────────────────────────────┼───────────┤
│ + │ * │ Allow │ kms:GenerateDataKey │ AWS:${lambda---------------------------------------/ServiceRole} │ │
└───┴──────────┴────────┴─────────────────────┴──────────────────────────────────────────────────────────────────┴───────────┘
Result: I still can't send messages to the SQS queue anymore ?!? What is happening here? It is the same policy state as with the first change....

How do I create an IAM role in Terraform for Amazon ECR?

Following on the back of this answer, I'm trying to create an aws_iam_role that allows for access to ECR. However, when I define the following:
resource "aws_iam_role" "jenkins_ecr_role" {
name = "JenkinsECRRole"
assume_role_policy = <<END_OF_POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecr.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
END_OF_POLICY
}
I get the error:
Error: Error creating IAM Role JenkinsECRRole:
MalformedPolicyDocument: Invalid principal in policy: "SERVICE":"*"
It looks like ecr.amazonaws.com is a valid principal according to the AWS documentation. What am I doing wrong?
It seems that this question has not been fully answered so I'll try to give an example on how I added ecr for my gitlab-runner ec2 instance. First off the ec2 instance needs a iam_instance_profile which it seems that you already have. Second: You need the assume-role so that the instance can assume the role of the service.
Notice am given access to all the resources not just an specific one(you can adjusted as needed)
The role
resource "aws_iam_role" "role" {
name = "${local.env}-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": ["ec2.amazonaws.com"]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
The policy to allow access to ECR
resource "aws_iam_policy" "policy" {
name = "${local.env}-ecr-access-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ecr:*",
]
Effect = "Allow"
Resource = "*"
},
]
})
}
The attachment of the policy to the role
resource "aws_iam_policy_attachment" "attach" {
name = "${local.env}-attach"
roles = ["${aws_iam_role.role.name}"]
policy_arn = "${aws_iam_policy.policy.arn}"
}
And finally the profile the EC2 will need
resource "aws_iam_instance_profile" "profile" {
name = "${local.env}-gitlab-runner-instance-profile"
role = aws_iam_role.role.name
}
The EC2 instance
resource "aws_instance" "ec2" {
ami = "ami-06c94f9acb4ba21b2"
instance_type = "t2.small"
associate_public_ip_address = true
key_name = "<key_name>"
subnet_id = <subnet>
iam_instance_profile = aws_iam_instance_profile.profile.name
vpc_security_group_ids = ["<security_group>"]
tags = {
Environment = "dev"
}
}
I think you are trying to give EC2 permission to access the ECR. For this, you need to create IAM policy for ECR and create IAM role for EC2 and attach the role with the policy.
Please refer to this code:
resource "aws_iam_role" "role" {
name = "test-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "policy" {
name = "test-policy"
description = "A test policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecr:*",
"cloudtrail:LookupEvents"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "test-attach" {
role = "${aws_iam_role.role.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
Hope, it helps.
You need to attach a below mentioned manual policy to your IAM role.
resource "aws_iam_role_policy" "role_policy" {
name = "${aws_iam_role.role.name}"
role = "${aws_iam_role.role.id}"
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "new statement",
"Effect": "Allow",
"Principal": {
"AWS": "<IAM-ROLE-ARN>"
},
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart"
]
}
]
}
EOF
}
Your role is created for a Service that will need the policy to use other resources, I'm not sure if this helps.
You need to create a role that something will be able to assume, ec2, sagemaker, s3, something. ECR does not assume a role as it's just a registry.
For example, I have a Sagemaker instance:
resource "aws_iam_role" "sagemaker_model" {
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "sagemaker.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
Then that instance needs permission to use other Resource (ECR):
resource "aws_iam_policy" "ecr" {
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecr:*"
],
"Resource": [
"*"
]
}
]
}
EOF
}
Then I attach that policy to the previous role:
resource "aws_iam_role_policy_attachment" "model_attach_ecr" {
role = aws_iam_role.sagemaker_model.name
policy_arn = aws_iam_policy.ecr.arn
}
Although ECR has a specific property that it has its own access policy, you will need to allow that the previously created role can access the specific container registry by creating one aws_ecr_repository_policy:
resource "aws_ecr_repository_policy" "policy" {
repository = <aws_ecr_repository.repo.name>
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "new statement",
"Effect": "Allow",
"Principal": {
"AWS": "${aws_iam_role.sagemaker_model.arn}"
},
"Action": [
"ecr:*"
]
}
]
}
EOF
}
In this one, you will need to replace <aws_ecr_repository.repo.name> by the actual repository name.
I hope this helps.