Editing This Question.
I'm using Terraform v0.12.9
and I'm trying to conditionally create bucket policies with the custom policy stored as an IAM policy document.
data "aws_iam_policy_document" "my_policy" {
statement {
sid = "IPALLOW"
effect = "Deny"
actions = ["s3:*"]
resources = [
"arn:aws:s3:::${var.my_bucket}/*",
"arn:aws:s3:::${var.my_bucket}"
]
principals {
type = "AWS"
identifiers = ["*"]
}
condition {
test = "NotIpAddress"
variable = "aws:SourceIp"
values = [
"${concat(var.ip_one,
var.ip_two,
var.ip_three)}"
]
}
}
}
resource "aws_s3_bucket_policy" "my-bucket-policy" {
count = length(var.buckets)
bucket = element(values(var.buckets[count.index]), 0)
policy = (
element(values(var.buckets[count.index]), 0) == "bar_bucket" ?
data.aws_iam_policy_document.my_policy.json : <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "HTTP",
"Effect": "Deny",
"Principal": "*",
"Action": "*",
REST OF POLICY REDACTED
POLICY
)
}
}
However this fails and throws an error
Inappropriate value for attribute "values": element 0: string required.
But when I hardcode the ip addresses in the policy like this,
["100.0.0.100","100.0.0.101","100.0.0.102/24","100.0.0.103/24","100.0.0.104"]
It works.
Is there a way to pass the IP addresses as a variable in the IAM policy document?
I've tried jsonencode
on the values, but it add a bunch of \
which doesn't work.
These are what the variables look like.
variable "ip_one" {
type = list(string)
default = [
"100.0.0.100",
"100.0.0.101"
]
}
variable "ip_two" {
type = list(string)
default = [
"100.0.0.102/24",
"100.0.0.103/24"
]
}
variable "ip_three" {
type = list(string)
default = [
"100.0.0.104"
]
}
CodePudding user response:
As I see it, there are a couple of problems:
- The IPs have to have the subnet mask as well, i.e., you cannot mix IP addresses with and without subnet mask. For example, in
ip_one
you are using100.0.0.100
while inip_two
you have100.0.0.102/24
. - The variables are already lists of strings, so concatenating lists will create a list and then
values
is supposed to be a list as well.
What I would suggest is using a local variable for any value manipulation and then using the local variable in the values
argument. So you could do the following:
locals {
ips = concat(var.ip_one, var.ip_two, var.ip_three)
}
data "aws_iam_policy_document" "my_policy" {
statement {
sid = "IPALLOW"
effect = "Deny"
actions = ["s3:*"]
resources = [
"arn:aws:s3:::${var.my_bucket}/*",
"arn:aws:s3:::${var.my_bucket}"
]
principals {
type = "AWS"
identifiers = ["*"]
}
condition {
test = "NotIpAddress"
variable = "aws:SourceIp"
values = local.ips
}
}
}
Also, if you want to limit access to only a set of IPs or subnets, you should definitely consider adding the subnet mask to IPs in ip_one
and ip_three
. If you do not do that, the access will probably be allowed from the IP addresses you do not want to allow access from.
CodePudding user response:
Can you try something like
values = [
join(",", concat(var.ip_one,
var.ip_two,
var.ip_three))
]