Check if aws_iam_policy sets policy value from reference#1058
Check if aws_iam_policy sets policy value from reference#1058fionn wants to merge 2 commits intoterraform-linters:masterfrom
Conversation
87396cb to
9c40d79
Compare
I'm not sure how useful this rule is when we're allowing variables. For example, this is also valid when using an |
|
Yeah, it's not perfect, because it doesn't recursively check the source. I did consider checking if the source is a (I also originally considered checking that the My argument for why it's acceptable as-is is that if there's some indirection, the problem sort of lies elsewhere? Not sure it holds up, let me know if you think we need to check all the way down. |
9c40d79 to
801c9d8
Compare
|
The important question is whether this rule is also useful to other users. If the warning can be avoided by using local variables, there may be no incentive to enable this rule. However, I agree that recursive checking is too complex. As a compromise, one possible criterion might be whether the expression can be resolved to a static string, since the data attribute is resolved as an unknown value in TFLint. That said, considering that cases where external files are referenced using functions such as |
I think this would work well.
When I started this I initially wanted to only permit I think we probably do want to permit loading from files in general, since there could be some process producing well-formed policy documents in JSON format that would be valid to read from. That said, I personally don't want to permit reading from files in any Terraform I review, every time I've come across this it would have been better to use a How about, emit an issue if:
That way we permit references and loading from files and so on. (Totally happy to emit an issue on resolving any function call also, which would catch loading from files, if you think that's not too aggressive.) |
|
Going any further than matching on a string or object literal seems too far.
In the vast majority of cases this is preferable but this is probably only achievable with AI code review and not static analysis. A There's also every variation of getting a policy from a remote service: |
I would say it should go further, emit if |
|
There are probably two options:
Hmm, I'm not sure about this. It seems to me that there are no situations where it would be more reasonable to maintain the input type of the |
The aws_iam_policy resource's policy argument takes a string that must match the structure of a JSON-formatted IAM policy document. Often this is done by assigning to the output of jsonencode which is passed some HCL -- however, this doesn't guarantee that the string is well-formed, only that it is JSON, and can result in errors at apply-time. The spirit of this check is to ensure that policy values are from references. In practice, it's anticipated that these will be data.aws_iam_policy_document.foo.json objects, but it also permits locals, resources and data sources of any type.
801c9d8 to
46fb8ea
Compare
|
As far as I can tell, So I opted to try out the second option. With this, we could also consider making the list of permitted functions configurable. |
| } | ||
|
|
||
| // Check if the value is a reference and if so permit it. | ||
| if _, ok := attribute.Expr.(*hclsyntax.ScopeTraversalExpr); ok { |
There was a problem hiding this comment.
JSON syntax is not HCL native syntax, so we should not assume it is hclsyntax expression here.
You can determine whether an expression can be resolved statically by evaluating it as cty.Value.
https://pkg.go.dev/github.com/terraform-linters/tflint-plugin-sdk@v0.24.0/tflint#Runner
|
|
||
| ## How To Fix | ||
|
|
||
| Define an `aws_iam_policy_document` data source and assign its `json` attribute to `policy`. |
There was a problem hiding this comment.
Please add the fixed code shown in the above examples.
| @@ -0,0 +1,94 @@ | |||
| # aws_iam_policy_use_policy_reference | |||
|
|
|||
| Check the source of the value for `policy` in an `aws_iam_policy` to catch values not generated from resources or data sources such as `data.aws_iam_policy_document`. This includes function calls, except those that read from files (`file` and `templatefile`). | |||
There was a problem hiding this comment.
It's a good idea to include examples demonstrating how certain functions or unknown variables are handled exceptionally, and to keep the introductory explanation as concise as possible.
| rule "aws_iam_policy_use_policy_reference" { | ||
| enabled = true | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Since there are no configs specific to this rule, this section can be deleted.
|
|
||
| // Check checks if policy is not referencing an object reference | ||
| func (r *AwsIAMPolicyUsePolicyReference) Check(runner tflint.Runner) error { | ||
| issueMessage := "The policy does not reference an object" |
There was a problem hiding this comment.
I would like to make the message a little clearer. I also would like to avoid overly long messages consisting of multiple sentences, but as it is, it's probably not clear what "object" refers to.
The
aws_iam_policyresource'spolicyargument takes a string that must match the structure of a JSON-formatted IAM policy document. Often this is done by assigning to the output ofjsonencodewhich is passed some HCL -- however, this doesn't guarantee that the string is well-formed, only that it is JSON, and can result in errors at apply-time.The spirit of this check is to ensure that
policyvalues are from references. In practice, it's anticipated that these will bedata.aws_iam_policy_document.foo.jsonobjects, but it also permits locals, resources and data sources of any type.The motivation is that I occasionally come across incorrect (or not obviously correct)
jsonencode(...)inputs in code review, which this would catch automatically.If this seems reasonable, I'll do the same for
aws_iam_role'sassume_role_policyargument.