From 8f1ad61f00fc45bf9e8dd6f8f9ecc592b62db090 Mon Sep 17 00:00:00 2001 From: Nader Ziada Date: Wed, 22 Apr 2020 17:29:27 -0400 Subject: [PATCH] add support for azure system assigned identities - add new field for IdentityType in AzureMachineSpec - add new flavor for VMs with system assigned identity --- api/v1alpha2/azuremachine_conversion.go | 4 + .../azuremachinetemplate_conversion.go | 4 + api/v1alpha3/azuremachine_types.go | 4 + api/v1alpha3/types.go | 7 + .../virtualmachines/virtualmachines.go | 7 + ...ucture.cluster.x-k8s.io_azuremachines.yaml | 4 + ...luster.x-k8s.io_azuremachinetemplates.yaml | 5 + controllers/azuremachine_reconciler.go | 1 + ...ter-template-system-assigned-identity.yaml | 197 ++++++++++++++++++ .../kustomization.yaml | 5 + .../patches/system-assigned-identity.yaml | 52 +++++ .../system-assigned-identity.yaml | 76 +++++++ 12 files changed, 366 insertions(+) create mode 100644 templates/cluster-template-system-assigned-identity.yaml create mode 100644 templates/flavors/system-assigned-identity/kustomization.yaml create mode 100644 templates/flavors/system-assigned-identity/patches/system-assigned-identity.yaml create mode 100644 templates/flavors/system-assigned-identity/system-assigned-identity.yaml diff --git a/api/v1alpha2/azuremachine_conversion.go b/api/v1alpha2/azuremachine_conversion.go index 8e1feadb5ac..532c00fde21 100644 --- a/api/v1alpha2/azuremachine_conversion.go +++ b/api/v1alpha2/azuremachine_conversion.go @@ -35,6 +35,10 @@ func (src *AzureMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint restored := &infrav1alpha3.AzureMachine{} if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err + } else if ok { + if restored.Spec.Identity != "" { + dst.Spec.Identity = restored.Spec.Identity + } } return nil diff --git a/api/v1alpha2/azuremachinetemplate_conversion.go b/api/v1alpha2/azuremachinetemplate_conversion.go index d1a5da3d3ba..74a47670d2a 100644 --- a/api/v1alpha2/azuremachinetemplate_conversion.go +++ b/api/v1alpha2/azuremachinetemplate_conversion.go @@ -33,6 +33,10 @@ func (src *AzureMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nol restored := &infrav1alpha3.AzureMachineTemplate{} if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err + } else if ok { + if restored.Spec.Template.Spec.Identity != "" { + dst.Spec.Template.Spec.Identity = restored.Spec.Template.Spec.Identity + } } return nil diff --git a/api/v1alpha3/azuremachine_types.go b/api/v1alpha3/azuremachine_types.go index aaa5487de0d..5c00fa19ecd 100644 --- a/api/v1alpha3/azuremachine_types.go +++ b/api/v1alpha3/azuremachine_types.go @@ -44,6 +44,10 @@ type AzureMachineSpec struct { // +optional Image *Image `json:"image,omitempty"` + // Identity is the type of identity used for the virtual machine. + // The type 'SystemAssigned' is an implicitly created identity + Identity VMIdentity `json:"identity,omitempty"` + OSDisk OSDisk `json:"osDisk"` Location string `json:"location"` diff --git a/api/v1alpha3/types.go b/api/v1alpha3/types.go index cd9940f325c..1437e4b77a5 100644 --- a/api/v1alpha3/types.go +++ b/api/v1alpha3/types.go @@ -459,6 +459,13 @@ type AvailabilityZone struct { // VMIdentity defines the identity of the virtual machine, if configured. type VMIdentity string +const ( + // VMIdentityNone ... + VMIdentityNone VMIdentity = "None" + // VMIdentitySystemAssigned ... + VMIdentitySystemAssigned VMIdentity = "SystemAssigned" +) + type OSDisk struct { OSType string `json:"osType"` DiskSizeGB int32 `json:"diskSizeGB"` diff --git a/cloud/services/virtualmachines/virtualmachines.go b/cloud/services/virtualmachines/virtualmachines.go index 31529c495ed..c2aa6d5b10b 100644 --- a/cloud/services/virtualmachines/virtualmachines.go +++ b/cloud/services/virtualmachines/virtualmachines.go @@ -43,6 +43,7 @@ type Spec struct { Size string Zone string Image *infrav1.Image + Identity infrav1.VMIdentity OSDisk infrav1.OSDisk CustomData string } @@ -165,6 +166,12 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { virtualMachine.Zones = &zones } + if vmSpec.Identity == infrav1.VMIdentitySystemAssigned { + virtualMachine.Identity = &compute.VirtualMachineIdentity{ + Type: compute.ResourceIdentityTypeSystemAssigned, + } + } + err = s.Client.CreateOrUpdate( ctx, s.Scope.ResourceGroup(), diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml index 915d307f500..6bf3f0c3c18 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml @@ -253,6 +253,10 @@ spec: id: type: string type: object + identity: + description: Identity is the type of identity used for the virtual + machine. The type 'SystemAssigned' is an implicitly created identity + type: string image: description: Image is used to provide details of an image to use during VM creation. If image details are omitted the image will default diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml index 98662904be1..86d73a82137 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml @@ -190,6 +190,11 @@ spec: id: type: string type: object + identity: + description: Identity is the type of identity used for the + virtual machine. The type 'SystemAssigned' is an implicitly + created identity + type: string image: description: Image is used to provide details of an image to use during VM creation. If image details are omitted diff --git a/controllers/azuremachine_reconciler.go b/controllers/azuremachine_reconciler.go index 68c38acfaf5..f5c8aac4fa2 100644 --- a/controllers/azuremachine_reconciler.go +++ b/controllers/azuremachine_reconciler.go @@ -306,6 +306,7 @@ func (s *azureMachineService) createVirtualMachine(nicName string) (*infrav1.VM, Image: image, CustomData: bootstrapData, Zone: vmZone, + Identity: s.machineScope.AzureMachine.Spec.Identity, } err = s.virtualMachinesSvc.Reconcile(s.clusterScope.Context, vmSpec) diff --git a/templates/cluster-template-system-assigned-identity.yaml b/templates/cluster-template-system-assigned-identity.yaml new file mode 100644 index 00000000000..c7e3935a2eb --- /dev/null +++ b/templates/cluster-template-system-assigned-identity.yaml @@ -0,0 +1,197 @@ +apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 +kind: KubeadmConfigTemplate +metadata: + name: ${CLUSTER_NAME}-md-0 +spec: + template: + spec: + files: + - content: | + { + "cloud": "AzurePublicCloud", + "tenantId": "${AZURE_TENANT_ID}", + "subscriptionId": "${AZURE_SUBSCRIPTION_ID}", + "resourceGroup": "${CLUSTER_NAME}", + "securityGroupName": "${CLUSTER_NAME}-node-nsg", + "location": "${AZURE_LOCATION}", + "vmType": "standard", + "vnetName": "${CLUSTER_NAME}-vnet", + "vnetResourceGroup": "${CLUSTER_NAME}", + "subnetName": "${CLUSTER_NAME}-node-subnet", + "routeTableName": "${CLUSTER_NAME}-node-routetable", + "loadBalancerSku": "standard", + "maximumLoadBalancerRuleCount": 250, + "useManagedIdentityExtension": true, + "useInstanceMetadata": true + } + owner: root:root + path: /etc/kubernetes/azure.json + permissions: "0644" + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + name: '{{ ds.meta_data["local_hostname"] }}' +--- +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: Cluster +metadata: + name: ${CLUSTER_NAME} + namespace: default +spec: + clusterNetwork: + pods: + cidrBlocks: + - 192.168.0.0/16 + controlPlaneRef: + apiVersion: controlplane.cluster.x-k8s.io/v1alpha3 + kind: KubeadmControlPlane + name: ${CLUSTER_NAME}-control-plane + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: AzureCluster + name: ${CLUSTER_NAME} +--- +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: MachineDeployment +metadata: + name: ${CLUSTER_NAME}-md-0 +spec: + clusterName: ${CLUSTER_NAME} + replicas: ${WORKER_MACHINE_COUNT} + selector: + matchLabels: null + template: + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 + kind: KubeadmConfigTemplate + name: ${CLUSTER_NAME}-md-0 + clusterName: ${CLUSTER_NAME} + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: AzureMachineTemplate + name: ${CLUSTER_NAME}-md-0 + version: ${KUBERNETES_VERSION} +--- +apiVersion: controlplane.cluster.x-k8s.io/v1alpha3 +kind: KubeadmControlPlane +metadata: + name: ${CLUSTER_NAME}-control-plane + namespace: default +spec: + infrastructureTemplate: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: AzureMachineTemplate + name: ${CLUSTER_NAME}-control-plane + kubeadmConfigSpec: + clusterConfiguration: + apiServer: + extraArgs: + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + extraVolumes: + - hostPath: /etc/kubernetes/azure.json + mountPath: /etc/kubernetes/azure.json + name: cloud-config + readOnly: true + timeoutForControlPlane: 20m + controllerManager: + extraArgs: + allocate-node-cidrs: "false" + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + extraVolumes: + - hostPath: /etc/kubernetes/azure.json + mountPath: /etc/kubernetes/azure.json + name: cloud-config + readOnly: true + files: + - content: | + { + "cloud": "AzurePublicCloud", + "tenantId": "${AZURE_TENANT_ID}", + "subscriptionId": "${AZURE_SUBSCRIPTION_ID}", + "aadClientId": "${AZURE_CLIENT_ID}", + "aadClientSecret": "${AZURE_CLIENT_SECRET}", + "resourceGroup": "${AZURE_RESOURCE_GROUP}", + "securityGroupName": "${CLUSTER_NAME}-node-nsg", + "location": "${AZURE_LOCATION}", + "vmType": "standard", + "vnetName": "${CLUSTER_NAME}-vnet", + "vnetResourceGroup": "${CLUSTER_NAME}", + "subnetName": "${CLUSTER_NAME}-node-subnet", + "routeTableName": "${CLUSTER_NAME}-node-routetable", + "userAssignedID": "${CLUSTER_NAME}", + "loadBalancerSku": "standard", + "maximumLoadBalancerRuleCount": 250, + "useManagedIdentityExtension": false, + "useInstanceMetadata": true + } + owner: root:root + path: /etc/kubernetes/azure.json + permissions: "0644" + initConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + name: '{{ ds.meta_data["local_hostname"] }}' + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + name: '{{ ds.meta_data["local_hostname"] }}' + useExperimentalRetryJoin: true + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + version: ${KUBERNETES_VERSION} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +kind: AzureCluster +metadata: + name: ${CLUSTER_NAME} + namespace: default +spec: + location: ${AZURE_LOCATION} + networkSpec: + vnet: + name: ${AZURE_VNET_NAME} + resourceGroup: ${AZURE_RESOURCE_GROUP} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +kind: AzureMachineTemplate +metadata: + name: ${CLUSTER_NAME}-control-plane + namespace: default +spec: + template: + spec: + identity: SystemAssigned + location: ${AZURE_LOCATION} + osDisk: + diskSizeGB: 128 + managedDisk: + storageAccountType: Premium_LRS + osType: Linux + sshPublicKey: ${AZURE_SSH_PUBLIC_KEY} + vmSize: ${AZURE_CONTROL_PLANE_MACHINE_TYPE} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +kind: AzureMachineTemplate +metadata: + name: ${CLUSTER_NAME}-md-0 +spec: + template: + spec: + identity: SystemAssigned + location: ${AZURE_LOCATION} + osDisk: + diskSizeGB: 30 + managedDisk: + storageAccountType: Premium_LRS + osType: Linux + sshPublicKey: ${AZURE_SSH_PUBLIC_KEY} + vmSize: ${AZURE_NODE_MACHINE_TYPE} diff --git a/templates/flavors/system-assigned-identity/kustomization.yaml b/templates/flavors/system-assigned-identity/kustomization.yaml new file mode 100644 index 00000000000..1a43c4024b6 --- /dev/null +++ b/templates/flavors/system-assigned-identity/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../base + - system-assigned-identity.yaml +patchesStrategicMerge: + - patches/system-assigned-identity.yaml \ No newline at end of file diff --git a/templates/flavors/system-assigned-identity/patches/system-assigned-identity.yaml b/templates/flavors/system-assigned-identity/patches/system-assigned-identity.yaml new file mode 100644 index 00000000000..3b86140db9f --- /dev/null +++ b/templates/flavors/system-assigned-identity/patches/system-assigned-identity.yaml @@ -0,0 +1,52 @@ +apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 +kind: KubeadmConfigTemplate +metadata: + name: ${CLUSTER_NAME}-md-0 +spec: + template: + spec: + files: + - content: | + { + "cloud": "AzurePublicCloud", + "tenantId": "${AZURE_TENANT_ID}", + "subscriptionId": "${AZURE_SUBSCRIPTION_ID}", + "resourceGroup": "${CLUSTER_NAME}", + "securityGroupName": "${CLUSTER_NAME}-node-nsg", + "location": "${AZURE_LOCATION}", + "vmType": "standard", + "vnetName": "${CLUSTER_NAME}-vnet", + "vnetResourceGroup": "${CLUSTER_NAME}", + "subnetName": "${CLUSTER_NAME}-node-subnet", + "routeTableName": "${CLUSTER_NAME}-node-routetable", + "loadBalancerSku": "standard", + "maximumLoadBalancerRuleCount": 250, + "useManagedIdentityExtension": true, + "useInstanceMetadata": true + } + owner: root:root + path: /etc/kubernetes/azure.json + permissions: "0644" + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-config: /etc/kubernetes/azure.json + cloud-provider: azure + name: '{{ ds.meta_data["local_hostname"] }}' +--- +kind: AzureMachineTemplate +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +metadata: + name: "${CLUSTER_NAME}-control-plane" +spec: + template: + spec: + location: ${AZURE_LOCATION} + identity: SystemAssigned + vmSize: ${AZURE_CONTROL_PLANE_MACHINE_TYPE} + osDisk: + osType: "Linux" + diskSizeGB: 128 + managedDisk: + storageAccountType: "Premium_LRS" + sshPublicKey: ${AZURE_SSH_PUBLIC_KEY} \ No newline at end of file diff --git a/templates/flavors/system-assigned-identity/system-assigned-identity.yaml b/templates/flavors/system-assigned-identity/system-assigned-identity.yaml new file mode 100644 index 00000000000..2e12e81cf92 --- /dev/null +++ b/templates/flavors/system-assigned-identity/system-assigned-identity.yaml @@ -0,0 +1,76 @@ +--- +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: MachineDeployment +metadata: + name: "${CLUSTER_NAME}-md-0" +spec: + clusterName: "${CLUSTER_NAME}" + replicas: ${WORKER_MACHINE_COUNT} + selector: + matchLabels: + template: + spec: + clusterName: "${CLUSTER_NAME}" + version: "${KUBERNETES_VERSION}" + bootstrap: + configRef: + name: "${CLUSTER_NAME}-md-0" + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 + kind: KubeadmConfigTemplate + infrastructureRef: + name: "${CLUSTER_NAME}-md-0" + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: AzureMachineTemplate +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +kind: AzureMachineTemplate +metadata: + name: "${CLUSTER_NAME}-md-0" +spec: + template: + spec: + location: ${AZURE_LOCATION} + identity: SystemAssigned + vmSize: ${AZURE_NODE_MACHINE_TYPE} + osDisk: + osType: "Linux" + diskSizeGB: 30 + managedDisk: + storageAccountType: "Premium_LRS" + sshPublicKey: ${AZURE_SSH_PUBLIC_KEY} +--- +apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 +kind: KubeadmConfigTemplate +metadata: + name: "${CLUSTER_NAME}-md-0" +spec: + template: + spec: + joinConfiguration: + nodeRegistration: + name: '{{ ds.meta_data["local_hostname"] }}' + kubeletExtraArgs: + cloud-provider: azure + cloud-config: /etc/kubernetes/azure.json + files: + - path: /etc/kubernetes/azure.json + owner: "root:root" + permissions: "0644" + content: | + { + "cloud": "AzurePublicCloud", + "tenantId": "${AZURE_TENANT_ID}", + "subscriptionId": "${AZURE_SUBSCRIPTION_ID}", + "resourceGroup": "${CLUSTER_NAME}", + "securityGroupName": "${CLUSTER_NAME}-node-nsg", + "location": "${AZURE_LOCATION}", + "vmType": "standard", + "vnetName": "${CLUSTER_NAME}-vnet", + "vnetResourceGroup": "${CLUSTER_NAME}", + "subnetName": "${CLUSTER_NAME}-node-subnet", + "routeTableName": "${CLUSTER_NAME}-node-routetable", + "loadBalancerSku": "standard", + "maximumLoadBalancerRuleCount": 250, + "useManagedIdentityExtension": true, + "useInstanceMetadata": true + }