Noticed that each terraform plan shows this change:
Terraform will perform the following actions: # aws_iam_role.search_index_lambda will be updated in-place ~ resource "aws_iam_role" "search_index_lambda" { id = "search_index_lambda" ~ managed_policy_arns = [ - "arn:aws:iam::[CENSORED]:policy/opensearch-domain-access-policy", # (3 unchanged elements hidden) ] name = "search_index_lambda" tags = {} # (8 unchanged attributes hidden) } # aws_iam_role_policy_attachment.AWSLambdaVPCAccessExecutionRole will be created + resource "aws_iam_role_policy_attachment" "AWSLambdaVPCAccessExecutionRole" { + id = (known after apply) + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + role = "search_index_lambda" }
This is because we use both managed_policy_arns field in "aws_iam_role" as well as "aws_iam_role_policy_attachment" resource.
When reading state, terraform doesn't know that managed_policy_arns list is not exhaustive and shows the diff when encountered value added by aws_iam_role_policy_attachment.
Deciding to use either managed_policy_arns or "aws_iam_role_policy_attachment", solves the issue. I chose the latter (better flexibility at the cost of verbosity)