diff --git a/.env b/.env index a4e0122..db5df26 100644 --- a/.env +++ b/.env @@ -6,7 +6,7 @@ MINIO_IMAGE=minio/minio:RELEASE.2024-01-11T07-46-16Z # MinIO server image versi PROMETHEUS_IMAGE=prom/prometheus:v2.51.2 # Prometheus monitoring system image version ALERTMANAGER_IMAGE=prom/alertmanager:v0.27.0 # Alertmanager for Prometheus image version GRAFANA_IMAGE=grafana/grafana:11.0.1 # Grafana visualization tool image version -ETCD_IMAGE=quay.io/coreos/etcd:v3.5.13 +ETCD_IMAGE=bitnami/etcd:3.5.13 OPENIM_WEB_FRONT_IMAGE=openim/openim-web-front:release-v3.8.3 OPENIM_ADMIN_FRONT_IMAGE=openim/openim-admin-front:release-v1.8.4 @@ -31,9 +31,13 @@ MONGO_PASSWORD=openIM123 # MongoDB password # Kafka configuration KAFKA_ADDRESS="kafka:9094" # Address of Kafka server +KAFKA_USERNAME= # Kafka username +KAFKA_PASSWORD= # Kafka password # Etcd configuration ETCD_ADDRESS="etcd:2379" +ETCD_USERNAME= # Etcd username +ETCD_PASSWORD= # Etcd password # Redis configuration REDIS_ADDRESS="redis:6379" # Address of Redis server diff --git a/docker-compose.yaml b/docker-compose.yaml index 4017942..a5e400b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -58,7 +58,15 @@ services: restart: always sysctls: net.core.somaxconn: 1024 - command: [ "redis-server", "/usr/local/redis/config/redis.conf", "--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes" ] + command: + [ + "redis-server", + "/usr/local/redis/config/redis.conf", + "--requirepass", + "${REDIS_PASSWORD}", + "--appendonly", + "yes", + ] networks: - openim @@ -78,6 +86,83 @@ services: - ETCD_INITIAL_CLUSTER=s1=http://0.0.0.0:2380 - ETCD_INITIAL_CLUSTER_TOKEN=tkn - ETCD_INITIAL_CLUSTER_STATE=new + - ALLOW_NONE_AUTHENTICATION=no + + ## Optional: Enable etcd authentication by setting the following credentials + # - ETCD_ROOT_USER=root + # - ETCD_ROOT_PASSWORD=openIM123 + # - ETCD_USERNAME=openIM + # - ETCD_PASSWORD=openIM123 + volumes: + - "${DATA_DIR}/components/etcd:/etcd-data" + command: > + /bin/sh -c ' + etcd & + export ETCDCTL_API=3 + echo "Waiting for etcd to become healthy..." + until etcdctl --endpoints=http://127.0.0.1:2379 endpoint health &>/dev/null; do + echo "Waiting for ETCD to start..." + sleep 1 + done + + echo "etcd is healthy." + + if [ -n "$${ETCD_ROOT_USER}" ] && [ -n "$${ETCD_ROOT_PASSWORD}" ] && [ -n "$${ETCD_USERNAME}" ] && [ -n "$${ETCD_PASSWORD}" ]; then + echo "Authentication credentials provided. Setting up authentication..." + + echo "Checking authentication status..." + if ! etcdctl --endpoints=http://127.0.0.1:2379 auth status | grep -q "Authentication Status: true"; then + echo "Authentication is disabled. Creating users and enabling..." + + # Create users and setup permissions + etcdctl --endpoints=http://127.0.0.1:2379 user add $${ETCD_ROOT_USER} --new-user-password=$${ETCD_ROOT_PASSWORD} || true + etcdctl --endpoints=http://127.0.0.1:2379 user add $${ETCD_USERNAME} --new-user-password=$${ETCD_PASSWORD} || true + + etcdctl --endpoints=http://127.0.0.1:2379 role add openim-role || true + etcdctl --endpoints=http://127.0.0.1:2379 role grant-permission openim-role --prefix=true readwrite / || true + etcdctl --endpoints=http://127.0.0.1:2379 role grant-permission openim-role --prefix=true readwrite "" || true + etcdctl --endpoints=http://127.0.0.1:2379 user grant-role $${ETCD_USERNAME} openim-role || true + + etcdctl --endpoints=http://127.0.0.1:2379 user grant-role $${ETCD_ROOT_USER} $${ETCD_USERNAME} root || true + + echo "Enabling authentication..." + etcdctl --endpoints=http://127.0.0.1:2379 auth enable + echo "Authentication enabled successfully" + else + echo "Authentication is already enabled. Checking OpenIM user..." + + # Check if openIM user exists and can perform operations + if ! etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_USERNAME}:$${ETCD_PASSWORD} put /test/auth "auth-check" &>/dev/null; then + echo "OpenIM user test failed. Recreating user with root credentials..." + + # Try to create/update the openIM user using root credentials + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_ROOT_USER}:$${ETCD_ROOT_PASSWORD} user add $${ETCD_USERNAME} --new-user-password=$${ETCD_PASSWORD} --no-password-file || true + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_ROOT_USER}:$${ETCD_ROOT_PASSWORD} role add openim-role || true + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_ROOT_USER}:$${ETCD_ROOT_PASSWORD} role grant-permission openim-role --prefix=true readwrite / || true + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_ROOT_USER}:$${ETCD_ROOT_PASSWORD} role grant-permission openim-role --prefix=true readwrite "" || true + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_ROOT_USER}:$${ETCD_ROOT_PASSWORD} user grant-role $${ETCD_USERNAME} openim-role || true + etcdctl --endpoints=http://127.0.0.1:2379 user grant-role $${ETCD_ROOT_USER} $${ETCD_USERNAME} root || true + + echo "OpenIM user recreated with required permissions" + else + echo "OpenIM user exists and has correct permissions" + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_USERNAME}:$${ETCD_PASSWORD} del /test/auth &>/dev/null + fi + fi + echo "Testing authentication with OpenIM user..." + if etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_USERNAME}:$${ETCD_PASSWORD} put /test/auth "auth-works"; then + echo "Authentication working properly" + etcdctl --endpoints=http://127.0.0.1:2379 --user=$${ETCD_USERNAME}:$${ETCD_PASSWORD} del /test/auth + else + echo "WARNING: Authentication test failed" + fi + else + echo "No authentication credentials provided. Running in no-auth mode." + echo "To enable authentication, set ETCD_ROOT_USER, ETCD_ROOT_PASSWORD, ETCD_USERNAME, and ETCD_PASSWORD environment variables." + fi + + tail -f /dev/null + ' restart: always networks: - openim @@ -94,12 +179,38 @@ services: KAFKA_CFG_NODE_ID: 0 KAFKA_CFG_PROCESS_ROLES: controller,broker KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093 - KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://kafka:9094 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_NUM_PARTITIONS: 8 KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: "true" + + KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094" + KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092,EXTERNAL://localhost:19094" + KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT" + KAFKA_CFG_INTER_BROKER_LISTENER_NAME: "PLAINTEXT" + + # Authentication configuration variables - comment out to disable auth + # KAFKA_USERNAME: "openIM" + # KAFKA_PASSWORD: "openIM123" + command: > + /bin/sh -c ' + if [ -n "$${KAFKA_USERNAME}" ] && [ -n "$${KAFKA_PASSWORD}" ]; then + echo "=== Kafka SASL Authentication ENABLED ===" + echo "Username: $${KAFKA_USERNAME}" + + # Set environment variables for SASL authentication + export KAFKA_CFG_LISTENERS="SASL_PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094" + export KAFKA_CFG_ADVERTISED_LISTENERS="SASL_PLAINTEXT://kafka:9092,EXTERNAL://localhost:19094" + export KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP="CONTROLLER:PLAINTEXT,EXTERNAL:SASL_PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT" + export KAFKA_CFG_SASL_ENABLED_MECHANISMS="PLAIN" + export KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL="PLAIN" + export KAFKA_CFG_INTER_BROKER_LISTENER_NAME="SASL_PLAINTEXT" + export KAFKA_CLIENT_USERS="$${KAFKA_USERNAME}" + export KAFKA_CLIENT_PASSWORDS="$${KAFKA_PASSWORD}" + fi + + # Start Kafka with the configured environment + exec /opt/bitnami/scripts/kafka/entrypoint.sh /opt/bitnami/scripts/kafka/run.sh + ' networks: - openim @@ -151,9 +262,9 @@ services: - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml - ${DATA_DIR}/components/prometheus/data:/prometheus command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.listen-address=:${PROMETHEUS_PORT}' + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" + - "--web.listen-address=:${PROMETHEUS_PORT}" network_mode: host alertmanager: @@ -166,8 +277,8 @@ services: - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml - ./config/email.tmpl:/etc/alertmanager/email.tmpl command: - - '--config.file=/etc/alertmanager/alertmanager.yml' - - '--web.listen-address=:${ALERTMANAGER_PORT}' + - "--config.file=/etc/alertmanager/alertmanager.yml" + - "--web.listen-address=:${ALERTMANAGER_PORT}" network_mode: host grafana: @@ -199,10 +310,10 @@ services: - /sys:/host/sys:ro - /:/rootfs:ro command: - - '--path.procfs=/host/proc' - - '--path.sysfs=/host/sys' - - '--path.rootfs=/rootfs' - - '--web.listen-address=:${NODE_EXPORTER_PORT}' + - "--path.procfs=/host/proc" + - "--path.sysfs=/host/sys" + - "--path.rootfs=/rootfs" + - "--web.listen-address=:${NODE_EXPORTER_PORT}" network_mode: host openim-server: @@ -213,7 +324,7 @@ services: - "${OPENIM_MSG_GATEWAY_PORT}:10001" - "${OPENIM_API_PORT}:10002" healthcheck: - test: [ "CMD", "sh", "-c", "mage check" ] + test: ["CMD", "sh", "-c", "mage check"] interval: 5s timeout: 60s retries: 10 @@ -222,9 +333,13 @@ services: - IMENV_MONGODB_USERNAME=${MONGO_USERNAME} - IMENV_MONGODB_PASSWORD=${MONGO_PASSWORD} - IMENV_KAFKA_ADDRESS=${KAFKA_ADDRESS} + - IMENV_KAFKA_USERNAME=${KAFKA_USERNAME} + - IMENV_KAFKA_PASSWORD=${KAFKA_PASSWORD} - IMENV_DISCOVERY_ETCD_ADDRESS=${ETCD_ADDRESS} - IMENV_REDIS_ADDRESS=${REDIS_ADDRESS} - IMENV_REDIS_PASSWORD=${REDIS_PASSWORD} + - IMENV_DISCOVERY_ETCD_USERNAME=${ETCD_USERNAME} + - IMENV_DISCOVERY_ETCD_PASSWORD=${ETCD_PASSWORD} - IMENV_MINIO_INTERNALADDRESS=${MINIO_INTERNAL_ADDRESS} - IMENV_MINIO_EXTERNALADDRESS=${MINIO_EXTERNAL_ADDRESS} - IMENV_MINIO_ACCESSKEYID=${MINIO_ACCESS_KEY_ID} @@ -248,7 +363,7 @@ services: container_name: openim-chat init: true healthcheck: - test: [ "CMD", "sh", "-c", "mage check" ] + test: ["CMD", "sh", "-c", "mage check"] interval: 5s timeout: 60s retries: 10 @@ -260,6 +375,8 @@ services: - CHATENV_REDIS_ADDRESS=${REDIS_ADDRESS} - CHATENV_REDIS_PASSWORD=${REDIS_PASSWORD} - CHATENV_SHARE_OPENIM_SECRET=${OPENIM_SECRET} + - CHATENV_DISCOVERY_ETCD_USERNAME=${ETCD_USERNAME} + - CHATENV_DISCOVERY_ETCD_PASSWORD=${ETCD_PASSWORD} - CHATENV_SHARE_OPENIM_APIURL=${API_URL} - CHATENV_LOG_ISSTDOUT=${LOG_IS_STDOUT} - CHATENV_LOG_REMAINLOGLEVEL=${LOG_LEVEL}