-
Notifications
You must be signed in to change notification settings - Fork 93
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
Support disabling the Accept header when requesting Json Web Key Sets. #201
Conversation
Signed-off-by: Hunter Madison <[email protected]>
When attemping to use Kubernetes' api-server as the source of JWK keys for JWT validation, it will only process requests which either do not have the "Accept" header set or requests which have the header set to "application/jwk-set+json". Signed-off-by: Hunter Madison <[email protected]>
Signed-off-by: Hunter Madison <[email protected]>
e217d8b
to
ce72e6b
Compare
Signed-off-by: Hunter Madison <[email protected]>
examples/kubernetes/README.md
Outdated
* `kafka-oauth-single-authz-service-accounts.yaml` | ||
|
||
A single node Kafka cluster using [service account tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens) for authorization and the `simple` authorizer. | ||
It requires that the `kube-root-ca.crt` be copied from its ConfigMap to a Secret: | ||
|
||
kubectl get configmap/kube-root-ca.crt -o=json | jq -r '.data."ca.crt"' | kubectl create secret generic kube-root-ca --from-file=ca.crt=/dev/stdin |
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.
Is this really something what works with every single Kubernetes cluster based on Service accounts only? Or does it really on OpenID provider?
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.
The Kubernetes api-server supports OpenID Connect to validate the credentials which (since version 1.22) get projected into a pod based off of it's service account. You don't need anything outside of a Kubernetes cluster to make use of this authentication.
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.
Ok, interesting. I will have to try that.
subjects: | ||
- apiGroup: rbac.authorization.k8s.io | ||
kind: User | ||
name: "system:anonymous" |
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 should have the service account of the Kafka brokers I guess and not anonymous?
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.
Since strimizi-kafka-oauth
isn't setting its Bearer token to the one projected into the container, you need to allow system:anonymous
to access the endpoints needed to retrieve the OpenID Connect settings and the Json Web Key Sets.
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.
If that is not enabled for everyone by default, it means this is likely a security risk? Should it really be used here? Shouldn't you instead use the broker's service account?
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 guess the same applies to system:serviceaccount:default:default
-> maybe you should use some better example SA then the default one.
I'm also not sure I follow the relation ship of this example to the PR here. How do they relate? You do not seem to use any new flag in the example to disable the Accept
header. So while the Kubernetes example is interesting, I do not follow the relationship here.
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'm setting the value of oauth.include.accept.header
to false
via spec.kafka.jvmOptions.javaSystemProperties
on line 63.
From my perspective, the ODIC and JWKS endpdoints in a "normal" application are exposed over the public internet. If someone is in a position to make a web request from inside of the kubernetes cluster to these endpoints, they are also going to be able to access the token for the service account and make those requests with authentication. If we want to use the brokers service account, then we should back this example out of this pull request and I'll open a new one which includes a dedicated authenticator for Kubernetes service accounts.
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.
We'll need to add the includeAcceptHeader
config option to oauth
listener authentication and keycloak
authorization when we integrate the next OAuth release into the Strimzi Operator (another PR). We can then improve the example Kafka CR.
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'm setting the value of oauth.include.accept.header to false via spec.kafka.jvmOptions.javaSystemProperties on line 63.
I missed that part. As mentioned by Marko, this will need to be added tot he options after the next OAuth release. Until then it is a bit misleading since it will not work with OAuth 0.13.
From my perspective, the ODIC and JWKS endpdoints in a "normal" application are exposed over the public internet. If someone is in a position to make a web request from inside of the kubernetes cluster to these endpoints, they are also going to be able to access the token for the service account and make those requests with authentication. If we want to use the brokers service account, then we should back this example out of this pull request and I'll open a new one which includes a dedicated authenticator for Kubernetes service accounts.
It seems that from Kubernetes perspective it is not something what they thing should be public. Also, thing like this will discourage users from using it as it does not look secure. If this works on any Kubernetes cluster, I think this would be a great usecase. But I think we need to work out the details to make sure it uses the service account and does not connect over as anonymous. So my vote would be to move this to a separate PR and do this through the broker service account.
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.
That's fine by me. I'll back this change out and start on a dedicated Kubernetes service account configuration which supports using the pod's service account token to authenticate with the api server.
oauth-server/src/main/java/io/strimzi/kafka/oauth/server/ServerConfig.java
Outdated
Show resolved
Hide resolved
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.
Thanks for the PR. As I mentioned in another comment I think this new option constant should really live in Config.java
, and functionally be used not only in JWTSignatureValidator.java
but also in OAuthIntrospectionValidator.java
, and in KeycloakRBACAuthorizer.java
and JaasClientOauthLoginCallbackHandler
.
In KeycloakRBACAuthorizer.java
the analogous option should also be introduced strimzi.authorization.include.accept.header
that falls back to oauth.include.accept.header
the same way some other options in there do.
5c1b7fe
to
2c41701
Compare
@mstruk I've made the requested changes. Do you have any idea why the s390x portion of the build is currently breaking? |
d9e321f
to
adfbf8e
Compare
Signed-off-by: Hunter Madison <[email protected]>
adfbf8e
to
c55abba
Compare
The issue is definitely unrelated to this PR. travis-ci.com has had some issues with JDK 11 on |
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.
Some minor issues, otherwise it looks good to me.
examples/kubernetes/kafka-oauth-single-authz-service-accounts.yaml
Outdated
Show resolved
Hide resolved
...-keycloak-authorizer/src/main/java/io/strimzi/kafka/oauth/server/authorizer/AuthzConfig.java
Outdated
Show resolved
Hide resolved
...-client/src/main/java/io/strimzi/kafka/oauth/client/JaasClientOauthLoginCallbackHandler.java
Show resolved
Hide resolved
Signed-off-by: Hunter Madison <[email protected]>
metadata: | ||
name: oidc-reader-binding | ||
annotations: | ||
kubernetes.io/description: | |
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.
Still not ok. It's this line (19) that should be indented in order to be a child of annotations
. Currently it is a child of metadata
which is incorrect.
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.
Based off of @scholzj's feedback, I've backed this example out and will open up a subsequent PR with a better "out of the box" experience around service account usage.
subjects: | ||
- apiGroup: rbac.authorization.k8s.io | ||
kind: User | ||
name: "system:anonymous" |
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.
We'll need to add the includeAcceptHeader
config option to oauth
listener authentication and keycloak
authorization when we integrate the next OAuth release into the Strimzi Operator (another PR). We can then improve the example Kafka CR.
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.
One nit. LGTM otherwise.
Signed-off-by: Hunter Madison <[email protected]>
33e8980
to
b7f488d
Compare
Signed-off-by: Marko Strukelj <[email protected]>
I added some tests to the testsuite and fixed some additional issues I found while writing tests: hmadison#1 |
Added configuration tests to the testsuite + fixed some issues
@hmadison Thank you very much for the contribution! |
For certain servers which provide Json Web Key Sets, such as the Kubernetes API Server, if the
Accept
header sent by the client is present it is expected to beapplication/jwk-set+json
. Based off of the discussion in the Strimzi slack channel, I've added an option which allows for users to skip sending theAccept
header when making the JWKS request.I've also updated the test documentation to cover how to use MiniKube and Helm to simplify the testing process and included an example of how to use this feature to authenticate into a Kafka cluster with a Service Account's token. To validate this locally, you can apply
kafka-oauth-single-authz-service-accounts.yaml
to a Kubernetes cluster with the operator installed and using a version ofstrimzi-kafka-oauth
installed then:kubectl create token default
.kubectl exec -it pod/test-cluster-kafka-0 -- /bin/bash
.env OAUTH_ACCESS_TOKEN="<token>" bin/kafka-console-producer.sh --broker-list test-cluster-kafka-bootstrap.default:9092 --topic my-topic --producer-property 'security.protocol=SASL_PLAINTEXT' --producer-property 'sasl.mechanism=OAUTHBEARER' --producer-property 'sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;' --producer-property 'sasl.login.callback.handler.class=io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler'