-
Notifications
You must be signed in to change notification settings - Fork 556
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
290 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,158 @@ | ||
package vault | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/vault/api" | ||
) | ||
|
||
func mfaDuoResource() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: mfaDuoWrite, | ||
Update: mfaDuoWrite, | ||
Delete: mfaDuoDelete, | ||
Read: mfaDuoRead, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Name of the MFA method.", | ||
ValidateFunc: validateNoTrailingSlash, | ||
}, | ||
"mount_accessor": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "The mount to tie this method to for use in automatic mappings. The mapping will use the Name field of Aliases associated with this mount as the username in the mapping.", | ||
}, | ||
"username_format": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "A format string for mapping Identity names to MFA method names. Values to substitute should be placed in `{{}}`.", | ||
}, | ||
"secret_key": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Secret key for Duo.", | ||
}, | ||
"integration_key": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Integration key for Duo.", | ||
}, | ||
"api_hostname": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "API hostname for Duo.", | ||
}, | ||
"push_info": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Push information for Duo.", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func mfaDuoWrite(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
name := d.Get("name").(string) | ||
|
||
data := map[string]interface{}{} | ||
mfaDuoUpdateFields(d, data) | ||
|
||
log.Printf("[DEBUG] Writing role %q to MFA Duo auth backend", name) | ||
d.SetId(name) | ||
|
||
log.Printf("[DEBUG] Creating mfaDuo %s in Vault", name) | ||
_, err := client.Logical().Write(mfaDuoPath(name), data) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error writing to Vault: %s", err) | ||
} | ||
|
||
return mfaDuoRead(d, meta) | ||
} | ||
|
||
func mfaDuoDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
name := d.Get("name").(string) | ||
|
||
log.Printf("[DEBUG] Deleting mfaDuo %s from Vault", mfaDuoPath(name)) | ||
|
||
_, err := client.Logical().Delete(mfaDuoPath(name)) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error deleting from Vault: %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func mfaDuoRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*api.Client) | ||
|
||
name := d.Get("name").(string) | ||
|
||
resp, err := client.Logical().Read(mfaDuoPath(name)) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error reading from Vault: %s", err) | ||
} | ||
|
||
log.Printf("[DEBUG] Read MFA Duo config %q", mfaDuoPath(name)) | ||
|
||
d.Set("mount_accessor", resp.Data["mount_accessor"]) | ||
d.Set("username_format", resp.Data["username_format"]) | ||
d.Set("api_hostname", resp.Data["api_hostname"]) | ||
|
||
// When you push the data up, it's push_info | ||
// when vault responds, it's pushinfo :( | ||
d.Set("push_info", resp.Data["pushinfo"]) | ||
|
||
// secret_key and integration_key, can't read out from the api | ||
// So... if it drifts, it drift. | ||
|
||
d.SetId(name) | ||
|
||
return nil | ||
} | ||
|
||
func mfaDuoUpdateFields(d *schema.ResourceData, data map[string]interface{}) { | ||
if v, ok := d.GetOk("mount_accessor"); ok { | ||
data["mount_accessor"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("username_format"); ok { | ||
data["username_format"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("secret_key"); ok { | ||
data["secret_key"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("integration_key"); ok { | ||
data["integration_key"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("api_hostname"); ok { | ||
data["api_hostname"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("push_info"); ok { | ||
data["push_info"] = v.(string) | ||
} | ||
|
||
} | ||
|
||
func mfaDuoPath(name string) string { | ||
return "sys/mfa/method/duo/" + strings.Trim(name, "/") + "/" | ||
} |
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,62 @@ | ||
package vault | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"os" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestMFADuoBasic(t *testing.T) { | ||
|
||
isEnterprise := os.Getenv("TF_ACC_ENTERPRISE") | ||
if isEnterprise == "" { | ||
t.Skip("TF_ACC_ENTERPRISE is not set, test is applicable only for Enterprise version of Vault") | ||
} | ||
|
||
mfaDuoPath := acctest.RandomWithPrefix("mfa-duo") | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testMFADuoConfig(mfaDuoPath), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "name", mfaDuoPath), | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "secret_key", "8C7THtrIigh2rPZQMbguugt8IUftWhMRCOBzbuyz"), | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "integration_key", "BIACEUEAXI20BNWTEYXT"), | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "api_hostname", "api-2b5c39f5.duosecurity.com"), | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "username_format", "user@example.com"), | ||
resource.TestCheckResourceAttr("vault_mfa_duo.test", "push_info", "from=loginortal&domain=example.com"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testMFADuoConfig(path string) string { | ||
|
||
userPassPath := acctest.RandomWithPrefix("userpass") | ||
|
||
return fmt.Sprintf(` | ||
resource "vault_auth_backend" "userpass" { | ||
type = "userpass" | ||
path = %q | ||
} | ||
resource "vault_mfa_duo" "test" { | ||
name = %q | ||
mount_accessor = "${vault_auth_backend.userpass.accessor}" | ||
secret_key = "8C7THtrIigh2rPZQMbguugt8IUftWhMRCOBzbuyz" | ||
integration_key = "BIACEUEAXI20BNWTEYXT" | ||
api_hostname = "api-2b5c39f5.duosecurity.com" | ||
username_format = "user@example.com" | ||
push_info = "from=loginortal&domain=example.com" | ||
} | ||
`, userPassPath, 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,61 @@ | ||
--- | ||
layout: "vault" | ||
page_title: "Vault: vault_mfa_duo resource" | ||
sidebar_current: "docs-vault-resource-mfa-duo" | ||
description: |- | ||
Managing the MFA Duo method configuration | ||
--- | ||
|
||
# vault\_mfa-duo | ||
|
||
Provides a resource to manage [Duo MFA](https://www.vaultproject.io/docs/enterprise/mfa/mfa-duo.html). | ||
|
||
**Note** this feature is available only with Vault Enterprise. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "vault_auth_backend" "userpass" { | ||
type = "userpass" | ||
path = "userpass" | ||
} | ||
resource "vault_mfa_duo" "my_duo" { | ||
name = "my_duo" | ||
mount_accessor = "${vault_auth_backend.userpass.accessor}" | ||
secret_key = "8C7THtrIigh2rPZQMbguugt8IUftWhMRCOBzbuyz" | ||
integration_key = "BIACEUEAXI20BNWTEYXT" | ||
api_hostname = "api-2b5c39f5.duosecurity.com" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
- `name` `(string: <required>)` – Name of the MFA method. | ||
|
||
- `mount_accessor` `(string: <required>)` - The mount to tie this method to for use in automatic mappings. The mapping will use the Name field of Aliases associated with this mount as the username in the mapping. | ||
|
||
- `username_format` `(string)` - A format string for mapping Identity names to MFA method names. Values to substitute should be placed in `{{}}`. For example, `"{{alias.name}}@example.com"`. If blank, the Alias's Name field will be used as-is. Currently-supported mappings: | ||
- alias.name: The name returned by the mount configured via the `mount_accessor` parameter | ||
- entity.name: The name configured for the Entity | ||
- alias.metadata.`<key>`: The value of the Alias's metadata parameter | ||
- entity.metadata.`<key>`: The value of the Entity's metadata parameter | ||
|
||
- `secret_key` `(string: <required>)` - Secret key for Duo. | ||
|
||
- `integration_key` `(string: <required>)` - Integration key for Duo. | ||
|
||
- `api_hostname` `(string: <required>)` - API hostname for Duo. | ||
|
||
- `push_info` `(string)` - Push information for Duo. | ||
|
||
## Import | ||
|
||
Mounts can be imported using the `path`, e.g. | ||
|
||
``` | ||
$ terraform import vault_mfa_duo.my_duo my_duo | ||
``` | ||
|
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