MG-67 - Update Magistrala Compose with SuperMQ Compose (#76)

* chore: update compose with supermq override

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: remove duplicate env variables

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* ci(check-license.yaml): ignore rabbitmq files

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor: add supermq docker file

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* feat: add update option to make file

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor(supermq-docker-compose.override.yml): fix errors in files

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor: add amend commit to fetch and update commands

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: add supermq dependency update script

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: update SuperMQ dependency files

* fix: remove reverted changes to Makefile

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor(supermq.sh): remove git staging and commit from script

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: remove redundant docker config files

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: remove redundant files, update compose p[roject directory

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: update project dir path

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: update nginv env file variable, remove redundant nginx config files

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore: include journal and certs to mg compose

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor: update script to use sparse checkout and move docker files into ./docker/supermq-docker

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor: update docker compose file

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* feat(Makefile): add fetch_supermq to run recipe

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* refactor(supermq.sh): clean up

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* chore(go.mod): remove toolchain definition

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* ci(build.yml): add check for supermq dependency

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

* ci: move check to ci

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>

---------

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
Felix Gateru
2025-03-19 14:37:51 +03:00
committed by GitHub
parent 1b772d3bbe
commit be6d8deef7
68 changed files with 5517 additions and 2192 deletions
+1 -1
View File
@@ -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
+13 -3
View File
@@ -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:
+4 -1
View File
@@ -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
+5 -353
View File
@@ -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
-123
View File
@@ -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 <project_root>/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
+11 -1275
View File
File diff suppressed because it is too large Load Diff
@@ -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;
+151
View File
@@ -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
+492
View File
@@ -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
+24
View File
@@ -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"]
+8
View File
@@ -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"]
+134
View File
@@ -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/<path>/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.
@@ -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 <project_root>/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
@@ -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 <project_root>/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
@@ -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 <project_root>/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
@@ -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
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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
@@ -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_value>
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_value>
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 <command> [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`.
@@ -0,0 +1,10 @@
storage "file" {
path = "/vault/file"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
}
ui = true
@@ -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 <project_root>/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
@@ -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
@@ -0,0 +1,5 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
data
supermq_clients_certs_issue.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"]
}
@@ -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
}
@@ -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
@@ -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
@@ -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
+46
View File
@@ -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")
+251
View File
@@ -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
+46
View File
@@ -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}
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
snippets/mqtt-upstream.conf
snippets/mqtt-ws-upstream.conf
+28
View File
@@ -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;"
+157
View File
@@ -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;
+178
View File
@@ -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;
@@ -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;
@@ -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;
@@ -0,0 +1 @@
[rabbitmq_management,rabbitmq_mqtt,rabbitmq_web_mqtt].
@@ -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
+7
View File
@@ -0,0 +1,7 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
*grpc-server*
*grpc-client*
*srl
*conf
+170
View File
@@ -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 = <CLIENTS_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 = <<SERVICE_NAME>>
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 <<SERVICE_NAME>>,$(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 <<SERVICE_NAME>>,$(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 <<SERVICE_NAME>>,$(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 <<SERVICE_NAME>>,$(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
@@ -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();
}
}
}
+23
View File
@@ -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-----
+28
View File
@@ -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-----
@@ -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-----
@@ -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-----
+8
View File
@@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAquN8NRcSdLOM9RiumqWH8Jw3CGVR/eQQeq+jvT3zpxlUQPAMExQb
MRCspm1oRgDWGvch3Z4zfMmBZyzKJA4BDTh4USzcE5zvnx8aUcUPZPQpwSicKgzb
QGnl0Xf/75GAWrwhxn8GNyMP29wrpcd1Qg8fEQ3HAW1fCd9girKMKY9aBaHli/h2
R9Rd/KTbeqN88aoMjUvZHooIIZXu0A+kyulOajYQO4k3Sp6CBqv0FFcoLQnYNH13
kMUE5qJ68U732HybTw8sofTCOxKcCfM2kVP7dVoF3prlGjUw3z3l3STY8vuTdq0B
R7PslkoQHNmqcL+2gouoWP3GI+IeRzGSSwIBAg==
-----END DH PARAMETERS-----
-56
View File
@@ -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"]
-352
View File
@@ -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 <<EOF
$password
$password
EOF
done
if [ -z "$DOCKER_VERNEMQ_ERLANG__DISTRIBUTION__PORT_RANGE__MINIMUM" ]; then
echo "erlang.distribution.port_range.minimum = 9100" >> ${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
-15
View File
@@ -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
-2
View File
@@ -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
+40
View File
@@ -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"