Camunda 8 self managed Multitenancy

Hi @savi003 - I don’t quite know what is causing that, as it’s not an error I’m seeing on my system. I’m going to do some additional testing with that docker-compose configuration and see what I can find!

@jgeek1 - that is correct. Product licensing can be a confusing topic, so just to add a little bit more information: Multi-tenancy is available under the Camunda Self-Managed Free Edition license, but only for non-production use. Any production use of Camunda Self-Managed requires an enterprise license agreement. Zeebe is available under a much more permissive license, but Zeebe alone doesn’t understand multi-tenancy - multi-tenancy is a feature that is enabled by the entire stack, not just the process engine.

Hope that makes sense, but definitely let me know if there’s still confusion (might be good to start a new topic if there are additional questions!). We also have a page dedicated to our licensing: Licenses | Camunda 8 Docs

1 Like

@nathan.loding please let me know if you find, what’s the issue.

@savi003 - well, I don’t know the cause of those errors yet, but they don’t appear to be an issue. I will continue investigating those, but I think you need to make two small changes to your docker-compose.yml to get things running:

services:

  zeebe:
    # ...
    environment:
      # add identity.baseURL property (see note here: https://docs.camunda.io/docs/self-managed/zeebe-deployment/configuration/gateway-config/#zeebegatewaymultitenancy)
      - ZEEBE_BROKER_GATEWAY_SECURITY_AUTHENTICATION_IDENTITY_BASEURL=http://identity:8084/

  operate:
    # ...
    environment:
      # rename "camunda.operate.multiTenancy.enabled" to:
      - CAMUNDA_OPERATE_MULTITENANCY_ENABLED=${MULTITENANCY_ENABLED}

I would expect that you will still see those errors in your console - I am seeing them now also - but everything should start and run for you. Let me know how it goes!!

1 Like

Hello again @savi003! The errors we are seeing have been identified as a bug and the engineering team is working to clean them up. There is an open GitHub issue to track some of the work - you an subscribe to notifications on that to follow progress. It appears to be an issue with the Operate Docker image, not with the configuration.

@nathan.loding All the services are running, but there is some issue with identity, initially identity opened in the browser, then showed some error and now not opening , the logs is identity is as follows

2023-10-24 23:19:30 2023-10-24 17:49:30.490 ERROR 1 --- [io-8084-exec-20] i.s.e.RestResponseEntityExceptionHandler : Unexpected error
2023-10-24 23:19:30 
2023-10-24 23:19:30 io.camunda.identity.sdk.exception.InvalidConfigurationException: 'renewToken' can only be used if OAuth credentials are provided
2023-10-24 23:19:30     at io.camunda.identity.sdk.annotation.AnnotationProcessor.validateOAuthCredentials(AnnotationProcessor.java:50) ~[identity-sdk-8.0.0-SNAPSHOT.jar!/:8.0.0-SNAPSHOT]
2023-10-24 23:19:30     at io.camunda.identity.sdk.annotation.AnnotationProcessor.lambda$apply$0(AnnotationProcessor.java:27) ~[identity-sdk-8.0.0-SNAPSHOT.jar!/:8.0.0-SNAPSHOT]
2023-10-24 23:19:30     at jdk.proxy2.$Proxy218.renewToken(Unknown Source) ~[?:?]
2023-10-24 23:19:30     at io.camunda.identity.impl.sm.security.spring.filter.SmJwtFilter.doFilterInternal(SmJwtFilter.java:78) ~[classes!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at io.camunda.identity.security.spring.filter.FilterExceptionHandler.doFilterInternal(FilterExceptionHandler.java:31) ~[classes!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323) ~[spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224) [spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) [spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) [spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) [spring-security-web-6.1.3.jar!/:6.1.3]
2023-10-24 23:19:30     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) [spring-web-6.0.11.jar!/:6.0.11]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-10.1.12.jar!/:?]
2023-10-24 23:19:30     at java.lang.Thread.run(Unknown Source) [?:?]
2023-10-24 23:19:30 Caused by: java.lang.IllegalArgumentException: clientSecret must not be empty
2023-10-24 23:19:30     at org.apache.commons.lang3.Validate.notBlank(Validate.java:441) ~[commons-lang3-3.12.0.jar!/:3.12.0]
2023-10-24 23:19:30     at io.camunda.identity.sdk.annotation.AnnotationProcessor.validateOAuthCredentials(AnnotationProcessor.java:47) ~[identity-sdk-8.0.0-SNAPSHOT.jar!/:8.0.0-SNAPSHOT]
2023-10-24 23:19:30     ... 82 more
2023-10-24 23:19:30

@nathan.loding any idea what is causing the issue?

Hi @savi003 - the client secret is supposed to be pulled from Keycloak, so you don’t need to manually specify it yourself … but something seems to be going wrong here. First, make sure your Keycloak container is running without error, then try restarting the Identity container. I’m not able to recreate this error every time, but I have encountered it. Let me know if restarting the container helps. I’ve reached out to the engineering team for some more information/feedback on this issue too!

@nathan.loding Keycloak container is running without error, Restarting is also not working. But when I disabled multitenancy and restart all the containers identity start working without any errors and then again when I enable multitenancy and restart all the containers again identity will work without any error for sometime and then


when I looked into logs identity is showing the error and there is no error in keycloak. Please let me know if you get any more information/feedback from engineering team.

Hi @savi003 - we have definitely found a bug of some kind, unfortunately. The engineers are looking at it. For now, here is a workaround. (You may need to tear down all the containers first, I have not tested with existing containers.)

  1. Start only the Keycloak container (docker compose up -d keycloak). It will also start the Postgres container, as Postgres is a dependency.
  2. Log in to Keycloak at http://localhost:18080/auth (admin/admin is the user/pass for our Docker Compose example)
  3. Switch the realm (top left) to camunda-platform
  4. Click on “Clients” in the menu, and click on the “camunda-identity” client
  5. Click on the “Credentials” tab and reveal/copy the client secret
  6. Following steps 10 and 11 from this documentation, add this secret to the Identity container configuration with the environment variable IDENTITY_CLIENT_SECRET
  7. Start the rest of the containers (docker compose up -d)

That should get things working. The issue is that Identity isn’t grabbing the client secret, which is something it is supposed to be doing. The workaround fixes this by manually setting the client secret in the same way you would if you were connecting Identity to an existing Keycloak instance.

1 Like

hello nathan i have same problem when i am running in docker containers on linux nodes, here is not any fix? CAMUNDA_CONNECTORS_VERSION=8.3.0
CAMUNDA_OPTIMIZE_VERSION=8.3.0
CAMUNDA_PLATFORM_VERSION=8.3.1
CAMUNDA_WEB_MODELER_VERSION=8.3.0
ELASTIC_VERSION=8.8.2
KEYCLOAK_SERVER_VERSION=21.1.2
MAILPIT_VERSION=v1.7.0
POSTGRES_VERSION=14.5-alpine

Summary -: for anyone attempting to use Docker to enable multitenancy for local testing

docker-compose.yaml file

# While the Docker images themselves are supported for production usage,
# this docker-compose.yaml is designed to be used by developers to run
# an environment locally. It is not designed to be used in production.
# We recommend to use Kubernetes in production with our Helm Charts:
# https://docs.camunda.io/docs/self-managed/platform-deployment/kubernetes-helm/
# For local development, we recommend using KIND instead of `docker-compose`:
# https://docs.camunda.io/docs/self-managed/platform-deployment/helm-kubernetes/guides/local-kubernetes-cluster/

# This is a full configuration with Zeebe, Operate, Tasklist, Optimize, Identity, Keycloak, and Elasticsearch
# See docker-compose-core.yml for a lightweight configuration that does not include Optimize, Identity, and Keycloak.

services:

  zeebe: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#zeebe
    image: camunda/zeebe:${CAMUNDA_PLATFORM_VERSION}
    container_name: zeebe
    ports:
      - "26500:26500"
      - "9600:9600"
    environment: # https://docs.camunda.io/docs/self-managed/zeebe-deployment/configuration/environment-variables/
      - ZEEBE_BROKER_GATEWAY_SECURITY_AUTHENTICATION_MODE=${ZEEBE_AUTHENTICATION_MODE}
      - ZEEBE_BROKER_GATEWAY_SECURITY_AUTHENTICATION_IDENTITY_ISSUERBACKENDURL=http://keycloak:8080/auth/realms/camunda-platform
      - ZEEBE_BROKER_GATEWAY_SECURITY_AUTHENTICATION_IDENTITY_AUDIENCE=zeebe-api
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_CLASSNAME=io.camunda.zeebe.exporter.ElasticsearchExporter
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_URL=http://elasticsearch:9200
      # default is 1000, see here: https://github.com/camunda/zeebe/blob/ef7343c5362e8f62b3fd789795410e3fa953bb6a/exporters/elasticsearch-exporter/src/main/java/io/camunda/zeebe/exporter/ElasticsearchExporterConfiguration.java#L259
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_BULK_SIZE=1
      # allow running with low disk space
      - ZEEBE_BROKER_DATA_DISKUSAGECOMMANDWATERMARK=0.998
      - ZEEBE_BROKER_DATA_DISKUSAGEREPLICATIONWATERMARK=0.999
      - "JAVA_TOOL_OPTIONS=-Xms512m -Xmx512m"
      - ZEEBE_BROKER_GATEWAY_SECURITY_AUTHENTICATION_IDENTITY_BASEURL=http://identity:8084
      - ZEEBE_GATEWAY_SECURITY_AUTHENTICATION_IDENTITY_BASEURL=http://identity:8084
    restart: always
    healthcheck:
      test: [ "CMD-SHELL", "timeout 10s bash -c ':> /dev/tcp/127.0.0.1/9600' || exit 1" ]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
    volumes:
      - zeebe:/usr/local/zeebe/data
    networks:
      - camunda-platform
    depends_on:
      - elasticsearch
      - identity

  operate: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#operate
    image: camunda/operate:${CAMUNDA_PLATFORM_VERSION}
    container_name: operate
    ports:
      - "8081:8080"
    environment: # https://docs.camunda.io/docs/self-managed/operate-deployment/configuration/
      - CAMUNDA_OPERATE_ZEEBE_GATEWAYADDRESS=zeebe:26500
      - ZEEBE_CLIENT_ID=${ZEEBE_CLIENT_ID}
      - ZEEBE_CLIENT_SECRET=${ZEEBE_CLIENT_SECRET}
      - ZEEBE_TOKEN_AUDIENCE=zeebe-api
      - ZEEBE_AUTHORIZATION_SERVER_URL=http://keycloak:8080/auth/realms/camunda-platform/protocol/openid-connect/token
      - CAMUNDA_OPERATE_ELASTICSEARCH_URL=http://elasticsearch:9200
      - CAMUNDA_OPERATE_ZEEBEELASTICSEARCH_URL=http://elasticsearch:9200
      # For more information regarding configuration with Identity see:
      # https://docs.camunda.io/docs/self-managed/operate-deployment/authentication/#identity
      - SPRING_PROFILES_ACTIVE=identity-auth
      - CAMUNDA_OPERATE_IDENTITY_BASEURL=http://identity:8084
      - CAMUNDA_OPERATE_IDENTITY_ISSUER_URL=http://${HOST}:18080/auth/realms/camunda-platform
      - CAMUNDA_OPERATE_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_OPERATE_IDENTITY_CLIENTID=operate
      - CAMUNDA_OPERATE_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_OPERATE_IDENTITY_AUDIENCE=operate-api
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://${HOST}:18080/auth/realms/camunda-platform
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://${HOST}:18080/auth/realms/camunda-platform/protocol/openid-connect/certs
      - CAMUNDA_OPERATE_IDENTITY_RESOURCEPERMISSIONSENABLED=${RESOURCE_AUTHORIZATIONS_ENABLED}
      - management.endpoints.web.exposure.include=health
      - management.endpoint.health.probes.enabled=true
      - ZEEBE_CLIENT_CONFIG_PATH=/tmp/zeebe_auth_cache
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:8080/actuator/health/readiness" ]
      interval: 30s
      timeout: 1s
      retries: 5
      start_period: 30s
    volumes:
      - operate_tmp:/tmp
    networks:
      - camunda-platform
    depends_on:
      - zeebe
      - identity
      - elasticsearch

  tasklist: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#tasklist
    image: camunda/tasklist:${CAMUNDA_PLATFORM_VERSION}
    container_name: tasklist
    ports:
      - "8082:8080"
    environment: # https://docs.camunda.io/docs/self-managed/tasklist-deployment/configuration/
      - CAMUNDA_TASKLIST_ZEEBE_GATEWAYADDRESS=zeebe:26500
      - ZEEBE_CLIENT_ID=${ZEEBE_CLIENT_ID}
      - ZEEBE_CLIENT_SECRET=${ZEEBE_CLIENT_SECRET}
      - ZEEBE_TOKEN_AUDIENCE=zeebe-api
      - ZEEBE_AUTHORIZATION_SERVER_URL=http://keycloak:8080/auth/realms/camunda-platform/protocol/openid-connect/token
      - CAMUNDA_TASKLIST_ELASTICSEARCH_URL=http://elasticsearch:9200
      - CAMUNDA_TASKLIST_ZEEBEELASTICSEARCH_URL=http://elasticsearch:9200
      # For more information regarding configuration with Identity see:
      # https://docs.camunda.io/docs/self-managed/tasklist-deployment/authentication/#identity
      - SPRING_PROFILES_ACTIVE=identity-auth
      - CAMUNDA_TASKLIST_IDENTITY_BASEURL=http://identity:8084
      - CAMUNDA_TASKLIST_IDENTITY_ISSUER_URL=http://${HOST}:18080/auth/realms/camunda-platform
      - CAMUNDA_TASKLIST_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_TASKLIST_IDENTITY_CLIENTID=tasklist
      - CAMUNDA_TASKLIST_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_TASKLIST_IDENTITY_AUDIENCE=tasklist-api
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://${HOST}:18080/auth/realms/camunda-platform
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://${HOST}:18080/auth/realms/camunda-platform/protocol/openid-connect/certs
      - CAMUNDA_TASKLIST_IDENTITY_RESOURCE_PERMISSIONS_ENABLED=${RESOURCE_AUTHORIZATIONS_ENABLED}
      - management.endpoints.web.exposure.include=health
      - management.endpoint.health.probes.enabled=true
      - ZEEBE_CLIENT_CONFIG_PATH=/tmp/zeebe_auth_cache
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:8080/actuator/health/readiness" ]
      interval: 30s
      timeout: 1s
      retries: 5
      start_period: 30s
    volumes:
      - tasklist_tmp:/tmp
    networks:
      - camunda-platform
    depends_on:
      zeebe:
        condition: service_started
      elasticsearch:
        condition: service_healthy
      identity:
        condition: service_healthy

  connectors: # https://docs.camunda.io/docs/components/integration-framework/connectors/out-of-the-box-connectors/available-connectors-overview/
    image: camunda/connectors-bundle:${CAMUNDA_CONNECTORS_VERSION}
    container_name: connectors
    ports:
      - "8085:8080"
    environment:
      - ZEEBE_CLIENT_BROKER_GATEWAY-ADDRESS=zeebe:26500
      - ZEEBE_CLIENT_SECURITY_PLAINTEXT=true
      - ZEEBE_CLIENT_ID=${ZEEBE_CLIENT_ID}
      - ZEEBE_CLIENT_SECRET=${ZEEBE_CLIENT_SECRET}
      - ZEEBE_TOKEN_AUDIENCE=zeebe-api
      - ZEEBE_AUTHORIZATION_SERVER_URL=http://keycloak:8080/auth/realms/camunda-platform/protocol/openid-connect/token
      - CAMUNDA_OPERATE_CLIENT_KEYCLOAK-URL=http://keycloak:8080
      - CAMUNDA_OPERATE_CLIENT_CLIENT-ID=connectors
      - CAMUNDA_OPERATE_CLIENT_CLIENT-SECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_OPERATE_CLIENT_KEYCLOAK-REALM=camunda-platform
      - CAMUNDA_OPERATE_CLIENT_URL=http://operate:8080
      - management.endpoints.web.exposure.include=health
      - management.endpoint.health.probes.enabled=true
    env_file: connector-secrets.txt
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:8080/actuator/health/readiness" ]
      interval: 30s
      timeout: 1s
      retries: 5
      start_period: 30s
    networks:
      - camunda-platform
    depends_on:
      - zeebe
      - operate
      - identity

  optimize: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#optimize
    image: camunda/optimize:${CAMUNDA_OPTIMIZE_VERSION}
    container_name: optimize
    ports:
      - "8083:8090"
    environment: # https://docs.camunda.io/docs/self-managed/optimize-deployment/setup/installation/#available-environment-variables
      - OPTIMIZE_ELASTICSEARCH_HOST=elasticsearch
      - OPTIMIZE_ELASTICSEARCH_HTTP_PORT=9200
      - SPRING_PROFILES_ACTIVE=ccsm
      - CAMUNDA_OPTIMIZE_ZEEBE_ENABLED=true
      - CAMUNDA_OPTIMIZE_ENTERPRISE=false
      - CAMUNDA_OPTIMIZE_IDENTITY_ISSUER_URL=http://${HOST}:18080/auth/realms/camunda-platform
      - CAMUNDA_OPTIMIZE_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_OPTIMIZE_IDENTITY_CLIENTID=optimize
      - CAMUNDA_OPTIMIZE_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_OPTIMIZE_IDENTITY_AUDIENCE=optimize-api
      - CAMUNDA_OPTIMIZE_SECURITY_AUTH_COOKIE_SAME_SITE_ENABLED=false
      - CAMUNDA_OPTIMIZE_UI_LOGOUT_HIDDEN=true
      - management.endpoints.web.exposure.include=health
      - management.endpoint.health.probes.enabled=true
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:8090/api/readyz" ]
      interval: 30s
      timeout: 1s
      retries: 5
      start_period: 30s
    volumes:
      - "./.optimize/environment-config.yaml:/optimize/config/environment-config.yaml"
    restart: on-failure
    networks:
      - camunda-platform
    depends_on:
      - identity
      - elasticsearch

  identity: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#identity
    container_name: identity
    image: camunda/identity:${CAMUNDA_PLATFORM_VERSION}
    ports:
      - "8084:8084"
    environment: # https://docs.camunda.io/docs/self-managed/identity/deployment/configuration-variables/
      SERVER_PORT: 8084
      IDENTITY_RETRY_DELAY_SECONDS: 30
      KEYCLOAK_URL: http://keycloak:8080/auth
      IDENTITY_AUTH_PROVIDER_BACKEND_URL: http://keycloak:8080/auth/realms/camunda-platform
      IDENTITY_DATABASE_HOST: postgres
      IDENTITY_DATABASE_PORT: 5432
      IDENTITY_DATABASE_NAME: bitnami_keycloak
      IDENTITY_DATABASE_USERNAME: bn_keycloak
      IDENTITY_DATABASE_PASSWORD: "#3]O?4RGj)DE7Z!9SA5"
      KEYCLOAK_INIT_OPERATE_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_OPERATE_ROOT_URL: http://${HOST}:8081
      KEYCLOAK_INIT_TASKLIST_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_TASKLIST_ROOT_URL: http://${HOST}:8082
      KEYCLOAK_INIT_OPTIMIZE_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_OPTIMIZE_ROOT_URL: http://${HOST}:8083
      KEYCLOAK_INIT_WEBMODELER_ROOT_URL: http://${HOST}:8070
      KEYCLOAK_INIT_CONNECTORS_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_CONNECTORS_ROOT_URL: http://${HOST}:8085
      KEYCLOAK_INIT_ZEEBE_NAME: zeebe
      KEYCLOAK_USERS_0_USERNAME: "demo"
      KEYCLOAK_USERS_0_PASSWORD: "demo"
      KEYCLOAK_USERS_0_FIRST_NAME: "demo"
      KEYCLOAK_USERS_0_EMAIL: "demo@acme.com"
      KEYCLOAK_USERS_0_ROLES_0: "Identity"
      KEYCLOAK_USERS_0_ROLES_1: "Optimize"
      KEYCLOAK_USERS_0_ROLES_2: "Operate"
      KEYCLOAK_USERS_0_ROLES_3: "Tasklist"
      KEYCLOAK_USERS_0_ROLES_4: "Web Modeler"
      KEYCLOAK_CLIENTS_0_NAME: zeebe
      KEYCLOAK_CLIENTS_0_ID: ${ZEEBE_CLIENT_ID}
      KEYCLOAK_CLIENTS_0_SECRET: ${ZEEBE_CLIENT_SECRET}
      KEYCLOAK_CLIENTS_0_TYPE: M2M
      KEYCLOAK_CLIENTS_0_PERMISSIONS_0_RESOURCE_SERVER_ID: zeebe-api
      KEYCLOAK_CLIENTS_0_PERMISSIONS_0_DEFINITION: write:*
      RESOURCE_PERMISSIONS_ENABLED: ${RESOURCE_AUTHORIZATIONS_ENABLED}
    healthcheck:
      test: [ "CMD", "wget", "-q", "--tries=1", "--spider", "http://localhost:8082/actuator/health" ]
      interval: 5s
      timeout: 15s
      retries: 30
      start_period: 60s
    restart: on-failure
    volumes:
      - keycloak-theme:/app/keycloak-theme
    networks:
      - camunda-platform
      - identity-network
    depends_on:
      keycloak:
        condition: service_healthy

  postgres: # https://hub.docker.com/_/postgres
    container_name: postgres
    image: postgres:${POSTGRES_VERSION}
    environment:
      POSTGRES_DB: bitnami_keycloak
      POSTGRES_USER: bn_keycloak
      POSTGRES_PASSWORD: "#3]O?4RGj)DE7Z!9SA5"
    restart: on-failure
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - postgres:/var/lib/postgresql/data
    networks:
      - identity-network

  keycloak: # https://hub.docker.com/r/bitnami/keycloak
    container_name: keycloak
    image: bitnami/keycloak:${KEYCLOAK_SERVER_VERSION}
    volumes:
      - keycloak-theme:/opt/bitnami/keycloak/themes/identity
    ports:
      - "18080:8080"
    environment:
      KEYCLOAK_HTTP_RELATIVE_PATH: /auth
      KEYCLOAK_DATABASE_HOST: postgres
      KEYCLOAK_DATABASE_PASSWORD: "#3]O?4RGj)DE7Z!9SA5"
      KEYCLOAK_ADMIN_USER: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
    restart: on-failure
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:8080/auth" ]
      interval: 30s
      timeout: 15s
      retries: 5
      start_period: 30s
    networks:
      - camunda-platform
      - identity-network
    depends_on:
      - postgres

  elasticsearch: # https://hub.docker.com/_/elasticsearch
    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION}
    container_name: elasticsearch
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - bootstrap.memory_lock=true
      - discovery.type=single-node
      - xpack.security.enabled=false
      # allow running with low disk space
      - cluster.routing.allocation.disk.threshold_enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    restart: always
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:9200/_cat/health | grep -q green" ]
      interval: 30s
      timeout: 5s
      retries: 3
    volumes:
      - elastic:/usr/share/elasticsearch/data
    networks:
      - camunda-platform

  kibana:
    image: docker.elastic.co/kibana/kibana:${ELASTIC_VERSION}
    container_name: kibana
    ports:
      - 5601:5601
    volumes:
      - kibana:/usr/share/kibana/data
    networks:
      - camunda-platform
    depends_on:
      - elasticsearch
    profiles:
      - kibana

volumes:
  zeebe:
  elastic:
  postgres:
  keycloak-theme:
  kibana:
  operate_tmp:
  tasklist_tmp:

networks:
  # Note there are two bridge networks: One for Camunda Platform and one for Identity.
  # Identity and Keycloak are part of both as they need to be accessible by platform components.
  camunda-platform:
  identity-network:

.env file

## Image versions ##

CAMUNDA_CONNECTORS_VERSION=8.3.0

CAMUNDA_OPTIMIZE_VERSION=8.3.0

CAMUNDA_PLATFORM_VERSION=8.3.1

CAMUNDA_WEB_MODELER_VERSION=8.3.0

ELASTIC_VERSION=8.8.2

KEYCLOAK_SERVER_VERSION=21.1.2

MAILPIT_VERSION=v1.9.9

POSTGRES_VERSION=14.5-alpine

HOST=localhost

## Configuration ##

# By default the zeebe api is public, when setting this to `identity` a valid zeebe client token is required

# ZEEBE_AUTHENTICATION_MODE=none

ZEEBE_CLIENT_ID=zeebe

ZEEBE_CLIENT_SECRET=zecret

# Set to 'true' to enable resource based authorizations for users and groups

# This can be used to limit access for users or groups to view/update specific

# processes and decisions in Operate and Tasklist

RESOURCE_AUTHORIZATIONS_ENABLED=false

MULTITENANCY_ENABLED=true

ZEEBE_AUTHENTICATION_MODE=identity

IDENTITY_CLIENT_SECRET=CM95sEofY9rLq039Ws35IwVvpS530SXW

# Start only the Keycloak container (docker compose up -d keycloak). It will also start the Postgres container, as Postgres is a dependency.

# Log in to Keycloak at http://localhost:18080/auth 2 (admin/admin is the user/pass for our Docker Compose example)

#Switch the realm (top left) to camunda-platform

# Click on “Clients” in the menu, and click on the “camunda-identity” client

# Click on the “Credentials” tab and reveal/copy the client secret

To enable multitenancy set
MULTITENANCY_ENABLED flag in .env file to true
ZEEBE_AUTHENTICATION_MODE to identity

as @nathan.loding mentioned in the earlier post

  1. Start only the Keycloak container (docker compose up -d keycloak). It will also start the Postgres container, as Postgres is a dependency.
  2. Log in to Keycloak at http://localhost:18080/auth (admin/admin is the user/pass for our Docker Compose example)
  3. Switch the realm (top left) to camunda-platform
  4. Click on “Clients” in the menu, and click on the “camunda-identity” client
  5. Click on the “Credentials” tab and reveal/copy the client secret
  6. Replace the value of IDENTITY_CLIENT_SECRET in .env file with the copied value
  7. Start the rest of the containers (docker compose up -d)

After this all services will run without any issue with multitenancy enabled

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.