I write a policy that allows specific actions on secrets starts with the word project1. How can I add another condition for example project2to this policy?
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"secretsmanager:*"
],
"Effect": "Allow",
"Resource": "*",
"Condition": {
"StringLike": {
"secretsmanager:Name": "project1-*"
}
}
},
{
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:GetResourcePolicy",
"secretsmanager:DeleteSecret",
"secretsmanager:PutSecretValue"
],
"Effect": "Allow",
"Resource": "*",
"Condition": {
"StringLike": {
"secretsmanager:SecretId": "arn:aws:secretsmanager:${aws_region}:${aws_account_id}:secret:project1-*"
}
}
}
]
}
You don't have to write 2 different policy statement for this, instead you can use something like this.
Hope this will help.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "secretsmanager:*",
"Effect": "Allow",
"Resource": "*",
"Condition": {
"StringLike": {
"secretsmanager:SecretId": [
"arn:aws:secretsmanager:${aws_region}:${aws_account_id}:secret:project1-*",
"arn:aws:secretsmanager:${aws_region}:${aws_account_id}:secret:project2-*"
]
}
}
}
]
}
Related
I'm creating an s3 bucket using terraform and need to add a bucket policy to it, to whitelist a bunch of IP addresses.
resource "aws_s3_bucket" "foo-bucket" {
bucket = "foobar-bucket"
}
resource "aws_s3_bucket_policy" "foo-policy" {
bucket = "foobar-bucket"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "HTTP",
"Effect": "Deny",
"Principal": "*",
"Action": "*",
"Resource": [
"arn:aws:s3:::foobar-bucket/*",
"arn:aws:s3:::foobar-bucket"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
},
{
"Sid": "IPAllow",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::foobar-bucket/*",
"arn:aws:s3:::foobar-bucket"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"${join("\", \"", concat(var.foo_ip,
var.bar_ip,
var.foobar_ip))}"
]
},
"Bool": {
"aws:ViaAWSService": "true"
}
}
}
]
}
POLICY
}
The issue I have here is that while var.foo_ip and var.bar_ip are a single IP address, var.foobar_ip is an IP address range. 10.0.0.0 - 10.0.0.200
I don't want to have to write the IP address out 200 times, like
variable "foobar_ip" {
type = list(string)
default = [
"10.0.0.0",
"10.0.0.1",
"10.0.0.2"
]
}
All the way to 200
Is there a way to pass in this IP range so that the required range is populated?.
You can create a locals block.
locals {
cidr = "10.0.0.0/24"
ip_addresses = [ for host_number in range(0, 201) : cidrhost(local.cidr, host_number) ]
}
And then your policy becomes
"Sid": "IPAllow",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::foobar-bucket/*",
"arn:aws:s3:::foobar-bucket"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"${join("\", \"", concat(var.foo_ip,
var.bar_ip,
local.ip_addresses))}"
I have created resources for log_group for list of given job names
resource "aws_cloudwatch_log_group" "logGroups" {
count = length(var.jobnames)
name = format("/aws/lambda/%s", format(local.function_name_format, var.jobnames[count.index]))
retention_in_days = 7
}
and now for the each log resource i am creating an iam policy
resource "aws_iam_policy" "base_iam_policy" {
count = length(var.jobnames)
name = format(local.base_iam_policy_name_format, var.jobnames[count.index])
path = "/"
description = "Base IAM policy for creating a lambda"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"${element(aws_cloudwatch_log_group.logGroups.*.arn, count.index)}*"
]
},
{
"Action": [
"cloudwatch:PutMetricData",
"cloudwatch:GetMetricData",
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "${var.region}"
}
}
}
]
}
EOF
}
The issue is that for each BASE_IAM_POLICY, the resource for CreateLogStream is same. Looks like
in this "${element(aws_cloudwatch_log_group.logGroups.*.arn, count.index)}*" count is not getting incremented ?
Honestly, this seems like a bug in terraform. In the meantime I'd recommend indexing the elements directly, like the following
"${aws_cloudwatch_log_group.logGroups[count.index].arn}*"
This question already has answers here:
MalformedPolicyDocument error when creating policy via terraform
(2 answers)
Closed 3 years ago.
I am trying to create a lambda role and attach policies to it so it can start and stop ec2 instance. I will be triggering the lambda using cloudwatch.
I am getting this error:
"Error: Error creating IAM Role lambdaRole: MalformedPolicyDocument: JSON strings must not have leading spaces
status code: 400, request id: d6a86c41-6601-43af-9040-81f6e6a76ec8
on iam.tf line 11, in resource "aws_iam_role" "lambdaRole":
11: resource "aws_iam_role" "lambdaRole" {"
terraform {
backend "s3" {
region = "us-west-2"
bucket = "gitlegionbucket"
key = "ec2/terraform.tfstate"
dynamodb_table = "tf-state-lock"
}
}
resource "aws_iam_role" "lambdaRole" {
name = "lambdaRole"
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"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:Start*",
"ec2:Stop*"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach-policies" {
role = "${aws_iam_role.lambdaRole.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
I was also facing the same error. I have directly copied the code from the question.
The way it worked was for me was to start the { i.e the start of the policy after the EOF line immediately without any spaces.
resource "aws_iam_role" "lambdaRole" {
name = "lambdaRole"
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"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:Start*",
"ec2:Stop*"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach-policies" {
role = "${aws_iam_role.lambdaRole.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
terraform output:
aws_iam_role.lambdaRole: Creating...
aws_iam_role.lambdaRole: Creation complete after 2s [id=lambdaRole]
aws_iam_role_policy_attachment.attach-policies: Creating...
aws_iam_role_policy_attachment.attach-policies: Creation complete after 1s [id=lambdaRole-20191107141649610400000001]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Alright, I found a solution to this problem. I moved the jsons into different files and I just referred to those files instead.
like this, policy = "${file("lambda-policy.json")}"
and this I have in "lambda-policy.json" :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StartInstances",
"logs:",
"ec2:StopInstances"
],
"Resource": ""
}
]
}
I have a simple module that's something like this:
module "EncryptionKeys" {
source = "../../../../Modules/KeyGenerator"
item_list = ["${module.static_variables.item_list}"]
account_id = "${module.static_variables.account_id}"
key_alias_suffix = "a-suffix"
key_administrator_role = "${data.aws_iam_role.admins.name}"
key_user_suffix = "some-other-suffix"
}
Here is the key resource within the module:
resource "aws_kms_key" "key" {
count = "${length(var.item_list)}"
description = "${var.description}"
policy = "${data.aws_iam_policy_document.key_document.json}"
enable_key_rotation = "${var.enable_key_rotation}"
}
The module itself is making an AWS IAM role/policy with the following statement:
statement {
sid = "Allow use of the key for users"
effect = "Allow"
principals {
identifiers =
["arn:aws:iam::${var.account_id}:role/${var.key_administrator_role}", "${element(split(".",var.item_list[count.index]),0)}-${var.key_user_suffix}"]
type = "AWS"
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = ["*"]
}
The problem? When I view the successful terraform plan, item_list is parsed correctly according to the element, but it's only ever the same value. i.e. if I have item_list defined as:
item_list = ["a.blah", "b.foo", "c.bar", "d.foobar"]
there will be four instances of the relevant resources, the correct split will occur on the ".", but all will be named for "a".
"{
"Version": "2012-10-17",
"Id": "key=consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Action": "kms:*",
"Resource": "*",
"Principal": {
"AWS": "arn:aws:iam::123456789:role/Admins"
}
},
{
"Sid": "Allow attachment of persistent resources for admin",
"Effect": "Allow",
"Action": [
"kms:RevokeGrant",
"kms:ListGrants",
"kms:CreateGrant"
],
"Resource": "*",
"Principal": {
"AWS": "arn:aws:iam::123456789:role/Admins"
},
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
},
{
"Sid": "Allow use of the key for users",
"Effect": "Allow",
"Action": [
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:DescribeKey",
"kms:Decrypt"
],
"Resource": "*",
"Principal": {
"AWS": [
"a-stg-role",
"arn:aws:iam::123456789:role/Admins"
]
}
},
{
"Sid": "Allow attachment of persistent resources for users",
"Effect": "Allow",
"Action": [
"kms:RevokeGrant",
"kms:ListGrants",
"kms:CreateGrant"
],
"Resource": "*",
"Principal": {
"AWS": [
"a-stg-role",
"arn:aws:iam::123456789:role/Admins"
]
},
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}"
Am I doing something fundamentally wrong with count/count.index here? Why won't it loop item_list, and why does it always seem to get the same value?
You specify the count on the resource key, but that does not mean it is available for your aws_iam_policy_document.
Try to include the count in the aws_iam_policy_document, e.g.
data "aws_iam_policy_document" "key_document" {
count = "${length(var.item_list)}"
# rest of template ....
}
Then reference the policy list from the key resource using the count in the key resource: policy = "${element(data.aws_iam_policy_document.key_document.*.json, count.index)}"
I have a user group which we use for one of our environments in AWS.
We are trying to limit access of that group only to specific S3 bucket.
So, I created a policy as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::staging"
}
]
}
If I use AWS policy simulator, all shows as expected (at least looks like it).
But, through the app, that uses the API key of a user in this group I am getting access denied when I upload a file.
What am I doing wrong?
This gives the same result
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": [
"arn:aws:s3:::staffila-staging",
"arn:aws:s3:::staffila-staging/*"
]
}
]
}
Use this policy this will work.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::staging"]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": ["arn:aws:s3:::staging/*"]
}
]
}