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

New DataSource: azurerm_key_vault_certificates #19498

Merged
108 changes: 108 additions & 0 deletions internal/services/keyvault/key_vault_certificates_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package keyvault

import (
"fmt"
"net/url"
"strings"
"time"

"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse"
keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourceKeyVaultCertificates() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourceKeyVaultCertificatesRead,

Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"key_vault_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: keyVaultValidate.VaultID,
},

"names": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},

"include_pending": {
katbyte marked this conversation as resolved.
Show resolved Hide resolved
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},
},
}
}

func dataSourceKeyVaultCertificatesRead(d *pluginsdk.ResourceData, meta interface{}) error {
keyVaultsClient := meta.(*clients.Client).KeyVault
client := meta.(*clients.Client).KeyVault.ManagementClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

keyVaultId, err := parse.VaultID(d.Get("key_vault_id").(string))
if err != nil {
return err
}

includePending := d.Get("include_pending").(bool)

keyVaultBaseUri, err := keyVaultsClient.BaseUriForKeyVault(ctx, *keyVaultId)
if err != nil {
return fmt.Errorf("fetching base vault url from id %q: %+v", *keyVaultId, err)
}

certificateList, err := client.GetCertificatesComplete(ctx, *keyVaultBaseUri, utils.Int32(25), &includePending)
if err != nil {
return fmt.Errorf("making Read request on Azure KeyVault %q: %+v", *keyVaultId, err)
harshavmb marked this conversation as resolved.
Show resolved Hide resolved
}

d.SetId(keyVaultId.ID())

var names []string
if certificateList.Response().Value != nil {
for certificateList.NotDone() {
for _, v := range *certificateList.Response().Value {
name, err := parseNameFromCertificateUrl(*v.ID)
if err != nil {
return err
}
names = append(names, *name)
err = certificateList.NextWithContext(ctx)
if err != nil {
return fmt.Errorf("listing certificates on Azure KeyVault %q: %+v", *keyVaultId, err)
harshavmb marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

d.Set("names", names)
d.Set("key_vault_id", keyVaultId.ID())

return nil
}

func parseNameFromCertificateUrl(input string) (*string, error) {
uri, err := url.Parse(input)
if err != nil {
return nil, err
}
// https://favoretti-keyvault.vault.azure.net//certificates/certificate-name
segments := strings.Split(uri.Path, "/")
if len(segments) != 3 {
return nil, fmt.Errorf("expected a Path in the format `/certificates/certificate-name` but got %q", uri.Path)
}
return &segments[2], nil
harshavmb marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package keyvault_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type KeyVaultCertificatesDataSource struct{}

func TestAccDataSourceKeyVaultCertificates_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_key_vault_certificates", "test")
r := KeyVaultCertificatesDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("names.#").HasValue("9"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
check.That(data.ResourceName).Key("names.#").HasValue("9"),
check.That(data.ResourceName).Key("names.#").HasValue("31"),

Copy link
Collaborator

Choose a reason for hiding this comment

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

i can't edit this PR, @harshavmb once this change is made this is good to go

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @katbyte ,

I've pushed the change from my end.

),
},
})
}

func (KeyVaultCertificatesDataSource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s

resource "azurerm_key_vault_certificate" "test2" {
count = 10
Copy link
Contributor

Choose a reason for hiding this comment

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

we're creating 10 of these, so this would indicate that we're not paging or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Paging happens after 25 resources as per doc here.
So, left untouched.

Copy link
Contributor

Choose a reason for hiding this comment

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

so could we create 26 for test purposes to check we cross the boundary?

name = "certificate-${count.index}"
certificate_policy {
issuer_parameters {
name = "Self"
}

key_properties {
exportable = true
key_size = 2048
key_type = "RSA"
reuse_key = true
}

lifetime_action {
action {
action_type = "AutoRenew"
}

trigger {
days_before_expiry = 30
}
}

secret_properties {
content_type = "application/x-pkcs12"
}

x509_certificate_properties {
key_usage = [
"cRLSign",
"dataEncipherment",
"digitalSignature",
"keyAgreement",
"keyEncipherment",
"keyCertSign",
]

subject = "CN=hello-world"
validity_in_months = 12
}
}
key_vault_id = azurerm_key_vault.test.id
}

data "azurerm_key_vault_certificates" "test" {
key_vault_id = azurerm_key_vault.test.id

depends_on = [azurerm_key_vault_certificate.test, azurerm_key_vault_certificate.test2]
}
`, KeyVaultCertificateResource{}.basicGenerate(data))
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions internal/services/keyvault/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource {
"azurerm_key_vault_secret": dataSourceKeyVaultSecret(),
"azurerm_key_vault_secrets": dataSourceKeyVaultSecrets(),
"azurerm_key_vault": dataSourceKeyVault(),
"azurerm_key_vault_certificates": dataSourceKeyVaultCertificates(),
}
}

Expand Down
49 changes: 49 additions & 0 deletions website/docs/d/key_vault_certificates.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
subcategory: "Key Vault"
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_key_vault_certificates"
description: |-
Gets a list of certificate names from an existing Key Vault.
---

# Data Source: azurerm_key_vault_certificates

Use this data source to retrieve a list of certificate names from an existing Key Vault.

## Example Usage

```hcl
data "azurerm_key_vault_certificates" "example" {
key_vault_id = data.azurerm_key_vault.existing.id
}

data "azurerm_key_vault_certificate" "example" {
for_each = toset(data.azurerm_key_vault_certificates.example.names)
name = each.key
key_vault_id = data.azurerm_key_vault.existing.id
}

```

## Argument Reference

The following arguments are supported:

* `key_vault_id` - Specifies the ID of the Key Vault instance to fetch certificate names from, available on the `azurerm_key_vault` Data Source / Resource.

* `include_pending` - Specifies whether to include certificates which are not completely provisioned. Defaults to true.

**NOTE:** The vault must be in the same subscription as the provider. If the vault is in another subscription, you must create an aliased provider for that subscription.
harshavmb marked this conversation as resolved.
Show resolved Hide resolved

## Attributes Reference

The following attributes are exported:

* `names` - List containing names of certificates that exist in this Key Vault.
* `key_vault_id` - The Key Vault ID.
harshavmb marked this conversation as resolved.
Show resolved Hide resolved

## Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions:

* `read` - (Defaults to 5 minutes) Used when retrieving the Key Vault Certificate.
harshavmb marked this conversation as resolved.
Show resolved Hide resolved