camunda / camunda

Process Orchestration Framework
https://camunda.com/platform/
3.13k stars 569 forks source link

Support configuring SSL connection of the Elasticsearch exporter #9839

Open npepinpe opened 2 years ago

npepinpe commented 2 years ago

Is your feature request related to a problem? Please describe.

The Zeebe broker does not allow configuring the SSL connection between the Elasticsearch exporter and Elasticsearch itself. While this works generally when using certificates signed by root CAs, this prevents users from using custom or self-signed certificates.

Describe the solution you'd like

The Zeebe Elasticsearch exporter configuration supports the same SSL parameters as Operate and Tasklist does. Essentially:

Name Description Default value
args.ssl.certificatePath Path to certificate used by Elasticsearch -
args.ssl.selfSigned Certificate was self-signed false
args.ssl.verifyHostname Should the hostname be validated false

Describe alternatives you've considered

It's possible to create a custom trust-store including the custom certificate and start the application with it. When deploying in Kubernetes, this is much more cumbersome, however, as you need to mount the required file and fiddle with JAVA_OPTS.

It's also possible to install your custom CA into the trusted certificates. This is not only a security issue but also tedious, and may require users to either use an additional init container, or to customize the base image.

Additional context

npepinpe commented 2 years ago

Here's the sample test I used to confirm self-signed certificates are not supported:

/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Zeebe Community License 1.1. You may not use this file
 * except in compliance with the Zeebe Community License 1.1.
 */
package io.camunda.zeebe.exporter;

import static org.assertj.core.api.Assertions.assertThatNoException;

import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.Objects;
import java.util.UUID;
import org.agrona.LangUtil;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.MountableFile;

@Testcontainers
final class SecureElasticsearchIT {
  private static final SelfSignedCertificate CERTIFICATE =
      Objects.requireNonNull(newCertificate(), "must specify a certificate");

  @Container
  private static final ElasticsearchContainer CONTAINER =
      TestSupport.createDefaultContainer()
          .withEnv("xpack.license.self_generated.type", "trial")
          .withEnv("xpack.security.enabled", "true")
          .withEnv("xpack.security.http.ssl.enabled", "true")
          .withEnv("xpack.security.http.ssl.certificate", "cert.pem")
          .withEnv("xpack.security.http.ssl.key", "key.pem")
          .withEnv("xpack.security.authc.anonymous.username", "anon")
          .withEnv("xpack.security.authc.anonymous.roles", "superuser")
          .withEnv("xpack.security.authc.anonymous.authz_exception", "true")
          .withCopyFileToContainer(
              MountableFile.forHostPath(CERTIFICATE.certificate().toPath(), 0777),
              "/usr/share/elasticsearch/config/cert.pem")
          .withCopyFileToContainer(
              MountableFile.forHostPath(CERTIFICATE.privateKey().toPath(), 0777),
              "/usr/share/elasticsearch/config/key.pem");

  @Test
  void shouldConnectWithSelfSignedCertificate() throws IOException {
    // when
    // force recreating the client
    final var config = new ElasticsearchExporterConfiguration();
    config.index.prefix = UUID.randomUUID() + "-test-record";
    config.url = "https://" + CONTAINER.getHttpHostAddress();

    // when
    try (final var client = new ElasticsearchClient(config)) {
      // then
      assertThatNoException().isThrownBy(client::putComponentTemplate);
    }
  }

  private static SelfSignedCertificate newCertificate() {
    try {
      return new SelfSignedCertificate();
    } catch (final CertificateException e) {
      LangUtil.rethrowUnchecked(e);
      return null;
    }
  }
}
menski commented 1 year ago

@npepinpe do you have a rough estimate for this issue based on this scale?

npepinpe commented 1 year ago

Let's say S.

vctrmn commented 1 year ago

Hello team,

Any news on this feature ? The described alternative works fine. I have created a related enhancement issue on Camunda Helm Chart repo to better handle keystore or certificate. Issue : https://github.com/camunda/camunda-platform-helm/issues/446

By the way, I also tried to implement this for Operate, but it fails. I tried by :

korthout commented 1 year ago

Discussed during triage:

shivasdp commented 2 months ago

Any workaround/suggestion for using the self-signed certificates with elasticsearch exporter?