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 PKI EST configuration support #2246

Merged
merged 11 commits into from
Jun 4, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ FEATURES:
* Add support for new WIF fields in `vault_gcp_secret_backend`. Requires Vault 1.17+. *Available only for Vault Enterprise* ([#2249](https://github.com/hashicorp/terraform-provider-vault/pull/2249)).
* Add support for new WIF fields in `vault_aws_auth_backend_client`. Requires Vault 1.17+. *Available only for Vault Enterprise* ([#2243](https://github.com/hashicorp/terraform-provider-vault/pull/2243)).
* Add support for new WIF fields in `vault_azure_secret_backend`. Requires Vault 1.17+. *Available only for Vault Enterprise* ([#2250](https://github.com/hashicorp/terraform-provider-vault/pull/2250))
* Add new data source and resource `vault_pki_secret_backend_config_est`. Requires Vault 1.16+. *Available only for Vault Enterprise* ([#2246](https://github.com/hashicorp/terraform-provider-vault/pull/2246))

IMPROVEMENTS:
* return a useful error when delete fails for the `vault_jwt_auth_backend_role` resource: ([#2232](https://github.com/hashicorp/terraform-provider-vault/pull/2232))
Expand Down
8 changes: 8 additions & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,14 @@ const (
FieldDelegatedAuthAccessors = "delegated_auth_accessors"
FieldPluginVersion = "plugin_version"
FieldUseMSGraphAPI = "use_microsoft_graph_api"
FieldEnabled = "enabled"
FieldDefaultMount = "default_mount"
FieldDefaultPathPolicy = "default_path_policy"
FieldLabelToPathPolicy = "label_to_path_policy"
FieldAuthenticators = "authenticators"
FieldEnableSentinelParsing = "enable_sentinel_parsing"
FieldAuditFields = "audit_fields"
FieldLastUpdated = "last_updated"

/*
common environment variables
Expand Down
165 changes: 165 additions & 0 deletions vault/data_source_pki_secret_backend_config_est.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package vault

import (
"context"
"errors"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/vault/api"
)

func pkiSecretBackendConfigEstDataSource() *schema.Resource {
return &schema.Resource{
Description: "Reads Vault PKI EST configuration",
ReadContext: provider.ReadContextWrapper(readPKISecretBackendConfigEst),
Schema: map[string]*schema.Schema{
consts.FieldBackend: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Path where PKI engine is mounted",
},
consts.FieldEnabled: {
Type: schema.TypeBool,
Computed: true,
Description: "Is the EST feature enabled",
},
consts.FieldDefaultMount: {
Type: schema.TypeBool,
Computed: true,
Description: "Is this mount providing the cluster's default EST mount",
},
consts.FieldDefaultPathPolicy: {
Type: schema.TypeString,
Computed: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this marked as Computed? If we don't set the value in the config, does Vault return a default?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I just realized this is a data source so please disregard. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries, but that is the reason on FieldAuditFields within the resource Computed is set, we get back a default set of values from Vault if not set.

Description: "The behavior of the default_mount when enabled",
},
consts.FieldLabelToPathPolicy: {
Type: schema.TypeMap,
Computed: true,
Description: "A pairing of EST label to the configured EST behavior for it",
},
consts.FieldAuthenticators: {
Type: schema.TypeList,
Computed: true,
Description: "Lists the mount accessors EST should delegate authentication requests towards",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cert": {
Type: schema.TypeMap,
Optional: true,
Description: "The accessor and cert_role properties for cert auth backends",
},
"userpass": {
Type: schema.TypeMap,
Optional: true,
Description: "The accessor property for user pass auth backends",
},
},
},
},
consts.FieldEnableSentinelParsing: {
Type: schema.TypeBool,
Computed: true,
Description: "Are fields from the provided CSR parsed out for Sentinel policies",
},
consts.FieldAuditFields: {
Type: schema.TypeList,
Computed: true,
Description: "Fields parsed from the CSR that appear in the audit and can be used by sentinel policies",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
consts.FieldLastUpdated: {
Type: schema.TypeString,
Computed: true,
Description: "A read-only timestamp representing the last time the configuration was updated",
},
},
}
}

func readPKISecretBackendConfigEst(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
if err := verifyPkiEstFeatureSupported(meta); err != nil {
return diag.FromErr(err)
}

client, err := provider.GetClient(d, meta)
if err != nil {
return diag.FromErr(fmt.Errorf("failed getting client: %w", err))
}

backend := d.Get(consts.FieldBackend).(string)
path := pkiSecretBackendConfigEstPath(backend)

if err := readEstConfig(ctx, d, client, path); err != nil {
return diag.FromErr(err)
}

return nil
}

func readEstConfig(ctx context.Context, d *schema.ResourceData, client *api.Client, path string) error {
resp, err := client.Logical().ReadWithContext(ctx, path)
if err != nil {
return fmt.Errorf("error reading from Vault: %w", err)
}
if resp == nil {
return fmt.Errorf("got nil response from Vault from path: %q", path)
}

d.SetId(path)

keyComputedFields := []string{
consts.FieldEnabled,
consts.FieldDefaultMount,
consts.FieldDefaultPathPolicy,
consts.FieldLabelToPathPolicy,
consts.FieldEnableSentinelParsing,
consts.FieldAuditFields,
consts.FieldLastUpdated,
}

for _, k := range keyComputedFields {
if fieldVal, ok := resp.Data[k]; ok {
if err := d.Set(k, fieldVal); err != nil {
return fmt.Errorf("failed setting field [%s] with val [%s]: %w", k, fieldVal, err)
}
}
}

if authenticators, authOk := resp.Data[consts.FieldAuthenticators]; authOk {
if err := d.Set(consts.FieldAuthenticators, []interface{}{authenticators}); err != nil {
return fmt.Errorf("failed setting field [%s] with val [%s]: %w", consts.FieldAuthenticators, authenticators, err)
}
}

return nil
}

// verifyPkiEstFeatureSupported verifies that we are talking to a Vault enterprise edition
// and its version 1.16.0 or higher, returns nil if the above is met, otherwise an error
func verifyPkiEstFeatureSupported(meta interface{}) error {
currentVersion := meta.(*provider.ProviderMeta).GetVaultVersion()

minVersion := provider.VaultVersion116
if !provider.IsAPISupported(meta, minVersion) {
return fmt.Errorf("feature not enabled on current Vault version. min version required=%s; "+
"current vault version=%s", minVersion, currentVersion)
}

if !provider.IsEnterpriseSupported(meta) {
return errors.New("feature requires Vault Enterprise")
}
return nil
}

func pkiSecretBackendConfigEstPath(backend string) string {
return strings.Trim(backend, "/") + "/config/est"
}
52 changes: 52 additions & 0 deletions vault/data_source_pki_secret_backend_config_est_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/terraform-provider-vault/testutil"
)

func TestAccDataSourcePKISecretConfigEst(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-pki-backend")
dataName := "data.vault_pki_secret_backend_config_est.test"
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() {
testutil.TestAccPreCheck(t)
testutil.TestEntPreCheck(t)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion116)
},
Steps: []resource.TestStep{
{
// Note this is more thoroughly tested within TestAccPKISecretBackendConfigEst_basic
// we don't want to start having test failures if Vault changes default values.
Config: testPKISecretEmptyEstConfigDataSource(backend),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataName, consts.FieldBackend, backend),
resource.TestCheckResourceAttrSet(dataName, consts.FieldEnabled),
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
resource.TestCheckResourceAttrSet(dataName, consts.FieldDefaultMount),
resource.TestCheckResourceAttrSet(dataName, consts.FieldEnableSentinelParsing),
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
resource.TestCheckResourceAttrSet(dataName, consts.FieldLastUpdated),
),
},
},
})
}

func testPKISecretEmptyEstConfigDataSource(path string) string {
return fmt.Sprintf(`
resource "vault_mount" "test" {
path = "%s"
type = "pki"
description = "PKI secret engine mount"
}

data "vault_pki_secret_backend_config_est" "test" {
backend = vault_mount.test.path
}`, path)
}
8 changes: 8 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ var (
Resource: UpdateSchemaResource(raftAutopilotStateDataSource()),
PathInventory: []string{"/sys/storage/raft/autopilot/state"},
},
"vault_pki_secret_backend_config_est": {
Resource: UpdateSchemaResource(pkiSecretBackendConfigEstDataSource()),
PathInventory: []string{"/pki/config/est"},
},
"vault_pki_secret_backend_issuer": {
Resource: UpdateSchemaResource(pkiSecretBackendIssuerDataSource()),
PathInventory: []string{"/pki/issuer/{issuer_ref}"},
Expand Down Expand Up @@ -583,6 +587,10 @@ var (
Resource: UpdateSchemaResource(pkiSecretBackendConfigClusterResource()),
PathInventory: []string{"/pki/config/cluster"},
},
"vault_pki_secret_backend_config_est": {
Resource: UpdateSchemaResource(pkiSecretBackendConfigEstResource()),
PathInventory: []string{"/pki/config/est"},
},
"vault_pki_secret_backend_config_urls": {
Resource: UpdateSchemaResource(pkiSecretBackendConfigUrlsResource()),
PathInventory: []string{"/pki/config/urls"},
Expand Down
Loading