From be6d8deef77dd53727c9627b583385e62478e731 Mon Sep 17 00:00:00 2001 From: Felix Gateru Date: Wed, 19 Mar 2025 14:37:51 +0300 Subject: [PATCH] MG-67 - Update Magistrala Compose with SuperMQ Compose (#76) * chore: update compose with supermq override Signed-off-by: Felix Gateru * chore: remove duplicate env variables Signed-off-by: Felix Gateru * ci(check-license.yaml): ignore rabbitmq files Signed-off-by: Felix Gateru * refactor: add supermq docker file Signed-off-by: Felix Gateru * feat: add update option to make file Signed-off-by: Felix Gateru * refactor(supermq-docker-compose.override.yml): fix errors in files Signed-off-by: Felix Gateru * refactor: add amend commit to fetch and update commands Signed-off-by: Felix Gateru * chore: add supermq dependency update script Signed-off-by: Felix Gateru * chore: update SuperMQ dependency files * fix: remove reverted changes to Makefile Signed-off-by: Felix Gateru * refactor(supermq.sh): remove git staging and commit from script Signed-off-by: Felix Gateru * chore: remove redundant docker config files Signed-off-by: Felix Gateru * chore: remove redundant files, update compose p[roject directory Signed-off-by: Felix Gateru * chore: update project dir path Signed-off-by: Felix Gateru * chore: update nginv env file variable, remove redundant nginx config files Signed-off-by: Felix Gateru * chore: include journal and certs to mg compose Signed-off-by: Felix Gateru * refactor: update script to use sparse checkout and move docker files into ./docker/supermq-docker Signed-off-by: Felix Gateru * refactor: update docker compose file Signed-off-by: Felix Gateru * feat(Makefile): add fetch_supermq to run recipe Signed-off-by: Felix Gateru * refactor(supermq.sh): clean up Signed-off-by: Felix Gateru * chore(go.mod): remove toolchain definition Signed-off-by: Felix Gateru * ci(build.yml): add check for supermq dependency Signed-off-by: Felix Gateru * ci: move check to ci Signed-off-by: Felix Gateru --------- Signed-off-by: Felix Gateru --- .github/workflows/check-license.yaml | 2 +- .github/workflows/tests.yml | 16 +- Makefile | 5 +- docker/.env | 358 +---- docker/addons/certs/docker-compose.yml | 123 -- docker/docker-compose.yml | 1286 +--------------- docker/nginx/snippets/http_access_log.conf | 8 - docker/supermq-docker-compose.override.yml | 151 ++ docker/supermq-docker/.env | 492 ++++++ docker/supermq-docker/Dockerfile | 24 + docker/supermq-docker/Dockerfile.dev | 8 + docker/supermq-docker/README.md | 134 ++ .../addons/certs/config.yml | 0 .../addons/certs/docker-compose.yml | 124 ++ .../addons/journal/docker-compose.yml | 72 + .../addons/prometheus/docker-compose.yml | 53 + .../addons/prometheus/grafana/dashboard.yml | 15 + .../addons/prometheus/grafana/datasource.yml | 12 + .../prometheus/grafana/example-dashboard.json | 1317 +++++++++++++++++ .../addons/prometheus/metrics/prometheus.yml | 22 + docker/supermq-docker/addons/vault/README.md | 290 ++++ docker/supermq-docker/addons/vault/config.hcl | 10 + .../addons/vault/docker-compose.yml | 39 + .../supermq-docker/addons/vault/entrypoint.sh | 25 + .../addons/vault/scripts/.gitignore | 5 + ...agistrala_clients_certs_issue.template.hcl | 32 + .../addons/vault/scripts/vault_cmd.sh | 24 + .../addons/vault/scripts/vault_copy_certs.sh | 86 ++ .../addons/vault/scripts/vault_copy_env.sh | 46 + .../vault/scripts/vault_create_approle.sh | 122 ++ .../addons/vault/scripts/vault_init.sh | 46 + .../addons/vault/scripts/vault_set_pki.sh | 251 ++++ .../addons/vault/scripts/vault_unseal.sh | 46 + docker/supermq-docker/docker-compose.yml | 1284 ++++++++++++++++ docker/{ => supermq-docker}/nats/nats.conf | 0 docker/supermq-docker/nginx/.gitignore | 5 + docker/supermq-docker/nginx/entrypoint.sh | 28 + docker/supermq-docker/nginx/nginx-key.conf | 157 ++ docker/supermq-docker/nginx/nginx-x509.conf | 178 +++ .../nginx/snippets/http_access_log.conf | 12 + .../nginx/snippets/mqtt-upstream-cluster.conf | 0 .../nginx/snippets/mqtt-upstream-single.conf | 0 .../snippets/mqtt-ws-upstream-cluster.conf | 0 .../snippets/mqtt-ws-upstream-single.conf | 0 .../nginx/snippets/proxy-headers.conf | 0 .../nginx/snippets/ssl-client.conf | 0 .../nginx/snippets/ssl.conf | 4 +- .../nginx/snippets/stream_access_log.conf | 0 .../nginx/snippets/verify-ssl-client.conf | 0 .../nginx/snippets/ws-upgrade.conf | 0 .../supermq-docker/rabbitmq/enabled_plugins | 1 + docker/supermq-docker/rabbitmq/rabbitmq.conf | 15 + .../{ => supermq-docker}/spicedb/schema.zed | 0 docker/supermq-docker/ssl/.gitignore | 7 + docker/supermq-docker/ssl/Makefile | 170 +++ .../{ => supermq-docker}/ssl/authorization.js | 2 +- docker/supermq-docker/ssl/certs/ca.crt | 23 + docker/supermq-docker/ssl/certs/ca.key | 28 + .../ssl/certs/supermq-server.crt | 26 + .../ssl/certs/supermq-server.key | 52 + docker/supermq-docker/ssl/dhparam.pem | 8 + .../templates/smtp-notifier.tmpl | 0 .../{ => supermq-docker}/templates/users.tmpl | 0 docker/vernemq/Dockerfile | 56 - docker/vernemq/bin/vernemq.sh | 352 ----- docker/vernemq/files/vm.args | 15 - go.mod | 2 - scripts/supermq.sh | 40 + 68 files changed, 5517 insertions(+), 2192 deletions(-) delete mode 100644 docker/addons/certs/docker-compose.yml delete mode 100644 docker/nginx/snippets/http_access_log.conf create mode 100644 docker/supermq-docker-compose.override.yml create mode 100644 docker/supermq-docker/.env create mode 100644 docker/supermq-docker/Dockerfile create mode 100644 docker/supermq-docker/Dockerfile.dev create mode 100644 docker/supermq-docker/README.md rename docker/{ => supermq-docker}/addons/certs/config.yml (100%) create mode 100644 docker/supermq-docker/addons/certs/docker-compose.yml create mode 100644 docker/supermq-docker/addons/journal/docker-compose.yml create mode 100644 docker/supermq-docker/addons/prometheus/docker-compose.yml create mode 100644 docker/supermq-docker/addons/prometheus/grafana/dashboard.yml create mode 100644 docker/supermq-docker/addons/prometheus/grafana/datasource.yml create mode 100644 docker/supermq-docker/addons/prometheus/grafana/example-dashboard.json create mode 100644 docker/supermq-docker/addons/prometheus/metrics/prometheus.yml create mode 100644 docker/supermq-docker/addons/vault/README.md create mode 100644 docker/supermq-docker/addons/vault/config.hcl create mode 100644 docker/supermq-docker/addons/vault/docker-compose.yml create mode 100644 docker/supermq-docker/addons/vault/entrypoint.sh create mode 100644 docker/supermq-docker/addons/vault/scripts/.gitignore create mode 100644 docker/supermq-docker/addons/vault/scripts/magistrala_clients_certs_issue.template.hcl create mode 100644 docker/supermq-docker/addons/vault/scripts/vault_cmd.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_copy_certs.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_copy_env.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_create_approle.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_init.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_set_pki.sh create mode 100755 docker/supermq-docker/addons/vault/scripts/vault_unseal.sh create mode 100644 docker/supermq-docker/docker-compose.yml rename docker/{ => supermq-docker}/nats/nats.conf (100%) create mode 100644 docker/supermq-docker/nginx/.gitignore create mode 100755 docker/supermq-docker/nginx/entrypoint.sh create mode 100644 docker/supermq-docker/nginx/nginx-key.conf create mode 100644 docker/supermq-docker/nginx/nginx-x509.conf create mode 100644 docker/supermq-docker/nginx/snippets/http_access_log.conf rename docker/{ => supermq-docker}/nginx/snippets/mqtt-upstream-cluster.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/mqtt-upstream-single.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/mqtt-ws-upstream-cluster.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/mqtt-ws-upstream-single.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/proxy-headers.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/ssl-client.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/ssl.conf (79%) rename docker/{ => supermq-docker}/nginx/snippets/stream_access_log.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/verify-ssl-client.conf (100%) rename docker/{ => supermq-docker}/nginx/snippets/ws-upgrade.conf (100%) create mode 100644 docker/supermq-docker/rabbitmq/enabled_plugins create mode 100644 docker/supermq-docker/rabbitmq/rabbitmq.conf rename docker/{ => supermq-docker}/spicedb/schema.zed (100%) create mode 100644 docker/supermq-docker/ssl/.gitignore create mode 100644 docker/supermq-docker/ssl/Makefile rename docker/{ => supermq-docker}/ssl/authorization.js (98%) create mode 100644 docker/supermq-docker/ssl/certs/ca.crt create mode 100644 docker/supermq-docker/ssl/certs/ca.key create mode 100644 docker/supermq-docker/ssl/certs/supermq-server.crt create mode 100644 docker/supermq-docker/ssl/certs/supermq-server.key create mode 100644 docker/supermq-docker/ssl/dhparam.pem rename docker/{ => supermq-docker}/templates/smtp-notifier.tmpl (100%) rename docker/{ => supermq-docker}/templates/users.tmpl (100%) delete mode 100644 docker/vernemq/Dockerfile delete mode 100755 docker/vernemq/bin/vernemq.sh delete mode 100644 docker/vernemq/files/vm.args create mode 100755 scripts/supermq.sh diff --git a/.github/workflows/check-license.yaml b/.github/workflows/check-license.yaml index 7b97d2b86..c02759780 100644 --- a/.github/workflows/check-license.yaml +++ b/.github/workflows/check-license.yaml @@ -23,7 +23,7 @@ jobs: CHECK="" for file in $(grep -rl --exclude-dir={.git,build,**vernemq**} \ --exclude=\*.{crt,key,pem,zed,hcl,md,json,csv,mod,sum,tmpl,args} \ - --exclude={CODEOWNERS,LICENSE,MAINTAINERS} \ + --exclude={CODEOWNERS,LICENSE,MAINTAINERS,enabled_plugins,rabbitmq.conf} \ .); do if ! head -n 5 "$file" | grep -q "Copyright (c) Abstract Machines"; then diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dbb740ab9..076b70657 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,6 +29,17 @@ jobs: version: v1.60.3 args: --config ./tools/config/golangci.yml + - name: Fetch supermq + run: | + make fetch_supermq + if [[ -n $(git status --porcelain docker/supermq-docker) ]]; then + echo "SuperMQ docker file is not up to date. Please update it" + git diff docker/supermq-docker + exit 1 + else + exit 0 + fi + - name: Build all Binaries run: | make all -j $(nproc) @@ -162,9 +173,8 @@ jobs: - name: Run rule engine tests if: steps.changes.outputs.re == 'true' || steps.changes.outputs.workflow == 'true' run: | - go test --race -v -count=1 -coverprofile=coverage/re.out ./re/... - - + go test --race -v -count=1 -coverprofile=coverage/re.out ./re/... + - name: Upload coverage uses: codecov/codecov-action@v5 with: diff --git a/Makefile b/Makefile index 93abf0682..18a639e06 100644 --- a/Makefile +++ b/Makefile @@ -246,7 +246,10 @@ endif endif endif -run: check_certs +fetch_supermq: + @./scripts/supermq.sh + +run: check_certs fetch_supermq docker compose -f docker/docker-compose.yml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args) run_addons: check_certs diff --git a/docker/.env b/docker/.env index 8a04831df..6f9844b21 100644 --- a/docker/.env +++ b/docker/.env @@ -18,37 +18,10 @@ SMQ_NATS_HEALTH_CHECK=http://nats:${SMQ_NATS_HTTP_PORT}/healthz SMQ_NATS_WS_TARGET_PATH= SMQ_NATS_MQTT_QOS=1 -## RabbitMQ -SMQ_RABBITMQ_PORT=5672 -SMQ_RABBITMQ_HTTP_PORT=15672 -SMQ_RABBITMQ_USER=supermq -SMQ_RABBITMQ_PASS=supermq -SMQ_RABBITMQ_COOKIE=supermq -SMQ_RABBITMQ_VHOST=/ -SMQ_RABBITMQ_URL=amqp://${SMQ_RABBITMQ_USER}:${SMQ_RABBITMQ_PASS}@rabbitmq:${SMQ_RABBITMQ_PORT}${SMQ_RABBITMQ_VHOST} - ## Message Broker SMQ_MESSAGE_BROKER_TYPE=nats SMQ_MESSAGE_BROKER_URL=${SMQ_NATS_URL} -## VERNEMQ -SMQ_DOCKER_VERNEMQ_ALLOW_ANONYMOUS=on -SMQ_DOCKER_VERNEMQ_LOG__CONSOLE__LEVEL=error -SMQ_VERNEMQ_HEALTH_CHECK=http://vernemq:8888/health -SMQ_VERNEMQ_WS_TARGET_PATH=/mqtt -SMQ_VERNEMQ_MQTT_QOS=2 - -## MQTT Broker -SMQ_MQTT_BROKER_TYPE=vernemq -SMQ_MQTT_BROKER_HEALTH_CHECK=${SMQ_VERNEMQ_HEALTH_CHECK} -SMQ_MQTT_ADAPTER_MQTT_QOS=${SMQ_VERNEMQ_MQTT_QOS} -SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} -SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT=1883 -SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK=${SMQ_MQTT_BROKER_HEALTH_CHECK} -SMQ_MQTT_ADAPTER_WS_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} -SMQ_MQTT_ADAPTER_WS_TARGET_PORT=8080 -SMQ_MQTT_ADAPTER_WS_TARGET_PATH=${SMQ_VERNEMQ_WS_TARGET_PATH} - ## Redis SMQ_REDIS_TCP_PORT=6379 SMQ_REDIS_URL=redis://es-redis:${SMQ_REDIS_TCP_PORT}/0 @@ -72,35 +45,6 @@ SMQ_SEND_TELEMETRY=true SMQ_POSTGRES_MAX_CONNECTIONS=100 ## Core Services - -### Auth -SMQ_AUTH_LOG_LEVEL=debug -SMQ_AUTH_HTTP_HOST=auth -SMQ_AUTH_HTTP_PORT=9001 -SMQ_AUTH_HTTP_SERVER_CERT= -SMQ_AUTH_HTTP_SERVER_KEY= -SMQ_AUTH_GRPC_HOST=auth -SMQ_AUTH_GRPC_PORT=7001 -SMQ_AUTH_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/auth-grpc-server.crt}${GRPC_TLS:+./ssl/certs/auth-grpc-server.crt} -SMQ_AUTH_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/auth-grpc-server.key}${GRPC_TLS:+./ssl/certs/auth-grpc-server.key} -SMQ_AUTH_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} -SMQ_AUTH_DB_HOST=auth-db -SMQ_AUTH_DB_PORT=5432 -SMQ_AUTH_DB_USER=supermq -SMQ_AUTH_DB_PASS=supermq -SMQ_AUTH_DB_NAME=auth -SMQ_AUTH_DB_SSL_MODE=disable -SMQ_AUTH_DB_SSL_CERT= -SMQ_AUTH_DB_SSL_KEY= -SMQ_AUTH_DB_SSL_ROOT_CERT= -SMQ_AUTH_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH -SMQ_AUTH_ACCESS_TOKEN_DURATION="1h" -SMQ_AUTH_REFRESH_TOKEN_DURATION="24h" -SMQ_AUTH_INVITATION_DURATION="168h" -SMQ_AUTH_ADAPTER_INSTANCE_ID= -SMQ_AUTH_CACHE_URL=redis://auth-redis:${SMQ_REDIS_TCP_PORT}/0 -SMQ_AUTH_CACHE_KEY_DURATION=10m - #### Auth Client Config SMQ_AUTH_URL=auth:9001 SMQ_AUTH_GRPC_URL=auth:7001 @@ -109,27 +53,6 @@ SMQ_AUTH_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/auth-grpc-client.crt} SMQ_AUTH_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/auth-grpc-client.key} SMQ_AUTH_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} -### Domains -SMQ_DOMAINS_LOG_LEVEL=debug -SMQ_DOMAINS_HTTP_HOST=domains -SMQ_DOMAINS_HTTP_PORT=9003 -SMQ_DOMAINS_HTTP_SERVER_KEY= -SMQ_DOMAINS_HTTP_SERVER_CERT= -SMQ_DOMAINS_GRPC_HOST=domains -SMQ_DOMAINS_GRPC_PORT=7003 -SMQ_DOMAINS_DB_HOST=domains-db -SMQ_DOMAINS_DB_PORT=5432 -SMQ_DOMAINS_DB_NAME=domains -SMQ_DOMAINS_DB_USER=supermq -SMQ_DOMAINS_DB_PASS=supermq -SMQ_DOMAINS_DB_SSL_MODE= -SMQ_DOMAINS_DB_SSL_KEY= -SMQ_DOMAINS_DB_SSL_CERT= -SMQ_DOMAINS_DB_SSL_ROOT_CERT= -SMQ_DOMAINS_INSTANCE_ID= -SMQ_DOMAINS_CACHE_URL=redis://domains-redis:${SMQ_REDIS_TCP_PORT}/0 -SMQ_DOMAINS_CACHE_KEY_DURATION=10m - #### Domains Client Config SMQ_DOMAINS_URL=http://domains:9003 SMQ_DOMAINS_GRPC_URL=domains:7003 @@ -147,153 +70,13 @@ SMQ_SPICEDB_DB_PORT=5432 ### SpiceDB config SMQ_SPICEDB_PRE_SHARED_KEY="12345678" SMQ_SPICEDB_SCHEMA_FILE="/schema.zed" -SMQ_SPICEDB_HOST=magistrala-spicedb +SMQ_SPICEDB_HOST=supermq-spicedb SMQ_SPICEDB_PORT=50051 SMQ_SPICEDB_DATASTORE_ENGINE=postgres ### UI SMQ_UI_PATH_PREFIX=/ui -### Users -SMQ_USERS_LOG_LEVEL=debug -SMQ_USERS_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH -SMQ_USERS_ADMIN_EMAIL=admin@example.com -SMQ_USERS_ADMIN_PASSWORD=12345678 -SMQ_USERS_ADMIN_USERNAME=admin -SMQ_USERS_ADMIN_FIRST_NAME=super -SMQ_USERS_ADMIN_LAST_NAME=admin -SMQ_USERS_PASS_REGEX=^.{8,}$ -SMQ_USERS_ACCESS_TOKEN_DURATION=15m -SMQ_USERS_REFRESH_TOKEN_DURATION=24h -SMQ_TOKEN_RESET_ENDPOINT=/reset-request -SMQ_USERS_HTTP_HOST=users -SMQ_USERS_HTTP_PORT=9002 -SMQ_USERS_HTTP_SERVER_CERT= -SMQ_USERS_HTTP_SERVER_KEY= -SMQ_USERS_DB_HOST=users-db -SMQ_USERS_DB_PORT=5432 -SMQ_USERS_DB_USER=supermq -SMQ_USERS_DB_PASS=supermq -SMQ_USERS_DB_NAME=users -SMQ_USERS_DB_SSL_MODE=disable -SMQ_USERS_DB_SSL_CERT= -SMQ_USERS_DB_SSL_KEY= -SMQ_USERS_DB_SSL_ROOT_CERT= -SMQ_USERS_RESET_PWD_TEMPLATE=users.tmpl -SMQ_USERS_INSTANCE_ID= -SMQ_USERS_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH -SMQ_USERS_ADMIN_EMAIL=admin@example.com -SMQ_USERS_ADMIN_PASSWORD=12345678 -SMQ_USERS_PASS_REGEX=^.{8,}$ -SMQ_USERS_ACCESS_TOKEN_DURATION=15m -SMQ_USERS_REFRESH_TOKEN_DURATION=24h -SMQ_TOKEN_RESET_ENDPOINT=/reset-request -SMQ_USERS_ALLOW_SELF_REGISTER=true -SMQ_OAUTH_UI_REDIRECT_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/tokens/secure -SMQ_OAUTH_UI_ERROR_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/error -SMQ_USERS_DELETE_INTERVAL=24h -SMQ_USERS_DELETE_AFTER=720h - -#### Users Client Config -SMQ_USERS_URL=users:9002 - -### Email utility -SMQ_EMAIL_HOST=smtp.mailtrap.io -SMQ_EMAIL_PORT=2525 -SMQ_EMAIL_USERNAME=18bf7f70705139 -SMQ_EMAIL_PASSWORD=2b0d302e775b1e -SMQ_EMAIL_FROM_ADDRESS=from@example.com -SMQ_EMAIL_FROM_NAME=Example -SMQ_EMAIL_TEMPLATE=email.tmpl - -### Google OAuth2 -SMQ_GOOGLE_CLIENT_ID= -SMQ_GOOGLE_CLIENT_SECRET= -SMQ_GOOGLE_REDIRECT_URL= -SMQ_GOOGLE_STATE= - -### Groups -SMQ_GROUPS_LOG_LEVEL=debug -SMQ_GROUPS_HTTP_HOST=groups -SMQ_GROUPS_HTTP_PORT=9004 -SMQ_GROUPS_HTTP_SERVER_CERT= -SMQ_GROUPS_HTTP_SERVER_KEY= -SMQ_GROUPS_GRPC_HOST=groups -SMQ_GROUPS_GRPC_PORT=7004 -SMQ_GROUPS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/groups-grpc-server.crt}${GRPC_TLS:+./ssl/certs/groups-grpc-server.crt} -SMQ_GROUPS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/groups-grpc-server.key}${GRPC_TLS:+./ssl/certs/groups-grpc-server.key} -SMQ_GROUPS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} -SMQ_GROUPS_DB_HOST=groups-db -SMQ_GROUPS_DB_PORT=5432 -SMQ_GROUPS_DB_USER=supermq -SMQ_GROUPS_DB_PASS=supermq -SMQ_GROUPS_DB_NAME=groups -SMQ_GROUPS_DB_SSL_MODE=disable -SMQ_GROUPS_DB_SSL_CERT= -SMQ_GROUPS_DB_SSL_KEY= -SMQ_GROUPS_DB_SSL_ROOT_CERT= -SMQ_GROUPS_INSTANCE_ID= - -#### Groups Client Config -SMQ_GROUPS_URL=groups:9004 -SMQ_GROUPS_GRPC_URL=groups:7004 -SMQ_GROUPS_GRPC_TIMEOUT=300s -SMQ_GROUPS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/groups-grpc-client.crt} -SMQ_GROUPS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/groups-grpc-client.key} -SMQ_GROUPS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} - -### Clients -SMQ_CLIENTS_LOG_LEVEL=debug -SMQ_CLIENTS_STANDALONE_ID= -SMQ_CLIENTS_STANDALONE_TOKEN= -SMQ_CLIENTS_CACHE_KEY_DURATION=10m -SMQ_CLIENTS_HTTP_HOST=clients -SMQ_CLIENTS_HTTP_PORT=9006 -SMQ_CLIENTS_GRPC_HOST=clients -SMQ_CLIENTS_GRPC_PORT=7006 -SMQ_CLIENTS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/clients-grpc-server.crt}${GRPC_TLS:+./ssl/certs/clients-grpc-server.crt} -SMQ_CLIENTS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/clients-grpc-server.key}${GRPC_TLS:+./ssl/certs/clients-grpc-server.key} -SMQ_CLIENTS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} -SMQ_CLIENTS_CACHE_URL=redis://clients-redis:${SMQ_REDIS_TCP_PORT}/0 -SMQ_CLIENTS_DB_HOST=clients-db -SMQ_CLIENTS_DB_PORT=5432 -SMQ_CLIENTS_DB_USER=supermq -SMQ_CLIENTS_DB_PASS=supermq -SMQ_CLIENTS_DB_NAME=clients -SMQ_CLIENTS_DB_SSL_MODE=disable -SMQ_CLIENTS_DB_SSL_CERT= -SMQ_CLIENTS_DB_SSL_KEY= -SMQ_CLIENTS_DB_SSL_ROOT_CERT= -SMQ_CLIENTS_INSTANCE_ID= - -#### Clients Client Config -SMQ_CLIENTS_URL=http://clients:9006 -SMQ_CLIENTS_GRPC_URL=clients:7006 -SMQ_CLIENTS_GRPC_TIMEOUT=30s -SMQ_CLIENTS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/clients-grpc-client.crt} -SMQ_CLIENTS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/clients-grpc-client.key} -SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} - -### Channels -SMQ_CHANNELS_LOG_LEVEL=debug -SMQ_CHANNELS_HTTP_HOST=channels -SMQ_CHANNELS_HTTP_PORT=9005 -SMQ_CHANNELS_GRPC_HOST=channels -SMQ_CHANNELS_GRPC_PORT=7005 -SMQ_CHANNELS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/channels-grpc-server.crt}${GRPC_TLS:+./ssl/certs/channels-grpc-server.crt} -SMQ_CHANNELS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/channels-grpc-server.key}${GRPC_TLS:+./ssl/certs/channels-grpc-server.key} -SMQ_CHANNELS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} -SMQ_CHANNELS_DB_HOST=channels-db -SMQ_CHANNELS_DB_PORT=5432 -SMQ_CHANNELS_DB_USER=supermq -SMQ_CHANNELS_DB_PASS=supermq -SMQ_CHANNELS_DB_NAME=channels -SMQ_CHANNELS_DB_SSL_MODE=disable -SMQ_CHANNELS_DB_SSL_CERT= -SMQ_CHANNELS_DB_SSL_KEY= -SMQ_CHANNELS_DB_SSL_ROOT_CERT= -SMQ_CHANNELS_INSTANCE_ID= - ### RE MG_RE_LOG_LEVEL=debug MG_RE_HTTP_HOST=re @@ -311,52 +94,10 @@ MG_RE_DB_SSL_KEY= MG_RE_DB_SSL_ROOT_CERT= MG_RE_INSTANCE_ID= -#### Channels Client Config -SMQ_CHANNELS_URL=http://channels:9005 -SMQ_CHANNELS_GRPC_URL=channels:7005 -SMQ_CHANNELS_GRPC_TIMEOUT=30s -SMQ_CHANNELS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/channels-grpc-client.crt} -SMQ_CHANNELS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/channels-grpc-client.key} -SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} +### Certs +SMQ_ADDONS_CERTS_PATH_PREFIX=./ -### HTTP -SMQ_HTTP_ADAPTER_LOG_LEVEL=debug -SMQ_HTTP_ADAPTER_HOST=http-adapter -SMQ_HTTP_ADAPTER_PORT=8008 -SMQ_HTTP_ADAPTER_SERVER_CERT= -SMQ_HTTP_ADAPTER_SERVER_KEY= -SMQ_HTTP_ADAPTER_INSTANCE_ID= - -### MQTT -SMQ_MQTT_ADAPTER_LOG_LEVEL=debug -SMQ_MQTT_ADAPTER_MQTT_PORT=1883 -SMQ_MQTT_ADAPTER_FORWARDER_TIMEOUT=30s -SMQ_MQTT_ADAPTER_WS_PORT=8080 -SMQ_MQTT_ADAPTER_INSTANCE= -SMQ_MQTT_ADAPTER_INSTANCE_ID= -SMQ_MQTT_ADAPTER_ES_DB=0 - -### CoAP -SMQ_COAP_ADAPTER_LOG_LEVEL=debug -SMQ_COAP_ADAPTER_HOST=coap-adapter -SMQ_COAP_ADAPTER_PORT=5683 -SMQ_COAP_ADAPTER_SERVER_CERT= -SMQ_COAP_ADAPTER_SERVER_KEY= -SMQ_COAP_ADAPTER_HTTP_HOST=coap-adapter -SMQ_COAP_ADAPTER_HTTP_PORT=5683 -SMQ_COAP_ADAPTER_HTTP_SERVER_CERT= -SMQ_COAP_ADAPTER_HTTP_SERVER_KEY= -SMQ_COAP_ADAPTER_INSTANCE_ID= - -### WS -SMQ_WS_ADAPTER_LOG_LEVEL=debug -SMQ_WS_ADAPTER_HTTP_HOST=ws-adapter -SMQ_WS_ADAPTER_HTTP_PORT=8186 -SMQ_WS_ADAPTER_HTTP_SERVER_CERT= -SMQ_WS_ADAPTER_HTTP_SERVER_KEY= -SMQ_WS_ADAPTER_INSTANCE_ID= - -## Addons Services +## Addon Services ### Bootstrap MG_BOOTSTRAP_LOG_LEVEL=debug MG_BOOTSTRAP_ENCRYPT_KEY=v7aT0HGxJxt2gULzr3RHwf4WIf6DusPp @@ -399,78 +140,6 @@ MG_PROVISION_CERTS_HOURS_VALID=2400h MG_PROVISION_CERTS_RSA_BITS=2048 MG_PROVISION_INSTANCE_ID= -### Vault -SMQ_VAULT_HOST=vault -SMQ_VAULT_PORT=8200 -SMQ_VAULT_ADDR=http://vault:8200 -SMQ_VAULT_NAMESPACE=supermq -SMQ_VAULT_UNSEAL_KEY_1= -SMQ_VAULT_UNSEAL_KEY_2= -SMQ_VAULT_UNSEAL_KEY_3= -SMQ_VAULT_TOKEN= - -SMQ_VAULT_PKI_PATH=pki -SMQ_VAULT_PKI_ROLE_NAME=supermq_int_ca -SMQ_VAULT_PKI_FILE_NAME=mg_root -SMQ_VAULT_PKI_CA_CN='SuperMQ Root Certificate Authority' -SMQ_VAULT_PKI_CA_OU='SuperMQ' -SMQ_VAULT_PKI_CA_O='SuperMQ' -SMQ_VAULT_PKI_CA_C='FRANCE' -SMQ_VAULT_PKI_CA_L='PARIS' -SMQ_VAULT_PKI_CA_ST='PARIS' -SMQ_VAULT_PKI_CA_ADDR='5 Av. Anatole' -SMQ_VAULT_PKI_CA_PO='75007' -SMQ_VAULT_PKI_CLUSTER_PATH=http://localhost -SMQ_VAULT_PKI_CLUSTER_AIA_PATH=http://localhost - -SMQ_VAULT_PKI_INT_PATH=pki_int -SMQ_VAULT_PKI_INT_SERVER_CERTS_ROLE_NAME=supermq_server_certs -SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME=supermq_clients_certs -SMQ_VAULT_PKI_INT_FILE_NAME=mg_int -SMQ_VAULT_PKI_INT_CA_CN='SuperMQ Intermediate Certificate Authority' -SMQ_VAULT_PKI_INT_CA_OU='SuperMQ' -SMQ_VAULT_PKI_INT_CA_O='SuperMQ' -SMQ_VAULT_PKI_INT_CA_C='FRANCE' -SMQ_VAULT_PKI_INT_CA_L='PARIS' -SMQ_VAULT_PKI_INT_CA_ST='PARIS' -SMQ_VAULT_PKI_INT_CA_ADDR='5 Av. Anatole' -SMQ_VAULT_PKI_INT_CA_PO='75007' -SMQ_VAULT_PKI_INT_CLUSTER_PATH=http://localhost -SMQ_VAULT_PKI_INT_CLUSTER_AIA_PATH=http://localhost - -SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID=supermq -SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET=supermq - -# Certs -SMQ_CERTS_LOG_LEVEL=debug -SMQ_CERTS_SIGN_CA_PATH=/etc/ssl/certs/ca.crt -SMQ_CERTS_SIGN_CA_KEY_PATH=/etc/ssl/certs/ca.key -SMQ_CERTS_VAULT_HOST=${SMQ_VAULT_ADDR} -SMQ_CERTS_VAULT_NAMESPACE=${SMQ_VAULT_NAMESPACE} -SMQ_CERTS_VAULT_APPROLE_ROLEID=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID} -SMQ_CERTS_VAULT_APPROLE_SECRET=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET} -SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH=${SMQ_VAULT_PKI_INT_PATH} -SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME=${SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME} -SMQ_CERTS_HTTP_HOST=certs -SMQ_CERTS_HTTP_PORT=9019 -SMQ_CERTS_HTTP_SERVER_CERT= -SMQ_CERTS_HTTP_SERVER_KEY= -SMQ_CERTS_GRPC_HOST= -SMQ_CERTS_GRPC_PORT= -SMQ_CERTS_DB_HOST=am-certs-db -SMQ_CERTS_DB_PORT=5432 -SMQ_CERTS_DB_USER=supermq -SMQ_CERTS_DB_PASS=supermq -SMQ_CERTS_DB_NAME=certs -SMQ_CERTS_DB_SSL_MODE= -SMQ_CERTS_DB_SSL_CERT= -SMQ_CERTS_DB_SSL_KEY= -SMQ_CERTS_DB_SSL_ROOT_CERT= -SMQ_CERTS_INSTANCE_ID= -SMQ_CERTS_SDK_HOST=http://supermq-am-certs -SMQ_CERTS_SDK_CERTS_URL=${SMQ_CERTS_SDK_HOST}:9010 -SMQ_CERTS_SDK_TLS_VERIFICATION=false - ### Postgres SMQ_POSTGRES_HOST=supermq-postgres SMQ_POSTGRES_PORT=5432 @@ -527,23 +196,6 @@ MG_TIMESCALE_READER_HTTP_SERVER_CERT= MG_TIMESCALE_READER_HTTP_SERVER_KEY= MG_TIMESCALE_READER_INSTANCE_ID= -### Journal -SMQ_JOURNAL_LOG_LEVEL=info -SMQ_JOURNAL_HTTP_HOST=journal -SMQ_JOURNAL_HTTP_PORT=9021 -SMQ_JOURNAL_HTTP_SERVER_CERT= -SMQ_JOURNAL_HTTP_SERVER_KEY= -SMQ_JOURNAL_DB_HOST=journal-db -SMQ_JOURNAL_DB_PORT=5432 -SMQ_JOURNAL_DB_USER=supermq -SMQ_JOURNAL_DB_PASS=supermq -SMQ_JOURNAL_DB_NAME=journal -SMQ_JOURNAL_DB_SSL_MODE=disable -SMQ_JOURNAL_DB_SSL_CERT= -SMQ_JOURNAL_DB_SSL_KEY= -SMQ_JOURNAL_DB_SSL_ROOT_CERT= -SMQ_JOURNAL_INSTANCE_ID= - ### GRAFANA and PROMETHEUS SMQ_PROMETHEUS_PORT=9090 SMQ_GRAFANA_PORT=3000 @@ -622,5 +274,5 @@ SUPPORT_EMAIL_PASS= MG_RELEASE_TAG=latest # runtime environment -RUNTIME_ENV=production # to be changed to production before production deployment +RUNTIME_ENV=production # to be changed to production before production deployment MG_UI_DOCKER_ACCEPT_EULA=false diff --git a/docker/addons/certs/docker-compose.yml b/docker/addons/certs/docker-compose.yml deleted file mode 100644 index e67065ab1..000000000 --- a/docker/addons/certs/docker-compose.yml +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (c) Abstract Machines -# SPDX-License-Identifier: Apache-2.0 - -# This docker-compose file contains optional certs services. Since it's optional, this file is -# dependent of docker-compose file from /docker. In order to run this services, execute command: -# docker compose -f docker/docker-compose.yml -f docker/addons/certs/docker-compose.yml up -# from project root. - -networks: - magistrala-base-net: - -volumes: - magistrala-certs-db-volume: - -services: - certs: - image: ghcr.io/absmach/magistrala/certs:${MG_RELEASE_TAG} - container_name: magistrala-certs - depends_on: - - am-certs - restart: on-failure - networks: - - magistrala-base-net - ports: - - ${MG_CERTS_HTTP_PORT}:${MG_CERTS_HTTP_PORT} - environment: - MG_CERTS_LOG_LEVEL: ${MG_CERTS_LOG_LEVEL} - MG_CERTS_SIGN_CA_PATH: ${MG_CERTS_SIGN_CA_PATH} - MG_CERTS_SIGN_CA_KEY_PATH: ${MG_CERTS_SIGN_CA_KEY_PATH} - MG_CERTS_VAULT_HOST: ${MG_CERTS_VAULT_HOST} - MG_CERTS_VAULT_NAMESPACE: ${MG_CERTS_VAULT_NAMESPACE} - MG_CERTS_VAULT_APPROLE_ROLEID: ${MG_CERTS_VAULT_APPROLE_ROLEID} - MG_CERTS_VAULT_APPROLE_SECRET: ${MG_CERTS_VAULT_APPROLE_SECRET} - MG_CERTS_VAULT_THINGS_CERTS_PKI_PATH: ${MG_CERTS_VAULT_THINGS_CERTS_PKI_PATH} - MG_CERTS_VAULT_THINGS_CERTS_PKI_ROLE_NAME: ${MG_CERTS_VAULT_THINGS_CERTS_PKI_ROLE_NAME} - MG_CERTS_HTTP_HOST: ${MG_CERTS_HTTP_HOST} - MG_CERTS_HTTP_PORT: ${MG_CERTS_HTTP_PORT} - MG_CERTS_HTTP_SERVER_CERT: ${MG_CERTS_HTTP_SERVER_CERT} - MG_CERTS_HTTP_SERVER_KEY: ${MG_CERTS_HTTP_SERVER_KEY} - MG_CERTS_DB_HOST: ${MG_CERTS_DB_HOST} - MG_CERTS_DB_PORT: ${MG_CERTS_DB_PORT} - MG_CERTS_DB_PASS: ${MG_CERTS_DB_PASS} - MG_CERTS_DB_USER: ${MG_CERTS_DB_USER} - MG_CERTS_DB_NAME: ${MG_CERTS_DB_NAME} - MG_CERTS_DB_SSL_MODE: ${MG_CERTS_DB_SSL_MODE} - MG_CERTS_DB_SSL_CERT: ${MG_CERTS_DB_SSL_CERT} - MG_CERTS_DB_SSL_KEY: ${MG_CERTS_DB_SSL_KEY} - MG_CERTS_DB_SSL_ROOT_CERT: ${MG_CERTS_DB_SSL_ROOT_CERT} - MG_CERTS_SDK_HOST: ${MG_CERTS_SDK_HOST} - MG_CERTS_SDK_CERTS_URL: ${MG_CERTS_SDK_CERTS_URL} - MG_CERTS_SDK_TLS_VERIFICATION: ${MG_CERTS_SDK_TLS_VERIFICATION} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - MG_THINGS_URL: ${MG_THINGS_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - MG_CERTS_INSTANCE_ID: ${MG_CERTS_INSTANCE_ID} - volumes: - - ../../ssl/certs/ca.key:/etc/ssl/certs/ca.key - - ../../ssl/certs/ca.crt:/etc/ssl/certs/ca.crt - - type: bind - source: ${MG_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_CLIENT_CERT:-./ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${MG_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_CLIENT_KEY:-./ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${MG_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-./ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - am-certs-db: - image: postgres:16.2-alpine - container_name: magistrala-am-certs-db - restart: on-failure - networks: - - magistrala-base-net - command: postgres -c "max_connections=${MG_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${MG_CERTS_DB_USER} - POSTGRES_PASSWORD: ${MG_CERTS_DB_PASS} - POSTGRES_DB: ${MG_CERTS_DB_NAME} - ports: - - 5454:5432 - volumes: - - magistrala-certs-db-volume:/var/lib/postgresql/data - - am-certs: - image: ghcr.io/absmach/certs:${MG_RELEASE_TAG} - container_name: magistrala-am-certs - depends_on: - - am-certs-db - restart: on-failure - networks: - - magistrala-base-net - environment: - AM_CERTS_LOG_LEVEL: ${MG_CERTS_LOG_LEVEL} - AM_CERTS_DB_HOST: ${MG_CERTS_DB_HOST} - AM_CERTS_DB_PORT: ${MG_CERTS_DB_PORT} - AM_CERTS_DB_USER: ${MG_CERTS_DB_USER} - AM_CERTS_DB_PASS: ${MG_CERTS_DB_PASS} - AM_CERTS_DB: ${MG_CERTS_DB_NAME} - AM_CERTS_DB_SSL_MODE: ${MG_CERTS_DB_SSL_MODE} - AM_CERTS_HTTP_HOST: magistrala-am-certs - AM_CERTS_HTTP_PORT: 9010 - AM_CERTS_GRPC_HOST: magistrala-am-certs - AM_CERTS_GRPC_PORT: 7012 - AM_JAEGER_URL: ${SMQ_JAEGER_URL} - AM_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - volumes: - - ./config.yml:/config/config.yml - ports: - - 9010:9010 - - 7012:7012 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 64f7fd028..732b1416b 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,1293 +1,29 @@ # Copyright (c) Abstract Machines # SPDX-License-Identifier: Apache-2.0 -name: "supermq" +name: "magistrala" + +include: + - path: + - ./supermq-docker/docker-compose.yml + - ./supermq-docker/addons/journal/docker-compose.yml + - ./supermq-docker/addons/certs/docker-compose.yml + - ./supermq-docker-compose.override.yml + project_directory: ./supermq-docker + env_file: + - ./supermq-docker/.env networks: magistrala-base-net: driver: bridge volumes: - magistrala-users-db-volume: - magistrala-groups-db-volume: - magistrala-clients-db-volume: - magistrala-channels-db-volume: - magistrala-clients-redis-volume: - magistrala-broker-volume: - magistrala-spicedb-db-volume: - magistrala-auth-db-volume: - magistrala-domains-db-volume: - magistrala-domains-redis-volume: magistrala-journal-volume: magistrala-ui-backend-db-volume: magistrala-re-db-volume: magistrala-auth-redis-volume: services: - spicedb: - image: "authzed/spicedb:v1.37.0" - container_name: magistrala-spicedb - command: "serve" - restart: "always" - networks: - - magistrala-base-net - ports: - - "8080:8080" - - "9091:9090" - - "50051:50051" - environment: - SPICEDB_GRPC_PRESHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SPICEDB_DATASTORE_ENGINE: ${SMQ_SPICEDB_DATASTORE_ENGINE} - SPICEDB_DATASTORE_CONN_URI: "${SMQ_SPICEDB_DATASTORE_ENGINE}://${SMQ_SPICEDB_DB_USER}:${SMQ_SPICEDB_DB_PASS}@spicedb-db:${SMQ_SPICEDB_DB_PORT}/${SMQ_SPICEDB_DB_NAME}?sslmode=disable" - depends_on: - - spicedb-migrate - - spicedb-migrate: - image: "authzed/spicedb:v1.37.0" - container_name: magistrala-spicedb-migrate - command: "migrate head" - restart: "on-failure" - networks: - - magistrala-base-net - environment: - SPICEDB_DATASTORE_ENGINE: ${SMQ_SPICEDB_DATASTORE_ENGINE} - SPICEDB_DATASTORE_CONN_URI: "${SMQ_SPICEDB_DATASTORE_ENGINE}://${SMQ_SPICEDB_DB_USER}:${SMQ_SPICEDB_DB_PASS}@spicedb-db:${SMQ_SPICEDB_DB_PORT}/${SMQ_SPICEDB_DB_NAME}?sslmode=disable" - depends_on: - - spicedb-db - - spicedb-db: - image: "postgres:16.2-alpine" - container_name: magistrala-spicedb-db - networks: - - magistrala-base-net - ports: - - "6010:5432" - environment: - POSTGRES_USER: ${SMQ_SPICEDB_DB_USER} - POSTGRES_PASSWORD: ${SMQ_SPICEDB_DB_PASS} - POSTGRES_DB: ${SMQ_SPICEDB_DB_NAME} - volumes: - - magistrala-spicedb-db-volume:/var/lib/postgresql/data - command: ["postgres", "-c", "track_commit_timestamp=on"] - - auth-db: - image: postgres:16.2-alpine - container_name: magistrala-auth-db - restart: on-failure - ports: - - 6001:5432 - environment: - POSTGRES_USER: ${SMQ_AUTH_DB_USER} - POSTGRES_PASSWORD: ${SMQ_AUTH_DB_PASS} - POSTGRES_DB: ${SMQ_AUTH_DB_NAME} - networks: - - magistrala-base-net - volumes: - - magistrala-auth-db-volume:/var/lib/postgresql/data - - auth-redis: - image: redis:7.2.4-alpine - container_name: magistrala-auth-redis - restart: on-failure - networks: - - magistrala-base-net - volumes: - - magistrala-auth-redis-volume:/data - - auth: - image: supermq/auth:${MG_RELEASE_TAG} - container_name: magistrala-auth - depends_on: - - auth-db - - spicedb - expose: - - ${SMQ_AUTH_GRPC_PORT} - restart: on-failure - environment: - SMQ_AUTH_LOG_LEVEL: ${SMQ_AUTH_LOG_LEVEL} - SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - SMQ_AUTH_ACCESS_TOKEN_DURATION: ${SMQ_AUTH_ACCESS_TOKEN_DURATION} - SMQ_AUTH_REFRESH_TOKEN_DURATION: ${SMQ_AUTH_REFRESH_TOKEN_DURATION} - SMQ_AUTH_INVITATION_DURATION: ${SMQ_AUTH_INVITATION_DURATION} - SMQ_AUTH_SECRET_KEY: ${SMQ_AUTH_SECRET_KEY} - SMQ_AUTH_HTTP_HOST: ${SMQ_AUTH_HTTP_HOST} - SMQ_AUTH_HTTP_PORT: ${SMQ_AUTH_HTTP_PORT} - SMQ_AUTH_HTTP_SERVER_CERT: ${SMQ_AUTH_HTTP_SERVER_CERT} - SMQ_AUTH_HTTP_SERVER_KEY: ${SMQ_AUTH_HTTP_SERVER_KEY} - SMQ_AUTH_GRPC_HOST: ${SMQ_AUTH_GRPC_HOST} - SMQ_AUTH_GRPC_PORT: ${SMQ_AUTH_GRPC_PORT} - ## Compose supports parameter expansion in environment, - ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty - ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default - SMQ_AUTH_GRPC_SERVER_CERT: ${SMQ_AUTH_GRPC_SERVER_CERT:+/auth-grpc-server.crt} - SMQ_AUTH_GRPC_SERVER_KEY: ${SMQ_AUTH_GRPC_SERVER_KEY:+/auth-grpc-server.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_AUTH_GRPC_CLIENT_CA_CERTS: ${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:+/auth-grpc-client-ca.crt} - SMQ_AUTH_DB_HOST: ${SMQ_AUTH_DB_HOST} - SMQ_AUTH_DB_PORT: ${SMQ_AUTH_DB_PORT} - SMQ_AUTH_DB_USER: ${SMQ_AUTH_DB_USER} - SMQ_AUTH_DB_PASS: ${SMQ_AUTH_DB_PASS} - SMQ_AUTH_DB_NAME: ${SMQ_AUTH_DB_NAME} - SMQ_AUTH_DB_SSL_MODE: ${SMQ_AUTH_DB_SSL_MODE} - SMQ_AUTH_DB_SSL_CERT: ${SMQ_AUTH_DB_SSL_CERT} - SMQ_AUTH_DB_SSL_KEY: ${SMQ_AUTH_DB_SSL_KEY} - SMQ_AUTH_DB_SSL_ROOT_CERT: ${SMQ_AUTH_DB_SSL_ROOT_CERT} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_AUTH_ADAPTER_INSTANCE_ID: ${SMQ_AUTH_ADAPTER_INSTANCE_ID} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_AUTH_CACHE_URL: ${SMQ_AUTH_CACHE_URL} - SMQ_AUTH_CACHE_KEY_DURATION: ${SMQ_AUTH_CACHE_KEY_DURATION} - ports: - - ${SMQ_AUTH_HTTP_PORT}:${SMQ_AUTH_HTTP_PORT} - - ${SMQ_AUTH_GRPC_PORT}:${SMQ_AUTH_GRPC_PORT} - networks: - - magistrala-base-net - volumes: - - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - # Auth gRPC mTLS server certificates - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} - target: /auth-grpc-server${SMQ_AUTH_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} - target: /auth-grpc-server${SMQ_AUTH_GRPC_SERVER_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} - target: /auth-grpc-client-ca${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:+.crt} - bind: - create_host_path: true - - domains-db: - image: postgres:16.2-alpine - container_name: magistrala-domains-db - restart: on-failure - ports: - - 6003:5432 - environment: - POSTGRES_USER: ${SMQ_DOMAINS_DB_USER} - POSTGRES_PASSWORD: ${SMQ_DOMAINS_DB_PASS} - POSTGRES_DB: ${SMQ_DOMAINS_DB_NAME} - networks: - - magistrala-base-net - volumes: - - magistrala-domains-db-volume:/var/lib/postgresql/data - - domains-redis: - image: redis:7.2.4-alpine - container_name: magistrala-domains-redis - restart: on-failure - networks: - - magistrala-base-net - volumes: - - magistrala-domains-redis-volume:/data - - domains: - image: supermq/domains:${MG_RELEASE_TAG} - container_name: magistrala-domains - depends_on: - - domains-db - - spicedb - expose: - - ${SMQ_DOMAINS_GRPC_PORT} - restart: on-failure - environment: - SMQ_DOMAINS_LOG_LEVEL: ${SMQ_DOMAINS_LOG_LEVEL} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} - SMQ_DOMAINS_HTTP_HOST: ${SMQ_DOMAINS_HTTP_HOST} - SMQ_DOMAINS_HTTP_PORT: ${SMQ_DOMAINS_HTTP_PORT} - SMQ_DOMAINS_HTTP_SERVER_CERT: ${SMQ_DOMAINS_HTTP_SERVER_CERT} - SMQ_DOMAINS_HTTP_SERVER_KEY: ${SMQ_DOMAINS_HTTP_SERVER_KEY} - SMQ_DOMAINS_GRPC_HOST: ${SMQ_DOMAINS_GRPC_HOST} - SMQ_DOMAINS_GRPC_PORT: ${SMQ_DOMAINS_GRPC_PORT} - ## Compose supports parameter expansion in environment, - ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty - ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default - SMQ_DOMAINS_GRPC_SERVER_CERT: ${SMQ_DOMAINS_GRPC_SERVER_CERT:+/auth-grpc-server.crt} - SMQ_DOMAINS_GRPC_SERVER_KEY: ${SMQ_DOMAINS_GRPC_SERVER_KEY:+/auth-grpc-server.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS: ${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:+/auth-grpc-client-ca.crt} - SMQ_DOMAINS_DB_HOST: ${SMQ_DOMAINS_DB_HOST} - SMQ_DOMAINS_DB_PORT: ${SMQ_DOMAINS_DB_PORT} - SMQ_DOMAINS_DB_USER: ${SMQ_DOMAINS_DB_USER} - SMQ_DOMAINS_DB_PASS: ${SMQ_DOMAINS_DB_PASS} - SMQ_DOMAINS_DB_NAME: ${SMQ_DOMAINS_DB_NAME} - SMQ_DOMAINS_DB_SSL_MODE: ${SMQ_DOMAINS_DB_SSL_MODE} - SMQ_DOMAINS_DB_SSL_CERT: ${SMQ_DOMAINS_DB_SSL_CERT} - SMQ_DOMAINS_DB_SSL_KEY: ${SMQ_DOMAINS_DB_SSL_KEY} - SMQ_DOMAINS_DB_SSL_ROOT_CERT: ${SMQ_DOMAINS_DB_SSL_ROOT_CERT} - SMQ_DOMAINS_INSTANCE_ID: ${SMQ_DOMAINS_INSTANCE_ID} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_DOMAINS_CACHE_URL: ${SMQ_DOMAINS_CACHE_URL} - SMQ_DOMAINS_CACHE_KEY_DURATION: ${SMQ_DOMAINS_CACHE_KEY_DURATION} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} - SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} - SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} - SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} - SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} - SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - ports: - - ${SMQ_DOMAINS_HTTP_PORT}:${SMQ_DOMAINS_HTTP_PORT} - - ${SMQ_DOMAINS_GRPC_PORT}:${SMQ_DOMAINS_GRPC_PORT} - networks: - - magistrala-base-net - volumes: - - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - # Auth gRPC mTLS server certificates - - type: bind - source: ${SMQ_DOMAINS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} - target: /auth-grpc-server${SMQ_DOMAINS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_DOMAINS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} - target: /auth-grpc-server${SMQ_DOMAINS_GRPC_SERVER_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} - target: /auth-grpc-server-ca${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} - target: /auth-grpc-client-ca${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - nginx: - image: nginx:1.25.4-alpine - container_name: magistrala-nginx - restart: on-failure - volumes: - - ./nginx/nginx-${AUTH-key}.conf:/etc/nginx/nginx.conf.template - - ./nginx/entrypoint.sh:/docker-entrypoint.d/entrypoint.sh - - ./nginx/snippets:/etc/nginx/snippets - - ./ssl/authorization.js:/etc/nginx/authorization.js - - type: bind - source: ${SMQ_NGINX_SERVER_CERT:-./ssl/certs/magistrala-server.crt} - target: /etc/ssl/certs/magistrala-server.crt - - type: bind - source: ${SMQ_NGINX_SERVER_KEY:-./ssl/certs/magistrala-server.key} - target: /etc/ssl/private/magistrala-server.key - - type: bind - source: ${SMQ_NGINX_SERVER_CLIENT_CA:-./ssl/certs/ca.crt} - target: /etc/ssl/certs/ca.crt - - type: bind - source: ${SMQ_NGINX_SERVER_DHPARAM:-./ssl/dhparam.pem} - target: /etc/ssl/certs/dhparam.pem - ports: - - ${SMQ_NGINX_HTTP_PORT}:${SMQ_NGINX_HTTP_PORT} - - ${SMQ_NGINX_SSL_PORT}:${SMQ_NGINX_SSL_PORT} - - ${SMQ_NGINX_MQTT_PORT}:${SMQ_NGINX_MQTT_PORT} - - ${SMQ_NGINX_MQTTS_PORT}:${SMQ_NGINX_MQTTS_PORT} - networks: - - magistrala-base-net - env_file: - - .env - depends_on: - - auth - - clients - - users - - mqtt-adapter - - http-adapter - - ws-adapter - - coap-adapter - - clients-db: - image: postgres:16.2-alpine - container_name: magistrala-clients-db - restart: on-failure - command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${SMQ_CLIENTS_DB_USER} - POSTGRES_PASSWORD: ${SMQ_CLIENTS_DB_PASS} - POSTGRES_DB: ${SMQ_CLIENTS_DB_NAME} - SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} - networks: - - magistrala-base-net - ports: - - 6006:5432 - volumes: - - magistrala-clients-db-volume:/var/lib/postgresql/data - - clients-redis: - image: redis:7.2.4-alpine - container_name: magistrala-clients-redis - restart: on-failure - networks: - - magistrala-base-net - volumes: - - magistrala-clients-redis-volume:/data - - clients: - image: supermq/clients:${MG_RELEASE_TAG} - container_name: magistrala-clients - depends_on: - - clients-db - - users - - auth - - nats - restart: on-failure - environment: - SMQ_CLIENTS_LOG_LEVEL: ${SMQ_CLIENTS_LOG_LEVEL} - SMQ_CLIENTS_STANDALONE_ID: ${SMQ_CLIENTS_STANDALONE_ID} - SMQ_CLIENTS_STANDALONE_TOKEN: ${SMQ_CLIENTS_STANDALONE_TOKEN} - SMQ_CLIENTS_CACHE_KEY_DURATION: ${SMQ_CLIENTS_CACHE_KEY_DURATION} - SMQ_CLIENTS_HTTP_HOST: ${SMQ_CLIENTS_HTTP_HOST} - SMQ_CLIENTS_HTTP_PORT: ${SMQ_CLIENTS_HTTP_PORT} - SMQ_CLIENTS_GRPC_HOST: ${SMQ_CLIENTS_GRPC_HOST} - SMQ_CLIENTS_GRPC_PORT: ${SMQ_CLIENTS_GRPC_PORT} - ## Compose supports parameter expansion in environment, - ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty - ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default - SMQ_CLIENTS_GRPC_SERVER_CERT: ${SMQ_CLIENTS_GRPC_SERVER_CERT:+/clients-grpc-server.crt} - SMQ_CLIENTS_GRPC_SERVER_KEY: ${SMQ_CLIENTS_GRPC_SERVER_KEY:+/clients-grpc-server.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS: ${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:+/clients-grpc-client-ca.crt} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_CLIENTS_CACHE_URL: ${SMQ_CLIENTS_CACHE_URL} - SMQ_CLIENTS_DB_HOST: ${SMQ_CLIENTS_DB_HOST} - SMQ_CLIENTS_DB_PORT: ${SMQ_CLIENTS_DB_PORT} - SMQ_CLIENTS_DB_USER: ${SMQ_CLIENTS_DB_USER} - SMQ_CLIENTS_DB_PASS: ${SMQ_CLIENTS_DB_PASS} - SMQ_CLIENTS_DB_NAME: ${SMQ_CLIENTS_DB_NAME} - SMQ_CLIENTS_DB_SSL_MODE: ${SMQ_CLIENTS_DB_SSL_MODE} - SMQ_CLIENTS_DB_SSL_CERT: ${SMQ_CLIENTS_DB_SSL_CERT} - SMQ_CLIENTS_DB_SSL_KEY: ${SMQ_CLIENTS_DB_SSL_KEY} - SMQ_CLIENTS_DB_SSL_ROOT_CERT: ${SMQ_CLIENTS_DB_SSL_ROOT_CERT} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_GROUPS_URL: ${SMQ_GROUPS_URL} - SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} - SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} - SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} - SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} - SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} - SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} - SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} - SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} - SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} - ports: - - ${SMQ_CLIENTS_HTTP_PORT}:${SMQ_CLIENTS_HTTP_PORT} - - ${SMQ_CLIENTS_GRPC_PORT}:${SMQ_CLIENTS_GRPC_PORT} - networks: - - magistrala-base-net - volumes: - - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - # Clients gRPC server certificates - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} - target: /clients-grpc-server${SMQ_CLIENTS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} - target: /clients-grpc-server${SMQ_CLIENTS_GRPC_SERVER_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} - target: /clients-grpc-client-ca${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:+.crt} - bind: - create_host_path: true - # Auth gRPC client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Channel gRPC client certificates - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Group gRPC client certificates - - type: bind - source: ${SMQ_GROUPS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_GROUPS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_GROUPS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} - target: /groups-grpc-server-ca${SMQ_GROUPS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - channels-db: - image: postgres:16.2-alpine - container_name: magistrala-channels-db - restart: on-failure - command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${SMQ_CHANNELS_DB_USER} - POSTGRES_PASSWORD: ${SMQ_CHANNELS_DB_PASS} - POSTGRES_DB: ${SMQ_CHANNELS_DB_NAME} - SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} - networks: - - magistrala-base-net - ports: - - 6005:5432 - volumes: - - magistrala-channels-db-volume:/var/lib/postgresql/data - - channels: - image: supermq/channels:${MG_RELEASE_TAG} - container_name: magistrala-channels - depends_on: - - channels-db - - users - - auth - - nats - restart: on-failure - environment: - SMQ_CHANNELS_LOG_LEVEL: ${SMQ_CHANNELS_LOG_LEVEL} - SMQ_CHANNELS_INSTANCE_ID: ${SMQ_CHANNELS_INSTANCE_ID} - SMQ_CHANNELS_HTTP_HOST: ${SMQ_CHANNELS_HTTP_HOST} - SMQ_CHANNELS_HTTP_PORT: ${SMQ_CHANNELS_HTTP_PORT} - SMQ_CHANNELS_GRPC_HOST: ${SMQ_CHANNELS_GRPC_HOST} - SMQ_CHANNELS_GRPC_PORT: ${SMQ_CHANNELS_GRPC_PORT} - ## Compose supports parameter expansion in environment, - ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty - ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default - SMQ_CHANNELS_GRPC_SERVER_CERT: ${SMQ_CHANNELS_GRPC_SERVER_CERT:+/channels-grpc-server.crt} - SMQ_CHANNELS_GRPC_SERVER_KEY: ${SMQ_CHANNELS_GRPC_SERVER_KEY:+/channels-grpc-server.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+/channels-grpc-client-ca.crt} - SMQ_CHANNELS_DB_HOST: ${SMQ_CHANNELS_DB_HOST} - SMQ_CHANNELS_DB_PORT: ${SMQ_CHANNELS_DB_PORT} - SMQ_CHANNELS_DB_USER: ${SMQ_CHANNELS_DB_USER} - SMQ_CHANNELS_DB_PASS: ${SMQ_CHANNELS_DB_PASS} - SMQ_CHANNELS_DB_NAME: ${SMQ_CHANNELS_DB_NAME} - SMQ_CHANNELS_DB_SSL_MODE: ${SMQ_CHANNELS_DB_SSL_MODE} - SMQ_CHANNELS_DB_SSL_CERT: ${SMQ_CHANNELS_DB_SSL_CERT} - SMQ_CHANNELS_DB_SSL_KEY: ${SMQ_CHANNELS_DB_SSL_KEY} - SMQ_CHANNELS_DB_SSL_ROOT_CERT: ${SMQ_CHANNELS_DB_SSL_ROOT_CERT} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} - SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} - SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} - SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} - SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} - SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} - SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} - SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} - SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} - ports: - - ${SMQ_CHANNELS_HTTP_PORT}:${SMQ_CHANNELS_HTTP_PORT} - - ${SMQ_CHANNELS_GRPC_PORT}:${SMQ_CHANNELS_GRPC_PORT} - networks: - - magistrala-base-net - volumes: - - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - # Auth gRPC client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_GROUPS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_GROUPS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_GROUPS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} - target: /groups-grpc-server-ca${SMQ_GROUPS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server${SMQ_CHANNELS_GRPC_SERVER_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} - target: /channels-grpc-server${SMQ_CHANNELS_GRPC_SERVER_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca} - target: /channels-grpc-client-ca${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+.crt} - bind: - create_host_path: true - - users-db: - image: postgres:16.2-alpine - container_name: magistrala-users-db - restart: on-failure - command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${SMQ_USERS_DB_USER} - POSTGRES_PASSWORD: ${SMQ_USERS_DB_PASS} - POSTGRES_DB: ${SMQ_USERS_DB_NAME} - SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} - ports: - - 6002:5432 - networks: - - magistrala-base-net - volumes: - - magistrala-users-db-volume:/var/lib/postgresql/data - - users: - image: supermq/users:${MG_RELEASE_TAG} - container_name: magistrala-users - depends_on: - - users-db - - auth - - nats - restart: on-failure - environment: - SMQ_USERS_LOG_LEVEL: ${SMQ_USERS_LOG_LEVEL} - SMQ_USERS_SECRET_KEY: ${SMQ_USERS_SECRET_KEY} - SMQ_USERS_ADMIN_EMAIL: ${SMQ_USERS_ADMIN_EMAIL} - SMQ_USERS_ADMIN_PASSWORD: ${SMQ_USERS_ADMIN_PASSWORD} - SMQ_USERS_ADMIN_USERNAME: ${SMQ_USERS_ADMIN_USERNAME} - SMQ_USERS_ADMIN_FIRST_NAME: ${SMQ_USERS_ADMIN_FIRST_NAME} - SMQ_USERS_ADMIN_LAST_NAME: ${SMQ_USERS_ADMIN_LAST_NAME} - SMQ_USERS_PASS_REGEX: ${SMQ_USERS_PASS_REGEX} - SMQ_USERS_ACCESS_TOKEN_DURATION: ${SMQ_USERS_ACCESS_TOKEN_DURATION} - SMQ_USERS_REFRESH_TOKEN_DURATION: ${SMQ_USERS_REFRESH_TOKEN_DURATION} - SMQ_TOKEN_RESET_ENDPOINT: ${SMQ_TOKEN_RESET_ENDPOINT} - SMQ_USERS_HTTP_HOST: ${SMQ_USERS_HTTP_HOST} - SMQ_USERS_HTTP_PORT: ${SMQ_USERS_HTTP_PORT} - SMQ_USERS_HTTP_SERVER_CERT: ${SMQ_USERS_HTTP_SERVER_CERT} - SMQ_USERS_HTTP_SERVER_KEY: ${SMQ_USERS_HTTP_SERVER_KEY} - SMQ_USERS_DB_HOST: ${SMQ_USERS_DB_HOST} - SMQ_USERS_DB_PORT: ${SMQ_USERS_DB_PORT} - SMQ_USERS_DB_USER: ${SMQ_USERS_DB_USER} - SMQ_USERS_DB_PASS: ${SMQ_USERS_DB_PASS} - SMQ_USERS_DB_NAME: ${SMQ_USERS_DB_NAME} - SMQ_USERS_DB_SSL_MODE: ${SMQ_USERS_DB_SSL_MODE} - SMQ_USERS_DB_SSL_CERT: ${SMQ_USERS_DB_SSL_CERT} - SMQ_USERS_DB_SSL_KEY: ${SMQ_USERS_DB_SSL_KEY} - SMQ_USERS_DB_SSL_ROOT_CERT: ${SMQ_USERS_DB_SSL_ROOT_CERT} - SMQ_USERS_ALLOW_SELF_REGISTER: ${SMQ_USERS_ALLOW_SELF_REGISTER} - SMQ_EMAIL_HOST: ${SMQ_EMAIL_HOST} - SMQ_EMAIL_PORT: ${SMQ_EMAIL_PORT} - SMQ_EMAIL_USERNAME: ${SMQ_EMAIL_USERNAME} - SMQ_EMAIL_PASSWORD: ${SMQ_EMAIL_PASSWORD} - SMQ_EMAIL_FROM_ADDRESS: ${SMQ_EMAIL_FROM_ADDRESS} - SMQ_EMAIL_FROM_NAME: ${SMQ_EMAIL_FROM_NAME} - SMQ_EMAIL_TEMPLATE: ${SMQ_EMAIL_TEMPLATE} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} - SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} - SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} - SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} - SMQ_GOOGLE_CLIENT_ID: ${SMQ_GOOGLE_CLIENT_ID} - SMQ_GOOGLE_CLIENT_SECRET: ${SMQ_GOOGLE_CLIENT_SECRET} - SMQ_GOOGLE_REDIRECT_URL: ${SMQ_GOOGLE_REDIRECT_URL} - SMQ_GOOGLE_STATE: ${SMQ_GOOGLE_STATE} - SMQ_OAUTH_UI_REDIRECT_URL: ${SMQ_OAUTH_UI_REDIRECT_URL} - SMQ_OAUTH_UI_ERROR_URL: ${SMQ_OAUTH_UI_ERROR_URL} - SMQ_USERS_DELETE_INTERVAL: ${SMQ_USERS_DELETE_INTERVAL} - SMQ_USERS_DELETE_AFTER: ${SMQ_USERS_DELETE_AFTER} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - ports: - - ${SMQ_USERS_HTTP_PORT}:${SMQ_USERS_HTTP_PORT} - networks: - - magistrala-base-net - volumes: - - ./templates/${SMQ_USERS_RESET_PWD_TEMPLATE}:/email.tmpl - # Auth gRPC client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - groups-db: - image: postgres:16.2-alpine - container_name: magistrala-groups-db - restart: on-failure - command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${SMQ_GROUPS_DB_USER} - POSTGRES_PASSWORD: ${SMQ_GROUPS_DB_PASS} - POSTGRES_DB: ${SMQ_GROUPS_DB_NAME} - SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} - ports: - - 6004:5432 - networks: - - magistrala-base-net - volumes: - - magistrala-groups-db-volume:/var/lib/postgresql/data - - groups: - image: supermq/groups:${MG_RELEASE_TAG} - container_name: magistrala-groups - depends_on: - - groups-db - - auth - - nats - restart: on-failure - environment: - SMQ_GROUPS_LOG_LEVEL: ${SMQ_GROUPS_LOG_LEVEL} - SMQ_GROUPS_HTTP_HOST: ${SMQ_GROUPS_HTTP_HOST} - SMQ_GROUPS_HTTP_PORT: ${SMQ_GROUPS_HTTP_PORT} - SMQ_GROUPS_HTTP_SERVER_CERT: ${SMQ_GROUPS_HTTP_SERVER_CERT} - SMQ_GROUPS_HTTP_SERVER_KEY: ${SMQ_GROUPS_HTTP_SERVER_KEY} - SMQ_GROUPS_GRPC_HOST: ${SMQ_GROUPS_GRPC_HOST} - SMQ_GROUPS_GRPC_PORT: ${SMQ_GROUPS_GRPC_PORT} - ## Compose supports parameter expansion in environment, - ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty - ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default - SMQ_GROUPS_GRPC_SERVER_CERT: ${SMQ_GROUPS_GRPC_SERVER_CERT:+/groups-grpc-server.crt} - SMQ_GROUPS_GRPC_SERVER_KEY: ${SMQ_GROUPS_GRPC_SERVER_KEY:+/groups-grpc-server.key} - SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} - SMQ_GROUPS_GRPC_CLIENT_CA_CERTS: ${SMQ_GROUPS_GRPC_CLIENT_CA_CERTS:+/groups-grpc-client-ca.crt} - SMQ_GROUPS_DB_HOST: ${SMQ_GROUPS_DB_HOST} - SMQ_GROUPS_DB_PORT: ${SMQ_GROUPS_DB_PORT} - SMQ_GROUPS_DB_USER: ${SMQ_GROUPS_DB_USER} - SMQ_GROUPS_DB_PASS: ${SMQ_GROUPS_DB_PASS} - SMQ_GROUPS_DB_NAME: ${SMQ_GROUPS_DB_NAME} - SMQ_GROUPS_DB_SSL_MODE: ${SMQ_GROUPS_DB_SSL_MODE} - SMQ_GROUPS_DB_SSL_CERT: ${SMQ_GROUPS_DB_SSL_CERT} - SMQ_GROUPS_DB_SSL_KEY: ${SMQ_GROUPS_DB_SSL_KEY} - SMQ_GROUPS_DB_SSL_ROOT_CERT: ${SMQ_GROUPS_DB_SSL_ROOT_CERT} - SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} - SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} - SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} - SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} - SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} - SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} - SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} - ports: - - ${SMQ_GROUPS_HTTP_PORT}:${SMQ_GROUPS_HTTP_PORT} - - ${SMQ_GROUPS_GRPC_PORT}:${SMQ_GROUPS_GRPC_PORT} - networks: - - magistrala-base-net - volumes: - - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - # Auth gRPC client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - jaeger: - image: jaegertracing/all-in-one:1.60 - container_name: magistrala-jaeger - environment: - COLLECTOR_OTLP_ENABLED: ${SMQ_JAEGER_COLLECTOR_OTLP_ENABLED} - command: --memory.max-traces ${SMQ_JAEGER_MEMORY_MAX_TRACES} - ports: - - ${SMQ_JAEGER_FRONTEND}:${SMQ_JAEGER_FRONTEND} - - ${SMQ_JAEGER_OLTP_HTTP}:${SMQ_JAEGER_OLTP_HTTP} - networks: - - magistrala-base-net - - mqtt-adapter: - image: supermq/mqtt:${MG_RELEASE_TAG} - container_name: magistrala-mqtt - depends_on: - - clients - - nats - restart: on-failure - environment: - SMQ_MQTT_ADAPTER_LOG_LEVEL: ${SMQ_MQTT_ADAPTER_LOG_LEVEL} - SMQ_MQTT_ADAPTER_MQTT_PORT: ${SMQ_MQTT_ADAPTER_MQTT_PORT} - SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST} - SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT} - SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK} - SMQ_MQTT_ADAPTER_WS_PORT: ${SMQ_MQTT_ADAPTER_WS_PORT} - SMQ_MQTT_ADAPTER_INSTANCE_ID: ${SMQ_MQTT_ADAPTER_INSTANCE_ID} - SMQ_MQTT_ADAPTER_WS_TARGET_HOST: ${SMQ_MQTT_ADAPTER_WS_TARGET_HOST} - SMQ_MQTT_ADAPTER_WS_TARGET_PORT: ${SMQ_MQTT_ADAPTER_WS_TARGET_PORT} - SMQ_MQTT_ADAPTER_INSTANCE: ${SMQ_MQTT_ADAPTER_INSTANCE} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - networks: - - magistrala-base-net - volumes: - # Clients gRPC mTLS client certificates - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Channels gRPC mTLS client certificates - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - http-adapter: - image: supermq/http:${MG_RELEASE_TAG} - container_name: magistrala-http - depends_on: - - clients - - nats - restart: on-failure - environment: - SMQ_HTTP_ADAPTER_LOG_LEVEL: ${SMQ_HTTP_ADAPTER_LOG_LEVEL} - SMQ_HTTP_ADAPTER_HOST: ${SMQ_HTTP_ADAPTER_HOST} - SMQ_HTTP_ADAPTER_PORT: ${SMQ_HTTP_ADAPTER_PORT} - SMQ_HTTP_ADAPTER_SERVER_CERT: ${SMQ_HTTP_ADAPTER_SERVER_CERT} - SMQ_HTTP_ADAPTER_SERVER_KEY: ${SMQ_HTTP_ADAPTER_SERVER_KEY} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_HTTP_ADAPTER_INSTANCE_ID: ${SMQ_HTTP_ADAPTER_INSTANCE_ID} - SMQ_ES_URL: ${SMQ_ES_URL} - ports: - - ${SMQ_HTTP_ADAPTER_PORT}:${SMQ_HTTP_ADAPTER_PORT} - networks: - - magistrala-base-net - volumes: - # Clients gRPC mTLS client certificates - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Channels gRPC mTLS client certificates - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Auth gRPC mTLS client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - coap-adapter: - image: supermq/coap:${MG_RELEASE_TAG} - container_name: magistrala-coap - depends_on: - - clients - - nats - restart: on-failure - environment: - SMQ_COAP_ADAPTER_LOG_LEVEL: ${SMQ_COAP_ADAPTER_LOG_LEVEL} - SMQ_COAP_ADAPTER_HOST: ${SMQ_COAP_ADAPTER_HOST} - SMQ_COAP_ADAPTER_PORT: ${SMQ_COAP_ADAPTER_PORT} - SMQ_COAP_ADAPTER_SERVER_CERT: ${SMQ_COAP_ADAPTER_SERVER_CERT} - SMQ_COAP_ADAPTER_SERVER_KEY: ${SMQ_COAP_ADAPTER_SERVER_KEY} - SMQ_COAP_ADAPTER_HTTP_HOST: ${SMQ_COAP_ADAPTER_HTTP_HOST} - SMQ_COAP_ADAPTER_HTTP_PORT: ${SMQ_COAP_ADAPTER_HTTP_PORT} - SMQ_COAP_ADAPTER_HTTP_SERVER_CERT: ${SMQ_COAP_ADAPTER_HTTP_SERVER_CERT} - SMQ_COAP_ADAPTER_HTTP_SERVER_KEY: ${SMQ_COAP_ADAPTER_HTTP_SERVER_KEY} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_COAP_ADAPTER_INSTANCE_ID: ${SMQ_COAP_ADAPTER_INSTANCE_ID} - SMQ_ES_URL: ${SMQ_ES_URL} - ports: - - ${SMQ_COAP_ADAPTER_PORT}:${SMQ_COAP_ADAPTER_PORT}/udp - - ${SMQ_COAP_ADAPTER_HTTP_PORT}:${SMQ_COAP_ADAPTER_HTTP_PORT}/tcp - networks: - - magistrala-base-net - volumes: - # Clients gRPC mTLS client certificates - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Channels gRPC mTLS client certificates - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca} - target: /channels-grpc-client-ca${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+.crt} - bind: - create_host_path: true - - ws-adapter: - image: supermq/ws:${MG_RELEASE_TAG} - container_name: magistrala-ws - depends_on: - - clients - - nats - restart: on-failure - environment: - SMQ_WS_ADAPTER_LOG_LEVEL: ${SMQ_WS_ADAPTER_LOG_LEVEL} - SMQ_WS_ADAPTER_HTTP_HOST: ${SMQ_WS_ADAPTER_HTTP_HOST} - SMQ_WS_ADAPTER_HTTP_PORT: ${SMQ_WS_ADAPTER_HTTP_PORT} - SMQ_WS_ADAPTER_HTTP_SERVER_CERT: ${SMQ_WS_ADAPTER_HTTP_SERVER_CERT} - SMQ_WS_ADAPTER_HTTP_SERVER_KEY: ${SMQ_WS_ADAPTER_HTTP_SERVER_KEY} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_WS_ADAPTER_INSTANCE_ID: ${SMQ_WS_ADAPTER_INSTANCE_ID} - SMQ_ES_URL: ${SMQ_ES_URL} - ports: - - ${SMQ_WS_ADAPTER_HTTP_PORT}:${SMQ_WS_ADAPTER_HTTP_PORT} - networks: - - magistrala-base-net - volumes: - # Clients gRPC mTLS client certificates - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Channels gRPC mTLS client certificates - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - # Auth gRPC mTLS client certificates - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} - target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} - bind: - create_host_path: true - - type: bind - source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} - target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} - bind: - create_host_path: true - - nats: - image: nats:2.10.9-alpine - container_name: magistrala-nats - restart: on-failure - command: "--config=/etc/nats/nats.conf" - environment: - - SMQ_NATS_PORT=${SMQ_NATS_PORT} - - SMQ_NATS_HTTP_PORT=${SMQ_NATS_HTTP_PORT} - - SMQ_NATS_JETSTREAM_KEY=${SMQ_NATS_JETSTREAM_KEY} - ports: - - ${SMQ_NATS_PORT}:${SMQ_NATS_PORT} - - ${SMQ_NATS_HTTP_PORT}:${SMQ_NATS_HTTP_PORT} - volumes: - - magistrala-broker-volume:/data - - ./nats:/etc/nats - networks: - - magistrala-base-net - - journal-db: - image: postgres:16.2-alpine - container_name: magistrala-journal-db - restart: on-failure - command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" - environment: - POSTGRES_USER: ${SMQ_JOURNAL_DB_USER} - POSTGRES_PASSWORD: ${SMQ_JOURNAL_DB_PASS} - POSTGRES_DB: ${SMQ_JOURNAL_DB_NAME} - SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} - networks: - - magistrala-base-net - volumes: - - magistrala-journal-volume:/var/lib/postgresql/data - - journal: - image: supermq/journal:${MG_RELEASE_TAG} - container_name: magistrala-journal - depends_on: - - journal-db - restart: on-failure - environment: - SMQ_JOURNAL_LOG_LEVEL: ${SMQ_JOURNAL_LOG_LEVEL} - SMQ_JOURNAL_HTTP_HOST: ${SMQ_JOURNAL_HTTP_HOST} - SMQ_JOURNAL_HTTP_PORT: ${SMQ_JOURNAL_HTTP_PORT} - SMQ_JOURNAL_HTTP_SERVER_CERT: ${SMQ_JOURNAL_HTTP_SERVER_CERT} - SMQ_JOURNAL_HTTP_SERVER_KEY: ${SMQ_JOURNAL_HTTP_SERVER_KEY} - SMQ_JOURNAL_DB_HOST: ${SMQ_JOURNAL_DB_HOST} - SMQ_JOURNAL_DB_PORT: ${SMQ_JOURNAL_DB_PORT} - SMQ_JOURNAL_DB_USER: ${SMQ_JOURNAL_DB_USER} - SMQ_JOURNAL_DB_PASS: ${SMQ_JOURNAL_DB_PASS} - SMQ_JOURNAL_DB_NAME: ${SMQ_JOURNAL_DB_NAME} - SMQ_JOURNAL_DB_SSL_MODE: ${SMQ_JOURNAL_DB_SSL_MODE} - SMQ_JOURNAL_DB_SSL_CERT: ${SMQ_JOURNAL_DB_SSL_CERT} - SMQ_JOURNAL_DB_SSL_KEY: ${SMQ_JOURNAL_DB_SSL_KEY} - SMQ_JOURNAL_DB_SSL_ROOT_CERT: ${SMQ_JOURNAL_DB_SSL_ROOT_CERT} - SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} - SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} - SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} - SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} - SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_ES_URL: ${SMQ_ES_URL} - SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} - SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} - SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} - SMQ_JOURNAL_INSTANCE_ID: ${SMQ_JOURNAL_INSTANCE_ID} - SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} - SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} - SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} - SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} - SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} - ports: - - ${SMQ_JOURNAL_HTTP_PORT}:${SMQ_JOURNAL_HTTP_PORT} - networks: - - magistrala-base-net - ui: image: ghcr.io/absmach/magistrala/ui-mg:latest container_name: magistrala-ui diff --git a/docker/nginx/snippets/http_access_log.conf b/docker/nginx/snippets/http_access_log.conf deleted file mode 100644 index d9adfa195..000000000 --- a/docker/nginx/snippets/http_access_log.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) Abstract Machines -# SPDX-License-Identifier: Apache-2.0 - -log_format access_log_format 'HTTP/WS ' - '$remote_addr: ' - '"$request" $status; ' - 'request time=$request_time upstream connect time=$upstream_connect_time upstream response time=$upstream_response_time'; -access_log access.log access_log_format; diff --git a/docker/supermq-docker-compose.override.yml b/docker/supermq-docker-compose.override.yml new file mode 100644 index 000000000..47b5a7681 --- /dev/null +++ b/docker/supermq-docker-compose.override.yml @@ -0,0 +1,151 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +services: + spicedb: + networks: + - magistrala-base-net + + spicedb-migrate: + networks: !override + - magistrala-base-net + + spicedb-db: + networks: !override + - magistrala-base-net + + auth-db: + networks: !override + - magistrala-base-net + + auth-redis: + networks: !override + - magistrala-base-net + + auth: + networks: !override + - magistrala-base-net + + domains-db: + networks: !override + - magistrala-base-net + + domains-redis: + networks: !override + - magistrala-base-net + + domains: + networks: !override + - magistrala-base-net + + clients-db: + networks: !override + - magistrala-base-net + + clients-redis: + networks: !override + - magistrala-base-net + + clients: + networks: !override + - magistrala-base-net + + channels-db: + networks: !override + - magistrala-base-net + + channels: + networks: !override + - magistrala-base-net + + users-db: + networks: !override + - magistrala-base-net + + users: + networks: !override + - magistrala-base-net + + groups-db: + networks: !override + - magistrala-base-net + + groups: + networks: !override + - magistrala-base-net + + jaeger: + networks: + - magistrala-base-net + + mqtt-adapter: + networks: !override + - magistrala-base-net + + http-adapter: + networks: !override + - magistrala-base-net + + coap-adapter: + networks: !override + - magistrala-base-net + + ws-adapter: + networks: !override + - magistrala-base-net + + rabbitmq: + networks: !override + - magistrala-base-net + + nats: + networks: !override + - magistrala-base-net + + journal-db: + networks: !override + - magistrala-base-net + + journal: + networks: !override + - magistrala-base-net + + am-certs-db: + networks: !override + - magistrala-base-net + + am-certs: + volumes: + - ./addons/certs/config.yml:/config/config.yml + networks: !override + - magistrala-base-net + + certs: + volumes: + - ../../docker/ssl/certs/ca.key:/etc/ssl/certs/ca.key + - ../../docker/ssl/certs/ca.crt:/etc/ssl/certs/ca.crt + networks: !override + - magistrala-base-net + + nginx: + container_name: magistrala-nginx + volumes: + - ../../docker/nginx/nginx-${AUTH-key}.conf:/etc/nginx/nginx.conf.template + - ../../docker/nginx/entrypoint.sh:/docker-entrypoint.d/entrypoint.sh + - type: bind + source: ${SMQ_NGINX_SERVER_CERT:-../../docker/ssl/certs/magistrala-server.crt} + target: /etc/ssl/certs/magistrala-server.crt + - type: bind + source: ${SMQ_NGINX_SERVER_KEY:-../../docker/ssl/certs/magistrala-server.key} + target: /etc/ssl/private/magistrala-server.key + - type: bind + source: ${SMQ_NGINX_SERVER_CLIENT_CA:-../../docker/ssl/certs/ca.crt} + target: /etc/ssl/certs/ca.crt + - type: bind + source: ${SMQ_NGINX_SERVER_DHPARAM:-../../docker/ssl/dhparam.pem} + target: /etc/ssl/certs/dhparam.pem + networks: !override + - magistrala-base-net + env_file: !override + - ./.env + - ../../docker/.env diff --git a/docker/supermq-docker/.env b/docker/supermq-docker/.env new file mode 100644 index 000000000..f88856e39 --- /dev/null +++ b/docker/supermq-docker/.env @@ -0,0 +1,492 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 +# Docker: Environment variables in Compose + +## Enable GRPC SSL +## If enabled run ./scripts/generate-grpc-certs.sh to generate the GRPC certs +GRPC_MTLS= + +## NginX +SMQ_NGINX_HTTP_PORT=80 +SMQ_NGINX_SSL_PORT=443 +SMQ_NGINX_MQTT_PORT=1883 +SMQ_NGINX_MQTTS_PORT=8883 + +## Nats +SMQ_NATS_PORT=4222 +SMQ_NATS_HTTP_PORT=8222 +SMQ_NATS_JETSTREAM_KEY=u7wFoAPgXpDueXOFldBnXDh4xjnSOyEJ2Cb8Z5SZvGLzIZ3U4exWhhoIBZHzuNvh +SMQ_NATS_URL=nats://nats:${SMQ_NATS_PORT} +# Configs for nats as MQTT broker +SMQ_NATS_HEALTH_CHECK=http://nats:${SMQ_NATS_HTTP_PORT}/healthz +SMQ_NATS_WS_TARGET_PATH= +SMQ_NATS_MQTT_QOS=0 + +## RabbitMQ +SMQ_RABBITMQ_PORT=5672 +SMQ_RABBITMQ_HTTP_PORT=15672 +SMQ_RABBITMQ_WS_PORT=15675 +SMQ_RABBITMQ_USER=supermq +SMQ_RABBITMQ_PASS=supermq +SMQ_RABBITMQ_COOKIE=supermq +SMQ_RABBITMQ_VHOST=/ +SMQ_RABBITMQ_URL=amqp://${SMQ_RABBITMQ_USER}:${SMQ_RABBITMQ_PASS}@rabbitmq:${SMQ_RABBITMQ_PORT}${SMQ_RABBITMQ_VHOST} +SMQ_RABBITMQ_MQTT_QOS=0 +SMQ_RABBITMQ_WS_TARGET_PATH=/ws + +## Message Broker +SMQ_MESSAGE_BROKER_TYPE=nats +SMQ_MESSAGE_BROKER_URL=${SMQ_NATS_URL} + +## MQTT Broker +SMQ_MQTT_BROKER_TYPE=rabbitmq +SMQ_MQTT_BROKER_HEALTH_CHECK= +SMQ_MQTT_ADAPTER_MQTT_QOS=${SMQ_RABBITMQ_MQTT_QOS} +SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} +SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT=1883 +SMQ_MQTT_ADAPTER_MQTT_TARGET_USERNAME=${SMQ_RABBITMQ_USER} +SMQ_MQTT_ADAPTER_MQTT_TARGET_PASSWORD=${SMQ_RABBITMQ_PASS} +SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK=${SMQ_MQTT_BROKER_HEALTH_CHECK} +SMQ_MQTT_ADAPTER_WS_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} +SMQ_MQTT_ADAPTER_WS_TARGET_PORT=${SMQ_RABBITMQ_WS_PORT} +SMQ_MQTT_ADAPTER_WS_TARGET_PATH=${SMQ_RABBITMQ_WS_TARGET_PATH} + +## Redis +SMQ_REDIS_TCP_PORT=6379 +SMQ_REDIS_URL=redis://es-redis:${SMQ_REDIS_TCP_PORT}/0 + +## Event Store +SMQ_ES_TYPE=${SMQ_MESSAGE_BROKER_TYPE} +SMQ_ES_URL=${SMQ_MESSAGE_BROKER_URL} + +## Jaeger +SMQ_JAEGER_COLLECTOR_OTLP_ENABLED=true +SMQ_JAEGER_FRONTEND=16686 +SMQ_JAEGER_OLTP_HTTP=4318 +SMQ_JAEGER_URL=http://jaeger:4318/v1/traces +SMQ_JAEGER_TRACE_RATIO=1.0 +SMQ_JAEGER_MEMORY_MAX_TRACES=5000 + +## Call home +SMQ_SEND_TELEMETRY=true + +## Postgres +SMQ_POSTGRES_MAX_CONNECTIONS=100 + +## Core Services + +### Auth +SMQ_AUTH_LOG_LEVEL=debug +SMQ_AUTH_HTTP_HOST=auth +SMQ_AUTH_HTTP_PORT=9001 +SMQ_AUTH_HTTP_SERVER_CERT= +SMQ_AUTH_HTTP_SERVER_KEY= +SMQ_AUTH_GRPC_HOST=auth +SMQ_AUTH_GRPC_PORT=7001 +SMQ_AUTH_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/auth-grpc-server.crt}${GRPC_TLS:+./ssl/certs/auth-grpc-server.crt} +SMQ_AUTH_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/auth-grpc-server.key}${GRPC_TLS:+./ssl/certs/auth-grpc-server.key} +SMQ_AUTH_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} +SMQ_AUTH_DB_HOST=auth-db +SMQ_AUTH_DB_PORT=5432 +SMQ_AUTH_DB_USER=supermq +SMQ_AUTH_DB_PASS=supermq +SMQ_AUTH_DB_NAME=auth +SMQ_AUTH_DB_SSL_MODE=disable +SMQ_AUTH_DB_SSL_CERT= +SMQ_AUTH_DB_SSL_KEY= +SMQ_AUTH_DB_SSL_ROOT_CERT= +SMQ_AUTH_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH +SMQ_AUTH_ACCESS_TOKEN_DURATION="1h" +SMQ_AUTH_REFRESH_TOKEN_DURATION="24h" +SMQ_AUTH_INVITATION_DURATION="168h" +SMQ_AUTH_ADAPTER_INSTANCE_ID= +SMQ_AUTH_CACHE_URL=redis://auth-redis:${SMQ_REDIS_TCP_PORT}/0 +SMQ_AUTH_CACHE_KEY_DURATION=10m +SMQ_AUTH_CALLOUT_URLS="" +SMQ_AUTH_CALLOUT_METHOD="POST" +SMQ_AUTH_CALLOUT_TLS_VERIFICATION="false" +SMQ_AUTH_CALLOUT_TIMEOUT="10s" +SMQ_AUTH_CALLOUT_CA_CERT="" +SMQ_AUTH_CALLOUT_CERT="" +SMQ_AUTH_CALLOUT_KEY="" + +#### Auth Client Config +SMQ_AUTH_URL=auth:9001 +SMQ_AUTH_GRPC_URL=auth:7001 +SMQ_AUTH_GRPC_TIMEOUT=300s +SMQ_AUTH_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/auth-grpc-client.crt} +SMQ_AUTH_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/auth-grpc-client.key} +SMQ_AUTH_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} + +### Domains +SMQ_DOMAINS_LOG_LEVEL=debug +SMQ_DOMAINS_HTTP_HOST=domains +SMQ_DOMAINS_HTTP_PORT=9003 +SMQ_DOMAINS_HTTP_SERVER_KEY= +SMQ_DOMAINS_HTTP_SERVER_CERT= +SMQ_DOMAINS_GRPC_HOST=domains +SMQ_DOMAINS_GRPC_PORT=7003 +SMQ_DOMAINS_DB_HOST=domains-db +SMQ_DOMAINS_DB_PORT=5432 +SMQ_DOMAINS_DB_NAME=domains +SMQ_DOMAINS_DB_USER=supermq +SMQ_DOMAINS_DB_PASS=supermq +SMQ_DOMAINS_DB_SSL_MODE= +SMQ_DOMAINS_DB_SSL_KEY= +SMQ_DOMAINS_DB_SSL_CERT= +SMQ_DOMAINS_DB_SSL_ROOT_CERT= +SMQ_DOMAINS_INSTANCE_ID= +SMQ_DOMAINS_CACHE_URL=redis://domains-redis:${SMQ_REDIS_TCP_PORT}/0 +SMQ_DOMAINS_CACHE_KEY_DURATION=10m + +#### Domains Client Config +SMQ_DOMAINS_URL=http://domains:9003 +SMQ_DOMAINS_GRPC_URL=domains:7003 +SMQ_DOMAINS_GRPC_TIMEOUT=300s +SMQ_DOMAINS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/domains-grpc-client.crt} +SMQ_DOMAINS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/domains-grpc-client.key} +SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} + +### SpiceDB Datastore config +SMQ_SPICEDB_DB_USER=supermq +SMQ_SPICEDB_DB_PASS=supermq +SMQ_SPICEDB_DB_NAME=spicedb +SMQ_SPICEDB_DB_PORT=5432 + +### SpiceDB config +SMQ_SPICEDB_PRE_SHARED_KEY="12345678" +SMQ_SPICEDB_SCHEMA_FILE="/schema.zed" +SMQ_SPICEDB_HOST=supermq-spicedb +SMQ_SPICEDB_PORT=50051 +SMQ_SPICEDB_DATASTORE_ENGINE=postgres + +### UI +SMQ_UI_LOG_LEVEL=debug +SMQ_UI_PORT=9095 +SMQ_HTTP_ADAPTER_URL=http://http-adapter:8008 +SMQ_CLIENTS_URL=http://clients:9006 +SMQ_USERS_URL=http://users:9002 +SMQ_INVITATIONS_URL=http://invitations:9020 +SMQ_DOMAINS_URL=http://domains:9003 +SMQ_UI_HOST_URL=http://localhost:9095 +SMQ_UI_VERIFICATION_TLS=false +SMQ_UI_CONTENT_TYPE=application/senml+json +SMQ_UI_INSTANCE_ID= +SMQ_UI_DB_HOST=ui-db +SMQ_UI_DB_PORT=5432 +SMQ_UI_DB_USER=supermq +SMQ_UI_DB_PASS=supermq +SMQ_UI_DB_NAME=ui +SMQ_UI_DB_SSL_MODE=disable +SMQ_UI_DB_SSL_CERT= +SMQ_UI_DB_SSL_KEY= +SMQ_UI_DB_SSL_ROOT_CERT= +SMQ_UI_HASH_KEY=5jx4x2Qg9OUmzpP5dbveWQ +SMQ_UI_BLOCK_KEY=UtgZjr92jwRY6SPUndHXiyl9QY8qTUyZ +SMQ_UI_PATH_PREFIX=/ui + +### Users +SMQ_USERS_LOG_LEVEL=debug +SMQ_USERS_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH +SMQ_USERS_ADMIN_EMAIL=admin@example.com +SMQ_USERS_ADMIN_PASSWORD=12345678 +SMQ_USERS_ADMIN_USERNAME=admin +SMQ_USERS_ADMIN_FIRST_NAME=super +SMQ_USERS_ADMIN_LAST_NAME=admin +SMQ_USERS_PASS_REGEX=^.{8,}$ +SMQ_USERS_ACCESS_TOKEN_DURATION=15m +SMQ_USERS_REFRESH_TOKEN_DURATION=24h +SMQ_TOKEN_RESET_ENDPOINT=/reset-request +SMQ_USERS_HTTP_HOST=users +SMQ_USERS_HTTP_PORT=9002 +SMQ_USERS_HTTP_SERVER_CERT= +SMQ_USERS_HTTP_SERVER_KEY= +SMQ_USERS_DB_HOST=users-db +SMQ_USERS_DB_PORT=5432 +SMQ_USERS_DB_USER=supermq +SMQ_USERS_DB_PASS=supermq +SMQ_USERS_DB_NAME=users +SMQ_USERS_DB_SSL_MODE=disable +SMQ_USERS_DB_SSL_CERT= +SMQ_USERS_DB_SSL_KEY= +SMQ_USERS_DB_SSL_ROOT_CERT= +SMQ_USERS_RESET_PWD_TEMPLATE=users.tmpl +SMQ_USERS_INSTANCE_ID= +SMQ_USERS_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH +SMQ_USERS_ADMIN_EMAIL=admin@example.com +SMQ_USERS_ADMIN_PASSWORD=12345678 +SMQ_USERS_PASS_REGEX=^.{8,}$ +SMQ_USERS_ACCESS_TOKEN_DURATION=15m +SMQ_USERS_REFRESH_TOKEN_DURATION=24h +SMQ_TOKEN_RESET_ENDPOINT=/reset-request +SMQ_USERS_ALLOW_SELF_REGISTER=true +SMQ_OAUTH_UI_REDIRECT_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/tokens/secure +SMQ_OAUTH_UI_ERROR_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/error +SMQ_USERS_DELETE_INTERVAL=24h +SMQ_USERS_DELETE_AFTER=720h + +#### Users Client Config +SMQ_USERS_URL=users:9002 + +### Email utility +SMQ_EMAIL_HOST=smtp.mailtrap.io +SMQ_EMAIL_PORT=2525 +SMQ_EMAIL_USERNAME=18bf7f70705139 +SMQ_EMAIL_PASSWORD=2b0d302e775b1e +SMQ_EMAIL_FROM_ADDRESS=from@example.com +SMQ_EMAIL_FROM_NAME=Example +SMQ_EMAIL_TEMPLATE=email.tmpl + +### Google OAuth2 +SMQ_GOOGLE_CLIENT_ID= +SMQ_GOOGLE_CLIENT_SECRET= +SMQ_GOOGLE_REDIRECT_URL= +SMQ_GOOGLE_STATE= + +### Groups +SMQ_GROUPS_LOG_LEVEL=debug +SMQ_GROUPS_HTTP_HOST=groups +SMQ_GROUPS_HTTP_PORT=9004 +SMQ_GROUPS_HTTP_SERVER_CERT= +SMQ_GROUPS_HTTP_SERVER_KEY= +SMQ_GROUPS_GRPC_HOST=groups +SMQ_GROUPS_GRPC_PORT=7004 +SMQ_GROUPS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/groups-grpc-server.crt}${GRPC_TLS:+./ssl/certs/groups-grpc-server.crt} +SMQ_GROUPS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/groups-grpc-server.key}${GRPC_TLS:+./ssl/certs/groups-grpc-server.key} +SMQ_GROUPS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} +SMQ_GROUPS_DB_HOST=groups-db +SMQ_GROUPS_DB_PORT=5432 +SMQ_GROUPS_DB_USER=supermq +SMQ_GROUPS_DB_PASS=supermq +SMQ_GROUPS_DB_NAME=groups +SMQ_GROUPS_DB_SSL_MODE=disable +SMQ_GROUPS_DB_SSL_CERT= +SMQ_GROUPS_DB_SSL_KEY= +SMQ_GROUPS_DB_SSL_ROOT_CERT= +SMQ_GROUPS_INSTANCE_ID= + +#### Groups Client Config +SMQ_GROUPS_URL=groups:9004 +SMQ_GROUPS_GRPC_URL=groups:7004 +SMQ_GROUPS_GRPC_TIMEOUT=300s +SMQ_GROUPS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/groups-grpc-client.crt} +SMQ_GROUPS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/groups-grpc-client.key} +SMQ_GROUPS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} + +### Clients +SMQ_CLIENTS_LOG_LEVEL=debug +SMQ_CLIENTS_STANDALONE_ID= +SMQ_CLIENTS_STANDALONE_TOKEN= +SMQ_CLIENTS_CACHE_KEY_DURATION=10m +SMQ_CLIENTS_HTTP_HOST=clients +SMQ_CLIENTS_HTTP_PORT=9006 +SMQ_CLIENTS_GRPC_HOST=clients +SMQ_CLIENTS_GRPC_PORT=7006 +SMQ_CLIENTS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/clients-grpc-server.crt}${GRPC_TLS:+./ssl/certs/clients-grpc-server.crt} +SMQ_CLIENTS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/clients-grpc-server.key}${GRPC_TLS:+./ssl/certs/clients-grpc-server.key} +SMQ_CLIENTS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} +SMQ_CLIENTS_CACHE_URL=redis://clients-redis:${SMQ_REDIS_TCP_PORT}/0 +SMQ_CLIENTS_DB_HOST=clients-db +SMQ_CLIENTS_DB_PORT=5432 +SMQ_CLIENTS_DB_USER=supermq +SMQ_CLIENTS_DB_PASS=supermq +SMQ_CLIENTS_DB_NAME=clients +SMQ_CLIENTS_DB_SSL_MODE=disable +SMQ_CLIENTS_DB_SSL_CERT= +SMQ_CLIENTS_DB_SSL_KEY= +SMQ_CLIENTS_DB_SSL_ROOT_CERT= +SMQ_CLIENTS_INSTANCE_ID= + +#### Clients Client Config +SMQ_CLIENTS_URL=http://clients:9006 +SMQ_CLIENTS_GRPC_URL=clients:7006 +SMQ_CLIENTS_GRPC_TIMEOUT=300s +SMQ_CLIENTS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/clients-grpc-client.crt} +SMQ_CLIENTS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/clients-grpc-client.key} +SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} + +### Channels +SMQ_CHANNELS_LOG_LEVEL=debug +SMQ_CHANNELS_HTTP_HOST=channels +SMQ_CHANNELS_HTTP_PORT=9005 +SMQ_CHANNELS_GRPC_HOST=channels +SMQ_CHANNELS_GRPC_PORT=7005 +SMQ_CHANNELS_GRPC_SERVER_CERT=${GRPC_MTLS:+./ssl/certs/channels-grpc-server.crt}${GRPC_TLS:+./ssl/certs/channels-grpc-server.crt} +SMQ_CHANNELS_GRPC_SERVER_KEY=${GRPC_MTLS:+./ssl/certs/channels-grpc-server.key}${GRPC_TLS:+./ssl/certs/channels-grpc-server.key} +SMQ_CHANNELS_GRPC_SERVER_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt}${GRPC_TLS:+./ssl/certs/ca.crt} +SMQ_CHANNELS_DB_HOST=channels-db +SMQ_CHANNELS_DB_PORT=5432 +SMQ_CHANNELS_DB_USER=supermq +SMQ_CHANNELS_DB_PASS=supermq +SMQ_CHANNELS_DB_NAME=channels +SMQ_CHANNELS_DB_SSL_MODE=disable +SMQ_CHANNELS_DB_SSL_CERT= +SMQ_CHANNELS_DB_SSL_KEY= +SMQ_CHANNELS_DB_SSL_ROOT_CERT= +SMQ_CHANNELS_INSTANCE_ID= + +#### Channels Client Config +SMQ_CHANNELS_URL=http://channels:9005 +SMQ_CHANNELS_GRPC_URL=channels:7005 +SMQ_CHANNELS_GRPC_TIMEOUT=300s +SMQ_CHANNELS_GRPC_CLIENT_CERT=${GRPC_MTLS:+./ssl/certs/channels-grpc-client.crt} +SMQ_CHANNELS_GRPC_CLIENT_KEY=${GRPC_MTLS:+./ssl/certs/channels-grpc-client.key} +SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS=${GRPC_MTLS:+./ssl/certs/ca.crt} + +### HTTP +SMQ_HTTP_ADAPTER_LOG_LEVEL=debug +SMQ_HTTP_ADAPTER_HOST=http-adapter +SMQ_HTTP_ADAPTER_PORT=8008 +SMQ_HTTP_ADAPTER_SERVER_CERT= +SMQ_HTTP_ADAPTER_SERVER_KEY= +SMQ_HTTP_ADAPTER_INSTANCE_ID= + +### MQTT +SMQ_MQTT_ADAPTER_LOG_LEVEL=debug +SMQ_MQTT_ADAPTER_MQTT_PORT=1883 +SMQ_MQTT_ADAPTER_FORWARDER_TIMEOUT=30s +SMQ_MQTT_ADAPTER_WS_PORT=8080 +SMQ_MQTT_ADAPTER_INSTANCE= +SMQ_MQTT_ADAPTER_INSTANCE_ID= +SMQ_MQTT_ADAPTER_ES_DB=0 + +### CoAP +SMQ_COAP_ADAPTER_LOG_LEVEL=debug +SMQ_COAP_ADAPTER_HOST=coap-adapter +SMQ_COAP_ADAPTER_PORT=5683 +SMQ_COAP_ADAPTER_SERVER_CERT= +SMQ_COAP_ADAPTER_SERVER_KEY= +SMQ_COAP_ADAPTER_HTTP_HOST=coap-adapter +SMQ_COAP_ADAPTER_HTTP_PORT=5683 +SMQ_COAP_ADAPTER_HTTP_SERVER_CERT= +SMQ_COAP_ADAPTER_HTTP_SERVER_KEY= +SMQ_COAP_ADAPTER_INSTANCE_ID= + +### WS +SMQ_WS_ADAPTER_LOG_LEVEL=debug +SMQ_WS_ADAPTER_HTTP_HOST=ws-adapter +SMQ_WS_ADAPTER_HTTP_PORT=8186 +SMQ_WS_ADAPTER_HTTP_SERVER_CERT= +SMQ_WS_ADAPTER_HTTP_SERVER_KEY= +SMQ_WS_ADAPTER_INSTANCE_ID= + +## Addons Services +### Vault +SMQ_VAULT_HOST=vault +SMQ_VAULT_PORT=8200 +SMQ_VAULT_ADDR=http://vault:8200 +SMQ_VAULT_NAMESPACE=supermq +SMQ_VAULT_UNSEAL_KEY_1= +SMQ_VAULT_UNSEAL_KEY_2= +SMQ_VAULT_UNSEAL_KEY_3= +SMQ_VAULT_TOKEN= + +SMQ_VAULT_PKI_PATH=pki +SMQ_VAULT_PKI_ROLE_NAME=supermq_int_ca +SMQ_VAULT_PKI_FILE_NAME=mg_root +SMQ_VAULT_PKI_CA_CN='SuperMQ Root Certificate Authority' +SMQ_VAULT_PKI_CA_OU='SuperMQ' +SMQ_VAULT_PKI_CA_O='SuperMQ' +SMQ_VAULT_PKI_CA_C='FRANCE' +SMQ_VAULT_PKI_CA_L='PARIS' +SMQ_VAULT_PKI_CA_ST='PARIS' +SMQ_VAULT_PKI_CA_ADDR='5 Av. Anatole' +SMQ_VAULT_PKI_CA_PO='75007' +SMQ_VAULT_PKI_CLUSTER_PATH=http://localhost +SMQ_VAULT_PKI_CLUSTER_AIA_PATH=http://localhost + +SMQ_VAULT_PKI_INT_PATH=pki_int +SMQ_VAULT_PKI_INT_SERVER_CERTS_ROLE_NAME=supermq_server_certs +SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME=supermq_clients_certs +SMQ_VAULT_PKI_INT_FILE_NAME=mg_int +SMQ_VAULT_PKI_INT_CA_CN='SuperMQ Intermediate Certificate Authority' +SMQ_VAULT_PKI_INT_CA_OU='SuperMQ' +SMQ_VAULT_PKI_INT_CA_O='SuperMQ' +SMQ_VAULT_PKI_INT_CA_C='FRANCE' +SMQ_VAULT_PKI_INT_CA_L='PARIS' +SMQ_VAULT_PKI_INT_CA_ST='PARIS' +SMQ_VAULT_PKI_INT_CA_ADDR='5 Av. Anatole' +SMQ_VAULT_PKI_INT_CA_PO='75007' +SMQ_VAULT_PKI_INT_CLUSTER_PATH=http://localhost +SMQ_VAULT_PKI_INT_CLUSTER_AIA_PATH=http://localhost + +SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID=supermq +SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET=supermq + +# Certs +SMQ_CERTS_LOG_LEVEL=debug +SMQ_CERTS_SIGN_CA_PATH=/etc/ssl/certs/ca.crt +SMQ_CERTS_SIGN_CA_KEY_PATH=/etc/ssl/certs/ca.key +SMQ_CERTS_VAULT_HOST=${SMQ_VAULT_ADDR} +SMQ_CERTS_VAULT_NAMESPACE=${SMQ_VAULT_NAMESPACE} +SMQ_CERTS_VAULT_APPROLE_ROLEID=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID} +SMQ_CERTS_VAULT_APPROLE_SECRET=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET} +SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH=${SMQ_VAULT_PKI_INT_PATH} +SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME=${SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME} +SMQ_CERTS_HTTP_HOST=certs +SMQ_CERTS_HTTP_PORT=9019 +SMQ_CERTS_HTTP_SERVER_CERT= +SMQ_CERTS_HTTP_SERVER_KEY= +SMQ_CERTS_GRPC_HOST= +SMQ_CERTS_GRPC_PORT= +SMQ_CERTS_DB_HOST=am-certs-db +SMQ_CERTS_DB_PORT=5432 +SMQ_CERTS_DB_USER=supermq +SMQ_CERTS_DB_PASS=supermq +SMQ_CERTS_DB_NAME=certs +SMQ_CERTS_DB_SSL_MODE= +SMQ_CERTS_DB_SSL_CERT= +SMQ_CERTS_DB_SSL_KEY= +SMQ_CERTS_DB_SSL_ROOT_CERT= +SMQ_CERTS_INSTANCE_ID= +SMQ_CERTS_SDK_HOST=http://supermq-am-certs +SMQ_CERTS_SDK_CERTS_URL=${SMQ_CERTS_SDK_HOST}:9010 +SMQ_CERTS_SDK_TLS_VERIFICATION=false + +### Postgres +SMQ_POSTGRES_HOST=supermq-postgres +SMQ_POSTGRES_PORT=5432 +SMQ_POSTGRES_USER=supermq +SMQ_POSTGRES_PASS=supermq +SMQ_POSTGRES_NAME=messages +SMQ_POSTGRES_SSL_MODE=disable +SMQ_POSTGRES_SSL_CERT= +SMQ_POSTGRES_SSL_KEY= +SMQ_POSTGRES_SSL_ROOT_CERT= + +### Timescale +SMQ_TIMESCALE_HOST=supermq-timescale +SMQ_TIMESCALE_PORT=5432 +SMQ_TIMESCALE_USER=supermq +SMQ_TIMESCALE_PASS=supermq +SMQ_TIMESCALE_NAME=supermq +SMQ_TIMESCALE_SSL_MODE=disable +SMQ_TIMESCALE_SSL_CERT= +SMQ_TIMESCALE_SSL_KEY= +SMQ_TIMESCALE_SSL_ROOT_CERT= + +### Journal +SMQ_JOURNAL_LOG_LEVEL=info +SMQ_JOURNAL_HTTP_HOST=journal +SMQ_JOURNAL_HTTP_PORT=9021 +SMQ_JOURNAL_HTTP_SERVER_CERT= +SMQ_JOURNAL_HTTP_SERVER_KEY= +SMQ_JOURNAL_DB_HOST=journal-db +SMQ_JOURNAL_DB_PORT=5432 +SMQ_JOURNAL_DB_USER=supermq +SMQ_JOURNAL_DB_PASS=supermq +SMQ_JOURNAL_DB_NAME=journal +SMQ_JOURNAL_DB_SSL_MODE=disable +SMQ_JOURNAL_DB_SSL_CERT= +SMQ_JOURNAL_DB_SSL_KEY= +SMQ_JOURNAL_DB_SSL_ROOT_CERT= +SMQ_JOURNAL_INSTANCE_ID= + +### GRAFANA and PROMETHEUS +SMQ_PROMETHEUS_PORT=9090 +SMQ_GRAFANA_PORT=3000 +SMQ_GRAFANA_ADMIN_USER=supermq +SMQ_GRAFANA_ADMIN_PASSWORD=supermq + +# Docker image tag +SMQ_RELEASE_TAG=latest diff --git a/docker/supermq-docker/Dockerfile b/docker/supermq-docker/Dockerfile new file mode 100644 index 000000000..758494821 --- /dev/null +++ b/docker/supermq-docker/Dockerfile @@ -0,0 +1,24 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +FROM golang:1.24-alpine AS builder +ARG SVC +ARG GOARCH +ARG GOARM +ARG VERSION +ARG COMMIT +ARG TIME + +WORKDIR /go/src/github.com/absmach/supermq +COPY . . +RUN apk update \ + && apk add make upx\ + && make $SVC \ + && upx build/$SVC \ + && mv build/$SVC /exe + +FROM scratch +# Certificates are needed so that mailing util can work. +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /exe / +ENTRYPOINT ["/exe"] diff --git a/docker/supermq-docker/Dockerfile.dev b/docker/supermq-docker/Dockerfile.dev new file mode 100644 index 000000000..7d55569c2 --- /dev/null +++ b/docker/supermq-docker/Dockerfile.dev @@ -0,0 +1,8 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +FROM scratch +ARG SVC +COPY $SVC /exe +COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +ENTRYPOINT ["/exe"] diff --git a/docker/supermq-docker/README.md b/docker/supermq-docker/README.md new file mode 100644 index 000000000..ecf02df9a --- /dev/null +++ b/docker/supermq-docker/README.md @@ -0,0 +1,134 @@ +# Docker Composition + +Configure environment variables and run SuperMQ Docker Composition. + +\*Note\*\*: `docker-compose` uses `.env` file to set all environment variables. Ensure that you run the command from the same location as .env file. + +## Installation + +Follow the [official documentation](https://docs.docker.com/compose/install/). + +## Usage + +Run the following commands from the project root directory. + +```bash +docker compose -f docker/docker-compose.yml up +``` + +```bash +docker compose -f docker/addons//docker-compose.yml up +``` + +To pull docker images from a specific release you need to change the value of `SMQ_RELEASE_TAG` in `.env` before running these commands. + +## Broker Configuration + +SuperMQ supports configurable MQTT broker and Message broker, which also acts as an events store. SuperMQ uses two types of brokers: + +1. MQTT_BROKER: Handles MQTT communication between MQTT adapters and message broker. This can either be 'RabbitMQ' or 'NATS'. +2. MESSAGE_BROKER: Manages message exchange between SuperMQ core, optional, and external services. This can either be 'NATS' or 'RabbitMQ'. This is used to store messages for distributed processing. + +Events store: This is used by SuperMQ services to store events for distributed processing. SuperMQ uses a single service to be the message broker and events store. This can either be 'NATS' or 'RabbitMQ'. Redis can also be used as an events store, but it requires a message broker to be deployed along with it for message exchange. + +This is the same as MESSAGE_BROKER. This can either be 'NATS' or 'RabbitMQ' or 'Redis'. If Redis is used as an events store, then RabbitMQ or NATS is used as a message broker. + +The current deployment strategy for SuperMQ in `docker/docker-compose.yml` is to use RabbitMQ as a MQTT_BROKER and NATS as a MESSAGE_BROKER and EVENTS_STORE. + +Therefore, the following combinations are possible: + +- MQTT_BROKER: RabbitMQ, MESSAGE_BROKER: NATS, EVENTS_STORE: NATS +- MQTT_BROKER: RabbitMQ, MESSAGE_BROKER: NATS, EVENTS_STORE: Redis +- MQTT_BROKER: RabbitMQ, MESSAGE_BROKER: RabbitMQ, EVENTS_STORE: RabbitMQ +- MQTT_BROKER: RabbitMQ, MESSAGE_BROKER: RabbitMQ, EVENTS_STORE: Redis +- MQTT_BROKER: NATS, MESSAGE_BROKER: RabbitMQ, EVENTS_STORE: RabbitMQ +- MQTT_BROKER: NATS, MESSAGE_BROKER: RabbitMQ, EVENTS_STORE: Redis +- MQTT_BROKER: NATS, MESSAGE_BROKER: NATS, EVENTS_STORE: NATS +- MQTT_BROKER: NATS, MESSAGE_BROKER: NATS, EVENTS_STORE: Redis + +For Message brokers other than NATS, you would need to build the docker images with RabbitMQ as the build tag and change the `docker/.env`. For example, to use RabbitMQ as a message broker: + +```bash +SMQ_MESSAGE_BROKER_TYPE=rabbitmq make dockers +``` + +```env +SMQ_MESSAGE_BROKER_TYPE=rabbitmq +SMQ_MESSAGE_BROKER_URL=${SMQ_RABBITMQ_URL} +``` + +For Redis as an events store, you would need to run RabbitMQ or NATS as a message broker. For example, to use Redis as an events store with rabbitmq as a message broker: + +```bash +SMQ_ES_TYPE=redis SMQ_MESSAGE_BROKER_TYPE=rabbitmq make dockers +``` + +```env +SMQ_MESSAGE_BROKER_TYPE=rabbitmq +SMQ_MESSAGE_BROKER_URL=${SMQ_RABBITMQ_URL} +SMQ_ES_TYPE=redis +SMQ_ES_URL=${SMQ_REDIS_URL} +``` + +For MQTT broker other than RabbitMQ, you would need to change the `docker/.env`. For example, to use NATS as a MQTT broker: + +```env +SMQ_MQTT_BROKER_TYPE=nats +SMQ_MQTT_BROKER_HEALTH_CHECK=${SMQ_NATS_HEALTH_CHECK} +SMQ_MQTT_ADAPTER_MQTT_QOS=${SMQ_NATS_MQTT_QOS} +SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} +SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT=1883 +SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK=${SMQ_MQTT_BROKER_HEALTH_CHECK} +SMQ_MQTT_ADAPTER_WS_TARGET_HOST=${SMQ_MQTT_BROKER_TYPE} +SMQ_MQTT_ADAPTER_WS_TARGET_PORT=8080 +SMQ_MQTT_ADAPTER_WS_TARGET_PATH=${SMQ_NATS_WS_TARGET_PATH} +``` + +### RabbitMQ configuration + +```yaml +services: + rabbitmq: + image: rabbitmq:3.12.12-management-alpine + container_name: supermq-rabbitmq + restart: on-failure + environment: + RABBITMQ_ERLANG_COOKIE: ${SMQ_RABBITMQ_COOKIE} + RABBITMQ_DEFAULT_USER: ${SMQ_RABBITMQ_USER} + RABBITMQ_DEFAULT_PASS: ${SMQ_RABBITMQ_PASS} + RABBITMQ_DEFAULT_VHOST: ${SMQ_RABBITMQ_VHOST} + ports: + - ${SMQ_RABBITMQ_PORT}:${SMQ_RABBITMQ_PORT} + - ${SMQ_RABBITMQ_HTTP_PORT}:${SMQ_RABBITMQ_HTTP_PORT} + networks: + - supermq-base-net +``` + +### Redis configuration + +```yaml +services: + redis: + image: redis:7.2.4-alpine + container_name: supermq-es-redis + restart: on-failure + networks: + - supermq-base-net + volumes: + - supermq-broker-volume:/data +``` + +## Nginx Configuration + +Nginx is the entry point for all traffic to SuperMQ. +By using environment variables file at `docker/.env` you can modify the below given Nginx directive. + +`SMQ_NGINX_SERVER_NAME` environmental variable is used to configure nginx directive `server_name`. If environmental variable `SMQ_NGINX_SERVER_NAME` is empty then default value `localhost` will set to `server_name`. + +`SMQ_NGINX_SERVER_CERT` environmental variable is used to configure nginx directive `ssl_certificate`. If environmental variable `SMQ_NGINX_SERVER_CERT` is empty then by default server certificate in the path `docker/ssl/certs/supermq-server.crt` will be assigned. + +`SMQ_NGINX_SERVER_KEY` environmental variable is used to configure nginx directive `ssl_certificate_key`. If environmental variable `SMQ_NGINX_SERVER_KEY` is empty then by default server certificate key in the path `docker/ssl/certs/supermq-server.key` will be assigned. + +`SMQ_NGINX_SERVER_CLIENT_CA` environmental variable is used to configure nginx directive `ssl_client_certificate`. If environmental variable `SMQ_NGINX_SERVER_CLIENT_CA` is empty then by default certificate in the path `docker/ssl/certs/ca.crt` will be assigned. + +`SMQ_NGINX_SERVER_DHPARAM` environmental variable is used to configure nginx directive `ssl_dhparam`. If environmental variable `SMQ_NGINX_SERVER_DHPARAM` is empty then by default file in the path `docker/ssl/dhparam.pem` will be assigned. diff --git a/docker/addons/certs/config.yml b/docker/supermq-docker/addons/certs/config.yml similarity index 100% rename from docker/addons/certs/config.yml rename to docker/supermq-docker/addons/certs/config.yml diff --git a/docker/supermq-docker/addons/certs/docker-compose.yml b/docker/supermq-docker/addons/certs/docker-compose.yml new file mode 100644 index 000000000..f8602df5b --- /dev/null +++ b/docker/supermq-docker/addons/certs/docker-compose.yml @@ -0,0 +1,124 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This docker-compose file contains optional certs services. Since it's optional, this file is +# dependent of docker-compose file from /docker. In order to run this services, execute command: +# docker compose -f docker/docker-compose.yml -f docker/addons/certs/docker-compose.yml up +# from project root. + +networks: + supermq-base-net: + +volumes: + supermq-certs-db-volume: + + +services: + certs: + image: supermq/certs:${SMQ_RELEASE_TAG} + container_name: supermq-certs + depends_on: + - am-certs + restart: on-failure + networks: + - supermq-base-net + ports: + - ${SMQ_CERTS_HTTP_PORT}:${SMQ_CERTS_HTTP_PORT} + environment: + SMQ_CERTS_LOG_LEVEL: ${SMQ_CERTS_LOG_LEVEL} + SMQ_CERTS_SIGN_CA_PATH: ${SMQ_CERTS_SIGN_CA_PATH} + SMQ_CERTS_SIGN_CA_KEY_PATH: ${SMQ_CERTS_SIGN_CA_KEY_PATH} + SMQ_CERTS_VAULT_HOST: ${SMQ_CERTS_VAULT_HOST} + SMQ_CERTS_VAULT_NAMESPACE: ${SMQ_CERTS_VAULT_NAMESPACE} + SMQ_CERTS_VAULT_APPROLE_ROLEID: ${SMQ_CERTS_VAULT_APPROLE_ROLEID} + SMQ_CERTS_VAULT_APPROLE_SECRET: ${SMQ_CERTS_VAULT_APPROLE_SECRET} + SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH: ${SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH} + SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME: ${SMQ_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME} + SMQ_CERTS_HTTP_HOST: ${SMQ_CERTS_HTTP_HOST} + SMQ_CERTS_HTTP_PORT: ${SMQ_CERTS_HTTP_PORT} + SMQ_CERTS_HTTP_SERVER_CERT: ${SMQ_CERTS_HTTP_SERVER_CERT} + SMQ_CERTS_HTTP_SERVER_KEY: ${SMQ_CERTS_HTTP_SERVER_KEY} + SMQ_CERTS_DB_HOST: ${SMQ_CERTS_DB_HOST} + SMQ_CERTS_DB_PORT: ${SMQ_CERTS_DB_PORT} + SMQ_CERTS_DB_PASS: ${SMQ_CERTS_DB_PASS} + SMQ_CERTS_DB_USER: ${SMQ_CERTS_DB_USER} + SMQ_CERTS_DB_NAME: ${SMQ_CERTS_DB_NAME} + SMQ_CERTS_DB_SSL_MODE: ${SMQ_CERTS_DB_SSL_MODE} + SMQ_CERTS_DB_SSL_CERT: ${SMQ_CERTS_DB_SSL_CERT} + SMQ_CERTS_DB_SSL_KEY: ${SMQ_CERTS_DB_SSL_KEY} + SMQ_CERTS_DB_SSL_ROOT_CERT: ${SMQ_CERTS_DB_SSL_ROOT_CERT} + SMQ_CERTS_SDK_HOST: ${SMQ_CERTS_SDK_HOST} + SMQ_CERTS_SDK_CERTS_URL: ${SMQ_CERTS_SDK_CERTS_URL} + SMQ_CERTS_SDK_TLS_VERIFICATION: ${SMQ_CERTS_SDK_TLS_VERIFICATION} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_CLIENTS_URL: ${SMQ_CLIENTS_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_CERTS_INSTANCE_ID: ${SMQ_CERTS_INSTANCE_ID} + volumes: + - ../../ssl/certs/ca.key:/etc/ssl/certs/ca.key + - ../../ssl/certs/ca.crt:/etc/ssl/certs/ca.crt + - type: bind + source: ${SMQ_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_CLIENT_CERT:-./ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_CLIENT_KEY:-./ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_ADDONS_CERTS_PATH_PREFIX}${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-./ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + am-certs-db: + image: postgres:16.2-alpine + container_name: supermq-am-certs-db + restart: on-failure + networks: + - supermq-base-net + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_CERTS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_CERTS_DB_PASS} + POSTGRES_DB: ${SMQ_CERTS_DB_NAME} + ports: + - 5454:5432 + volumes: + - supermq-certs-db-volume:/var/lib/postgresql/data + + am-certs: + image: ghcr.io/absmach/certs:${SMQ_RELEASE_TAG} + container_name: supermq-am-certs + depends_on: + - am-certs-db + restart: on-failure + networks: + - supermq-base-net + environment: + AM_CERTS_LOG_LEVEL: ${SMQ_CERTS_LOG_LEVEL} + AM_CERTS_DB_HOST: ${SMQ_CERTS_DB_HOST} + AM_CERTS_DB_PORT: ${SMQ_CERTS_DB_PORT} + AM_CERTS_DB_USER: ${SMQ_CERTS_DB_USER} + AM_CERTS_DB_PASS: ${SMQ_CERTS_DB_PASS} + AM_CERTS_DB: ${SMQ_CERTS_DB_NAME} + AM_CERTS_DB_SSL_MODE: ${SMQ_CERTS_DB_SSL_MODE} + AM_CERTS_HTTP_HOST: supermq-am-certs + AM_CERTS_HTTP_PORT: 9010 + AM_CERTS_GRPC_HOST: supermq-am-certs + AM_CERTS_GRPC_PORT: 7012 + AM_JAEGER_URL: ${SMQ_JAEGER_URL} + AM_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + volumes: + - ./config.yml:/config/config.yml + ports: + - 9010:9010 + - 7012:7012 diff --git a/docker/supermq-docker/addons/journal/docker-compose.yml b/docker/supermq-docker/addons/journal/docker-compose.yml new file mode 100644 index 000000000..3e78a94db --- /dev/null +++ b/docker/supermq-docker/addons/journal/docker-compose.yml @@ -0,0 +1,72 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This docker-compose file contains optional Postgres and journal services +# for SuperMQ platform. Since these are optional, this file is dependent of docker-compose file +# from /docker. In order to run these services, execute command: +# docker-compose -f docker/docker-compose.yml -f docker/addons/journal/docker-compose.yml up +# from project root. PostgreSQL default port (5432) is exposed, so you can use various tools for database +# inspection and data visualization. + +networks: + supermq-base-net: + +volumes: + supermq-journal-volume: + +services: + journal-db: + image: postgres:16.2-alpine + container_name: supermq-journal-db + restart: on-failure + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_JOURNAL_DB_USER} + POSTGRES_PASSWORD: ${SMQ_JOURNAL_DB_PASS} + POSTGRES_DB: ${SMQ_JOURNAL_DB_NAME} + SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} + networks: + - supermq-base-net + volumes: + - supermq-journal-volume:/var/lib/postgresql/data + + journal: + image: supermq/journal:${SMQ_RELEASE_TAG} + container_name: supermq-journal + depends_on: + - journal-db + restart: on-failure + environment: + SMQ_JOURNAL_LOG_LEVEL: ${SMQ_JOURNAL_LOG_LEVEL} + SMQ_JOURNAL_HTTP_HOST: ${SMQ_JOURNAL_HTTP_HOST} + SMQ_JOURNAL_HTTP_PORT: ${SMQ_JOURNAL_HTTP_PORT} + SMQ_JOURNAL_HTTP_SERVER_CERT: ${SMQ_JOURNAL_HTTP_SERVER_CERT} + SMQ_JOURNAL_HTTP_SERVER_KEY: ${SMQ_JOURNAL_HTTP_SERVER_KEY} + SMQ_JOURNAL_DB_HOST: ${SMQ_JOURNAL_DB_HOST} + SMQ_JOURNAL_DB_PORT: ${SMQ_JOURNAL_DB_PORT} + SMQ_JOURNAL_DB_USER: ${SMQ_JOURNAL_DB_USER} + SMQ_JOURNAL_DB_PASS: ${SMQ_JOURNAL_DB_PASS} + SMQ_JOURNAL_DB_NAME: ${SMQ_JOURNAL_DB_NAME} + SMQ_JOURNAL_DB_SSL_MODE: ${SMQ_JOURNAL_DB_SSL_MODE} + SMQ_JOURNAL_DB_SSL_CERT: ${SMQ_JOURNAL_DB_SSL_CERT} + SMQ_JOURNAL_DB_SSL_KEY: ${SMQ_JOURNAL_DB_SSL_KEY} + SMQ_JOURNAL_DB_SSL_ROOT_CERT: ${SMQ_JOURNAL_DB_SSL_ROOT_CERT} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_JOURNAL_INSTANCE_ID: ${SMQ_JOURNAL_INSTANCE_ID} + SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} + SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} + SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} + SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + ports: + - ${SMQ_JOURNAL_HTTP_PORT}:${SMQ_JOURNAL_HTTP_PORT} + networks: + - supermq-base-net diff --git a/docker/supermq-docker/addons/prometheus/docker-compose.yml b/docker/supermq-docker/addons/prometheus/docker-compose.yml new file mode 100644 index 000000000..86daaa413 --- /dev/null +++ b/docker/supermq-docker/addons/prometheus/docker-compose.yml @@ -0,0 +1,53 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This docker-compose file contains optional Prometheus and Grafana service for SuperMQ platform. +# Since this service is optional, this file is dependent of docker-compose.yml file +# from /docker. In order to run this service, execute command: +# docker compose -f docker/addons/prometheus/docker-compose.yml up +# from project root. + +networks: + supermq-base-net: + +volumes: + supermq-prometheus-volume: + +services: + promethues: + image: prom/prometheus:v2.49.1 + container_name: supermq-prometheus + restart: on-failure + ports: + - ${SMQ_PROMETHEUS_PORT}:${SMQ_PROMETHEUS_PORT} + networks: + - supermq-base-net + volumes: + - type: bind + source: ./metrics/prometheus.yml + target: /etc/prometheus/prometheus.yml + - supermq-prometheus-volume:/prometheus + + grafana: + image: grafana/grafana:10.2.3 + container_name: supermq-grafana + depends_on: + - promethues + restart: on-failure + ports: + - ${SMQ_GRAFANA_PORT}:${SMQ_GRAFANA_PORT} + environment: + - GF_SECURITY_ADMIN_USER=${SMQ_GRAFANA_ADMIN_USER} + - GF_SECURITY_ADMIN_PASSWORD=${SMQ_GRAFANA_ADMIN_PASSWORD} + networks: + - supermq-base-net + volumes: + - type: bind + source: ./grafana/datasource.yml + target: /etc/grafana/provisioning/datasources/datasource.yml + - type: bind + source: ./grafana/dashboard.yml + target: /etc/grafana/provisioning/dashboards/main.yaml + - type: bind + source: ./grafana/example-dashboard.json + target: /var/lib/grafana/dashboards/example-dashboard.json diff --git a/docker/supermq-docker/addons/prometheus/grafana/dashboard.yml b/docker/supermq-docker/addons/prometheus/grafana/dashboard.yml new file mode 100644 index 000000000..91f95f3a4 --- /dev/null +++ b/docker/supermq-docker/addons/prometheus/grafana/dashboard.yml @@ -0,0 +1,15 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: 1 + +providers: + - name: "Dashboard provider" + orgId: 1 + type: file + disableDeletion: false + updateIntervalSeconds: 10 + allowUiUpdates: false + options: + path: /var/lib/grafana/dashboards + foldersFromFilesStructure: true diff --git a/docker/supermq-docker/addons/prometheus/grafana/datasource.yml b/docker/supermq-docker/addons/prometheus/grafana/datasource.yml new file mode 100644 index 000000000..e30f53eaf --- /dev/null +++ b/docker/supermq-docker/addons/prometheus/grafana/datasource.yml @@ -0,0 +1,12 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: 1 + +datasources: +- name: Prometheus + type: prometheus + url: http://supermq-prometheus:9090 + isDefault: true + access: proxy + editable: true diff --git a/docker/supermq-docker/addons/prometheus/grafana/example-dashboard.json b/docker/supermq-docker/addons/prometheus/grafana/example-dashboard.json new file mode 100644 index 000000000..c2eabb4fb --- /dev/null +++ b/docker/supermq-docker/addons/prometheus/grafana/example-dashboard.json @@ -0,0 +1,1317 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 39, + "panels": [], + "title": "General", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 1, + "text": "down" + }, + "1": { + "color": "green", + "index": 0, + "text": "up" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": false, + "expr": "up{}", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "title": "State", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 8, + "interval": "30s", + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "go_memstats_alloc_bytes{}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 10, + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "title": "Allocated Bytes", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 22, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 4, + "interval": "15s", + "options": { + "legend": { + "calcs": [ + "mean", + "sum", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "promhttp_metric_handler_requests_total{}", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{instance}} - Code {{code}}", + "refId": "A" + } + ], + "title": "Total HTTP Requests", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "go_goroutines{}", + "interval": "", + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "title": "Goroutines instaces", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 35, + "panels": [], + "title": "Clients-Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 10, + "x": 0, + "y": 23 + }, + "id": 10, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "clients_api_request_count{}", + "instant": false, + "interval": "", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "title": "Clients Request Count", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "NaN": { + "index": 0, + "text": "0" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "µs" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 14, + "x": 10, + "y": 23 + }, + "id": 42, + "interval": "30", + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(label_replace(label_replace(clients_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")", + "format": "time_series", + "instant": false, + "interval": "", + "key": "Q-cc5a9d33-5437-4862-abd9-60afd75f3f39-0", + "legendFormat": "{{method}} - {{quantile}}", + "range": true, + "refId": "A" + } + ], + "title": "Clients Latency Quantiles", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 33 + }, + "id": 33, + "panels": [], + "title": "Users-Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 10, + "x": 0, + "y": 34 + }, + "id": 22, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "users_api_request_count{}", + "interval": "", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "title": "Users Request Count", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "NaN": { + "index": 0, + "text": "0" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "µs" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 14, + "x": 10, + "y": 34 + }, + "id": 41, + "interval": "30", + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(label_replace(label_replace(users_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")", + "format": "time_series", + "instant": false, + "interval": "", + "key": "Q-cc5a9d33-5437-4862-abd9-60afd75f3f39-0", + "legendFormat": "{{method}} - {{quantile}}", + "range": true, + "refId": "A" + } + ], + "title": "Users Latency Quantiles", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 31, + "panels": [], + "title": "CoAP-Adapter", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 10, + "x": 0, + "y": 45 + }, + "id": 18, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "coap_adapter_api_request_count{}", + "interval": "", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "title": "Coap Adapter Request Count", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "NaN": { + "index": 0, + "text": "0" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "µs" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 14, + "x": 10, + "y": 45 + }, + "id": 44, + "interval": "30", + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(label_replace(label_replace(coap_adapter_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")", + "format": "time_series", + "instant": false, + "interval": "", + "key": "Q-cc5a9d33-5437-4862-abd9-60afd75f3f39-0", + "legendFormat": "{{method}} - {{quantile}}", + "range": true, + "refId": "A" + } + ], + "title": "CoAP Latency Quantiles", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 29, + "panels": [], + "title": "Web Sockets-Adapter", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 10, + "x": 0, + "y": 56 + }, + "id": 20, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "ws_adapter_api_request_count{}", + "interval": "", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "title": "Web Sockets Request Count", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "NaN": { + "index": 0, + "text": "0" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "µs" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 14, + "x": 10, + "y": 56 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(label_replace(label_replace(ws_adapter_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")", + "format": "time_series", + "instant": false, + "interval": "", + "key": "Q-cc5a9d33-5437-4862-abd9-60afd75f3f39-0", + "legendFormat": "{{method}} - {{quantile}}", + "range": true, + "refId": "A" + } + ], + "title": "WS Latency Quantiles", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 66 + }, + "id": 27, + "panels": [], + "title": "HTTP-Adapter", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 10, + "x": 0, + "y": 67 + }, + "id": 6, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "http_adapter_api_request_count{}", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "title": "HTTP Adapter Request Count", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "µs" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 14, + "x": 10, + "y": 67 + }, + "id": 40, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(label_replace(label_replace(http_adapter_api_request_latency_microseconds, \"quantile\", \"50th percentile\", \"quantile\", \"0.5\"), \"quantile\", \"90th percentile\", \"quantile\", \"0.9\"), \"quantile\", \"99th percentile\", \"quantile\", \"0.99\")", + "format": "time_series", + "instant": false, + "interval": "", + "key": "Q-cc5a9d33-5437-4862-abd9-60afd75f3f39-0", + "legendFormat": "{{method}} - {{quantile}}", + "range": true, + "refId": "A" + } + ], + "title": "HTTP Latency Quantiles", + "type": "timeseries" + } + ], + "refresh": "5s", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "supermq", + "uid": "sgKwOwY4k", + "version": 1, + "weekStart": "" +} diff --git a/docker/supermq-docker/addons/prometheus/metrics/prometheus.yml b/docker/supermq-docker/addons/prometheus/metrics/prometheus.yml new file mode 100644 index 000000000..1c705c1d3 --- /dev/null +++ b/docker/supermq-docker/addons/prometheus/metrics/prometheus.yml @@ -0,0 +1,22 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: 'supermq' + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /metrics + follow_redirects: true + enable_http2: true + static_configs: + - targets: + - supermq-clients:9000 + - supermq-users:9002 + - supermq-http:8008 + - supermq-ws:8186 + - supermq-coap:5683 diff --git a/docker/supermq-docker/addons/vault/README.md b/docker/supermq-docker/addons/vault/README.md new file mode 100644 index 000000000..4b84b4012 --- /dev/null +++ b/docker/supermq-docker/addons/vault/README.md @@ -0,0 +1,290 @@ +# Vault + +This is Vault service deployment to be used with SuperMQ. + +When the Vault service is started, some initialization steps need to be done to set clients up. + +## Configuration + +| Variable | Description | Default | +| :-------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------- | +| SMQ_VAULT_ADDR | Vault Address | http://vault:8200 | +| SMQ_VAULT_UNSEAL_KEY_1 | Vault unseal key | "" | +| SMQ_VAULT_UNSEAL_KEY_2 | Vault unseal key | "" | +| SMQ_VAULT_UNSEAL_KEY_3 | Vault unseal key | "" | +| SMQ_VAULT_TOKEN | Vault cli access token | "" | +| SMQ_VAULT_PKI_PATH | Vault secrets engine path for Root CA | pki | +| SMQ_VAULT_PKI_ROLE_NAME | Vault Root CA role name to issue intermediate CA | supermq_int_ca | +| SMQ_VAULT_PKI_FILE_NAME | Root CA Certificates name used by`vault_set_pki.sh` | mg_root | +| SMQ_VAULT_PKI_CA_CN | Common name used for Root CA creation by`vault_set_pki.sh` | SuperMQ Root Certificate Authority | +| SMQ_VAULT_PKI_CA_OU | Organization unit used for Root CA creation by`vault_set_pki.sh` | SuperMQ | +| SMQ_VAULT_PKI_CA_O | Organization used for Root CA creation by`vault_set_pki.sh` | SuperMQ | +| SMQ_VAULT_PKI_CA_C | Country used for Root CA creation by`vault_set_pki.sh` | FRANCE | +| SMQ_VAULT_PKI_CA_L | Location used for Root CA creation by`vault_set_pki.sh` | PARIS | +| SMQ_VAULT_PKI_CA_ST | State or Provisions used for Root CA creation by`vault_set_pki.sh` | PARIS | +| SMQ_VAULT_PKI_CA_ADDR | Address used for Root CA creation by`vault_set_pki.sh` | 5 Av. Anatole | +| SMQ_VAULT_PKI_CA_PO | Postal code used for Root CA creation by`vault_set_pki.sh` | 75007 | +| SMQ_VAULT_PKI_CLUSTER_PATH | Vault Root CA Cluster Path | http://localhost | +| SMQ_VAULT_PKI_CLUSTER_AIA_PATH | Vault Root CA Cluster AIA Path | http://localhost | +| SMQ_VAULT_PKI_INT_PATH | Vault secrets engine path for Intermediate CA | pki_int | +| SMQ_VAULT_PKI_INT_SERVER_CERTS_ROLE_NAME | Vault Intermediate CA role name to issue server certificate | supermq_server_certs | +| SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME | Vault Intermediate CA role name to issue Clients certificates | supermq_clients_certs | +| SMQ_VAULT_PKI_INT_FILE_NAME | Intermediate CA Certificates name used by`vault_set_pki.sh` | mg_root | +| SMQ_VAULT_PKI_INT_CA_CN | Common name used for Intermediate CA creation by`vault_set_pki.sh` | SuperMQ Root Certificate Authority | +| SMQ_VAULT_PKI_INT_CA_OU | Organization unit used for Root CA creation by`vault_set_pki.sh` | SuperMQ | +| SMQ_VAULT_PKI_INT_CA_O | Organization used for Intermediate CA creation by`vault_set_pki.sh` | SuperMQ | +| SMQ_VAULT_PKI_INT_CA_C | Country used for Intermediate CA creation by`vault_set_pki.sh` | FRANCE | +| SMQ_VAULT_PKI_INT_CA_L | Location used for Intermediate CA creation by`vault_set_pki.sh` | PARIS | +| SMQ_VAULT_PKI_INT_CA_ST | State or Provisions used for Intermediate CA creation by`vault_set_pki.sh` | PARIS | +| SMQ_VAULT_PKI_INT_CA_ADDR | Address used for Intermediate CA creation by`vault_set_pki.sh` | 5 Av. Anatole | +| SMQ_VAULT_PKI_INT_CA_PO | Postal code used for Intermediate CA creation by`vault_set_pki.sh` | 75007 | +| SMQ_VAULT_PKI_INT_CLUSTER_PATH | Vault Intermediate CA Cluster Path | http://localhost | +| SMQ_VAULT_PKI_INT_CLUSTER_AIA_PATH | Vault Intermediate CA Cluster AIA Path | http://localhost | +| SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID | Vault Intermediate CA Clients Certificate issuer AppRole authentication RoleID | supermq | +| SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET | Vault Intermediate CA Clients Certificate issuer AppRole authentication Secret | supermq | + +## Setup + +The following scripts are provided, which work on the running Vault service from within the `docker/addons/vault/scripts` directory. + +### 1. `vault_init.sh` + +Calls `vault operator init` to perform the initial vault initialization and generates a `docker/addons/vault/scripts/data/secrets` file which contains the Vault unseal keys and root tokens. + +### 2. `vault_copy_env.sh` + +After the initial setup, the Vault-related environment variables (`SMQ_VAULT_TOKEN`, `SMQ_VAULT_UNSEAL_KEY_1`, `SMQ_VAULT_UNSEAL_KEY_2`, `SMQ_VAULT_UNSEAL_KEY_3`) need to be updated in the `.env` file. + +The `vault_copy_env.sh` script automatically retrieves these values from the `docker/addons/vault/scripts/data/secrets` file and updates the corresponding environment variables in your `.env` file. + +Example: + +```sh +Vault environment variables have been successfully set in ~/supermq/docker/.env +``` + +### 3. `vault_unseal.sh` + +This can be run after the initialization to unseal Vault, which is necessary for it to be used to store and/or get secrets. + +This can be used if you don't want to restart the service. + +The unseal environment variables need to be set in `.env` for the script to work (`SMQ_VAULT_TOKEN`,`SMQ_VAULT_UNSEAL_KEY_1`, `SMQ_VAULT_UNSEAL_KEY_2`, `SMQ_VAULT_UNSEAL_KEY_3`). + +This script should not be necessary to run after the initial setup, since the Vault service unseals itself when starting the container. + +Example output: + +```bash +Key Value +--- ----- +Seal Type shamir +Initialized true +Sealed true +Total Shares 5 +Threshold 3 +Unseal Progress 1/3 +Unseal Nonce 4c248cc8-e9f5-055e-319b-00ee06f998a0 +Version 1.15.4 +Build Date 2023-12-04T17:45:28Z +Storage Type file +HA Enabled false +Key Value +--- ----- +Seal Type shamir +Initialized true +Sealed true +Total Shares 5 +Threshold 3 +Unseal Progress 2/3 +Unseal Nonce 4c248cc8-e9f5-055e-319b-00ee06f998a0 +Version 1.15.4 +Build Date 2023-12-04T17:45:28Z +Storage Type file +HA Enabled false +Key Value +--- ----- +Seal Type shamir +Initialized true +Sealed false +Total Shares 5 +Threshold 3 +Unseal Progress 3/3 +Unseal Nonce 4c248cc8-e9f5-055e-319b-00ee06f998a0 +Version 1.15.4 +Build Date 2023-12-04T17:45:28Z +Storage Type file +HA Enabled false +``` + +### 4. vault_set_pki.sh + +The `vault_set_pki.sh` script is responsible for generating the root certificate, intermediate certificate, and HTTPS server certificate. All generated certificates, keys, and CSR files are stored in the `docker/addons/vault/scripts/data` directory. + +The script pulls necessary parameters for certificate generation from environment variables, which are, by default, loaded from `docker/.env`. + +- Environment variables prefixed with `SMQ_VAULT_PKI` in the `docker/.env` file are used for generating the root CA. +- Environment variables prefixed with `SMQ_VAULT_PKI_INT` are used for generating the intermediate CA. + +To skip generating the server certificate and key, you can pass the `--skip-server-cert` option to the script: + +```sh +./vault_set_pki.sh --skip-server-cert +``` + +#### Troubleshooting: + +If you encounter the following error: + +```sh +jq command could not be found, please install it and try again. +``` + +Install `jq` using: + +```sh +sudo apt-get update && sudo apt-get install -y jq +``` + +After installing `jq`, rerun the script. + +### 5. `vault_create_approle.sh` + +This script enables AppRole authorization in Vault. The certs service uses these AppRole credentials to issue and revoke certificates from the Vault intermediate CA. + +Example output: + +```sh +Success! You are now authenticated. The token information displayed below +is already stored in the token helper. You do NOT need to run "vault login" +again. Future Vault requests will automatically use this token. + +Key Value +--- ----- +token +token_accessor i6YVeKh4wQ4e0Aj0ONiyGw1Z +token_duration ∞ +token_renewable false +token_policies ["root"] +identity_policies [] +policies ["root"] +Creating new policy for AppRole +Successfully copied 2.56kB to supermq-vault:/vault/supermq_clients_certs_issue.hcl +Success! Uploaded policy: supermq_clients_certs_issue +Enabling AppRole +Success! Enabled approle auth method at: approle/ +Deleting old AppRole +Success! Data deleted (if it existed) at: auth/approle/role/supermq_clients_certs_issuer +Creating new AppRole +Success! Data written to: auth/approle/role/supermq_clients_certs_issuer +Writing custom role ID +Key Value +--- ----- +role_id f23942b3-62b9-7456-784f-220ca3f703b9 +Success! Data written to: auth/approle/role/supermq_clients_certs_issuer/role-id +Writing custom secret +Key Value +--- ----- +secret_id 61d5a30f-634c-6027-f5b6-4934e6fc49b2 +secret_id_accessor 1d744f6e-e0c2-5431-a87a-2b23fde584a7 +secret_id_num_uses 0 +secret_id_ttl 0s +Testing custom role ID and secret by logging in +Key Value +--- ----- +token +token_accessor 9cuwS4mrLHKhJQMv0pl9Bbg9 +token_duration 1h +token_renewable true +token_policies ["default" "supermq_clients_certs_issue"] +identity_policies [] +policies ["default" "supermq_clients_certs_issue"] +token_meta_role_name supermq_clients_certs_issuer +``` + +By default, the `vault_create_approle.sh` script tries to enable the AppRole authentication method. Certs service uses the approle credentials to issue and revoke clients certificate from vault intermedate CA. If AppRole is already enabled, you can skip this step by passing the `--skip-enable-approle` argument: + +```sh +./vault_create_approle.sh --skip-enable-approle +``` + +### 6. `vault_copy_certs.sh` + +This script copies the required certificates and keys from `docker/addons/vault/scripts/data` to the `docker/ssl/certs` folder. + +Example output: + +```bash +Copying certificate files +'data/localhost.crt' -> '~/Documents/supermq/docker/ssl/certs/supermq-server.crt' +'data/localhost.key' -> '~/Documents/supermq/docker/ssl/certs/supermq-server.key' +'data/mg_int.key' -> '~/Documents/supermq/docker/ssl/certs/ca.key' +'data/mg_int_bundle.crt' -> '~/Documents/supermq/docker/ssl/certs/ca.crt' +``` + +## Custom `.env` Path Support + +Vault scripts support specifying a custom `.env` file path using the `--env-file` argument. If this argument is not provided, the scripts will use the default `.env` file located at `docker/.env`. + +To use a different `.env` file, include the `--env-file` argument followed by the path to your `.env` file when running the Vault scripts. Below are examples of how to execute each script with a custom `.env` file path: + +```bash +./vault_init.sh --env-file /custom/path/.env +./vault_copy_env.sh --env-file /custom/path/.env +./vault_unseal.sh --env-file /custom/path/.env +./vault_set_pki.sh --env-file /custom/path/.env +./vault_create_approle.sh --env-file /custom/path/.env +./vault_copy_certs.sh --env-file /custom/path/.env +``` + +## Hashicorp Cloud Platform (HCP) Vault + +To have the same PKI setup can done in Hashicorp Cloud Platform (HCP) Vault follow the below steps: +Requirement: [VAULT CLI](https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-install) + +- Replace the environmental variable `SMQ_VAULT_ADDR` in `docker/.env` with HCP Vault address. +- Replace the environmental variable `SMQ_VAULT_TOKEN` in `docker/.env` with HCP Vault Admin token. +- Run script `vault_set_pki.sh` and `vault_create_approle.sh`. +- Optional step, run script `vault_copy_certs.sh` to copy certificates to supermq default path. + +## Vault CLI + +It can also be useful to run the Vault CLI for inspection and administration work. + +```bash +Usage: vault [args] + +Common commands: + read Read data and retrieves secrets + write Write data, configuration, and secrets + delete Delete secrets and configuration + list List data or secrets + login Authenticate locally + agent Start a Vault agent + server Start a Vault server + status Print seal and HA status + unwrap Unwrap a wrapped secret + +Other commands: + audit Interact with audit devices + auth Interact with auth methods + debug Runs the debug command + kv Interact with Vault's Key-Value storage + lease Interact with leases + monitor Stream log messages from a Vault server + namespace Interact with namespaces + operator Perform operator-specific tasks + path-help Retrieve API help for paths + plugin Interact with Vault plugins and catalog + policy Interact with policies + print Prints runtime configurations + secrets Interact with secrets engines + ssh Initiate an SSH session + token Interact with tokens +``` + +If the Vault is setup through `docker/addons/vault`, then Vault CLI can be run directly using the Vault image in Docker: `docker run -it supermq/vault:latest vault` + +## Vault Web UI + +If the Vault is setup through `docker/addons/vault`, Then Vault Web UI is accessible by default on `http://localhost:8200/ui`. diff --git a/docker/supermq-docker/addons/vault/config.hcl b/docker/supermq-docker/addons/vault/config.hcl new file mode 100644 index 000000000..192dd5af2 --- /dev/null +++ b/docker/supermq-docker/addons/vault/config.hcl @@ -0,0 +1,10 @@ +storage "file" { + path = "/vault/file" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 +} + +ui = true diff --git a/docker/supermq-docker/addons/vault/docker-compose.yml b/docker/supermq-docker/addons/vault/docker-compose.yml new file mode 100644 index 000000000..4ef5ff367 --- /dev/null +++ b/docker/supermq-docker/addons/vault/docker-compose.yml @@ -0,0 +1,39 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This docker-compose file contains optional Vault service for SuperMQ platform. +# Since this is optional, this file is dependent of docker-compose file +# from /docker. In order to run these services, execute command: +# docker compose -f docker/docker-compose.yml -f docker/addons/vault/docker-compose.yml up +# from project root. Vault default port (8200) is exposed, so you can use Vault CLI tool for +# vault inspection and administration, as well as access the UI. + +networks: + supermq-base-net: + +volumes: + supermq-vault-volume: + +services: + vault: + image: hashicorp/vault:1.15.4 + container_name: supermq-vault + ports: + - ${SMQ_VAULT_PORT}:8200 + networks: + - supermq-base-net + volumes: + - supermq-vault-volume:/vault/file + - supermq-vault-volume:/vault/logs + - ./config.hcl:/vault/config/config.hcl + - ./entrypoint.sh:/entrypoint.sh + environment: + VAULT_ADDR: http://127.0.0.1:${SMQ_VAULT_PORT} + SMQ_VAULT_PORT: ${SMQ_VAULT_PORT} + SMQ_VAULT_UNSEAL_KEY_1: ${SMQ_VAULT_UNSEAL_KEY_1} + SMQ_VAULT_UNSEAL_KEY_2: ${SMQ_VAULT_UNSEAL_KEY_2} + SMQ_VAULT_UNSEAL_KEY_3: ${SMQ_VAULT_UNSEAL_KEY_3} + entrypoint: /bin/sh + command: /entrypoint.sh + cap_add: + - IPC_LOCK diff --git a/docker/supermq-docker/addons/vault/entrypoint.sh b/docker/supermq-docker/addons/vault/entrypoint.sh new file mode 100644 index 000000000..382452e18 --- /dev/null +++ b/docker/supermq-docker/addons/vault/entrypoint.sh @@ -0,0 +1,25 @@ +#!/usr/bin/dumb-init /bin/sh +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +VAULT_CONFIG_DIR=/vault/config + +docker-entrypoint.sh server & +VAULT_PID=$! + +sleep 2 + +echo $SMQ_VAULT_UNSEAL_KEY_1 +echo $SMQ_VAULT_UNSEAL_KEY_2 +echo $SMQ_VAULT_UNSEAL_KEY_3 + +if [[ ! -z "${SMQ_VAULT_UNSEAL_KEY_1}" ]] && + [[ ! -z "${SMQ_VAULT_UNSEAL_KEY_2}" ]] && + [[ ! -z "${SMQ_VAULT_UNSEAL_KEY_3}" ]]; then + echo "Unsealing Vault" + vault operator unseal ${SMQ_VAULT_UNSEAL_KEY_1} + vault operator unseal ${SMQ_VAULT_UNSEAL_KEY_2} + vault operator unseal ${SMQ_VAULT_UNSEAL_KEY_3} +fi + +wait $VAULT_PID \ No newline at end of file diff --git a/docker/supermq-docker/addons/vault/scripts/.gitignore b/docker/supermq-docker/addons/vault/scripts/.gitignore new file mode 100644 index 000000000..a2b072da1 --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/.gitignore @@ -0,0 +1,5 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +data +supermq_clients_certs_issue.hcl diff --git a/docker/supermq-docker/addons/vault/scripts/magistrala_clients_certs_issue.template.hcl b/docker/supermq-docker/addons/vault/scripts/magistrala_clients_certs_issue.template.hcl new file mode 100644 index 000000000..cab99abf0 --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/magistrala_clients_certs_issue.template.hcl @@ -0,0 +1,32 @@ + +# Allow issue certificate with role with default issuer from Intermediate PKI +path "${SMQ_VAULT_PKI_INT_PATH}/issue/${SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME}" { + capabilities = ["create", "update"] +} + +## Revole certificate from Intermediate PKI +path "${SMQ_VAULT_PKI_INT_PATH}/revoke" { + capabilities = ["create", "update"] +} + +## List Revoked Certificates from Intermediate PKI +path "${SMQ_VAULT_PKI_INT_PATH}/certs/revoked" { + capabilities = ["list"] +} + + +## List Certificates from Intermediate PKI +path "${SMQ_VAULT_PKI_INT_PATH}/certs" { + capabilities = ["list"] +} + +## Read Certificate from Intermediate PKI +path "${SMQ_VAULT_PKI_INT_PATH}/cert/+" { + capabilities = ["read"] +} +path "${SMQ_VAULT_PKI_INT_PATH}/cert/+/raw" { + capabilities = ["read"] +} +path "${SMQ_VAULT_PKI_INT_PATH}/cert/+/raw/pem" { + capabilities = ["read"] +} diff --git a/docker/supermq-docker/addons/vault/scripts/vault_cmd.sh b/docker/supermq-docker/addons/vault/scripts/vault_cmd.sh new file mode 100644 index 000000000..2dac80d85 --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_cmd.sh @@ -0,0 +1,24 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +vault() { + if is_container_running "supermq-vault"; then + docker exec -it supermq-vault vault "$@" + else + if which vault &> /dev/null; then + $(which vault) "$@" + else + echo "supermq-vault container or vault command not found. Please refer to the documentation: https://github.com/absmach/supermq/blob/main/docker/addons/vault/README.md" + fi + fi +} + +is_container_running() { + local container_name="$1" + if [ "$(docker inspect --format '{{.State.Running}}' "$container_name" 2>/dev/null)" = "true" ]; then + return 0 + else + return 1 + fi +} diff --git a/docker/supermq-docker/addons/vault/scripts/vault_copy_certs.sh b/docker/supermq-docker/addons/vault/scripts/vault_copy_certs.sh new file mode 100755 index 000000000..a069fbdf0 --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_copy_certs.sh @@ -0,0 +1,86 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# default env file path +env_file="docker/.env" + +# default certs copy path +certs_copy_path="docker/ssl/certs/" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + --certs-copy-path) + if [[ -z "${2:-}" ]]; then + echo "Error: --certs-copy-path requires a non-empty option argument." + exit 1 + fi + certs_copy_path="$2" + shift + ;; + *) + echo "Error: Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +readDotEnv() { + set -o allexport + source "$env_file" + set +o allexport +} + +readDotEnv + +server_name="localhost" + +# Check if SMQ_NGINX_SERVER_NAME is set or not empty +if [ -n "${SMQ_NGINX_SERVER_NAME:-}" ]; then + server_name="$SMQ_NGINX_SERVER_NAME" +fi + +echo "Copying certificate files to ${certs_copy_path}" + +if [ -e "$scriptdir/data/${server_name}.crt" ]; then + cp -v "$scriptdir/data/${server_name}.crt" "${certs_copy_path}supermq-server.crt" +else + echo "${server_name}.crt file not available" +fi + +if [ -e "$scriptdir/data/${server_name}.key" ]; then + cp -v "$scriptdir/data/${server_name}.key" "${certs_copy_path}supermq-server.key" +else + echo "${server_name}.key file not available" +fi + +if [ -e "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.key" ]; then + cp -v "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.key" "${certs_copy_path}ca.key" +else + echo "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.key file not available" +fi + +if [ -e "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_bundle.crt" ]; then + cp -v "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_bundle.crt" "${certs_copy_path}ca.crt" +else + echo "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_bundle.crt file not available" +fi + +exit 0 diff --git a/docker/supermq-docker/addons/vault/scripts/vault_copy_env.sh b/docker/supermq-docker/addons/vault/scripts/vault_copy_env.sh new file mode 100755 index 000000000..865679d2f --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_copy_env.sh @@ -0,0 +1,46 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# default env file path +env_file="docker/.env" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +write_env() { + if [ -e "$scriptdir/data/secrets" ]; then + sed -i "s,SMQ_VAULT_UNSEAL_KEY_1=.*,SMQ_VAULT_UNSEAL_KEY_1=$(awk -F ": " '$1 == "Unseal Key 1" {print $2}' $scriptdir/data/secrets)," "$env_file" + sed -i "s,SMQ_VAULT_UNSEAL_KEY_2=.*,SMQ_VAULT_UNSEAL_KEY_2=$(awk -F ": " '$1 == "Unseal Key 2" {print $2}' $scriptdir/data/secrets)," "$env_file" + sed -i "s,SMQ_VAULT_UNSEAL_KEY_3=.*,SMQ_VAULT_UNSEAL_KEY_3=$(awk -F ": " '$1 == "Unseal Key 3" {print $2}' $scriptdir/data/secrets)," "$env_file" + sed -i "s,SMQ_VAULT_TOKEN=.*,SMQ_VAULT_TOKEN=$(awk -F ": " '$1 == "Initial Root Token" {print $2}' $scriptdir/data/secrets)," "$env_file" + echo "Vault environment variables are set successfully in $env_file" + else + echo "Error: Source file '$scriptdir/data/secrets' not found." + fi +} + +write_env diff --git a/docker/supermq-docker/addons/vault/scripts/vault_create_approle.sh b/docker/supermq-docker/addons/vault/scripts/vault_create_approle.sh new file mode 100755 index 000000000..ed2f0043c --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_create_approle.sh @@ -0,0 +1,122 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# default env file path +env_file="docker/.env" + +SKIP_ENABLE_APP_ROLE="" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + --skip-enable-approle) + SKIP_ENABLE_APP_ROLE="true" + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +readDotEnv() { + set -o allexport + source "$env_file" + set +o allexport +} + +source "$scriptdir/vault_cmd.sh" + +vaultCreatePolicyFile() { + envsubst ' + ${SMQ_VAULT_PKI_INT_PATH} + ${SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME} + ' < "$scriptdir/supermq_clients_certs_issue.template.hcl" > "$scriptdir/supermq_clients_certs_issue.hcl" +} + +vaultCreatePolicy() { + echo "Creating new policy for AppRole" + if is_container_running "supermq-vault"; then + docker cp "$scriptdir/supermq_clients_certs_issue.hcl" supermq-vault:/vault/supermq_clients_certs_issue.hcl + vault policy write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} supermq_clients_certs_issue /vault/supermq_clients_certs_issue.hcl + else + vault policy write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} supermq_clients_certs_issue "$scriptdir/supermq_clients_certs_issue.hcl" + fi +} + +vaultEnableAppRole() { + if [[ "$SKIP_ENABLE_APP_ROLE" == "true" ]]; then + echo "Skipping Enable AppRole" + else + echo "Enabling AppRole" + vault auth enable -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} approle + fi +} + +vaultDeleteRole() { + echo "Deleting old AppRole" + vault delete -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/role/supermq_clients_certs_issuer +} + +vaultCreateRole() { + echo "Creating new AppRole" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/role/supermq_clients_certs_issuer \ + token_policies=supermq_clients_certs_issue secret_id_num_uses=0 \ + secret_id_ttl=0 token_ttl=1h token_max_ttl=3h token_num_uses=0 +} + +vaultWriteCustomRoleID() { + echo "Writing custom role id" + vault read -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/role/supermq_clients_certs_issuer/role-id + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/role/supermq_clients_certs_issuer/role-id role_id=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID} +} + +vaultWriteCustomSecret() { + echo "Writing custom secret" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -f auth/approle/role/supermq_clients_certs_issuer/secret-id + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/role/supermq_clients_certs_issuer/custom-secret-id secret_id=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET} num_uses=0 ttl=0 +} + +vaultTestRoleLogin() { + echo "Testing custom roleid secret by logging in" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} auth/approle/login \ + role_id=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_ROLEID} \ + secret_id=${SMQ_VAULT_CLIENTS_CERTS_ISSUER_SECRET} +} + +if ! command -v jq &> /dev/null; then + echo "jq command could not be found, please install it and try again." + exit 1 +fi + +readDotEnv + +vault login -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_TOKEN} + +vaultCreatePolicyFile +vaultCreatePolicy +vaultEnableAppRole +vaultDeleteRole +vaultCreateRole +vaultWriteCustomRoleID +vaultWriteCustomSecret +vaultTestRoleLogin + +exit 0 diff --git a/docker/supermq-docker/addons/vault/scripts/vault_init.sh b/docker/supermq-docker/addons/vault/scripts/vault_init.sh new file mode 100755 index 000000000..10900e119 --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_init.sh @@ -0,0 +1,46 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# default env file path +env_file="docker/.env" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +readDotEnv() { + set -o allexport + source "$env_file" + set +o allexport +} + +source "$scriptdir/vault_cmd.sh" + +readDotEnv + +mkdir -p "$scriptdir/data" + +vault operator init -address="$SMQ_VAULT_ADDR" 2>&1 | tee >(sed -r 's/\x1b\[[0-9;]*m//g' > "$scriptdir/data/secrets") diff --git a/docker/supermq-docker/addons/vault/scripts/vault_set_pki.sh b/docker/supermq-docker/addons/vault/scripts/vault_set_pki.sh new file mode 100755 index 000000000..289d55f2d --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_set_pki.sh @@ -0,0 +1,251 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# edfault env file path +env_file="docker/.env" + +SKIP_SERVER_CERT="" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + --skip-server-cert) + SKIP_SERVER_CERT="--skip-server-cert" + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +readDotEnv() { + set -o allexport + source "$env_file" + set +o allexport +} + +server_name="localhost" + +# Check if SMQ_NGINX_SERVER_NAME is set or not empty +if [ -n "${SMQ_NGINX_SERVER_NAME:-}" ]; then + server_name="$SMQ_NGINX_SERVER_NAME" +fi + +source "$scriptdir/vault_cmd.sh" + +vaultEnablePKI() { + vault secrets enable -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -path ${SMQ_VAULT_PKI_PATH} pki + vault secrets tune -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -max-lease-ttl=87600h ${SMQ_VAULT_PKI_PATH} +} + +vaultConfigPKIClusterPath() { + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_PATH}/config/cluster aia_path=${SMQ_VAULT_PKI_CLUSTER_AIA_PATH} path=${SMQ_VAULT_PKI_CLUSTER_PATH} +} + +vaultConfigPKICrl() { + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_PATH}/config/crl expiry="5m" ocsp_disable=false ocsp_expiry=0 auto_rebuild=true auto_rebuild_grace_period="2m" enable_delta=true delta_rebuild_interval="1m" +} + +vaultAddRoleToSecret() { + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_PATH}/roles/${SMQ_VAULT_PKI_ROLE_NAME} \ + allow_any_name=true \ + max_ttl="8760h" \ + default_ttl="8760h" \ + generate_lease=true +} + +vaultGenerateRootCACertificate() { + echo "Generate root CA certificate" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -format=json ${SMQ_VAULT_PKI_PATH}/root/generate/exported \ + common_name="\"$SMQ_VAULT_PKI_CA_CN\"" \ + ou="\"$SMQ_VAULT_PKI_CA_OU\"" \ + organization="\"$SMQ_VAULT_PKI_CA_O\"" \ + country="\"$SMQ_VAULT_PKI_CA_C\"" \ + locality="\"$SMQ_VAULT_PKI_CA_L\"" \ + province="\"$SMQ_VAULT_PKI_CA_ST\"" \ + street_address="\"$SMQ_VAULT_PKI_CA_ADDR\"" \ + postal_code="\"$SMQ_VAULT_PKI_CA_PO\"" \ + ttl=87600h | tee >(jq -r .data.certificate >"$scriptdir/data/${SMQ_VAULT_PKI_FILE_NAME}_ca.crt") \ + >(jq -r .data.issuing_ca >"$scriptdir/data/${SMQ_VAULT_PKI_FILE_NAME}_issuing_ca.crt") \ + >(jq -r .data.private_key >"$scriptdir/data/${SMQ_VAULT_PKI_FILE_NAME}_ca.key") +} + +vaultSetupRootCAIssuingURLs() { + echo "Setup URLs for CRL and issuing" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_PATH}/config/urls \ + issuing_certificates="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_PATH}/ca" \ + crl_distribution_points="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_PATH}/crl" \ + ocsp_servers="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_PATH}/ocsp" \ + enable_templating=true +} + +vaultGenerateIntermediateCAPKI() { + echo "Generate Intermediate CA PKI" + vault secrets enable -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -path=${SMQ_VAULT_PKI_INT_PATH} pki + vault secrets tune -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -max-lease-ttl=43800h ${SMQ_VAULT_PKI_INT_PATH} +} + +vaultConfigIntermediatePKIClusterPath() { + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/config/cluster aia_path=${SMQ_VAULT_PKI_INT_CLUSTER_AIA_PATH} path=${SMQ_VAULT_PKI_INT_CLUSTER_PATH} +} + +vaultConfigIntermediatePKICrl() { + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/config/crl expiry="5m" ocsp_disable=false ocsp_expiry=0 auto_rebuild=true auto_rebuild_grace_period="2m" enable_delta=true delta_rebuild_interval="1m" +} + +vaultGenerateIntermediateCSR() { + echo "Generate intermediate CSR" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -format=json ${SMQ_VAULT_PKI_INT_PATH}/intermediate/generate/exported \ + common_name="\"$SMQ_VAULT_PKI_INT_CA_CN\"" \ + ou="\"$SMQ_VAULT_PKI_INT_CA_OU\""\ + organization="\"$SMQ_VAULT_PKI_INT_CA_O\"" \ + country="\"$SMQ_VAULT_PKI_INT_CA_C\"" \ + locality="\"$SMQ_VAULT_PKI_INT_CA_L\"" \ + province="\"$SMQ_VAULT_PKI_INT_CA_ST\"" \ + street_address="\"$SMQ_VAULT_PKI_INT_CA_ADDR\"" \ + postal_code="\"$SMQ_VAULT_PKI_INT_CA_PO\"" \ + | tee >(jq -r .data.csr >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.csr") \ + >(jq -r .data.private_key >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.key") +} + +vaultSignIntermediateCSR() { + echo "Sign intermediate CSR" + if is_container_running "supermq-vault"; then + docker cp "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.csr" supermq-vault:/vault/${SMQ_VAULT_PKI_INT_FILE_NAME}.csr + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -format=json ${SMQ_VAULT_PKI_PATH}/root/sign-intermediate \ + csr=@/vault/${SMQ_VAULT_PKI_INT_FILE_NAME}.csr ttl="8760h" \ + ou="\"$SMQ_VAULT_PKI_INT_CA_OU\""\ + organization="\"$SMQ_VAULT_PKI_INT_CA_O\"" \ + country="\"$SMQ_VAULT_PKI_INT_CA_C\"" \ + locality="\"$SMQ_VAULT_PKI_INT_CA_L\"" \ + province="\"$SMQ_VAULT_PKI_INT_CA_ST\"" \ + street_address="\"$SMQ_VAULT_PKI_INT_CA_ADDR\"" \ + postal_code="\"$SMQ_VAULT_PKI_INT_CA_PO\"" \ + | tee >(jq -r .data.certificate >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt") \ + >(jq -r .data.issuing_ca >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_issuing_ca.crt") + else + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -format=json ${SMQ_VAULT_PKI_PATH}/root/sign-intermediate \ + csr=@"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.csr" ttl="8760h" \ + ou="\"$SMQ_VAULT_PKI_INT_CA_OU\""\ + organization="\"$SMQ_VAULT_PKI_INT_CA_O\"" \ + country="\"$SMQ_VAULT_PKI_INT_CA_C\"" \ + locality="\"$SMQ_VAULT_PKI_INT_CA_L\"" \ + province="\"$SMQ_VAULT_PKI_INT_CA_ST\"" \ + street_address="\"$SMQ_VAULT_PKI_INT_CA_ADDR\"" \ + postal_code="\"$SMQ_VAULT_PKI_INT_CA_PO\"" \ + | tee >(jq -r .data.certificate >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt") \ + >(jq -r .data.issuing_ca >"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_issuing_ca.crt") + fi +} + +vaultInjectIntermediateCertificate() { + echo "Inject Intermediate Certificate" + if is_container_running "supermq-vault"; then + docker cp "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt" supermq-vault:/vault/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/intermediate/set-signed certificate=@/vault/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt + else + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/intermediate/set-signed certificate=@"$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt" + fi +} + +vaultGenerateIntermediateCertificateBundle() { + echo "Generate intermediate certificate bundle" + cat "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}.crt" "$scriptdir/data/${SMQ_VAULT_PKI_FILE_NAME}_ca.crt" \ + > "$scriptdir/data/${SMQ_VAULT_PKI_INT_FILE_NAME}_bundle.crt" +} + +vaultSetupIntermediateIssuingURLs() { + echo "Setup URLs for CRL and issuing" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/config/urls \ + issuing_certificates="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_INT_PATH}/ca" \ + crl_distribution_points="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_INT_PATH}/crl" \ + ocsp_servers="{{cluster_aia_path}}/v1/${SMQ_VAULT_PKI_INT_PATH}/ocsp" \ + enable_templating=true +} + +vaultSetupServerCertsRole() { + if [ "$SKIP_SERVER_CERT" == "--skip-server-cert" ]; then + echo "Skipping server certificate role" + else + echo "Setup Server certificate role" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/roles/${SMQ_VAULT_PKI_INT_SERVER_CERTS_ROLE_NAME} \ + allow_subdomains=true \ + max_ttl="4320h" + fi +} + +vaultGenerateServerCertificate() { + if [ "$SKIP_SERVER_CERT" == "--skip-server-cert" ]; then + echo "Skipping generate server certificate" + else + echo "Generate server certificate" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} -format=json ${SMQ_VAULT_PKI_INT_PATH}/issue/${SMQ_VAULT_PKI_INT_SERVER_CERTS_ROLE_NAME} \ + common_name="$server_name" ttl="4320h" \ + | tee >(jq -r .data.certificate >"$scriptdir/data/${server_name}.crt") \ + >(jq -r .data.private_key >"$scriptdir/data/${server_name}.key") + fi +} + +vaultSetupClientCertsRole() { + echo "Setup Client Certs role" + vault write -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_PKI_INT_PATH}/roles/${SMQ_VAULT_PKI_INT_CLIENTS_CERTS_ROLE_NAME} \ + allow_subdomains=true \ + allow_any_name=true \ + max_ttl="2160h" +} + +vaultCleanupFiles() { + if is_container_running "supermq-vault"; then + docker exec supermq-vault sh -c 'rm -rf /vault/*.{crt,csr}' + fi +} + +if ! command -v jq &> /dev/null; then + echo "jq command could not be found, please install it and try again." + exit 1 +fi + +readDotEnv + +mkdir -p "$scriptdir/data" + +vault login -namespace=${SMQ_VAULT_NAMESPACE} -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_TOKEN} + +vaultEnablePKI +vaultConfigPKIClusterPath +vaultConfigPKICrl +vaultAddRoleToSecret +vaultGenerateRootCACertificate +vaultSetupRootCAIssuingURLs +vaultGenerateIntermediateCAPKI +vaultConfigIntermediatePKIClusterPath +vaultConfigIntermediatePKICrl +vaultGenerateIntermediateCSR +vaultSignIntermediateCSR +vaultInjectIntermediateCertificate +vaultGenerateIntermediateCertificateBundle +vaultSetupIntermediateIssuingURLs +vaultSetupServerCertsRole +vaultGenerateServerCertificate +vaultSetupClientCertsRole +vaultCleanupFiles + +exit 0 diff --git a/docker/supermq-docker/addons/vault/scripts/vault_unseal.sh b/docker/supermq-docker/addons/vault/scripts/vault_unseal.sh new file mode 100755 index 000000000..c7f5d654b --- /dev/null +++ b/docker/supermq-docker/addons/vault/scripts/vault_unseal.sh @@ -0,0 +1,46 @@ +#!/usr/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# default env file path +env_file="docker/.env" + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env-file) + if [[ -z "${2:-}" ]]; then + echo "Error: --env-file requires a non-empty option argument." + exit 1 + fi + env_file="$2" + if [[ ! -f "$env_file" ]]; then + echo "Error: .env file not found at $env_file" + exit 1 + fi + shift + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +readDotEnv() { + set -o allexport + source "$env_file" + set +o allexport +} + +source "$scriptdir/vault_cmd.sh" + +readDotEnv + +vault operator unseal -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_UNSEAL_KEY_1} +vault operator unseal -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_UNSEAL_KEY_2} +vault operator unseal -address=${SMQ_VAULT_ADDR} ${SMQ_VAULT_UNSEAL_KEY_3} diff --git a/docker/supermq-docker/docker-compose.yml b/docker/supermq-docker/docker-compose.yml new file mode 100644 index 000000000..c56bdb27b --- /dev/null +++ b/docker/supermq-docker/docker-compose.yml @@ -0,0 +1,1284 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +name: "supermq" + +networks: + supermq-base-net: + driver: bridge + +volumes: + supermq-users-db-volume: + supermq-groups-db-volume: + supermq-clients-db-volume: + supermq-channels-db-volume: + supermq-clients-redis-volume: + supermq-broker-volume: + supermq-mqtt-broker-volume: + supermq-spicedb-db-volume: + supermq-auth-db-volume: + supermq-pat-db-volume: + supermq-domains-db-volume: + supermq-domains-redis-volume: + supermq-ui-db-volume: + supermq-auth-redis-volume: + +services: + spicedb: + image: "authzed/spicedb:v1.37.0" + container_name: supermq-spicedb + command: "serve" + restart: "always" + networks: + - supermq-base-net + ports: + - "8080:8080" + - "9091:9090" + - "50051:50051" + environment: + SPICEDB_GRPC_PRESHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SPICEDB_DATASTORE_ENGINE: ${SMQ_SPICEDB_DATASTORE_ENGINE} + SPICEDB_DATASTORE_CONN_URI: "${SMQ_SPICEDB_DATASTORE_ENGINE}://${SMQ_SPICEDB_DB_USER}:${SMQ_SPICEDB_DB_PASS}@spicedb-db:${SMQ_SPICEDB_DB_PORT}/${SMQ_SPICEDB_DB_NAME}?sslmode=disable" + depends_on: + - spicedb-migrate + + spicedb-migrate: + image: "authzed/spicedb:v1.37.0" + container_name: supermq-spicedb-migrate + command: "migrate head" + restart: "on-failure" + networks: + - supermq-base-net + environment: + SPICEDB_DATASTORE_ENGINE: ${SMQ_SPICEDB_DATASTORE_ENGINE} + SPICEDB_DATASTORE_CONN_URI: "${SMQ_SPICEDB_DATASTORE_ENGINE}://${SMQ_SPICEDB_DB_USER}:${SMQ_SPICEDB_DB_PASS}@spicedb-db:${SMQ_SPICEDB_DB_PORT}/${SMQ_SPICEDB_DB_NAME}?sslmode=disable" + depends_on: + - spicedb-db + + spicedb-db: + image: "postgres:16.2-alpine" + container_name: supermq-spicedb-db + networks: + - supermq-base-net + ports: + - "6010:5432" + environment: + POSTGRES_USER: ${SMQ_SPICEDB_DB_USER} + POSTGRES_PASSWORD: ${SMQ_SPICEDB_DB_PASS} + POSTGRES_DB: ${SMQ_SPICEDB_DB_NAME} + volumes: + - supermq-spicedb-db-volume:/var/lib/postgresql/data + command: ["postgres", "-c", "track_commit_timestamp=on"] + + auth-db: + image: postgres:16.2-alpine + container_name: supermq-auth-db + restart: on-failure + ports: + - 6001:5432 + environment: + POSTGRES_USER: ${SMQ_AUTH_DB_USER} + POSTGRES_PASSWORD: ${SMQ_AUTH_DB_PASS} + POSTGRES_DB: ${SMQ_AUTH_DB_NAME} + networks: + - supermq-base-net + volumes: + - supermq-auth-db-volume:/var/lib/postgresql/data + + auth-redis: + image: redis:7.2.4-alpine + container_name: supermq-auth-redis + restart: on-failure + networks: + - supermq-base-net + volumes: + - supermq-auth-redis-volume:/data + + auth: + image: supermq/auth:${SMQ_RELEASE_TAG} + container_name: supermq-auth + depends_on: + - auth-db + - spicedb + expose: + - ${SMQ_AUTH_GRPC_PORT} + restart: on-failure + environment: + SMQ_AUTH_LOG_LEVEL: ${SMQ_AUTH_LOG_LEVEL} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_AUTH_ACCESS_TOKEN_DURATION: ${SMQ_AUTH_ACCESS_TOKEN_DURATION} + SMQ_AUTH_REFRESH_TOKEN_DURATION: ${SMQ_AUTH_REFRESH_TOKEN_DURATION} + SMQ_AUTH_INVITATION_DURATION: ${SMQ_AUTH_INVITATION_DURATION} + SMQ_AUTH_SECRET_KEY: ${SMQ_AUTH_SECRET_KEY} + SMQ_AUTH_HTTP_HOST: ${SMQ_AUTH_HTTP_HOST} + SMQ_AUTH_HTTP_PORT: ${SMQ_AUTH_HTTP_PORT} + SMQ_AUTH_HTTP_SERVER_CERT: ${SMQ_AUTH_HTTP_SERVER_CERT} + SMQ_AUTH_HTTP_SERVER_KEY: ${SMQ_AUTH_HTTP_SERVER_KEY} + SMQ_AUTH_GRPC_HOST: ${SMQ_AUTH_GRPC_HOST} + SMQ_AUTH_GRPC_PORT: ${SMQ_AUTH_GRPC_PORT} + ## Compose supports parameter expansion in environment, + ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty + ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default + SMQ_AUTH_GRPC_SERVER_CERT: ${SMQ_AUTH_GRPC_SERVER_CERT:+/auth-grpc-server.crt} + SMQ_AUTH_GRPC_SERVER_KEY: ${SMQ_AUTH_GRPC_SERVER_KEY:+/auth-grpc-server.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_AUTH_GRPC_CLIENT_CA_CERTS: ${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:+/auth-grpc-client-ca.crt} + SMQ_AUTH_DB_HOST: ${SMQ_AUTH_DB_HOST} + SMQ_AUTH_DB_PORT: ${SMQ_AUTH_DB_PORT} + SMQ_AUTH_DB_USER: ${SMQ_AUTH_DB_USER} + SMQ_AUTH_DB_PASS: ${SMQ_AUTH_DB_PASS} + SMQ_AUTH_DB_NAME: ${SMQ_AUTH_DB_NAME} + SMQ_AUTH_DB_SSL_MODE: ${SMQ_AUTH_DB_SSL_MODE} + SMQ_AUTH_DB_SSL_CERT: ${SMQ_AUTH_DB_SSL_CERT} + SMQ_AUTH_DB_SSL_KEY: ${SMQ_AUTH_DB_SSL_KEY} + SMQ_AUTH_DB_SSL_ROOT_CERT: ${SMQ_AUTH_DB_SSL_ROOT_CERT} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_AUTH_ADAPTER_INSTANCE_ID: ${SMQ_AUTH_ADAPTER_INSTANCE_ID} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_AUTH_CACHE_URL: ${SMQ_AUTH_CACHE_URL} + SMQ_AUTH_CACHE_KEY_DURATION: ${SMQ_AUTH_CACHE_KEY_DURATION} + SMQ_AUTH_CALLOUT_URLS: ${SMQ_AUTH_CALLOUT_URLS} + SMQ_AUTH_CALLOUT_METHOD: ${SMQ_AUTH_CALLOUT_METHOD} + SMQ_AUTH_CALLOUT_TLS_VERIFICATION: ${SMQ_AUTH_CALLOUT_TLS_VERIFICATION} + SMQ_AUTH_CALLOUT_TIMEOUT: ${SMQ_AUTH_CALLOUT_TIMEOUT} + SMQ_AUTH_CALLOUT_CA_CERT: ${SMQ_AUTH_CALLOUT_CA_CERT} + SMQ_AUTH_CALLOUT_CERT: ${SMQ_AUTH_CALLOUT_CERT} + SMQ_AUTH_CALLOUT_KEY: ${SMQ_AUTH_CALLOUT_KEY} + ports: + - ${SMQ_AUTH_HTTP_PORT}:${SMQ_AUTH_HTTP_PORT} + - ${SMQ_AUTH_GRPC_PORT}:${SMQ_AUTH_GRPC_PORT} + networks: + - supermq-base-net + volumes: + - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} + - supermq-pat-db-volume:/supermq-data + # Auth gRPC mTLS server certificates + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} + target: /auth-grpc-server${SMQ_AUTH_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} + target: /auth-grpc-server${SMQ_AUTH_GRPC_SERVER_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} + target: /auth-grpc-client-ca${SMQ_AUTH_GRPC_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + # Auth Callout Client Certificates + - type: bind + source: ${SMQ_AUTH_CALLOUT_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-callout-client${SMQ_AUTH_CALLOUT_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_CALLOUT_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-callout-client${SMQ_AUTH_CALLOUT_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_CALLOUT_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} + target: /auth-callout-client-ca${SMQ_AUTH_CALLOUT_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + + domains-db: + image: postgres:16.2-alpine + container_name: supermq-domains-db + restart: on-failure + ports: + - 6003:5432 + environment: + POSTGRES_USER: ${SMQ_DOMAINS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_DOMAINS_DB_PASS} + POSTGRES_DB: ${SMQ_DOMAINS_DB_NAME} + networks: + - supermq-base-net + volumes: + - supermq-domains-db-volume:/var/lib/postgresql/data + + domains-redis: + image: redis:7.2.4-alpine + container_name: supermq-domains-redis + restart: on-failure + networks: + - supermq-base-net + volumes: + - supermq-domains-redis-volume:/data + + domains: + image: supermq/domains:${SMQ_RELEASE_TAG} + container_name: supermq-domains + depends_on: + - domains-db + - spicedb + expose: + - ${SMQ_DOMAINS_GRPC_PORT} + restart: on-failure + environment: + SMQ_DOMAINS_LOG_LEVEL: ${SMQ_DOMAINS_LOG_LEVEL} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + SMQ_DOMAINS_HTTP_HOST: ${SMQ_DOMAINS_HTTP_HOST} + SMQ_DOMAINS_HTTP_PORT: ${SMQ_DOMAINS_HTTP_PORT} + SMQ_DOMAINS_HTTP_SERVER_CERT: ${SMQ_DOMAINS_HTTP_SERVER_CERT} + SMQ_DOMAINS_HTTP_SERVER_KEY: ${SMQ_DOMAINS_HTTP_SERVER_KEY} + SMQ_DOMAINS_GRPC_HOST: ${SMQ_DOMAINS_GRPC_HOST} + SMQ_DOMAINS_GRPC_PORT: ${SMQ_DOMAINS_GRPC_PORT} + ## Compose supports parameter expansion in environment, + ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty + ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default + SMQ_DOMAINS_GRPC_SERVER_CERT: ${SMQ_DOMAINS_GRPC_SERVER_CERT:+/auth-grpc-server.crt} + SMQ_DOMAINS_GRPC_SERVER_KEY: ${SMQ_DOMAINS_GRPC_SERVER_KEY:+/auth-grpc-server.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS: ${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:+/auth-grpc-client-ca.crt} + SMQ_DOMAINS_DB_HOST: ${SMQ_DOMAINS_DB_HOST} + SMQ_DOMAINS_DB_PORT: ${SMQ_DOMAINS_DB_PORT} + SMQ_DOMAINS_DB_USER: ${SMQ_DOMAINS_DB_USER} + SMQ_DOMAINS_DB_PASS: ${SMQ_DOMAINS_DB_PASS} + SMQ_DOMAINS_DB_NAME: ${SMQ_DOMAINS_DB_NAME} + SMQ_DOMAINS_DB_SSL_MODE: ${SMQ_DOMAINS_DB_SSL_MODE} + SMQ_DOMAINS_DB_SSL_CERT: ${SMQ_DOMAINS_DB_SSL_CERT} + SMQ_DOMAINS_DB_SSL_KEY: ${SMQ_DOMAINS_DB_SSL_KEY} + SMQ_DOMAINS_DB_SSL_ROOT_CERT: ${SMQ_DOMAINS_DB_SSL_ROOT_CERT} + SMQ_DOMAINS_INSTANCE_ID: ${SMQ_DOMAINS_INSTANCE_ID} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_DOMAINS_CACHE_URL: ${SMQ_DOMAINS_CACHE_URL} + SMQ_DOMAINS_CACHE_KEY_DURATION: ${SMQ_DOMAINS_CACHE_KEY_DURATION} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} + SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} + SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} + SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} + SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} + SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_R_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + ports: + - ${SMQ_DOMAINS_HTTP_PORT}:${SMQ_DOMAINS_HTTP_PORT} + - ${SMQ_DOMAINS_GRPC_PORT}:${SMQ_DOMAINS_GRPC_PORT} + networks: + - supermq-base-net + volumes: + - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} + # Auth gRPC mTLS server certificates + - type: bind + source: ${SMQ_DOMAINS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} + target: /auth-grpc-server${SMQ_DOMAINS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_DOMAINS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} + target: /auth-grpc-server${SMQ_DOMAINS_GRPC_SERVER_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} + target: /auth-grpc-server-ca${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} + target: /auth-grpc-client-ca${SMQ_DOMAINS_GRPC_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + nginx: + image: nginx:1.25.4-alpine + container_name: supermq-nginx + restart: on-failure + volumes: + - ./nginx/nginx-${AUTH-key}.conf:/etc/nginx/nginx.conf.template + - ./nginx/entrypoint.sh:/docker-entrypoint.d/entrypoint.sh + - ./nginx/snippets:/etc/nginx/snippets + - ./ssl/authorization.js:/etc/nginx/authorization.js + - type: bind + source: ${SMQ_NGINX_SERVER_CERT:-./ssl/certs/supermq-server.crt} + target: /etc/ssl/certs/supermq-server.crt + - type: bind + source: ${SMQ_NGINX_SERVER_KEY:-./ssl/certs/supermq-server.key} + target: /etc/ssl/private/supermq-server.key + - type: bind + source: ${SMQ_NGINX_SERVER_CLIENT_CA:-./ssl/certs/ca.crt} + target: /etc/ssl/certs/ca.crt + - type: bind + source: ${SMQ_NGINX_SERVER_DHPARAM:-./ssl/dhparam.pem} + target: /etc/ssl/certs/dhparam.pem + ports: + - ${SMQ_NGINX_HTTP_PORT}:${SMQ_NGINX_HTTP_PORT} + - ${SMQ_NGINX_SSL_PORT}:${SMQ_NGINX_SSL_PORT} + - ${SMQ_NGINX_MQTT_PORT}:${SMQ_NGINX_MQTT_PORT} + - ${SMQ_NGINX_MQTTS_PORT}:${SMQ_NGINX_MQTTS_PORT} + networks: + - supermq-base-net + env_file: + - .env + depends_on: + - auth + - clients + - users + - mqtt-adapter + - http-adapter + - ws-adapter + - coap-adapter + + clients-db: + image: postgres:16.2-alpine + container_name: supermq-clients-db + restart: on-failure + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_CLIENTS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_CLIENTS_DB_PASS} + POSTGRES_DB: ${SMQ_CLIENTS_DB_NAME} + SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} + networks: + - supermq-base-net + ports: + - 6006:5432 + volumes: + - supermq-clients-db-volume:/var/lib/postgresql/data + + clients-redis: + image: redis:7.2.4-alpine + container_name: supermq-clients-redis + restart: on-failure + networks: + - supermq-base-net + volumes: + - supermq-clients-redis-volume:/data + + clients: + image: supermq/clients:${SMQ_RELEASE_TAG} + container_name: supermq-clients + depends_on: + - clients-db + - users + - auth + - nats + restart: on-failure + environment: + SMQ_CLIENTS_LOG_LEVEL: ${SMQ_CLIENTS_LOG_LEVEL} + SMQ_CLIENTS_STANDALONE_ID: ${SMQ_CLIENTS_STANDALONE_ID} + SMQ_CLIENTS_STANDALONE_TOKEN: ${SMQ_CLIENTS_STANDALONE_TOKEN} + SMQ_CLIENTS_CACHE_KEY_DURATION: ${SMQ_CLIENTS_CACHE_KEY_DURATION} + SMQ_CLIENTS_HTTP_HOST: ${SMQ_CLIENTS_HTTP_HOST} + SMQ_CLIENTS_HTTP_PORT: ${SMQ_CLIENTS_HTTP_PORT} + SMQ_CLIENTS_GRPC_HOST: ${SMQ_CLIENTS_GRPC_HOST} + SMQ_CLIENTS_GRPC_PORT: ${SMQ_CLIENTS_GRPC_PORT} + ## Compose supports parameter expansion in environment, + ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty + ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default + SMQ_CLIENTS_GRPC_SERVER_CERT: ${SMQ_CLIENTS_GRPC_SERVER_CERT:+/clients-grpc-server.crt} + SMQ_CLIENTS_GRPC_R_KEY: ${SMQ_CLIENTS_GRPC_SERVER_KEY:+/clients-grpc-server.key} + SMQ_CLIENTS_GRPC_R_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS: ${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:+/clients-grpc-client-ca.crt} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_CLIENTS_CACHE_URL: ${SMQ_CLIENTS_CACHE_URL} + SMQ_CLIENTS_DB_HOST: ${SMQ_CLIENTS_DB_HOST} + SMQ_CLIENTS_DB_PORT: ${SMQ_CLIENTS_DB_PORT} + SMQ_CLIENTS_DB_USER: ${SMQ_CLIENTS_DB_USER} + SMQ_CLIENTS_DB_PASS: ${SMQ_CLIENTS_DB_PASS} + SMQ_CLIENTS_DB_NAME: ${SMQ_CLIENTS_DB_NAME} + SMQ_CLIENTS_DB_SSL_MODE: ${SMQ_CLIENTS_DB_SSL_MODE} + SMQ_CLIENTS_DB_SSL_CERT: ${SMQ_CLIENTS_DB_SSL_CERT} + SMQ_CLIENTS_DB_SSL_KEY: ${SMQ_CLIENTS_DB_SSL_KEY} + SMQ_CLIENTS_DB_SSL_ROOT_CERT: ${SMQ_CLIENTS_DB_SSL_ROOT_CERT} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_GROUPS_URL: ${SMQ_GROUPS_URL} + SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} + SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} + SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} + SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} + SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} + SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} + SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} + SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} + SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + ports: + - ${SMQ_CLIENTS_HTTP_PORT}:${SMQ_CLIENTS_HTTP_PORT} + - ${SMQ_CLIENTS_GRPC_PORT}:${SMQ_CLIENTS_GRPC_PORT} + networks: + - supermq-base-net + volumes: + - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} + # Clients gRPC server certificates + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_cert} + target: /clients-grpc-server${SMQ_CLIENTS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} + target: /clients-grpc-server${SMQ_CLIENTS_GRPC_SERVER_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca_certs} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca_certs} + target: /clients-grpc-client-ca${SMQ_CLIENTS_GRPC_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + # Auth gRPC client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Channel gRPC client certificates + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Group gRPC client certificates + - type: bind + source: ${SMQ_GROUPS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_GROUPS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_GROUPS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} + target: /groups-grpc-server-ca${SMQ_GROUPS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + + channels-db: + image: postgres:16.2-alpine + container_name: supermq-channels-db + restart: on-failure + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_CHANNELS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_CHANNELS_DB_PASS} + POSTGRES_DB: ${SMQ_CHANNELS_DB_NAME} + SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} + networks: + - supermq-base-net + ports: + - 6005:5432 + volumes: + - supermq-channels-db-volume:/var/lib/postgresql/data + + channels: + image: supermq/channels:${SMQ_RELEASE_TAG} + container_name: supermq-channels + depends_on: + - channels-db + - users + - auth + - nats + restart: on-failure + environment: + SMQ_CHANNELS_LOG_LEVEL: ${SMQ_CHANNELS_LOG_LEVEL} + SMQ_CHANNELS_INSTANCE_ID: ${SMQ_CHANNELS_INSTANCE_ID} + SMQ_CHANNELS_HTTP_HOST: ${SMQ_CHANNELS_HTTP_HOST} + SMQ_CHANNELS_HTTP_PORT: ${SMQ_CHANNELS_HTTP_PORT} + SMQ_CHANNELS_GRPC_HOST: ${SMQ_CHANNELS_GRPC_HOST} + SMQ_CHANNELS_GRPC_PORT: ${SMQ_CHANNELS_GRPC_PORT} + ## Compose supports parameter expansion in environment, + ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty + ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default + SMQ_CHANNELS_GRPC_SERVER_CERT: ${SMQ_CHANNELS_GRPC_SERVER_CERT:+/channels-grpc-server.crt} + SMQ_CHANNELS_GRPC_SERVER_KEY: ${SMQ_CHANNELS_GRPC_SERVER_KEY:+/channels-grpc-server.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+/channels-grpc-client-ca.crt} + SMQ_CHANNELS_DB_HOST: ${SMQ_CHANNELS_DB_HOST} + SMQ_CHANNELS_DB_PORT: ${SMQ_CHANNELS_DB_PORT} + SMQ_CHANNELS_DB_USER: ${SMQ_CHANNELS_DB_USER} + SMQ_CHANNELS_DB_PASS: ${SMQ_CHANNELS_DB_PASS} + SMQ_CHANNELS_DB_NAME: ${SMQ_CHANNELS_DB_NAME} + SMQ_CHANNELS_DB_SSL_MODE: ${SMQ_CHANNELS_DB_SSL_MODE} + SMQ_CHANNELS_DB_SSL_CERT: ${SMQ_CHANNELS_DB_SSL_CERT} + SMQ_CHANNELS_DB_SSL_KEY: ${SMQ_CHANNELS_DB_SSL_KEY} + SMQ_CHANNELS_DB_SSL_ROOT_CERT: ${SMQ_CHANNELS_DB_SSL_ROOT_CERT} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} + SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} + SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} + SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} + SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} + SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} + SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} + SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} + SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + ports: + - ${SMQ_CHANNELS_HTTP_PORT}:${SMQ_CHANNELS_HTTP_PORT} + - ${SMQ_CHANNELS_GRPC_PORT}:${SMQ_CHANNELS_GRPC_PORT} + networks: + - supermq-base-net + volumes: + - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} + # Auth gRPC client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_GROUPS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_GROUPS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /groups-grpc-client${SMQ_GROUPS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_GROUPS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} + target: /groups-grpc-server-ca${SMQ_GROUPS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CERT:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server${SMQ_CHANNELS_GRPC_SERVER_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_KEY:-ssl/certs/dummy/server_key} + target: /channels-grpc-server${SMQ_CHANNELS_GRPC_SERVER_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca} + target: /channels-grpc-client-ca${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + + users-db: + image: postgres:16.2-alpine + container_name: supermq-users-db + restart: on-failure + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_USERS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_USERS_DB_PASS} + POSTGRES_DB: ${SMQ_USERS_DB_NAME} + SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} + ports: + - 6002:5432 + networks: + - supermq-base-net + volumes: + - supermq-users-db-volume:/var/lib/postgresql/data + + users: + image: supermq/users:${SMQ_RELEASE_TAG} + container_name: supermq-users + depends_on: + - users-db + - auth + - nats + restart: on-failure + environment: + SMQ_USERS_LOG_LEVEL: ${SMQ_USERS_LOG_LEVEL} + SMQ_USERS_SECRET_KEY: ${SMQ_USERS_SECRET_KEY} + SMQ_USERS_ADMIN_EMAIL: ${SMQ_USERS_ADMIN_EMAIL} + SMQ_USERS_ADMIN_PASSWORD: ${SMQ_USERS_ADMIN_PASSWORD} + SMQ_USERS_ADMIN_USERNAME: ${SMQ_USERS_ADMIN_USERNAME} + SMQ_USERS_ADMIN_FIRST_NAME: ${SMQ_USERS_ADMIN_FIRST_NAME} + SMQ_USERS_ADMIN_LAST_NAME: ${SMQ_USERS_ADMIN_LAST_NAME} + SMQ_USERS_PASS_REGEX: ${SMQ_USERS_PASS_REGEX} + SMQ_USERS_ACCESS_TOKEN_DURATION: ${SMQ_USERS_ACCESS_TOKEN_DURATION} + SMQ_USERS_REFRESH_TOKEN_DURATION: ${SMQ_USERS_REFRESH_TOKEN_DURATION} + SMQ_TOKEN_RESET_ENDPOINT: ${SMQ_TOKEN_RESET_ENDPOINT} + SMQ_USERS_HTTP_HOST: ${SMQ_USERS_HTTP_HOST} + SMQ_USERS_HTTP_PORT: ${SMQ_USERS_HTTP_PORT} + SMQ_USERS_HTTP_SERVER_CERT: ${SMQ_USERS_HTTP_SERVER_CERT} + SMQ_USERS_HTTP_SERVER_KEY: ${SMQ_USERS_HTTP_SERVER_KEY} + SMQ_USERS_DB_HOST: ${SMQ_USERS_DB_HOST} + SMQ_USERS_DB_PORT: ${SMQ_USERS_DB_PORT} + SMQ_USERS_DB_USER: ${SMQ_USERS_DB_USER} + SMQ_USERS_DB_PASS: ${SMQ_USERS_DB_PASS} + SMQ_USERS_DB_NAME: ${SMQ_USERS_DB_NAME} + SMQ_USERS_DB_SSL_MODE: ${SMQ_USERS_DB_SSL_MODE} + SMQ_USERS_DB_SSL_CERT: ${SMQ_USERS_DB_SSL_CERT} + SMQ_USERS_DB_SSL_KEY: ${SMQ_USERS_DB_SSL_KEY} + SMQ_USERS_DB_SSL_ROOT_CERT: ${SMQ_USERS_DB_SSL_ROOT_CERT} + SMQ_USERS_ALLOW_SELF_REGISTER: ${SMQ_USERS_ALLOW_SELF_REGISTER} + SMQ_EMAIL_HOST: ${SMQ_EMAIL_HOST} + SMQ_EMAIL_PORT: ${SMQ_EMAIL_PORT} + SMQ_EMAIL_USERNAME: ${SMQ_EMAIL_USERNAME} + SMQ_EMAIL_PASSWORD: ${SMQ_EMAIL_PASSWORD} + SMQ_EMAIL_FROM_ADDRESS: ${SMQ_EMAIL_FROM_ADDRESS} + SMQ_EMAIL_FROM_NAME: ${SMQ_EMAIL_FROM_NAME} + SMQ_EMAIL_TEMPLATE: ${SMQ_EMAIL_TEMPLATE} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} + SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} + SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} + SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + SMQ_GOOGLE_CLIENT_ID: ${SMQ_GOOGLE_CLIENT_ID} + SMQ_GOOGLE_CLIENT_SECRET: ${SMQ_GOOGLE_CLIENT_SECRET} + SMQ_GOOGLE_REDIRECT_URL: ${SMQ_GOOGLE_REDIRECT_URL} + SMQ_GOOGLE_STATE: ${SMQ_GOOGLE_STATE} + SMQ_OAUTH_UI_REDIRECT_URL: ${SMQ_OAUTH_UI_REDIRECT_URL} + SMQ_OAUTH_UI_ERROR_URL: ${SMQ_OAUTH_UI_ERROR_URL} + SMQ_USERS_DELETE_INTERVAL: ${SMQ_USERS_DELETE_INTERVAL} + SMQ_USERS_DELETE_AFTER: ${SMQ_USERS_DELETE_AFTER} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + ports: + - ${SMQ_USERS_HTTP_PORT}:${SMQ_USERS_HTTP_PORT} + networks: + - supermq-base-net + volumes: + - ./templates/${SMQ_USERS_RESET_PWD_TEMPLATE}:/email.tmpl + # Auth gRPC client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + groups-db: + image: postgres:16.2-alpine + container_name: supermq-groups-db + restart: on-failure + command: postgres -c "max_connections=${SMQ_POSTGRES_MAX_CONNECTIONS}" + environment: + POSTGRES_USER: ${SMQ_GROUPS_DB_USER} + POSTGRES_PASSWORD: ${SMQ_GROUPS_DB_PASS} + POSTGRES_DB: ${SMQ_GROUPS_DB_NAME} + SMQ_POSTGRES_MAX_CONNECTIONS: ${SMQ_POSTGRES_MAX_CONNECTIONS} + ports: + - 6004:5432 + networks: + - supermq-base-net + volumes: + - supermq-groups-db-volume:/var/lib/postgresql/data + + groups: + image: supermq/groups:${SMQ_RELEASE_TAG} + container_name: supermq-groups + depends_on: + - groups-db + - auth + - nats + restart: on-failure + environment: + SMQ_GROUPS_LOG_LEVEL: ${SMQ_GROUPS_LOG_LEVEL} + SMQ_GROUPS_HTTP_HOST: ${SMQ_GROUPS_HTTP_HOST} + SMQ_GROUPS_HTTP_PORT: ${SMQ_GROUPS_HTTP_PORT} + SMQ_GROUPS_HTTP_SERVER_CERT: ${SMQ_GROUPS_HTTP_SERVER_CERT} + SMQ_GROUPS_HTTP_SERVER_KEY: ${SMQ_GROUPS_HTTP_SERVER_KEY} + SMQ_GROUPS_GRPC_HOST: ${SMQ_GROUPS_GRPC_HOST} + SMQ_GROUPS_GRPC_PORT: ${SMQ_GROUPS_GRPC_PORT} + ## Compose supports parameter expansion in environment, + ## Eg: ${VAR:+replacement} or ${VAR+replacement} -> replacement if VAR is set and non-empty, otherwise empty + ## Eg :${VAR:-default} or ${VAR-default} -> value of VAR if set and non-empty, otherwise default + SMQ_GROUPS_GRPC_SERVER_CERT: ${SMQ_GROUPS_GRPC_SERVER_CERT:+/groups-grpc-server.crt} + SMQ_GROUPS_GRPC_SERVER_KEY: ${SMQ_GROUPS_GRPC_SERVER_KEY:+/groups-grpc-server.key} + SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} + SMQ_GROUPS_GRPC_CLIENT_CA_CERTS: ${SMQ_GROUPS_GRPC_CLIENT_CA_CERTS:+/groups-grpc-client-ca.crt} + SMQ_GROUPS_DB_HOST: ${SMQ_GROUPS_DB_HOST} + SMQ_GROUPS_DB_PORT: ${SMQ_GROUPS_DB_PORT} + SMQ_GROUPS_DB_USER: ${SMQ_GROUPS_DB_USER} + SMQ_GROUPS_DB_PASS: ${SMQ_GROUPS_DB_PASS} + SMQ_GROUPS_DB_NAME: ${SMQ_GROUPS_DB_NAME} + SMQ_GROUPS_DB_SSL_MODE: ${SMQ_GROUPS_DB_SSL_MODE} + SMQ_GROUPS_DB_SSL_CERT: ${SMQ_GROUPS_DB_SSL_CERT} + SMQ_GROUPS_DB_SSL_KEY: ${SMQ_GROUPS_DB_SSL_KEY} + SMQ_GROUPS_DB_SSL_ROOT_CERT: ${SMQ_GROUPS_DB_SSL_ROOT_CERT} + SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_DOMAINS_GRPC_URL: ${SMQ_DOMAINS_GRPC_URL} + SMQ_DOMAINS_GRPC_TIMEOUT: ${SMQ_DOMAINS_GRPC_TIMEOUT} + SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} + SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} + SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + ports: + - ${SMQ_GROUPS_HTTP_PORT}:${SMQ_GROUPS_HTTP_PORT} + - ${SMQ_GROUPS_GRPC_PORT}:${SMQ_GROUPS_GRPC_PORT} + networks: + - supermq-base-net + volumes: + - ./spicedb/schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} + # Auth gRPC client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + jaeger: + image: jaegertracing/all-in-one:1.66.0 + container_name: supermq-jaeger + environment: + COLLECTOR_OTLP_ENABLED: ${SMQ_JAEGER_COLLECTOR_OTLP_ENABLED} + command: --memory.max-traces ${SMQ_JAEGER_MEMORY_MAX_TRACES} + ports: + - ${SMQ_JAEGER_FRONTEND}:${SMQ_JAEGER_FRONTEND} + - ${SMQ_JAEGER_OLTP_HTTP}:${SMQ_JAEGER_OLTP_HTTP} + networks: + - supermq-base-net + + mqtt-adapter: + image: supermq/mqtt:${SMQ_RELEASE_TAG} + container_name: supermq-mqtt + depends_on: + - clients + - rabbitmq + - nats + restart: on-failure + environment: + SMQ_MQTT_ADAPTER_LOG_LEVEL: ${SMQ_MQTT_ADAPTER_LOG_LEVEL} + SMQ_MQTT_ADAPTER_MQTT_PORT: ${SMQ_MQTT_ADAPTER_MQTT_PORT} + SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_HOST} + SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_PORT} + SMQ_MQTT_ADAPTER_MQTT_TARGET_USERNAME: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_USERNAME} + SMQ_MQTT_ADAPTER_MQTT_TARGET_PASSWORD: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_PASSWORD} + SMQ_MQTT_ADAPTER_FORWARDER_TIMEOUT: ${SMQ_MQTT_ADAPTER_FORWARDER_TIMEOUT} + SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK: ${SMQ_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK} + SMQ_MQTT_ADAPTER_MQTT_QOS: ${SMQ_MQTT_ADAPTER_MQTT_QOS} + SMQ_MQTT_ADAPTER_WS_PORT: ${SMQ_MQTT_ADAPTER_WS_PORT} + SMQ_MQTT_ADAPTER_INSTANCE_ID: ${SMQ_MQTT_ADAPTER_INSTANCE_ID} + SMQ_MQTT_ADAPTER_WS_TARGET_HOST: ${SMQ_MQTT_ADAPTER_WS_TARGET_HOST} + SMQ_MQTT_ADAPTER_WS_TARGET_PORT: ${SMQ_MQTT_ADAPTER_WS_TARGET_PORT} + SMQ_MQTT_ADAPTER_WS_TARGET_PATH: ${SMQ_MQTT_ADAPTER_WS_TARGET_PATH} + SMQ_MQTT_ADAPTER_INSTANCE: ${SMQ_MQTT_ADAPTER_INSTANCE} + SMQ_ES_URL: ${SMQ_ES_URL} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_T_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + networks: + - supermq-base-net + volumes: + # Clients gRPC mTLS client certificates + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Channels gRPC mTLS client certificates + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + http-adapter: + image: supermq/http:${SMQ_RELEASE_TAG} + container_name: supermq-http + depends_on: + - clients + - nats + restart: on-failure + environment: + SMQ_HTTP_ADAPTER_LOG_LEVEL: ${SMQ_HTTP_ADAPTER_LOG_LEVEL} + SMQ_HTTP_ADAPTER_HOST: ${SMQ_HTTP_ADAPTER_HOST} + SMQ_HTTP_ADAPTER_PORT: ${SMQ_HTTP_ADAPTER_PORT} + SMQ_HTTP_ADAPTER_SERVER_CERT: ${SMQ_HTTP_ADAPTER_SERVER_CERT} + SMQ_HTTP_ADAPTER_SERVER_KEY: ${SMQ_HTTP_ADAPTER_SERVER_KEY} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_T_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_HTTP_ADAPTER_INSTANCE_ID: ${SMQ_HTTP_ADAPTER_INSTANCE_ID} + SMQ_ES_URL: ${SMQ_ES_URL} + ports: + - ${SMQ_HTTP_ADAPTER_PORT}:${SMQ_HTTP_ADAPTER_PORT} + networks: + - supermq-base-net + volumes: + # Clients gRPC mTLS client certificates + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Channels gRPC mTLS client certificates + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Auth gRPC mTLS client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + coap-adapter: + image: supermq/coap:${SMQ_RELEASE_TAG} + container_name: supermq-coap + depends_on: + - clients + - nats + restart: on-failure + environment: + SMQ_COAP_ADAPTER_LOG_LEVEL: ${SMQ_COAP_ADAPTER_LOG_LEVEL} + SMQ_COAP_ADAPTER_HOST: ${SMQ_COAP_ADAPTER_HOST} + SMQ_COAP_ADAPTER_PORT: ${SMQ_COAP_ADAPTER_PORT} + SMQ_COAP_ADAPTER_SERVER_CERT: ${SMQ_COAP_ADAPTER_SERVER_CERT} + SMQ_COAP_ADAPTER_SERVER_KEY: ${SMQ_COAP_ADAPTER_SERVER_KEY} + SMQ_COAP_ADAPTER_HTTP_HOST: ${SMQ_COAP_ADAPTER_HTTP_HOST} + SMQ_COAP_ADAPTER_HTTP_PORT: ${SMQ_COAP_ADAPTER_HTTP_PORT} + SMQ_COAP_ADAPTER_HTTP_SERVER_CERT: ${SMQ_COAP_ADAPTER_HTTP_SERVER_CERT} + SMQ_COAP_ADAPTER_HTTP_SERVER_KEY: ${SMQ_COAP_ADAPTER_HTTP_SERVER_KEY} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_COAP_ADAPTER_INSTANCE_ID: ${SMQ_COAP_ADAPTER_INSTANCE_ID} + SMQ_ES_URL: ${SMQ_ES_URL} + ports: + - ${SMQ_COAP_ADAPTER_PORT}:${SMQ_COAP_ADAPTER_PORT}/udp + - ${SMQ_COAP_ADAPTER_HTTP_PORT}:${SMQ_COAP_ADAPTER_HTTP_PORT}/tcp + networks: + - supermq-base-net + volumes: + # Clients gRPC mTLS client certificates + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Channels gRPC mTLS client certificates + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:-ssl/certs/dummy/client_ca} + target: /channels-grpc-client-ca${SMQ_CHANNELS_GRPC_CLIENT_CA_CERTS:+.crt} + bind: + create_host_path: true + + ws-adapter: + image: supermq/ws:${SMQ_RELEASE_TAG} + container_name: supermq-ws + depends_on: + - clients + - nats + restart: on-failure + environment: + SMQ_WS_ADAPTER_LOG_LEVEL: ${SMQ_WS_ADAPTER_LOG_LEVEL} + SMQ_WS_ADAPTER_HTTP_HOST: ${SMQ_WS_ADAPTER_HTTP_HOST} + SMQ_WS_ADAPTER_HTTP_PORT: ${SMQ_WS_ADAPTER_HTTP_PORT} + SMQ_WS_ADAPTER_HTTP_SERVER_CERT: ${SMQ_WS_ADAPTER_HTTP_SERVER_CERT} + SMQ_WS_ADAPTER_HTTP_SERVER_KEY: ${SMQ_WS_ADAPTER_HTTP_SERVER_KEY} + SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} + SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} + SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} + SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} + SMQ_CLIENTS_GRPC_SERVER_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} + SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} + SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} + SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} + SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} + SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} + SMQ_AUTH_GRPC_URL: ${SMQ_AUTH_GRPC_URL} + SMQ_AUTH_GRPC_TIMEOUT: ${SMQ_AUTH_GRPC_TIMEOUT} + SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} + SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} + SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} + SMQ_MESSAGE_BROKER_URL: ${SMQ_MESSAGE_BROKER_URL} + SMQ_JAEGER_URL: ${SMQ_JAEGER_URL} + SMQ_JAEGER_TRACE_RATIO: ${SMQ_JAEGER_TRACE_RATIO} + SMQ_SEND_TELEMETRY: ${SMQ_SEND_TELEMETRY} + SMQ_WS_ADAPTER_INSTANCE_ID: ${SMQ_WS_ADAPTER_INSTANCE_ID} + SMQ_ES_URL: ${SMQ_ES_URL} + ports: + - ${SMQ_WS_ADAPTER_HTTP_PORT}:${SMQ_WS_ADAPTER_HTTP_PORT} + networks: + - supermq-base-net + volumes: + # Clients gRPC mTLS client certificates + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /clients-grpc-client${SMQ_CLIENTS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /clients-grpc-server-ca${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Channels gRPC mTLS client certificates + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /channels-grpc-client${SMQ_CHANNELS_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /channels-grpc-server-ca${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + # Auth gRPC mTLS client certificates + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_CERT:+.crt} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_CLIENT_KEY:-ssl/certs/dummy/client_key} + target: /auth-grpc-client${SMQ_AUTH_GRPC_CLIENT_KEY:+.key} + bind: + create_host_path: true + - type: bind + source: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:-ssl/certs/dummy/server_ca} + target: /auth-grpc-server-ca${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+.crt} + bind: + create_host_path: true + + rabbitmq: + image: rabbitmq:4.0.5-management-alpine + container_name: supermq-rabbitmq + restart: on-failure + environment: + RABBITMQ_ERLANG_COOKIE: ${SMQ_RABBITMQ_COOKIE} + RABBITMQ_DEFAULT_USER: ${SMQ_RABBITMQ_USER} + RABBITMQ_DEFAULT_PASS: ${SMQ_RABBITMQ_PASS} + RABBITMQ_DEFAULT_VHOST: ${SMQ_RABBITMQ_VHOST} + RABBITMQ_CONFIG_FILES: /etc/rabbitmq/conf.d/ + ports: + - ${SMQ_RABBITMQ_PORT}:${SMQ_RABBITMQ_PORT} + - ${SMQ_RABBITMQ_HTTP_PORT}:${SMQ_RABBITMQ_HTTP_PORT} + - ${SMQ_RABBITMQ_WS_PORT}:${SMQ_RABBITMQ_WS_PORT} + volumes: + - ./rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins + - ./rabbitmq/rabbitmq.conf:/etc/rabbitmq/conf.d/10-defaults.conf + - supermq-mqtt-broker-volume:/var/lib/rabbitmq + networks: + - supermq-base-net + + nats: + image: nats:2.10.25-alpine + container_name: supermq-nats + restart: on-failure + command: "--config=/etc/nats/nats.conf" + environment: + - SMQ_NATS_PORT=${SMQ_NATS_PORT} + - SMQ_NATS_HTTP_PORT=${SMQ_NATS_HTTP_PORT} + - SMQ_NATS_JETSTREAM_KEY=${SMQ_NATS_JETSTREAM_KEY} + ports: + - ${SMQ_NATS_PORT}:${SMQ_NATS_PORT} + - ${SMQ_NATS_HTTP_PORT}:${SMQ_NATS_HTTP_PORT} + volumes: + - supermq-broker-volume:/data + - ./nats:/etc/nats + networks: + - supermq-base-net diff --git a/docker/nats/nats.conf b/docker/supermq-docker/nats/nats.conf similarity index 100% rename from docker/nats/nats.conf rename to docker/supermq-docker/nats/nats.conf diff --git a/docker/supermq-docker/nginx/.gitignore b/docker/supermq-docker/nginx/.gitignore new file mode 100644 index 000000000..9453269cc --- /dev/null +++ b/docker/supermq-docker/nginx/.gitignore @@ -0,0 +1,5 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +snippets/mqtt-upstream.conf +snippets/mqtt-ws-upstream.conf \ No newline at end of file diff --git a/docker/supermq-docker/nginx/entrypoint.sh b/docker/supermq-docker/nginx/entrypoint.sh new file mode 100755 index 000000000..b221dc054 --- /dev/null +++ b/docker/supermq-docker/nginx/entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/ash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +if [ -z "$SMQ_MQTT_CLUSTER" ] +then + envsubst '${SMQ_MQTT_ADAPTER_MQTT_PORT}' < /etc/nginx/snippets/mqtt-upstream-single.conf > /etc/nginx/snippets/mqtt-upstream.conf + envsubst '${SMQ_MQTT_ADAPTER_WS_PORT}' < /etc/nginx/snippets/mqtt-ws-upstream-single.conf > /etc/nginx/snippets/mqtt-ws-upstream.conf +else + envsubst '${SMQ_MQTT_ADAPTER_MQTT_PORT}' < /etc/nginx/snippets/mqtt-upstream-cluster.conf > /etc/nginx/snippets/mqtt-upstream.conf + envsubst '${SMQ_MQTT_ADAPTER_WS_PORT}' < /etc/nginx/snippets/mqtt-ws-upstream-cluster.conf > /etc/nginx/snippets/mqtt-ws-upstream.conf +fi + +envsubst ' + ${SMQ_NGINX_SERVER_NAME} + ${SMQ_AUTH_HTTP_PORT} + ${SMQ_DOMAINS_HTTP_PORT} + ${SMQ_GROUPS_HTTP_PORT} + ${SMQ_USERS_HTTP_PORT} + ${SMQ_CLIENTS_HTTP_PORT} + ${SMQ_CLIENTS_AUTH_HTTP_PORT} + ${SMQ_CHANNELS_HTTP_PORT} + ${SMQ_HTTP_ADAPTER_PORT} + ${SMQ_NGINX_MQTT_PORT} + ${SMQ_NGINX_MQTTS_PORT} + ${SMQ_WS_ADAPTER_HTTP_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf + +exec nginx -g "daemon off;" diff --git a/docker/supermq-docker/nginx/nginx-key.conf b/docker/supermq-docker/nginx/nginx-key.conf new file mode 100644 index 000000000..d4ea0dbdc --- /dev/null +++ b/docker/supermq-docker/nginx/nginx-key.conf @@ -0,0 +1,157 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This is the default SuperMQ NGINX configuration. + +user nginx; +worker_processes auto; +worker_cpu_affinity auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + # Explanation: https://serverfault.com/questions/787919/optimal-value-for-nginx-worker-connections + # We'll keep 10k connections per core (assuming one worker per core) + worker_connections 10000; +} + +http { + include snippets/http_access_log.conf; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + # Include single-node or multiple-node (cluster) upstream + include snippets/mqtt-ws-upstream.conf; + + server { + listen 80 default_server; + listen [::]:80 default_server; + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + set $dynamic_server_name "$SMQ_NGINX_SERVER_NAME"; + + if ($dynamic_server_name = '') { + set $dynamic_server_name "localhost"; + } + + server_name $dynamic_server_name; + + include snippets/ssl.conf; + + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Access-Control-Allow-Origin '*'; + add_header Access-Control-Allow-Methods '*'; + add_header Access-Control-Allow-Headers '*'; + + # Proxy pass to auth service + location ~ ^/(pats) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://auth:${SMQ_AUTH_HTTP_PORT}; + } + + # Proxy pass to domains service + location ~ ^/(domains|invitations) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://domains:${SMQ_DOMAINS_HTTP_PORT}; + } + + # Proxy pass to users service + location ~ ^/(users|password|authorize|oauth/callback/[^/]+) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://users:${SMQ_USERS_HTTP_PORT}; + } + + # Proxy pass to groups service + location ~ "^/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})/(groups)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://groups:${SMQ_GROUPS_HTTP_PORT}; + } + + # Proxy pass to clients service + location ~ "^/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})/(clients)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + # Proxy pass to channels service + location ~ "^/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})/(channels)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://channels:${SMQ_CHANNELS_HTTP_PORT}; + } + + location /health { + include snippets/proxy-headers.conf; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + location /metrics { + include snippets/proxy-headers.conf; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + # Proxy pass to supermq-http-adapter + location /http/ { + include snippets/proxy-headers.conf; + + # Trailing `/` is mandatory. Refer to the http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass + # If the proxy_pass directive is specified with a URI, then when a request is passed to the server, + # the part of a normalized request URI matching the location is replaced by a URI specified in the directive + proxy_pass http://http-adapter:${SMQ_HTTP_ADAPTER_PORT}/; + } + + # Proxy pass to supermq-mqtt-adapter over WS + location /mqtt { + include snippets/proxy-headers.conf; + include snippets/ws-upgrade.conf; + proxy_pass http://mqtt_ws_cluster; + } + + # Proxy pass to supermq-ws-adapter + location /ws/ { + include snippets/proxy-headers.conf; + include snippets/ws-upgrade.conf; + proxy_pass http://ws-adapter:${SMQ_WS_ADAPTER_HTTP_PORT}/; + } + } +} + +# MQTT +stream { + include snippets/stream_access_log.conf; + + # Include single-node or multiple-node (cluster) upstream + include snippets/mqtt-upstream.conf; + + server { + listen ${SMQ_NGINX_MQTT_PORT}; + listen [::]:${SMQ_NGINX_MQTT_PORT}; + listen ${SMQ_NGINX_MQTTS_PORT} ssl; + listen [::]:${SMQ_NGINX_MQTTS_PORT} ssl; + + include snippets/ssl.conf; + + proxy_pass mqtt_cluster; + } +} + +error_log info.log info; diff --git a/docker/supermq-docker/nginx/nginx-x509.conf b/docker/supermq-docker/nginx/nginx-x509.conf new file mode 100644 index 000000000..dadcb547a --- /dev/null +++ b/docker/supermq-docker/nginx/nginx-x509.conf @@ -0,0 +1,178 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +# This is the SuperMQ NGINX configuration for mututal authentication based on X.509 certifiactes. + +user nginx; +worker_processes auto; +worker_cpu_affinity auto; +pid /run/nginx.pid; +load_module /etc/nginx/modules/ngx_stream_js_module.so; +load_module /etc/nginx/modules/ngx_http_js_module.so; +include /etc/nginx/modules-enabled/*.conf; + +events { + # Explanation: https://serverfault.com/questions/787919/optimal-value-for-nginx-worker-connections + # We'll keep 10k connections per core (assuming one worker per core) + worker_connections 10000; +} + +http { + include snippets/http_access_log.conf; + + js_path "/etc/nginx/njs/"; + js_import authorization from /etc/nginx/authorization.js; + + js_set $auth_key authorization.setKey; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + # Include single-node or multiple-node (cluster) upstream + include snippets/mqtt-ws-upstream.conf; + + server { + listen 80 default_server; + listen [::]:80 default_server; + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + set $dynamic_server_name "$SMQ_NGINX_SERVER_NAME"; + + if ($dynamic_server_name = '') { + set $dynamic_server_name "localhost"; + } + + server_name $dynamic_server_name; + + ssl_verify_client optional; + include snippets/ssl.conf; + include snippets/ssl-client.conf; + + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Access-Control-Allow-Origin '*'; + add_header Access-Control-Allow-Methods '*'; + add_header Access-Control-Allow-Headers '*'; + + # Proxy pass to auth service + location ~ ^/(pats) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://auth:${SMQ_AUTH_HTTP_PORT}; + } + + # Proxy pass to domains service + location ~ ^/(domains|invitations) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://domains:${SMQ_DOMAINS_HTTP_PORT}; + } + + # Proxy pass to users service + location ~ ^/(users|groups|password|authorize|oauth/callback/[^/]+) { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://users:${SMQ_USERS_HTTP_PORT}; + } + + # Proxy pass to groups service + location ~ "^/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})/(groups)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://groups:${SMQ_GROUPS_HTTP_PORT}; + } + + # Proxy pass to clients service + location ~ "^/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})/(clients)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + # Proxy pass to channels service + location ~ "^/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})/(channels)" { + include snippets/proxy-headers.conf; + add_header Access-Control-Expose-Headers Location; + proxy_pass http://channels:${SMQ_CHANNELS_HTTP_PORT}; + } + + location /health { + include snippets/proxy-headers.conf; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + location /metrics { + include snippets/proxy-headers.conf; + proxy_pass http://clients:${SMQ_CLIENTS_HTTP_PORT}; + } + + # Proxy pass to supermq-http-adapter + location /http/ { + include snippets/verify-ssl-client.conf; + include snippets/proxy-headers.conf; + proxy_set_header Authorization $auth_key; + + # Trailing `/` is mandatory. Refer to the http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass + # If the proxy_pass directive is specified with a URI, then when a request is passed to the server, + # the part of a normalized request URI matching the location is replaced by a URI specified in the directive + proxy_pass http://http-adapter:${SMQ_HTTP_ADAPTER_PORT}/; + } + + # Proxy pass to supermq-mqtt-adapter over WS + location /mqtt { + include snippets/verify-ssl-client.conf; + include snippets/proxy-headers.conf; + include snippets/ws-upgrade.conf; + proxy_pass http://mqtt_ws_cluster; + } + + # Proxy pass to supermq-ws-adapter + location /ws/ { + include snippets/verify-ssl-client.conf; + include snippets/proxy-headers.conf; + include snippets/ws-upgrade.conf; + proxy_pass http://ws-adapter:${SMQ_WS_ADAPTER_HTTP_PORT}/; + } + } +} + +# MQTT +stream { + include snippets/stream_access_log.conf; + + # Include JS script for mTLS + js_path "/etc/nginx/njs/"; + + js_import authorization from /etc/nginx/authorization.js; + + # Include single-node or multiple-node (cluster) upstream + include snippets/mqtt-upstream.conf; + ssl_verify_client on; + include snippets/ssl-client.conf; + + server { + listen ${SMQ_NGINX_MQTT_PORT}; + listen [::]:${SMQ_NGINX_MQTT_PORT}; + listen ${SMQ_NGINX_MQTTS_PORT} ssl; + listen [::]:${SMQ_NGINX_MQTTS_PORT} ssl; + + include snippets/ssl.conf; + js_preread authorization.authenticate; + + proxy_pass mqtt_cluster; + } +} + +error_log info.log info; diff --git a/docker/supermq-docker/nginx/snippets/http_access_log.conf b/docker/supermq-docker/nginx/snippets/http_access_log.conf new file mode 100644 index 000000000..4bc37166d --- /dev/null +++ b/docker/supermq-docker/nginx/snippets/http_access_log.conf @@ -0,0 +1,12 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +log_format access_log_format 'HTTP/WS ' + '$remote_addr: ' + '"$request" $status; ' + 'request time=$request_time ' + 'upstream connect time=$upstream_connect_time ' + 'upstream address $upstream_addr ' + 'upstream status $upstream_status ' + 'upstream response time=$upstream_response_time'; +access_log access.log access_log_format; diff --git a/docker/nginx/snippets/mqtt-upstream-cluster.conf b/docker/supermq-docker/nginx/snippets/mqtt-upstream-cluster.conf similarity index 100% rename from docker/nginx/snippets/mqtt-upstream-cluster.conf rename to docker/supermq-docker/nginx/snippets/mqtt-upstream-cluster.conf diff --git a/docker/nginx/snippets/mqtt-upstream-single.conf b/docker/supermq-docker/nginx/snippets/mqtt-upstream-single.conf similarity index 100% rename from docker/nginx/snippets/mqtt-upstream-single.conf rename to docker/supermq-docker/nginx/snippets/mqtt-upstream-single.conf diff --git a/docker/nginx/snippets/mqtt-ws-upstream-cluster.conf b/docker/supermq-docker/nginx/snippets/mqtt-ws-upstream-cluster.conf similarity index 100% rename from docker/nginx/snippets/mqtt-ws-upstream-cluster.conf rename to docker/supermq-docker/nginx/snippets/mqtt-ws-upstream-cluster.conf diff --git a/docker/nginx/snippets/mqtt-ws-upstream-single.conf b/docker/supermq-docker/nginx/snippets/mqtt-ws-upstream-single.conf similarity index 100% rename from docker/nginx/snippets/mqtt-ws-upstream-single.conf rename to docker/supermq-docker/nginx/snippets/mqtt-ws-upstream-single.conf diff --git a/docker/nginx/snippets/proxy-headers.conf b/docker/supermq-docker/nginx/snippets/proxy-headers.conf similarity index 100% rename from docker/nginx/snippets/proxy-headers.conf rename to docker/supermq-docker/nginx/snippets/proxy-headers.conf diff --git a/docker/nginx/snippets/ssl-client.conf b/docker/supermq-docker/nginx/snippets/ssl-client.conf similarity index 100% rename from docker/nginx/snippets/ssl-client.conf rename to docker/supermq-docker/nginx/snippets/ssl-client.conf diff --git a/docker/nginx/snippets/ssl.conf b/docker/supermq-docker/nginx/snippets/ssl.conf similarity index 79% rename from docker/nginx/snippets/ssl.conf rename to docker/supermq-docker/nginx/snippets/ssl.conf index 9650f1fad..5ee8e3a79 100644 --- a/docker/nginx/snippets/ssl.conf +++ b/docker/supermq-docker/nginx/snippets/ssl.conf @@ -3,8 +3,8 @@ # These paths are set to its default values as # a volume in the docker/docker-compose.yml file. -ssl_certificate /etc/ssl/certs/magistrala-server.crt; -ssl_certificate_key /etc/ssl/private/magistrala-server.key; +ssl_certificate /etc/ssl/certs/supermq-server.crt; +ssl_certificate_key /etc/ssl/private/supermq-server.key; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_protocols TLSv1.2 TLSv1.3; diff --git a/docker/nginx/snippets/stream_access_log.conf b/docker/supermq-docker/nginx/snippets/stream_access_log.conf similarity index 100% rename from docker/nginx/snippets/stream_access_log.conf rename to docker/supermq-docker/nginx/snippets/stream_access_log.conf diff --git a/docker/nginx/snippets/verify-ssl-client.conf b/docker/supermq-docker/nginx/snippets/verify-ssl-client.conf similarity index 100% rename from docker/nginx/snippets/verify-ssl-client.conf rename to docker/supermq-docker/nginx/snippets/verify-ssl-client.conf diff --git a/docker/nginx/snippets/ws-upgrade.conf b/docker/supermq-docker/nginx/snippets/ws-upgrade.conf similarity index 100% rename from docker/nginx/snippets/ws-upgrade.conf rename to docker/supermq-docker/nginx/snippets/ws-upgrade.conf diff --git a/docker/supermq-docker/rabbitmq/enabled_plugins b/docker/supermq-docker/rabbitmq/enabled_plugins new file mode 100644 index 000000000..2561f4974 --- /dev/null +++ b/docker/supermq-docker/rabbitmq/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_management,rabbitmq_mqtt,rabbitmq_web_mqtt]. diff --git a/docker/supermq-docker/rabbitmq/rabbitmq.conf b/docker/supermq-docker/rabbitmq/rabbitmq.conf new file mode 100644 index 000000000..31e326c6b --- /dev/null +++ b/docker/supermq-docker/rabbitmq/rabbitmq.conf @@ -0,0 +1,15 @@ +## DEFAULT SETTINGS ARE NOT MEANT TO BE TAKEN STRAIGHT INTO PRODUCTION +## see https://www.rabbitmq.com/configure.html for further information +## on configuring RabbitMQ + +## allow access to the guest user from anywhere on the network +## https://www.rabbitmq.com/access-control.html#loopback-users +## https://www.rabbitmq.com/production-checklist.html#users +loopback_users.guest = false + +## Send all logs to stdout/TTY. Necessary to see logs when running via +## a container +log.console = true + +## Enable anonymous connection +mqtt.allow_anonymous = true diff --git a/docker/spicedb/schema.zed b/docker/supermq-docker/spicedb/schema.zed similarity index 100% rename from docker/spicedb/schema.zed rename to docker/supermq-docker/spicedb/schema.zed diff --git a/docker/supermq-docker/ssl/.gitignore b/docker/supermq-docker/ssl/.gitignore new file mode 100644 index 000000000..9ea7050a8 --- /dev/null +++ b/docker/supermq-docker/ssl/.gitignore @@ -0,0 +1,7 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +*grpc-server* +*grpc-client* +*srl +*conf diff --git a/docker/supermq-docker/ssl/Makefile b/docker/supermq-docker/ssl/Makefile new file mode 100644 index 000000000..8be7242c0 --- /dev/null +++ b/docker/supermq-docker/ssl/Makefile @@ -0,0 +1,170 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +CRT_LOCATION = certs +O = SuperMQ +OU_CA = supermq_ca +OU_CRT = supermq_crt +EA = info@supermq.com +CN_CA = SuperMQ_Self_Signed_CA +CN_SRV = localhost +CLIENT_SECRET = # e.g. 8f65ed04-0770-4ce4-a291-6d1bf2000f4d +CRT_FILE_NAME = client +CLIENTS_GRPC_SERVER_CONF_FILE_NAME=client-grpc-server.conf +CLIENTS_GRPC_CLIENT_CONF_FILE_NAME=client-grpc-client.conf +CLIENTS_GRPC_SERVER_CN=clients +CLIENTS_GRPC_CLIENT_CN=clients-client +CLIENTS_GRPC_SERVER_CRT_FILE_NAME=clients-grpc-server +CLIENTS_GRPC_CLIENT_CRT_FILE_NAME=clients-grpc-client +AUTH_GRPC_SERVER_CONF_FILE_NAME=auth-grpc-server.conf +AUTH_GRPC_CLIENT_CONF_FILE_NAME=auth-grpc-client.conf +AUTH_GRPC_SERVER_CN=auth +AUTH_GRPC_CLIENT_CN=auth-client +AUTH_GRPC_SERVER_CRT_FILE_NAME=auth-grpc-server +AUTH_GRPC_CLIENT_CRT_FILE_NAME=auth-grpc-client + +define GRPC_CERT_CONFIG +[req] +req_extensions = v3_req +distinguished_name = dn +prompt = no + +[dn] +CN = mg.svc +C = RS +ST = RS +L = BELGRADE +O = SUPERMQ +OU = SUPERMQ + +[v3_req] +subjectAltName = @alt_names + +[alt_names] +DNS.1 = <> +endef + +define ANNOUNCE_BODY +Version $(VERSION) of $(PACKAGE_NAME) has been released. + +It can be downloaded from $(DOWNLOAD_URL). + +etc, etc. +endef +all: clean_certs ca server_cert clients_grpc_certs auth_grpc_certs + +# CA name and key is "ca". +ca: + openssl req -newkey rsa:2048 -x509 -nodes -sha512 -days 1095 \ + -keyout $(CRT_LOCATION)/ca.key -out $(CRT_LOCATION)/ca.crt -subj "/CN=$(CN_CA)/O=$(O)/OU=$(OU_CA)/emailAddress=$(EA)" + +# Server cert and key name is "supermq-server". +server_cert: + # Create supermq server key and CSR. + openssl req -new -sha256 -newkey rsa:4096 -nodes -keyout $(CRT_LOCATION)/supermq-server.key \ + -out $(CRT_LOCATION)/supermq-server.csr -subj "/CN=$(CN_SRV)/O=$(O)/OU=$(OU_CRT)/emailAddress=$(EA)" + + # Sign server CSR. + openssl x509 -req -days 1000 -in $(CRT_LOCATION)/supermq-server.csr -CA $(CRT_LOCATION)/ca.crt -CAkey $(CRT_LOCATION)/ca.key -CAcreateserial -out $(CRT_LOCATION)/supermq-server.crt + + # Remove CSR. + rm $(CRT_LOCATION)/supermq-server.csr + +client_cert: + # Create supermq server key and CSR. + openssl req -new -sha256 -newkey rsa:4096 -nodes -keyout $(CRT_LOCATION)/$(CRT_FILE_NAME).key \ + -out $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -subj "/CN=$(CLIENTS_SECRET)/O=$(O)/OU=$(OU_CRT)/emailAddress=$(EA)" + + # Sign client CSR. + openssl x509 -req -days 730 -in $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -CA $(CRT_LOCATION)/ca.crt -CAkey $(CRT_LOCATION)/ca.key -CAcreateserial -out $(CRT_LOCATION)/$(CRT_FILE_NAME).crt + + # Remove CSR. + rm $(CRT_LOCATION)/$(CRT_FILE_NAME).csr + +clients_grpc_certs: + # Clients server grpc certificates + $(file > $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).conf,$(subst <>,$(CLIENTS_GRPC_SERVER_CN),$(GRPC_CERT_CONFIG)) ) + + openssl req -new -sha256 -newkey rsa:4096 -nodes \ + -keyout $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).key \ + -out $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).csr \ + -config $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).conf \ + -extensions v3_req + + openssl x509 -req -sha256 \ + -in $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).csr \ + -CA $(CRT_LOCATION)/ca.crt \ + -CAkey $(CRT_LOCATION)/ca.key \ + -CAcreateserial \ + -out $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).crt \ + -days 365 \ + -extfile $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).conf \ + -extensions v3_req + + rm -rf $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).csr $(CRT_LOCATION)/$(CLIENTS_GRPC_SERVER_CRT_FILE_NAME).conf + # Clients client grpc certificates + $(file > $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).conf,$(subst <>,$(CLIENTS_GRPC_CLIENT_CN),$(GRPC_CERT_CONFIG)) ) + + openssl req -new -sha256 -newkey rsa:4096 -nodes \ + -keyout $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).key \ + -out $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).csr \ + -config $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).conf \ + -extensions v3_req + + openssl x509 -req -sha256 \ + -in $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).csr \ + -CA $(CRT_LOCATION)/ca.crt \ + -CAkey $(CRT_LOCATION)/ca.key \ + -CAcreateserial \ + -out $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).crt \ + -days 365 \ + -extfile $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).conf \ + -extensions v3_req + + rm -rf $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).csr $(CRT_LOCATION)/$(CLIENTS_GRPC_CLIENT_CRT_FILE_NAME).conf + +auth_grpc_certs: + # Auth gRPC server certificate + $(file > $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).conf,$(subst <>,$(AUTH_GRPC_SERVER_CN),$(GRPC_CERT_CONFIG)) ) + + openssl req -new -sha256 -newkey rsa:4096 -nodes \ + -keyout $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).key \ + -out $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).csr \ + -config $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).conf \ + -extensions v3_req + + openssl x509 -req -sha256 \ + -in $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).csr \ + -CA $(CRT_LOCATION)/ca.crt \ + -CAkey $(CRT_LOCATION)/ca.key \ + -CAcreateserial \ + -out $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).crt \ + -days 365 \ + -extfile $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).conf \ + -extensions v3_req + + rm -rf $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).csr $(CRT_LOCATION)/$(AUTH_GRPC_SERVER_CRT_FILE_NAME).conf + # Auth gRPC client certificate + $(file > $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).conf,$(subst <>,$(AUTH_GRPC_CLIENT_CN),$(GRPC_CERT_CONFIG)) ) + + openssl req -new -sha256 -newkey rsa:4096 -nodes \ + -keyout $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).key \ + -out $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).csr \ + -config $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).conf \ + -extensions v3_req + + openssl x509 -req -sha256 \ + -in $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).csr \ + -CA $(CRT_LOCATION)/ca.crt \ + -CAkey $(CRT_LOCATION)/ca.key \ + -CAcreateserial \ + -out $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).crt \ + -days 365 \ + -extfile $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).conf \ + -extensions v3_req + + rm -rf $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).csr $(CRT_LOCATION)/$(AUTH_GRPC_CLIENT_CRT_FILE_NAME).conf + +clean_certs: + rm -r $(CRT_LOCATION)/*.crt + rm -r $(CRT_LOCATION)/*.key diff --git a/docker/ssl/authorization.js b/docker/supermq-docker/ssl/authorization.js similarity index 98% rename from docker/ssl/authorization.js rename to docker/supermq-docker/ssl/authorization.js index 5bfedbe9c..bf0652138 100644 --- a/docker/ssl/authorization.js +++ b/docker/supermq-docker/ssl/authorization.js @@ -170,7 +170,7 @@ function parseCert(cert, key) { for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].split('='); if (pair[0].toUpperCase() == key) { - return "Thing " + pair[1].replace("\\", "").trim(); + return "Client " + pair[1].replace("\\", "").trim(); } } } diff --git a/docker/supermq-docker/ssl/certs/ca.crt b/docker/supermq-docker/ssl/certs/ca.crt new file mode 100644 index 000000000..34f07283e --- /dev/null +++ b/docker/supermq-docker/ssl/certs/ca.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIUDIJg63dQVzoD9nmWi9YPscQwTgIwDQYJKoZIhvcNAQEN +BQAwdTEiMCAGA1UEAwwZTWFnaXN0cmFsYV9TZWxmX1NpZ25lZF9DQTETMBEGA1UE +CgwKTWFnaXN0cmFsYTEWMBQGA1UECwwNbWFnaXN0cmFsYV9jYTEiMCAGCSqGSIb3 +DQEJARYTaW5mb0BtYWdpc3RyYWxhLmNvbTAeFw0yMzEwMzAwODE5MDFaFw0yNjEw +MjkwODE5MDFaMHUxIjAgBgNVBAMMGU1hZ2lzdHJhbGFfU2VsZl9TaWduZWRfQ0Ex +EzARBgNVBAoMCk1hZ2lzdHJhbGExFjAUBgNVBAsMDW1hZ2lzdHJhbGFfY2ExIjAg +BgkqhkiG9w0BCQEWE2luZm9AbWFnaXN0cmFsYS5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWNIeGfo/SePOvviJE6UHJhBzWcPfNVbzSF6A42WgB +DEgI3KFr+/rgWMEaCOD4QzCl3Lqa89EgCA7xCgxcqFwEo33SyhAivwoHL2pRVHXn +oee3z9U757T63YLE0qrXQY2cbyChX/OU99rZxyd5l5jUGN7MCu+RYurfTIiYN+Uv +NZdl8a3X84g7fa70EOYas7cTunWUt9x64/jYDoYmn+XPXET1yEU1dQTnKY4cRjhv +HS1u2QsadHKi1hgeILyLbB4u1T5N+WfxFknhFHTu8PVPxfowrVv/xzmxOe0zSZFd +SbhtrmwT4S1wJ4PfUa3+tYZVtjEKKbyObsAW91WzOLS9AgMBAAGjUzBRMB0GA1Ud +DgQWBBQkE4koZctEZpTz9pq6a6s6xg+myTAfBgNVHSMEGDAWgBQkE4koZctEZpTz +9pq6a6s6xg+myTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQA7 +w/oh5U9loJsigf3X3T3jQM8PVmhsUfNMJ3kc1Yumr72S4sGKjdWwuU0vk+B3eQzh +zXAj65BHhs1pXcukeoLR7YcHABEsEMg6lar/E4A+MgAZfZFVSvPpsByIK8I5ARk+ +K1V/lWso+GJJM/lImPPnpvUWBdbntqC5WtjoMMGL9uyV3kVS6yT/kJ2ercnPzhPh +uBkL1ZH3ivDn/0JDY+T8Sfeq08vNWaTcoC7qpPwqXhuT0ytY7oaBS5wmPcvvzpZg +6zZYPZfhjhdEFYY1hDrrPYNYO72jncUnwQVp3X0DQpSvbxp681hVkcEtwHB2B8l0 +tBGhgoH+TqZs0AUjoXM0 +-----END CERTIFICATE----- diff --git a/docker/supermq-docker/ssl/certs/ca.key b/docker/supermq-docker/ssl/certs/ca.key new file mode 100644 index 000000000..0ba786be5 --- /dev/null +++ b/docker/supermq-docker/ssl/certs/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCWNIeGfo/SePOv +viJE6UHJhBzWcPfNVbzSF6A42WgBDEgI3KFr+/rgWMEaCOD4QzCl3Lqa89EgCA7x +CgxcqFwEo33SyhAivwoHL2pRVHXnoee3z9U757T63YLE0qrXQY2cbyChX/OU99rZ +xyd5l5jUGN7MCu+RYurfTIiYN+UvNZdl8a3X84g7fa70EOYas7cTunWUt9x64/jY +DoYmn+XPXET1yEU1dQTnKY4cRjhvHS1u2QsadHKi1hgeILyLbB4u1T5N+WfxFknh +FHTu8PVPxfowrVv/xzmxOe0zSZFdSbhtrmwT4S1wJ4PfUa3+tYZVtjEKKbyObsAW +91WzOLS9AgMBAAECggEAEOxEq6jFO/WgIPgHROPR42ok1J1AMgx7nGEIjnciImIX +mJYBAtlOM+oUAYKoFBh/2eQTSyN2t4jo5AvZhjP6wBQKeE4HQN7supADRrwBF7KU +WI+MKvZpW81KrzG8CUoLsikMEFpu52UAbYJkZmznzVeq/GqsAKGYLEXjauD7S5Tu +GeGVKO4novus6t3AHnBvfalIQ1JUuJFvcd5ZDhPljlzPbbWdM4WpRPaFZIKmfXft +G7Izt58yPCYwhxohjrunRudyX3oKvmCBUOBXC8HdHzND/dLxwlrVu7OjmXprmC6P +8ggNpjAPeO8Y6+EKGne1fETNsKgODY/lXGOwECY4eQKBgQDSGi3WuoT/+DecVeSF +GfmavdGCQKOD0kdl7qCeQYAL+SPVz4157AtxZs3idapvlbrc7wvw4Ev1XT7ZmWUj +Lc4/UAITR8EkkFRVbxt2PvV86AiQtmXFguTNEX5vTszRwZ2+eqijZga5niBkqyAi +SRuTwR8WrDZau4mRNnF8bUl8dQKBgQC3BKYifRp4hHqBycHe9rSMZ8Xz+ZOy+IFA +vYap1Az+e8KuqlmD9Kfpp2Mjba1+HL5WKeTJGpFE7bhvb/xMPJgbMgtQ/cw4uDJ/ +fwv4m6arf76ebOhaZtkT1vD4NyiyB+z6xP0TRgQRr2Or98XBSvGAYDXIn5vL7fUg +KrDF0ePuKQKBgDfaOcFRiDW7uJzYwI0ZoJ8gQufLYyyR4+UXEJ/BbdbA/mPCbyuw +MkKNP8Ip4YsUVL6S1avNFKQ/i4uxGY/Gh4ORM1wIwTGFJMYpaTV/+yafUFeYBWoC +J+zT77aLTiucuuB+HwKBBtylSps4WqyCntAikK8oTLLGFAYEYRrgup5ZAoGAbQ8j +JNghxwFCs0aT9ZZTfnt0NW9auUJmWzrVHSxUVe1P1J+EWiKXUJ/DbuAzizv7nAK4 +57GiMU3rItS7pn5RMZt/rNKgOIhi5yDA9HNkPTwRTfyd9QjmgHEMBQ1xfa1FZSWv +nSWS1SsLnPU37XgIMzShuByMTVhOQs3NqwPo7AkCgYAf8AzQNjFCoTwU3SJezJ4H +9j1jvMO232hAl8UDNtqvJ1APn87tOtnfX48OMoRrP9kKI0oygE3pq7rFxu1qmTns +Zir0+KLeWGg58fSZkUEAp6kbO5CKwoeVAY9EMgd7BYBqlXLqUNfdH0L+KUOFKHha +7e82VxpgBeskzAqN1e7YRA== +-----END PRIVATE KEY----- diff --git a/docker/supermq-docker/ssl/certs/supermq-server.crt b/docker/supermq-docker/ssl/certs/supermq-server.crt new file mode 100644 index 000000000..4e893c1ec --- /dev/null +++ b/docker/supermq-docker/ssl/certs/supermq-server.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEYjCCA0oCFGXr7rfGAynaa4KMTG1+23EEF0lYMA0GCSqGSIb3DQEBCwUAMHUx +IjAgBgNVBAMMGU1hZ2lzdHJhbGFfU2VsZl9TaWduZWRfQ0ExEzARBgNVBAoMCk1h +Z2lzdHJhbGExFjAUBgNVBAsMDW1hZ2lzdHJhbGFfY2ExIjAgBgkqhkiG9w0BCQEW +E2luZm9AbWFnaXN0cmFsYS5jb20wHhcNMjMxMDMwMDgxOTA4WhcNMjYwNzI2MDgx +OTA4WjBmMRIwEAYDVQQDDAlsb2NhbGhvc3QxEzARBgNVBAoMCk1hZ2lzdHJhbGEx +FzAVBgNVBAsMDm1hZ2lzdHJhbGFfY3J0MSIwIAYJKoZIhvcNAQkBFhNpbmZvQG1h +Z2lzdHJhbGEuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAojas +t6M294uS5q8oFmYM6DULVQ1lY3K659VusJshjGvn8bi50vhKo8PpxL6ygVpjWcHG ++/gclQnTaYZumC1TUohibpBnrFx1PZUvGiryAPudFY2nC5af5BQnYGi845FcVWx5 +FNLq+IsedgSZf7FuGcZruXiukBCWVyWJRJh+8FDakc65BPeG9FpCxbeLZ1nrDpnQ +bhHbwEQrwwHk0FHZ/3cuVFJAjwqJSivJ9598eU0YWAsqsLM3uYyvOMd8alMs5vCZ +9tMCpO2v6xTdJ6kr68SwQQAiefRy6gsD5J5A4ySyCz7KX9fHCrqx1kdcDJ/CXZmh +mXxrCFKSjqjuSn2qtm+gxvAc26Zbt5z5eihpdISDUKrjW11+yapNZLATGBX8ktek +gW467V9DQYOsbA3fNkWgd5UcV5HIViUpqFMFvi1NpWc2INi/PTDWuAIBLUiVNk0W +qMtG7/HqFRPn6MrNGpvFpglgxXGNfjsggkK/3INtFnAou2rN9+ieeuzO7Zjrtwsq +sP64GVw/vLv3tgT6TIZmDnCDCqtEGEVutt7ldu3M0/fLm4qOUsZqFGrIOO1cfI4x +7FRnHwaTsTB1Og+I7lEujb4efHV+uRjKyrGh6L6hDt94IkGm6ZEj5z/iEmq16jRX +dUbYsu4f1KlfTYdHWGHp+6kAmDn0jGCwz2BBrnsCAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAKyg5kvDk+TQ6ZDCK7qxKY+uN9setYvvsLfde+Uy51a3zj8RIHRgkOT2C +LuuTtTYKu3XmfCKId0oTXynGuP+yDAIuVwuZz3S0VmA8ijoZ87LJXzsLjjTjQSzZ +ar6RmlRDH+8Bm4AOrT4TDupqifag4J0msHkNPo0jVK6fnuniqJoSlhIbbHrJTHhv +jKNXrThjr/irgg1MZ7slojieOS0QoZHRE9eunIR5enDJwB5pWUJSmZWlisI7+Ibi +06+j8wZegU0nqeWp4wFSZxKnrzz5B5Qu9SrALwlHWirzBpyr0gAcF2v7nzbWviZ/ +0VMyY4FGEbkp6trMxwJs5hGYhAiyXg== +-----END CERTIFICATE----- diff --git a/docker/supermq-docker/ssl/certs/supermq-server.key b/docker/supermq-docker/ssl/certs/supermq-server.key new file mode 100644 index 000000000..f2b56f417 --- /dev/null +++ b/docker/supermq-docker/ssl/certs/supermq-server.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCiNqy3ozb3i5Lm +rygWZgzoNQtVDWVjcrrn1W6wmyGMa+fxuLnS+Eqjw+nEvrKBWmNZwcb7+ByVCdNp +hm6YLVNSiGJukGesXHU9lS8aKvIA+50VjacLlp/kFCdgaLzjkVxVbHkU0ur4ix52 +BJl/sW4Zxmu5eK6QEJZXJYlEmH7wUNqRzrkE94b0WkLFt4tnWesOmdBuEdvARCvD +AeTQUdn/dy5UUkCPColKK8n3n3x5TRhYCyqwsze5jK84x3xqUyzm8Jn20wKk7a/r +FN0nqSvrxLBBACJ59HLqCwPknkDjJLILPspf18cKurHWR1wMn8JdmaGZfGsIUpKO +qO5Kfaq2b6DG8Bzbplu3nPl6KGl0hINQquNbXX7Jqk1ksBMYFfyS16SBbjrtX0NB +g6xsDd82RaB3lRxXkchWJSmoUwW+LU2lZzYg2L89MNa4AgEtSJU2TRaoy0bv8eoV +E+foys0am8WmCWDFcY1+OyCCQr/cg20WcCi7as336J567M7tmOu3Cyqw/rgZXD+8 +u/e2BPpMhmYOcIMKq0QYRW623uV27czT98ubio5SxmoUasg47Vx8jjHsVGcfBpOx +MHU6D4juUS6Nvh58dX65GMrKsaHovqEO33giQabpkSPnP+ISarXqNFd1Rtiy7h/U +qV9Nh0dYYen7qQCYOfSMYLDPYEGuewIDAQABAoICACvgzTyJTkOMwipbQ+U3KpOf +UZbqnjvV23/9iEkGVX9V6vJETSOnnQ0KYBAjo0aBLDGpzIj41sZr13+KaR0J2amQ +EcwljJ2fjukfExQpfLfOV/HuFLr6Pfrkhrg57KpD9i13P5Nl8EBV5WH4IYtcc9NO +DHKpldKLYhdlpGllNKUNwenB+ONCj4NGbRxtZyyIMqCK88nqU76A0jOYLgw5r9W+ +J86QRz1KFNP231V3kyR+ubCLKLuOZuruhrE9qMZcBF/dwk/1SRhS4QyeYqopRSOr +2x9iCXFisbjkTOPI+PVYRj7rd7OQOxuIX7V+LQSPLHTEK2XItW0VZOZpBLgqoQP1 +Eu19LOOs77DI5FBia1qhSpjjVGOE6koQmCki8KSFZM+CzuflTPkWNVvTNzjKrhUj +Rbezx40VVFt+q38bsTjWJbimMSo1jChianwjtotGnGpC6pD0KnHsBmfceWaL7+eC +n9KtSeAbnXlFN/rHdK7ZeP/PTSjHa+6i1awGZxhwdVsERJy/2xwZzh3uMLS2ZhXM +Tuh1D5GzlUlkMP8K23rfaXnaOXkwYxHFGi23NmxHGSqzA3TVVreWLqRSZJd/Ar67 +9Pl4S9p9f+Xkvq8tQANfoaTbjc//dpK8rjCKnwdWA3cL7eekq9sm4+lTmik9Bn2v +Bo+3/89Fr1FvlkuQvktJAoIBAQDNuc2r/9sthHZg1hOCFd5XmnMX/mXNPs+SDPRW +/VZBHjxGApz+CoZS7qk0q7f/vzYFTB6N3778f7RsgwrZYSD4I4jumvSFNFsxsHCY +K3O4kkd2YaFaZPwUYbbAcBr6nVnW/9b1aagEfWIMQ18FHLaQ6u2OfUOcNDGZEqwj +YqJmZr8plhWLeKP2c673j6g/ztnL0w77y3LnIuLjFGex17l1lQzbUgOPSKyoQj03 +d5eRoJv2aQTaOXaBzGrDtBDDd3BpXrriJEMqSZbZFRLM28jD+VuHjfHOZRUMy1hw +vZCifRrBYA6Frko7ZweRxIkcOwQsQjV/tkzVkg9FHrVhMKQTAoIBAQDJ2r+lR73d +va1JjWoXKe5qAWtprRyI8DpJM/G2/V/V3+RVOGgBeRlu6WDiMpMd9hFB6bAmX+1y +S17svw1f4DQskkTKi9EWBsWRnh2Pnd4q91TjKFsBuci8/EtAXb7C0KV5nEtasEUJ +klMmO1evAXMhn7VzmE3Ic/ttcQHxQZ+TC4G5dGsYcideJ5zOeEIATtFypDNG/0Bw +rvmBbIIylY2KwUAx3UexRgH1hRSecTzkokT39WJbefUg952h7yZXrrhb71AfWLTC +A5MJeArqPK6z/RMxDyvnk7xW326dtBBgqYyTOIHCANRB1kAG0xEyia/WI94uyNfH +YfIHglDFGIj5AoIBAEVVNEqeXPi3Jso1+7cgtaFijR1uAFMusvfu474ZfSNPFFMn ++E7pryFuC5qTsNxBTex1HesEmDIyu9TCSTq/sEPQfgqkMHpgDcfuRdQS+NogenMc +Livv0sDvuY6beYwy0Z9S89gbtqNkulGVtwVbCvBGLK+T6eBP+tMy5s66JC9Mu2pB +iZtKmj+p9zK5uKNgjChURj138I6TRFHxg4z9PiSxifa0ajy06nN+d3ElHfDXZxih +hiAhs53FDcpM+kVWEI2CfotOW1B6IpugrYhbHgtmE4HYxcCgcnqwYWsFiCQq84Ru +YhaNibkBXRy0Vt0rypk76xnSj4x+wCS0V76cjP8CggEAHXdoaJlLdzY8OLODHDSL +0D+6zWdu9fKTn6IMlBjyx4byjxo33JcwBkfdU8fsQABuzn9trnxsbjXgepD9Q9S3 +6RXFIwg8EooUh0hcql1yVDVc1/hJKLxVOHlgBtpogYnxzgnp2ihHO7l3l+orx6lf +hDYLR/+gwzVjK7vGe9CHmfChFFCRXbU0WANSWbWmdOMMoj6kGaYjYw+37pPHgdjh +G7NQSrcxwwgkOxIdS2/eYsXpaYURwabRCOn8wenmYABqe0k5GgpaAMSCz2wNs9n9 +6tpz1cKQNzMS2F+vhygFCAdYNRmXn5l9YssC97wSE52T5J/BzHSXQ0ziBwSYA92s +CQKCAQAFPujh1HhOBtn3FOT3I2jNSTv9OJsmAeiFrhVfIw+Ij8XzzUf0aV04Et/R +/EetirP6WjNQuJ5/YYVUFWj07vSl20YP7NtDGFUlvWugJUvQByidHt5DkmehBWax +cfp5LWwZ4W/wm4F/DtPkgEXgEwY/TMXHvhvN6+JaQPO7iemWL7qsRAPea0oDLkMm +0phT3hKgcnbyewH6GU53KQgr2hUzhgGOKibAo+4ud9lY6M/X1axCepetKMl78Cz9 +rK2MgJOhDr6Nu/K2bKL8Q3zSB1n1WRNaTVnH6wY4j/FpeQvVv+qTAbZhJm7cRT5m ++C7JCqJGg66liqIMq6YyYXK//Ddl +-----END PRIVATE KEY----- diff --git a/docker/supermq-docker/ssl/dhparam.pem b/docker/supermq-docker/ssl/dhparam.pem new file mode 100644 index 000000000..e0f2ebb78 --- /dev/null +++ b/docker/supermq-docker/ssl/dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAquN8NRcSdLOM9RiumqWH8Jw3CGVR/eQQeq+jvT3zpxlUQPAMExQb +MRCspm1oRgDWGvch3Z4zfMmBZyzKJA4BDTh4USzcE5zvnx8aUcUPZPQpwSicKgzb +QGnl0Xf/75GAWrwhxn8GNyMP29wrpcd1Qg8fEQ3HAW1fCd9girKMKY9aBaHli/h2 +R9Rd/KTbeqN88aoMjUvZHooIIZXu0A+kyulOajYQO4k3Sp6CBqv0FFcoLQnYNH13 +kMUE5qJ68U732HybTw8sofTCOxKcCfM2kVP7dVoF3prlGjUw3z3l3STY8vuTdq0B +R7PslkoQHNmqcL+2gouoWP3GI+IeRzGSSwIBAg== +-----END DH PARAMETERS----- diff --git a/docker/templates/smtp-notifier.tmpl b/docker/supermq-docker/templates/smtp-notifier.tmpl similarity index 100% rename from docker/templates/smtp-notifier.tmpl rename to docker/supermq-docker/templates/smtp-notifier.tmpl diff --git a/docker/templates/users.tmpl b/docker/supermq-docker/templates/users.tmpl similarity index 100% rename from docker/templates/users.tmpl rename to docker/supermq-docker/templates/users.tmpl diff --git a/docker/vernemq/Dockerfile b/docker/vernemq/Dockerfile deleted file mode 100644 index 76152b1f5..000000000 --- a/docker/vernemq/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) Abstract Machines -# SPDX-License-Identifier: Apache-2.0 - -# Builder -FROM erlang:25.3.2.8-alpine AS builder -RUN apk add --update git build-base bsd-compat-headers openssl-dev snappy-dev curl \ - && git clone -b 1.13.0 https://github.com/vernemq/vernemq \ - && cd vernemq \ - && make -j 16 rel - -# Executor -FROM alpine:3.19 - -COPY --from=builder /vernemq/_build/default/rel / - -RUN apk --no-cache --update --available upgrade && \ - apk add --no-cache ncurses-libs openssl libstdc++ jq curl bash snappy-dev && \ - addgroup --gid 10000 vernemq && \ - adduser --uid 10000 -H -D -G vernemq -h /vernemq vernemq && \ - install -d -o vernemq -g vernemq /vernemq - -# Defaults -ENV DOCKER_VERNEMQ_KUBERNETES_LABEL_SELECTOR="app=vernemq" \ - DOCKER_VERNEMQ_LOG__CONSOLE=console \ - PATH="/vernemq/bin:$PATH" \ - VERNEMQ_VERSION="1.13.0" - -WORKDIR /vernemq - -COPY --chown=10000:10000 bin/vernemq.sh /usr/sbin/start_vernemq -COPY --chown=10000:10000 files/vm.args /vernemq/etc/vm.args - -RUN chown -R 10000:10000 /vernemq && \ - ln -s /vernemq/etc /etc/vernemq && \ - ln -s /vernemq/data /var/lib/vernemq && \ - ln -s /vernemq/log /var/log/vernemq - -# Ports -# 1883 MQTT -# 8883 MQTT/SSL -# 8080 MQTT WebSockets -# 44053 VerneMQ Message Distribution -# 4369 EPMD - Erlang Port Mapper Daemon -# 8888 Health, API, Prometheus Metrics -# 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 Specific Distributed Erlang Port Range - -EXPOSE 1883 8883 8080 44053 4369 8888 \ - 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 - - -VOLUME ["/vernemq/log", "/vernemq/data", "/vernemq/etc"] - -HEALTHCHECK CMD vernemq ping | grep -q pong - -USER vernemq -CMD ["start_vernemq"] \ No newline at end of file diff --git a/docker/vernemq/bin/vernemq.sh b/docker/vernemq/bin/vernemq.sh deleted file mode 100755 index 4c990dafd..000000000 --- a/docker/vernemq/bin/vernemq.sh +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env sh - -NET_INTERFACE=$(route | grep '^default' | grep -o '[^ ]*$') -NET_INTERFACE=${DOCKER_NET_INTERFACE:-${NET_INTERFACE}} -IP_ADDRESS=$(ip -4 addr show ${NET_INTERFACE} | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sed -e "s/^[[:space:]]*//" | head -n 1) -IP_ADDRESS=${DOCKER_IP_ADDRESS:-${IP_ADDRESS}} - -VERNEMQ_ETC_DIR="/vernemq/etc" -VERNEMQ_VM_ARGS_FILE="${VERNEMQ_ETC_DIR}/vm.args" -VERNEMQ_CONF_FILE="${VERNEMQ_ETC_DIR}/vernemq.conf" -VERNEMQ_CONF_LOCAL_FILE="${VERNEMQ_ETC_DIR}/vernemq.conf.local" - -SECRETS_KUBERNETES_DIR="/var/run/secrets/kubernetes.io/serviceaccount" - -# Function to check istio readiness -istio_health() { - cmd=$(curl -s http://localhost:15021/healthz/ready > /dev/null) - status=$? - return $status -} - -# Ensure we have all files and needed directory write permissions -if [ ! -d ${VERNEMQ_ETC_DIR} ]; then - echo "Configuration directory at ${VERNEMQ_ETC_DIR} does not exist, exiting" >&2 - exit 1 -fi -if [ ! -f ${VERNEMQ_VM_ARGS_FILE} ]; then - echo "ls -l ${VERNEMQ_ETC_DIR}" - ls -l ${VERNEMQ_ETC_DIR} - echo "###" >&2 - echo "### Configuration file ${VERNEMQ_VM_ARGS_FILE} does not exist, exiting" >&2 - echo "###" >&2 - exit 1 -fi -if [ ! -w ${VERNEMQ_VM_ARGS_FILE} ]; then - echo "# whoami" - whoami - echo "# ls -l ${VERNEMQ_ETC_DIR}" - ls -l ${VERNEMQ_ETC_DIR} - echo "###" >&2 - echo "### Configuration file ${VERNEMQ_VM_ARGS_FILE} exists, but there are no write permissions! Exiting." >&2 - echo "###" >&2 - exit 1 -fi -if [ ! -s ${VERNEMQ_VM_ARGS_FILE} ]; then - echo "ls -l ${VERNEMQ_ETC_DIR}" - ls -l ${VERNEMQ_ETC_DIR} - echo "###" >&2 - echo "### Configuration file ${VERNEMQ_VM_ARGS_FILE} is empty! This will not work." >&2 - echo "### Exiting now." >&2 - echo "###" >&2 - exit 1 -fi - -# Ensure the Erlang node name is set correctly -if env | grep "DOCKER_VERNEMQ_NODENAME" -q; then - sed -i.bak -r "s/-name VerneMQ@.+/-name VerneMQ@${DOCKER_VERNEMQ_NODENAME}/" ${VERNEMQ_VM_ARGS_FILE} -else - if [ -n "$DOCKER_VERNEMQ_SWARM" ]; then - NODENAME=$(hostname -i) - sed -i.bak -r "s/VerneMQ@.+/VerneMQ@${NODENAME}/" ${VERNEMQ_VM_ARGS_FILE} - else - sed -i.bak -r "s/-name VerneMQ@.+/-name VerneMQ@${IP_ADDRESS}/" ${VERNEMQ_VM_ARGS_FILE} - fi -fi - -if env | grep "DOCKER_VERNEMQ_DISCOVERY_NODE" -q; then - discovery_node=$DOCKER_VERNEMQ_DISCOVERY_NODE - if [ -n "$DOCKER_VERNEMQ_SWARM" ]; then - tmp='' - while [[ -z "$tmp" ]]; do - tmp=$(getent hosts tasks.$discovery_node | awk '{print $1}' | head -n 1) - sleep 1 - done - discovery_node=$tmp - fi - if [ -n "$DOCKER_VERNEMQ_COMPOSE" ]; then - tmp='' - while [[ -z "$tmp" ]]; do - tmp=$(getent hosts $discovery_node | awk '{print $1}' | head -n 1) - sleep 1 - done - discovery_node=$tmp - fi - - sed -i.bak -r "/-eval.+/d" ${VERNEMQ_VM_ARGS_FILE} - echo "-eval \"vmq_server_cmd:node_join('VerneMQ@$discovery_node')\"" >> ${VERNEMQ_VM_ARGS_FILE} -fi - -# If you encounter "SSL certification error (subject name does not match the host name)", you may try to set DOCKER_VERNEMQ_KUBERNETES_INSECURE to "1". -insecure="" -if env | grep "DOCKER_VERNEMQ_KUBERNETES_INSECURE" -q; then - echo "Using curl with \"--insecure\" argument to access kubernetes API without matching SSL certificate" - insecure="--insecure" -fi - -if env | grep "DOCKER_VERNEMQ_KUBERNETES_ISTIO_ENABLED" -q; then - istio_health - while [ $status != 0 ]; do - istio_health - sleep 1 - done - echo "Istio ready" -fi - -# Function to call a HTTP GET request on the given URL Path, using the hostname -# of the current k8s cluster name. Usage: "k8sCurlGet /my/path" -function k8sCurlGet () { - local urlPath=$1 - - local hostname="kubernetes.default.svc.${DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME}" - local certsFile="${SECRETS_KUBERNETES_DIR}/ca.crt" - local token=$(cat ${SECRETS_KUBERNETES_DIR}/token) - local header="Authorization: Bearer ${token}" - local url="https://${hostname}/${urlPath}" - - curl -sS ${insecure} --cacert ${certsFile} -H "${header}" ${url} \ - || ( echo "### Error on accessing URL ${url}" ) -} - -DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME=${DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME:-cluster.local} -if [ -d "${SECRETS_KUBERNETES_DIR}" ] ; then - # Let's get the namespace if it isn't set - DOCKER_VERNEMQ_KUBERNETES_NAMESPACE=${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE:-$(cat "${SECRETS_KUBERNETES_DIR}/namespace")} - - # Check the API access that will be needed in the TERM signal handler - podResponse=$(k8sCurlGet api/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/pods/$(hostname) ) - statefulSetName=$(echo ${podResponse} | jq -r '.metadata.ownerReferences[0].name') - statefulSetPath="apis/apps/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/statefulsets/${statefulSetName}" - statefulSetResponse=$(k8sCurlGet ${statefulSetPath} ) - isCodeForbidden=$(echo ${statefulSetResponse} | jq '.code == 403') - if [[ ${isCodeForbidden} == "true" ]]; then - echo "Permission error: Cannot access URL ${statefulSetPath}: $(echo ${statefulSetResponse} | jq '.reason,.code,.message')" - exit 1 - else - numReplicas=$(echo ${statefulSetResponse} | jq '.status.replicas') - echo "Permissions ok: Our pod $(hostname) belongs to StatefulSet ${statefulSetName} with ${numReplicas} replicas" - fi -fi - -# Set up kubernetes node discovery -start_join_cluster=0 -if env | grep "DOCKER_VERNEMQ_DISCOVERY_KUBERNETES" -q; then - # Let's set our nodename correctly - # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#list-pod-v1-core - podList=$(k8sCurlGet "api/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/pods?labelSelector=${DOCKER_VERNEMQ_KUBERNETES_LABEL_SELECTOR}") - VERNEMQ_KUBERNETES_SUBDOMAIN=${DOCKER_VERNEMQ_KUBERNETES_SUBDOMAIN:-$(echo ${podList} | jq '.items[0].spec.subdomain' | tr '\n' '"' | sed 's/"//g')} - if [[ $VERNEMQ_KUBERNETES_SUBDOMAIN == "null" ]]; then - VERNEMQ_KUBERNETES_HOSTNAME=${MY_POD_NAME}.${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}.svc.${DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME} - else - VERNEMQ_KUBERNETES_HOSTNAME=${MY_POD_NAME}.${VERNEMQ_KUBERNETES_SUBDOMAIN}.${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}.svc.${DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME} - fi - - sed -i.bak -r "s/VerneMQ@.+/VerneMQ@${VERNEMQ_KUBERNETES_HOSTNAME}/" ${VERNEMQ_VM_ARGS_FILE} - # Hack into K8S DNS resolution (temporarily) - kube_pod_names=$(echo ${podList} | jq '.items[].spec.hostname' | sed 's/"//g' | tr '\n' ' ' | sed 's/ *$//') - - for kube_pod_name in $kube_pod_names; do - if [[ $kube_pod_name == "null" ]]; then - echo "Kubernetes discovery selected, but no pods found. Maybe we're the first?" - echo "Anyway, we won't attempt to join any cluster." - break - fi - if [[ $kube_pod_name != $MY_POD_NAME ]]; then - discoveryHostname="${kube_pod_name}.${VERNEMQ_KUBERNETES_SUBDOMAIN}.${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}.svc.${DOCKER_VERNEMQ_KUBERNETES_CLUSTER_NAME}" - start_join_cluster=1 - echo "Will join an existing Kubernetes cluster with discovery node at ${discoveryHostname}" - echo "-eval \"vmq_server_cmd:node_join('VerneMQ@${discoveryHostname}')\"" >> ${VERNEMQ_VM_ARGS_FILE} - echo "Did I previously leave the cluster? If so, purging old state." - curl -fsSL http://${discoveryHostname}:8888/status.json >/dev/null 2>&1 || - (echo "Can't download status.json, better to exit now" && exit 1) - curl -fsSL http://${discoveryHostname}:8888/status.json | grep -q ${VERNEMQ_KUBERNETES_HOSTNAME} || - (echo "Cluster doesn't know about me, this means I've left previously. Purging old state..." && rm -rf /vernemq/data/*) - break - fi - done -fi - -if [ -f "${VERNEMQ_CONF_LOCAL_FILE}" ]; then - cp "${VERNEMQ_CONF_LOCAL_FILE}" ${VERNEMQ_CONF_FILE} - sed -i -r "s/###IPADDRESS###/${IP_ADDRESS}/" ${VERNEMQ_CONF_FILE} -else - sed -i '/########## Start ##########/,/########## End ##########/d' ${VERNEMQ_CONF_FILE} - - echo "########## Start ##########" >> ${VERNEMQ_CONF_FILE} - - env | grep DOCKER_VERNEMQ | grep -v 'DISCOVERY_NODE\|KUBERNETES\|SWARM\|COMPOSE\|DOCKER_VERNEMQ_USER' | cut -c 16- | awk '{match($0,/^[A-Z0-9_]*/)}{print tolower(substr($0,RSTART,RLENGTH)) substr($0,RLENGTH+1)}' | sed 's/__/./g' >> ${VERNEMQ_CONF_FILE} - - users_are_set=$(env | grep DOCKER_VERNEMQ_USER) - if [ ! -z "$users_are_set" ]; then - echo "vmq_passwd.password_file = /vernemq/etc/vmq.passwd" >> ${VERNEMQ_CONF_FILE} - touch /vernemq/etc/vmq.passwd - fi - - for vernemq_user in $(env | grep DOCKER_VERNEMQ_USER); do - username=$(echo $vernemq_user | awk -F '=' '{ print $1 }' | sed 's/DOCKER_VERNEMQ_USER_//g' | tr '[:upper:]' '[:lower:]') - password=$(echo $vernemq_user | awk -F '=' '{ print $2 }') - /vernemq/bin/vmq-passwd /vernemq/etc/vmq.passwd $username <> ${VERNEMQ_CONF_FILE} - fi - - if [ -z "$DOCKER_VERNEMQ_ERLANG__DISTRIBUTION__PORT_RANGE__MAXIMUM" ]; then - echo "erlang.distribution.port_range.maximum = 9109" >> ${VERNEMQ_CONF_FILE} - fi - - if [ -z "$DOCKER_VERNEMQ_LISTENER__TCP__DEFAULT" ]; then - echo "listener.tcp.default = ${IP_ADDRESS}:1883" >> ${VERNEMQ_CONF_FILE} - fi - - if [ -z "$DOCKER_VERNEMQ_LISTENER__WS__DEFAULT" ]; then - echo "listener.ws.default = ${IP_ADDRESS}:8080" >> ${VERNEMQ_CONF_FILE} - fi - - if [ -z "$DOCKER_VERNEMQ_LISTENER__VMQ__CLUSTERING" ]; then - echo "listener.vmq.clustering = ${IP_ADDRESS}:44053" >> ${VERNEMQ_CONF_FILE} - fi - - if [ -z "$DOCKER_VERNEMQ_LISTENER__HTTP__METRICS" ]; then - echo "listener.http.metrics = ${IP_ADDRESS}:8888" >> ${VERNEMQ_CONF_FILE} - fi - - echo "########## End ##########" >> ${VERNEMQ_CONF_FILE} -fi - -if [ ! -z "$DOCKER_VERNEMQ_ERLANG__MAX_PORTS" ]; then - sed -i.bak -r "s/\+Q.+/\+Q ${DOCKER_VERNEMQ_ERLANG__MAX_PORTS}/" ${VERNEMQ_VM_ARGS_FILE} -fi - -if [ ! -z "$DOCKER_VERNEMQ_ERLANG__PROCESS_LIMIT" ]; then - sed -i.bak -r "s/\+P.+/\+P ${DOCKER_VERNEMQ_ERLANG__PROCESS_LIMIT}/" ${VERNEMQ_VM_ARGS_FILE} -fi - -if [ ! -z "$DOCKER_VERNEMQ_ERLANG__MAX_ETS_TABLES" ]; then - sed -i.bak -r "s/\+e.+/\+e ${DOCKER_VERNEMQ_ERLANG__MAX_ETS_TABLES}/" ${VERNEMQ_VM_ARGS_FILE} -fi - -if [ ! -z "$DOCKER_VERNEMQ_ERLANG__DISTRIBUTION_BUFFER_SIZE" ]; then - sed -i.bak -r "s/\+zdbbl.+/\+zdbbl ${DOCKER_VERNEMQ_ERLANG__DISTRIBUTION_BUFFER_SIZE}/" ${VERNEMQ_VM_ARGS_FILE} -fi - -# Check configuration file -/vernemq/bin/vernemq config generate 2>&1 > /dev/null | tee /tmp/config.out | grep error - -if [ $? -ne 1 ]; then - echo "configuration error, exit" - echo "$(cat /tmp/config.out)" - exit $? -fi - -pid=0 - -# SIGUSR1-handler -siguser1_handler() { - echo "stopped" -} - -# SIGTERM-handler -sigterm_handler() { - if [ $pid -ne 0 ]; then - if [ -d "${SECRETS_KUBERNETES_DIR}" ] ; then - # this will stop the VerneMQ process, but first drain the node from all existing client sessions (-k) - if [ -n "$VERNEMQ_KUBERNETES_HOSTNAME" ]; then - terminating_node_name=VerneMQ@$VERNEMQ_KUBERNETES_HOSTNAME - else - terminating_node_name=VerneMQ@$IP_ADDRESS - fi - podList=$(k8sCurlGet "api/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/pods?labelSelector=${DOCKER_VERNEMQ_KUBERNETES_LABEL_SELECTOR}") - kube_pod_names=$(echo ${podList} | jq '.items[].spec.hostname' | sed 's/"//g' | tr '\n' ' ' | sed 's/ *$//') - if [ "$kube_pod_names" = "$MY_POD_NAME" ]; then - echo "I'm the only pod remaining. Not performing leave and/or state purge." - /vernemq/bin/vmq-admin node stop >/dev/null - else - # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-pod-v1-core - podResponse=$(k8sCurlGet api/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/pods/$(hostname) ) - statefulSetName=$(echo ${podResponse} | jq -r '.metadata.ownerReferences[0].name') - - # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#-strong-read-operations-statefulset-v1-apps-strong- - statefulSetResponse=$(k8sCurlGet "apis/apps/v1/namespaces/${DOCKER_VERNEMQ_KUBERNETES_NAMESPACE}/statefulsets/${statefulSetName}" ) - - isCodeForbidden=$(echo ${statefulSetResponse} | jq '.code == 403') - if [[ ${isCodeForbidden} == "true" ]]; then - echo "Permission error: Cannot access URL ${statefulSetPath}: $(echo ${statefulSetResponse} | jq '.reason,.code,.message')" - fi - - reschedule=$(echo ${statefulSetResponse} | jq '.status.replicas == .status.readyReplicas') - scaled_down=$(echo ${statefulSetResponse} | jq '.status.currentReplicas == .status.updatedReplicas') - - if [[ $reschedule == "true" ]]; then - # Perhaps is an scale down? - if [[ $scaled_down == "true" ]]; then - echo "Seems that this is a scale down scenario. Leaving cluster." - /vernemq/bin/vmq-admin cluster leave node=${terminating_node_name} -k && rm -rf /vernemq/data/* - else - echo "Reschedule is true. Not leaving the cluster." - /vernemq/bin/vmq-admin node stop >/dev/null - fi - else - echo "Reschedule is false. Leaving the cluster." - /vernemq/bin/vmq-admin cluster leave node=${terminating_node_name} -k && rm -rf /vernemq/data/* - fi - fi - else - if [ -n "$DOCKER_VERNEMQ_SWARM" ]; then - terminating_node_name=VerneMQ@$(hostname -i) - # For Swarm we keep the old "cluster leave" approach for now - echo "Swarm node is leaving the cluster." - /vernemq/bin/vmq-admin cluster leave node=${terminating_node_name} -k && rm -rf /vernemq/data/* - else - # In non-k8s mode: Stop the vernemq node gracefully - /vernemq/bin/vmq-admin node stop >/dev/null - fi - fi - kill -s TERM ${pid} - WAITFOR_PID=${pid} - pid=0 - wait ${WAITFOR_PID} - fi - exit 143; # 128 + 15 -- SIGTERM -} - -if [ ! -s ${VERNEMQ_VM_ARGS_FILE} ]; then - echo "ls -l ${VERNEMQ_ETC_DIR}" - ls -l ${VERNEMQ_ETC_DIR} - echo "###" >&2 - echo "### Configuration file ${VERNEMQ_VM_ARGS_FILE} is empty! This will not work." >&2 - echo "### Exiting now." >&2 - echo "###" >&2 - exit 1 -fi - -# Setup OS signal handlers -trap 'siguser1_handler' SIGUSR1 -trap 'sigterm_handler' SIGTERM - -# Start VerneMQ -/vernemq/bin/vernemq console -noshell -noinput $@ & -pid=$! -if [ $start_join_cluster -eq 1 ]; then - mkdir -p /var/log/vernemq/log - join_cluster > /var/log/vernemq/log/join_cluster.log & -fi -if [ -n "$API_KEY" ]; then - sleep 10 && echo "Adding API_KEY..." && /vernemq/bin/vmq-admin api-key add key="${API_KEY:-DEFAULT}" - vmq-admin api-key show -fi -wait $pid diff --git a/docker/vernemq/files/vm.args b/docker/vernemq/files/vm.args deleted file mode 100644 index afb3c022b..000000000 --- a/docker/vernemq/files/vm.args +++ /dev/null @@ -1,15 +0,0 @@ -+P 512000 -+e 256000 --env ERL_CRASH_DUMP /erl_crash.dump --env ERL_FULLSWEEP_AFTER 0 -+Q 512000 -+A 64 --setcookie vmq --name VerneMQ@127.0.0.1 -+K true -+W w -+sbwt none -+sbwtdcpu none -+sbwtdio none --smp enable -+zdbbl 32768 diff --git a/go.mod b/go.mod index fa9d02b03..8880bc471 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/absmach/magistrala go 1.23.4 -toolchain go1.24.1 - require ( github.com/0x6flab/namegenerator v1.4.0 github.com/absmach/callhome v0.14.0 diff --git a/scripts/supermq.sh b/scripts/supermq.sh new file mode 100755 index 000000000..6382262f3 --- /dev/null +++ b/scripts/supermq.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +### +# Fetches the latest version of the docker files from the SuperMQ repository. +### + +set -e +set -o pipefail + +REPO_URL=https://github.com/absmach/supermq +TEMP_DIR="supermq" +DOCKER_DIR="docker" +DEST_DIR="../../docker/supermq-docker" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" || exit 1 + +if [ -n "$(git status --porcelain)" ]; then + echo "There are uncommitted changes. Please commit or stash them before running this script." + exit 1 +fi + +cleanup() { + rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + +git clone --depth 1 --filter=blob:none --sparse "$REPO_URL" +cd "$TEMP_DIR" +git sparse-checkout set "$DOCKER_DIR" + +if [ -d "$DEST_DIR" ]; then + rm -r "$DEST_DIR" +fi +mkdir -p "$DEST_DIR" +mv -f "$DOCKER_DIR"/{*,.*} "$DEST_DIR" +cd .. +rm -rf "$TEMP_DIR"