Skip to content

Conversation

@elsesiy
Copy link

@elsesiy elsesiy commented Sep 16, 2025

We're using a custom secret solution that decrypts credentials via an init container and writes the resulting credentials to a shared emptyDir. The current AuthenticationRef is limiting as it forces us to store the credential in a Secret/ConfigMap instead and we'd like to avoid doing that due to the fact that we cannot use these safely in our environment.

Happy to discuss viable alternatives but for now the implementation looks as follows:

• Add optional FilePath field to AuthenticationRef for reading auth params from mounted files
• Implement readAuthParamsFromFile helper to parse JSON credentials
• Modify resolveAuthRef to handle file-based auth when FilePath is specified
• Add tests for new functionality
• Maintain backward compatibility with existing authentication methods

For namespaced TriggerAuthentication, users will need to use existing configMapTargetRef or secretTargetRef as file-mounting across namespaces (outside of the operator namespace that is) is impractical and provides no benefit over existing functionality.

Checklist

Fixes #7083

Relates to #

Note: I will open a docs PR shortly after a KEDA member confirms that they are accepting this change.

@github-actions
Copy link

Thank you for your contribution! 🙏

Please understand that we will do our best to review your PR and give you feedback as soon as possible, but please bear with us if it takes a little longer as expected.

While you are waiting, make sure to:

  • Add an entry in our changelog in alphabetical order and link related issue
  • Update the documentation, if needed
  • Add unit & e2e tests for your changes
  • GitHub checks are passing
  • Is the DCO check failing? Here is how you can fix DCO issues

Once the initial tests are successful, a KEDA member will ensure that the e2e tests are run. Once the e2e tests have been successfully completed, the PR may be merged at a later date. Please be patient.

Learn more about our contribution guide.

@keda-automation keda-automation requested review from a team September 16, 2025 06:24
@elsesiy elsesiy force-pushed the read-file branch 4 times, most recently from 104a39e to 690655c Compare September 16, 2025 07:11
@elsesiy elsesiy marked this pull request as ready for review September 16, 2025 07:28
@rickbrouwer
Copy link
Member

rickbrouwer commented Sep 17, 2025

/run-e2e file_based_auth_test
Update: You can check the progress here

@rickbrouwer
Copy link
Member

in a quick look I do see errors in the e2e:

ERROR Failed to get TriggerAuthentication "controller": "scaledobject", "controllerGroup": "keda.sh", "controllerKind": "ScaledObject", "ScaledObject": "name":"file-based-auth-test-so","namespace":"file-based-auth-test-ns", "namespace": "file-based-auth-test-ns", "name": "file-based-auth-test-so", "reconcileID": "0d8eea8-5d05-4d***-be5f-0ed760b04a4b", "error": "TriggerAuthentication.keda.sh "file-auth" not found"***

@elsesiy
Copy link
Author

elsesiy commented Sep 18, 2025

in a quick look I do see errors in the e2e:

ERROR Failed to get TriggerAuthentication "controller": "scaledobject", "controllerGroup": "keda.sh", "controllerKind": "ScaledObject", "ScaledObject": _"name":"file-based-auth-test-so","namespace":"file-based-auth-test-ns"**, "namespace": "file-based-auth-test-ns", "name": "file-based-auth-test-so", "reconcileID": "0d8eea**_8-5d05-4d***-be5f-0ed760b04a4b", "error": "TriggerAuthentication.keda.sh "file-auth" not found"***

Thanks for taking a look! I just pushed a fix in d80bb2e and was able to run it successfully locally now.

@SpiritZhou
Copy link
Contributor

SpiritZhou commented Sep 18, 2025

/run-e2e file_based_auth_test
Update: You can check the progress here

@rickbrouwer
Copy link
Member

Could you take a look at the test log? Because it looks like that the tests not have been executed.

@JorTurFer
Copy link
Member

Hello
I see the use case but in general, we try to avoid to use the filesystem to pull secrets because it means that KEDA needs to be restarted if the secret value changes or if new secrets are used. Instead of adding a source from file-system, I'd suggest to add another configuration source to pull the secrets directly from your secrets store.
What technology are you using if I can ask?

@JorTurFer JorTurFer closed this Sep 18, 2025
@JorTurFer JorTurFer reopened this Sep 18, 2025
@JorTurFer
Copy link
Member

sorry, I closed the PR by mistake clicking on comment button 🤦

@elsesiy
Copy link
Author

elsesiy commented Sep 19, 2025

Could you take a look at the test log? Because it looks like that the tests not have been executed.

Thanks @rickbrouwer I see the tests executed successfully here. Isn't that the correct log?

Hello
I see the use case but in general, we try to avoid to use the filesystem to pull secrets because it means that KEDA needs to be restarted if the secret value changes or if new secrets are used. Instead of adding a source from file-system, I'd suggest to add another configuration source to pull the secrets directly from your secrets store.
What technology are you using if I can ask?

@JorTurFer Thank you for your feedback and for sharing your concerns about storing credentials on disk.
I completely understand the caution around filesystem-based approaches, and I’d like to clarify a potential misunderstanding about pod restarts while explaining why this feature could benefit the KEDA ecosystem.

To address the bits about needing pod restarts when credentials on disk change: in Kubernetes, most volume types support dynamic updates without requiring a restart. For my use case with emptyDir, the ephemeral scratch space is shared across containers in the pod and tied to its lifecycle. Any writes by one container (e.g., updating a credential file) are immediately visible to others via the shared tmpfs or disk-backed filesystem, with no kubelet intervention or restart needed. Similarly, for hostPath with HostToContainer mount propagation , changes on the host’s filesystem propagate instantly to the pod’s mount. Even for ConfigMap or Secret volumes, the kubelet automatically updates mounted files during its sync loop (~1-2 minute delay) without restarts, unless using subPath. Arguably, users probably won't these as much since they provide little benefit over the existing config sources.

The proposed feature lets us avoid forking KEDA as our solution is proprietary, hence there is no easy way to add a new config source. Forking KEDA would also introduce long-term challenges for us with compatibility and maintainability as it'll likely require backporting upstream changes, so we’re aiming for a solution that aligns with the ecosystem.

Our use case with Grafana involves long-lived credentials across multiple clouds, so frequent secret changes aren’t a primary concern. However, the proposed filesystem-based approach still supports dynamic updates if needed (e.g., via external tools updating hostPath or in-pod writes to emptyDir). A key benefit is performance: unlike existing KEDA config sources that rely on network calls to external secret managers (e.g., Vault or AWS Secrets Manager), reading credentials from a mounted volume avoids network hops, reducing latency for each scaling trigger.

I’d love to hear your thoughts on this approach, thanks again for your time and for maintaining KEDA!

@elsesiy
Copy link
Author

elsesiy commented Sep 25, 2025

@rickbrouwer @JorTurFer could you please take another look here? Thank you!

@elsesiy elsesiy force-pushed the read-file branch 3 times, most recently from 5884a88 to ffc2afb Compare October 4, 2025 03:47
@JorTurFer
Copy link
Member

Hi,
I see your point but keeping aside the restart topic, reading arbitrary options and using the content as variables is quite risky if we don't at least limit the allowed folders. For example, I can use /var/run/secrets/kubernetes.io/serviceaccount/token as API key and send the content of the file to my malicious server, exposing KEDA's service account with high privileges.
I'd like to see other colleagues but if they agree with reading files mounted and not other resources storing them as files, at least we must limit the folder options to limit available paths to some well-defined paths.

In the other hand, I agree with the point of not building your custom KEDA's flavor just to support your secrets source and I'm wondering if it's worth for KEDA supporting a gRPC interface to query secrets to "external" secret sources (like we do with external scaler but for secrets), this could bring the option to implement just a proxy between the secrets solution and KEDA implementing the gRPC interface 🤔

@kedacore/keda-core-contributors @kedacore/keda-core-maintainers

@elsesiy
Copy link
Author

elsesiy commented Oct 20, 2025

Hi, I see your point but keeping aside the restart topic, reading arbitrary options and using the content as variables is quite risky if we don't at least limit the allowed folders. For example, I can use /var/run/secrets/kubernetes.io/serviceaccount/token as API key and send the content of the file to my malicious server, exposing KEDA's service account with high privileges. I'd like to see other colleagues but if they agree with reading files mounted and not other resources storing them as files, at least we must limit the folder options to limit available paths to some well-defined paths.

In the other hand, I agree with the point of not building your custom KEDA's flavor just to support your secrets source and I'm wondering if it's worth for KEDA supporting a gRPC interface to query secrets to "external" secret sources (like we do with external scaler but for secrets), this could bring the option to implement just a proxy between the secrets solution and KEDA implementing the gRPC interface 🤔

@kedacore/keda-core-contributors @kedacore/keda-core-maintainers

Thank you @JorTurFer for the discussion, I can see how the provided example of using /var/run/secrets/kubernetes.io/serviceaccount/token is problematic and agree that it should be limited. It's not something we would have encountered as we don't allow arbitrary creation of ClusterTriggerAuthentication CRs by users but I'm happy to make changes as needed. Do you have a path in mind?

@kedacore/keda-core-contributors @kedacore/keda-core-maintainers could you please chime in here? 🙇

@JorTurFer
Copy link
Member

What about passing the path as argument during startup? This can be useful to change it in the future and makes less relevant the current path that we decide because users can choose it for themselves.

we don't allow arbitrary creation of ClusterTriggerAuthentication

The point is that ClusterTriggerAuthentication uses the same API as TriggerAuthentication (and makese sense) , so you'd need to limit that API by RBAC too or the exposition vector is there.

Thoughts @kedacore/keda-core-contributors @kedacore/keda-core-maintainers?

@elsesiy
Copy link
Author

elsesiy commented Oct 25, 2025

What about passing the path as argument during startup? This can be useful to change it in the future and makes less relevant the current path that we decide because users can choose it for themselves.

I can add that in if that's the mechanism you feel comfortable with, let me know when consensus is reached with the rest of the maintainers and I'll add it.

we don't allow arbitrary creation of ClusterTriggerAuthentication

The point is that ClusterTriggerAuthentication uses the same API as TriggerAuthentication (and makese sense) , so you'd need to limit that API by RBAC too or the exposition vector is there.

https://github.com/kedacore/keda/pull/7082/files#diff-8c546d2eb95a297e897b699d6103324875de92d89c7e2519182c011c68317b57R247-R250 intentionally limits the filePath usage to the ClusterTriggerAuthentication CR i.e. a TriggerAuthentication creation with this feature would fail to create. I outlined the reasons for this in the PR description, hence any RBAC restricting ClusterTriggerAuthentication creation would suffice. Alternatively, one could implement a more fine-grained control using OPA or similar policy engines if needed.

Thoughts @kedacore/keda-core-contributors @kedacore/keda-core-maintainers?

Friendly nudge @kedacore/keda-core-contributors @kedacore/keda-core-maintainers 🙇

@JorTurFer
Copy link
Member

#7082 (files) intentionally limits the filePath usage to the ClusterTriggerAuthentication CR i.e. a TriggerAuthentication creation with this feature would fail to create. I outlined the reasons for this in the PR description, hence any RBAC restricting ClusterTriggerAuthentication creation would suffice. Alternatively, one could implement a more fine-grained control using OPA or similar policy engines if needed.

That's a good point, IMHO we should avoid shipping this only for clustertrigger, this is an auth method that can be leveraged using both apis

@elsesiy
Copy link
Author

elsesiy commented Oct 26, 2025

#7082 (files) intentionally limits the filePath usage to the ClusterTriggerAuthentication CR i.e. a TriggerAuthentication creation with this feature would fail to create. I outlined the reasons for this in the PR description, hence any RBAC restricting ClusterTriggerAuthentication creation would suffice. Alternatively, one could implement a more fine-grained control using OPA or similar policy engines if needed.

That's a good point, IMHO we should avoid shipping this only for clustertrigger, this is an auth method that can be leveraged using both apis

Apologies if this wasn't clear from the beginning but I don't think this functionality should be extended to the namespaced TriggerAuthentication i.e. it's not a bug, it's a feature that actually fits well with KEDA's architecture.

Here's a diagram to illustrate:

flowchart TD
    subgraph "User Namespace (team-a)"
        TA[TriggerAuthentication]
        FileUser[File: /creds/team-a.json]
        TA --> FileUser
    end

    subgraph "KEDA Namespace (keda)"
        OP[KEDA Operator Pod]
        Vol[emptyDir Volume]
        FileKeda[File: /keda/creds/shared.json]
        OP --> Vol --> FileKeda
    end

    FileUser -->|Cross-namespace mount?| No[NOT POSSIBLE]
    TA -.->|Sync to keda NS?| No
    OP -->|Reads file directly| FileKeda

    style No fill:#fee,stroke:#f66,stroke-width:2px
Loading

There's a few caveats that make using TriggerAuthentication cross-namespace impractical which is why it wasn't added:

  • Files are read from the operator pod’s filesystem — not from the app namespace.
  • No volume type supports direct cross-namespace file sharing.
  • Forcing namespaced support effectively means sync files into keda ns → defeats the purpose of avoiding Secret/ConfigMap.

ClusterTriggerAuthentication is the only practical target:

  • Cluster-scoped → readable everywhere
  • Mount once into operator pods → shared securely
  • RBAC restricts creation
  • No cross-namespace hacks

Can we please merge this as-is? Path whitelisting via startup arg can come in now (if agreed upon) or as a follow-up but I have been rebasing this PR for over a month and would like to be able to set timeline expectations with stakeholders internally. Thanks again!

Copy link
Member

@wozniakjan wozniakjan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point, but as currently implemented by the PR, this will allow anyone who can create ScaledObject to gain root access to the whole KEDA instance. That is not something we can merge because users expect a certain level of isolation and they depend on it. Telling KEDA users that if they want to upgrade, they need OPA with new rules is just not desirable.

But I think with a few tweaks this feature might be mergeable:

  1. KEDA will need a new command-line argument, which could be called filepath-auth-root-path. The filePath configured in ClusterTriggerAuthentication will be treated as a relative path under the filepath-auth-root-path that is ensured to always expand under the filepath-auth-root-path
  2. The API should not be in ScaledObject or ScaledJob but instead in ClusterTriggerAuthentication / TriggerAuthentication.

@keda-automation keda-automation requested a review from a team November 2, 2025 18:50
@elsesiy elsesiy marked this pull request as draft November 2, 2025 19:27
@elsesiy elsesiy requested a review from wozniakjan November 2, 2025 22:17
@elsesiy
Copy link
Author

elsesiy commented Nov 2, 2025

I see your point, but as currently implemented by the PR, this will allow anyone who can create ScaledObject to gain root access to the whole KEDA instance. That is not something we can merge because users expect a certain level of isolation and they depend on it. Telling KEDA users that if they want to upgrade, they need OPA with new rules is just not desirable.

But I think with a few tweaks this feature might be mergeable:

1. KEDA will need a new command-line argument, which could be called `filepath-auth-root-path`. The `filePath` configured in `ClusterTriggerAuthentication` will be treated as a relative path under the `filepath-auth-root-path` that is ensured to always expand under the `filepath-auth-root-path`

2. The API should not be in `ScaledObject` or `ScaledJob` but instead in `ClusterTriggerAuthentication` / `TriggerAuthentication`.

Thank you @wozniakjan, I incorporated your feedback. Let me know if it needs further adjustments. Could you please trigger the e2e tests?

@rickbrouwer
Copy link
Member

rickbrouwer commented Nov 3, 2025

/run-e2e file_based_auth_test
Update: You can check the progress here

Copy link
Member

@wozniakjan wozniakjan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks great!

e2e test related nit below, but maybe first wait for other @kedacore/keda-maintainers to chime in

}

// Update the deployment
_, err = kc.AppsV1().Deployments("keda").Update(context.Background(), operatorDeployment, metav1.UpdateOptions{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho this could part of the KEDA e2e test setup to avoid KEDA restarts during executing e2e tests, wdyt @kedacore/keda-maintainers ?

out, err := ExecuteCommandWithDirAndEnv("make deploy", "../..", envVars)
require.NoErrorf(t, err, "error deploying KEDA - %s", err)

- op: add
path: /spec/template/spec/containers/0/volumeMounts/1
value:
name: custom-cas
mountPath: /custom/ca
readOnly: true
- op: add
path: /spec/template/spec/volumes/1
value:
name: custom-cas
secret:
defaultMode: 420
secretName: custom-cas
optional: true

@snyk-io
Copy link

snyk-io bot commented Nov 16, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@elsesiy
Copy link
Author

elsesiy commented Nov 16, 2025

I think this looks great!

e2e test related nit below, but maybe first wait for other @kedacore/keda-maintainers to chime in

Thanks @wozniakjan, I just rebased again to resolve conflicts. Did you receive any feedback from @kedacore/keda-core-maintainers? Happy to make adjustments as needed, thanks!

@elsesiy elsesiy marked this pull request as ready for review November 16, 2025 02:14
…ication

We're using a custom secret solution that decrypts credentials via an init container and writes the resulting credentials to a shared emptyDir.
The current `AuthenticationRef` is limiting as it forces us to store the credential in a `Secret`/`ConfigMap` instead and we'd like to avoid doing that due to the fact that we cannot use these safely in our environment.

Happy to discuss viable alternatives but for now the implementation looks as follows:

• Add optional FilePath field to AuthenticationRef for reading auth params from mounted files
• Implement readAuthParamsFromFile helper to parse JSON credentials
• Modify resolveAuthRef to handle file-based auth when FilePath is specified
• Add comprehensive tests for new functionality
• Maintain backward compatibility with existing authentication methods

Fix kedacore#7083

Signed-off-by: Jonas-Taha El Sesiy <[email protected]>
Signed-off-by: Jonas-Taha El Sesiy <[email protected]>
@elsesiy
Copy link
Author

elsesiy commented Nov 24, 2025

I think this looks great!
e2e test related nit below, but maybe first wait for other @kedacore/keda-maintainers to chime in

Thanks @wozniakjan, I just rebased again to resolve conflicts. Did you receive any feedback from @kedacore/keda-core-maintainers? Happy to make adjustments as needed, thanks!

Friendly nudge @wozniakjan, thank you!

@wozniakjan
Copy link
Member

Friendly nudge @wozniakjan, thank you!

I don't have any new feedback, I think this approach should be safe and not bypass any RBAC or security guarantees from KEDA. I'd personally not patch the deployment of KEDA operator mid e2e tests (as mentioned here) and rather set the path when KEDA is deployed. But at least one more maintainer has to review this, otherwise it won't be merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for reading authentication ref from file

5 participants