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

feat: ✨ Add support for assume-role block in S3 backend for Terraform #74

Merged
merged 7 commits into from
Nov 11, 2024

Conversation

erikpaasonen
Copy link
Contributor

@erikpaasonen erikpaasonen commented Jul 12, 2024

Proposed changes

Adds support for the assume_role = {} block that is the current syntax for assuming a role for an S3 backend in Terraform.

Issues for these changes

#73

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (changes to code, which do not change application behavior)

Checklist

  • I have filled out this PR template
  • I have read the CONTRIBUTING doc
  • I have added automated tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (README.md, CHANGELOG.md, etc. - if appropriate)

Dependencies and Blockers

Relevant Links

Further comments

Note: this will break compatibility with Terraform v1.1 and below. (The assume-role block was added in v1.2.) For reference, the current version of Terraform is 1.9.

@CLAassistant
Copy link

CLAassistant commented Jul 12, 2024

CLA assistant check
All committers have signed the CLA.

@erikpaasonen
Copy link
Contributor Author

All tests passing locally for me.
image

plugins/terraform/stepper.go Outdated Show resolved Hide resolved
Comment on lines +369 to +372
if interpolatedRoleArn != roleArn {
roleArn = interpolatedRoleArn
b["assume_role"] = fmt.Sprintf("{\"role_arn\"=\"%s\"}", roleArn)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead assignment to roleArn as it's local scope ends at the close of line 374. We always want the interpolated value anyhow.

Suggested change
if interpolatedRoleArn != roleArn {
roleArn = interpolatedRoleArn
b["assume_role"] = fmt.Sprintf("{\"role_arn\"=\"%s\"}", roleArn)
}
if interpolatedRoleArn != roleArn {
b["assume_role"] = fmt.Sprintf("{\"role_arn\"=\"%s\"}", interpolatedRoleArn)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this suggestion is taken, then line 373 will log the wrong i.e. non-interpolated value. the suggestion is the way I originally coded it.

line 370 is what preserves the correct value outside the local scope, and that is being set correctly. so this is really just semantics of how to also log the chosen value (since we want the log entry regardless of the if condition on line 369).

// only track override config if interpolated is different from what user declared
if interpolatedBucket != bucket {
b["bucket"] = interpolatedBucket
bucket = interpolatedBucket
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead assignment of bucket. Scope ends at line 387.

Suggested change
bucket = interpolatedBucket

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto previous comment; the var bucket is logged before the local scope ends.

// only track override config if interpolated is different from what user declared
if interpolatedBucket != bucket {
b["bucket"] = interpolatedBucket
bucket = interpolatedBucket
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead assignment of bucket. Scope ends at line 400.

Suggested change
bucket = interpolatedBucket

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto previous comment; the var bucket is logged before the local scope ends.

// only track override config if interpolated is different from what user declared
if interpolatedPrefix != prefix {
b["prefix"] = interpolatedPrefix
prefix = interpolatedPrefix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead assignment of prefix. Scope ends at line 413

Suggested change
prefix = interpolatedPrefix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto previous comment; the var prefix is logged before the local scope ends.

@@ -59,7 +59,7 @@ func TestGetBackendConfig_ShouldParseAssumeRoleCoreAccountIDMapCorrectly(t *test
}}, ParseTFBackend)

require.Equal(t, S3Backend, mockResult.Type)
require.Equal(t, fmt.Sprintf("arn:aws:iam::%s:role/OrganizationAccountAccessRole", DefaultStubAccountID), mockResult.Config["role_arn"])
require.Contains(t, mockResult.Config["assume_role"], fmt.Sprintf("arn:aws:iam::%s:role/OrganizationAccountAccessRole", DefaultStubAccountID))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is passing, but only because the paramater happens to have the same name for its key at both the deprecated depth and the newer, nested depth. The mock backend uses the deprecated syntax but never tests the newer syntax. It also appears that the parser is not extracting the role arn value from a specific depth during initial ingestion. The regex catches and parses both cases of a role_arn value at

// RoleArn
rRegex, _ := regexp.Compile(`role_arn\s*=\s*"(.+)"`)
roleMatch := rRegex.FindStringSubmatch(s)
if len(roleMatch) > 0 {
backend.S3RoleArn = roleMatch[1]
}

I would suggest mocking both the deprecated syntax and the newer assume_role block as separate tests to validate behavior when encountering either one. This is also more likely to catch regressions for either case if they diverge in the future.

@@ -502,7 +504,7 @@ func TestParseBackend_ShouldParseRoleArnWhenSet(t *testing.T) {
mockResult := ParseTFBackend(fs, logger, "testbackend.tf")

require.Equal(t, S3Backend, mockResult.Type)
require.Equal(t, "stubrolearn", mockResult.S3RoleArn)
require.Equal(t, "stubrolearn", mockResult.AssumeRole.RoleArn)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock input is only using the deprecated syntax without interpolation. It does not validate the newer backend.assume_role.role_arn syntax.

@mbpolan mbpolan merged commit 75d8663 into Optum:main Nov 11, 2024
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants