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

Add support to perform semantic version comparisons against Vault's server version #1426

Merged
merged 16 commits into from
Aug 19, 2022

Conversation

vinay-gopalan
Copy link
Contributor

@vinay-gopalan vinay-gopalan commented Apr 22, 2022

This PR adds a mechanism that performs semantic version comparison against Vault’s target version to determine whether certain features are available in the current Vault client. This mechanism allows the TFVP to have knowledge of Vault's version, supported paths and version-specific schemas, allowing us to further improve upon the codebase's overall architecture.

In this PR, we demonstrate how the semantic version comparison mechanism can be used to determine whether Auth and Secret Engines can be remounted. Mount Migration is a newly available feature as of Vault 1.10.0, and hence this feature is only enabled for clients with the required version or above.

This PR also includes wrapper functions that can be used with new resources to determine whether said resources are available within the current version of Vault. If the user attempts to create a resource using this wrapper function and it does not meet the necessary version requirements, the resource shall fail to create.

Features that this PR adds semantic version comparison to:

  • Kubernetes Secret Backend resource (1.11)
  • Kubernetes Secret Backend Role resource (1.11)
  • Managed Keys resource (1.10)
  • Mount migration for AWS (1.10)

Output from acceptance testing:

$ make testacc TESTARGS='-run=TestAccAWSSecretBackend_remount'
=== RUN   TestAccAWSSecretBackend_remount
--- PASS: TestAccAWSSecretBackend_remount (2.90s)
PASS

=== RUN   TestAccKubernetesSecretBackend
--- PASS: TestAccKubernetesSecretBackend (4.38s)
PASS

=== RUN   TestAccKubernetesSecretBackendRole
--- PASS: TestAccKubernetesSecretBackendRole (4.52s)
PASS

=== RUN   TestManagedKeys
--- PASS: TestManagedKeys (4.92s)
PASS

@vinay-gopalan vinay-gopalan marked this pull request as draft April 22, 2022 23:00
@vinay-gopalan vinay-gopalan changed the base branch from main to VAULT-5928/release-adaptive-mount-migration April 22, 2022 23:05
@vinay-gopalan vinay-gopalan changed the base branch from VAULT-5928/release-adaptive-mount-migration to main August 18, 2022 20:02
@vinay-gopalan vinay-gopalan changed the title POC: Semantic Version Check for Adaptive Mount Migration Add support to perform semantic version comparisons against Vault's server version Aug 18, 2022
@vinay-gopalan vinay-gopalan marked this pull request as ready for review August 18, 2022 21:49
Copy link
Contributor

@swenson swenson left a comment

Choose a reason for hiding this comment

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

Awesome! This is super useful.

vault/provider.go Outdated Show resolved Hide resolved
internal/semver/semver.go Outdated Show resolved Hide resolved
internal/semver/semver.go Outdated Show resolved Hide resolved
vault/provider.go Outdated Show resolved Hide resolved
vault/provider.go Outdated Show resolved Hide resolved
internal/semver/semver.go Outdated Show resolved Hide resolved
@github-actions github-actions bot added size/L and removed size/XL labels Aug 19, 2022
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
Copy link
Member

Choose a reason for hiding this comment

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

I was looking in the testing framework to see if there was anything to support checking whether a resource is being destroyed or not between test steps, but I didn't find anything. Do you know if there might be a way to accomplish that? It may be a useful ability to have going forward as we utilize the feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. I've been meaning to add this check in the Managed keys tests as well, but I think one way would be if Vault has a UUID for the resource then we can check if the UUIDs are different after re-creation. Other than that, I haven't come up with a better solution as of yet unfortunately

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this test, I had to check my Vault logs to confirm that a mount migration had occurred successfully

Copy link
Member

Choose a reason for hiding this comment

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

There is a CheckDestroy field in resource.TestCase that I've seen used elsewhere, though I think that's after the test and not between steps.

You may be able to use TestCheckNoResourceAttr to check that the old mount doesn't exist in the state at least?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are correct! CheckDestroy runs after the test completes, so unfortunately we can't use that in this case

I looked into trying to make TestCheckNoResourceAttr work. The function checks whether certain state keys exist in the TF state for a particular resource. In this case, while the mount does change (expressed in this resource as a path change), the path key isn't being deleted or removed, so it still exists in the TF state (albeit with a different value). In this case unfortunately, I don't think that would work exactly the way we want it to

I'll definitely keep looking into this as an improvement to our testing since this is also needed in a few other places!

In the future I think we also plan to refactor all secret and auth engines be mounted solely via the vault_mount resource (currently some resources mount the engine as well as the config; including the resource we are talking about: https://github.com/hashicorp/terraform-provider-vault/blob/main/vault/resource_aws_secret_backend.go#L119). This might help check the TF state for deleted mounts in a cleaner way.

Copy link
Contributor

@fairclothjm fairclothjm left a comment

Choose a reason for hiding this comment

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

👍

internal/semver/semver.go Show resolved Hide resolved
@github-actions github-actions bot added size/XL and removed size/L labels Aug 19, 2022
@vinay-gopalan vinay-gopalan merged commit c3dcbc3 into main Aug 19, 2022
@vinay-gopalan vinay-gopalan deleted the VAULT-5392/adaptive-mount-migration branch August 19, 2022 21:11
// This function can be used to perform semantic version comparisons
// to conditionally enable features, or to resolve any diffs in the TF
// state based on the Vault version.
func GreaterThanOrEqual(ctx context.Context, client *api.Client, minVersionString string) (bool, string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should be doing the initial version check in provider.NewProviderMeta instead. This would allow the provider to abort early if it encounters an error getting the Vault version. It would also make it easier to use in the resource code since we would no longer have to handle the error. We would store the version.Version in the ProviderMeta so there would be no need to return the vault version string.

If we make minVersionString a version.Version the caller would be responsible for handling any parse errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@benashz I'm glad you brought this up! I initially thought of this approach as well, and the main drawback that came to my mind (which I remember we briefly chatted about) was in the case where users use the same TF instance to configure multiple versions of Vault. In that case, the approach of storing the current Vault version to the ProviderMeta would explicitly disallow the use of the TFVP in those kind of scenarios, and I wanted to get your take on the larger implications/architecture before going down that route. I do agree that the current implementation adds an overhead of multiple calls to the same endpoint

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we are okay here since each instance of the provider corresponds to a single Vault server instance.

Copy link
Contributor

Choose a reason for hiding this comment

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

By instance of the provider, I am referring to each provider{} block defined; terraform will spawn a separate process for each block defined.

/*
Vault version constants
*/
VaultVersion11 = "1.11.0"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest making these version.Version variables instead, then there is no need to reparse them for every API request.

// This function can be used to perform semantic version comparisons
// to conditionally enable features, or to resolve any diffs in the TF
// state based on the Vault version.
func GreaterThanOrEqual(ctx context.Context, client *api.Client, minVersionString string) (bool, string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like we will be calling the API for every Version check, this seems like a unnecessary increase in the overall the number of requests per operation. It is very unlikely that the vault server version will change during a run of Terraform.

@vinay-gopalan vinay-gopalan added this to the 3.9.0 milestone Sep 1, 2022
marcboudreau pushed a commit to marcboudreau/terraform-provider-vault that referenced this pull request Nov 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants