Files
cs-note/hhs/MQ/11-安全与多租户/42-MQ-认证与授权.md
T
2026-05-24 20:51:06 +08:00

217 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags:
- MQ
- 安全
- 认证
- 授权
- Kafka
create time: 2026-05-24 19:52
---
# MQ 认证与授权
## 概述
MQ 作为数据流转的核心枢纽,安全防护至关重要。本文梳理 MQ 面临的安全威胁,对比 SASL/PLAIN、SASL/SCRAM、mTLS、OAuth2 四种认证机制,讲解 ACL 授权模型,并以 Kafka 为例展示完整的安全配置实践。
## 正文
### MQ 安全威胁分析
一个没有安全防护的 MQ 集群就像一栋没有门锁的大楼:
- **未授权访问**:任何人都能连接 Broker,读取或写入任意 Topic
- **消息篡改**:中间人攻击修改消息内容,下游消费者收到错误数据
- **消息窃听**:网络嗅探获取敏感消息(如用户订单、支付信息)
- **DoS 攻击**:恶意客户端大量发送消息耗尽 Broker 资源
> [!question]
> 如果你的 MQ 集群部署在内网,是否还需要认证授权?内网就一定安全吗?
### 认证机制对比
#### SASL/PLAIN
最简单的用户名密码认证。密码以明文传输(除非配合 TLS),适合开发测试环境。
- 优点:配置简单,无需额外基础设施
- 缺点:密码明文传输、不支持动态添加用户(需重启 Broker)
#### SASL/SCRAM
基于挑战-响应的认证协议,密码不在网络上传输。Kafka 支持 SCRAM-SHA-256 和 SCRAM-SHA-512。
- 优点:密码加密存储、支持动态添加用户、无需重启 Broker
- 缺点:性能比 mTLS 略低
#### mTLS(双向 TLS)
客户端和服务端互相验证证书。这是安全性最高的方案。
- 优点:双向认证、无需密码管理、证书可自动轮转
- 缺点:证书管理复杂(签发、分发、续期、吊销)
#### OAuth2/OIDC
基于令牌的认证,适合云原生和微服务场景。客户端通过 OAuth2 Server 获取 Token,携带 Token 连接 Broker。
- 优点:与企业身份系统集成、支持细粒度权限、令牌可过期
- 缺点:依赖外部 OAuth2 Server、配置复杂
### 认证授权流程
```mermaid
sequenceDiagram
participant Client as "Client App"
participant Broker as "Kafka Broker"
participant Authn as "Authentication Module"
participant Authz as "Authorization Module (ACL)"
Client->>Broker: "Connect with credentials"
Broker->>Authn: "Verify identity"
Authn-->>Broker: "Identity: user-service-order"
Client->>Broker: "Produce to order-topic"
Broker->>Authz: "Check ACL: can user-service-order WRITE order-topic?"
Authz-->>Broker: "ALLOW"
Broker-->>Client: "Produce success"
Client->>Broker: "Consume payment-topic"
Broker->>Authz: "Check ACL: can user-service-order READ payment-topic?"
Authz-->>Broker: "DENY"
Broker-->>Client: "Authorization failed"
```
### ACL 授权模型
ACL(Access Control List)提供 Topic 级别的细粒度权限控制。Kafka 的 ACL 由五元组定义:
- **Principal**:认证身份(如 `User:alice`)
- **Resource**:资源类型和名称(如 `Topic:order-events`)
- **Operation**:操作类型(Read/Write/Create/Delete/Describe)
- **Permission**:Allow/Deny
- **Host**:来源 IP(可选)
常见权限模式:
- 最小权限原则:每个服务只授予需要的 Topic 权限
- 生产者只有 Write 权限,消费者只有 Read 权限
- 管理操作(Create/Delete)只授予运维账号
### Kafka 完整安全配置
下面展示 SASL/SCRAM + ACL 的完整配置流程。
Broker 端配置(`server.properties`):
```properties
# 启用 SASL/SCRAM 认证
listeners=SASL_SSL://:9093
security.inter.broker.protocol=SASL_SSL
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
sasl.enabled.mechanisms=SCRAM-SHA-256
# 启用 ACL
authorizer.class.name=kafka.security.authorizer.AclAuthorizer
super.users=User:admin
allow.everyone.if.no.acl.found=false
```
```bash
# 创建用户
kafka-configs.sh --bootstrap-server localhost:9093 \
--alter --add-config 'SCRAM-SHA-256=[iterations=8192,password=secret]' \
--entity-type users --entity-name order-service
# 授权:允许 order-service 写 order-topic
kafka-acls.sh --bootstrap-server localhost:9093 \
--add --allow-principal User:order-service \
--producer --topic order-topic
# 授权:允许 payment-service 读 order-topic
kafka-acls.sh --bootstrap-server localhost:9093 \
--add --allow-principal User:payment-service \
--consumer --topic order-topic --group payment-group
```
### Go 代码:SASL/SCRAM 认证配置
```go
package main
import (
"crypto/sha256"
"crypto/sha512"
"hash"
"github.com/IBM/sarama"
"github.com/xdg-go/scram"
)
// SCRAM 客户端实现
type SCRAMClient struct {
*scram.Client
*scram.ClientConversation
hashGenerator func() hash.Hash
}
func (c *SCRAMClient) Begin(userName, password, authzID string) error {
client, err := c.hashGenerator().NewClient(userName, password, authzID)
if err != nil {
return err
}
c.Client = client
c.ClientConversation = client.NewConversation()
return nil
}
func (c *SCRAMClient) Step(challenge string) (string, error) {
return c.ClientConversation.Step(challenge)
}
func (c *SCRAMClient) Done() bool {
return c.ClientConversation.Done()
}
func main() {
config := sarama.NewConfig()
config.Net.SASL.Enable = true
config.Net.SASL.Mechanism = sarama.SASLTypeSCRAMSHA256
config.Net.SASL.User = "order-service"
config.Net.SASL.Password = "secret"
config.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient {
return &SCRAMClient{hashGenerator: sha256.New}
}
config.Net.TLS.Enable = true // SCRAM 通常配合 TLS 使用
producer, err := sarama.NewSyncProducer([]string{"localhost:9093"}, config)
if err != nil {
panic(err)
}
defer producer.Close()
// 发送消息,自动完成 SCRAM 认证握手
msg := &sarama.ProducerMessage{
Topic: "order-topic",
Value: sarama.StringEncoder(`{"order_id": "12345"}`),
}
partition, offset, _ := producer.SendMessage(msg)
_ = partition
_ = offset
}
```
这段代码实现了 SASL/SCRAM-SHA-256 认证的完整流程:客户端发送用户名,Broker 返回挑战(salt + iteration),客户端计算哈希响应,Broker 验证通过后建立连接。
### mTLS 的简化方案
> [!question]
> mTLS 安全性最高,但管理证书很麻烦。在微服务场景下如何简化证书管理?
几种主流方案:
- **Service Mesh(Istio)**:Sidecar 代理自动处理证书签发和轮转,应用层完全无感
- **cert-manager**:K8s 上的证书管理控制器,自动签发和续期
- **SPIFFE/SPIRE**:标准化的服务身份框架,跨平台证书管理
## 关联笔记
- [[43-MQ-加密与审计]]
- [[40-MQ-性能调优]]
- [[39-MQ-容器化与-K8s-部署]]