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

Added Azure auth support for backend config and role. #275

Merged
merged 2 commits into from
Jan 29, 2019
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
2 changes: 2 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ func Provider() terraform.ResourceProvider {
"vault_aws_auth_backend_sts_role": awsAuthBackendSTSRoleResource(),
"vault_aws_secret_backend": awsSecretBackendResource(),
"vault_aws_secret_backend_role": awsSecretBackendRoleResource(),
"vault_azure_auth_backend_config": azureAuthBackendConfigResource(),
"vault_azure_auth_backend_role": azureAuthBackendRoleResource(),
"vault_consul_secret_backend": consulSecretBackendResource(),
"vault_database_secret_backend_connection": databaseSecretBackendConnectionResource(),
"vault_database_secret_backend_role": databaseSecretBackendRoleResource(),
Expand Down
156 changes: 156 additions & 0 deletions vault/resource_azure_auth_backend_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package vault

import (
"fmt"
"log"
"strings"

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

func azureAuthBackendConfigResource() *schema.Resource {
return &schema.Resource{
Create: azureAuthBackendWrite,
Read: azureAuthBackendRead,
Update: azureAuthBackendWrite,
Delete: azureAuthBackendDelete,
Exists: azureAuthBackendExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"backend": {
Type: schema.TypeString,
Optional: true,
Description: "Unique name of the auth backend to configure.",
ForceNew: true,
Default: "azure",
// standardise on no beginning or trailing slashes
StateFunc: func(v interface{}) string {
return strings.Trim(v.(string), "/")
},
},
"tenant_id": {
Type: schema.TypeString,
Required: true,
Description: "The tenant id for the Azure Active Directory organization.",
Sensitive: true,
},
"client_id": {
Type: schema.TypeString,
Optional: true,
Description: "The client id for credentials to query the Azure APIs. Currently read permissions to query compute resources are required.",
Sensitive: true,
},
"client_secret": {
Type: schema.TypeString,
Optional: true,
Description: "The client secret for credentials to query the Azure APIs",
Sensitive: true,
},
"resource": {
Type: schema.TypeString,
Required: true,
Description: "The configured URL for the application registered in Azure Active Directory.",
},
"environment": {
Type: schema.TypeString,
Optional: true,
Description: "The Azure cloud environment. Valid values: AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud.",
},
},
}
}

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

// if backend comes from the config, it won't have the StateFunc
// applied yet, so we need to apply it again.
backend := d.Get("backend").(string)
tenantId := d.Get("tenant_id").(string)
clientId := d.Get("client_id").(string)
clientSecret := d.Get("client_secret").(string)
resource := d.Get("resource").(string)
environment := d.Get("environment").(string)

path := azureAuthBackendConfigPath(backend)

data := map[string]interface{}{
"tenant_id": tenantId,
"client_id": clientId,
"client_secret": clientSecret,
"resource": resource,
"environment": environment,
}

log.Printf("[DEBUG] Writing Azure auth backend config to %q", path)
_, err := config.Logical().Write(path, data)
if err != nil {
return fmt.Errorf("error writing to %q: %s", path, err)
}
log.Printf("[DEBUG] Wrote Azure auth backend config to %q", path)

d.SetId(path)

return azureAuthBackendRead(d, meta)
}

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

log.Printf("[DEBUG] Reading Azure auth backend config")
secret, err := config.Logical().Read(d.Id())
if err != nil {
return fmt.Errorf("error reading Azure auth backend config from %q: %s", d.Id(), err)
}
log.Printf("[DEBUG] Read Azure auth backend config")

if secret == nil {
log.Printf("[WARN] No info found at %q; removing from state.", d.Id())
d.SetId("")
return nil
}
idPieces := strings.Split(d.Id(), "/")
if len(idPieces) != 3 {
return fmt.Errorf("expected %q to have 4 pieces, has %d", d.Id(), len(idPieces))
}
d.Set("backend", idPieces[1])
d.Set("tenant_id", secret.Data["tenant_id"])
d.Set("client_id", secret.Data["client_id"])
d.Set("client_secert", secret.Data["client_secret"])
d.Set("resource", secret.Data["resource"])
d.Set("environment", secret.Data["environment"])
return nil
}

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

log.Printf("[DEBUG] Deleting Azure auth backend config from %q", d.Id())
_, err := config.Logical().Delete(d.Id())
if err != nil {
return fmt.Errorf("error deleting Azure auth backend config from %q: %s", d.Id(), err)
}
log.Printf("[DEBUG] Deleted Azure auth backend config from %q", d.Id())

return nil
}

func azureAuthBackendExists(d *schema.ResourceData, meta interface{}) (bool, error) {
config := meta.(*api.Client)

log.Printf("[DEBUG] Checking if Azure auth backend is configured at %q", d.Id())
secret, err := config.Logical().Read(d.Id())
if err != nil {
return true, fmt.Errorf("error checking if Azure auth backend is configured at %q: %s", d.Id(), err)
}
log.Printf("[DEBUG] Checked if Azure auth backend is configured at %q", d.Id())
return secret != nil, nil
}

func azureAuthBackendConfigPath(path string) string {
return "auth/" + strings.Trim(path, "/") + "/config"
}
149 changes: 149 additions & 0 deletions vault/resource_azure_auth_backend_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package vault

import (
"fmt"
"testing"

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

func TestAccAzureAuthBackendConfig_import(t *testing.T) {
backend := acctest.RandomWithPrefix("azure")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccCheckAzureAuthBackendConfigDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureAuthBackendConfig_basic(backend),
Check: testAccAzureAuthBackendConfigCheck_attrs(backend),
},
{
ResourceName: "vault_azure_auth_backend_config.config",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"client_secret"},
},
},
})
}

func TestAccAzureAuthBackendConfig_basic(t *testing.T) {
backend := acctest.RandomWithPrefix("azure")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccCheckAzureAuthBackendConfigDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureAuthBackendConfig_basic(backend),
Check: testAccAzureAuthBackendConfigCheck_attrs(backend),
},
{
Config: testAccAzureAuthBackendConfig_updated(backend),
Check: testAccAzureAuthBackendConfigCheck_attrs(backend),
},
},
})
}

func testAccCheckAzureAuthBackendConfigDestroy(s *terraform.State) error {
config := testProvider.Meta().(*api.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_azure_auth_backend_config" {
continue
}
secret, err := config.Logical().Read(rs.Primary.ID)
if err != nil {
return fmt.Errorf("error checking for Azure auth backend %q config: %s", rs.Primary.ID, err)
}
if secret != nil {
return fmt.Errorf("Azure auth backend %q still configured", rs.Primary.ID)
}
}
return nil
}

func testAccAzureAuthBackendConfig_basic(backend string) string {
return fmt.Sprintf(`
resource "vault_auth_backend" "azure" {
type = "azure"
path = "%s"
description = "Test auth backend for Azure backend config"
}

resource "vault_azure_auth_backend_config" "config" {
backend = "${vault_auth_backend.azure.path}"
tenant_id = "11111111-2222-3333-4444-555555555555"
client_id = "11111111-2222-3333-4444-555555555555"
client_secret = "12345678901234567890"
resource = "http://vault.hashicorp.com"
}
`, backend)
}

func testAccAzureAuthBackendConfigCheck_attrs(backend string) resource.TestCheckFunc {
return func(s *terraform.State) error {
resourceState := s.Modules[0].Resources["vault_azure_auth_backend_config.config"]
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")
}

endpoint := instanceState.ID

if endpoint != "auth/"+backend+"/config" {
return fmt.Errorf("expected ID to be %q, got %q", "auth/"+backend+"/config", endpoint)
}

config := testProvider.Meta().(*api.Client)
resp, err := config.Logical().Read(endpoint)
if err != nil {
return fmt.Errorf("error reading back Azure auth config from %q: %s", endpoint, err)
}
if resp == nil {
return fmt.Errorf("Azure auth not configured at %q", endpoint)
}
attrs := map[string]string{
"tenant_id": "tenant_id",
"client_id": "client_id",
//"client_secret": "client_secret",
"resource": "resource",
"environment": "environment",
}
for stateAttr, apiAttr := range attrs {
if resp.Data[apiAttr] == nil && instanceState.Attributes[stateAttr] == "" {
continue
}
if resp.Data[apiAttr] != instanceState.Attributes[stateAttr] {
return fmt.Errorf("expected %s (%s) of %q to be %q, got %q", apiAttr, stateAttr, endpoint, instanceState.Attributes[stateAttr], resp.Data[apiAttr])
}
}
return nil
}
}

func testAccAzureAuthBackendConfig_updated(backend string) string {
return fmt.Sprintf(`
resource "vault_auth_backend" "azure" {
path = "%s"
type = "azure"
description = "Test auth backend for Azure backend config"
}

resource "vault_azure_auth_backend_config" "config" {
backend = "${vault_auth_backend.azure.path}"
tenant_id = "11111111-2222-3333-4444-555555555555"
client_id = "11111111-2222-3333-4444-555555555555"
client_secret = "12345678901234567890"
resource = "http://vault.hashicorp.com"
}`, backend)
}
Loading