Skip to content

Commit d6624b3

Browse files
authored
Merge pull request #7285 from terraform-providers/d/kv-certificate-datasource
New data source azurerm_key_vault_certificate
2 parents 1e850c6 + 18a1eb4 commit d6624b3

File tree

5 files changed

+593
-0
lines changed

5 files changed

+593
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
package keyvault
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/hex"
6+
"fmt"
7+
"log"
8+
"strings"
9+
"time"
10+
11+
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
12+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
13+
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
14+
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
15+
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
16+
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
17+
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
18+
)
19+
20+
func dataSourceArmKeyVaultCertificate() *schema.Resource {
21+
return &schema.Resource{
22+
Read: dataSourceArmKeyVaultCertificateRead,
23+
24+
Timeouts: &schema.ResourceTimeout{
25+
Read: schema.DefaultTimeout(5 * time.Minute),
26+
},
27+
28+
Schema: map[string]*schema.Schema{
29+
"name": {
30+
Type: schema.TypeString,
31+
Required: true,
32+
ValidateFunc: azure.ValidateKeyVaultChildName,
33+
},
34+
35+
"key_vault_id": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
ValidateFunc: azure.ValidateResourceID,
39+
},
40+
41+
"version": {
42+
Type: schema.TypeString,
43+
Optional: true,
44+
Computed: true,
45+
},
46+
47+
// Computed
48+
"certificate_policy": {
49+
Type: schema.TypeList,
50+
Computed: true,
51+
Elem: &schema.Resource{
52+
Schema: map[string]*schema.Schema{
53+
"issuer_parameters": {
54+
Type: schema.TypeList,
55+
Computed: true,
56+
Elem: &schema.Resource{
57+
Schema: map[string]*schema.Schema{
58+
"name": {
59+
Type: schema.TypeString,
60+
Computed: true,
61+
},
62+
},
63+
},
64+
},
65+
"key_properties": {
66+
Type: schema.TypeList,
67+
Computed: true,
68+
Elem: &schema.Resource{
69+
Schema: map[string]*schema.Schema{
70+
"exportable": {
71+
Type: schema.TypeBool,
72+
Computed: true,
73+
},
74+
"key_size": {
75+
Type: schema.TypeInt,
76+
Computed: true,
77+
},
78+
"key_type": {
79+
Type: schema.TypeString,
80+
Computed: true,
81+
},
82+
"reuse_key": {
83+
Type: schema.TypeBool,
84+
Computed: true,
85+
},
86+
},
87+
},
88+
},
89+
90+
"lifetime_action": {
91+
Type: schema.TypeList,
92+
Optional: true,
93+
Elem: &schema.Resource{
94+
Schema: map[string]*schema.Schema{
95+
"action": {
96+
Type: schema.TypeList,
97+
Computed: true,
98+
Elem: &schema.Resource{
99+
Schema: map[string]*schema.Schema{
100+
"action_type": {
101+
Type: schema.TypeString,
102+
Computed: true,
103+
},
104+
},
105+
},
106+
},
107+
"trigger": {
108+
Type: schema.TypeList,
109+
Computed: true,
110+
Elem: &schema.Resource{
111+
Schema: map[string]*schema.Schema{
112+
"days_before_expiry": {
113+
Type: schema.TypeInt,
114+
Computed: true,
115+
},
116+
"lifetime_percentage": {
117+
Type: schema.TypeInt,
118+
Computed: true,
119+
},
120+
},
121+
},
122+
},
123+
},
124+
},
125+
},
126+
127+
"secret_properties": {
128+
Type: schema.TypeList,
129+
Required: true,
130+
Elem: &schema.Resource{
131+
Schema: map[string]*schema.Schema{
132+
"content_type": {
133+
Type: schema.TypeString,
134+
Computed: true,
135+
},
136+
},
137+
},
138+
},
139+
140+
"x509_certificate_properties": {
141+
Type: schema.TypeList,
142+
Computed: true,
143+
Elem: &schema.Resource{
144+
Schema: map[string]*schema.Schema{
145+
"extended_key_usage": {
146+
Type: schema.TypeList,
147+
Computed: true,
148+
Elem: &schema.Schema{
149+
Type: schema.TypeString,
150+
},
151+
},
152+
"key_usage": {
153+
Type: schema.TypeList,
154+
Computed: true,
155+
Elem: &schema.Schema{
156+
Type: schema.TypeString,
157+
},
158+
},
159+
"subject": {
160+
Type: schema.TypeString,
161+
Computed: true,
162+
},
163+
"subject_alternative_names": {
164+
Type: schema.TypeList,
165+
Computed: true,
166+
Elem: &schema.Resource{
167+
Schema: map[string]*schema.Schema{
168+
"emails": {
169+
Type: schema.TypeList,
170+
Computed: true,
171+
Elem: &schema.Schema{
172+
Type: schema.TypeString,
173+
},
174+
},
175+
"dns_names": {
176+
Type: schema.TypeList,
177+
Computed: true,
178+
Elem: &schema.Schema{
179+
Type: schema.TypeString,
180+
},
181+
},
182+
"upns": {
183+
Type: schema.TypeList,
184+
Computed: true,
185+
Elem: &schema.Schema{
186+
Type: schema.TypeString,
187+
},
188+
},
189+
},
190+
},
191+
},
192+
"validity_in_months": {
193+
Type: schema.TypeInt,
194+
Computed: true,
195+
},
196+
},
197+
},
198+
},
199+
},
200+
},
201+
},
202+
203+
"secret_id": {
204+
Type: schema.TypeString,
205+
Computed: true,
206+
},
207+
208+
"certificate_data": {
209+
Type: schema.TypeString,
210+
Computed: true,
211+
},
212+
213+
"thumbprint": {
214+
Type: schema.TypeString,
215+
Computed: true,
216+
},
217+
218+
"tags": tags.SchemaDataSource(),
219+
},
220+
}
221+
}
222+
223+
func dataSourceArmKeyVaultCertificateRead(d *schema.ResourceData, meta interface{}) error {
224+
vaultClient := meta.(*clients.Client).KeyVault.VaultsClient
225+
client := meta.(*clients.Client).KeyVault.ManagementClient
226+
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
227+
defer cancel()
228+
229+
name := d.Get("name").(string)
230+
keyVaultId := d.Get("key_vault_id").(string)
231+
version := d.Get("version").(string)
232+
233+
keyVaultBaseUri, err := azure.GetKeyVaultBaseUrlFromID(ctx, vaultClient, keyVaultId)
234+
if err != nil {
235+
return fmt.Errorf("Error looking up Key %q vault url from id %q: %+v", name, keyVaultId, err)
236+
}
237+
238+
cert, err := client.GetCertificate(ctx, keyVaultBaseUri, name, version)
239+
if err != nil {
240+
if utils.ResponseWasNotFound(cert.Response) {
241+
log.Printf("[DEBUG] Certificate %q was not found in Key Vault at URI %q - removing from state", name, keyVaultBaseUri)
242+
d.SetId("")
243+
return nil
244+
}
245+
246+
return fmt.Errorf("Error reading Key Vault Certificate: %+v", err)
247+
}
248+
249+
if cert.ID == nil || *cert.ID == "" {
250+
return fmt.Errorf("failure reading Key Vault Certificate ID for %q", name)
251+
}
252+
253+
d.SetId(*cert.ID)
254+
255+
id, err := azure.ParseKeyVaultChildID(*cert.ID)
256+
if err != nil {
257+
return err
258+
}
259+
260+
d.Set("name", id.Name)
261+
262+
certificatePolicy := flattenKeyVaultCertificatePolicyForDataSource(cert.Policy)
263+
if err := d.Set("certificate_policy", certificatePolicy); err != nil {
264+
return fmt.Errorf("Error setting Key Vault Certificate Policy: %+v", err)
265+
}
266+
267+
d.Set("version", id.Version)
268+
d.Set("secret_id", cert.Sid)
269+
270+
certificateData := ""
271+
if contents := cert.Cer; contents != nil {
272+
certificateData = strings.ToUpper(hex.EncodeToString(*contents))
273+
}
274+
d.Set("certificate_data", certificateData)
275+
276+
thumbprint := ""
277+
if v := cert.X509Thumbprint; v != nil {
278+
x509Thumbprint, err := base64.RawURLEncoding.DecodeString(*v)
279+
if err != nil {
280+
return err
281+
}
282+
283+
thumbprint = strings.ToUpper(hex.EncodeToString(x509Thumbprint))
284+
}
285+
d.Set("thumbprint", thumbprint)
286+
287+
return tags.FlattenAndSet(d, cert.Tags)
288+
}
289+
290+
func flattenKeyVaultCertificatePolicyForDataSource(input *keyvault.CertificatePolicy) []interface{} {
291+
policy := make(map[string]interface{})
292+
293+
if params := input.IssuerParameters; params != nil {
294+
issuerParams := make(map[string]interface{})
295+
issuerParams["name"] = *params.Name
296+
policy["issuer_parameters"] = []interface{}{issuerParams}
297+
}
298+
299+
// key properties
300+
if props := input.KeyProperties; props != nil {
301+
keyProps := make(map[string]interface{})
302+
keyProps["exportable"] = *props.Exportable
303+
keyProps["key_size"] = int(*props.KeySize)
304+
keyProps["key_type"] = *props.KeyType
305+
keyProps["reuse_key"] = *props.ReuseKey
306+
307+
policy["key_properties"] = []interface{}{keyProps}
308+
}
309+
310+
// lifetime actions
311+
lifetimeActions := make([]interface{}, 0)
312+
if actions := input.LifetimeActions; actions != nil {
313+
for _, action := range *actions {
314+
lifetimeAction := make(map[string]interface{})
315+
316+
actionOutput := make(map[string]interface{})
317+
if act := action.Action; act != nil {
318+
actionOutput["action_type"] = string(act.ActionType)
319+
}
320+
lifetimeAction["action"] = []interface{}{actionOutput}
321+
322+
triggerOutput := make(map[string]interface{})
323+
if trigger := action.Trigger; trigger != nil {
324+
if days := trigger.DaysBeforeExpiry; days != nil {
325+
triggerOutput["days_before_expiry"] = int(*trigger.DaysBeforeExpiry)
326+
}
327+
328+
if days := trigger.LifetimePercentage; days != nil {
329+
triggerOutput["lifetime_percentage"] = int(*trigger.LifetimePercentage)
330+
}
331+
}
332+
lifetimeAction["trigger"] = []interface{}{triggerOutput}
333+
lifetimeActions = append(lifetimeActions, lifetimeAction)
334+
}
335+
}
336+
policy["lifetime_action"] = lifetimeActions
337+
338+
// secret properties
339+
if props := input.SecretProperties; props != nil {
340+
keyProps := make(map[string]interface{})
341+
keyProps["content_type"] = *props.ContentType
342+
343+
policy["secret_properties"] = []interface{}{keyProps}
344+
}
345+
346+
// x509 Certificate Properties
347+
if props := input.X509CertificateProperties; props != nil {
348+
certProps := make(map[string]interface{})
349+
350+
usages := make([]string, 0)
351+
for _, usage := range *props.KeyUsage {
352+
usages = append(usages, string(usage))
353+
}
354+
355+
sanOutputs := make([]interface{}, 0)
356+
if san := props.SubjectAlternativeNames; san != nil {
357+
sanOutput := make(map[string]interface{})
358+
if emails := san.Emails; emails != nil {
359+
sanOutput["emails"] = *emails
360+
}
361+
if dnsNames := san.DNSNames; dnsNames != nil {
362+
sanOutput["dns_names"] = *dnsNames
363+
}
364+
if upns := san.Upns; upns != nil {
365+
sanOutput["upns"] = *upns
366+
}
367+
368+
sanOutputs = append(sanOutputs, sanOutput)
369+
}
370+
371+
certProps["key_usage"] = usages
372+
certProps["subject"] = *props.Subject
373+
certProps["validity_in_months"] = int(*props.ValidityInMonths)
374+
if props.Ekus != nil {
375+
certProps["extended_key_usage"] = props.Ekus
376+
}
377+
certProps["subject_alternative_names"] = sanOutputs
378+
policy["x509_certificate_properties"] = []interface{}{certProps}
379+
}
380+
381+
return []interface{}{policy}
382+
}

azurerm/internal/services/keyvault/registration.go

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func (r Registration) WebsiteCategories() []string {
2222
func (r Registration) SupportedDataSources() map[string]*schema.Resource {
2323
return map[string]*schema.Resource{
2424
"azurerm_key_vault_access_policy": dataSourceArmKeyVaultAccessPolicy(),
25+
"azurerm_key_vault_certificate": dataSourceArmKeyVaultCertificate(),
2526
"azurerm_key_vault_key": dataSourceArmKeyVaultKey(),
2627
"azurerm_key_vault_secret": dataSourceArmKeyVaultSecret(),
2728
"azurerm_key_vault": dataSourceArmKeyVault(),

0 commit comments

Comments
 (0)