Skip to content

Commit

Permalink
shared_image_version_resource - add uefi_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
yeoldegrove committed Nov 14, 2024
1 parent 0213933 commit 092ccf4
Show file tree
Hide file tree
Showing 2 changed files with 304 additions and 5 deletions.
251 changes: 246 additions & 5 deletions internal/services/compute/shared_image_version_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,62 @@ func resourceSharedImageVersion() *pluginsdk.Resource {
Default: false,
},

"uefi_settings": {
Type: pluginsdk.TypeList,
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"signature_template_names": {
Type: pluginsdk.TypeList,
Required: true,
Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString},
// not supported yet
// ValidateFunc: validation.StringInSlice(galleryimageversions.PossibleValuesForUefiSignatureTemplateName(), false),
},
"additional_signatures": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"db": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: uefiKeySchema(),
},
"dbx": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: uefiKeySchema(),
},
"kek": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: uefiKeySchema(),
},
"pk": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: uefiKeySchema(),
},
},
},
},
},
},
},

"tags": commonschema.Tags(),
},

CustomizeDiff: pluginsdk.CustomDiffWithAll(
pluginsdk.ForceNewIfChange("end_of_life_date", func(ctx context.Context, old, new, meta interface{}) bool {
return old.(string) != "" && new.(string) == ""
}),
),
CustomizeDiff: pluginsdk.CustomDiffWithAll(
pluginsdk.ForceNewIfChange("end_of_life_date", func(ctx context.Context, old, new, meta interface{}) bool {
return old.(string) != "" && new.(string) == ""
}),
),
}
}

Expand Down Expand Up @@ -237,6 +285,9 @@ func resourceSharedImageVersionCreate(d *pluginsdk.ResourceData, meta interface{
AllowDeletionOfReplicatedLocations: utils.Bool(d.Get("deletion_of_replicated_locations_enabled").(bool)),
},
StorageProfile: galleryimageversions.GalleryImageVersionStorageProfile{},
SecurityProfile: &galleryimageversions.ImageVersionSecurityProfile{
UefiSettings: expandUefiSettings(d),
},
},
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}
Expand Down Expand Up @@ -330,6 +381,12 @@ func resourceSharedImageVersionUpdate(d *pluginsdk.ResourceData, meta interface{
payload.Properties.PublishingProfile.ExcludeFromLatest = pointer.To(d.Get("exclude_from_latest").(bool))
}

if d.HasChange("uefi_settings") {
payload.Properties.SecurityProfile = &galleryimageversions.ImageVersionSecurityProfile{
UefiSettings: expandUefiSettings(d),
}
}

if d.HasChange("tags") {
payload.Tags = tags.Expand(d.Get("tags").(map[string]interface{}))
}
Expand Down Expand Up @@ -416,6 +473,17 @@ func resourceSharedImageVersionRead(d *pluginsdk.ResourceData, meta interface{})
if safetyProfile := props.SafetyProfile; safetyProfile != nil {
d.Set("deletion_of_replicated_locations_enabled", pointer.From(safetyProfile.AllowDeletionOfReplicatedLocations))
}

if securityProfile := props.SecurityProfile; securityProfile != nil {
if uefiSettings := securityProfile.UefiSettings; uefiSettings != nil {
d.Set("uefi_settings", []interface{}{
map[string]interface{}{
"signature_template_names": uefiSettings.SignatureTemplateNames,
"additional_signatures": flattenAdditionalSignatures(uefiSettings.AdditionalSignatures),
},
})
}
}
}
return tags.FlattenAndSet(d, model.Tags)
}
Expand Down Expand Up @@ -511,6 +579,179 @@ func expandSharedImageVersionTargetRegions(d *pluginsdk.ResourceData) (*[]galler
return &results, nil
}

func uefiKeySchema() *pluginsdk.Resource {
possibleKeyTypes := galleryimageversions.PossibleValuesForUefiKeyType()

validKeyTypes := make([]string, len(possibleKeyTypes))
for i, keyType := range possibleKeyTypes {
validKeyTypes[i] = string(keyType)
}

return &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"certificate_data": {
Type: pluginsdk.TypeString,
Required: true,
},
"key_type": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(galleryimageversions.PossibleValuesForUefiKeyType(), false),
},
},
}
}

func expandUefiSettings(d *pluginsdk.ResourceData) *galleryimageversions.GalleryImageVersionUefiSettings {
if uefiSettings, ok := d.GetOk("uefi_settings"); ok {
settings := uefiSettings.([]interface{})
if len(settings) == 0 {
return nil
}

us := settings[0].(map[string]interface{})
return &galleryimageversions.GalleryImageVersionUefiSettings{
SignatureTemplateNames: expandStringList(us["signature_template_names"].([]interface{})),
AdditionalSignatures: expandAdditionalSignatures(us["additional_signatures"]),
}
}
return nil
}

func expandAdditionalSignatures(input interface{}) *galleryimageversions.UefiKeySignatures {
if input == nil {
return nil
}

data := input.([]interface{})[0].(map[string]interface{})
return &galleryimageversions.UefiKeySignatures{
Db: expandUefiKeyList(data["db"]),
Dbx: expandUefiKeyList(data["dbx"]),
Kek: expandUefiKeyList(data["kek"]),
Pk: expandSingleUefiKey(data["pk"]),
}
}

func expandUefiKeyList(input interface{}) *[]galleryimageversions.UefiKey {
if input == nil {
return nil
}

keys := input.([]interface{})
result := make([]galleryimageversions.UefiKey, len(keys))
for i, v := range keys {
result[i] = expandUefiKey(v.(map[string]interface{})) // Correctly returns a value, not a pointer
}
return &result
}

func expandSingleUefiKey(input interface{}) *galleryimageversions.UefiKey {
if input == nil {
return nil
}

keys := input.([]interface{})
if len(keys) == 0 {
return nil
}

data := keys[0].(map[string]interface{})
return &galleryimageversions.UefiKey{
Type: pointer.To(galleryimageversions.UefiKeyType(data["key_type"].(string))),
Value: &[]string{data["certificate_data"].(string)},
}
}

func expandUefiKey(data map[string]interface{}) galleryimageversions.UefiKey {
return galleryimageversions.UefiKey{
Type: pointer.To(galleryimageversions.UefiKeyType(data["key_type"].(string))),
Value: &[]string{data["certificate_data"].(string)},
}
}



func expandStringList(input []interface{}) *[]galleryimageversions.UefiSignatureTemplateName {
result := make([]galleryimageversions.UefiSignatureTemplateName, len(input))
for i, v := range input {
result[i] = galleryimageversions.UefiSignatureTemplateName(v.(string))
}
return &result
}

func flattenUefiSettings(input *galleryimageversions.GalleryImageVersionUefiSettings) []interface{} {
if input == nil {
return []interface{}{}
}

return []interface{}{
map[string]interface{}{
"signature_template_names": flattenStringList(*input.SignatureTemplateNames),
"additional_signatures": []interface{}{
flattenAdditionalSignatures(input.AdditionalSignatures),
},
},
}
}

func flattenAdditionalSignatures(input *galleryimageversions.UefiKeySignatures) map[string]interface{} {
if input == nil {
return map[string]interface{}{}
}

return map[string]interface{}{
"db": flattenUefiKeyList(input.Db),
"dbx": flattenUefiKeyList(input.Dbx),
"kek": flattenUefiKeyList(input.Kek),
"pk": flattenSingleUefiKey(input.Pk),
}
}

func flattenSingleUefiKey(input *galleryimageversions.UefiKey) []interface{} {
if input == nil || input.Value == nil || len(*input.Value) == 0 {
return []interface{}{}
}

return []interface{}{
map[string]interface{}{
"certificate_data": (*input.Value)[0],
},
}
}

func flattenUefiKeyList(input *[]galleryimageversions.UefiKey) []interface{} {
if input == nil {
return []interface{}{}
}

result := make([]interface{}, len(*input))
for i, v := range *input {
result[i] = flattenUefiKey(&v)
}
return result
}

func flattenUefiKey(input *galleryimageversions.UefiKey) []interface{} {
if input == nil || input.Value == nil || len(*input.Value) == 0 {
return []interface{}{}
}

return []interface{}{
map[string]interface{}{
"certificate_data": (*input.Value)[0],
"key_type": string(*input.Type),
},
}
}

func flattenStringList(input []galleryimageversions.UefiSignatureTemplateName) []interface{} {
result := make([]interface{}, len(input))
for i, v := range input {
result[i] = string(v)
}
return result
}

func flattenSharedImageVersionTargetRegions(input *[]galleryimageversions.TargetRegion) []interface{} {
results := make([]interface{}, 0)

Expand Down
58 changes: 58 additions & 0 deletions internal/services/compute/shared_image_version_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,28 @@ func TestAccSharedImageVersion_requiresImport(t *testing.T) {
})
}

func TestAccSharedImageVersion_uefiSettings(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_shared_image_version", "test")
r := SharedImageVersionResource{}

keyType := "x509"
certData := "MIIDNzCCAh+gAwIBAgIRANcuAK10JUqNpehWlkldzxEwDQYJKoZIhvcNAQELBQAwFzEVMBMGA1UEAxMMQ3VzdG9tRGJLZXkzMB4XDTIzMDYxOTEwNTI0MloXDTMzMDYxNjEwNTI0MlowFzEVMBMGA1UEAxMMQ3VzdG9tRGJLZXkzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq+QdB6n3TDk12Qa/JcbmdfEpIrx4dKG9d5D/SRHWfJACInxtH64jzvGohVnAqIDqcKK+FvVLDPrqD7hbzV34AOXkyVoRtHEsdDErkG9CVBJlWleuew+if9TkW8wabFT3/sHSzVbG6+6AFOHsnDbO1Rpvh1ZPp2AgqiNg7XUHQM9zH00BYz7xtL9XEr+sRRgp0Bn0PGQGQU1Q302TK6jlHwJGMidke4Le2IIDJTUTGx3yWuX7f/T/u6alZeKjg+hYysJ7dpaaC5DyRTT5pJv62pZBJa3DkwWWSKroJozp9ujf93KYP7NoCLHkyiITAUK04hsHm/UvIt7ZhayTS24MbwIDAQABo34wfDAfBgNVHSMEGDAWgBQBXPUO5tTx8gh9G1iwS1KMwXUi/zAVBglghkgBhvhCAQEBAf8EBQMDAPABMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIEsDAdBgNVHQ4EFgQUAVz1DubU8fIIfRtYsEtSjMF1Iv8wDQYJKoZIhvcNAQELBQADggEBAA4xZmr3HhDOc2xzDMjqiVnCBMPT8nS9P+jCXezTeG1SIWrMmQUSs8rtU0YoNRIq1wbT/rqbYIwwhRfth0nUGf22zp4UdigVcpt+FQj9eGgeF6sJyHVWmMZu8rEi8BhHEsS6jHqExckp0vshhyW5whr86znWFWf/EsVGFkxd7kjv/KB0ff2ide5vLOWxoTfYmSxYyg2K1FQXP7L87Rb7O6PKzo0twVgeZ616e/yFLcmUQgnHBhb2IKtdo+CdTCxcw9/nNqGPwsNLsti2jyr5oNm9mX6wVaAuXCC3maX35DdWFVK0gXcENEw+Q6+JSyPV1ItXc5CD0NU9pd+R85qsFlY="

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.imageVersionWithUefiSettings(data, []string{"MicrosoftUefiCertificateAuthorityTemplate"}, keyType, certData),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("uefi_settings.0.signature_template_names.#").HasValue("1"),
check.That(data.ResourceName).Key("uefi_settings.0.signature_template_names.0").HasValue("MicrosoftUefiCertificateAuthorityTemplate"),
check.That(data.ResourceName).Key("uefi_settings.0.additional_signatures.0.db.0.key_type").HasValue(keyType),
check.That(data.ResourceName).Key("uefi_settings.0.additional_signatures.0.db.0.certificate_data").HasValue(certData),
),
},
data.ImportStep(),
})
}

func (r SharedImageVersionResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := galleryimageversions.ParseImageVersionID(state.ID)
if err != nil {
Expand Down Expand Up @@ -742,3 +764,39 @@ resource "azurerm_shared_image_version" "test" {
}
`, template)
}

func (r SharedImageVersionResource) imageVersionWithUefiSettings(data acceptance.TestData, templates []string, keyType, certData string) string {
template := r.provision(data)
templatesStr := ""
for _, t := range templates {
templatesStr += fmt.Sprintf(`"%s",`, t)
}
return fmt.Sprintf(`
%s
resource "azurerm_shared_image_version" "test" {
name = "0.0.1"
gallery_name = azurerm_shared_image_gallery.test.name
image_name = azurerm_shared_image.test.name
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
managed_image_id = azurerm_image.test.id
uefi_settings {
signature_template_names = [%s]
additional_signatures {
db {
key_type = "%s"
certificate_data = "%s"
}
}
}
target_region {
name = azurerm_resource_group.test.location
regional_replica_count = 1
}
}
`, template, templatesStr, keyType, certData)
}

0 comments on commit 092ccf4

Please sign in to comment.