From d91302fba2f186ea980b048a271a205fbc6267d2 Mon Sep 17 00:00:00 2001 From: vinay-gopalan <86625824+vinay-gopalan@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:27:42 -0700 Subject: [PATCH] Add field `set_namespace_from_token` to Provider configuration (#2070) --- CHANGELOG.md | 1 + internal/consts/consts.go | 1 + internal/provider/meta.go | 6 ++- internal/provider/meta_test.go | 68 ++++++++++++++++++++++++++------ internal/provider/provider.go | 8 ++++ website/docs/index.html.markdown | 4 ++ 6 files changed, 74 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a19c2baf5..828e38084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ FEATURES: * Add support for configuring SAML Auth resources ([#2053](https://github.com/hashicorp/terraform-provider-vault/pull/2053)) * Add support for `custom_metadata` on `vault_namespace`: ([#2033](https://github.com/hashicorp/terraform-provider-vault/pull/2033)) * Add support for `OCSP*` role fields for the cert auth resource: ([#2056](https://github.com/hashicorp/terraform-provider-vault/pull/2056)) +* Add field `set_namespace_from_token` to Provider configuration ([#2070](https://github.com/hashicorp/terraform-provider-vault/pull/2070)) BUGS: * Fix panic when reading `client_secret` from a public oidc client ([#2048](https://github.com/hashicorp/terraform-provider-vault/pull/2048)) diff --git a/internal/consts/consts.go b/internal/consts/consts.go index 909b2c190..4d00b09b9 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -363,6 +363,7 @@ const ( FieldServiceAccountJWT = "service_account_jwt" FieldDisableISSValidation = "disable_iss_validation" FieldPEMKeys = "pem_keys" + FieldSetNamespaceFromToken = "set_namespace_from_token" /* common environment variables */ diff --git a/internal/provider/meta.go b/internal/provider/meta.go index 7651aefc4..230453aaa 100644 --- a/internal/provider/meta.go +++ b/internal/provider/meta.go @@ -314,8 +314,10 @@ func NewProviderMeta(d *schema.ResourceData) (interface{}, error) { namespace = tokenNamespace // set the namespace on the provider to ensure that all child // namespace paths are properly honoured. - if err := d.Set(consts.FieldNamespace, namespace); err != nil { - return nil, err + if v, ok := d.Get(consts.FieldSetNamespaceFromToken).(bool); ok && v { + if err := d.Set(consts.FieldNamespace, namespace); err != nil { + return nil, err + } } } diff --git a/internal/provider/meta_test.go b/internal/provider/meta_test.go index fba0c71a3..dee7fa1e3 100644 --- a/internal/provider/meta_test.go +++ b/internal/provider/meta_test.go @@ -553,13 +553,15 @@ func TestNewProviderMeta(t *testing.T) { } tests := []struct { - name string - d *schema.ResourceData - data map[string]interface{} - wantNamespace string - tokenNamespace string - authLoginNamespace string - wantErr bool + name string + d *schema.ResourceData + data map[string]interface{} + wantNamespace string + tokenNamespace string + authLoginNamespace string + wantErr bool + checkSetSetTokenNamespace bool + wantNamespaceFromToken string }{ { name: "invalid-nil-ResourceData", @@ -627,22 +629,60 @@ func TestNewProviderMeta(t *testing.T) { name: "with-provider-ns-and-auth-login-with-ns", d: pr.TestResourceData(), data: map[string]interface{}{ - consts.FieldNamespace: nsPrefix + "prov-ns-auth-ns", + consts.FieldNamespace: nsPrefix + "prov-ns-prov-ns", consts.FieldSkipGetVaultVersion: true, consts.FieldSkipChildToken: true, consts.FieldAuthLoginUserpass: []map[string]interface{}{ { - consts.FieldNamespace: nsPrefix + "auth-ns-prov-ns", + consts.FieldNamespace: nsPrefix + "auth-ns-auth-ns", consts.FieldMount: consts.MountTypeUserpass, consts.FieldUsername: defaultUser, consts.FieldPassword: defaultPassword, }, }, }, - authLoginNamespace: nsPrefix + "auth-ns-prov-ns", - wantNamespace: nsPrefix + "prov-ns-auth-ns", + authLoginNamespace: nsPrefix + "auth-ns-auth-ns", + wantNamespace: nsPrefix + "prov-ns-prov-ns", wantErr: false, }, + { + // expect token based namespace to be ignored. + name: "set-namespace-from-token-false", + d: pr.TestResourceData(), + data: map[string]interface{}{ + consts.FieldSkipGetVaultVersion: true, + consts.FieldSetNamespaceFromToken: false, + consts.FieldSkipChildToken: true, + }, + tokenNamespace: nsPrefix + "set-ns-from-token-auth-false-ignored", + wantNamespace: nsPrefix + "set-ns-from-token-auth-false-ignored", + checkSetSetTokenNamespace: true, + wantNamespaceFromToken: "", + wantErr: false, + }, + { + // expect token based namespace to be ignored. + name: "set-namespace-from-token-true", + d: pr.TestResourceData(), + data: map[string]interface{}{ + consts.FieldSkipGetVaultVersion: true, + consts.FieldSetNamespaceFromToken: true, + consts.FieldSkipChildToken: true, + consts.FieldAuthLoginUserpass: []map[string]interface{}{ + { + consts.FieldNamespace: nsPrefix + "set-ns-from-token-auth-true", + consts.FieldMount: consts.MountTypeUserpass, + consts.FieldUsername: defaultUser, + consts.FieldPassword: defaultPassword, + }, + }, + }, + authLoginNamespace: nsPrefix + "set-ns-from-token-auth-true", + wantNamespace: nsPrefix + "set-ns-from-token-auth-true", + checkSetSetTokenNamespace: true, + wantNamespaceFromToken: nsPrefix + "set-ns-from-token-auth-true", + wantErr: false, + }, } createNamespace := func(t *testing.T, client *api.Client, ns string) { @@ -748,7 +788,11 @@ func TestNewProviderMeta(t *testing.T) { } if !reflect.DeepEqual(p.client.Namespace(), tt.wantNamespace) { - t.Errorf("NewProviderMeta() got ns = %v, want ns %v", p.client.Namespace(), tt.wantNamespace) + t.Errorf("NewProviderMeta() got ns = %q, want ns %q", p.client.Namespace(), tt.wantNamespace) + } + + if tt.checkSetSetTokenNamespace && tt.wantNamespaceFromToken != tt.d.Get(consts.FieldNamespace).(string) { + t.Errorf("NewProviderMeta() got ns = %q, want ns %q", tt.d.Get(consts.FieldNamespace).(string), tt.wantNamespaceFromToken) } if client.Token() == "" { diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 3b7a38fc4..b6f05fe10 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -175,6 +175,14 @@ func NewProvider( DefaultFunc: schema.EnvDefaultFunc("VAULT_NAMESPACE", ""), Description: "The namespace to use. Available only for Vault Enterprise.", }, + consts.FieldSetNamespaceFromToken: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "In the case where the Vault token is for a specific namespace " + + "and the provider namespace is not configured, use the token namespace " + + "as the root namespace for all resources.", + }, "headers": { Type: schema.TypeList, Optional: true, diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index e5d96e002..1bee9419c 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -214,6 +214,10 @@ variables in order to keep credential information out of the configuration. * `use_root_namespace` - (Optional) Authenticate to the root Vault namespace. Conflicts with `namespace`. +* `set_namespace_from_token` -(Optional) Defaults to `true`. In the case where the Vault token is + for a specific namespace and the provider namespace is not configured, use the token namespace + as the root namespace for all resources. + * `skip_get_vault_version` - (Optional) Skip the dynamic fetching of the Vault server version. Set to `true` when the */sys/seal-status* API endpoint is not available. See [vault_version_override](#vault_version_override) for related info