diff --git a/builtin/providers/vault/provider.go b/builtin/providers/vault/provider.go index ceebd4acf..d9c7719e9 100644 --- a/builtin/providers/vault/provider.go +++ b/builtin/providers/vault/provider.go @@ -87,6 +87,7 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ + "vault_auth_backend": authBackendResource(), "vault_generic_secret": genericSecretResource(), "vault_policy": policyResource(), }, diff --git a/builtin/providers/vault/resource_auth_backend.go b/builtin/providers/vault/resource_auth_backend.go new file mode 100644 index 000000000..800155040 --- /dev/null +++ b/builtin/providers/vault/resource_auth_backend.go @@ -0,0 +1,121 @@ +package vault + +import ( + "errors" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/vault/api" +) + +func authBackendResource() *schema.Resource { + return &schema.Resource{ + Create: authBackendWrite, + Delete: authBackendDelete, + Read: authBackendRead, + + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the auth backend", + }, + + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "path to mount the backend. This defaults to the type.", + ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { + value := v.(string) + if strings.HasSuffix(value, "/") { + errs = append(errs, errors.New("cannot write to a path ending in '/'")) + } + return + }, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "The description of the auth backend", + }, + }, + } +} + +func authBackendWrite(d *schema.ResourceData, meta interface{}) error { + client := meta.(*api.Client) + + name := d.Get("type").(string) + desc := d.Get("description").(string) + path := d.Get("path").(string) + + log.Printf("[DEBUG] Writing auth %s to Vault", name) + + var err error + + if path == "" { + path = name + err = d.Set("path", name) + if err != nil { + return fmt.Errorf("unable to set state: %s", err) + } + } + + err = client.Sys().EnableAuth(path, name, desc) + + if err != nil { + return fmt.Errorf("error writing to Vault: %s", err) + } + + d.SetId(name) + + return nil +} + +func authBackendDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*api.Client) + + name := d.Id() + + log.Printf("[DEBUG] Deleting auth %s from Vault", name) + + err := client.Sys().DisableAuth(name) + + if err != nil { + return fmt.Errorf("error disabling auth from Vault: %s", err) + } + + return nil +} + +func authBackendRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*api.Client) + + name := d.Id() + + auths, err := client.Sys().ListAuth() + + if err != nil { + return fmt.Errorf("error reading from Vault: %s", err) + } + + for path, auth := range auths { + configuredPath := d.Get("path").(string) + + vaultPath := configuredPath + "/" + if auth.Type == name && path == vaultPath { + return nil + } + } + + // If we fell out here then we didn't find our Auth in the list. + d.SetId("") + return nil +} diff --git a/builtin/providers/vault/resource_auth_backend_test.go b/builtin/providers/vault/resource_auth_backend_test.go new file mode 100644 index 000000000..344eafbd5 --- /dev/null +++ b/builtin/providers/vault/resource_auth_backend_test.go @@ -0,0 +1,129 @@ +package vault + +import ( + "fmt" + "testing" + + r "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/vault/api" +) + +func TestResourceAuth(t *testing.T) { + r.Test(t, r.TestCase{ + Providers: testProviders, + PreCheck: func() { testAccPreCheck(t) }, + Steps: []r.TestStep{ + r.TestStep{ + Config: testResourceAuth_initialConfig, + Check: testResourceAuth_initialCheck, + }, + r.TestStep{ + Config: testResourceAuth_updateConfig, + Check: testResourceAuth_updateCheck, + }, + }, + }) +} + +var testResourceAuth_initialConfig = ` + +resource "vault_auth_backend" "test" { + type = "github" +} + +` + +func testResourceAuth_initialCheck(s *terraform.State) error { + resourceState := s.Modules[0].Resources["vault_auth_backend.test"] + if resourceState == nil { + return fmt.Errorf("resource not found in state") + } + + instanceState := resourceState.Primary + if instanceState == nil { + return fmt.Errorf("resource has no primary instance") + } + + name := instanceState.ID + + if name != instanceState.Attributes["type"] { + return fmt.Errorf("id doesn't match name") + } + + if name != "github" { + return fmt.Errorf("unexpected auth name %s", name) + } + + client := testProvider.Meta().(*api.Client) + auths, err := client.Sys().ListAuth() + + if err != nil { + return fmt.Errorf("error reading back auth: %s", err) + } + + found := false + for _, auth := range auths { + if auth.Type == name { + found = true + break + } + } + + if !found { + return fmt.Errorf("could not find auth backend %s in %+v", name, auths) + } + + return nil +} + +var testResourceAuth_updateConfig = ` + +resource "vault_auth_backend" "test" { + type = "ldap" +} + +` + +func testResourceAuth_updateCheck(s *terraform.State) error { + resourceState := s.Modules[0].Resources["vault_auth_backend.test"] + if resourceState == nil { + return fmt.Errorf("resource not found in state") + } + + instanceState := resourceState.Primary + if instanceState == nil { + return fmt.Errorf("resource has no primary instance") + } + + name := instanceState.ID + + if name != instanceState.Attributes["type"] { + return fmt.Errorf("id doesn't match name") + } + + if name != "ldap" { + return fmt.Errorf("unexpected auth name") + } + + client := testProvider.Meta().(*api.Client) + auths, err := client.Sys().ListAuth() + + if err != nil { + return fmt.Errorf("error reading back auth: %s", err) + } + + found := false + for _, auth := range auths { + if auth.Type == name { + found = true + break + } + } + + if !found { + return fmt.Errorf("could not find auth backend %s in %+v", name, auths) + } + + return nil +}