Java 如何使用密钥库检查SSL Kafka主题的授权
我使用Java 如何使用密钥库检查SSL Kafka主题的授权,java,ssl,apache-kafka,Java,Ssl,Apache Kafka,我使用keystore.jks文件生成了一个简单的SSL卡夫卡主题 Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("acks", "all"); props.put("retries", 0); props.put("batch.size&q
keystore.jks
文件生成了一个简单的SSL卡夫卡主题
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("security.protocol", "SSL");
props.put("ssl.key.password", "password");
props.put("ssl.keystore.password", "password");
props.put("ssl.keystore.location", "/keystore.jks");
Producer<String, String> producer = new KafkaProducer<>(props);
producer.send(new ProducerRecord<String, String>("my-topic", key, body));
尽管您没有为Kafka服务器配置必要的属性:
ssl.truststore.location=/var/private/ssl/client.truststore.jks
ssl.truststore.password=test1234
可能您的SSL设置很好,但正如您所指出的,存在与客户端授权相关的一些问题:
org.apache.kafka.common.errors.TopicAuthorizationException:无权访问主题:[我的主题]
请考虑查看,特别是描述您的客户端SSL证书的<代码> CN>代码>中的用户名是如何导出的:
默认情况下,SSL用户名的格式为“CN=writeuser,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown”。可以通过在server.properties中将ssl.principal.mapping.rules设置为自定义规则来改变这一点。此配置允许将X.500可分辨名称映射为短名称的规则列表
一旦识别出用户,请检查是否为其应用了必要的ACL,并检查主题my topic
。请参阅文档中提供的
例如,要将上述用户添加为主题my topic
的制作人,请尝试以下类似操作:
bin/kafka-acls.sh--授权者属性zookeeper.connect=localhost:2181--添加--允许主要用户:writeuser--生产者--主题我的主题
您可以在您的用例中验证应用于资源的ACL,my topic
,如下所示:
bin/kafka-acls.sh--授权人属性zookeeper.connect=localhost:2181--列表--主题我的主题
经过长时间的研究,在@jccampanero提供的帮助下,我创建了一块java代码来列出用于特定主题的ACL
AdminClient adminClient = KafkaAdminClient.create(configProps);
ResourcePatternFilter resourceFilter = new ResourcePatternFilter(ResourceType.TOPIC,"my-topic", PatternType.ANY);
AclBindingFilter aclBindingFilter = new AclBindingFilter(resourceFilter, AccessControlEntryFilter.ANY);
DescribeAclsResult describe = adminClient.describeAcls(aclBindingFilter);
KafkaFuture<Collection<AclBinding>> values = describe.values();
Collection<AclBinding> aclBindings = values.get();
aclBindings.forEach(acl->{
System.out.println(String.format("%s %s %s",acl.entry().operation().name(),acl.entry().principal(),acl.entry().permissionType().name()));
});
现在,您可以从AclBinding
中提取CN
部分,然后将其用作alias
从JSK文件中获取证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] pwdArray = "password".toCharArray();
keyStore.load(new FileInputStream("/keystore.jks"), pwdArray);
Certificate certificate = keyStore.getCertificate(alias); //alias = test-cert.com
if (certificate instanceof X509Certificate) {
X509Certificate x509cert = (X509Certificate) certificate;
// Get subject
Principal principal = x509cert.getSubjectDN();
String subjectDn = principal.getName();
System.out.println(principal); //test-cert.com
}
感谢命令行的回答,但是我正在寻找Java代码来在连接到Kafka主题You are welcome@Deadpool之前进行验证。老实说,我以前没有使用过Kafka Java API的管理相关代码。我正在查看API和相关文档,并试图完成我的回答,以便提供基于Java的解决方案,当我意识到您的评论时,您实际上提供了一个新的答案。你完全正确,这是正确的解决方案。无论如何,请考虑一下这个问题。见下一篇评论和。在我的研究中,我当时遇到了一些问题,我认为它们可能会有所帮助。但老实说,你的回答帮助我找到了解决问题的途径@jccampaneroThank非常感谢你将我的答案标记为正确@Deadpool,我真的很感激!!。请不要犹豫与我联系,如果你认为我能提供任何帮助,我将很高兴尝试帮助你。非常感谢。
DESCRIBE User:CN=test-cert.com,O=Corporation,OU=1234567,L=Newyork,ST=NY,C=US ALLOW
WRITE User:CN=CN=test-cert.com,O=Corporation,OU=1234567,L=Newyork,ST=NY,C=US ALLOW
READ User:CN=test-cert.com,O=Corporation,OU=1234567,L=Newyork,ST=NY,C=US ALLOW
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] pwdArray = "password".toCharArray();
keyStore.load(new FileInputStream("/keystore.jks"), pwdArray);
Certificate certificate = keyStore.getCertificate(alias); //alias = test-cert.com
if (certificate instanceof X509Certificate) {
X509Certificate x509cert = (X509Certificate) certificate;
// Get subject
Principal principal = x509cert.getSubjectDN();
String subjectDn = principal.getName();
System.out.println(principal); //test-cert.com
}