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 vault_alicloud_auth_backend_role resource #673

Merged
merged 2 commits into from
Mar 6, 2020
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
4 changes: 4 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ var (
}

ResourceRegistry = map[string]*Description{
"vault_alicloud_auth_backend_role": {
Resource: alicloudAuthBackendRoleResource(),
PathInventory: []string{"/auth/alicloud/role/{name}"},
},
"vault_approle_auth_backend_login": {
Resource: approleAuthBackendLoginResource(),
PathInventory: []string{"/auth/approle/login"},
Expand Down
191 changes: 191 additions & 0 deletions vault/resource_alicloud_auth_backend_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package vault

import (
"fmt"
"log"
"strings"

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

func alicloudAuthBackendRoleResource() *schema.Resource {
fields := map[string]*schema.Schema{
"role": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the role. Must correspond with the name of the role reflected in the arn.",
},
"arn": {
Type: schema.TypeString,
Required: true,
Description: "The role's arn.",
},
"backend": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: "alicloud",
Description: "Auth backend.",
StateFunc: func(v interface{}) string {
return strings.Trim(v.(string), "/")
},
},
}

addTokenFields(fields, &addTokenFieldsConfig{})

return &schema.Resource{
Create: alicloudAuthBackendRoleCreate,
Update: alicloudAuthBackendRoleUpdate,
Read: alicloudAuthBackendRoleRead,
Delete: alicloudAuthBackendRoleDelete,
Exists: alicloudAuthBackendRoleExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: fields,
}
}

func alicloudAuthBackendRolePath(backend, role string) string {
return "auth/" + strings.Trim(backend, "/") + "/role/" + strings.Trim(role, "/")
}

func alicloudAuthBackendFromPath(path string) (string, error) {
var parts = strings.Split(path, "/")
if len(parts) != 4 {
return "", fmt.Errorf("expected 4 parts in path '%s'", path)
}
return parts[1], nil
}

func alicloudAuthRoleFromPath(path string) (string, error) {
var parts = strings.Split(path, "/")
if len(parts) != 4 {
return "", fmt.Errorf("expected 4 parts in path '%s'", path)
}
return parts[3], nil
}

func alicloudAuthBackendRoleUpdateFields(d *schema.ResourceData, data map[string]interface{}, create bool) {
updateTokenFields(d, data, create)

if v, ok := d.GetOk("role"); ok {
data["role"] = v
}

if v, ok := d.GetOk("arn"); ok {
data["arn"] = v
}
}

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

backend := d.Get("backend").(string)
role := d.Get("role").(string)

path := alicloudAuthBackendRolePath(backend, role)

data := map[string]interface{}{}
alicloudAuthBackendRoleUpdateFields(d, data, true)

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

return alicloudAuthBackendRoleRead(d, meta)
}

func alicloudAuthBackendRoleUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
path := d.Id()

data := map[string]interface{}{}
alicloudAuthBackendRoleUpdateFields(d, data, false)

log.Printf("[DEBUG] Updating role %q in AliCloud auth backend", path)
_, err := client.Logical().Write(path, data)
if err != nil {
return fmt.Errorf("error updating AliCloud auth role %q: %s", path, err)
}
log.Printf("[DEBUG] Updated role %q to AliCloud auth backend", path)

return alicloudAuthBackendRoleRead(d, meta)
}

func alicloudAuthBackendRoleRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
path := d.Id()

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

if resp == nil {
log.Printf("[WARN] AliCloud role %q not found, removing from state", path)
d.SetId("")
return nil
}

backend, err := alicloudAuthBackendFromPath(path)
if err != nil {
return fmt.Errorf("invalid path %q for AliCloud auth backend role: %s", path, err)
}
d.Set("backend", backend)
role, err := alicloudAuthRoleFromPath(path)
if err != nil {
return fmt.Errorf("invalid path %q for AliCloud auth backend role: %s", path, err)
}
d.Set("role", role)

readTokenFields(d, resp)

for _, k := range []string{"arn"} {
if v, ok := resp.Data[k]; ok {
if err := d.Set(k, v); err != nil {
return fmt.Errorf("error reading %s for AliCloud Auth Backend Role %q: %q", k, path, err)
}
}
}

return nil
}

func alicloudAuthBackendRoleDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
path := d.Id()

log.Printf("[DEBUG] Deleting AliCloud role %q", path)
_, err := client.Logical().Delete(path)
if err != nil {
return fmt.Errorf("error deleting AliCloud role %q", path)
}
log.Printf("[DEBUG] Deleted AliCloud role %q", path)

return nil
}

func alicloudAuthBackendRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) {
client := meta.(*api.Client)
path := d.Id()

log.Printf("[DEBUG] Checking if AliCloud Auth Backend role %q exists", path)
resp, err := client.Logical().Read(path)
if err != nil {
return true, fmt.Errorf("error checking for existence of AliCloud Auth Backend resource config %q: %s", path, err)
}
log.Printf("[DEBUG] Checked if AliCloud Auth Backend role %q exists", path)

return resp != nil, nil
}
84 changes: 84 additions & 0 deletions vault/resource_alicloud_auth_backend_role_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
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-plugin-sdk/terraform"
"github.com/hashicorp/vault/api"
)

func TestAlicloudAuthBackendRole_basic(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-alicloud-backend")
name := acctest.RandomWithPrefix("tf-test-alicloud-role")
arn := acctest.RandomWithPrefix("acs:ram:123456:tf:role/")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAlicloudAuthBackedRoleDestroy,
Steps: []resource.TestStep{
{
Config: testAlicloudAuthBackedRoleConfig_basic(backend, name, arn),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_alicloud_auth_backend_role.test",
"arn", arn),
resource.TestCheckResourceAttr("vault_alicloud_auth_backend_role.test",
"role", name),
),
},
{
Config: testAlicloudAuthBackedRoleConfig_basic(backend, name+"updated", arn+"updated"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_alicloud_auth_backend_role.test",
"arn", arn+"updated"),
resource.TestCheckResourceAttr("vault_alicloud_auth_backend_role.test",
"role", name+"updated"),
),
},
{
ResourceName: "vault_alicloud_auth_backend_role.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

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

for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_alicloud_auth_backend_role" {
continue
}
secret, err := client.Logical().Read(rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error checking for AliCloud Auth Backend role %q: %s", rs.Primary.ID, err)
}
if secret != nil {
return fmt.Errorf("AliCloud Auth Backend role %q still exists", rs.Primary.ID)
}
}
return nil
}

func testAlicloudAuthBackedRoleConfig_basic(backend, name, arn string) string {

return fmt.Sprintf(`

resource "vault_auth_backend" "alicloud" {
path = "%s"
type = "alicloud"
}

resource "vault_alicloud_auth_backend_role" "test" {
backend = vault_auth_backend.alicloud.path
role = "%s"
arn = "%s"

}
`, backend, name, arn)
}
93 changes: 93 additions & 0 deletions website/docs/r/alicloud_auth_backend_role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
layout: "vault"
page_title: "Vault: vault_alicloud_auth_backend_role resource"
sidebar_current: "docs-vault-resource-alicloud-auth-backend-role"
description: |-
Managing roles in an AliCloud auth backend in Vault
---

# vault\_alicloud\_auth\_backend\_role

Provides a resource to create a role in an [AliCloud auth backend within Vault](https://www.vaultproject.io/docs/auth/alicloud.html).

## Example Usage

```hcl
resource "vault_auth_backend" "alicloud" {
type = "alicloud"
path = "alicloud"
}

resource "vault_alicloud_auth_backend_role" "alicloud" {
backend = vault_auth_backend.alicloud.path
role = "example"
arn = "acs:ram:123456:tf:role/foobar"

}
```

## Argument Reference

The following arguments are supported:

* `role` - (Required; Forces new resource) Name of the role. Must correspond with the name of
the role reflected in the arn.

* `arn` - (Required) The role's arn.

* `backend` - (Optional; Forces new resource) Path to the mounted AliCloud auth backend.
Defaults to `alicloud`

For more details on the usage of each argument consult the [Vault AliCloud API documentation](https://www.vaultproject.io/api/auth/alicloud/index.html).

### Common Token Arguments

These arguments are common across several Authentication Token resources since Vault 1.2.

* `token_ttl` - (Optional) The incremental lifetime for generated tokens in number of seconds.
Its current value will be referenced at renewal time.

* `token_max_ttl` - (Optional) The maximum lifetime for generated tokens in number of seconds.
Its current value will be referenced at renewal time.

* `token_period` - (Optional) If set, indicates that the
token generated using this role should never expire. The token should be renewed within the
duration specified by this value. At each renewal, the token's TTL will be set to the
value of this field. Specified in seconds.

* `token_policies` - (Optional) List of policies to encode onto generated tokens. Depending
on the auth method, this list may be supplemented by user/group/other values.

* `token_bound_cidrs` - (Optional) List of CIDR blocks; if set, specifies blocks of IP
addresses which can authenticate successfully, and ties the resulting token to these blocks
as well.

* `token_explicit_max_ttl` - (Optional) If set, will encode an
[explicit max TTL](https://www.vaultproject.io/docs/concepts/tokens.html#token-time-to-live-periodic-tokens-and-explicit-max-ttls)
onto the token in number of seconds. This is a hard cap even if `token_ttl` and
`token_max_ttl` would otherwise allow a renewal.

* `token_no_default_policy` - (Optional) If set, the default policy will not be set on
generated tokens; otherwise it will be added to the policies set in token_policies.

* `token_num_uses` - (Optional) The
[period](https://www.vaultproject.io/docs/concepts/tokens.html#token-time-to-live-periodic-tokens-and-explicit-max-ttls),
if any, in number of seconds to set on the token.

* `token_type` - (Optional) The type of token that should be generated. Can be `service`,
`batch`, or `default` to use the mount's tuned default (which unless changed will be
`service` tokens). For token store roles, there are two additional possibilities:
`default-service` and `default-batch` which specify the type to return unless the client
requests a different type at generation time.

## Attribute Reference

No additional attributes are exposed by this resource.

## Import

Alicloud authentication roles can be imported using the `path`, e.g.

```
$ terraform import vault_alicloud_auth_backend_role.my_role auth/alicloud/role/my_role
```
4 changes: 2 additions & 2 deletions website/docs/r/gcp_auth_backend_role.html.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: "vault"
page_title: "Vault: vault_auth_backend resource"
page_title: "Vault: vault_gcp_auth_backend_role resource"
sidebar_current: "docs-vault-resource-gcp-auth-backend-role"
description: |-
Managing roles in an GCP auth backend in Vault
Expand All @@ -19,7 +19,7 @@ resource "vault_auth_backend" "gcp" {
}

resource "vault_gcp_auth_backend_role" "gcp" {
backend = vault_auth_backend.cert.path
backend = vault_auth_backend.gcp.path
project_id = "foo-bar-baz"
bound_service_accounts = ["[email protected]"]
token_policies = ["database-server"]
Expand Down
Loading