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(pki): Add resource for cluster configuration #1949

Merged
merged 6 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ BUGS:
* Handle graceful destruction of resources when approle is deleted out-of-band ([#2142](https://github.com/hashicorp/terraform-provider-vault/pull/2142)).

FEATURES:
* Add support for PKI Secrets Engine cluster configuration. Requires Vault 1.13+ ([#1949](https://github.com/hashicorp/terraform-provider-vault/pull/1949)).
* Add support for `skip_import_rotation` and `skip_static_role_import_rotation` in `ldap_secret_backend_static_role` and `ldap_secret_backend` respectively. Requires Vault 1.16+ ([#2128](https://github.com/hashicorp/terraform-provider-vault/pull/2128)).
* Improve logging to track full API exchanges between the provider and Vault ([#2139](https://github.com/hashicorp/terraform-provider-vault/pull/2139))

Expand Down
1 change: 1 addition & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ const (
FieldSecretID = "secret_id"
FieldWrappingToken = "wrapping_token"
FieldWithWrappedAccessor = "with_wrapped_accessor"
FieldAIAPath = "aia_path"

/*
common environment variables
Expand Down
4 changes: 4 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,10 @@ var (
Resource: UpdateSchemaResource(pkiSecretBackendConfigCAResource()),
PathInventory: []string{"/pki/config/ca"},
},
"vault_pki_secret_backend_config_cluster": {
Resource: UpdateSchemaResource(pkiSecretBackendConfigClusterResource()),
PathInventory: []string{"/pki/config/cluster"},
},
"vault_pki_secret_backend_config_urls": {
Resource: UpdateSchemaResource(pkiSecretBackendConfigUrlsResource()),
PathInventory: []string{"/pki/config/urls"},
Expand Down
187 changes: 187 additions & 0 deletions vault/resource_pki_secret_backend_config_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package vault

import (
"context"
"fmt"
"log"
"regexp"
"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/terraform-provider-vault/util"
)

var pkiSecretBackendFromConfigClusterRegex = regexp.MustCompile("^(.+)/config/cluster$")

func pkiSecretBackendConfigClusterResource() *schema.Resource {
return &schema.Resource{
CreateContext: provider.MountCreateContextWrapper(pkiSecretBackendConfigClusterCreate, provider.VaultVersion113),
ReadContext: provider.ReadContextWrapper(pkiSecretBackendConfigClusterRead),
UpdateContext: pkiSecretBackendConfigClusterUpdate,
DeleteContext: pkiSecretBackendConfigClusterDelete,
Importer: &schema.ResourceImporter{
StateContext: func(_ context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
id := d.Id()
if id == "" {
return nil, fmt.Errorf("no path set for import, id=%q", id)
}

parts := strings.Split(util.NormalizeMountPath(id), "/")
if err := d.Set("backend", parts[0]); err != nil {
return nil, err
}

return []*schema.ResourceData{d}, nil
},
},

Schema: map[string]*schema.Schema{
consts.FieldBackend: {
Viper61 marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Full path where PKI backend is mounted.",
// standardise on no beginning or trailing slashes
StateFunc: func(v interface{}) string {
return strings.Trim(v.(string), "/")
},
},
consts.FieldPath: {
Type: schema.TypeString,
Optional: true,
Description: "Path to the cluster's API mount path.",
},
consts.FieldAIAPath: {
Type: schema.TypeString,
Optional: true,
Description: "Path to the cluster's AIA distribution point.",
},
},
}
}

func pkiSecretBackendConfigClusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, e := provider.GetClient(d, meta)
if e != nil {
return diag.FromErr(e)
}

backend := d.Get(consts.FieldBackend).(string)
path := fmt.Sprintf("%s/config/cluster", backend)

resp, err := client.Logical().ReadWithContext(ctx, path)
if err != nil {
return diag.Errorf("error reading cluster config at %s, err=%s", path, err)
}

if resp == nil {
return diag.Errorf("no cluster config found at path %s", path)
}

d.SetId(path)

return pkiSecretBackendConfigClusterUpdate(ctx, d, meta)
}

func pkiSecretBackendConfigClusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, e := provider.GetClient(d, meta)
if e != nil {
return diag.FromErr(e)
}

path := d.Id()

fields := []string{
consts.FieldPath,
consts.FieldAIAPath,
}

var patchRequired bool
data := map[string]interface{}{}
for _, k := range fields {
if d.HasChange(k) {
data[k] = d.Get(k)
patchRequired = true
}
}

if patchRequired {
_, err := client.Logical().WriteWithContext(ctx, path, data)
if err != nil {
return diag.Errorf("error writing data to %q, err=%s", path, err)
}
}

return pkiSecretBackendConfigClusterRead(ctx, d, meta)
}

func pkiSecretBackendConfigClusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, e := provider.GetClient(d, meta)
if e != nil {
return diag.FromErr(e)
}

path := d.Id()
if path == "" {
return diag.Errorf("no path set, id=%q", d.Id())
}

// get backend from full path
backend, err := pkiSecretBackendFromConfigCluster(path)
if err != nil {
return diag.FromErr(err)
}

log.Printf("[DEBUG] Reading %s from Vault", path)
resp, err := client.Logical().ReadWithContext(ctx, path)
if err != nil {
return diag.Errorf("error reading from Vault: %s", err)
}

if resp == nil {
d.SetId("")

return nil
}

// set backend and issuerRef
if err := d.Set(consts.FieldBackend, backend); err != nil {
return diag.FromErr(err)
}

fields := []string{
consts.FieldPath,
consts.FieldAIAPath,
}

for _, k := range fields {
if err := d.Set(k, resp.Data[k]); err != nil {
return diag.Errorf("error setting state key %q for cluster config, err=%s",
k, err)
}
}

return nil
}

func pkiSecretBackendConfigClusterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return nil
}

func pkiSecretBackendFromConfigCluster(path string) (string, error) {
if !pkiSecretBackendFromConfigClusterRegex.MatchString(path) {
return "", fmt.Errorf("no backend found")
}
res := pkiSecretBackendFromConfigClusterRegex.FindStringSubmatch(path)
if len(res) != 2 {
return "", fmt.Errorf("unexpected number of matches (%d) for backend", len(res))
}
return res[1], nil
}
70 changes: 70 additions & 0 deletions vault/resource_pki_secret_backend_config_cluster_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

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 TestPkiSecretBackendConfigCluster_basic(t *testing.T) {
backend := acctest.RandomWithPrefix("pki-root")
resourceType := "vault_pki_secret_backend_config_cluster"
resourceName := resourceType + ".test"

clusterPath := "http://127.0.0.1:8200/v1/pki"
clusterAiaPath := "http://127.0.0.1:8200/v1/pki"

resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() {
testutil.TestAccPreCheck(t)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion113)
},
CheckDestroy: testCheckMountDestroyed(resourceType, consts.MountTypePKI, consts.FieldBackend),
Steps: []resource.TestStep{
{
Config: testPkiSecretBackendConfigCluster(backend, "", ""),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, consts.FieldBackend, backend),
resource.TestCheckResourceAttr(resourceName, consts.FieldPath, ""),
resource.TestCheckResourceAttr(resourceName, consts.FieldAIAPath, ""),
),
},
{
Config: testPkiSecretBackendConfigCluster(backend, clusterPath, clusterAiaPath),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, consts.FieldBackend, backend),
resource.TestCheckResourceAttr(resourceName, consts.FieldPath, clusterPath),
resource.TestCheckResourceAttr(resourceName, consts.FieldAIAPath, clusterAiaPath),
),
},
testutil.GetImportTestStep(resourceName, false, nil),
},
})
}

func testPkiSecretBackendConfigCluster(path, clusterPath string, clusterAiaPath string) string {
return fmt.Sprintf(`
resource "vault_mount" "test" {
path = "%s"
type = "pki"
description = "PKI secret engine mount"
default_lease_ttl_seconds = 8640000
max_lease_ttl_seconds = 8640000
}

resource "vault_pki_secret_backend_config_cluster" "test" {
backend = vault_mount.test.path
path = "%s"
aia_path = "%s"
}`, path, clusterPath, clusterAiaPath)
}
58 changes: 58 additions & 0 deletions website/docs/r/pki_secret_backend_config_cluster.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
layout: "vault"
page_title: "Vault: vault_pki_secret_backend_config_cluster resource"
sidebar_current: "docs-vault-resource-pki-secret-backend-config-cluster"
description: |-
Sets the cluster configuration on an PKI Secret Backend for Vault.
---

# vault\_pki\_secret\_backend\_config\_cluster

Allows setting the cluster-local's API mount path and AIA distribution point on a particular performance replication cluster.

## Example Usage

```hcl
resource "vault_mount" "root" {
path = "pki-root"
type = "pki"
description = "root PKI"
default_lease_ttl_seconds = 8640000
max_lease_ttl_seconds = 8640000
}

resource "vault_pki_secret_backend_config_cluster" "example" {
backend = vault_mount.root.path
path = "http://127.0.0.1:8200/v1/pki-root"
aia_path = "http://127.0.0.1:8200/v1/pki-root"
}
```

## Argument Reference

The following arguments are supported:

* `namespace` - (Optional) The namespace to provision the resource in.
The value should not contain leading or trailing forward slashes.
The `namespace` is always relative to the provider's configured [namespace](/docs/providers/vault#namespace).
*Available only for Vault Enterprise*.

* `backend` - (Required) The path the PKI secret backend is mounted at, with no leading or trailing `/`s.

* `path` - (Required) Specifies the path to this performance replication cluster's API mount path.

* `aia_path` - (Required) Specifies the path to this performance replication cluster's AIA distribution point.

## Attributes Reference

No additional attributes are exported by this resource.

## Import

The PKI config cluster can be imported using the resource's `id`.
In the case of the example above the `id` would be `pki-root/config/cluster`,
where the `pki-root` component is the resource's `backend`, e.g.

```
$ terraform import vault_pki_secret_backend_config_cluster.example pki-root/config/cluster
```
4 changes: 4 additions & 0 deletions website/vault.erb
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,10 @@
<a href="/docs/providers/vault/r/pki_secret_backend_config_ca.html">vault_pki_secret_backend_config_ca</a>
</li>

<li<%= sidebar_current("docs-vault-resource-pki-secret-backend-config-cluster") %>>
<a href="/docs/providers/vault/r/pki_secret_backend_config_cluster.html">vault_pki_secret_backend_config_cluster</a>
</li>

<li<%= sidebar_current("docs-vault-resource-pki-secret-backend-config-urls") %>>
<a href="/docs/providers/vault/r/pki_secret_backend_config_urls.html">vault_pki_secret_backend_config_urls</a>
</li>
Expand Down
Loading