With the following Terraform and aws provider
Terraform v1.1.8
on linux_amd64
Installed hashicorp/aws v4.10.0
And the following code
# S3 Bucket Policy
data "aws_iam_policy_document" "lambda-bucket" {
statement {
effect = "Allow"
actions = [
"s3:*",
]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::${var.account_ids.account_1}:role/Teamcity-fullaccess",
"arn:aws:iam::${var.account_ids.account_2}:role/teamcity-poweruser"
]
}
resources = [
aws_s3_bucket.lambda-bucket.arn,
"${aws_s3_bucket.lambda-bucket.arn}/*",
]
}
}
# Bucket
resource "aws_s3_bucket" "lambda-bucket" {
bucket = "lambdas-${terraform.workspace}"
tags = merge(var.default_tags, local.env_tag, {
Name = "lambdas-${terraform.workspace}"
})
}
resource "aws_s3_bucket_versioning" "lambda-bucket" {
bucket = aws_s3_bucket.lambda-bucket.bucket
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "lambda-bucket" {
bucket = aws_s3_bucket.lambda-bucket.bucket
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_acl" "lambda-bucket" {
bucket = aws_s3_bucket.lambda-bucket.bucket
acl = "private"
}
resource "aws_s3_bucket_policy" "lambda-bucket" {
bucket = aws_s3_bucket.lambda-bucket.id
policy = data.aws_iam_policy_document.lambda-bucket.json
}
I keep getting a notifications saying objects have changed outside of Terraform, which is not true AFAIK
# aws_s3_bucket.lambda-bucket has changed
~ resource "aws_s3_bucket" "lambda-bucket" {
id = "lambdas-dev1"
~ policy = jsonencode(
~ {
~ Statement = [
~ {
~ Principal = {
~ AWS = [
- "arn:aws:iam::xxxx:role/Teamcity-fullaccess",
"arn:aws:iam::yyyy:role/teamcity-poweruser",
"arn:aws:iam::xxxx:role/Teamcity-fullaccess",
]
}
# (3 unchanged elements hidden)
},
]
# (1 unchanged element hidden)
}
)
tags = {
"Environment" = "dev1"
"Name" = "lambdas-dev1"
"Terraform" = "True"
}
# (11 unchanged attributes hidden)
# (3 unchanged blocks hidden)
}
If it worth something, here's my account ids vars
# Account IDs
account_ids = {
"account_1" = "xxxx",
"account_2" = "yyyy"
}
Do I miss something here?
CodePudding user response:
Terraform produces this "Objects have changed outside of Terraform" messaging whenever a provider responds to the "refresh" operation by returning different values than were returned from the most recent infrastructure changes.
In Terraform's architecture, part of the responsibility of a provider is to implement rules for distinguishing between differences that imply a change in functionality -- such as a policy now having a different effect -- and differences that are just different ways to write down the same rule, as seems to be the case in your example.
Remote APIs often allow multiple ways to express the same intent as a concession to usability, and Terraform providers should in principle implement corresponding rules themselves to avoid misreporting this sort of normalization. However, in practice these rules are often not described well in API docs and so provider developers unfortunately learn about them only from feedback about observed behavior of the provider.
I see in the comment thread above that you already opened an issue with the AWS provider team to report te problem, which is what I would've recommended here.
In the meantime you may be able to avoid the noise by reordering your source policy to match the normalized form that the S3 API is returning, though that isn't always possible if e.g. the API is not itself consistent in its normalization (some APIs return different ordering on each request, even if the underlying data didn't change) or if you're constructing the data using a mechanism within Terraform that does not decide a specific order.
If the aws_iam_policy_document
data source has identifiers
specified as being a set of strings rather than a list of strings then you will not be able to override the ordering just by reordering in your configuration, because Terraform sets are inherently unordered. If that's true then you may need to construct the intended IAM policy document directly using the jsonencode
function so that you can control exactly what structure and ordering you'll use, and can therefore match the normalization that the S3 API is performing until the provider is updated to be aware of this normalization rule and handle it automatically.