Skip to content

Commit

Permalink
Merge pull request #7285 from terraform-providers/d/kv-certificate-da…
Browse files Browse the repository at this point in the history
…tasource

New data source azurerm_key_vault_certificate
  • Loading branch information
jackofallops committed Jun 11, 2020
2 parents 1e850c6 + 18a1eb4 commit d6624b3
Show file tree
Hide file tree
Showing 5 changed files with 593 additions and 0 deletions.
@@ -0,0 +1,382 @@
package keyvault

import (
"encoding/base64"
"encoding/hex"
"fmt"
"log"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func dataSourceArmKeyVaultCertificate() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmKeyVaultCertificateRead,

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

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: azure.ValidateKeyVaultChildName,
},

"key_vault_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: azure.ValidateResourceID,
},

"version": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

// Computed
"certificate_policy": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"issuer_parameters": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"key_properties": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"exportable": {
Type: schema.TypeBool,
Computed: true,
},
"key_size": {
Type: schema.TypeInt,
Computed: true,
},
"key_type": {
Type: schema.TypeString,
Computed: true,
},
"reuse_key": {
Type: schema.TypeBool,
Computed: true,
},
},
},
},

"lifetime_action": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"action": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"action_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"trigger": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"days_before_expiry": {
Type: schema.TypeInt,
Computed: true,
},
"lifetime_percentage": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},

"secret_properties": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"content_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},

"x509_certificate_properties": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"extended_key_usage": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"key_usage": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"subject": {
Type: schema.TypeString,
Computed: true,
},
"subject_alternative_names": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"emails": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"dns_names": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"upns": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"validity_in_months": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},

"secret_id": {
Type: schema.TypeString,
Computed: true,
},

"certificate_data": {
Type: schema.TypeString,
Computed: true,
},

"thumbprint": {
Type: schema.TypeString,
Computed: true,
},

"tags": tags.SchemaDataSource(),
},
}
}

func dataSourceArmKeyVaultCertificateRead(d *schema.ResourceData, meta interface{}) error {
vaultClient := meta.(*clients.Client).KeyVault.VaultsClient
client := meta.(*clients.Client).KeyVault.ManagementClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("name").(string)
keyVaultId := d.Get("key_vault_id").(string)
version := d.Get("version").(string)

keyVaultBaseUri, err := azure.GetKeyVaultBaseUrlFromID(ctx, vaultClient, keyVaultId)
if err != nil {
return fmt.Errorf("Error looking up Key %q vault url from id %q: %+v", name, keyVaultId, err)
}

cert, err := client.GetCertificate(ctx, keyVaultBaseUri, name, version)
if err != nil {
if utils.ResponseWasNotFound(cert.Response) {
log.Printf("[DEBUG] Certificate %q was not found in Key Vault at URI %q - removing from state", name, keyVaultBaseUri)
d.SetId("")
return nil
}

return fmt.Errorf("Error reading Key Vault Certificate: %+v", err)
}

if cert.ID == nil || *cert.ID == "" {
return fmt.Errorf("failure reading Key Vault Certificate ID for %q", name)
}

d.SetId(*cert.ID)

id, err := azure.ParseKeyVaultChildID(*cert.ID)
if err != nil {
return err
}

d.Set("name", id.Name)

certificatePolicy := flattenKeyVaultCertificatePolicyForDataSource(cert.Policy)
if err := d.Set("certificate_policy", certificatePolicy); err != nil {
return fmt.Errorf("Error setting Key Vault Certificate Policy: %+v", err)
}

d.Set("version", id.Version)
d.Set("secret_id", cert.Sid)

certificateData := ""
if contents := cert.Cer; contents != nil {
certificateData = strings.ToUpper(hex.EncodeToString(*contents))
}
d.Set("certificate_data", certificateData)

thumbprint := ""
if v := cert.X509Thumbprint; v != nil {
x509Thumbprint, err := base64.RawURLEncoding.DecodeString(*v)
if err != nil {
return err
}

thumbprint = strings.ToUpper(hex.EncodeToString(x509Thumbprint))
}
d.Set("thumbprint", thumbprint)

return tags.FlattenAndSet(d, cert.Tags)
}

func flattenKeyVaultCertificatePolicyForDataSource(input *keyvault.CertificatePolicy) []interface{} {
policy := make(map[string]interface{})

if params := input.IssuerParameters; params != nil {
issuerParams := make(map[string]interface{})
issuerParams["name"] = *params.Name
policy["issuer_parameters"] = []interface{}{issuerParams}
}

// key properties
if props := input.KeyProperties; props != nil {
keyProps := make(map[string]interface{})
keyProps["exportable"] = *props.Exportable
keyProps["key_size"] = int(*props.KeySize)
keyProps["key_type"] = *props.KeyType
keyProps["reuse_key"] = *props.ReuseKey

policy["key_properties"] = []interface{}{keyProps}
}

// lifetime actions
lifetimeActions := make([]interface{}, 0)
if actions := input.LifetimeActions; actions != nil {
for _, action := range *actions {
lifetimeAction := make(map[string]interface{})

actionOutput := make(map[string]interface{})
if act := action.Action; act != nil {
actionOutput["action_type"] = string(act.ActionType)
}
lifetimeAction["action"] = []interface{}{actionOutput}

triggerOutput := make(map[string]interface{})
if trigger := action.Trigger; trigger != nil {
if days := trigger.DaysBeforeExpiry; days != nil {
triggerOutput["days_before_expiry"] = int(*trigger.DaysBeforeExpiry)
}

if days := trigger.LifetimePercentage; days != nil {
triggerOutput["lifetime_percentage"] = int(*trigger.LifetimePercentage)
}
}
lifetimeAction["trigger"] = []interface{}{triggerOutput}
lifetimeActions = append(lifetimeActions, lifetimeAction)
}
}
policy["lifetime_action"] = lifetimeActions

// secret properties
if props := input.SecretProperties; props != nil {
keyProps := make(map[string]interface{})
keyProps["content_type"] = *props.ContentType

policy["secret_properties"] = []interface{}{keyProps}
}

// x509 Certificate Properties
if props := input.X509CertificateProperties; props != nil {
certProps := make(map[string]interface{})

usages := make([]string, 0)
for _, usage := range *props.KeyUsage {
usages = append(usages, string(usage))
}

sanOutputs := make([]interface{}, 0)
if san := props.SubjectAlternativeNames; san != nil {
sanOutput := make(map[string]interface{})
if emails := san.Emails; emails != nil {
sanOutput["emails"] = *emails
}
if dnsNames := san.DNSNames; dnsNames != nil {
sanOutput["dns_names"] = *dnsNames
}
if upns := san.Upns; upns != nil {
sanOutput["upns"] = *upns
}

sanOutputs = append(sanOutputs, sanOutput)
}

certProps["key_usage"] = usages
certProps["subject"] = *props.Subject
certProps["validity_in_months"] = int(*props.ValidityInMonths)
if props.Ekus != nil {
certProps["extended_key_usage"] = props.Ekus
}
certProps["subject_alternative_names"] = sanOutputs
policy["x509_certificate_properties"] = []interface{}{certProps}
}

return []interface{}{policy}
}
1 change: 1 addition & 0 deletions azurerm/internal/services/keyvault/registration.go
Expand Up @@ -22,6 +22,7 @@ func (r Registration) WebsiteCategories() []string {
func (r Registration) SupportedDataSources() map[string]*schema.Resource {
return map[string]*schema.Resource{
"azurerm_key_vault_access_policy": dataSourceArmKeyVaultAccessPolicy(),
"azurerm_key_vault_certificate": dataSourceArmKeyVaultCertificate(),
"azurerm_key_vault_key": dataSourceArmKeyVaultKey(),
"azurerm_key_vault_secret": dataSourceArmKeyVaultSecret(),
"azurerm_key_vault": dataSourceArmKeyVault(),
Expand Down

0 comments on commit d6624b3

Please sign in to comment.