Skip to content

Commit

Permalink
azurerm_key_vault_certificate: expose arm resource id (#21314)
Browse files Browse the repository at this point in the history
* export arm id

* expose keyvault certificate arm style id, just as secret

* rename resource id field name

* update kv certificate document
  • Loading branch information
wuxu92 authored Apr 12, 2023
1 parent 973e7a5 commit 4e065b7
Show file tree
Hide file tree
Showing 15 changed files with 702 additions and 0 deletions.
13 changes: 13 additions & 0 deletions internal/services/keyvault/key_vault_certificate_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ func dataSourceKeyVaultCertificate() *pluginsdk.Resource {
ValidateFunc: keyVaultValidate.VaultID,
},

"resource_manager_id": {
Computed: true,
Type: pluginsdk.TypeString,
},

"resource_manager_versionless_id": {
Computed: true,
Type: pluginsdk.TypeString,
},

"version": {
Type: pluginsdk.TypeString,
Optional: true,
Expand Down Expand Up @@ -298,6 +308,9 @@ func dataSourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface
d.Set("secret_id", cert.Sid)
d.Set("versionless_id", id.VersionlessID())

d.Set("resource_manager_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID())
d.Set("resource_manager_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID())

if cert.Sid != nil {
secretId, err := parse.ParseNestedItemID(*cert.Sid)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func TestAccDataSourceKeyVaultCertificate_basic(t *testing.T) {
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("certificate_data").Exists(),
check.That(data.ResourceName).Key("certificate_data_base64").Exists(),
check.That(data.ResourceName).Key("resource_manager_id").Exists(),
check.That(data.ResourceName).Key("resource_manager_versionless_id").Exists(),
check.That(data.ResourceName).Key("certificate_policy.0.key_properties.0.key_size").HasValue("2048"),
check.That(data.ResourceName).Key("certificate_policy.0.key_properties.0.key_type").HasValue("RSA"),
check.That(data.ResourceName).Key("not_before").HasValue("2017-10-10T08:27:55Z"),
Expand Down
13 changes: 13 additions & 0 deletions internal/services/keyvault/key_vault_certificate_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,16 @@ func resourceKeyVaultCertificate() *pluginsdk.Resource {
},
},

"resource_manager_id": {
Computed: true,
Type: pluginsdk.TypeString,
},

"resource_manager_versionless_id": {
Computed: true,
Type: pluginsdk.TypeString,
},

"version": {
Type: pluginsdk.TypeString,
Computed: true,
Expand Down Expand Up @@ -682,6 +692,9 @@ func resourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface{}
d.Set("secret_id", cert.Sid)
d.Set("versionless_id", id.VersionlessID())

d.Set("resource_manager_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID())
d.Set("resource_manager_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID())

if cert.Sid != nil {
secretId, err := parse.ParseNestedItemID(*cert.Sid)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func TestAccKeyVaultCertificate_basicImportPFX(t *testing.T) {
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("certificate_data").Exists(),
check.That(data.ResourceName).Key("resource_manager_id").Exists(),
check.That(data.ResourceName).Key("resource_manager_versionless_id").Exists(),
check.That(data.ResourceName).Key("certificate_data_base64").Exists(),
check.That(data.ResourceName).Key("certificate_policy.0.secret_properties.0.content_type").HasValue("application/x-pkcs12"),
check.That(data.ResourceName).Key("versionless_id").HasValue(fmt.Sprintf("https://acctestkeyvault%s.vault.azure.net/certificates/acctestcert%s", data.RandomString, data.RandomString)),
Expand Down
81 changes: 81 additions & 0 deletions internal/services/keyvault/parse/certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"fmt"
"strings"

"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
)

type CertificateId struct {
SubscriptionId string
ResourceGroup string
VaultName string
Name string
VersionName string
}

func NewCertificateID(subscriptionId, resourceGroup, vaultName, name, versionName string) CertificateId {
return CertificateId{
SubscriptionId: subscriptionId,
ResourceGroup: resourceGroup,
VaultName: vaultName,
Name: name,
VersionName: versionName,
}
}

func (id CertificateId) String() string {
segments := []string{
fmt.Sprintf("Version Name %q", id.VersionName),
fmt.Sprintf("Name %q", id.Name),
fmt.Sprintf("Vault Name %q", id.VaultName),
fmt.Sprintf("Resource Group %q", id.ResourceGroup),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "Certificate", segmentsStr)
}

func (id CertificateId) ID() string {
fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.KeyVault/vaults/%s/certificates/%s/versions/%s"
return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.VaultName, id.Name, id.VersionName)
}

// CertificateID parses a Certificate ID into an CertificateId struct
func CertificateID(input string) (*CertificateId, error) {
id, err := resourceids.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

resourceId := CertificateId{
SubscriptionId: id.SubscriptionID,
ResourceGroup: id.ResourceGroup,
}

if resourceId.SubscriptionId == "" {
return nil, fmt.Errorf("ID was missing the 'subscriptions' element")
}

if resourceId.ResourceGroup == "" {
return nil, fmt.Errorf("ID was missing the 'resourceGroups' element")
}

if resourceId.VaultName, err = id.PopSegment("vaults"); err != nil {
return nil, err
}
if resourceId.Name, err = id.PopSegment("certificates"); err != nil {
return nil, err
}
if resourceId.VersionName, err = id.PopSegment("versions"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &resourceId, nil
}
144 changes: 144 additions & 0 deletions internal/services/keyvault/parse/certificate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"testing"

"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
)

var _ resourceids.Id = CertificateId{}

func TestCertificateIDFormatter(t *testing.T) {
actual := NewCertificateID("12345678-1234-9876-4563-123456789012", "resGroup1", "vault1", "cert1", "version1").ID()
expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1"
if actual != expected {
t.Fatalf("Expected %q but got %q", expected, actual)
}
}

func TestCertificateID(t *testing.T) {
testData := []struct {
Input string
Error bool
Expected *CertificateId
}{

{
// empty
Input: "",
Error: true,
},

{
// missing SubscriptionId
Input: "/",
Error: true,
},

{
// missing value for SubscriptionId
Input: "/subscriptions/",
Error: true,
},

{
// missing ResourceGroup
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/",
Error: true,
},

{
// missing value for ResourceGroup
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/",
Error: true,
},

{
// missing VaultName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/",
Error: true,
},

{
// missing value for VaultName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/",
Error: true,
},

{
// missing Name
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/",
Error: true,
},

{
// missing value for Name
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/",
Error: true,
},

{
// missing VersionName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/",
Error: true,
},

{
// missing value for VersionName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/",
Error: true,
},

{
// valid
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1",
Expected: &CertificateId{
SubscriptionId: "12345678-1234-9876-4563-123456789012",
ResourceGroup: "resGroup1",
VaultName: "vault1",
Name: "cert1",
VersionName: "version1",
},
},

{
// upper-cased
Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/VAULT1/CERTIFICATES/CERT1/VERSIONS/VERSION1",
Error: true,
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q", v.Input)

actual, err := CertificateID(v.Input)
if err != nil {
if v.Error {
continue
}

t.Fatalf("Expect a value but got an error: %s", err)
}
if v.Error {
t.Fatal("Expect an error but didn't get one")
}

if actual.SubscriptionId != v.Expected.SubscriptionId {
t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId)
}
if actual.ResourceGroup != v.Expected.ResourceGroup {
t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup)
}
if actual.VaultName != v.Expected.VaultName {
t.Fatalf("Expected %q but got %q for VaultName", v.Expected.VaultName, actual.VaultName)
}
if actual.Name != v.Expected.Name {
t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name)
}
if actual.VersionName != v.Expected.VersionName {
t.Fatalf("Expected %q but got %q for VersionName", v.Expected.VersionName, actual.VersionName)
}
}
}
75 changes: 75 additions & 0 deletions internal/services/keyvault/parse/certificate_versionless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"fmt"
"strings"

"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
)

type CertificateVersionlessId struct {
SubscriptionId string
ResourceGroup string
VaultName string
CertificateName string
}

func NewCertificateVersionlessID(subscriptionId, resourceGroup, vaultName, certificateName string) CertificateVersionlessId {
return CertificateVersionlessId{
SubscriptionId: subscriptionId,
ResourceGroup: resourceGroup,
VaultName: vaultName,
CertificateName: certificateName,
}
}

func (id CertificateVersionlessId) String() string {
segments := []string{
fmt.Sprintf("Certificate Name %q", id.CertificateName),
fmt.Sprintf("Vault Name %q", id.VaultName),
fmt.Sprintf("Resource Group %q", id.ResourceGroup),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "Certificate Versionless", segmentsStr)
}

func (id CertificateVersionlessId) ID() string {
fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.KeyVault/vaults/%s/certificates/%s"
return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.VaultName, id.CertificateName)
}

// CertificateVersionlessID parses a CertificateVersionless ID into an CertificateVersionlessId struct
func CertificateVersionlessID(input string) (*CertificateVersionlessId, error) {
id, err := resourceids.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

resourceId := CertificateVersionlessId{
SubscriptionId: id.SubscriptionID,
ResourceGroup: id.ResourceGroup,
}

if resourceId.SubscriptionId == "" {
return nil, fmt.Errorf("ID was missing the 'subscriptions' element")
}

if resourceId.ResourceGroup == "" {
return nil, fmt.Errorf("ID was missing the 'resourceGroups' element")
}

if resourceId.VaultName, err = id.PopSegment("vaults"); err != nil {
return nil, err
}
if resourceId.CertificateName, err = id.PopSegment("certificates"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &resourceId, nil
}
Loading

0 comments on commit 4e065b7

Please sign in to comment.