**# 引言
在现代数据架构中,Kafka 作为一种高性能的消息队列系统,已被广泛应用于处理实时数据流。在企业级部署中,保证数据传输的安全性以及服务的稳定性变得尤为重要。本文将详细介绍如何在 Docker 环境下部署 Kafka 服务,并使用 Systemctl 进行管理,特别注重在部署过程中安全性的处理,包括密码的加密存储与日志的安全输出的完整流程

当前部署方式

当前环境使用docker docker-compose 部署raft模式的kafka三节点集群,某一个节点的docker-compose.yaml配置文件如下:


version: "3"
services:
  kafka:
    image: 'bitnami/kafka:3.7.0'
    network_mode: "host"
    ports:
      - '9092:9092'
      - '9093:9093'
      - '9999:9999'
    privileged: true
    environment:
      - KAFKA_CFG_NODE_ID=0
      - TZ=Asia/Shanghai
      - KAFKA_CFG_PROCESS_ROLES=controller,broker
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@192.168.0.10:9093,1@192.168.0.13:9093,2@192.168.0.11:9093
      - KAFKA_KRAFT_CLUSTER_ID=metabank
      - KAFKA_CFG_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.0.10:9092
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:SASL_PLAINTEXT,CONTROLLER:SASL_PLAINTEXT
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT
      - KAFKA_CLIENT_USERS=vuser
      - KAFKA_CLIENT_PASSWORDS=vuserpwd123
      - KAFKA_CFG_SASL_MECHANISM_CONTROLLER_PROTOCOL=PLAIN
      - KAFKA_CONTROLLER_USER=vuser
      - KAFKA_CONTROLLER_PASSWORD=vuserpwd123
      - KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL=PLAIN
      - KAFKA_INTER_BROKER_USER=vuser
      - KAFKA_INTER_BROKER_PASSWORD=vuserpwd123
      - KAFKA_CFG_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM=
      - KAFKA_CFG_SASL_ENABLED_MECHANISMS=PLAIN,SCRAM-SHA-512
      - KAFKA_TLS_TYPE=JKS
      - KAFKA_JMX_ENABLED=true 
      - KAFKA_JMX_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.rmi.port=9999 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
volumes:
      - ./kafka_data:/bitnami/kafka

系统服务使用systemctl 管理:

[Unit]
Description=kafka Service
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
User=apppub
Group=apppub
WorkingDirectory=/app/metabank/kafka
ExecStart=/usr/bin/docker-compose up -d
ExecStop=/usr/bin/docker-compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target

服务的启停管理使用systemctl start|stop|status 参数管理kafka服务

安全需求

最新需求密码不得以明文形式在任何配置文件或命令行中出现。
Kafka 的运行日志需要被安全地记录并存储。

解决方案设计

密码的加密存储和使用

考虑到安全性,我们将使用 OpenSSL 工具为 Kafka 的密码生成密钥,并进行 AES-256 加密,确保即使在配置文件被泄露的情况下,敏感信息也不会直接暴露。

生成和管理加密密钥

您应该生成一个强加密密钥,并将其存储在安全的位置。这个密钥将用于加密和解密 Kafka 配置中的密码。

mkdir /app/metabank/kafka/secrets/
openssl rand -hex 16 > /app/metabank/kafka/secrets/encryption_key
chmod 400 /app/metabank/kafka/secrets/encryption_key
chown apppub:apppub /app/metabank/kafka/secrets/encryption_key

密码加密脚本

创建一个脚本 encrypt_kafka_password.sh 来加密 Kafka 的密码:

#!/bin/bash

ENCRYPTION_KEY=$(cat /app/metabank/kafka/secrets/encryption_key)

encrypt_password() {
    local password=$1
    echo -n "$password" | openssl enc -aes-256-cbc -base64 -pbkdf2 -salt -k "$ENCRYPTION_KEY" 2>/dev/null
}

echo "Enter Kafka client password:"
read -s password
ENCRYPTED_CLIENT_PASSWORD=$(encrypt_password "$password")
echo -e "\nEnter Kafka controller password:"
read -s password
ENCRYPTED_CONTROLLER_PASSWORD=$(encrypt_password "$password")
echo -e "\nEnter Kafka broker password:"
read -s password
ENCRYPTED_BROKER_PASSWORD=$(encrypt_password "$password")

# 将加密后的密码写入环境变量文件
cat > /app/metabank/kafka/secrets/kafka_passwords.env << EOF
ENCRYPTED_CLIENT_PASSWORD='${ENCRYPTED_CLIENT_PASSWORD}'
ENCRYPTED_CONTROLLER_PASSWORD='${ENCRYPTED_CONTROLLER_PASSWORD}'
ENCRYPTED_BROKER_PASSWORD='${ENCRYPTED_BROKER_PASSWORD}'
EOF

echo -e "\nPasswords have been encrypted and saved to kafka_passwords.env"

该脚本读取原始密码,利用预存的密钥进行加密,并输出加密后的密码。

密码解密脚本

#!/bin/bash

ENCRYPTION_KEY=$(cat /app/metabank/kafka/secrets/encryption_key)

decrypt_password() {
    local encrypted_password=$1
    # 移除可能的引号
    encrypted_password="${encrypted_password//\'/}"
    echo "$encrypted_password" | openssl enc -aes-256-cbc -base64 -pbkdf2 -salt -d -k "$ENCRYPTION_KEY" 2>/dev/null
}

# 从环境变量文件读取加密密码
if [ -f "/app/metabank/kafka/secrets/kafka_passwords.env" ]; then
    # 使用 source 命令加载环境变量
    source /app/metabank/kafka/secrets/kafka_passwords.env
    
    # 解密并导出密码
    export KAFKA_CLIENT_PASSWORDS=$(decrypt_password "$ENCRYPTED_CLIENT_PASSWORD")
    export KAFKA_CONTROLLER_PASSWORD=$(decrypt_password "$ENCRYPTED_CONTROLLER_PASSWORD")
    export KAFKA_INTER_BROKER_PASSWORD=$(decrypt_password "$ENCRYPTED_BROKER_PASSWORD")
    
    # 验证解密是否成功(可选)
    if [ -n "$KAFKA_CLIENT_PASSWORDS" ] && [ -n "$KAFKA_CONTROLLER_PASSWORD" ] && [ -n "$KAFKA_INTER_BROKER_PASSWORD" ]; then
        echo "Passwords decrypted successfully"
    else
        echo "Error: Failed to decrypt one or more passwords"
        exit 1
    fi
else
    echo "Error: kafka_passwords.env file not found"
    exit 1
fi

启动脚本与安全日志处理

将 Kafka 的日志输出到特定目录,并确保这些日志文件的访问权限受到严格控制。

#!/bin/bash
# start-kafka.sh

source ./decrypt_kafka_passwords.sh
# 检查解密是否成功
if [ $? -ne 0 ]; then
    echo "Failed to decrypt passwords"
    exit 1
fi

exec /usr/bin/docker-compose up & 
sleep 5 
/usr/bin/docker-compose logs -f kafka >> /app/metabank/kafka/kafka_logs/kafka.log 2>&1

使用 Systemctl 管理 Kafka 服务

创建一个名为 kafka.service 的 Systemctl 单元文件,提供了 Kafka 服务的启动和停止命令,并能够让服务在系统启动时自动启动。

[Unit]
Description=kafka Service
Requires=docker.service
After=docker.service

[Service]
Type=simple
User=apppub
Group=apppub
WorkingDirectory=/app/metabank/kafka
ExecStart=/bin/bash /app/metabank/kafka/start-kafka-service.sh
ExecStop=/bin/bash -c '/usr/bin/docker-compose down'
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

其他日志切割与回收

由于我七天内的日志可能会查看,我启用了延迟压缩:

/app/metabank/kafka/kafka_logs/kafka.log {
    su apppub apppub
    daily
    rotate 30            # 增大rotate值以确保能保留足够的日志
    dateext
    dateformat -%Y%m%d
    delaycompress        # 延迟压缩
    maxage 7            # 7天后才压缩
    missingok
    notifempty
    create 0640 apppub apppub
    sharedscripts
}

注意:配置文件中不能添加注释,这里只做演示,配置文件记得自己去除配置!

使用如下命令测试日志切割:

touch -d "yesterday" /app/metabank/kafka/kafka_logs/*.log
logrotate -f /etc/logrotate.d/kafka

另外journalctl中这样日志的量级会比较大,还很烦人:

我需要处理一下:

修改了kafka.service

[Unit]
Description=kafka Service
Requires=docker.service
After=docker.service

[Service]
Type=simple
User=apppub
Group=apppub
WorkingDirectory=/app/metabank/kafka
ExecStart=/bin/bash /app/metabank/kafka/start-kafka-service.sh
ExecStop=/bin/bash -c '/usr/bin/docker-compose down'
Restart=always
RestartSec=10
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target

嗯查看了一下journalctl 总算没有那么多烦人的日志了

实施步骤

安装必要的软件:确保系统已安装 Docker、Docker Compose 和 OpenSSL。
配置 Kafka 的 Docker Compose:根据需求配置 Kafka,并注意在环境变量中使用加密密码。
创建并部署加密脚本:将 encrypt_kafka_password.sh 部署到服务器上,保证其执行权限并对密码进行加密。
配置 Systemctl 服务:部署 kafka.service 文件至 /etc/systemd/system/ 目录。
启动服务:使用 systemctl start kafka.service 启动服务。
验证:确保 Kafka 运行正常,加密脚本工作良好,且日志按预期记录。

其他可以完善的

总结

通过本教程,您可以实现一个安全、可靠的 Kafka 服务部署。通过加密关键配置和细心设计日志存储,显著提升整个系统的安全性。日常运维中,请注意定期检查和更新安全设置,修改密码,确保系统能防范新的安全威胁。

**


对你无可奈何
40 声望12 粉丝