forked from hashicorp/terraform-provider-vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request hashicorp#481 from petems/add_vault_azure_secret_b…
…ackend Add Azure Secret Backend resource
- Loading branch information
Showing
4 changed files
with
302 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package vault | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/vault/api" | ||
) | ||
|
||
func azureSecretBackendResource() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: azureSecretBackendCreate, | ||
Read: azureSecretBackendRead, | ||
Update: azureSecretBackendCreate, | ||
Delete: azureSecretBackendDelete, | ||
Exists: azureSecretBackendExists, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"path": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
Default: "azure", | ||
Description: "Path to mount the backend at.", | ||
ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) { | ||
value := v.(string) | ||
if strings.HasSuffix(value, "/") { | ||
errs = append(errs, fmt.Errorf("path cannot end in '/'")) | ||
} | ||
return | ||
}, | ||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { | ||
return old+"/" == new || new+"/" == old | ||
}, | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Human-friendly description of the mount for the backend.", | ||
}, | ||
"subscription_id": { | ||
Type: schema.TypeString, | ||
ForceNew: true, | ||
Required: true, | ||
Sensitive: true, | ||
Description: "The subscription id for the Azure Active Directory.", | ||
}, | ||
"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, | ||
}, | ||
"environment": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Default: "AzurePublicCloud", | ||
Description: "The Azure cloud environment. Valid values: AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud.", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func azureSecretBackendCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
path := d.Get("path").(string) | ||
description := d.Get("description").(string) | ||
tenantID := d.Get("tenant_id").(string) | ||
clientID := d.Get("client_id").(string) | ||
clientSecret := d.Get("client_secret").(string) | ||
environment := d.Get("environment").(string) | ||
subscriptionID := d.Get("subscription_id").(string) | ||
|
||
configPath := azureSecretBackendPath(path) | ||
|
||
data := map[string]interface{}{ | ||
"tenant_id": tenantID, | ||
"client_id": clientID, | ||
"client_secret": clientSecret, | ||
"environment": environment, | ||
"subscription_id": subscriptionID, | ||
} | ||
|
||
d.Partial(true) | ||
log.Printf("[DEBUG] Mounting Azure backend at %q", path) | ||
err := client.Sys().Mount(path, &api.MountInput{ | ||
Type: "azure", | ||
Description: description, | ||
Config: api.MountConfigInput{}, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("error mounting to %q: %s", path, err) | ||
} | ||
log.Printf("[DEBUG] Mounted Azure backend at %q", path) | ||
d.SetId(path) | ||
|
||
d.SetPartial("path") | ||
|
||
log.Printf("[DEBUG] Writing Azure configuration to %q", configPath) | ||
if _, err := client.Logical().Write(configPath, data); err != nil { | ||
return fmt.Errorf("error writing Azure configuration for %q: %s", path, err) | ||
} | ||
log.Printf("[DEBUG] Wrote Azure configuration to %q", configPath) | ||
d.Partial(false) | ||
|
||
return azureSecretBackendRead(d, meta) | ||
} | ||
|
||
func azureSecretBackendRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
path := d.Id() | ||
|
||
log.Printf("[DEBUG] Reading Azure backend mount %q from Vault", path) | ||
mounts, err := client.Sys().ListMounts() | ||
if err != nil { | ||
return fmt.Errorf("error reading mount %q: %s", path, err) | ||
} | ||
log.Printf("[DEBUG] Read Azure backend mount %q from Vault", path) | ||
|
||
// the API always returns the path with a trailing slash, so let's make | ||
// sure we always specify it as a trailing slash. | ||
mount, ok := mounts[strings.Trim(path, "/")+"/"] | ||
if !ok { | ||
log.Printf("[WARN] Mount %q not found, removing backend from state.", path) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("path", path) | ||
d.Set("description", mount.Description) | ||
|
||
return nil | ||
} | ||
|
||
func azureSecretBackendDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
path := d.Id() | ||
|
||
log.Printf("[DEBUG] Unmounting Azure backend %q", path) | ||
err := client.Sys().Unmount(path) | ||
if err != nil { | ||
return fmt.Errorf("error unmounting Azure backend from %q: %s", path, err) | ||
} | ||
log.Printf("[DEBUG] Unmounted Azure backend %q", path) | ||
return nil | ||
} | ||
|
||
func azureSecretBackendExists(d *schema.ResourceData, meta interface{}) (bool, error) { | ||
client := meta.(*api.Client) | ||
path := d.Id() | ||
log.Printf("[DEBUG] Checking if Azure backend exists at %q", path) | ||
mounts, err := client.Sys().ListMounts() | ||
if err != nil { | ||
return true, fmt.Errorf("error retrieving list of mounts: %s", err) | ||
} | ||
log.Printf("[DEBUG] Checked if Azure backend exists at %q", path) | ||
_, ok := mounts[strings.Trim(path, "/")+"/"] | ||
return ok, nil | ||
} | ||
|
||
func azureSecretBackendPath(path string) string { | ||
return strings.Trim(path, "/") + "/config" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package vault | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
"github.com/hashicorp/vault/api" | ||
) | ||
|
||
func TestAzureSecretBackend(t *testing.T) { | ||
path := acctest.RandomWithPrefix("tf-test-azure") | ||
resource.Test(t, resource.TestCase{ | ||
Providers: testProviders, | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
CheckDestroy: testAccAzureSecretBackendCheckDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAzureSecretBackend_initialConfig(path), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "path", path), | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "subscription_id", "11111111-2222-3333-4444-111111111111"), | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "tenant_id", "11111111-2222-3333-4444-222222222222"), | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "client_id", "11111111-2222-3333-4444-333333333333"), | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "client_secret", "12345678901234567890"), | ||
resource.TestCheckResourceAttr("vault_azure_secret_backend.test", "environment", "AzurePublicCloud"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccAzureSecretBackendCheckDestroy(s *terraform.State) error { | ||
client := testProvider.Meta().(*api.Client) | ||
|
||
mounts, err := client.Sys().ListMounts() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "vault_azure_secret_backend" { | ||
continue | ||
} | ||
for path, mount := range mounts { | ||
path = strings.Trim(path, "/") | ||
rsPath := strings.Trim(rs.Primary.Attributes["path"], "/") | ||
if mount.Type == "azure" && path == rsPath { | ||
return fmt.Errorf("Mount %q still exists", path) | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func testAzureSecretBackend_initialConfig(path string) string { | ||
return fmt.Sprintf(` | ||
resource "vault_azure_secret_backend" "test" { | ||
path = "%s" | ||
subscription_id = "11111111-2222-3333-4444-111111111111" | ||
tenant_id = "11111111-2222-3333-4444-222222222222" | ||
client_id = "11111111-2222-3333-4444-333333333333" | ||
client_secret = "12345678901234567890" | ||
environment = "AzurePublicCloud" | ||
}`, path) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
layout: "vault" | ||
page_title: "Vault: vault_azure_secret_backend resource" | ||
sidebar_current: "docs-vault-resource-azure-secret-backend" | ||
description: |- | ||
Creates an azure secret backend for Vault. | ||
--- | ||
|
||
# vault\_azure\_secret\_backend | ||
|
||
Creates an Azure Secret Backend for Vault. | ||
|
||
The Azure secrets engine dynamically generates Azure service principals and role assignments. Vault roles can be mapped to one or more Azure roles, providing a simple, flexible way to manage the permissions granted to generated service principals. | ||
|
||
~> **Important** All data provided in the resource configuration will be | ||
written in cleartext to state and plan files generated by Terraform, and | ||
will appear in the console output when Terraform runs. Protect these | ||
artifacts accordingly. See | ||
[the main provider documentation](../index.html) | ||
for more details. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "vault_azure_secret_backend" "azure" { | ||
subscription_id = "11111111-2222-3333-4444-111111111111" | ||
tenant_id = "11111111-2222-3333-4444-222222222222" | ||
client_id = "11111111-2222-3333-4444-333333333333" | ||
client_secret = "12345678901234567890" | ||
environment = "AzurePublicCloud" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
- `subscription_id` (`string: <required>`) - The subscription id for the Azure Active Directory. | ||
- `tenant_id` (`string: <required>`) - The tenant id for the Azure Active Directory. | ||
- `client_id` (`string:""`) - The OAuth2 client id to connect to Azure. | ||
- `client_secret` (`string:""`) - The OAuth2 client secret to connect to Azure. | ||
- `environment` (`string:""`) - The Azure environment. | ||
|
||
## Attributes Reference | ||
|
||
No additional attributes are exported by this resource. |