Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removal of Microsoft ADAL identity and to use azidentity(MSAL) #6280 #6353

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ images:
- name: ghcr.io/kedacore/keda
newName: ghcr.io/kedacore/keda
newTag: main
commonLabels:
azure.workload.identity/use: "true"
5 changes: 5 additions & 0 deletions config/service_account/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ resources:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
azure.workload.identity/use: "true"
commonAnnotations:
azure.workload.identity/client-id: ""
azure.workload.identity/tenant-id: ""
7 changes: 2 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ require (
cloud.google.com/go/secretmanager v1.14.2
cloud.google.com/go/storage v1.43.0
dario.cat/mergo v1.0.1
github.com/Azure/azure-amqp-common-go/v4 v4.2.0
github.com/Azure/azure-kusto-go v0.16.1
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
Expand All @@ -20,7 +19,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0
github.com/Azure/go-autorest/autorest v0.11.29
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3
github.com/DataDog/datadog-api-client-go v1.16.0
github.com/Huawei/gophercloud v1.0.21
Expand Down Expand Up @@ -118,6 +116,8 @@ require (
sigs.k8s.io/kustomize/kustomize/v5 v5.5.0
)

require github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect

replace (
// pin k8s.io to v0.31.2 & sigs.k8s.io/controller-runtime to v0.19.1
github.com/google/cel-go => github.com/google/cel-go v0.20.1
Expand Down Expand Up @@ -172,8 +172,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect
github.com/Azure/go-amqp v1.1.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
Expand Down Expand Up @@ -206,7 +204,6 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/eapache/go-resiliency v1.7.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
github.com/eapache/queue v1.1.0 // indirect
Expand Down
10 changes: 0 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1340,8 +1340,6 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
github.com/Azure/azure-amqp-common-go/v4 v4.2.0 h1:q/jLx1KJ8xeI8XGfkOWMN9XrXzAfVTkyvCxPvHCjd2I=
github.com/Azure/azure-amqp-common-go/v4 v4.2.0/go.mod h1:GD3m/WPPma+621UaU6KNjKEo5Hl09z86viKwQjTpV0Q=
github.com/Azure/azure-kusto-go v0.16.1 h1:vCBWcQghmC1qIErUUgVNWHxGhZVStu1U/hki6iBA14k=
github.com/Azure/azure-kusto-go v0.16.1/go.mod h1:9F2zvXH8B6eWzgI1S4k1ZXAIufnBZ1bv1cW1kB1n3D0=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
Expand Down Expand Up @@ -1384,17 +1382,11 @@ github.com/Azure/go-amqp v1.1.0 h1:XUhx5f4lZFVf6LQc5kBUFECW0iJW9VLxKCYrBeGwl0U=
github.com/Azure/go-amqp v1.1.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8=
github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
Expand Down Expand Up @@ -1604,8 +1596,6 @@ github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down
80 changes: 0 additions & 80 deletions pkg/scalers/azure/azure_aad_workload_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ import (
"os"
"strconv"
"strings"
"time"

amqpAuth "github.com/Azure/azure-amqp-common-go/v4/auth"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

Expand Down Expand Up @@ -128,24 +124,6 @@ func getScopedResource(resource string) string {
return resource
}

type ADWorkloadIdentityConfig struct {
ctx context.Context
IdentityID string
IdentityTenantID string
IdentityAuthorityHost string
Resource string
}

func NewAzureADWorkloadIdentityConfig(ctx context.Context, identityID, identityTenantID, identityAuthorityHost, resource string) auth.AuthorizerConfig {
return ADWorkloadIdentityConfig{ctx: ctx, IdentityID: identityID, IdentityTenantID: identityTenantID, IdentityAuthorityHost: identityAuthorityHost, Resource: resource}
}

// Authorizer implements the auth.AuthorizerConfig interface
func (aadWiConfig ADWorkloadIdentityConfig) Authorizer() (autorest.Authorizer, error) {
return autorest.NewBearerAuthorizer(NewAzureADWorkloadIdentityTokenProvider(
aadWiConfig.ctx, aadWiConfig.IdentityID, aadWiConfig.IdentityTenantID, aadWiConfig.IdentityAuthorityHost, aadWiConfig.Resource)), nil
}

func NewADWorkloadIdentityCredential(identityID, identityTenantID string) (*azidentity.WorkloadIdentityCredential, error) {
options := &azidentity.WorkloadIdentityCredentialOptions{}
if identityID != "" {
Expand All @@ -156,61 +134,3 @@ func NewADWorkloadIdentityCredential(identityID, identityTenantID string) (*azid
}
return azidentity.NewWorkloadIdentityCredential(options)
}

// ADWorkloadIdentityTokenProvider is a type that implements the adal.OAuthTokenProvider and adal.Refresher interfaces.
// The OAuthTokenProvider interface is used by the BearerAuthorizer to get the token when preparing the HTTP Header.
// The Refresher interface is used by the BearerAuthorizer to refresh the token.
type ADWorkloadIdentityTokenProvider struct {
ctx context.Context
IdentityID string
IdentityTenantID string
IdentityAuthorityHost string
Resource string
aadToken AADToken
}

func NewAzureADWorkloadIdentityTokenProvider(ctx context.Context, identityID, identityTenantID, identityAuthorityHost, resource string) *ADWorkloadIdentityTokenProvider {
return &ADWorkloadIdentityTokenProvider{ctx: ctx, IdentityID: identityID, IdentityTenantID: identityTenantID, IdentityAuthorityHost: identityAuthorityHost, Resource: resource}
}

// OAuthToken is for implementing the adal.OAuthTokenProvider interface. It returns the current access token.
func (wiTokenProvider *ADWorkloadIdentityTokenProvider) OAuthToken() string {
return wiTokenProvider.aadToken.AccessToken
}

// Refresh is for implementing the adal.Refresher interface
func (wiTokenProvider *ADWorkloadIdentityTokenProvider) Refresh() error {
if time.Now().Before(wiTokenProvider.aadToken.ExpiresOnTimeObject) {
return nil
}

aadToken, err := GetAzureADWorkloadIdentityToken(wiTokenProvider.ctx, wiTokenProvider.IdentityID, wiTokenProvider.IdentityTenantID, wiTokenProvider.IdentityAuthorityHost, wiTokenProvider.Resource)
if err != nil {
return err
}

wiTokenProvider.aadToken = aadToken
return nil
}

// RefreshExchange is for implementing the adal.Refresher interface
func (wiTokenProvider *ADWorkloadIdentityTokenProvider) RefreshExchange(resource string) error {
wiTokenProvider.Resource = resource
return wiTokenProvider.Refresh()
}

// EnsureFresh is for implementing the adal.Refresher interface
func (wiTokenProvider *ADWorkloadIdentityTokenProvider) EnsureFresh() error {
return wiTokenProvider.Refresh()
}

// GetToken is for implementing the auth.TokenProvider interface
func (wiTokenProvider *ADWorkloadIdentityTokenProvider) GetToken(_ string) (*amqpAuth.Token, error) {
err := wiTokenProvider.Refresh()
if err != nil {
return nil, err
}

return amqpAuth.NewToken(amqpAuth.CBSTokenTypeJWT, wiTokenProvider.aadToken.AccessToken,
wiTokenProvider.aadToken.ExpiresOn), nil
}
34 changes: 17 additions & 17 deletions pkg/scalers/azure/azure_app_insights.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"strings"

"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure/auth"
logf "sigs.k8s.io/controller-runtime/pkg/log"

kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
Expand Down Expand Up @@ -59,19 +58,6 @@ func toISO8601(time string) (string, error) {
return fmt.Sprintf("PT%02dH%02dM", hours, minutes), nil
}

func getAuthConfig(ctx context.Context, info AppInsightsInfo, podIdentity kedav1alpha1.AuthPodIdentity) auth.AuthorizerConfig {
switch podIdentity.Provider {
case "", kedav1alpha1.PodIdentityProviderNone:
config := auth.NewClientCredentialsConfig(info.ClientID, info.ClientPassword, info.TenantID)
config.Resource = info.AppInsightsResourceURL
config.AADEndpoint = info.ActiveDirectoryEndpoint
return config
case kedav1alpha1.PodIdentityProviderAzureWorkload:
return NewAzureADWorkloadIdentityConfig(ctx, podIdentity.GetIdentityID(), podIdentity.GetIdentityTenantID(), podIdentity.GetIdentityAuthorityHost(), info.AppInsightsResourceURL)
}
return nil
}

func extractAppInsightValue(info AppInsightsInfo, metric ApplicationInsightsMetric) (float64, error) {
if _, ok := metric.Value[info.MetricID]; !ok {
return -1, fmt.Errorf("metric named %s not found in app insights response", info.MetricID)
Expand Down Expand Up @@ -109,10 +95,23 @@ func queryParamsForAppInsightsRequest(info AppInsightsInfo) (map[string]interfac
return queryParams, nil
}

func getAuthConfig(ctx context.Context, info AppInsightsInfo, podIdentity kedav1alpha1.AuthPodIdentity) (AADToken, error) {
token := AADToken{}
var err error

switch podIdentity.Provider {
case "", kedav1alpha1.PodIdentityProviderNone:
token, err = GetAzureADWorkloadIdentityToken(ctx, info.ClientID, info.TenantID, info.ActiveDirectoryEndpoint, info.AppInsightsResourceURL)
case kedav1alpha1.PodIdentityProviderAzureWorkload:
token, err = GetAzureADWorkloadIdentityToken(ctx, podIdentity.GetIdentityID(), podIdentity.GetIdentityTenantID(), podIdentity.GetIdentityAuthorityHost(), info.AppInsightsResourceURL)
}

return token, err
}

// GetAzureAppInsightsMetricValue returns the value of an Azure App Insights metric, rounded to the nearest int
func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, podIdentity kedav1alpha1.AuthPodIdentity, ignoreNullValues bool) (float64, error) {
config := getAuthConfig(ctx, info, podIdentity)
authorizer, err := config.Authorizer()
token, err := getAuthConfig(ctx, info, podIdentity)
Fixed Show fixed Hide fixed
if err != nil {
return -1, err
}
Expand All @@ -129,7 +128,8 @@ func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, p
autorest.WithPath("metrics"),
autorest.WithPath(info.MetricID),
autorest.WithQueryParameters(queryParams),
authorizer.WithAuthorization())
// MSAL here, use the autorest.WithBearerAuthorization(token)
autorest.WithBearerAuthorization(token.AccessToken))
if err != nil {
return -1, err
}
Expand Down
44 changes: 0 additions & 44 deletions pkg/scalers/azure/azure_app_insights_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package azure

import (
"context"
"testing"

"github.com/Azure/go-autorest/autorest/azure/auth"

kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
)

type testExtractAzAppInsightsTestData struct {
Expand Down Expand Up @@ -69,45 +64,6 @@ func TestAzGetAzureAppInsightsMetricValue(t *testing.T) {
}
}

type testAppInsightsAuthConfigTestData struct {
testName string
config string
info AppInsightsInfo
podIdentity kedav1alpha1.PodIdentityProvider
}

const (
msiConfig = "msiConfig"
clientCredentialsConfig = "clientCredentialsConfig"
workloadIdentityConfig = "workloadIdentityConfig"
)

var testAppInsightsAuthConfigData = []testAppInsightsAuthConfigTestData{
{"client credentials", clientCredentialsConfig, AppInsightsInfo{ClientID: "1234", ClientPassword: "pw", TenantID: "5678"}, ""},
{"client credentials - pod id none", clientCredentialsConfig, AppInsightsInfo{ClientID: "1234", ClientPassword: "pw", TenantID: "5678"}, kedav1alpha1.PodIdentityProviderNone},
{"azure workload identity", workloadIdentityConfig, AppInsightsInfo{}, kedav1alpha1.PodIdentityProviderAzureWorkload},
}

func TestAzAppInfoGetAuthConfig(t *testing.T) {
for _, testData := range testAppInsightsAuthConfigData {
authConfig := getAuthConfig(context.TODO(), testData.info, kedav1alpha1.AuthPodIdentity{Provider: testData.podIdentity})
switch testData.config {
case msiConfig:
if _, ok := authConfig.(auth.MSIConfig); !ok {
t.Errorf("Test %v; incorrect auth config. expected MSI config", testData.testName)
}
case clientCredentialsConfig:
if _, ok := authConfig.(auth.ClientCredentialsConfig); !ok {
t.Errorf("Test: %v; incorrect auth config. expected client credentials config", testData.testName)
}
case workloadIdentityConfig:
if _, ok := authConfig.(ADWorkloadIdentityConfig); !ok {
t.Errorf("Test: %v; incorrect auth config. expected ad workload identity config", testData.testName)
}
}
}
}

type toISO8601TestData struct {
testName string
isError bool
Expand Down
29 changes: 23 additions & 6 deletions pkg/scalers/rabbitmq_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
"strings"
"time"

"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
"github.com/go-logr/logr"
amqp "github.com/rabbitmq/amqp091-go"
v2 "k8s.io/api/autoscaling/v2"
"k8s.io/metrics/pkg/apis/external_metrics"

"github.com/kedacore/keda/v2/apis/keda/v1alpha1"
"github.com/kedacore/keda/v2/pkg/scalers/azure"
"github.com/kedacore/keda/v2/pkg/scalers/scalersconfig"
kedautil "github.com/kedacore/keda/v2/pkg/util"
)
Expand Down Expand Up @@ -64,7 +64,7 @@ type rabbitMQScaler struct {
connection *amqp.Connection
channel *amqp.Channel
httpClient *http.Client
azureOAuth *azure.ADWorkloadIdentityTokenProvider
azureOAuth *confidential.Client
logger logr.Logger
}

Expand Down Expand Up @@ -409,15 +409,32 @@ func getJSON(ctx context.Context, s *rabbitMQScaler, url string) (queueInfo, err

if s.metadata.WorkloadIdentityResource != "" {
if s.azureOAuth == nil {
s.azureOAuth = azure.NewAzureADWorkloadIdentityTokenProvider(ctx, s.metadata.workloadIdentityClientID, s.metadata.workloadIdentityTenantID, s.metadata.workloadIdentityAuthorityHost, s.metadata.WorkloadIdentityResource)
cred, err := confidential.NewCredFromSecret(s.metadata.workloadIdentityClientID)
if err != nil {
return result, err
}

client, err := confidential.New(
fmt.Sprintf("%s%s/oauth2/token", s.metadata.workloadIdentityAuthorityHost, s.metadata.workloadIdentityTenantID),
s.metadata.workloadIdentityClientID,
cred,
)
if err != nil {
return result, err
}

s.azureOAuth = &client
}

err = s.azureOAuth.Refresh()
token, err := s.azureOAuth.AcquireTokenSilent(ctx, []string{s.metadata.WorkloadIdentityResource})
if err != nil {
return result, err
token, err = s.azureOAuth.AcquireTokenByCredential(ctx, []string{s.metadata.WorkloadIdentityResource})
if err != nil {
return result, err
}
}

request.Header.Set("Authorization", "Bearer "+s.azureOAuth.OAuthToken())
request.Header.Set("Authorization", "Bearer "+token.AccessToken)
}

r, err := s.httpClient.Do(request)
Expand Down
21 changes: 0 additions & 21 deletions vendor/github.com/Azure/azure-amqp-common-go/v4/LICENSE

This file was deleted.

Loading
Loading