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 Nomad secret backend #923

Merged
merged 9 commits into from
Dec 11, 2020
14 changes: 14 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,20 @@ func GetTestADCreds(t *testing.T) (string, string, string) {
return adBindDN, adBindPass, adURL
}

func GetTestNomadCreds(t *testing.T) (string, string) {
address := os.Getenv("NOMAD_ADDR")
token := os.Getenv("NOMAD_TOKEN")

if address == "" {
t.Skip("NOMAD_ADDR not set")
}
if token == "" {
t.Skip("NOMAD_TOKEN not set")
}

return address, token
}

func TestCheckResourceAttrJSON(name, key, expectedValue string) resource.TestCheckFunc {
return func(s *terraform.State) error {
resourceState, ok := s.RootModule().Resources[name]
Expand Down
71 changes: 71 additions & 0 deletions vault/data_source_nomad_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package vault

import (
"fmt"
"log"

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

func nomadAccessCredentialsDataSource() *schema.Resource {
return &schema.Resource{
Read: readNomadCredsResource,
Schema: map[string]*schema.Schema{
"backend": {
Type: schema.TypeString,
Required: true,
Description: "Nomad secret backend to generate tokens from.",
},
"role": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the role.",
},
"accessor_id": {
Type: schema.TypeString,
Computed: true,
Description: "The public identifier for a specific token. It can be used to look up information about a token or to revoke a token.",
},
"secret_id": {
Type: schema.TypeString,
Computed: true,
Description: "Used to make requests to Nomad and should be kept private.",
},
},
}
}

func readNomadCredsResource(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
backend := d.Get("backend").(string)
role := d.Get("role").(string)
path := fmt.Sprintf("%s/creds/%s", backend, role)

secret, err := client.Logical().Read(path)
if err != nil {
return fmt.Errorf("error reading from Vault: %s", err)
}
log.Printf("[DEBUG] Read %q from Vault", path)

if secret == nil {
return fmt.Errorf("no role found at %q", path)
}

accessorID := secret.Data["accessor_id"].(string)
if accessorID == "" {
return fmt.Errorf("accessor_id is not set in response")
}

secretID := secret.Data["secret_id"].(string)
if secretID == "" {
return fmt.Errorf("secret_id is not set in response")
}

d.SetId(accessorID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use path here? Granted, we aren't using the ID at all that I can see

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each call to this endpoint generates a new token, so we want the ID to be the unique identifier of that specific generated token. Path would be too generic I think?

d.Set("accessor_id", accessorID)
d.Set("secret_id", secretID)

return nil
}
96 changes: 96 additions & 0 deletions vault/data_source_nomad_credentials_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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-provider-vault/util"
)

func TestAccDataSourceNomadAccessCredentialsClientBasic(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-nomad")
address, token := util.GetTestNomadCreds(t)

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { util.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testAccDataSourceNomadAccessCredentialsConfig(backend, address, token, "test"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.vault_nomad_access_token.token", "secret_id"),
resource.TestCheckResourceAttrSet("data.vault_nomad_access_token.token", "accessor_id"),
),
},
},
})
}

func TestAccDataSourceNomadAccessCredentialsManagementBasic(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-nomad")
address, token := util.GetTestNomadCreds(t)

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { util.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testAccDataSourceNomadAccessCredentialsManagementConfig(backend, address, token, "test"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.vault_nomad_access_token.token", "secret_id"),
resource.TestCheckResourceAttrSet("data.vault_nomad_access_token.token", "accessor_id"),
),
},
},
})
}

func testAccDataSourceNomadAccessCredentialsConfig(backend, address, token, role string) string {
return fmt.Sprintf(`
resource "vault_nomad_secret_backend" "config" {
backend = "%s"
description = "test description"
default_lease_ttl_seconds = "3600"
max_lease_ttl_seconds = "7200"
address = "%s"
token = "%s"
}

resource "vault_nomad_secret_role" "test" {
backend = vault_nomad_secret_backend.config.backend
role = "%s"
policies = ["reaodnly"]
}

data "vault_nomad_access_token" "token" {
backend = vault_nomad_secret_backend.config.backend
role = vault_nomad_secret_role.test.role
}
`, backend, address, token, role)
}

func testAccDataSourceNomadAccessCredentialsManagementConfig(backend, address, token, role string) string {
return fmt.Sprintf(`
resource "vault_nomad_secret_backend" "config" {
backend = "%s"
description = "test description"
default_lease_ttl_seconds = "3600"
max_lease_ttl_seconds = "7200"
address = "%s"
token = "%s"
}

resource "vault_nomad_secret_role" "test" {
backend = vault_nomad_secret_backend.config.backend
role = "%s"
type = "management"
}

data "vault_nomad_access_token" "token" {
backend = vault_nomad_secret_backend.config.backend
role = vault_nomad_secret_role.test.role
}
`, backend, address, token, role)
}
16 changes: 16 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ var (
Resource: adAccessCredentialsDataSource(),
PathInventory: []string{"/ad/creds/{role}"},
},
"vault_nomad_access_token": {
Resource: nomadAccessCredentialsDataSource(),
PathInventory: []string{"/nomad/creds/{role}"},
},
"vault_aws_access_credentials": {
Resource: awsAccessCredentialsDataSource(),
PathInventory: []string{"/aws/creds"},
Expand Down Expand Up @@ -466,6 +470,18 @@ var (
Resource: ldapAuthBackendGroupResource(),
PathInventory: []string{"/auth/ldap/groups/{name}"},
},
"vault_nomad_secret_backend": {
Resource: nomadSecretAccessBackendResource(),
PathInventory: []string{
"/nomad",
"/nomad/config/access",
"/nomad/config/lease",
},
},
"vault_nomad_secret_role": {
Resource: nomadSecretBackendRoleResource(),
PathInventory: []string{"/nomad/role/{role}"},
},
"vault_policy": {
Resource: policyResource(),
PathInventory: []string{"/sys/policy/{name}"},
Expand Down
Loading