-
Notifications
You must be signed in to change notification settings - Fork 32
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
feat: configurable API Key K8s secret key name #488
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for taking the time to address this issue, @KevFan!
I've left a few comments. Nothing that invalidates the change, but mainly to double check on the design we want for the feature and some implementation detail.
One general wondering I have though is whether we want to allow this change into v1beta2 or v1beta3 (addressing #480 first). Although the keySelectors
field not being backwards compatible with v1beta1 is not much of a concern (since #483 was merged), it feels like breaking a promise (internal agreement maybe?) that all changes to the API now would go into v1beta3.
Do you have an opinion on this, @alexsnaps?
So... @guicassolato, you'd bump the version with this change, is that it? I'm growing concerned I won't get the CEL stuff done by the EOW tho... So the question becomes more of when would |
@@ -134,7 +144,6 @@ func (a *APIKey) RevokeK8sSecretBasedIdentity(ctx context.Context, deleted k8s_t | |||
if secret.GetNamespace() == deleted.Namespace && secret.GetName() == deleted.Name { | |||
delete(a.secrets, key) | |||
log.FromContext(ctx).WithName("apikey").V(1).Info("api key deleted") | |||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should no longer return early since the change now allows for the possibility of multiple keys pointing to the same secret
api/v1beta3/auth_config_types.go
Outdated
// Authorino will attempt to authenticate using any matching key, including "api-key". | ||
// If no match is found, the Kubernetes secret is not considered a valid Authorino API Key secret and is ignored. | ||
// +optional | ||
KeySelectors []string `json:"keySelectors,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to define the kubebuilder default here also? 🤔
// +kubebuilder:default:={"api_key"}
Do we want to set a maximum?
+kubebuilder:validation:MaxItems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good question. I guess the only reason I can think of to do that is to help users not to shoot themselves in the foot when tempted to add hundreds, thousands of valid keys as a workaround to store multiple valid API keys inside of a same Kubernetes secret.
If we ignore performance (and let users figure that out by themselves), arguably storing multiple valid identities in the same Secret may not be necessarily such a bad idea-even though it isn't how this feature was originally designed to work and users would lose capabilities in the process (e.g. storing one identity's metadata in the secret's metadata).
Say we do want to let users store multiple API keys in a Secret (now that it will be technically possible anyway). Probably, having to come up with a different key name for each identity would be a PITA. I can see requests of extending the key selector to support things like regexes, globs, etc coming up.
So I wonder, should we embrace that we make the key selector to be a CEL expression?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is a good point, moving to CEL expression would make a more consistent experience while giving users more capabilities to how they want to select the secret keys 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've a working implementation based on how it's currently done for the AuthJSON and implementing
authorino/pkg/expressions/types.go
Lines 3 to 5 in b2bde91
type Value interface { | |
ResolveFor(jsonData string) (interface{}, error) | |
} |
Interested in @alexsnaps opinions on this
cc84bee
to
faec0db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verification steps work.
nit: we may want to fix perhaps only where it says:
- Curling with api_key_2 should succeed
curl -H 'Authorization: APIKEY key_2' http://talker-api.127.0.0.1.nip.io:8000/hello -v # HTTP/1.1 401 Unauthorized
Last line (commented) should probably read # HTTP/1.1 200 OK
.
Let's just make sure we're all in agreement regarding https://github.com/Kuadrant/authorino/pull/488/files#r1958525812 before merging this (or making the proper adjustments.)
Nice job, @KevFan!
I wondered if binding the |
assert.Equal(t, apiKey.LabelSelectors.String(), "planet=coruscant") | ||
assert.Equal(t, apiKey.Namespace, "ns1") | ||
assert.Equal(t, len(apiKey.secrets), 1) | ||
_, exists := apiKey.secrets["ObiWanKenobiLightSaber"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Signed-off-by: KevFan <[email protected]>
Thanks @alexsnaps for raising this. Yes, I believe its always a unique set of keys also. Agreed, I'm in favour of possibly exposing more of the secret as needed in any future work 👍 |
Let me start by saying that API key authentication, without proper guardrails set by a cluster admin beforehand, can easily be the least secure feature of Authorino. On one hand, giving access to the entire secret by binding to the root of the object instead of Only this change could make label selectors obsolete (if it wasn't for the optimisation aspect involved when querying the API server of course). On the other hand, such change marginally increases an existing known vulnerability of unsafe Authorino deployments, that allow malicious users to elevate privileges and get access to Kubernetes secrets otherwise out of reach. While checking the listed secrets for valid API keys stored in it, this line could be exploited to leak sensitive data to the logs, such as other values stored in the secret that are unrelated to API key authn. Combined with I say "marginally", however, because arguably such vulnerability already exists. It exists in 2 levels. First, because any secret deemed to contain a valid API key secret already gets a root binding at The second level is enabled by this PR. One who can guess the value of any key stored in a secret-it doesn't have to be necessarily the value of the |
Signed-off-by: KevFan <[email protected]>
Description
Closes: #360
Adds Key Selectors support for API Key k8s secret
Verification
api_key
key (default key as not key selector was defined) should succeedapi_key_2
andkey 3
key should fail with401 Unauthorized
api_key_2
api_key_2
should succeedapi_key
andkey 3
key should fail with401 Unauthorized
api_key*
api_key
andapi_key_2
should succeedkey_3
key should fail with401 Unauthorized
curl -H 'Authorization: APIKEY key_3' http://talker-api.127.0.0.1.nip.io:8000/hello -v
api_key_2
kubectl patch secret api-key-1 -p '{"data":{"api_key_2": null}}'
api_key_2
should failapi_key
should still succeedapi_key_2
from second secret should succeedapi_key
,api_key_2
andapi_key_3
should failapi_key_2
andapi_key_3
should succeed