让我们回顾一下 MySQL Debezium connector的连接器注册请求:
{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "debezium",
"database.password": "dbz",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory"
}
}
用户名和密码以纯字符串形式传递给 API。更糟糕的是,任何有权访问 Kafka Connect 集群及其 REST API 的人都可以发出 GET 请求来获取连接器的配置,包括数据库凭据:
curl -s http://localhost:8083/connectors/inventory-connector | jq .
{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.user": "debezium",
"database.server.id": "184054",
"tasks.max": "1",
"database.hostname": "mysql",
"database.password": "dbz",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory",
"name": "inventory-connector",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.port": "3306"
},
"tasks": [
{
"connector": "inventory-connector",
"task": 0
}
],
"type": "source"
}
如果一个 Kafka Connect 集群由多个连接器/团队共享,那么出于安全原因,这种行为可能是不可取的。
外部化期望至少有一个 org.apache.kafka.common.config.provider.ConfigProvider 接口的实现类。
Kafka Connect 提供了从文件读取机密的参考实现 org.apache.kafka.common.config.provider.FileConfigProvider。可用的配置提供程序在 Kafka Connect 工作线程级别进行配置(例如在 connect-distributed.properties 中),并从连接器配置中引用。
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
连接器注册请求将像这样引用它:
{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "${file:/secrets/mysql.properties:user}",
"database.password": "${file:/secrets/mysql.properties:password}",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory"
}
这里,占位符 ${file:/secrets/mysql.properties:user} 表示应该使用文件配置提供程序,读取属性文件 /secrets/mysql.properties 并从中提取用户属性。
文件配置提供程序可能是最简单的实现,并且可以预期将会出现与密钥存储库或身份管理系统集成的其他提供程序。值得注意的是,文件配置提供程序在 Kubernetes/OpenShift 部署中是令人满意的,因为机密对象可以作为文件注入到集群 pod 中,从而被集群 pod 消耗。
我们创建了 Debezium 教程示例的一个版本,它演示了外部化机密的部署。请注意 Docker Compose 连接服务中的两个环境变量:
- CONNECT_CONFIG_PROVIDERS=file
- CONNECT_CONFIG_PROVIDERS_FILE_CLASS=org.apache.kafka.common.config.provider.FileConfigProvider
这些环境变量作为 debezium/connect 映像的功能直接映射到 Kafka Connect 工作线程属性中。
当您发出 REST 调用来获取连接器配置时,您将看到敏感信息已被外部化并且对未经授权的用户屏蔽:
curl -s http://localhost:8083/connectors/inventory-connector | jq .
{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.user": "${file:/secrets/mysql.properties:user}",
"database.server.id": "184054",
"tasks.max": "1",
"database.hostname": "mysql",
"database.password": "${file:/secrets/mysql.properties:password}",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory",
"name": "inventory-connector",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.port": "3306"
},
"tasks": [
{
"connector": "inventory-connector",
"task": 0
}
],
"type": "source"
}