From e9e5a59251534857f25998acfe6b12632295cef0 Mon Sep 17 00:00:00 2001
From: sternik <147771+sternik@users.noreply.github.com>
Date: Mon, 15 Jul 2024 15:48:29 +0200
Subject: [PATCH] feat: add support for Secure Boot UEFI keys in Azure images
(#70)
---
docs/index.md | 2 +-
docs/resources/template.md | 33 ++++++++++++
examples/provider/provider.tf | 2 +-
.../imagefactory_template/resource.tf | 24 +++++++++
imagefactory/imagetemplate/schema.go | 18 +++++++
imagefactory/imagetemplate/structures.go | 16 ++++++
pkg/graphql/graphql.go | 50 ++++++++++++++-----
pkg/graphql/schema.graphql | 36 ++++++++++++-
8 files changed, 166 insertions(+), 15 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 569aefa..acb858b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -34,7 +34,7 @@ terraform {
required_providers {
imagefactory = {
source = "nordcloud/imagefactory"
- version = "1.9.1"
+ version = "1.10.0"
}
}
}
diff --git a/docs/resources/template.md b/docs/resources/template.md
index ad12247..e715526 100644
--- a/docs/resources/template.md
+++ b/docs/resources/template.md
@@ -144,6 +144,30 @@ resource "imagefactory_template" "azure_template" {
}
}
+# AZURE Template - additional signatures on Gen2 images
+
+resource "imagefactory_variable" "uefi_key" {
+ name = "UEFI_KEY"
+ value = "MIIDQTCCAimgAwIBAgIQDd70KTXzSXuUqRAfm+RzqzANBgkqhkiG9w0BAQsFADAj...."
+}
+
+resource "imagefactory_template" "azure_template" {
+ name = "Ubuntu1804"
+ description = "Ubuntu 18.04 on Azure"
+ cloud_provider = "AZURE"
+ distribution_id = data.imagefactory_distribution.ubuntu18.id
+ config {
+ azure {
+ trusted_launch = true
+ additional_signatures {
+ variable_name = imagefactory_variable.uefi_key.name
+ # If the variable is not defined in the template, the value can be set directly
+ # variable_value = "UEFI_KEY"
+ }
+ }
+ }
+}
+
output "azure_template" {
value = imagefactory_template.azure_template
}
@@ -308,6 +332,7 @@ Required:
Optional:
- `additional_data_disks` (Block List, Max: 10) (see [below for nested schema](#nestedblock--config--azure--additional_data_disks))
+- `additional_signatures` (Block List) Additional UEFI keys that are used to validate the boot loader. This feature allows you to bind UEFI keys for driver/kernel modules that are signed by using a private key that's owned by third-party vendors. (see [below for nested schema](#nestedblock--config--azure--additional_signatures))
- `eol_date_option` (Boolean) Default value is set to true
- `exclude_from_latest` (Boolean)
- `replica_regions` (List of String)
@@ -322,6 +347,14 @@ Required:
- `size` (Number) Data disk size between 1 and 10 GB.
+
+### Nested Schema for `config.azure.additional_signatures`
+
+Required:
+
+- `variable_name` (String) The name of the Customer Variable that is used to store the UEFI key.
+
+
### Nested Schema for `config.azure.vm_image_definition`
diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf
index 417b591..ed04e64 100644
--- a/examples/provider/provider.tf
+++ b/examples/provider/provider.tf
@@ -7,7 +7,7 @@ terraform {
required_providers {
imagefactory = {
source = "nordcloud/imagefactory"
- version = "1.9.1"
+ version = "1.10.0"
}
}
}
diff --git a/examples/resources/imagefactory_template/resource.tf b/examples/resources/imagefactory_template/resource.tf
index 0df6f2a..bed48f5 100644
--- a/examples/resources/imagefactory_template/resource.tf
+++ b/examples/resources/imagefactory_template/resource.tf
@@ -129,6 +129,30 @@ resource "imagefactory_template" "azure_template" {
}
}
+# AZURE Template - additional signatures on Gen2 images
+
+resource "imagefactory_variable" "uefi_key" {
+ name = "UEFI_KEY"
+ value = "MIIDQTCCAimgAwIBAgIQDd70KTXzSXuUqRAfm+RzqzANBgkqhkiG9w0BAQsFADAj...."
+}
+
+resource "imagefactory_template" "azure_template" {
+ name = "Ubuntu1804"
+ description = "Ubuntu 18.04 on Azure"
+ cloud_provider = "AZURE"
+ distribution_id = data.imagefactory_distribution.ubuntu18.id
+ config {
+ azure {
+ trusted_launch = true
+ additional_signatures {
+ variable_name = imagefactory_variable.uefi_key.name
+ # If the variable is not defined in the template, the value can be set directly
+ # variable_value = "UEFI_KEY"
+ }
+ }
+ }
+}
+
output "azure_template" {
value = imagefactory_template.azure_template
}
diff --git a/imagefactory/imagetemplate/schema.go b/imagefactory/imagetemplate/schema.go
index f698e40..210a0bd 100644
--- a/imagefactory/imagetemplate/schema.go
+++ b/imagefactory/imagetemplate/schema.go
@@ -128,6 +128,16 @@ var additionalDataDisksResource = &schema.Resource{
},
}
+var additionalSignaturesResource = &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "variable_name": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The name of the Customer Variable that is used to store the UEFI key.",
+ },
+ },
+}
+
var azureTemplateConfigResource = &schema.Resource{
Schema: map[string]*schema.Schema{
"exclude_from_latest": {
@@ -162,6 +172,14 @@ var azureTemplateConfigResource = &schema.Resource{
Type: schema.TypeBool,
Optional: true,
},
+ "additional_signatures": {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: additionalSignaturesResource,
+ Description: "Additional UEFI keys that are used to validate the boot loader. " +
+ "This feature allows you to bind UEFI keys for driver/kernel modules that " +
+ "are signed by using a private key that's owned by third-party vendors.",
+ },
},
}
diff --git a/imagefactory/imagetemplate/structures.go b/imagefactory/imagetemplate/structures.go
index 8fc3bcc..88e2727 100644
--- a/imagefactory/imagetemplate/structures.go
+++ b/imagefactory/imagetemplate/structures.go
@@ -121,6 +121,18 @@ func expandAdditionalDataDisks(in []interface{}) *[]graphql.NewAdditionalDataDis
return &out
}
+func expandAdditionalSignatures(in []interface{}) *[]graphql.NewUefiKey {
+ out := []graphql.NewUefiKey{}
+ for i := range in {
+ m := in[i].(map[string]interface{})
+ out = append(out, graphql.NewUefiKey{
+ VariableName: graphql.String(m["variable_name"].(string)),
+ })
+ }
+
+ return &out
+}
+
func expandTemplateAzureConfig(in []interface{}) *graphql.NewTemplateAZUREConfig {
if len(in) == 0 {
return nil
@@ -149,6 +161,10 @@ func expandTemplateAzureConfig(in []interface{}) *graphql.NewTemplateAZUREConfig
out.AdditionalDataDisks = expandAdditionalDataDisks(m["additional_data_disks"].([]interface{}))
}
+ if m["additional_signatures"] != nil {
+ out.AdditionalSignatures = expandAdditionalSignatures(m["additional_signatures"].([]interface{}))
+ }
+
return out
}
diff --git a/pkg/graphql/graphql.go b/pkg/graphql/graphql.go
index bbd231e..80f6d6c 100644
--- a/pkg/graphql/graphql.go
+++ b/pkg/graphql/graphql.go
@@ -3083,6 +3083,13 @@ const (
DistributionAttributePROVIDER DistributionAttribute = "PROVIDER"
)
+type HyperVGeneration string
+
+const (
+ HyperVGenerationHYPERVGENERATIONV1 HyperVGeneration = "HYPERV_GENERATION_V1"
+ HyperVGenerationHYPERVGENERATIONV2 HyperVGeneration = "HYPERV_GENERATION_V2"
+)
+
type ImageAttribute string
const (
@@ -3676,12 +3683,13 @@ type NewTemplateAWSConfig struct {
}
type NewTemplateAZUREConfig struct {
- AdditionalDataDisks *[]NewAdditionalDataDisks `json:"additionalDataDisks,omitempty"`
- EolDateOption *Boolean `json:"eolDateOption,omitempty"`
- ExcludeFromLatest *Boolean `json:"excludeFromLatest,omitempty"`
- ReplicaRegions *[]String `json:"replicaRegions,omitempty"`
- TrustedLaunch *Boolean `json:"trustedLaunch,omitempty"`
- VmImageDefinition *NewVMImageDefinition `json:"vmImageDefinition,omitempty"`
+ AdditionalDataDisks *[]NewAdditionalDataDisks `json:"additionalDataDisks,omitempty"`
+ AdditionalSignatures *[]NewUefiKey `json:"additionalSignatures,omitempty"`
+ EolDateOption *Boolean `json:"eolDateOption,omitempty"`
+ ExcludeFromLatest *Boolean `json:"excludeFromLatest,omitempty"`
+ ReplicaRegions *[]String `json:"replicaRegions,omitempty"`
+ TrustedLaunch *Boolean `json:"trustedLaunch,omitempty"`
+ VmImageDefinition *NewVMImageDefinition `json:"vmImageDefinition,omitempty"`
}
type NewTemplateComponent struct {
@@ -3713,6 +3721,10 @@ type NewTemplateExoscaleConfig struct {
Zone *String `json:"zone,omitempty"`
}
+type NewUefiKey struct {
+ VariableName String `json:"variableName"`
+}
+
type NewVMImageDefinition struct {
Name String `json:"name"`
Offer String `json:"offer"`
@@ -3800,6 +3812,10 @@ type TemplatesSort struct {
// Objects
//
+type AZUREConfig struct {
+ HypervGeneration *HyperVGeneration `json:"hypervGeneration,omitempty"`
+}
+
type Account struct {
Alias *String `json:"alias,omitempty"`
ChangeDetails ChangeDetails `json:"changeDetails"`
@@ -3969,6 +3985,10 @@ type ComponentResults struct {
Results *[]Component `json:"results,omitempty"`
}
+type Config struct {
+ Azure *AZUREConfig `json:"azure,omitempty"`
+}
+
type Contact struct {
Email String `json:"email"`
Name String `json:"name"`
@@ -4012,6 +4032,7 @@ type CustomerStats struct {
type Distribution struct {
ComplianceScore *ComplianceScore `json:"complianceScore,omitempty"`
+ Config *Config `json:"config,omitempty"`
CreatedAt String `json:"createdAt"`
Deprecated *Boolean `json:"deprecated,omitempty"`
Description *String `json:"description,omitempty"`
@@ -4262,12 +4283,13 @@ type TemplateAWSConfig struct {
}
type TemplateAZUREConfig struct {
- AdditionalDataDisks *[]AdditionalDataDisks `json:"additionalDataDisks,omitempty"`
- EolDateOption *Boolean `json:"eolDateOption,omitempty"`
- ExcludeFromLatest *Boolean `json:"excludeFromLatest,omitempty"`
- ReplicaRegions *[]String `json:"replicaRegions,omitempty"`
- TrustedLaunch *Boolean `json:"trustedLaunch,omitempty"`
- VmImageDefinition *VMImageDefinition `json:"vmImageDefinition,omitempty"`
+ AdditionalDataDisks *[]AdditionalDataDisks `json:"additionalDataDisks,omitempty"`
+ AdditionalSignatures *[]UefiKey `json:"additionalSignatures,omitempty"`
+ EolDateOption *Boolean `json:"eolDateOption,omitempty"`
+ ExcludeFromLatest *Boolean `json:"excludeFromLatest,omitempty"`
+ ReplicaRegions *[]String `json:"replicaRegions,omitempty"`
+ TrustedLaunch *Boolean `json:"trustedLaunch,omitempty"`
+ VmImageDefinition *VMImageDefinition `json:"vmImageDefinition,omitempty"`
}
type TemplateComponent struct {
@@ -4313,6 +4335,10 @@ type TemplateState struct {
Status BuildStatus `json:"status"`
}
+type UefiKey struct {
+ VariableName String `json:"variableName"`
+}
+
type VMImageDefinition struct {
Name String `json:"name"`
Offer String `json:"offer"`
diff --git a/pkg/graphql/schema.graphql b/pkg/graphql/schema.graphql
index c07776b..d309959 100644
--- a/pkg/graphql/schema.graphql
+++ b/pkg/graphql/schema.graphql
@@ -606,7 +606,7 @@ type CustomerStats {
}
-# Copyright 2021-2023 Nordcloud Oy or its affiliates. All Rights Reserved.
+# Copyright 2021-2024 Nordcloud Oy or its affiliates. All Rights Reserved.
"""
Distribution defines the cloud image that can be created by the ImageFactory.
@@ -631,6 +631,7 @@ type Distribution {
osEolDate: String
complianceScore: ComplianceScore
deprecated: Boolean
+ config: Config
}
type ComplianceScore {
@@ -644,6 +645,19 @@ type DistributionResults {
count: Int!
}
+type Config {
+ azure: AZUREConfig
+}
+
+enum HyperVGeneration {
+ HYPERV_GENERATION_V1
+ HYPERV_GENERATION_V2
+}
+
+type AZUREConfig {
+ hypervGeneration: HyperVGeneration
+}
+
# Copyright 2022-2024 Nordcloud Oy or its affiliates. All Rights Reserved.
@@ -1010,6 +1024,10 @@ type AdditionalDataDisks {
size: Int!
}
+type UefiKey {
+ variableName: String!
+}
+
type TemplateAZUREConfig {
replicaRegions: [String]
excludeFromLatest: Boolean
@@ -1017,6 +1035,7 @@ type TemplateAZUREConfig {
eolDateOption: Boolean
additionalDataDisks: [AdditionalDataDisks!]
trustedLaunch: Boolean
+ additionalSignatures: [UefiKey!]
}
type TemplateExoscaleConfig {
@@ -1150,6 +1169,13 @@ input NewVMImageDefinition {
sku: String!
}
+input NewUefiKey {
+ """
+ variableName is the name of the Customer Variable that is used to store the UEFI key.
+ """
+ variableName: String!
+}
+
input NewAdditionalDataDisks {
"""
size is in GB, from 1G to 10G.
@@ -1172,6 +1198,14 @@ input NewTemplateAZUREConfig {
"""
trustedLaunch: Boolean
+ """
+ `additionalSignatures` defines additional UEFI keys that are used to validate the boot loader.
+
+ This feature allows you to bind unified extensible firmware interface (UEFI) keys for driver/kernel modules
+ that are signed by using a private key that's owned by third-party vendors.
+ """
+ additionalSignatures: [NewUefiKey!]
+
"""
`additionalDataDisks` defines extra data disks attached to the image with a limit of 10.