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

PKI: Add support for CPS URL in custom policy identifiers #1495

Merged
merged 4 commits into from
Jun 10, 2022

Conversation

swenson
Copy link
Contributor

@swenson swenson commented Jun 9, 2022

Update the vault_resource_pki_secret_backend_role to support
specifying the CPS URL when specifying policy identifiers in line with
the recent changes to the PKI Secrets Engine in Vault 1.11:
hashicorp/vault#15751

We do this by deprecating the existing policy_identifiers argument and
creating a new block, policy_identifier, which can be specified
multiple times.

If both policy_identifiers and policy_identifier blocks are present,
then policy_identifier is ignored. (Otherwise, refreshing would delete
one or the other, and the state wouldn't have round trip stability.)

This was also tested locally with, for example, a terraform file like:

provider "vault" {
}

resource "vault_mount" "pki" {
  path                      = "pki"
  type                      = "pki"
  default_lease_ttl_seconds = 3600
  max_lease_ttl_seconds     = 86400
}

resource "vault_pki_secret_backend_role" "role" {
  name = "example-dot-com"
  backend = vault_mount.pki.path
  allowed_domains = ["example.com"]
  allow_subdomains = true
  allow_bare_domains = true
  allow_glob_domains = true
  allow_ip_sans = true
  allow_localhost = "true"
  generate_lease = true
  organization = ["Hashi test"]
  country = ["USA"]
  locality = ["Area 51"]
  province = ["NV"]
  max_ttl = "720h"
  policy_identifiers = ["2.5.29.32","1.2.3"]
  // or
  policy_identifier {
    oid = "2.5.29.32"
    cps = "https://example.com/cps"
    notice = "Some notice"
  }
  policy_identifier {
    oid = "1.2.3"
  }
}

Community Note

  • Please vote on this pull request by adding a 👍 reaction to the original pull request comment to help the community and maintainers prioritize this request
  • Please do not leave "+1" comments, they generate extra noise for pull request followers and do not help prioritize the request

Release note for CHANGELOG:

`resource/pki_secret_backend_role`: Add support for `policy_identifier` blocks, deprecate `policy_identifiers`

Output from acceptance testing:

$ make testacc TESTARGS="-v ./vault -run .*TestPkiSecretBackendRole.*"
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test -v -v ./vault -run .*TestPkiSecretBackendRole.* -timeout 30m ./...
=== RUN   TestPkiSecretBackendRole_basic
--- PASS: TestPkiSecretBackendRole_basic (4.75s)
PASS
ok  	github.com/hashicorp/terraform-provider-vault/vault	5.093s
...

Update the `vault_resource_pki_secret_backend_role` to support
specifying the CPS URL when specifying policy identifiers in line with
the recent changes to the PKI Secrets Engine in Vault 1.11:
hashicorp/vault#15751

We do this by deprecating the existing `policy_identifiers` argument and
creating a new block, `policy_identifier`, which can be specified
multiple times.

If both `policy_identifiers` and `policy_identifier` blocks are present,
then `policy_identifier` is ignored. (Otherwise, refreshing would delete
one or the other, and the state wouldn't have round trip stability.)

This was also tested locally with, for example, a terraform file like:

```hcl
provider "vault" {
}

resource "vault_mount" "pki" {
  path                      = "pki"
  type                      = "pki"
  default_lease_ttl_seconds = 3600
  max_lease_ttl_seconds     = 86400
}

resource "vault_pki_secret_backend_role" "role" {
  name = "example-dot-com"
  backend = vault_mount.pki.path
  allowed_domains = ["example.com"]
  allow_subdomains = true
  allow_bare_domains = true
  allow_glob_domains = true
  allow_ip_sans = true
  allow_localhost = "true"
  generate_lease = true
  organization = ["Hashi test"]
  country = ["USA"]
  locality = ["Area 51"]
  province = ["NV"]
  max_ttl = "720h"
  policy_identifiers = ["2.5.29.32","1.2.3"]
  // or
  policy_identifier {
    oid = "2.5.29.32"
    cps = "https://example.com/cps"
    notice = "Some notice"
  }
  policy_identifier {
    oid = "1.2.3"
  }
}
```
Copy link
Contributor

@vinay-gopalan vinay-gopalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR is looking great! Had some comments/questions

vault/resource_pki_secret_backend_role.go Show resolved Hide resolved
vault/resource_pki_secret_backend_role_test.go Outdated Show resolved Hide resolved
Copy link
Contributor

@benashz benashz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! I left some initial feedback/suggestions.

@@ -79,7 +79,7 @@ The following arguments are supported:

* `email_protection_flag` - (Optional) Flag to specify certificates for email protection use

* `key_type` - (Optional) The generated key type, choices: `rsa`, `ec`, `ed25519`, `any`
* `key_type` - (Optional) The generated key type, choices: `rsa`, `ec`, `ed25519`, `any`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the trailing double space denotes a line beak in Markdown. I think this was intentional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Weird. My text editor isn't going to like that :) I'll see if I can add it back.

vault/pki.go Outdated Show resolved Hide resolved
vault/pki.go Outdated
// into a list of strings (the OIDs) or the JSON serialization of the `policy_identifier` blocks,
// respectively.
func readPolicyIdentifiers(d *schema.ResourceData) interface{} {
policyIdentifiersList := d.Get("policy_identifiers").([]interface{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we me make the two fields mutually exclusive by setting ConflictsWith on their schema.Schema, then we can update this function to only have to support the Set type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

vault/pki.go Outdated
@@ -0,0 +1,79 @@
package vault
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if we could make this the beginning of a new package under internal/.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can do. I was mostly following the pattern I saw of other utilities, e.g., gcp.go

@@ -112,7 +112,14 @@ The following arguments are supported:

* `require_cn` - (Optional) Flag to force CN usage

* `policy_identifiers` - (Optional) Specify the list of allowed policies IODs
* `policy_identifiers` - (Optional) Specify the list of allowed policies OIDs; Deprecated: use `policy_identifier` blocks instead
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe we have deprecated this field yet. We probably just want to say that it is used for Vault 1.10 and below, or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -12,6 +12,17 @@ import (
"github.com/hashicorp/terraform-provider-vault/testutil"
)

var legacyPolicyIdentifiers = `policy_identifiers = ["1.2.3.4"]`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the vault project is already so massive, I'd suggest that we either move theses vars within the test's scope, or include test in their names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

internal/pki.go Outdated
@@ -0,0 +1,64 @@
package internal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be better to instead make this live under internal/pki and call it something like package pki. We did something similar for packages like internal/consts and internal/identity/entity. Importing might make things more explictly clear as well with things like pki.ReadPolicyIdentifierBlocks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 makes sense

Copy link
Contributor

@benashz benashz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice update! I have a few more comments/suggestions.

internal/pki.go Outdated
@@ -0,0 +1,64 @@
package internal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I was thinking more of moving this code to a package called pki under internal/, sorry if I wasn't clear.

resource.TestCheckTypeSetElemNestedAttrs(resourceName, "policy_identifier.*", map[string]string{"oid": "1.2.3.4.5.6"}),
)...,
),
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add an import TestStep after each Config step. This will ensure that a terraform import will work.

Similar to:

{
ResourceName: resourcePath,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: importIgnoreKeys,
},

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

policyIdentifiers := make([]string, 0, len(iPolicyIdentifiers))
for _, iIdentifier := range iPolicyIdentifiers {
policyIdentifiers = append(policyIdentifiers, iIdentifier.(string))
legacyPolicyIdentifiers, newPolicyIdentifiers, err := internal.MakePkiPolicyIdentifiersListOrSet(secret.Data["policy_identifiers"].([]interface{}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might panic here on the type assertion in the case of a value other than []interface{}. We probably want to call MakePkiPolicyIdentifiersListOrSet() conditionally when policy_identifiers in the resp.Data, and guard against the type assert panic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -413,8 +439,10 @@ func pkiSecretBackendRoleCreate(d *schema.ResourceData, meta interface{}) error
data["ext_key_usage"] = extKeyUsage
}

if len(policyIdentifiers) > 0 {
data["policy_identifiers"] = policyIdentifiers
if len(policyIdentifiersList) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think calling d.GetOk() on each field would probably do the same, and then we could avoid the extra variable assignments above.

Comment on lines 386 to 387
policyIdentifiersList := d.Get("policy_identifiers").([]interface{})
policyIdentifierBlocks := internal.ReadPolicyIdentifierBlocks(d.Get("policy_identifier").(*schema.Set))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably drop these with the suggestion below.

Suggested change
policyIdentifiersList := d.Get("policy_identifiers").([]interface{})
policyIdentifierBlocks := internal.ReadPolicyIdentifierBlocks(d.Get("policy_identifier").(*schema.Set))

Comment on lines 662 to 665
if len(policyIdentifiersList) > 0 {
data["policy_identifiers"] = policyIdentifiersList
} else if policyIdentifierBlocks != "" {
data["policy_identifiers"] = policyIdentifierBlocks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same suggestion as in the Read() method. Ideally we would merge the two and rely on d.HasChange(), but I think that is probably out of scope for this PR.

Suggested change
if len(policyIdentifiersList) > 0 {
data["policy_identifiers"] = policyIdentifiersList
} else if policyIdentifierBlocks != "" {
data["policy_identifiers"] = policyIdentifierBlocks
if v, ok := d.GetOk("policy_identifiers"); ok {
data["policy_identifiers"] = v
} else if v, ok := d.GetOk("policy_identifier"); ok {
data["policy_identifiers"] = internal.ReadPolicyIdentifierBlocks(v.(*schema.Set))
}

Comment on lines 606 to 607
policyIdentifiersList := d.Get("policy_identifiers").([]interface{})
policyIdentifierBlocks := internal.ReadPolicyIdentifierBlocks(d.Get("policy_identifier").(*schema.Set))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
policyIdentifiersList := d.Get("policy_identifiers").([]interface{})
policyIdentifierBlocks := internal.ReadPolicyIdentifierBlocks(d.Get("policy_identifier").(*schema.Set))

* `policy_identifiers` - (Optional) Specify the list of allowed policies IODs
* `policy_identifiers` - (Optional) Specify the list of allowed policies OIDs. Use with Vault 1.10 or before. For Vault 1.11+, use `policy_identifier` blocks instead

* `policy_identifier` - (Optional) (Vault 1.11+ only) A block for specifying policy identifers. The `policy_identifier` block can be repeated, and supports the following arguments:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth adding a new example for this new feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

)...,
),
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want test that the two fields are mutually exclusive by adding a ExpectError TestStep similar to:

{
Config: testAccGCPAuthBackendRoleDataSourceConfig(backend, name),
ExpectError: regexp.MustCompile(
fmt.Sprintf("role not found at %q", gcpRoleResourcePath(backend, name)),
),
},

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, perfect. I had wanted to do that, but didn't quite know how. That helps.

@github-actions github-actions bot added size/XL and removed size/L labels Jun 9, 2022
@@ -9,7 +9,7 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/hashicorp/terraform-provider-vault/internal/pki"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@benashz benashz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@swenson
Copy link
Contributor Author

swenson commented Jun 10, 2022

Thanks for all of the helpful feedback!

@swenson swenson merged commit 85ebb88 into release/vault-next Jun 10, 2022
@swenson swenson deleted the vault-5965/pki-cps-url branch June 10, 2022 20:59
@benashz benashz added this to the 3.8.0 milestone Jun 28, 2022
marcboudreau pushed a commit to marcboudreau/terraform-provider-vault that referenced this pull request Nov 6, 2022
…1495)

PKI: Add support for CPS URL in custom policy identifiers

Update the `vault_resource_pki_secret_backend_role` to support
specifying the CPS URL when specifying policy identifiers in line with
the recent changes to the PKI Secrets Engine in Vault 1.11:
hashicorp/vault#15751

We do this by deprecating the existing `policy_identifiers` argument and
creating a new block, `policy_identifier`, which can be specified
multiple times.

If both `policy_identifiers` and `policy_identifier` blocks are present,
then `policy_identifier` is ignored. (Otherwise, refreshing would delete
one or the other, and the state wouldn't have round trip stability.)

This was also tested locally with, for example, a terraform file like:

```hcl
provider "vault" {
}

resource "vault_mount" "pki" {
  path                      = "pki"
  type                      = "pki"
  default_lease_ttl_seconds = 3600
  max_lease_ttl_seconds     = 86400
}

resource "vault_pki_secret_backend_role" "role" {
  name = "example-dot-com"
  backend = vault_mount.pki.path
  allowed_domains = ["example.com"]
  allow_subdomains = true
  allow_bare_domains = true
  allow_glob_domains = true
  allow_ip_sans = true
  allow_localhost = "true"
  generate_lease = true
  organization = ["Hashi test"]
  country = ["USA"]
  locality = ["Area 51"]
  province = ["NV"]
  max_ttl = "720h"
  policy_identifiers = ["2.5.29.32","1.2.3"]
  // or
  policy_identifier {
    oid = "2.5.29.32"
    cps = "https://example.com/cps"
    notice = "Some notice"
  }
  policy_identifier {
    oid = "1.2.3"
  }
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants