Skip to content

Commit

Permalink
update logic to support identity owner at ta level
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Turrado <[email protected]>
  • Loading branch information
JorTurFer committed Dec 27, 2023
1 parent b967a98 commit 0e6a3f3
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 39 deletions.
10 changes: 10 additions & 0 deletions apis/keda/v1alpha1/triggerauthentication_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ type AuthPodIdentity struct {
IdentityID *string `json:"identityId"`
// +optional
RoleArn string `json:"roleArn"`
// +kubebuilder:validation:Enum=keda;workload
// +optional
IdentityOwner *string `json:"identityOwner"`
}

func (a *AuthPodIdentity) GetIdentityID() string {
Expand All @@ -145,6 +148,13 @@ func (a *AuthPodIdentity) GetIdentityID() string {
return *a.IdentityID
}

func (a *AuthPodIdentity) IsKedaIdentityOwner() bool {
if a.IdentityOwner == nil {
return true
}
return *a.IdentityOwner == "keda"
}

// AuthSecretTargetRef is used to authenticate using a reference to a secret
type AuthSecretTargetRef struct {
Parameter string `json:"parameter"`
Expand Down
4 changes: 4 additions & 0 deletions apis/keda/v1alpha1/triggerauthentication_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ func validateSpec(spec *TriggerAuthenticationSpec) (admission.Warnings, error) {
if spec.PodIdentity.IdentityID != nil && *spec.PodIdentity.IdentityID == "" {
return nil, fmt.Errorf("identityid of PodIdentity should not be empty. If it's set, identityId has to be different than \"\"")
}
case PodIdentityProviderAws:
if spec.PodIdentity.RoleArn != "" && !spec.PodIdentity.IsKedaIdentityOwner() {
return nil, fmt.Errorf("identityid of PodIdentity should not be empty. If it's set, identityId has to be different than \"\"")
}
default:
return nil, nil
}
Expand Down
160 changes: 150 additions & 10 deletions apis/keda/v1alpha1/triggerauthentication_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var _ = It("validate triggerauthentication when IdentityID is nil", func() {
var _ = It("validate triggerauthentication when IdentityID is nil, roleArn is empty and identityOwner is nil", func() {
namespaceName := "nilidentityid"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

spec := createTriggerAuthenticationSpecWithPodIdentity(nil)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, nil)
ta := createTriggerAuthentication("nilidentityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
Expand All @@ -44,7 +44,7 @@ var _ = It("validate triggerauthentication when IdentityID is empty", func() {
Expect(err).ToNot(HaveOccurred())

identityID := ""
spec := createTriggerAuthenticationSpecWithPodIdentity(&identityID)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", &identityID, nil)
ta := createTriggerAuthentication("emptyidentityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
Expand All @@ -58,7 +58,76 @@ var _ = It("validate triggerauthentication when IdentityID is not empty", func()
Expect(err).ToNot(HaveOccurred())

identityID := "12345"
spec := createTriggerAuthenticationSpecWithPodIdentity(&identityID)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", &identityID, nil)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate triggerauthentication when RoleArn is not empty and IdentityOwner is nil", func() {
namespaceName := "rolearn"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, nil)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate triggerauthentication when RoleArn is not empty and IdentityOwner is keda", func() {
namespaceName := "rolearnandkedaowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "keda"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, &identityOwner)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate triggerauthentication when RoleArn is not empty and IdentityOwner is workload", func() {
namespaceName := "rolearnandworkloadowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "workload"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, &identityOwner)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).Should(HaveOccurred())
})

var _ = It("validate triggerauthentication when RoleArn is empty and IdentityOwner is keda", func() {
namespaceName := "kedaowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "keda"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, &identityOwner)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate triggerauthentication when RoleArn is not empty and IdentityOwner is workload", func() {
namespaceName := "workloadowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "workload"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, &identityOwner)
ta := createTriggerAuthentication("identityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
Expand All @@ -71,7 +140,7 @@ var _ = It("validate clustertriggerauthentication when IdentityID is nil", func(
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

spec := createTriggerAuthenticationSpecWithPodIdentity(nil)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, nil)
ta := createTriggerAuthentication("clusternilidentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
Expand All @@ -85,7 +154,7 @@ var _ = It("validate clustertriggerauthentication when IdentityID is empty", fun
Expect(err).ToNot(HaveOccurred())

identityID := ""
spec := createTriggerAuthenticationSpecWithPodIdentity(&identityID)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", &identityID, nil)
ta := createTriggerAuthentication("clusteremptyidentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
Expand All @@ -99,18 +168,89 @@ var _ = It("validate clustertriggerauthentication when IdentityID is not empty",
Expect(err).ToNot(HaveOccurred())

identityID := "12345"
spec := createTriggerAuthenticationSpecWithPodIdentity(&identityID)
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", &identityID, nil)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

func createTriggerAuthenticationSpecWithPodIdentity(identityID *string) TriggerAuthenticationSpec {
var _ = It("validate clustertriggerauthentication when RoleArn is not empty and IdentityOwner is nil", func() {
namespaceName := "clusterrolearn"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, nil)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate clustertriggerauthentication when RoleArn is not empty and IdentityOwner is keda", func() {
namespaceName := "clusterrolearnandkedaowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "keda"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, &identityOwner)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate clustertriggerauthentication when RoleArn is not empty and IdentityOwner is workload", func() {
namespaceName := "clusterrolearnandworkloadowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "workload"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "Helo", nil, &identityOwner)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).Should(HaveOccurred())
})

var _ = It("validate clustertriggerauthentication when RoleArn is empty and IdentityOwner is keda", func() {
namespaceName := "clusterandkedaowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "keda"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, &identityOwner)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "ClusterTriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

var _ = It("validate clustertriggerauthentication when RoleArn is not empty and IdentityOwner is workload", func() {
namespaceName := "clusterandworkloadowner"
namespace := createNamespace(namespaceName)
err := k8sClient.Create(context.Background(), namespace)
Expect(err).ToNot(HaveOccurred())

identityOwner := "workload"
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAzure, "", nil, &identityOwner)
ta := createTriggerAuthentication("clusteridentityidta", namespaceName, "TriggerAuthentication", spec)
Eventually(func() error {
return k8sClient.Create(context.Background(), ta)
}).ShouldNot(HaveOccurred())
})

func createTriggerAuthenticationSpecWithPodIdentity(provider PodIdentityProvider, roleArn string, identityID, identityOwner *string) TriggerAuthenticationSpec {
return TriggerAuthenticationSpec{
PodIdentity: &AuthPodIdentity{
Provider: PodIdentityProviderAzure,
IdentityID: identityID,
Provider: PodIdentityProviderAzure,
IdentityID: identityID,
RoleArn: roleArn,
IdentityOwner: identityOwner,
},
}
}
Expand Down
5 changes: 5 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.

10 changes: 10 additions & 0 deletions config/crd/bases/keda.sh_clustertriggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ spec:
properties:
identityId:
type: string
identityOwner:
enum:
- keda
- workload
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -235,6 +240,11 @@ spec:
properties:
identityId:
type: string
identityOwner:
enum:
- keda
- workload
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down
10 changes: 10 additions & 0 deletions config/crd/bases/keda.sh_triggerauthentications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ spec:
properties:
identityId:
type: string
identityOwner:
enum:
- keda
- workload
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down Expand Up @@ -234,6 +239,11 @@ spec:
properties:
identityId:
type: string
identityOwner:
enum:
- keda
- workload
type: string
provider:
description: PodIdentityProvider contains the list of providers
enum:
Expand Down
31 changes: 17 additions & 14 deletions pkg/scaling/resolver/scale_resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,21 +185,24 @@ func ResolveAuthRefAndPodIdentity(ctx context.Context, client client.Client, log
switch podIdentity.Provider {
case kedav1alpha1.PodIdentityProviderAws:
if podIdentity.RoleArn != "" {
if podIdentity.RoleArn == "workload" {
serviceAccountName := defaultServiceAccount
if podTemplateSpec.Spec.ServiceAccountName != "" {
serviceAccountName = podTemplateSpec.Spec.ServiceAccountName
}
serviceAccount := &corev1.ServiceAccount{}
err := client.Get(ctx, types.NamespacedName{Name: serviceAccountName, Namespace: namespace}, serviceAccount)
if err != nil {
return nil, kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone},
fmt.Errorf("error getting service account: '%s', error: %w", serviceAccountName, err)
}
authParams["awsRoleArn"] = serviceAccount.Annotations[kedav1alpha1.PodIdentityAnnotationEKS]
} else {
authParams["awsRoleArn"] = podIdentity.RoleArn
if !podIdentity.IsKedaIdentityOwner() {
return nil, kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone},
fmt.Errorf("roleArn can't be set if KEDA isn't identity owner, current value: '%s'", *podIdentity.IdentityOwner)
}
authParams["awsRoleArn"] = podIdentity.RoleArn
}
if !podIdentity.IsKedaIdentityOwner() {
serviceAccountName := defaultServiceAccount
if podTemplateSpec.Spec.ServiceAccountName != "" {
serviceAccountName = podTemplateSpec.Spec.ServiceAccountName
}
serviceAccount := &corev1.ServiceAccount{}
err := client.Get(ctx, types.NamespacedName{Name: serviceAccountName, Namespace: namespace}, serviceAccount)
if err != nil {
return nil, kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone},
fmt.Errorf("error getting service account: '%s', error: %w", serviceAccountName, err)
}
authParams["awsRoleArn"] = serviceAccount.Annotations[kedav1alpha1.PodIdentityAnnotationEKS]
}
case kedav1alpha1.PodIdentityProviderAwsEKS:
serviceAccountName := defaultServiceAccount
Expand Down
Loading

0 comments on commit 0e6a3f3

Please sign in to comment.