From f9cccc59cea5ee02650a84941f007b09f9424ff8 Mon Sep 17 00:00:00 2001
From: Bryan Cox
Date: Mon, 4 Dec 2023 13:20:46 -0500
Subject: [PATCH 1/2] Add ability to encrypt OS disks in Azure VMs
Adds the ability to encrypt the OS disks in the Azure VMs, using a
DiskEncryptionSet resource. The DiskEncryptionSet ID can be passed in
when creating a new Hosted Cluster or creating a new NodePool.
Signed-off-by: Bryan Cox
---
api/hypershift/v1alpha1/nodepool_types.go | 3 +
api/hypershift/v1beta1/nodepool_types.go | 3 +
.../v1alpha1/azurenodepoolplatform.go | 9 +++
.../v1beta1/azurenodepoolplatform.go | 9 +++
cmd/cluster/azure/create.go | 62 ++++++++++-------
cmd/cluster/core/create.go | 16 ++---
.../hypershift.openshift.io_nodepools.yaml | 8 +++
cmd/nodepool/azure/create.go | 67 +++++++++----------
docs/content/reference/api.md | 12 ++++
examples/fixtures/example.go | 22 +++---
examples/fixtures/example_azure.go | 28 ++++----
hack/app-sre/saas_template.yaml | 8 +++
.../controllers/nodepool/azure.go | 20 ++++--
13 files changed, 170 insertions(+), 97 deletions(-)
diff --git a/api/hypershift/v1alpha1/nodepool_types.go b/api/hypershift/v1alpha1/nodepool_types.go
index dae7f03190..6f0afecbbf 100644
--- a/api/hypershift/v1alpha1/nodepool_types.go
+++ b/api/hypershift/v1alpha1/nodepool_types.go
@@ -883,6 +883,9 @@ type AzureNodePoolPlatform struct {
// in a location that does not support AvailabilityZone.
// +optional
AvailabilityZone string `json:"availabilityZone,omitempty"`
+ // DiskEncryptionSetID is the ID of the DiskEncryptionSet resource to use to encrypt the OS disks for the VMs.
+ // +optional
+ DiskEncryptionSetID string `json:"diskEncryptionSetID,omitempty"`
}
// We define our own condition type since metav1.Condition has validation
diff --git a/api/hypershift/v1beta1/nodepool_types.go b/api/hypershift/v1beta1/nodepool_types.go
index 1ab9581869..42921cea6f 100644
--- a/api/hypershift/v1beta1/nodepool_types.go
+++ b/api/hypershift/v1beta1/nodepool_types.go
@@ -876,6 +876,9 @@ type AzureNodePoolPlatform struct {
// in a location that does not support AvailabilityZone.
// +optional
AvailabilityZone string `json:"availabilityZone,omitempty"`
+ // DiskEncryptionSetID is the ID of the DiskEncryptionSet resource to use to encrypt the OS disks for the VMs.
+ // +optional
+ DiskEncryptionSetID string `json:"diskEncryptionSetID,omitempty"`
}
// We define our own condition type since metav1.Condition has validation
diff --git a/client/applyconfiguration/hypershift/v1alpha1/azurenodepoolplatform.go b/client/applyconfiguration/hypershift/v1alpha1/azurenodepoolplatform.go
index 536ec42227..9adb49c3c8 100644
--- a/client/applyconfiguration/hypershift/v1alpha1/azurenodepoolplatform.go
+++ b/client/applyconfiguration/hypershift/v1alpha1/azurenodepoolplatform.go
@@ -25,6 +25,7 @@ type AzureNodePoolPlatformApplyConfiguration struct {
DiskSizeGB *int32 `json:"diskSizeGB,omitempty"`
DiskStorageAccountType *string `json:"diskStorageAccountType,omitempty"`
AvailabilityZone *string `json:"availabilityZone,omitempty"`
+ DiskEncryptionSetID *string `json:"diskEncryptionSetID,omitempty"`
}
// AzureNodePoolPlatformApplyConfiguration constructs an declarative configuration of the AzureNodePoolPlatform type for use with
@@ -72,3 +73,11 @@ func (b *AzureNodePoolPlatformApplyConfiguration) WithAvailabilityZone(value str
b.AvailabilityZone = &value
return b
}
+
+// WithDiskEncryptionSetID sets the DiskEncryptionSetID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DiskEncryptionSetID field is set to the value of the last call.
+func (b *AzureNodePoolPlatformApplyConfiguration) WithDiskEncryptionSetID(value string) *AzureNodePoolPlatformApplyConfiguration {
+ b.DiskEncryptionSetID = &value
+ return b
+}
diff --git a/client/applyconfiguration/hypershift/v1beta1/azurenodepoolplatform.go b/client/applyconfiguration/hypershift/v1beta1/azurenodepoolplatform.go
index e5f01dd428..e0e1bef744 100644
--- a/client/applyconfiguration/hypershift/v1beta1/azurenodepoolplatform.go
+++ b/client/applyconfiguration/hypershift/v1beta1/azurenodepoolplatform.go
@@ -25,6 +25,7 @@ type AzureNodePoolPlatformApplyConfiguration struct {
DiskSizeGB *int32 `json:"diskSizeGB,omitempty"`
DiskStorageAccountType *string `json:"diskStorageAccountType,omitempty"`
AvailabilityZone *string `json:"availabilityZone,omitempty"`
+ DiskEncryptionSetID *string `json:"diskEncryptionSetID,omitempty"`
}
// AzureNodePoolPlatformApplyConfiguration constructs an declarative configuration of the AzureNodePoolPlatform type for use with
@@ -72,3 +73,11 @@ func (b *AzureNodePoolPlatformApplyConfiguration) WithAvailabilityZone(value str
b.AvailabilityZone = &value
return b
}
+
+// WithDiskEncryptionSetID sets the DiskEncryptionSetID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DiskEncryptionSetID field is set to the value of the last call.
+func (b *AzureNodePoolPlatformApplyConfiguration) WithDiskEncryptionSetID(value string) *AzureNodePoolPlatformApplyConfiguration {
+ b.DiskEncryptionSetID = &value
+ return b
+}
diff --git a/cmd/cluster/azure/create.go b/cmd/cluster/azure/create.go
index c9165342e6..c84da4a515 100644
--- a/cmd/cluster/azure/create.go
+++ b/cmd/cluster/azure/create.go
@@ -5,9 +5,7 @@ import (
"fmt"
"net/url"
"os"
- "os/signal"
"strings"
- "syscall"
hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
"github.com/openshift/hypershift/cmd/cluster/core"
@@ -30,35 +28,37 @@ func NewCreateCommand(opts *core.CreateOptions) *cobra.Command {
opts.AzurePlatform.Location = "eastus"
opts.AzurePlatform.InstanceType = "Standard_D4s_v4"
opts.AzurePlatform.DiskSizeGB = 120
+
cmd.Flags().StringVar(&opts.AzurePlatform.CredentialsFile, "azure-creds", opts.AzurePlatform.CredentialsFile, "Path to an Azure credentials file (required)")
cmd.Flags().StringVar(&opts.AzurePlatform.Location, "location", opts.AzurePlatform.Location, "Location for the cluster")
cmd.Flags().StringVar(&opts.AzurePlatform.EncryptionKeyID, "encryption-key-id", opts.AzurePlatform.EncryptionKeyID, "etcd encryption key identifier in the form of https://.vault.azure.net/keys//")
cmd.Flags().StringVar(&opts.AzurePlatform.InstanceType, "instance-type", opts.AzurePlatform.InstanceType, "The instance type to use for nodes")
cmd.Flags().Int32Var(&opts.AzurePlatform.DiskSizeGB, "root-disk-size", opts.AzurePlatform.DiskSizeGB, "The size of the root disk for machines in the NodePool (minimum 16)")
- cmd.Flags().StringSliceVar(&opts.AzurePlatform.AvailabilityZones, "availablity-zones", opts.AzurePlatform.AvailabilityZones, "The availablity zones in which NodePools will be created. Must be left unspecified if the region does not support AZs. If set, one nodepool per zone will be created.")
+ cmd.Flags().StringSliceVar(&opts.AzurePlatform.AvailabilityZones, "availability-zones", opts.AzurePlatform.AvailabilityZones, "The availability zones in which NodePools will be created. Must be left unspecified if the region does not support AZs. If set, one nodepool per zone will be created.")
cmd.Flags().StringVar(&opts.AzurePlatform.ResourceGroupName, "resource-group-name", opts.AzurePlatform.ResourceGroupName, "A resource group name to create the HostedCluster infrastructure resources under.")
+ cmd.Flags().StringVar(&opts.AzurePlatform.DiskEncryptionSetID, "disk-encryption-set-id", opts.AzurePlatform.DiskEncryptionSetID, "The Disk Encryption Set ID to use to encrypt the OS disks for the VMs.")
_ = cmd.MarkFlagRequired("azure-creds")
_ = cmd.MarkPersistentFlagRequired("pull-secret")
- cmd.Run = func(cmd *cobra.Command, args []string) {
- ctx, cancel := context.WithCancel(context.Background())
+ cmd.RunE = func(cmd *cobra.Command, args []string) error {
+ ctx := cmd.Context()
if opts.Timeout > 0 {
- ctx, cancel = context.WithTimeout(context.Background(), opts.Timeout)
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, opts.Timeout)
+ defer cancel()
}
- defer cancel()
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT)
- go func() {
- <-sigs
- cancel()
- }()
+ err := validate(opts)
+ if err != nil {
+ return err
+ }
- if err := CreateCluster(ctx, opts); err != nil {
+ if err = CreateCluster(ctx, opts); err != nil {
opts.Log.Error(err, "Failed to create cluster")
- os.Exit(1)
+ return err
}
+ return nil
}
return cmd
@@ -109,17 +109,18 @@ func applyPlatformSpecificsValues(ctx context.Context, exampleOptions *apifixtur
exampleOptions.InfraID = infra.InfraID
exampleOptions.ExternalDNSDomain = opts.ExternalDNSDomain
exampleOptions.Azure = &apifixtures.ExampleAzureOptions{
- Location: infra.Location,
- ResourceGroupName: infra.ResourceGroupName,
- VnetName: infra.VnetName,
- VnetID: infra.VNetID,
- SubnetName: infra.SubnetName,
- BootImageID: infra.BootImageID,
- MachineIdentityID: infra.MachineIdentityID,
- InstanceType: opts.AzurePlatform.InstanceType,
- SecurityGroupName: infra.SecurityGroupName,
- DiskSizeGB: opts.AzurePlatform.DiskSizeGB,
- AvailabilityZones: opts.AzurePlatform.AvailabilityZones,
+ Location: infra.Location,
+ ResourceGroupName: infra.ResourceGroupName,
+ VnetName: infra.VnetName,
+ VnetID: infra.VNetID,
+ SubnetName: infra.SubnetName,
+ BootImageID: infra.BootImageID,
+ MachineIdentityID: infra.MachineIdentityID,
+ InstanceType: opts.AzurePlatform.InstanceType,
+ SecurityGroupName: infra.SecurityGroupName,
+ DiskSizeGB: opts.AzurePlatform.DiskSizeGB,
+ AvailabilityZones: opts.AzurePlatform.AvailabilityZones,
+ DiskEncryptionSetID: opts.AzurePlatform.DiskEncryptionSetID,
}
if opts.AzurePlatform.EncryptionKeyID != "" {
@@ -178,3 +179,12 @@ func lookupRHCOSImage(ctx context.Context, arch string, image string, pullSecret
return rhcosImage, nil
}
+
+// validate validates the core create options passed in by the user
+func validate(opts *core.CreateOptions) error {
+ // Resource group name is required when using DiskEncryptionSetID
+ if opts.AzurePlatform.DiskEncryptionSetID != "" && opts.AzurePlatform.ResourceGroupName == "" {
+ return fmt.Errorf("validate: resource-group-name is required when using disk-encryption-set-id")
+ }
+ return nil
+}
diff --git a/cmd/cluster/core/create.go b/cmd/cluster/core/create.go
index fa014f4b40..8219466bc6 100644
--- a/cmd/cluster/core/create.go
+++ b/cmd/cluster/core/create.go
@@ -162,17 +162,17 @@ type AWSPlatformOptions struct {
}
type AzurePlatformOptions struct {
- CredentialsFile string
- Location string
- EncryptionKeyID string
- InstanceType string
- DiskSizeGB int32
- AvailabilityZones []string
- ResourceGroupName string
+ CredentialsFile string
+ Location string
+ EncryptionKeyID string
+ InstanceType string
+ DiskSizeGB int32
+ AvailabilityZones []string
+ ResourceGroupName string
+ DiskEncryptionSetID string
}
func createCommonFixture(ctx context.Context, opts *CreateOptions) (*apifixtures.ExampleOptions, error) {
-
// allow client side defaulting when release image is empty but release stream is set.
if len(opts.ReleaseImage) == 0 && len(opts.ReleaseStream) != 0 {
defaultVersion, err := version.LookupDefaultOCPVersion(opts.ReleaseStream)
diff --git a/cmd/install/assets/hypershift-operator/hypershift.openshift.io_nodepools.yaml b/cmd/install/assets/hypershift-operator/hypershift.openshift.io_nodepools.yaml
index 4dc82f394c..1c071e21bb 100644
--- a/cmd/install/assets/hypershift-operator/hypershift.openshift.io_nodepools.yaml
+++ b/cmd/install/assets/hypershift-operator/hypershift.openshift.io_nodepools.yaml
@@ -484,6 +484,10 @@ spec:
specified for clusters in a location that does not support
AvailabilityZone.
type: string
+ diskEncryptionSetID:
+ description: DiskEncryptionSetID is the ID of the DiskEncryptionSet
+ resource to use to encrypt the OS disks for the VMs.
+ type: string
diskSizeGB:
default: 120
format: int32
@@ -1463,6 +1467,10 @@ spec:
specified for clusters in a location that does not support
AvailabilityZone.
type: string
+ diskEncryptionSetID:
+ description: DiskEncryptionSetID is the ID of the DiskEncryptionSet
+ resource to use to encrypt the OS disks for the VMs.
+ type: string
diskSizeGB:
default: 120
format: int32
diff --git a/cmd/nodepool/azure/create.go b/cmd/nodepool/azure/create.go
index c9340d5b85..5f96efba95 100644
--- a/cmd/nodepool/azure/create.go
+++ b/cmd/nodepool/azure/create.go
@@ -2,65 +2,62 @@ package azure
import (
"context"
- "os"
- "os/signal"
- "syscall"
+ "fmt"
hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
- "github.com/openshift/hypershift/cmd/log"
"github.com/openshift/hypershift/cmd/nodepool/core"
+
"github.com/spf13/cobra"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
)
+type AzurePlatformCreateOptions struct {
+ InstanceType string
+ DiskSize int32
+ AvailabilityZone string
+ ResourceGroupName string
+ DiskEncryptionSetID string
+}
+
func NewCreateCommand(coreOpts *core.CreateNodePoolOptions) *cobra.Command {
+ platformOpts := &AzurePlatformCreateOptions{
+ InstanceType: "Standard_D4s_v4",
+ DiskSize: 120,
+ }
+
cmd := &cobra.Command{
Use: "azure",
- Short: "Creates an Azure nodepool",
+ Short: "Creates basic functional NodePool resources for Azure platform",
SilenceUsage: true,
}
- o := &opts{
- instanceType: "Standard_D4s_v4",
- diskSize: 120,
- }
- cmd.Flags().StringVar(&o.instanceType, "instance-type", o.instanceType, "The instance type to use for the nodepool")
- cmd.Flags().Int32Var(&o.diskSize, "root-disk-size", o.diskSize, "The size of the root disk for machines in the NodePool (minimum 16)")
- cmd.Flags().StringVar(&o.availabilityZone, "availability-zone", o.availabilityZone, "The availabilityZone for the nodepool. Must be left unspecified if in a region that doesn't support AZs")
- cmd.Run = func(cmd *cobra.Command, args []string) {
- ctx, cancel := context.WithCancel(context.Background())
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT)
- go func() {
- <-sigs
- cancel()
- }()
+ cmd.Flags().StringVar(&platformOpts.InstanceType, "instance-type", platformOpts.InstanceType, "The instance type to use for the nodepool")
+ cmd.Flags().Int32Var(&platformOpts.DiskSize, "root-disk-size", platformOpts.DiskSize, "The size of the root disk for machines in the NodePool (minimum 16)")
+ cmd.Flags().StringVar(&platformOpts.AvailabilityZone, "availability-zone", platformOpts.AvailabilityZone, "The availabilityZone for the nodepool. Must be left unspecified if in a region that doesn't support AZs")
+ cmd.Flags().StringVar(&platformOpts.ResourceGroupName, "resource-group-name", platformOpts.ResourceGroupName, "A resource group name to create the HostedCluster infrastructure resources under.")
+ cmd.Flags().StringVar(&platformOpts.DiskEncryptionSetID, "disk-encryption-set-id", platformOpts.DiskEncryptionSetID, "The Disk Encryption Set ID to use to encrypt the OS disks for the VMs.")
- if err := coreOpts.CreateNodePool(ctx, o); err != nil {
- log.Log.Error(err, "Failed to create nodepool")
- os.Exit(1)
- }
- }
+ cmd.RunE = coreOpts.CreateRunFunc(platformOpts)
return cmd
}
-type opts struct {
- instanceType string
- diskSize int32
- availabilityZone string
-}
+func (o *AzurePlatformCreateOptions) UpdateNodePool(_ context.Context, nodePool *hyperv1.NodePool, _ *hyperv1.HostedCluster, _ crclient.Client) error {
+ // Resource group name is required when using DiskEncryptionSetID
+ if o.DiskEncryptionSetID != "" && o.ResourceGroupName == "" {
+ return fmt.Errorf("UpdateNodePool: resource-group-name is required when using disk-encryption-set-id")
+ }
-func (o *opts) UpdateNodePool(ctx context.Context, nodePool *hyperv1.NodePool, hcluster *hyperv1.HostedCluster, client crclient.Client) error {
nodePool.Spec.Platform.Type = hyperv1.AzurePlatform
nodePool.Spec.Platform.Azure = &hyperv1.AzureNodePoolPlatform{
- VMSize: o.instanceType,
- DiskSizeGB: o.diskSize,
- AvailabilityZone: o.availabilityZone,
+ VMSize: o.InstanceType,
+ DiskSizeGB: o.DiskSize,
+ AvailabilityZone: o.AvailabilityZone,
+ DiskEncryptionSetID: o.DiskEncryptionSetID,
}
return nil
}
-func (o opts) Type() hyperv1.PlatformType {
+func (o *AzurePlatformCreateOptions) Type() hyperv1.PlatformType {
return hyperv1.AzurePlatform
}
diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md
index 7fa422bca6..80459e2a63 100644
--- a/docs/content/reference/api.md
+++ b/docs/content/reference/api.md
@@ -2337,6 +2337,18 @@ string
in a location that does not support AvailabilityZone.
+
+
+diskEncryptionSetID
+
+string
+
+ |
+
+(Optional)
+ DiskEncryptionSetID is the ID of the DiskEncryptionSet resource to use to encrypt the OS disks for the VMs.
+ |
+
###AzurePlatformSpec { #hypershift.openshift.io/v1beta1.AzurePlatformSpec }
diff --git a/examples/fixtures/example.go b/examples/fixtures/example.go
index 57ee0eb7fc..2c88841025 100644
--- a/examples/fixtures/example.go
+++ b/examples/fixtures/example.go
@@ -461,9 +461,9 @@ func (o ExampleOptions) Resources() *ExampleResources {
}
}
- var etcdStorgageClass *string = nil
+ var etcdStorageClass *string = nil
if len(o.EtcdStorageClass) > 0 {
- etcdStorgageClass = pointer.String(o.EtcdStorageClass)
+ etcdStorageClass = pointer.String(o.EtcdStorageClass)
}
cluster := &hyperv1.HostedCluster{
TypeMeta: metav1.TypeMeta{
@@ -485,7 +485,7 @@ func (o ExampleOptions) Resources() *ExampleResources {
Storage: hyperv1.ManagedEtcdStorageSpec{
Type: hyperv1.PersistentVolumeEtcdStorage,
PersistentVolume: &hyperv1.PersistentVolumeEtcdStorageSpec{
- StorageClassName: etcdStorgageClass,
+ StorageClassName: etcdStorageClass,
Size: &hyperv1.DefaultPersistentVolumeEtcdStorageSize,
},
},
@@ -692,10 +692,11 @@ func (o ExampleOptions) Resources() *ExampleResources {
nodePool.Spec.Management.UpgradeType = hyperv1.UpgradeTypeReplace
}
nodePool.Spec.Platform.Azure = &hyperv1.AzureNodePoolPlatform{
- VMSize: o.Azure.InstanceType,
- ImageID: o.Azure.BootImageID,
- DiskSizeGB: o.Azure.DiskSizeGB,
- AvailabilityZone: availabilityZone,
+ VMSize: o.Azure.InstanceType,
+ ImageID: o.Azure.BootImageID,
+ DiskSizeGB: o.Azure.DiskSizeGB,
+ AvailabilityZone: availabilityZone,
+ DiskEncryptionSetID: o.Azure.DiskEncryptionSetID,
}
nodePools = append(nodePools, nodePool)
}
@@ -706,9 +707,10 @@ func (o ExampleOptions) Resources() *ExampleResources {
nodePool.Spec.Management.UpgradeType = hyperv1.UpgradeTypeReplace
}
nodePool.Spec.Platform.Azure = &hyperv1.AzureNodePoolPlatform{
- VMSize: o.Azure.InstanceType,
- ImageID: o.Azure.BootImageID,
- DiskSizeGB: o.Azure.DiskSizeGB,
+ VMSize: o.Azure.InstanceType,
+ ImageID: o.Azure.BootImageID,
+ DiskSizeGB: o.Azure.DiskSizeGB,
+ DiskEncryptionSetID: o.Azure.DiskEncryptionSetID,
}
nodePools = append(nodePools, nodePool)
}
diff --git a/examples/fixtures/example_azure.go b/examples/fixtures/example_azure.go
index 8699c1157c..9fd63f23c8 100644
--- a/examples/fixtures/example_azure.go
+++ b/examples/fixtures/example_azure.go
@@ -3,20 +3,20 @@ package fixtures
import "github.com/openshift/hypershift/cmd/util"
type ExampleAzureOptions struct {
- Creds util.AzureCreds
- Location string
- ResourceGroupName string
- VnetName string
- VnetID string
- SubnetName string
- BootImageID string
- MachineIdentityID string
- InstanceType string
- SecurityGroupName string
- DiskSizeGB int32
- AvailabilityZones []string
-
- EncryptionKey *AzureEncryptionKey
+ Creds util.AzureCreds
+ Location string
+ ResourceGroupName string
+ VnetName string
+ VnetID string
+ SubnetName string
+ BootImageID string
+ MachineIdentityID string
+ InstanceType string
+ SecurityGroupName string
+ DiskSizeGB int32
+ AvailabilityZones []string
+ DiskEncryptionSetID string
+ EncryptionKey *AzureEncryptionKey
}
type AzureEncryptionKey struct {
diff --git a/hack/app-sre/saas_template.yaml b/hack/app-sre/saas_template.yaml
index e1748b95e2..7ab17aee30 100644
--- a/hack/app-sre/saas_template.yaml
+++ b/hack/app-sre/saas_template.yaml
@@ -51609,6 +51609,10 @@ objects:
be specified for clusters in a location that does not
support AvailabilityZone.
type: string
+ diskEncryptionSetID:
+ description: DiskEncryptionSetID is the ID of the DiskEncryptionSet
+ resource to use to encrypt the OS disks for the VMs.
+ type: string
diskSizeGB:
default: 120
format: int32
@@ -52599,6 +52603,10 @@ objects:
be specified for clusters in a location that does not
support AvailabilityZone.
type: string
+ diskEncryptionSetID:
+ description: DiskEncryptionSetID is the ID of the DiskEncryptionSet
+ resource to use to encrypt the OS disks for the VMs.
+ type: string
diskSizeGB:
default: 120
format: int32
diff --git a/hypershift-operator/controllers/nodepool/azure.go b/hypershift-operator/controllers/nodepool/azure.go
index 84538cee2e..83bd9ac94a 100644
--- a/hypershift-operator/controllers/nodepool/azure.go
+++ b/hypershift-operator/controllers/nodepool/azure.go
@@ -5,12 +5,13 @@ import (
"crypto/rsa"
"encoding/base64"
"fmt"
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
+
+ hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
"golang.org/x/crypto/ssh"
utilpointer "k8s.io/utils/pointer"
capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
-
- hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
)
func azureMachineTemplateSpec(hcluster *hyperv1.HostedCluster, nodePool *hyperv1.NodePool, existing capiazure.AzureMachineTemplateSpec) (*capiazure.AzureMachineTemplateSpec, error) {
@@ -24,7 +25,7 @@ func azureMachineTemplateSpec(hcluster *hyperv1.HostedCluster, nodePool *hyperv1
return nil, fmt.Errorf("failed to generate a SSH key: %w", err)
}
}
- return &capiazure.AzureMachineTemplateSpec{Template: capiazure.AzureMachineTemplateResource{Spec: capiazure.AzureMachineSpec{
+ azureMachineTemplate := &capiazure.AzureMachineTemplateSpec{Template: capiazure.AzureMachineTemplateResource{Spec: capiazure.AzureMachineSpec{
VMSize: nodePool.Spec.Platform.Azure.VMSize,
Image: &capiazure.Image{ID: utilpointer.String(bootImage(hcluster, nodePool))},
OSDisk: capiazure.OSDisk{
@@ -40,7 +41,18 @@ func azureMachineTemplateSpec(hcluster *hyperv1.HostedCluster, nodePool *hyperv1
UserAssignedIdentities: []capiazure.UserAssignedIdentity{{ProviderID: hcluster.Spec.Platform.Azure.MachineIdentityID}},
SSHPublicKey: sshKey,
FailureDomain: failureDomain(nodePool),
- }}}, nil
+ }}}
+
+ if nodePool.Spec.Platform.Azure.DiskEncryptionSetID != "" {
+ azureMachineTemplate.Template.Spec.OSDisk.ManagedDisk.DiskEncryptionSet = &capiazure.DiskEncryptionSetParameters{
+ ID: nodePool.Spec.Platform.Azure.DiskEncryptionSetID,
+ }
+ azureMachineTemplate.Template.Spec.SecurityProfile = &capiazure.SecurityProfile{
+ EncryptionAtHost: to.Ptr(true),
+ }
+ }
+
+ return azureMachineTemplate, nil
}
func generateSSHPubkey() (string, error) {
From 2acb5ff6b757e17569630f74b9aa1a5a402ffe60 Mon Sep 17 00:00:00 2001
From: Bryan Cox
Date: Tue, 5 Dec 2023 08:43:35 -0500
Subject: [PATCH 2/2] Add doc on encrypting OS disks on Azure VMs
Signed-off-by: Bryan Cox
---
.../create-azure-cluster-with-options.md | 102 ++++++++++++++++++
.../how-to/azure/create-azure-cluster.md | 26 -----
docs/mkdocs.yml | 1 +
3 files changed, 103 insertions(+), 26 deletions(-)
create mode 100644 docs/content/how-to/azure/create-azure-cluster-with-options.md
diff --git a/docs/content/how-to/azure/create-azure-cluster-with-options.md b/docs/content/how-to/azure/create-azure-cluster-with-options.md
new file mode 100644
index 0000000000..7ead4c9bbf
--- /dev/null
+++ b/docs/content/how-to/azure/create-azure-cluster-with-options.md
@@ -0,0 +1,102 @@
+# Create an Azure cluster with Additional Options
+This document describes how to set up an Azure cluster with Hypershift with additional flag options.
+
+Creating an Azure cluster with Hypershift without any additional flag options can be found [here](create-azure-cluster.md).
+
+## Prerequisites
+See the Prerequisites section in [Create an Azure Cluster](./create-azure-cluster.md#prerequisites)
+
+## Creating the Cluster in an Existing Resource Group
+If you want to use an existing resource group you've created in Azure, you can pass the name into the `--resource-group-name` flag. This will create all needed Azure infrastructure in specified resource group.
+
+```
+hypershift create cluster azure \
+--name \
+--pull-secret \
+--azure-creds \
+--location \
+--base-domain \
+--release-image \
+--node-pool-replicas \
+--resource-group-name
+```
+
+If you need to delete your hosted cluster, you will need to also use the `--resource-group-name` flag on the delete command.
+
+```
+hypershift destroy cluster azure \
+--name \
+--azure-creds \
+--resource-group-name
+```
+
+!!! note
+
+ If you delete your hosted cluster, it will end up deleting any existing resources prior to when the hosted cluster was created as well as the resource group itself.
+
+## Encrypting the OS Disks on Azure VMs
+There are a few prerequisites for encrypting the OS disks on the Azure VMs:
+
+1. Create your own resource group
+2. Create an Azure Key Vault, with purge protection required, within the resource group
+3. Create a key in the vault to use to create a DiskEncryptionSet
+4. Create a DiskEncryptionSet with key in the vault and grant it permissions to assess the key vault
+
+!!! note
+
+ You will need to use the `resource-group-name` flag when using the `DiskEncryptionSetID` flag.
+
+After performing these steps, you just need to provide the DiskEncryptionSet ID when creating a hosted cluster.
+
+### CLI Example
+```
+hypershift create cluster azure \
+--name \
+--pull-secret \
+--azure-creds \
+--location \
+--base-domain \
+--release-image \
+--node-pool-replicas \
+--resource-group-name \
+--disk-encryption-set-id
+```
+
+You can also pass in the DiskEncryptionSet ID when creating a NodePool.
+
+```
+hypershift create nodepool azure \
+--name \
+--cluster-name \
+--resource-group-name \
+--disk-encryption-set-id
+```
+
+### NodePool CR Example
+The DiskEncryptionSet ID can also be set directly through the NodePool CR.
+
+```
+apiVersion: hypershift.openshift.io/v1beta1
+kind: NodePool
+metadata:
+ creationTimestamp: null
+ name:
+ namespace: clusters
+spec:
+ arch: amd64
+ clusterName:
+ management:
+ autoRepair: false
+ upgradeType: Replace
+ platform:
+ azure:
+ diskEncryptionSetID:
+ diskSizeGB: 120
+ vmsize: Standard_D4s_v4
+ type: Azure
+ release:
+ image:
+ replicas:
+status:
+ replicas: 0
+```
diff --git a/docs/content/how-to/azure/create-azure-cluster.md b/docs/content/how-to/azure/create-azure-cluster.md
index ef32231851..b36c27d8b8 100644
--- a/docs/content/how-to/azure/create-azure-cluster.md
+++ b/docs/content/how-to/azure/create-azure-cluster.md
@@ -36,29 +36,3 @@ hypershift create cluster azure --pull-secret \
--node-pool-replicas 3 \
--external-dns-domain=
```
-
-## Creating the Cluster in an Existing Resource Group
-If you want to use an existing resource group you've created in Azure, you can pass the name into the `--resource-group-name` flag. This will create all needed Azure infrastructure in specified resource group.
-
-```
-hypershift create cluster azure --pull-secret \
---name \
---azure-creds \
---location eastus --base-domain \
---release-image \
---node-pool-replicas 3 \
---resource-group-name
-```
-
-If you need to delete your hosted cluster, you will need to also use the `--resource-group-name` flag on the delete command.
-
-```
-hypershift destroy cluster azure \
---name $CLUSTER_NAME \
---azure-creds $AZURE_CREDS \
---resource-group-name
-```
-
-!!! note
-
- If you delete your hosted cluster, it will end up deleting any existing resources prior to when the hosted cluster was created as well as the resource group itself.
\ No newline at end of file
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index 0815375f55..2cf39a6978 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -74,6 +74,7 @@ nav:
- how-to/aws/create-aws-hosted-cluster-arm-workers.md
- 'Azure':
- how-to/azure/create-azure-cluster.md
+ - how-to/azure/create-azure-cluster-with-options.md
- 'Agent':
- how-to/agent/create-agent-cluster.md
- 'Disconnected':