Skip to content

Commit

Permalink
feat: azure tenant id override for azure workload identity trigger auth
Browse files Browse the repository at this point in the history
resolves kedacore#5441
  • Loading branch information
pauldotyu committed Feb 17, 2024
1 parent 8bfd635 commit c158979
Show file tree
Hide file tree
Showing 17 changed files with 155 additions and 36 deletions.
25 changes: 25 additions & 0 deletions apis/keda/v1alpha1/triggerauthentication_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,22 @@ const (
type AuthPodIdentity struct {
// +kubebuilder:validation:Enum=azure;azure-workload;gcp;aws;aws-eks;aws-kiam
Provider PodIdentityProvider `json:"provider"`

// +optional
IdentityID *string `json:"identityId"`

// +optional
// Set identityTenantId to override the default Azure tenant id
IdentityTenantID *string `json:"identityTenantId"`

// +optional
// Set identityAuthorityHost to override the default Azure authority host
IdentityAuthorityHost *string `json:"identityAuthorityHost"`

// +kubebuilder:validation:Optional
// RoleArn sets the AWS RoleArn to be used. Mutually exclusive with IdentityOwner
RoleArn string `json:"roleArn"`

// +kubebuilder:validation:Enum=keda;workload
// +optional
// IdentityOwner configures which identity has to be used during auto discovery, keda or the scaled workload. Mutually exclusive with roleArn
Expand All @@ -159,6 +170,20 @@ func (a *AuthPodIdentity) GetIdentityID() string {
return *a.IdentityID
}

func (a *AuthPodIdentity) GetIdentityTenantID() string {
if a.IdentityTenantID == nil {
return ""
}
return *a.IdentityTenantID
}

func (a *AuthPodIdentity) GetIdentityAuthorityHost() string {
if a.IdentityAuthorityHost == nil {
return ""
}
return *a.IdentityAuthorityHost
}

func (a *AuthPodIdentity) IsWorkloadIdentityOwner() bool {
if a.IdentityOwner == nil {
return false
Expand Down
10 changes: 10 additions & 0 deletions apis/keda/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions config/crd/bases/keda.sh_clustertriggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -148,6 +152,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -237,6 +245,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -247,6 +259,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -350,6 +366,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -360,6 +380,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -466,6 +490,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -476,6 +504,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default Azure
tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down
32 changes: 32 additions & 0 deletions config/crd/bases/keda.sh_triggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -147,6 +151,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -236,6 +244,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -246,6 +258,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -349,6 +365,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -359,6 +379,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default
Azure tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -465,6 +489,10 @@ spec:
AuthPodIdentity allows users to select the platform native identity
mechanism
properties:
identityAuthorityHost:
description: Set identityAuthorityHost to override the default
Azure authority host
type: string
identityId:
type: string
identityOwner:
Expand All @@ -475,6 +503,10 @@ spec:
- keda
- workload
type: string
identityTenantId:
description: Set identityTenantId to override the default Azure
tenant id
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down
59 changes: 38 additions & 21 deletions pkg/scalers/azure/azure_aad_workload_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,38 @@ const (
azureClientIDEnv = "AZURE_CLIENT_ID"
azureTenantIDEnv = "AZURE_TENANT_ID"
azureFederatedTokenFileEnv = "AZURE_FEDERATED_TOKEN_FILE"
azureAuthrityHostEnv = "AZURE_AUTHORITY_HOST"
azureAuthorityHostEnv = "AZURE_AUTHORITY_HOST"
)

var DefaultClientID string
var TenantID string
var DefaultTenantID string
var TokenFilePath string
var AuthorityHost string
var DefaultAuthorityHost string

func init() {
DefaultClientID = os.Getenv(azureClientIDEnv)
TenantID = os.Getenv(azureTenantIDEnv)
DefaultTenantID = os.Getenv(azureTenantIDEnv)
TokenFilePath = os.Getenv(azureFederatedTokenFileEnv)
AuthorityHost = os.Getenv(azureAuthrityHostEnv)
DefaultAuthorityHost = os.Getenv(azureAuthorityHostEnv)
}

// GetAzureADWorkloadIdentityToken returns the AADToken for resource
func GetAzureADWorkloadIdentityToken(ctx context.Context, identityID, resource string) (AADToken, error) {
func GetAzureADWorkloadIdentityToken(ctx context.Context, identityID, identityTenantID, identityAuthorityHost, resource string) (AADToken, error) {
clientID := DefaultClientID
if identityID != "" {
clientID = identityID
}

tenantID := DefaultTenantID
if identityTenantID != "" {
tenantID = identityTenantID
}

authorityHost := DefaultAuthorityHost
if identityAuthorityHost != "" {
authorityHost = identityAuthorityHost
}

signedAssertion, err := readJWTFromFileSystem(TokenFilePath)
if err != nil {
return AADToken{}, fmt.Errorf("error reading service account token - %w", err)
Expand All @@ -77,7 +87,7 @@ func GetAzureADWorkloadIdentityToken(ctx context.Context, identityID, resource s
})

confidentialClient, err := confidential.New(
fmt.Sprintf("%s%s/oauth2/token", AuthorityHost, TenantID),
fmt.Sprintf("%s%s/oauth2/token", authorityHost, tenantID),
clientID,
cred,
)
Expand Down Expand Up @@ -117,41 +127,48 @@ func getScopedResource(resource string) string {
}

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

func NewAzureADWorkloadIdentityConfig(ctx context.Context, identityID, resource string) auth.AuthorizerConfig {
return ADWorkloadIdentityConfig{ctx: ctx, IdentityID: identityID, Resource: resource}
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.Resource)), nil
aadWiConfig.ctx, aadWiConfig.IdentityID, aadWiConfig.IdentityTenantID, aadWiConfig.IdentityAuthorityHost, aadWiConfig.Resource)), nil
}

func NewADWorkloadIdentityCredential(identityID string) (*azidentity.WorkloadIdentityCredential, error) {
func NewADWorkloadIdentityCredential(identityID, identityTenantId string) (*azidentity.WorkloadIdentityCredential, error) {
options := &azidentity.WorkloadIdentityCredentialOptions{}
if identityID != "" {
options.ClientID = identityID
}
if identityTenantId != "" {
options.TenantID = identityTenantId
}
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
Resource string
aadToken AADToken
ctx context.Context
IdentityID string
IdentityTenantID string
IdentityAuthorityHost string
Resource string
aadToken AADToken
}

func NewAzureADWorkloadIdentityTokenProvider(ctx context.Context, identityID, resource string) *ADWorkloadIdentityTokenProvider {
return &ADWorkloadIdentityTokenProvider{ctx: ctx, IdentityID: identityID, Resource: resource}
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.
Expand All @@ -165,7 +182,7 @@ func (wiTokenProvider *ADWorkloadIdentityTokenProvider) Refresh() error {
return nil
}

aadToken, err := GetAzureADWorkloadIdentityToken(wiTokenProvider.ctx, wiTokenProvider.IdentityID, wiTokenProvider.Resource)
aadToken, err := GetAzureADWorkloadIdentityToken(wiTokenProvider.ctx, wiTokenProvider.IdentityID, wiTokenProvider.IdentityTenantID, wiTokenProvider.IdentityAuthorityHost, wiTokenProvider.Resource)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/scalers/azure/azure_app_insights.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func getAuthConfig(ctx context.Context, info AppInsightsInfo, podIdentity kedav1
config.ClientID = podIdentity.GetIdentityID()
return config
case kedav1alpha1.PodIdentityProviderAzureWorkload:
return NewAzureADWorkloadIdentityConfig(ctx, podIdentity.GetIdentityID(), info.AppInsightsResourceURL)
return NewAzureADWorkloadIdentityConfig(ctx, podIdentity.GetIdentityID(), podIdentity.GetIdentityTenantID(), podIdentity.GetIdentityAuthorityHost(), info.AppInsightsResourceURL)
}
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/scalers/azure/azure_azidentity_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/kedacore/keda/v2/apis/keda/v1alpha1"
)

func NewChainedCredential(logger logr.Logger, identityID string, podIdentity v1alpha1.PodIdentityProvider) (*azidentity.ChainedTokenCredential, error) {
func NewChainedCredential(logger logr.Logger, identityID, identityTenantId string, podIdentity v1alpha1.PodIdentityProvider) (*azidentity.ChainedTokenCredential, error) {
var creds []azcore.TokenCredential

// Used for local debug based on az-cli user
Expand Down Expand Up @@ -42,7 +42,7 @@ func NewChainedCredential(logger logr.Logger, identityID string, podIdentity v1a
creds = append(creds, msiCred)
}
case v1alpha1.PodIdentityProviderAzureWorkload:
wiCred, err := NewADWorkloadIdentityCredential(identityID)
wiCred, err := NewADWorkloadIdentityCredential(identityID, identityTenantId)
if err != nil {
logger.Error(err, "error starting azure workload-identity token provider")
} else {
Expand Down
2 changes: 1 addition & 1 deletion pkg/scalers/azure/azure_data_explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func getDataExplorerAuthConfig(metadata *DataExplorerMetadata) (*kusto.Connectio

case kedav1alpha1.PodIdentityProviderAzure, kedav1alpha1.PodIdentityProviderAzureWorkload:
azureDataExplorerLogger.V(1).Info(fmt.Sprintf("Creating Azure Data Explorer Client using podIdentity %s", metadata.PodIdentity.Provider))
creds, chainedErr := NewChainedCredential(azureDataExplorerLogger, metadata.PodIdentity.GetIdentityID(), metadata.PodIdentity.Provider)
creds, chainedErr := NewChainedCredential(azureDataExplorerLogger, metadata.PodIdentity.GetIdentityID(), metadata.PodIdentity.GetIdentityTenantID(), metadata.PodIdentity.Provider)
if chainedErr != nil {
return nil, chainedErr
}
Expand Down
Loading

0 comments on commit c158979

Please sign in to comment.