Skip to content

Commit a7f43de

Browse files
author
adamglt
authored
Merge pull request #1 from Traiana/subject-spiffe-duality
Support regular Subject handling fallback when no SPIFFE ID can be determined
2 parents 458cada + f1da6e2 commit a7f43de

File tree

2 files changed

+44
-7
lines changed

2 files changed

+44
-7
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Kafka SPIFFE Principal Builder
2+
3+
A custom `KafkaPrincipalBuilder` implementation for Apache Kafka.
4+
This class and documentation deals only with `SslAuthenticationContext`, we do not support any other context at the moment (Kerberos, SASL, Oauth)
5+
6+
#### Default behavior
7+
The default `DefaultKafkaPrincipalBuilder` class that comes with Apache Kafka builds a principal
8+
name according to the x509 Subject in the SSL certificate. Since there is no logic that deals with *Subject Alternative Name*,
9+
this approach cannot handle a *SPIFFE ID*.
10+
11+
#### New behavior
12+
The principal builder first looks for any valid *SPIFFE ID* in the certificate, if found, the *KafkaPrincipal* that will
13+
be returned would be seen by an *ACL Authorizer* as **SPIFFE:spiffe://some.spiffe.id.uri**. If that fails, a normal usage of the Subject will
14+
used with a normal **USER:CN=...**
15+

src/main/java/io/okro/kafka/SpiffePrincipalBuilder.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@
77
import java.security.cert.Certificate;
88
import java.security.cert.CertificateParsingException;
99
import java.security.cert.X509Certificate;
10+
import java.util.Collection;
11+
import java.util.List;
12+
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
1015

1116
import static org.apache.commons.lang3.StringUtils.startsWith;
1217

1318
public class SpiffePrincipalBuilder implements KafkaPrincipalBuilder {
19+
private static final Logger LOG = LoggerFactory.getLogger(SpiffePrincipalBuilder.class);
20+
21+
private static final String SPIFFE_TYPE = "SPIFFE";
22+
1423
public KafkaPrincipal build(AuthenticationContext context) {
1524
if (context instanceof PlaintextAuthenticationContext) {
1625
return KafkaPrincipal.ANONYMOUS;
@@ -30,14 +39,27 @@ public KafkaPrincipal build(AuthenticationContext context) {
3039
return KafkaPrincipal.ANONYMOUS;
3140
}
3241
X509Certificate cert = (X509Certificate) peerCerts[0];
33-
return cert.getSubjectAlternativeNames().stream()
34-
.map(san -> (String) san.get(1))
35-
.filter(uri -> startsWith(uri, "spiffe://"))
36-
.findFirst()
37-
.map(s -> new KafkaPrincipal(KafkaPrincipal.USER_TYPE, s))
38-
.orElse(KafkaPrincipal.ANONYMOUS);
42+
43+
Collection<List<?>> sanCollection = cert.getSubjectAlternativeNames();
44+
KafkaPrincipal principal;
45+
46+
if (sanCollection != null) {
47+
principal = sanCollection.stream()
48+
.map(san -> (String) san.get(1))
49+
.filter(uri -> startsWith(uri, "spiffe://"))
50+
.findFirst()
51+
.map(s -> new KafkaPrincipal(SPIFFE_TYPE, s))
52+
.orElse(new KafkaPrincipal(KafkaPrincipal.USER_TYPE, cert.getSubjectX500Principal().getName()));
53+
} else {
54+
principal = new KafkaPrincipal(KafkaPrincipal.USER_TYPE, cert.getSubjectX500Principal().getName());
55+
}
56+
57+
LOG.debug("PrincipalBuilder found principal: {}", principal.toString());
58+
59+
return principal;
3960
} catch (SSLPeerUnverifiedException | CertificateParsingException se) {
61+
LOG.warn("Unhandled exception: " + se.toString());
4062
return KafkaPrincipal.ANONYMOUS;
4163
}
4264
}
43-
}
65+
}

0 commit comments

Comments
 (0)