Skip to content

Commit

Permalink
Add new AWS podIdentity
Browse files Browse the repository at this point in the history
Co-authored-by: Sami S <[email protected]>
Signed-off-by: Jorge Turrado <[email protected]>
  • Loading branch information
JorTurFer and ThaSami committed Dec 31, 2023
1 parent 3c0db29 commit e7a57ac
Show file tree
Hide file tree
Showing 48 changed files with 2,396 additions and 226 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pr-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
id: checkUserMember
with:
username: ${{ github.actor }}
team: 'keda-e2e-test-executors'
team: "keda-e2e-test-executors"
GITHUB_TOKEN: ${{ secrets.GH_CHECKING_USER_AUTH }}

- name: Update comment with the execution url
Expand Down Expand Up @@ -221,5 +221,5 @@ jobs:
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4
with:
name: e2e-test-logs
path: '${{ github.workspace }}/tests/**/*.log'
path: "${{ github.workspace }}/**/*.log"
if-no-files-found: ignore
2 changes: 1 addition & 1 deletion .github/workflows/template-main-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ jobs:
if: ${{ always() }}
with:
name: e2e-test-logs
path: '${{ github.workspace }}/tests/**/*.log'
path: "${{ github.workspace }}/**/*.log"
if-no-files-found: ignore
2 changes: 1 addition & 1 deletion .github/workflows/template-smoke-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ jobs:
if: ${{ always() }}
with:
name: smoke-test-logs ${{ inputs.runs-on }}-${{ inputs.kubernetesVersion }}
path: "${{ github.workspace }}/tests/**/*.log"
path: "${{ github.workspace }}/**/*.log"
if-no-files-found: ignore
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ __debug_bin

# GO Test result
report.xml

# KEDA Certs
certs/*
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio

### New

- **General**: TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX))
- **General**: Introduce new AWS Authentication ([#4134](https://github.com/kedacore/keda/issues/4134))

#### Experimental

Expand All @@ -65,7 +65,9 @@ Here is an overview of all new **experimental** features:
- **General**: Add parameter queryParameters to prometheus-scaler ([#4962](https://github.com/kedacore/keda/issues/4962))
- **General**: Add validations for replica counts when creating ScaledObjects ([#5288](https://github.com/kedacore/keda/issues/5288))
- **General**: Bubble up AuthRef TriggerAuthentication errors as ScaledObject events ([#5190](https://github.com/kedacore/keda/issues/5190))
- **General**: Enhance podIdentity Role Assumption in AWS by Direct Integration with OIDC/Federation ([#5178](https://github.com/kedacore/keda/issues/5178))
- **General**: Fix issue where paused annotation being set to false still leads to scaled objects/jobs being paused ([#5215](https://github.com/kedacore/keda/issues/5215))
- **General**: Implement Credentials Cache for AWS Roles to reduce AWS API calls ([#5297](https://github.com/kedacore/keda/issues/5297))
- **General**: Support TriggerAuthentication properties from ConfigMap ([#4830](https://github.com/kedacore/keda/issues/4830))
- **General**: Use client-side round-robin load balancing for grpc calls ([#5224](https://github.com/kedacore/keda/issues/5224))
- **GCP pubsub scaler**: Support distribution-valued metrics and metrics from topics ([#5070](https://github.com/kedacore/keda/issues/5070))
Expand Down
1 change: 0 additions & 1 deletion apis/eventing/v1alpha1/zz_generated.deepcopy.go

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

17 changes: 16 additions & 1 deletion apis/keda/v1alpha1/triggerauthentication_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ const (
PodIdentityProviderAzure PodIdentityProvider = "azure"
PodIdentityProviderAzureWorkload PodIdentityProvider = "azure-workload"
PodIdentityProviderGCP PodIdentityProvider = "gcp"
PodIdentityProviderSpiffe PodIdentityProvider = "spiffe"
PodIdentityProviderAwsEKS PodIdentityProvider = "aws-eks"
PodIdentityProviderAwsKiam PodIdentityProvider = "aws-kiam"
PodIdentityProviderAws PodIdentityProvider = "aws"
)

// PodIdentityAnnotationEKS specifies aws role arn for aws-eks Identity Provider
Expand All @@ -133,9 +133,17 @@ const (
// AuthPodIdentity allows users to select the platform native identity
// mechanism
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
// 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
IdentityOwner *string `json:"identityOwner"`
}

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

func (a *AuthPodIdentity) IsWorkloadIdentityOwner() bool {
if a.IdentityOwner == nil {
return false
}
return *a.IdentityOwner == workloadString
}

// AuthConfigMapTargetRef is used to authenticate using a reference to a config map
type AuthConfigMapTargetRef AuthTargetRef

Expand Down
9 changes: 9 additions & 0 deletions apis/keda/v1alpha1/triggerauthentication_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

const (
kedaString = "keda"
workloadString = "workload"
)

var triggerauthenticationlog = logf.Log.WithName("triggerauthentication-validation-webhook")

func (ta *TriggerAuthentication) SetupWebhookWithManager(mgr ctrl.Manager) error {
Expand Down Expand Up @@ -113,6 +118,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.IsWorkloadIdentityOwner() {
return nil, fmt.Errorf("roleArn of PodIdentity can't be set if KEDA isn't identityOwner")
}
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(PodIdentityProviderAws, "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 := kedaString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "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 := workloadString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "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 := kedaString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "", 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 := workloadString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "", 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(PodIdentityProviderAws, "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 := kedaString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "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 := workloadString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "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 := kedaString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "", 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 := workloadString
spec := createTriggerAuthenticationSpecWithPodIdentity(PodIdentityProviderAws, "", 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: provider,
IdentityID: identityID,
RoleArn: roleArn,
IdentityOwner: identityOwner,
},
}
}
Expand Down
21 changes: 20 additions & 1 deletion apis/keda/v1alpha1/zz_generated.deepcopy.go

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

Loading

0 comments on commit e7a57ac

Please sign in to comment.