OAuth keycloak authentication setup failing
bharat15-ml opened this issue · 9 comments
Hi,
I have followed this documentation to setup strimzi kafka-2.7.0 keycloak authentication- https://strimzi.io/blog/2019/10/25/kafka-authentication-using-oauth-2.0/
As the blog is divided into three sections-
- Setting up keycloak service.
- Start kafka cluster.
- Test Authentication through kafka producer and consumer clients.
Able to proceed with first two sections and properly configured keycloak and kafka cluser which is up and running fine.
Keycloak is setup with Enterprise certificate provider instead of self-signed one and its root.crt is used to create truststore "ca-trustore" and used in kafka deployment as mentioned in document, till here everything is working fine.
I have created three listeners while cluster creation- which need to specify in "apiVersion: kafka.strimzi.io/v1beta2".
I have created three listeners while cluster creation- providing below partial kafka-deployment.yaml file
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9093
type: internal
tls: true
- name: external
port: 30547
type: loadbalancer
tls: true
authentication:
type: oauth
validIssuerUri: https://153.88.30.40:30456/auth/realms/test
jwksEndpointUri: https://153.88.30.40:30456/auth/realms/test/protocol/openid-connect/certs
clientId: kafka-broker
clientSecret:
secretname: broker-oauth-secret
key: secret
userNameClaim: preferred_username
maxSecondsWithoutReauthentication: 3600
tlsTrustedCertificates:
- secretName: ca-truststore
certificate: rootCA.pem
disableTlsHostnameVerification: true
Now In the third section - Configuring application client pods - while exporting certificate and packaging into client truststore needs some clarifications-
kubectl get secret my-cluster-cluster-ca-cert -n kafka -o jsonpath='{.data.ca\.crt}' | base64 --decode > kafka.crt
# inspect the certificate
#openssl x509 -text -noout -in kafka.crt
extracted the password used in strimzi kafka cluster deployment--
kubectl get secret -n kafka my-cluster-cluster-ca-cert -o jsonpath='{.data.ca\.password}' | base64 -d > ca.password
then used this password values from ca.password file.
Now I have kafka.crt and also got password, as per documentation now will create kafka-client-truststore.p12 udsing kafka.crt and ca.crt.
but one question here, what is ca.crt file mentioned in documentation and how to get it?
I thought ca.crt is keycloak root certificate, So i have used rootCA.pem for my case, please let me know whether it is correct or wrong?
here while creating .p12 file ca.crt is keycloak root certificate which we created in step-1 or it is something else? i have replaced the ca.crt value with rootCA.pem file for my case.
export PASSWORD=********
keytool -keystore kafka-client-truststore.p12 -storetype PKCS12 -alias ca -storepass $PASSWORD -keypass $PASSWORD -import -file ca.crt <rootCA.pem> -noprompt
keytool -keystore kafka-client-truststore.p12 -storetype PKCS12 -alias kafka -storepass $PASSWORD -keypass $PASSWORD -import -file kafka.crt -noprompt
kubectl create secret generic kafka-client-truststore -n clients --from-file=kafka-client-truststore.p12
Now have created one more client kafka-producer in keycloak.
export OAUTH_CLIENT_ID=kafka-producer
export OAUTH_CLIENT_SECRET=*****************
then executed below commands, mentioned in documents-
## here used the same exported password of kafka cluster .
export PASSWORD=********
then used below deployment file and client pod (kafka-producer)came up and running.
apiVersion: v1
kind: Pod
metadata:
name: kafka-client-shell
spec:
containers:
- name: kafka-client-shell
image: strimzi/kafka:0.23.0-kafka-2.7.0
command: ["/bin/bash"]
args: [ "-c", 'for((i=0;;i+=1)); do echo "Up time: \$i min" && sleep 60; done' ]
env:
- name: CLASSPATH
value: /opt/kafka/libs/kafka-oauth-client-*:/opt/kafka/libs/kafka-oauth-common-*
- name: OAUTH_TOKEN_ENDPOINT_URI
value: https://153.88.30.40:30456/auth/realms/test/protocol/openid-connect/token
volumeMounts:
- name: truststore
mountPath: "/opt/kafka/certificates"
readOnly: true
volumes:
- name: truststore
secret:
secretName: kafka-client-truststore
then after logging to pod have executed below comands-
export KAFKA_OPTS=" \
-Djavax.net.ssl.trustStore=/opt/kafka/certificates/kafka-client-truststore.p12 \
-Djavax.net.ssl.trustStorePassword=$PASSWORD \
-Djavax.net.ssl.trustStoreType=PKCS12"
## here have passed LoadBlancer IP as bootstrap server of kafka cluster
bin/kafka-console-producer.sh --broker-list \
153.88.17.164:30547 --topic my-topic \
--producer-property 'security.protocol=SASL_SSL' \
--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'
getting following errors:
- ERROR java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider : SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
- Caused by : java.security.KeyStoreException: Problem accessing trust store
- Caused by : java.io.IOException: keystore password was incorrect
- filed to decrypt safe contents entry: javax.crypto.BadPaddingException: Given final block not properly padded.
- javax.security.auth.login.loginException: An internal error occured while retrieving from callback handler.
Please help me on this on resolving this issue?? Thanks!!
here while creating .p12 file ca.crt is keycloak root certificate which we created in step-1 or it is something else? i have replaced the ca.crt value with rootCA.pem file for my case.
It is instructing you to use the Cluster CA of the Kafka cluster. So I guess this is not your Keycloak certificate but the KAfka cluster certificate.
getting following errors:
Sharing the full log is always better than sharing some extract. But it suggests that your keystore / truststore is not in the right format or the password for it is wrong.
Thanks scholzj, I thought below command is used for kafka cluster CA..
kubectl get secret my-cluster-cluster-ca-cert -n kafka -o jsonpath='{.data.ca.crt}' | base64 --decode > kafka.crt
Please let me know what kafka.crt and ca.crt as per documentation??
It is the Kafka Cluster CA certificate. It is a secret created by Strimzi, you just extract the certificate.
Thanks!! So to create kafka-client-truststore.p12 required two files one is kafka.crt and another is ca.crt.
I have extracted kafka.crt file with command - kubectl get secret my-cluster-cluster-ca-cert -n kafka -o jsonpath='{.data.ca.crt}' | base64 --decode > kafka.crt
Please let me know what command to use to extract ca.crt file and have used the same extracted password while creatiing .p12 files, I guess this is also wrong.
Please provide correct commands to use for bellows -
export PASSWORD=********
keytool -keystore kafka-client-truststore.p12 -storetype PKCS12 -alias ca -storepass $PASSWORD -keypass $PASSWORD -import -file ca.crt <rootCA.pem> -noprompt
keytool -keystore kafka-client-truststore.p12 -storetype PKCS12 -alias kafka -storepass $PASSWORD -keypass $PASSWORD -import -file kafka.crt -noprompt
kubectl create secret generic kafka-client-truststore -n clients --from-file=kafka-client-truststore.p12
extracted the password used in strimzi kafka cluster deployment--
kubectl get secret -n kafka my-cluster-cluster-ca-cert -o jsonpath='{.data.ca\.password}' | base64 -d > ca.password
You don't need this password. It is generated by Strimzi operator to protect the content of the keystores and truststores used by brokers for the server-side of TLS connectivity.
The kafka.crt file that you exported contains the public certificate only and is not protected by any password.
Now I have kafka.crt and also got password, as per documentation now will create kafka-client-truststore.p12 udsing kafka.crt and ca.crt.
You need kafka.crt and keycloak certificate (looks like rootCA.pem in your case) to create your kafka-client-trustore.
I thought ca.crt is keycloak root certificate, So i have used rootCA.pem for my case, please let me know whether it is correct or wrong?
Assuming that your Keycloak certificate is signed by rootCA then that's the correct certificate.
**here while creating .p12 file ca.crt is keycloak root certificate which we created in step-1 or it is something else?
Yes in the blog post we create a ca.crt for keycloak.
export PASSWORD=********
This password is something you set yourself.
keytool -keystore kafka-client-truststore.p12 -storetype PKCS12 -alias ca -storepass $PASSWORD -keypass $PASSWORD -import -file ca.crt <rootCA.pem> -noprompt
If you say -file ca.crt
it means that the file called ca.crt
must exist. In your case it should simply be -file rootCA.pem
.
## here used the same exported password of kafka cluster . export PASSWORD=********
The exported password is irrelevant. You need a password for your kafka-client-truststore.p12
which you set when creating the .p12 file.
then used below deployment file and client pod (kafka-producer)came up and running.
apiVersion: v1
kind: Pod
metadata:
name: kafka-client-shell
spec:
containers:
- name: kafka-client-shell
image: strimzi/kafka:0.23.0-kafka-2.7.0
command: ["/bin/bash"]
args: [ "-c", 'for((i=0;;i+=1)); do echo "Up time: $i min" && sleep 60; done' ]
env:
- name: CLASSPATH
value: /opt/kafka/libs/kafka-oauth-client-:/opt/kafka/libs/kafka-oauth-common-
This is not enough jars. You also need dependencies / helper libraries. It's easiest to just include /opt/kafka/libs/*
.
export KAFKA_OPTS="
-Djavax.net.ssl.trustStore=/opt/kafka/certificates/kafka-client-truststore.p12
-Djavax.net.ssl.trustStorePassword=$PASSWORD
-Djavax.net.ssl.trustStoreType=PKCS12"
You refer to $PASSWORD in a new shell. Have you set it to some value first?
getting following errors:
- ERROR java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider : SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
- Caused by : java.security.KeyStoreException: Problem accessing trust store
- Caused by : java.io.IOException: keystore password was incorrect
- filed to decrypt safe contents entry: javax.crypto.BadPaddingException: Given final block not properly padded.
- javax.security.auth.login.loginException: An internal error occured while retrieving from callback handler.
It sounds like the secret you used to create the kafka-client-truststore is not the same as the $PASSWORD you provided. Maybe it's just an issue of the shell ENV. You exec
into your pod and refer to $PASSWORD env variable, but did you define PASSWORD env var in your exec shell?
Thanks @mstruk!! Able to deploy everything fine now.
Now when I am able to connect to kafka cluster and request forwarded to keycloak.
getting Error for Keycloak loadbalancer IP i.e. 153.88.30.40 -
**"ERROR No subject alternative names matching IP address 153.88.30.40 found (org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule)"**
It should be related to SAN /etc/hosts DNS Entry? Any input on this.
Keycloak / RH-SSO is typically set up to be widely accessible across networks so it's set up with a fully qualified domain name in the certificate.
The ususal approach is to have certificate present as something like sso.example.org
and in all urls to Keycloak you then use https://sso.example.org/auth/realms...
For your setup you can use the IP but then the IP address needs to be contained in the certificate that Keycloak presents with, which means you need to control how the certificate is created when issued.
So, either make sure the certificate contains the Keycloak IP, or find out which hostname / FQDN is declared in the certificate and use that. But you have to access your Keycloak using the same hostname / IP and port from all the clients (Kafka brokers and Kafka clients).
Thanks @mstruk, After making all the correction, one time it was tested and able to produce and consume data from kafka topic. Now again when I am retesting getting below errors:-
Executed below commands on kafka producer client-
bin/kafka-console-producer.sh --broker-list 153.88.17.164:30547 --topic my-topic \
--producer-property 'security.protocol=SASL_SSL' \
--producer-property 'sasl.mechanism=OAUTHBEARER' \
--producer-property 'sasl.jaas.config=org.aache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;' \
--producer-property 'sasl.login.callback.handler.class=io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler'
getting below errors:
org.apache.kafka.common.KafkaException: Failed to construct kafka producer
at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:441)
at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:302)
at kafka.tools.ConsoleProducer$.main(ConsoleProducer.scala:45)
at kafka.tools.ConsoleProducer.main(ConsoleProducer.scala)
Caused by: org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: No LoginModule found for org.aache.kafka.common.security.oauthbearer.OAuthBearerLoginModule
at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:172)
at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:157)
at org.apache.kafka.common.network.ChannelBuilders.clientChannelBuilder(ChannelBuilders.java:73)
at org.apache.kafka.clients.ClientUtils.createChannelBuilder(ClientUtils.java:105)
at org.apache.kafka.clients.producer.KafkaProducer.newSender(KafkaProducer.java:449)
at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:430)
... 3 more
Caused by: javax.security.auth.login.LoginException: No LoginModule found for
org.aache.kafka.common.security.oauthbearer.OAuthBearerLoginModule
at java.base/javax.security.auth.login.LoginContext.invoke(LoginContext.java:710)
at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:665)
at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:663)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:663)
at java.base/javax.security.auth.login.LoginContext.login(LoginContext.java:574)
oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin.login(ExpiringCredentialRefreshingLogin.java:204)
oauthbearer.internals.OAuthBearerRefreshingLogin.login(OAuthBearerRefreshingLogin.java:150)
at org.apache.kafka.common.security.authenticator.LoginManager.<init>(LoginManager.java:62)
at org.apache.kafka.common.security.authenticator.LoginManager.acquireLoginManager(LoginManager.java:105)
at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:158)
... 8 more
Please suggest something on probable cause of this error and how to resolve?
Thanks!! Able to resolve issues, it's working fine,closing this thread.