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

Support connecting to Heroku Kafka #8

Closed
sdball opened this issue Dec 22, 2016 · 5 comments
Closed

Support connecting to Heroku Kafka #8

sdball opened this issue Dec 22, 2016 · 5 comments
Assignees

Comments

@sdball
Copy link
Contributor

sdball commented Dec 22, 2016

Make changes to Kaffe that will allow declaring connections to an SSL Kafka (i.e. Heroku Kafka)

Blocked by spreedly/dev-services#36

@sdball sdball self-assigned this Dec 22, 2016
@sdball
Copy link
Contributor Author

sdball commented Dec 29, 2016

Now that we've got an ssl-test topic on Heroku I'm digging into how to setup brod to talk to SSL Kafka. (And also looking around the landscape of Elixir Kafka clients.)

(time passes)

Ok, brod and the leading Elixir Kafka client (kafka_ex) have the same "problem". They expect the SSL certs to be actual files:

{:cacertfile, "cacert.pem"},
{:certfile, "cert.pem"},
{:keyfile, "cert_key.pem"},

I'm not sure how that will match up with having the certs as ENV values. I hope there's a way to hand over the cert values directly instead of handing over filenames with the cert values.

For comparison here's Ruby-Kafka: https://github.com/spreedly/ruby-kafka/blob/master/heroku-kafka-consumer.rb#L48-L61

brokers = ENV.fetch("KAFKA_URL").split(",")
ssl_ca_cert = ENV.fetch("KAFKA_TRUSTED_CERT")
ssl_client_cert = ENV.fetch("KAFKA_CLIENT_CERT")
ssl_client_cert_key = ENV.fetch("KAFKA_CLIENT_CERT_KEY")

kafka = Kafka.new(
  seed_brokers: brokers,
  client_id: client_id,
  socket_timeout: 120,
  logger: logger,
  ssl_ca_cert: ssl_ca_cert,
  ssl_client_cert: ssl_client_cert,
  ssl_client_cert_key: ssl_client_cert_key,
)

@sdball
Copy link
Contributor Author

sdball commented Dec 29, 2016

And here's how to connect to Heroku Kafka from kafkacat: for posterity

$ kafkacat \
  -t ssl-test \
  -o beginning \
  -e \
  -b $(echo $KAFKA_URL | sed -e 's/kafka+ssl:\/\///g') \
  -X security.protocol=ssl \
  -X ssl.key.location=<(echo $KAFKA_CLIENT_CERT_KEY) \
  -X ssl.certificate.location=<(echo $KAFKA_CLIENT_CERT) \
  -X ssl.ca.location=<(echo $KAFKA_TRUSTED_CERT)

@sdball
Copy link
Contributor Author

sdball commented Dec 29, 2016

Yeah it's pretty clear that brod and kafka_ex are both using the Erlang SSL module:

http://erlang.org/doc/man/ssl.html

Happily it looks like that module can accept values and not just files. I'll try setting them for brod. First with the certs as files like it wants and next with the underlying Erlang SSL module options for values.

@sdball
Copy link
Contributor Author

sdball commented Dec 29, 2016

Woo! After much experimentation I finally found the magical combination of extracted pieces and SSL incantations to allow us to configure the Erlang SSL module used by brod to talk to the Heroku Kafka!

The magics:

def consumer_config do
  [
    auto_start_producers: false,
    allow_topic_auto_creation: false,
    ssl: [
      cert: client_cert,
      key: client_cert_key,
    ]
  ]
end

defp client_cert do
  {_type, der, _} = "KAFKA_CLIENT_CERT"
  |> System.get_env
  |> :public_key.pem_decode
  |> List.first
  der
end

defp client_cert_key do
  {type, der, _} = "KAFKA_CLIENT_CERT_KEY"
  |> System.get_env
  |> :public_key.pem_decode
  |> List.first
  {type, der}
end

This is all hacked together but working!

Next is to nicely expose the SSL configuration pieces. I have no problem with Kaffe assuming Heroku Kafka SSL setup since it is our client after all.

Perhaps a config like…

config :kaffe,
  consumer: [
    endpoints: [kafka: 9092],
    ssl: [
      client_cert: System.get_env("KAFKA_CLIENT_CERT"),
      client_cert_key: System.get_env("KAFKA_CLIENT_CERT_KEY")
    ],
    topics: ["whitelist"],
    offset_commit_interval_seconds: 5, # default
    begin_offset: :earliest # default :latest
  ],
  producer: [
    endpoints: [kafka: 9092],
    ssl: [
      client_cert: System.get_env("KAFKA_CLIENT_CERT"),
      client_cert_key: System.get_env("KAFKA_CLIENT_CERT_KEY")
    ],
    topics: ["decorated-whitelist"],
    partition_strategy: :round_robin # default
  ]

Using default values…

config :kaffe,
  consumer: [
    endpoints: [kafka: 9092], # yeah, gotta pull these from KAFKA_URL
    ssl: [
      client_cert: System.get_env("KAFKA_CLIENT_CERT"),
      client_cert_key: System.get_env("KAFKA_CLIENT_CERT_KEY")
    ],
    topics: ["whitelist"]
  ],
  producer: [
    endpoints: [kafka: 9092], # yeah, gotta pull these from KAFKA_URL
    ssl: [
      client_cert: System.get_env("KAFKA_CLIENT_CERT"),
      client_cert_key: System.get_env("KAFKA_CLIENT_CERT_KEY")
    ],
    topics: ["decorated-whitelist"]
  ]

@sdball
Copy link
Contributor Author

sdball commented Dec 29, 2016

What we get from KAFKA_URL:

iex(1)> "KAFKA_URL" |> System.get_env
"kafka+ssl://34.195.140.72:9096,kafka+ssl://34.195.135.147:9096,kafka+ssl://34.195.140.195:9096"

What brod wants for its endpoints configuration:

[{:"34.195.140.72", 9096}, {:"34.195.135.147", 9096}, {:"34.195.140.195", 9096}]

A straight up data transformation problem?! Yesssss

@sdball sdball changed the title Support connecting to Kafka via SSL Support connecting to Heroku Kafka Dec 30, 2016
@sdball sdball added the review label Dec 30, 2016
sdball added a commit that referenced this issue Jan 2, 2017
This is a BIG change to Kaffe! We now support connecting to Heroku Kafka
(and any other Kafka setup that uses the same ENV variables for
endpoints and SSL).

Making this change in a reasonable way required moving all configuration
into the actual application configuration. Before this Kaffe was in a
weird place where some things were configured in the application
configuration and some things were expected to be supplied when starting
up the consumer/producer workers.

No more! Now all configuration is in the application configuration and
the consumer/producer workers pull everything they need from there.

Fixes #8
@sdball sdball closed this as completed in #10 Jan 5, 2017
@ghost ghost removed the review label Jan 5, 2017
sdball added a commit that referenced this issue Jan 5, 2017
This is a BIG change to Kaffe! We now support connecting to Heroku Kafka
(and any other Kafka setup that uses the same ENV variables for
endpoints and SSL).

Making this change in a reasonable way required moving all configuration
into the actual application configuration. Before this Kaffe was in a
weird place where some things were configured in the application
configuration and some things were expected to be supplied when starting
up the consumer/producer workers.

No more! Now all configuration is in the application configuration and
the consumer/producer workers pull everything they need from there.

Fixes #8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant