diff --git a/azurerm/resource_arm_key_vault_certificate.go b/azurerm/resource_arm_key_vault_certificate.go index b3d427b75526..514d2afa04d3 100644 --- a/azurerm/resource_arm_key_vault_certificate.go +++ b/azurerm/resource_arm_key_vault_certificate.go @@ -220,6 +220,41 @@ func resourceArmKeyVaultCertificate() *schema.Resource { Required: true, ForceNew: true, }, + "subject_alternative_names": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Computed: 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, @@ -474,11 +509,37 @@ 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 { + + if sans := v.([]interface{}); len(sans) > 0 { + if sans[0] != nil { + san := sans[0].(map[string]interface{}) + + emails := san["emails"].([]interface{}) + if len(emails) > 0 { + subjectAlternativeNames.Emails = utils.ExpandStringArray(emails) + } + + dnsNames := san["dns_names"].([]interface{}) + if len(dnsNames) > 0 { + subjectAlternativeNames.DNSNames = utils.ExpandStringArray(dnsNames) + } + + upns := san["upns"].([]interface{}) + if len(upns) > 0 { + subjectAlternativeNames.Upns = utils.ExpandStringArray(upns) + } + } + } + } + policy.X509CertificateProperties = &keyvault.X509CertificateProperties{ ValidityInMonths: utils.Int32(int32(cert["validity_in_months"].(int))), Subject: utils.String(cert["subject"].(string)), KeyUsage: &keyUsage, Ekus: extendedKeyUsage, + SubjectAlternativeNames: subjectAlternativeNames, } } @@ -549,13 +610,25 @@ func flattenKeyVaultCertificatePolicy(input *keyvault.CertificatePolicy) []inter 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{}, 0) + + sanOutput["emails"] = utils.FlattenStringArray(san.Emails) + sanOutput["dns_names"] = utils.FlattenStringArray(san.DNSNames) + sanOutput["upns"] = utils.FlattenStringArray(san.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} } diff --git a/azurerm/resource_arm_key_vault_certificate_test.go b/azurerm/resource_arm_key_vault_certificate_test.go index c7b31b38e513..3adce3be1fdb 100644 --- a/azurerm/resource_arm_key_vault_certificate_test.go +++ b/azurerm/resource_arm_key_vault_certificate_test.go @@ -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) @@ -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" {} diff --git a/website/docs/r/key_vault_certificate.html.markdown b/website/docs/r/key_vault_certificate.html.markdown index 3ddf8f8a769b..d1f016fb6cf4 100644 --- a/website/docs/r/key_vault_certificate.html.markdown +++ b/website/docs/r/key_vault_certificate.html.markdown @@ -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", ] } @@ -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 } @@ -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