From f8126b701ab3f1de20bfb269c003710650ca404a Mon Sep 17 00:00:00 2001 From: sdehaes Date: Wed, 28 Dec 2022 10:38:08 +0100 Subject: [PATCH] Added support for azure workload identity --- charts/cluster-autoscaler/Chart.yaml | 2 +- charts/cluster-autoscaler/README.md | 1 + .../templates/deployment.yaml | 5 +++- charts/cluster-autoscaler/values.yaml | 3 ++ .../cloudprovider/azure/azure_client.go | 13 +++++++++ .../cloudprovider/azure/azure_config.go | 29 +++++++++++++++---- 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/charts/cluster-autoscaler/Chart.yaml b/charts/cluster-autoscaler/Chart.yaml index b8e42347c9ba..a893fc638526 100644 --- a/charts/cluster-autoscaler/Chart.yaml +++ b/charts/cluster-autoscaler/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 1.23.0 +appVersion: 1.23.1 description: Scales Kubernetes worker nodes within autoscaling groups. engine: gotpl home: https://github.com/kubernetes/autoscaler diff --git a/charts/cluster-autoscaler/README.md b/charts/cluster-autoscaler/README.md index cabc23ff62ac..4f1237a386af 100644 --- a/charts/cluster-autoscaler/README.md +++ b/charts/cluster-autoscaler/README.md @@ -304,6 +304,7 @@ Though enough for the majority of installations, the default PodSecurityPolicy _ | azureSubscriptionID | string | `""` | Azure subscription where the resources are located. Required if `cloudProvider=azure` | | azureTenantID | string | `""` | Azure tenant where the resources are located. Required if `cloudProvider=azure` | | azureUseManagedIdentityExtension | bool | `false` | Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. | +| azureUseWorkloadIdentityExtension | bool | `false` | Whether to use Azure's workload identity extension for credentials. | | azureVMType | string | `"AKS"` | Azure VM type. | | cloudConfigPath | string | `""` | Configuration file for cloud provider. | | cloudProvider | string | `"aws"` | The cloud provider where the autoscaler runs. Currently only `gce`, `aws`, `azure`, `magnum` and `clusterapi` are supported. `aws` supported for AWS. `gce` for GCE. `azure` for Azure AKS. `magnum` for OpenStack Magnum, `clusterapi` for Cluster API. | diff --git a/charts/cluster-autoscaler/templates/deployment.yaml b/charts/cluster-autoscaler/templates/deployment.yaml index 84444a8d6b92..cbe477de27dc 100644 --- a/charts/cluster-autoscaler/templates/deployment.yaml +++ b/charts/cluster-autoscaler/templates/deployment.yaml @@ -153,7 +153,10 @@ spec: secretKeyRef: key: ClusterName name: {{ template "cluster-autoscaler.fullname" . }} - {{- if .Values.azureUseManagedIdentityExtension }} + {{- if .Values.azureUseWorkloadIdentityExtension }} + - name: ARM_USE_WORKLOAD_IDENTITY_EXTENSION + value: "true" + {{- else if .Values.azureUseManagedIdentityExtension }} - name: ARM_USE_MANAGED_IDENTITY_EXTENSION value: "true" {{- else }} diff --git a/charts/cluster-autoscaler/values.yaml b/charts/cluster-autoscaler/values.yaml index 1a4c1bcf3946..8633cbca2d1a 100644 --- a/charts/cluster-autoscaler/values.yaml +++ b/charts/cluster-autoscaler/values.yaml @@ -95,6 +95,9 @@ azureClusterName: "" # Required if `cloudProvider=azure` azureNodeResourceGroup: "" +# azureUseWorkloadIdentityExtension -- Whether to use Azure's workload identity extension for credentials. +azureUseWorkloadIdentityExtension: false + # azureUseManagedIdentityExtension -- Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. azureUseManagedIdentityExtension: false diff --git a/cluster-autoscaler/cloudprovider/azure/azure_client.go b/cluster-autoscaler/cloudprovider/azure/azure_client.go index 8690e1114f4e..f344e79e155f 100644 --- a/cluster-autoscaler/cloudprovider/azure/azure_client.go +++ b/cluster-autoscaler/cloudprovider/azure/azure_client.go @@ -21,6 +21,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" @@ -162,6 +163,18 @@ func newServicePrincipalTokenFromCredentials(config *Config, env *azure.Environm return nil, fmt.Errorf("creating the OAuth config: %v", err) } + if config.UseWorkloadIdentityExtension { + klog.V(2).Infoln("azure: using workload identity extension to retrieve access token") + jwt, err := os.ReadFile(config.AADFederatedTokenFile) + if err != nil { + return nil, fmt.Errorf("failed to read a file with a federated token: %v", err) + } + token, err := adal.NewServicePrincipalTokenFromFederatedToken(*oauthConfig, config.AADClientID, string(jwt), env.ResourceManagerEndpoint) + if err != nil { + return nil, fmt.Errorf("failed to create a workload identity token: %v", err) + } + return token, nil + } if config.UseManagedIdentityExtension { klog.V(2).Infoln("azure: using managed identity extension to retrieve access token") msiEndpoint, err := adal.GetMSIVMEndpoint() diff --git a/cluster-autoscaler/cloudprovider/azure/azure_config.go b/cluster-autoscaler/cloudprovider/azure/azure_config.go index a1ef62d6cd9c..56e6ba99b1d2 100644 --- a/cluster-autoscaler/cloudprovider/azure/azure_config.go +++ b/cluster-autoscaler/cloudprovider/azure/azure_config.go @@ -97,12 +97,14 @@ type Config struct { // Settings for a service principal. - AADClientID string `json:"aadClientId" yaml:"aadClientId"` - AADClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"` - AADClientCertPath string `json:"aadClientCertPath" yaml:"aadClientCertPath"` - AADClientCertPassword string `json:"aadClientCertPassword" yaml:"aadClientCertPassword"` - UseManagedIdentityExtension bool `json:"useManagedIdentityExtension" yaml:"useManagedIdentityExtension"` - UserAssignedIdentityID string `json:"userAssignedIdentityID" yaml:"userAssignedIdentityID"` + AADClientID string `json:"aadClientId" yaml:"aadClientId"` + AADClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"` + AADClientCertPath string `json:"aadClientCertPath" yaml:"aadClientCertPath"` + AADClientCertPassword string `json:"aadClientCertPassword" yaml:"aadClientCertPassword"` + AADFederatedTokenFile string `json:"aadFederatedTokenFile" yaml:"aadFederatedTokenFile"` + UseManagedIdentityExtension bool `json:"useManagedIdentityExtension" yaml:"useManagedIdentityExtension"` + UseWorkloadIdentityExtension bool `json:"useWorkloadIdentityExtension" yaml:"useWorkloadIdentityExtension"` + UserAssignedIdentityID string `json:"userAssignedIdentityID" yaml:"userAssignedIdentityID"` // Configs only for standard vmType (agent pools). Deployment string `json:"deployment" yaml:"deployment"` @@ -155,7 +157,14 @@ func BuildAzureConfig(configReader io.Reader) (*Config, error) { cfg.Location = os.Getenv("LOCATION") cfg.ResourceGroup = os.Getenv("ARM_RESOURCE_GROUP") cfg.TenantID = os.Getenv("ARM_TENANT_ID") + if tenantId := os.Getenv("AZURE_TENANT_ID"); tenantId != "" { + cfg.TenantID = tenantId + } cfg.AADClientID = os.Getenv("ARM_CLIENT_ID") + if clientId := os.Getenv("AZURE_CLIENT_ID"); clientId != "" { + cfg.AADClientID = clientId + } + cfg.AADFederatedTokenFile = os.Getenv("AZURE_FEDERATED_TOKEN_FILE") cfg.AADClientSecret = os.Getenv("ARM_CLIENT_SECRET") cfg.VMType = strings.ToLower(os.Getenv("ARM_VM_TYPE")) cfg.AADClientCertPath = os.Getenv("ARM_CLIENT_CERT_PATH") @@ -178,6 +187,14 @@ func BuildAzureConfig(configReader io.Reader) (*Config, error) { } } + useWorkloadIdentityExtensionFromEnv := os.Getenv("ARM_USE_WORKLOAD_IDENTITY_EXTENSION") + if len(useWorkloadIdentityExtensionFromEnv) > 0 { + cfg.UseWorkloadIdentityExtension, err = strconv.ParseBool(useWorkloadIdentityExtensionFromEnv) + if err != nil { + return nil, err + } + } + userAssignedIdentityIDFromEnv := os.Getenv("ARM_USER_ASSIGNED_IDENTITY_ID") if userAssignedIdentityIDFromEnv != "" { cfg.UserAssignedIdentityID = userAssignedIdentityIDFromEnv