Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inline_policy configuration blocks using file() func not generating specific diff #20961

Closed
celik0311 opened this issue Sep 20, 2021 · 8 comments
Labels
service/iam Issues and PRs that pertain to the iam service.

Comments

@celik0311
Copy link

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform CLI and Terraform AWS Provider Version

terraform -v
Terraform v1.0.2
on linux_amd64

  • provider registry.terraform.io/hashicorp/aws v3.50.0
  • provider registry.terraform.io/hashicorp/template v2.2.0

Your version of Terraform is out of date! The latest version
is 1.0.7. You can update by downloading from https://www.terraform.io/downloads.html

Affected Resource(s)

aws_iam_role

Terraform Configuration Files

Please include all Terraform configurations required to reproduce the bug. Bug reports without a functional reproduction may be closed without investigation.

resource "aws_iam_role" "foo" {
  inline_policy {
    name   = "baz"
    policy = file("${path.module}/baz.json")
  }
  name                 = "foo"

}

Expected Behavior

When a change to baz.json occurs a diff should be generated displaying that change, and only that change.

Actual Behavior

The terraform plan generated a diff that deletes and recreates the entire inline policy not just modifying the single change.

Steps to Reproduce

  1. create an iam role with an inline_policy block referencing a policy as a JSON document inside a file. Ensure use of the file() function.
  2. Apply this
  3. Make a change to the policy contained in the referenced file
  4. plan the change

Important Factoids

I wonder if this has something to do with the use of the file() function when referencing the inline_policy.

@github-actions github-actions bot added needs-triage Waiting for first response or review from a maintainer. service/iam Issues and PRs that pertain to the iam service. labels Sep 20, 2021
@justinretzolk
Copy link
Member

Hey @celik0311 👋 Thanks for getting this filed! By chance, can you provide the (redacted as needed) output that you're seeing? I'd like to get a better idea, so that I can compare it against what I may see while reproducing this.

@justinretzolk justinretzolk added waiting-response Maintainers are waiting on response from community or contributor. and removed needs-triage Waiting for first response or review from a maintainer. labels Sep 20, 2021
@github-actions github-actions bot removed the waiting-response Maintainers are waiting on response from community or contributor. label Sep 20, 2021
@celik0311
Copy link
Author

resource definition

resource "aws_iam_role" "foo" {

  description = "foo Role"
  inline_policy {
    name   = "baz"
    policy = file("${path.module}/roles/foo/inline_policies/baz.json")
  }
  name                 = "foo"

}

initial apply

...

No changes. Your infrastructure matches the configuration.

Your configuration already matches the changes detected above. If you'd like to update the Terraform state to match, create and apply a refresh-only plan:
  terraform apply -refresh-only

update anything in the inline policy

$ git diff
diff --git a/roles/foo/inline_policies/baz.json b/roles/foo/inline_policies/baz.json
index 5111ddf..0cf52d4 100644
--- a/roles/foo/inline_policies/baz.json
+++ b/roles/foo/inline_policies/baz.json
@@ -6,7 +6,7 @@
             ],
             "Effect": "BLAH",
             "Resource": "*",
-            "Sid": "VisualEditor0"
+            "Sid": "VisualEditor01"
         }
     ],
     "Version": "2012-10-17"

plan changes

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_iam_role.foo will be updated in-place
  ~ resource "aws_iam_role" "foo" {
        id                    = "foo"
        name                  = "foo"
        tags                  = {}
        # (10 unchanged attributes hidden)

      + inline_policy {
          + name   = "baz"
          + policy = jsonencode(
                {
                  + Statement = [
                      + {
                          + Action   = [
                              + "BLAH",
                            ]
                          + Effect   = "BLAH"
                          + Resource = "*"
                          + Sid      = "VisualEditor01"
                        },
                    ]
                  + Version   = "2012-10-17"
                }
            )
        }
      - inline_policy {
          - name   = "baz" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action   = [
                              - "BLAH",
                            ]
                          - Effect   = "BLAH"
                          - Resource = "*"
                          - Sid      = "VisualEditor0"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

I see that it indicates 1 to change, but what I am confused about is the output generated. My interpretation of that is that terraform will create an inline policy then delete one. My expected behavior was just an update to the existing inline policy since I only modified it.

@justinretzolk
Copy link
Member

justinretzolk commented Sep 21, 2021

Hey @celik0311, thanks for providing that. I did a bit of reproducing and found the same behavior. To test further, I switched away from using the file() function and instead used the jsonencode() function with the policy defined inline and noticed the same behavior.

After seeing that, I took a look at the codebase to see how this resource is configured and found that the policy argument of the inline_policy block is a TypeString, which explains the behavior you're seeing. The whole policy is pulled in as a JSON encoded string, so a change to any given line will always show the full diff like you're seeing.

I was able to finally get around this by switching away from using inline_policy and instead using the aws_iam_role_policy resource with its policy defined in a aws_iam_policy_document data source in combination with the aws_iam_role resource you're already using. When using this method, the diff from Terraform showed as you might expect:

Terraform will perform the following actions:

  # aws_iam_role_policy.baz will be updated in-place
  ~ resource "aws_iam_role_policy" "baz" {
        id     = "foo:foo_policy"
        name   = "foo_policy"
      ~ policy = jsonencode(
          ~ {
              ~ Statement = [
                  ~ {
                      ~ Effect   = "Deny" -> "Allow"
                        # (3 unchanged elements hidden)
                    },
                ]
                # (1 unchanged element hidden)
            }
        )
        # (1 unchanged attribute hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

@celik0311
Copy link
Author

Thank you for the thorough and quick investigation. Is there any technical reason for not supporting this behavior for inline_policy? I ask because part of my IAM SDLC involves passing policies to the AWS Access Analyzer for validation, which need to be in JSON format.

@celik0311
Copy link
Author

I did just test that I can use file() with aws_iam_role_policy and get the desired result.

@justinretzolk
Copy link
Member

@celik0311 you just beat me to it! I did the same, but used the source_json argument of the aws_iam_policy_document data source with the file() function and had the same (desired) results. I think that's more a result of aws_iam_role_policy's handling than the data source though, given the output I posted above and your findings.

As far as why the behavior is different, I'm not quite sure without digging further into it. I assume it's a difference in how the resources are handled, but frankly I'm not strong enough a Go developer to give an authoritative answer at this point in time. That said, given that we've figured out a path forward that gives the desired results, I'm going to go ahead and close this issue out for now. If you feel I've done this in error, or have further questions, please do let me know.

@celik0311
Copy link
Author

Nope, @justinretzolk, thanks again for your help. I really appreciate it.

@github-actions
Copy link

github-actions bot commented Jun 7, 2022

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
service/iam Issues and PRs that pertain to the iam service.
Projects
None yet
Development

No branches or pull requests

2 participants