Skip to content
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

Add example for securely connecting to Kafka (and a potential bug?) #19

Closed
andrijadukic-syntio opened this issue May 17, 2023 · 26 comments · Fixed by #20
Closed

Add example for securely connecting to Kafka (and a potential bug?) #19

andrijadukic-syntio opened this issue May 17, 2023 · 26 comments · Fixed by #20
Assignees

Comments

@andrijadukic-syntio
Copy link

Hi, an example such as the Kafka to IBM MQ one, but for showing usage of security mechanisms would be much appreciated, as any production use case certainly requires something like SASL_PLAIN to be used.

We've attempted the exact integration I linked to, but through the "base" kafka source kamelet. The route we tried is (skipping irrelevant parts):

...
- route:
    id: "kafka-to-mq"
    from:
      uri: "kamelet:kafka-source"
      parameters:
        bootstrapServers: "{{kafka.bootstrapServers}}"
        topic: "{{kafka.kafka-to-mq-topic}}"
        saslMechanism: PLAIN
        securityProtocol: SASL_SSL
        user: "$ConnectionString"
        password: "<PASSWORD>"
        deserializeHeaders: true
...

However, this doesn't work because, for some reason, authentication is failing. The stacktrace says nothing useful, as it seems like a standard error you'd get from wrong credentials being used.
One potential issue that's happening is incorrect parsing due to the '$' character at the start of the username, but basically the authentication process fails for some reason.

To make sure this is an issue with the kamelet, and not with our configuration, we've also tried out the Camel Core Kafka source from which this kamelet is based on, which then looks something like this:

...
- route:
    id: "kafka-to-mq"
    from:
      uri: "kafka:{{kafka.kafka-to-mq-topic}}"
      parameters:
        brokers: "{{kafka.bootstrapServers}}"
        groupId: "{{kafka.groupId}}"
        saslJaasConfig: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password={{kafka.password}};'
        saslMechanism: PLAIN
        securityProtocol: SASL_SSL
...

This works as expected, but then the issue is that any custom header we have in Kafka won't be passed over to IBM MQ (but this is a separate issue that I won't get into in this context).

One thing we noticed, which might be the reason behind what's wrong is the fact that, in the case of the kamelet kafka source, the "compiled" (from the resolved uri) saslJaasConfig has single quotes around the username and password parts, but in the kafka source (the one which is working properly, aside from an issue with the headers), double quotes are used instead.
We've also tried to add an additional '$' in the username, in order to escape it (so "$$ConnectionString"), and trying wrapping the username in double quotes, but nothing works.

Used versions:

  • camel-k: dependency=mvn:com.ibm.mq:com.ibm.mq.allclient:9.2.5.0
  • camel-k: dependency=mvn:org.apache.camel.kamelets:camel-kamelets-utils:3.20.1.1

Additional notes:
The "Kafka" cluster we're attempting to connect to is actually an Azure Event Hubs namespace, but with Kafka enabled. This isn't relevant since the Camel Core Kafka source works with Event Hubs (since Event Hubs fully supports the Kafka Consumer/Producer API), but I'm mentioning it just in case (and to also explain the strange username).

@oscerd oscerd self-assigned this May 17, 2023
@oscerd
Copy link
Contributor

oscerd commented May 17, 2023

You should use this: https://github.com/apache/camel-kamelets/blob/main/kamelets/kafka-source.kamelet.yaml

I'll update the example accordingly

@andrijadukic-syntio
Copy link
Author

andrijadukic-syntio commented May 17, 2023

You should use this: https://github.com/apache/camel-kamelets/blob/main/kamelets/kafka-source.kamelet.yaml

I'll update the example accordingly

Hi @oscerd , thanks for replying so quickly!
The first snippet (the route definition that we've tried using but fails to authenticate) is the one you linked (so not the kafka-not-secured-source, but the kafka-source kamelet), but unfortunately, it's not working:

...
- route:
    id: "kafka-to-mq"
    from:
      uri: "kamelet:kafka-source"
      parameters:
        bootstrapServers: "{{kafka.bootstrapServers}}"
        topic: "{{kafka.kafka-to-mq-topic}}"
        saslMechanism: PLAIN
        securityProtocol: SASL_SSL
        user: "$ConnectionString"
        password: "<PASSWORD>"
        deserializeHeaders: true
...

Like I said in the issue description: when inspecting the source of the kamelet, I'd say the only difference between the way the kamelet sets up the saslJaasConfig compared to the Camel core route that we've tried are the quotes (single quotes compared to double). It might be that Azure Event Hubs expects double quotes here; I'm not really sure why it matters what quote type is being used.

@oscerd
Copy link
Contributor

oscerd commented May 17, 2023

The user needs to be just the username nothing more. It's already included in sala jaas config

@oscerd
Copy link
Contributor

oscerd commented May 17, 2023

By the way I'll try to reproduce. It's weird to see $connection as username.. but if you externalize the properties it should work. I'll have a look

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

@davsclaus I suppose the only problem is in relation to the '$' sign.

@andrijadukic-syntio
Copy link
Author

andrijadukic-syntio commented May 18, 2023

The user needs to be just the username nothing more. It's already included in sala jaas config

Yes, the value of the user is exactly $ConnectionString. This can't be changed unfortunately, as it's dictated by Azure.

@andrijadukic-syntio
Copy link
Author

andrijadukic-syntio commented May 18, 2023

By the way I'll try to reproduce. It's weird to see $connection as username.. but if you externalize the properties it should work. I'll have a look

We've placed the user credentials in an application.properties file; for the example route I've hardcoded it into the route so that it's simpler to show what the value would be (since it will always be $ConnectionString).

@andrijadukic-syntio
Copy link
Author

andrijadukic-syntio commented May 18, 2023

@davsclaus I suppose the only problem is in relation to the '$' sign.

It might be, but I think it's not only that but a combination of that and the single quotes that are being used in the saslJaasConfig; the kafka source kamelet uses single quotes, while saslJaasConfig would normally have double quotes, like in this example by Confluent. We've also used double quotes for saslJaasConfig in the Camel core Kafka source/sink and that is working as expected (despite the same $ConnectionString username).

NOTE: Here's a stackoverflow post that I think is relevant here: https://stackoverflow.com/questions/64635940/camel-kafka-security-protocol-sasl-sasl-not-working

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

Are you running this locally through some docker compose stuff? I would to try exactly the same

@andrijadukic-syntio
Copy link
Author

Are you running this locally through some docker compose stuff?

the integration is running locally (not in docker, on Windows 10, with OpenJDK 19 installed), the "Kafka" cluster (Azure Event Hubs) is running on Azure, and IBM MQ is tested out both on the cloud and as a docker container (but MQ isn't relevant here since it fails long before getting to the MQ part).

@davsclaus
Copy link
Contributor

So is it this

saslJaasConfig: "org.apache.kafka.common.security.plain.PlainLoginModule required username='{{user}}' password='{{password}}';"

Its all YAML (you have to love it ... ;)

So here it uses lined single quotes for that jaas config string

If it needs to be changed to double quotes, then you need to change yaml to use single quoted wrapped, so something like:

saslJaasConfig: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="{{user}}" password="{{password}}";'

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

I think we could do that easily. So I'm going to do that on camel-kamelets

1 similar comment
@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

I think we could do that easily. So I'm going to do that on camel-kamelets

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

Creating an example using all the configuration for having a local kafka with SASL_SSL and PLAIN is a bit more complex.

@davsclaus
Copy link
Contributor

With the current kamelet, then in the debugger I see this value set on the KafkaConfiguration instance

org.apache.kafka.common.security.plain.PlainLoginModule required username='$ConnectionString' password='mypassword';

@davsclaus
Copy link
Contributor

So if Azure expects that username and password are using double quotes, then its likely a matter of changing this in the kamelet yaml file

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

Yes, so we need to modify it

@davsclaus
Copy link
Contributor

With modified kamelet

org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="mypassword";

@andrijadukic-syntio
Copy link
Author

So if Azure expects that username and password are using double quotes, then its likely a matter of changing this in the kamelet yaml file

@davsclaus I think you're exactly right.
However, one needs to consider if this is a breaking change in the case the parser might treat single and double quotes differently. For example, if something that previously didn't need explicit escaping now needs it, but I'm just a user here so no idea if this is relevant :).
This stackoverflow post (the answer I'll link to) mentions something about RAW saslJaasConfig and how it treats quotes differently: https://stackoverflow.com/a/66763779.

@davsclaus
Copy link
Contributor

This is how I changed the kamelet

        saslJaasConfig: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="{{user}}" password="{{password}}";'

Camel takes care of the RAW automatic for kamelets

@davsclaus
Copy link
Contributor

You can even copy the existing kamelet yaml file and name it - mykafka-source.kamelet.yaml and change the file to use double quotes as ^^^, and then save this file to disk.

And with jbang you can then tell it to look for kamelets in the current dir (or another folder)

camel run consumer.yaml --local-kamelet-dir=. --console

And in your route (consumer.yaml) you can then use mykafka-source as the name instead of the default name.

@oscerd
Copy link
Contributor

oscerd commented May 18, 2023

I'll update the Kamelet, I'll use it on event hubs and I'll create an example with that

@andrijadukic-syntio
Copy link
Author

I'll update the Kamelet, I'll use it on event hubs and I'll create an example with that

Thanks @oscerd and @davsclaus!
I'm really thankful for your support with this :)

@oscerd
Copy link
Contributor

oscerd commented May 19, 2023

Fixed in camel-kamelets through: apache/camel-kamelets#1476

Tested with Azure Event Hubs for Kafka

@oscerd
Copy link
Contributor

oscerd commented May 19, 2023

Going to work on a good example for this.

@oscerd
Copy link
Contributor

oscerd commented May 22, 2023

This should be fixed now.

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 a pull request may close this issue.

3 participants