-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
#667 iam_role parsing before evaluation of other HCL blocks #1807
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a good start! I think the general idea of parsing iam_role
early in the process before others makes sense, but there are a few gotchas/edge cases that this implementation doesn't handle. See the comments below for more details.
config/config_partial.go
Outdated
if flags.IamRole != nil { | ||
terragruntOptions.IamRole = *flags.IamRole | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should check if terragruntOptions.IamRole
is already set or not, since we should prefer to use the CLI passed in option over the local configuration.
config/config_partial.go
Outdated
contextExtensions := EvalContextExtensions{} | ||
flags := terragruntFlags{} | ||
err := decodeHcl(hclFile, filename, &flags, terragruntOptions, contextExtensions) | ||
if err != nil { | ||
return nil, nil, TrackInclude{}, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this parsing here means that we won't honor iam_role
set on parent configurations that are include
d. You'll need to implement a special version of PartialParseConfigFile
that bypasses locals and only parses include
+ iam_role
to handle this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sense, will look in this dirrection
Simplified test for get_aws_account_id
Behaviour with current changes:
So |
config/config.go
Outdated
@@ -545,6 +545,17 @@ func ParseConfigFile(filename string, terragruntOptions *options.TerragruntOptio | |||
return nil, err | |||
} | |||
|
|||
// If IamRole wasn't provided, and if it is config file, try first to decode IamRole | |||
if include == nil && terragruntOptions.IamRole == "" { | |||
iamConfig, err := PartialParseConfigString(configString, terragruntOptions, include, filename, []PartialDecodeSectionType{TerragruntFlags}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the iam_role
param depends on a local
var? Or a dependency
block? Or anything else that hasn't been parsed yet? In other words, do we need to update the docs on parse order to call out any new limitations here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PartialParseConfigString
handles local
and include
, but not dependency
, so yes indeed we need to update the parsing order docs to indicate this.
stderr := bytes.Buffer{} | ||
|
||
// Invoke terragrunt and verify used IAM role | ||
err = runTerragruntCommand(t, fmt.Sprintf("terragrunt init --terragrunt-working-dir %s", TEST_FIXTURE_READ_IAM_ROLE), &stdout, &stderr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this actually try to assume the fake IAM role and lead to a permissions error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and it will fail to create state file with IAM role ID
Moved to draft since this implementation caused more integration tests to fail |
My local issue, the same number of tests don't pass with or without this change |
In the current implementation, it adds a +1 evaluation of HCL code at the beginning, fetching from result It will work in cases of remote state definition but may generate some unexpected output in cases like:
It will print:
|
@yorinasub17 If you're still digging into Terragrunt issues, could you review this one? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates LGTM! I think we are very close. Just a few more nits to address and I think we can get this going.
The side effect of additional parsing of locals is a potential cause for concern, but I think it would actually work out given that I think most configurations would limit the amount of side effects in locals. What is more of a concern is the backward incompatible nature of this feature.
Currently, before this PR, get_aws_account_id
will always return the value based on the original credentials. Now, this will change to the value after iam_role
is assumed. In most use cases, this is probably not a huge issue and could be worked around.
I think where this gets super tricky is if users had a config like the following:
iam_role = "arn:aws:iam::${get_aws_account_id()}:role/terragrunttest"
Currently as implemented, what would happen is that in the initial parse for iam_role
, iam_role
would resolve get_account_id
based on the original credentials, but when it goes through to do the full parse, get_account_id
would now be based on the assumed iam_role
. That means that potentially, the iam_role
could change depending on which stage of parsing it is in.
This probably isn't a big deal for functions like get_account_id
, where the value doesn't change even after assuming the role, but what about the following config?
# Where 333333333 is another account
iam_role = "arn:aws:iam::333333333:role/from-${get_aws_account_id()}"
In this case, get_aws_account_id()
will return 333333333
in the full parse, which means it will assume a different IAM role when it runs terraform.
That said, I think this is fine for now because I feel like the above case will be rare in practice. But it makes me wonder if this is a fundamentally flawed feature, and whether we should consider separating configuration of cloud authentication out of the main terragrunt.hcl
so that it can be parsed without side effects.
@brikis98 any thoughts on the above analysis of the implications here?
config/config.go
Outdated
@@ -545,6 +545,17 @@ func ParseConfigFile(filename string, terragruntOptions *options.TerragruntOptio | |||
return nil, err | |||
} | |||
|
|||
// If IamRole wasn't provided, and if it is config file, try first to decode IamRole | |||
if include == nil && terragruntOptions.IamRole == "" { | |||
iamConfig, err := PartialParseConfigString(configString, terragruntOptions, include, filename, []PartialDecodeSectionType{TerragruntFlags}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PartialParseConfigString
handles local
and include
, but not dependency
, so yes indeed we need to update the parsing order docs to indicate this.
config/config.go
Outdated
// Initial evaluation of configuration to load flags like IamRole which will be used for final parsing | ||
// https://github.com/gruntwork-io/terragrunt/issues/667 | ||
if include == nil && terragruntOptions.IamRole == "" { | ||
iamConfig, err := PartialParseConfigString(configString, terragruntOptions, include, filename, []PartialDecodeSectionType{TerragruntFlags}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if iamConfig.IamRole != "" { | ||
terragruntOptions.IamRole = iamConfig.IamRole | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want this logic in ParseConfigString
, since there are more entrypoints to that function than ParseConfigFile
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, put this in a separate function to make it easier to extend in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh do we also need to parse and set iam_assume_role_duration here?
config/config.go
Outdated
@@ -545,6 +545,18 @@ func ParseConfigFile(filename string, terragruntOptions *options.TerragruntOptio | |||
return nil, err | |||
} | |||
|
|||
// Initial evaluation of configuration to load flags like IamRole which will be used for final parsing | |||
// https://github.com/gruntwork-io/terragrunt/issues/667 | |||
if include == nil && terragruntOptions.IamRole == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to omit the include == nil
check here, as this means it won't handle a config where the iam_role
is defined on the child config that has an include
defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates LGTM! Just had one nit on the function name. I'll kick off a regression build.
Note that before merge, I'd like to make sure @brikis98 has a chance to sanity check the backward incompatible implications.
config/config.go
Outdated
// extractIamRole - extract IAM role details from Terragrunt flags block | ||
func extractIamRole(configString string, terragruntOptions *options.TerragruntOptions, filename string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: Rename to setIAMRole
, to indicate that this function has side effects (modifying attribute on terragruntOptions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build passed and last update LGTM, so only thing remaining is sanity check from Jim!
* Output contains multiple times `uuid1` and `uuid2` because during HCL evaluation each `run_cmd` in `locals` is evaluated multiple times and random argument generated from `uuid()` save cached value under different key each time | ||
* Output contains multiple times `uuid3`, +1 more output comparing to `uuid1` and `uuid2` - because `uuid3` is declared in locals and inputs which add one more evaluation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: are these changes related to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. It's the result of the change in the parsing order.
Oof, you're right, this does feel messy.
Yea, I've been having lots of second thoughts about:
And for that matter, the way we've implemented Auto Init for S3 buckets, DynamoDB tables, etc. They all feel like partial implementations that don't fully solve the problem; they also feel too cloud-specific and are a pain to maintain. I wonder if what we really need is:
But these are all larger changes, prob not super relevant to this PR. For this PR, the key question, I suppose, is how many users combine the
My guess is that 99% of the time, they are used separately, and the intention is (a) assume the specified IAM role and (b) fetch the requested data while authenticated as that IAM role. In the <1% of use cases where the two are combined together, the result will likely be unpredictable. Not sure if our partial parse can detect that and show a warning? If not, then perhaps we document it, merge this PR, and file issues to do the larger clean up mentioned above? |
That makes sense.
Let's move forward with documenting this. @denis256 can you update the docs for the following functions and mention the caveat that the value will change depending on the parsing stage?
The source is here: https://github.com/gruntwork-io/terragrunt/blob/master/docs/_docs/04_reference/built-in-functions.md Separately, I'll go ahead and file an issue capturing the above point: #1840 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs updates LGTM! I'm going to merge this in now given our discussion, and release as backward incompatible so we can better highlight the behavior change.
Updated HCL parsing first to extract
iam_role
and use obtained value in the evaluation of HCL blocksExample:
Before:
After this PR:
Fix for issue: #667