Skip to content

Commit

Permalink
Adding new resource for password policy
Browse files Browse the repository at this point in the history
  • Loading branch information
petems and jasonodonnell committed Jan 21, 2021
1 parent e0161ec commit c3b3c8a
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 0 deletions.
109 changes: 109 additions & 0 deletions vault/password_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package vault

import (
"context"
"errors"
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/vault/api"
)

func readPasswordPolicy(client *api.Client, name string) (map[string]interface{}, error) {
r := client.NewRequest("GET", fmt.Sprintf("/v1/sys/policies/password/%s", name))

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if resp != nil {
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, nil
}
}
if err != nil {
return nil, err
}

secret, err := api.ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
return secret.Data, nil
}

func passwordPolicyDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Id()

log.Printf("[DEBUG] Deleting %s password policy from Vault", name)

r := client.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policies/password/%s", name))

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if err == nil {
defer resp.Body.Close()
}

return err
}

func passwordPolicyRead(attributes []string, d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Id()

policy, err := readPasswordPolicy(client, name)

if err != nil {
return fmt.Errorf("error reading from Vault: %s", err)
}

for _, value := range attributes {
d.Set(value, policy[value])
}
d.Set("name", name)

return nil
}

func passwordPolicyWrite(attributes []string, d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

name := d.Get("name").(string)

log.Printf("[DEBUG] Writing %s password policy to Vault", name)

body := map[string]interface{}{}
for _, value := range attributes {
body[value] = d.Get(value)
}

r := client.NewRequest("PUT", fmt.Sprintf("/v1/sys/policies/password/%s", name))
if err := r.SetJSONBody(body); err != nil {
return err
}

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := client.RawRequestWithContext(ctx, r)
if err != nil {
return err
}
defer resp.Body.Close()

if err != nil {
return fmt.Errorf("error writing to Vault: %s", err)
}

d.SetId(name)

return passwordPolicyRead(attributes, d, meta)
}
4 changes: 4 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,10 @@ var (
Resource: rabbitmqSecretBackendRoleResource(),
PathInventory: []string{"/rabbitmq/roles/{name}"},
},
"vault_password_policy": {
Resource: passwordPolicyResource(),
PathInventory: []string{"/sys/policy/password/{name}"},
},
"vault_pki_secret_backend": {
Resource: pkiSecretBackendResource(),
PathInventory: []string{UnknownPath},
Expand Down
47 changes: 47 additions & 0 deletions vault/resource_password_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package vault

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

var passwordPolicyAttributes = []string{"policy"}

func passwordPolicyResource() *schema.Resource {
return &schema.Resource{
Create: resourcePasswordPolicyWrite,
Update: resourcePasswordPolicyWrite,
Delete: resourcePasswordPolicyDelete,
Read: resourcePasswordPolicyRead,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the password policy.",
},

"policy": {
Type: schema.TypeString,
Required: true,
Description: "The password policy document",
},
},
}
}

func resourcePasswordPolicyWrite(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyWrite(passwordPolicyAttributes, d, meta)
}

func resourcePasswordPolicyDelete(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyDelete(d, meta)
}

func resourcePasswordPolicyRead(d *schema.ResourceData, meta interface{}) error {
return passwordPolicyRead(passwordPolicyAttributes, d, meta)
}
89 changes: 89 additions & 0 deletions vault/resource_password_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/vault/api"
)

func TestAccPasswordPolicy(t *testing.T) {

policyName := acctest.RandomWithPrefix("test-policy")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccPasswordPolicyCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\nrule \"charset\" {\n charset = \"1234567890\"\nmin-chars = 1\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
},
})
}

func TestAccPasswordPolicy_import(t *testing.T) {
policyName := acctest.RandomWithPrefix("test-policy")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccPasswordPolicyCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccPasswordPolicy(policyName, "length = 20\nrule \"charset\" {\n charset = \"abcde\"\n}\n"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_password_policy.test", "name", policyName),
resource.TestCheckResourceAttrSet("vault_password_policy.test", "policy"),
),
},
{
ResourceName: "vault_password_policy.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccPasswordPolicyCheckDestroy(s *terraform.State) error {
client := testProvider.Meta().(*api.Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_password_policy" {
continue
}
name := rs.Primary.Attributes["name"]
data, err := client.Logical().Read(fmt.Sprintf("sys/policies/password/%s", name))
if err != nil {
return err
}
if data != nil {
return fmt.Errorf("Password policy %s still exists", name)
}
}
return nil
}

func testAccPasswordPolicy(policyName string, policy string) string {
return fmt.Sprintf(`
resource "vault_password_policy" "test" {
name = "%s"
policy = <<EOT
%s
EOT
}`, policyName, policy)
}
48 changes: 48 additions & 0 deletions website/docs/r/password_policy.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
layout: "vault"
page_title: "Vault: vault_password_policy resource"
sidebar_current: "docs-vault-resource-password-policy"
description: |-
Writes Password policies for Vault
---

# vault\_password\_policy

Provides a resource to manage Password Policies

**Note** this feature is available only Vault 1.5+

## Example Usage

```hcl
resource "vault_password_policy" "alphanumeric" {
name = "alphanumeric"
policy = <<EOT
length = 20
rule "charset" {
charset = "abcdefghijklmnopqrstuvwxyz0123456789"
}
EOT
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the password policy.

* `policy` - (Required) String containing a password policy.

## Attributes Reference

No additional attributes are exported by this resource.

## Import

Password policies can be imported using the `name`, e.g.

```
$ terraform import vault_password_policy.alphanumeric alphanumeric
```

0 comments on commit c3b3c8a

Please sign in to comment.