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 subject alternative names to azurerm_key_vault_certificate #2123

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
524a35f
azurerm_keyvault_certificate: Add subject alternative names
draggeta Oct 20, 2018
31ed307
azurerm_keyvault_certificate: update example as it is broken
draggeta Oct 20, 2018
c04c4a4
azurerm_keyvault_certificate: update documentation to add san capability
draggeta Oct 20, 2018
eb2533c
azurerm_keyvault_certificate: update test to deploy SANs
draggeta Oct 20, 2018
9e4ee91
azurerm_key_vault_certificate: remove unnecessary commented code
draggeta Oct 20, 2018
bcd540c
Update san acceptance tests
draggeta Oct 22, 2018
b2c569d
Update acceptance tests
draggeta Oct 22, 2018
bca17b8
azurerm_key_vault_certificate: documentation, changed email to emails
draggeta Oct 22, 2018
dc2f6cb
merge master
draggeta Oct 25, 2018
468d60d
azurerm_key_vault_certificate: fix unnecessary conversions, gofmt -s run
draggeta Oct 25, 2018
029686f
azurerm_key_vault_certificate: fix errors
draggeta Oct 26, 2018
6caa257
make fmt
katbyte Oct 27, 2018
786fe4b
Update azurerm/resource_arm_key_vault_certificate.go
tombuildsstuff Oct 27, 2018
853c3a2
Update azurerm/resource_arm_key_vault_certificate.go
tombuildsstuff Oct 27, 2018
46dfdd2
Update azurerm/resource_arm_key_vault_certificate.go
tombuildsstuff Oct 27, 2018
dd26590
Update azurerm/resource_arm_key_vault_certificate.go
tombuildsstuff Oct 27, 2018
add8500
azurerm_key_vault_certificate: Add requested changes
draggeta Oct 27, 2018
6d5c7d0
Merge branch 'master' of https://github.com/terraform-providers/terra…
draggeta Oct 27, 2018
8cc14a8
make subject_alternative_names computed
draggeta Oct 28, 2018
6fdb279
Flatten array always
draggeta Oct 28, 2018
3111e78
fix panic regarding empty item
draggeta Oct 28, 2018
8b3f5fe
remove if statements
draggeta Oct 28, 2018
de467bb
Fix the gofmt issue by running version 1.10 version of binary
draggeta Oct 29, 2018
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
89 changes: 85 additions & 4 deletions azurerm/resource_arm_key_vault_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,39 @@ func resourceArmKeyVaultCertificate() *schema.Resource {
Required: true,
ForceNew: true,
},
"subject_alternative_names": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"emails": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"dns_names": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"upns": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"validity_in_months": {
Type: schema.TypeInt,
Required: true,
Expand Down Expand Up @@ -474,17 +507,47 @@ func expandKeyVaultCertificatePolicy(d *schema.ResourceData) keyvault.Certificat
keyUsage = append(keyUsage, keyvault.KeyUsageType(key.(string)))
}

subjectAlternativeNames := &keyvault.SubjectAlternativeNames{}
if v, ok := cert["subject_alternative_names"]; ok {
sans := v.([]interface{})
san := sans[0].(map[string]interface{})

emails := san["emails"].([]interface{})
if len(emails) > 0 {
subjectAlternativeNames.Emails = expandKeyVaultSanProperty(emails)
}

dnsNames := san["dns_names"].([]interface{})
if len(dnsNames) > 0 {
subjectAlternativeNames.DNSNames = expandKeyVaultSanProperty(dnsNames)
}

upns := san["upns"].([]interface{})
if len(upns) > 0 {
subjectAlternativeNames.Upns = expandKeyVaultSanProperty(upns)
}
}

policy.X509CertificateProperties = &keyvault.X509CertificateProperties{
ValidityInMonths: utils.Int32(int32(cert["validity_in_months"].(int))),
Subject: utils.String(cert["subject"].(string)),
KeyUsage: &keyUsage,
Ekus: extendedKeyUsage,
ValidityInMonths: utils.Int32(int32(cert["validity_in_months"].(int))),
Subject: utils.String(cert["subject"].(string)),
KeyUsage: &keyUsage,
Ekus: extendedKeyUsage,
SubjectAlternativeNames: subjectAlternativeNames,
}
}

return policy
}

func expandKeyVaultSanProperty(input []interface{}) *[]string {
Copy link
Collaborator

@katbyte katbyte Oct 27, 2018

Choose a reason for hiding this comment

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

There is a utils.ExpandStringArray that does exactly this

properties := make([]string, len(input))
for i, v := range input {
properties[i] = fmt.Sprint(v)
}
return &properties
}

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

Expand Down Expand Up @@ -549,13 +612,31 @@ func flattenKeyVaultCertificatePolicy(input *keyvault.CertificatePolicy) []inter
for _, usage := range *props.KeyUsage {
usages = append(usages, string(usage))
}

sanOutput := make(map[string]interface{}, 0)
draggeta marked this conversation as resolved.
Show resolved Hide resolved
if san := props.SubjectAlternativeNames; san != nil {
if emails := san.Emails; emails != nil {
draggeta marked this conversation as resolved.
Show resolved Hide resolved
sanOutput["emails"] = *san.Emails
}

if dnsNames := san.DNSNames; dnsNames != nil {
sanOutput["dns_names"] = *san.DNSNames
}

if upns := san.Upns; upns != nil {
sanOutput["upns"] = *san.Upns
}
draggeta marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

in retrospect (since they're returned from the API) - we'll want to always flatten these fields (even if there's no items returned) - as such we should be able to make this:

sanOutput["emails"] = utils.FlattenStringArray(san.Emails)
sanOutput["dns_names"] = utils.FlattenStringArray(san.DNSNames)
sanOutput["upns"] = utils.FlattenStringArray(san.Upns)

}

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"] = []interface{}{sanOutput}

policy["x509_certificate_properties"] = []interface{}{certProps}
}

Expand Down
119 changes: 119 additions & 0 deletions azurerm/resource_arm_key_vault_certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,30 @@ func TestAccAzureRMKeyVaultCertificate_basicGenerate(t *testing.T) {
})
}

func TestAccAzureRMKeyVaultCertificate_basicGenerateSans(t *testing.T) {
resourceName := "azurerm_key_vault_certificate.test"
rs := acctest.RandString(6)
config := testAccAzureRMKeyVaultCertificate_basicGenerateSans(rs, testLocation())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMKeyVaultCertificateDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMKeyVaultCertificateExists(resourceName),
resource.TestCheckResourceAttrSet(resourceName, "certificate_data"),
resource.TestCheckResourceAttr(resourceName, "certificate_policy.0.x509_certificate_properties.0.subject_alternative_names.0.emails.0", "mary@stu.co.uk"),
resource.TestCheckResourceAttr(resourceName, "certificate_policy.0.x509_certificate_properties.0.subject_alternative_names.0.dns_names.0", "internal.contoso.com"),
resource.TestCheckResourceAttr(resourceName, "certificate_policy.0.x509_certificate_properties.0.subject_alternative_names.0.upns.0", "john@doe.com"),
),
},
},
})
}

func TestAccAzureRMKeyVaultCertificate_basicGenerateTags(t *testing.T) {
resourceName := "azurerm_key_vault_certificate.test"
rs := acctest.RandString(6)
Expand Down Expand Up @@ -379,6 +403,101 @@ resource "azurerm_key_vault_certificate" "test" {

`, rString, location, rString, rString)
}

func testAccAzureRMKeyVaultCertificate_basicGenerateSans(rString string, location string) string {
return fmt.Sprintf(`
data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-%s"
location = "%s"
}

resource "azurerm_key_vault" "test" {
name = "acctestkeyvault%s"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
tenant_id = "${data.azurerm_client_config.current.tenant_id}"

sku {
name = "standard"
}

access_policy {
tenant_id = "${data.azurerm_client_config.current.tenant_id}"
object_id = "${data.azurerm_client_config.current.service_principal_object_id}"

certificate_permissions = [
"create",
"delete",
"get",
"update"
]

key_permissions = [
"create",
]

secret_permissions = [
"set",
]
}
}

resource "azurerm_key_vault_certificate" "test" {
name = "acctestcert%s"
vault_uri = "${azurerm_key_vault.test.vault_uri}"

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",
"keyCertSign",
"keyEncipherment",
]

subject = "CN=hello-world"
subject_alternative_names {
emails = ["mary@stu.co.uk"]
dns_names = ["internal.contoso.com"]
upns = ["john@doe.com"]
}
validity_in_months = 12
}
}
}

`, rString, location, rString, rString)
}

func testAccAzureRMKeyVaultCertificate_basicGenerateTags(rString string, location string) string {
return fmt.Sprintf(`
data "azurerm_client_config" "current" {}
Expand Down
22 changes: 19 additions & 3 deletions website/docs/r/key_vault_certificate.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,20 @@ resource "azurerm_key_vault" "test" {
object_id = "${data.azurerm_client_config.current.service_principal_object_id}"

certificate_permissions = [
"all",
"create","delete","deleteissuers",
"get","getissuers","import","list",
"listissuers","managecontacts","manageissuers",
"setissuers","update",
]

key_permissions = [
"all",
"backup","create","decrypt","delete","encrypt","get",
"import","list","purge","recover","restore","sign",
"unwrapKey","update","verify","wrapKey",
]

secret_permissions = [
"all",
"backup","delete","get","list","purge","recover","restore","set",
]
}

Expand Down Expand Up @@ -198,6 +203,10 @@ resource "azurerm_key_vault_certificate" "test" {
"keyEncipherment",
]

subject_alternative_names {
dns_names = ["internal.contoso.com", "domain.hello.world"]
}

subject = "CN=hello-world"
validity_in_months = 12
}
Expand Down Expand Up @@ -269,8 +278,15 @@ The following arguments are supported:
* `extended_key_usage` - (Optional) A list of Extended/Enhanced Key Usages. If this argument is not specified, it defaults to `["1.3.6.1.5.5.7.3.1","1.3.6.1.5.5.7.3.2"]` (Server Authentication and Client Authentication respectively). Changing this forces a new resource to be created.
* `key_usage` - (Required) A list of uses associated with this Key. Possible values include `cRLSign`, `dataEncipherment`, `decipherOnly`, `digitalSignature`, `encipherOnly`, `keyAgreement`, `keyCertSign`, `keyEncipherment` and `nonRepudiation` and are case-sensitive. Changing this forces a new resource to be created.
* `subject` - (Required) The Certificate's Subject. Changing this forces a new resource to be created.
* `subject_alternative_names` - (Optional) A `subject_alternative_names` block as defined below.
* `validity_in_months` - (Required) The Certificates Validity Period in Months. Changing this forces a new resource to be created.

`subject_alternative_names` supports the following:

* `dns_names` - (Optional) A list of alternative DNS names (FQDNs) identified by the Certificate. Changing this forces a new resource to be created.
* `emails` - (Optional) A list of email addresses identified by this Certificate. Changing this forces a new resource to be created.
* `upns` - (Optional) A list of User Principal Names identified by the Certificate. Changing this forces a new resource to be created.


## Attributes Reference

Expand Down