Skip to content

Commit

Permalink
Update namespace docs (#1501)
Browse files Browse the repository at this point in the history
- add new namespace field path_fq, for use in the nested namespace
  context.

Co-authored-by: vinay-gopalan <86625824+vinay-gopalan@users.noreply.github.com>
  • Loading branch information
benashz and vinay-gopalan authored Jun 14, 2022
1 parent 1593e86 commit d5425b8
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 41 deletions.
2 changes: 2 additions & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
FieldNamespace = "namespace"
FieldNamespaceID = "namespace_id"
FieldBackend = "backend"
FieldPathFQ = "path_fq"
FieldData = "data"
FieldMount = "mount"
FieldName = "name"
Expand All @@ -21,6 +22,7 @@ const (
FieldLeaseRenewable = "lease_renewable"
FieldDepth = "depth"
FieldDataJSON = "data_json"

/*
common environment variables
*/
Expand Down
19 changes: 17 additions & 2 deletions vault/resource_namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net/http"
"strings"
"time"

"github.com/cenkalti/backoff/v4"
Expand All @@ -15,7 +16,9 @@ import (
"github.com/hashicorp/terraform-provider-vault/util"
)

const SysNamespaceRoot = "sys/namespaces/"
const (
SysNamespaceRoot = "sys/namespaces/"
)

func namespaceResource() *schema.Resource {
return &schema.Resource{
Expand All @@ -37,7 +40,12 @@ func namespaceResource() *schema.Resource {
consts.FieldNamespaceID: {
Type: schema.TypeString,
Computed: true,
Description: "Namespace ID",
Description: "Namespace ID.",
},
consts.FieldPathFQ: {
Type: schema.TypeString,
Computed: true,
Description: "The fully qualified namespace path.",
},
},
}
Expand Down Expand Up @@ -123,6 +131,13 @@ func namespaceRead(d *schema.ResourceData, meta interface{}) error {
consts.FieldNamespaceID: resp.Data["id"],
consts.FieldPath: util.TrimSlashes(path),
}

pathFQ := path
if parent, ok := d.GetOk(consts.FieldNamespace); ok {
pathFQ = strings.Join([]string{parent.(string), path}, "/")
}
toSet[consts.FieldPathFQ] = pathFQ

if err := util.SetResourceData(d, toSet); err != nil {
return err
}
Expand Down
5 changes: 5 additions & 0 deletions vault/resource_namespace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ func TestAccNamespace(t *testing.T) {
rsc, consts.FieldPath,
fmt.Sprintf("child_%d", i)),
)
checks = append(checks,
resource.TestCheckResourceAttr(
rsc, consts.FieldPathFQ,
fmt.Sprintf("%s/child_%d", namespacePath, i)),
)
}
return checks
}
Expand Down
105 changes: 66 additions & 39 deletions website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,47 @@ The Vault provider supports managing [Namespaces][namespaces] (a feature of
Vault Enterprise), as well as creating resources in those namespaces by
utilizing [Provider Aliasing][aliasing]. The `namespace` option in the [provider
block][provider-block] enables the management of resources in the specified
namespace.
namespace.
In addition, all resources and data sources support specifying their own `namespace`.
All resource's `namespace` will be made relative to the `provider`'s configured namespace.

### Simple namespace example
```hcl
provider vault{}
resource "vault_namespace" "secret" {
path = "secret_ns"
}
resource "vault_mount" "secret" {
namespace = vault_namespace.secret.path
path = "secrets"
type = "kv"
options = {
version = "1"
}
}
resource "vault_generic_secret" "secret" {
namespace = vault_mount.secret.namespace
path = "${vault_mount.secret.path}/secret"
data_json = jsonencode(
{
"ns" = "secret"
}
)
}
```

### Using Provider Aliases

The below configuration is a simple example of using the provider block's
~> It is advisable to set the `namespace` on individual resources and data sources,
rather than having to manage multiple `provider` aliases.
See [vault_namespace](r/namespace.html) for more information.

The configuration below is a simple example of using the provider block's
`namespace` attribute to configure an aliased provider and create a resource
within that namespace.
within that namespace.

```hcl
# main provider block with no namespace
Expand Down Expand Up @@ -389,22 +423,22 @@ root

### Nested Namespaces

A more complex example of nested namespaces is show below. Each provider blocks
uses interpolation of the `ID` of namespace it belongs in to ensure the namespace
exists before that provider gets configured:

The example below relies on setting the `namespace` per resource from a single `provider{}` block.
See the [vault_namespace](r/namespace.html#nested-namespaces) documentation for a slightly less elaborate example.

```hcl
# main provider block with no namespace
provider vault {}
resource "vault_namespace" "everyone" {
path = "everyone"
variable "everyone_ns" {
default = "everyone"
}
provider vault {
alias = "everyone"
namespace = trimsuffix(vault_namespace.everyone.id, "/")
variable "engineering_ns" {
default = "engineering"
}
variable "vault_team_ns" {
default = "vault-team"
}
data "vault_policy_document" "public_secrets" {
Expand All @@ -415,42 +449,37 @@ data "vault_policy_document" "public_secrets" {
}
}
resource "vault_policy" "everyone" {
provider = vault.everyone
name = "vault_everyone_policy"
policy = data.vault_policy_document.vault_team_secrets.hcl
data "vault_policy_document" "vault_team_secrets" {
rule {
path = "secret/*"
capabilities = ["create", "read", "update", "delete", "list"]
description = "allow all on secrets under everyone/engineering/vault-team/"
}
}
resource "vault_namespace" "engineering" {
provider = vault.everyone
path = "engineering"
resource "vault_namespace" "everyone" {
path = var.everyone_ns
}
provider vault {
alias = "engineering"
namespace = trimsuffix(vault_namespace.engineering.id, "/")
resource "vault_namespace" "engineering" {
namespace = vault_namespace.everyone.path
path = var.engineering_ns
}
resource "vault_namespace" "vault-team" {
provider = vault.engineering
path = "vault-team"
resource "vault_namespace" "vault_team" {
namespace = vault_namespace.engineering.path_fq
path = var.vault_team_ns
}
data "vault_policy_document" "vault_team_secrets" {
rule {
path = "secret/*"
capabilities = ["create", "read", "update", "delete", "list"]
description = "allow all on secrets under everyone/engineering/vault-team/"
}
}
provider vault {
alias = "vault-team"
namespace = trimsuffix(vault_namespace.vault-team.id, "/")
resource "vault_policy" "everyone" {
namespace = vault_namespace.everyone.path
name = "vault_everyone_policy"
policy = data.vault_policy_document.vault_team_secrets.hcl
}
resource "vault_policy" "vault_team" {
provider = vault.vault-team
namespace = vault_namespace.vault_team.path_fq
name = "vault_team_policy"
policy = data.vault_policy_document.vault_team_secrets.hcl
}
Expand Down Expand Up @@ -493,8 +522,6 @@ vault-team/
$ vault namespace list -namespace=everyone/engineering/vault-team
No namespaces found
$ vault namespace list -namespace=everyone/engineering/vault-team
$ vault policy list -namespace=everyone/engineering/vault-team
default
vault_team_policy
Expand Down
53 changes: 53 additions & 0 deletions website/docs/r/namespace.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,63 @@ Provides a resource to manage [Namespaces](https://www.vaultproject.io/docs/ente

## Example Usage

### Single namespace

```hcl
resource "vault_namespace" "ns1" {
path = "ns1"
}
```

### Nested namespaces

```hcl
provider "vault" {}
variable "child_namespaces" {
default = [
"child_0",
"child_1",
"child_2",
]
}
locals {
child_namespaces = toset(var.child_namespaces)
}
resource "vault_namespace" "parent" {
path = "parent"
}
resource "vault_namespace" "children" {
for_each = local.child_namespaces
namespace = vault_namespace.parent.path
path = each.key
}
resource "vault_mount" "children" {
for_each = local.child_namespaces
namespace = vault_namespace.children[each.key].path_fq
path = "secrets"
type = "kv"
options = {
version = "1"
}
}
resource "vault_generic_secret" "children" {
for_each = local.child_namespaces
namespace = vault_mount.children[each.key].namespace
path = "${vault_mount.children[each.key].path}/secret"
data_json = jsonencode(
{
"ns" = each.key
}
)
}
```

## Argument Reference

The following arguments are supported:
Expand All @@ -35,6 +86,8 @@ The following arguments are supported:

* `id` - ID of the namespace.

* `path_fq` - The fully qualified path to the namespace. Useful when provisioning resources in a child `namespace`.

## Import

Namespaces can be imported using its `name` as accessor id
Expand Down

0 comments on commit d5425b8

Please sign in to comment.