Server-only TLS with Alternative Client Authentication
This page is part of the
Public CA Client Authentication EKU Mitigation guide.
It describes how to configure Geode with TLS for transport
encryption while authenticating clients at the application layer — removing the
dependency on client certificates and the clientAuth EKU entirely.
Summary
When server-only TLS is configured:
- All network traffic is encrypted in both directions by TLS. Enabling TLS
on a Geode component (
ssl-enabled-components) causes the underlying JSSE socket/engine to encrypt all data for that component regardless of whether client certificates are required. - Client authentication uses application-layer mechanisms — username/password,
token-based auth, LDAP/AD, or other custom
SecurityManagerimplementations — rather than TLS handshake client certificates.
When to choose this option:
- Client certificates are operationally impractical to distribute or rotate.
- You already have or can build an application-layer authentication system.
- You want the simplest migration path: keep TLS encryption, remove client certs.
- You need a solution that works for both client/server and peer-to-peer (P2P) cache topologies.
Transport Encryption Clarification
A common question is whether disabling client certificate authentication (ssl-require-authentication=false)
reduces transport security. It does not.
Geode TLS is implemented at the socket/engine layer by JSSE. Once a TLS connection is established, all bytes exchanged over that connection are encrypted and authenticated by the negotiated cipher suite — in both the client-to-server and server-to-client directions. Client certificate authentication is a separate step in the TLS handshake that establishes the client's identity; it has no effect on the confidentiality or integrity of the channel.
Setting ssl-require-authentication=false disables mandatory client certificate
presentation during the handshake. The TLS session is still established and
data continues to flow over an encrypted channel.
Configuration
Enable TLS on Servers and Locators (Server-only TLS)
# Enable TLS for all components
ssl-enabled-components=all
# Server presents its certificate; client verifies it
ssl-keystore=/etc/geode/server-keystore.jks
ssl-keystore-password=<password>
ssl-keystore-type=JKS
# Do NOT require client certificates
ssl-require-authentication=false
# Optional but recommended: validate the server hostname from the client side
ssl-endpoint-identification-enabled=true
Note: ssl-require-authentication=false is the key change from a full mTLS
deployment. The server still presents its own certificate and all transport
remains TLS-encrypted.
For component-specific control (for example, requiring mTLS on cluster but
not on server), use the component-specific property variants:
cluster-ssl-require-authentication=true
server-ssl-require-authentication=false
Configure Application-layer Client Authentication
Geode supports pluggable authentication through:
AuthInitialize— a client-side interface whosegetCredentials()method injects credentials (as aPropertiesobject) into each connection attempt.SecurityManager— a server-side interface that receives the credentials and enforces authentication and authorization.
Username / password (simplest approach):
# Client-side: supply credentials using an AuthInitialize implementation
security-client-auth-init=org.apache.geode.security.templates.UserPasswordAuthInit.create
# Server-side: validate credentials with a SecurityManager implementation
security-manager=com.example.geode.security.MySecurityManager
A minimal SecurityManager implementation:
public class MySecurityManager implements SecurityManager {
@Override
public Object authenticate(Properties credentials) throws AuthenticationFailedException {
String user = credentials.getProperty(ResourceConstants.USER_NAME);
String pass = credentials.getProperty(ResourceConstants.PASSWORD);
// validate against your directory / token store
if (!isValid(user, pass)) {
throw new AuthenticationFailedException("Invalid credentials for user: " + user);
}
return user; // returned value becomes the principal
}
@Override
public boolean authorize(Object principal, ResourcePermission permission) {
return true; // add fine-grained authorization here
}
}
Token-based authentication (JWT / OAuth bearer tokens):
Implement AuthInitialize to supply a token string and a SecurityManager to
validate and decode that token:
// Client side
public class TokenAuthInit implements AuthInitialize {
public static AuthInitialize create() { return new TokenAuthInit(); }
@Override
public Properties getCredentials(Properties securityProps, DistributedMember server,
boolean isPeer) {
Properties creds = new Properties();
creds.setProperty("bearer-token", System.getenv("GEODE_BEARER_TOKEN"));
return creds;
}
}
LDAP / Active Directory:
Implement SecurityManager.authenticate() to verify the supplied credentials
against an LDAP server using the standard javax.naming.ldap API or JNDI.
Peer-to-Peer (P2P) Topology Support
This approach works for both client/server and peer-to-peer cache topologies. In P2P topologies, members authenticate with each other using the same application-layer authentication mechanism.
P2P Configuration:
ssl-enabled-components=all
ssl-keystore=/etc/geode/peer-keystore.jks
ssl-keystore-password=<password>
ssl-truststore=/etc/geode/peer-truststore.jks
ssl-truststore-password=<password>
# Disable certificate-based peer authentication
ssl-require-authentication=false
ssl-endpoint-identification-enabled=true
# Application-layer peer authentication
security-peer-auth-init=com.example.geode.security.PeerAuthInit.create
security-manager=com.example.geode.security.MySecurityManager
security-username=${PEER_USERNAME}
security-password=${PEER_PASSWORD}
Authorization Requirement:
Peers joining a P2P cluster must have CLUSTER:MANAGE permission. The
SecurityManager.authorize() method validates this during peer join:
@Override
public boolean authorize(Object principal, ResourcePermission permission) {
// Peer joining cluster must have CLUSTER:MANAGE
if (permission.getResource() == Resource.CLUSTER &&
permission.getOperation() == Operation.MANAGE) {
return hasClusterManagePermission(principal);
}
return authorizeDataOperation(principal, permission);
}
Client Driver Changes
When migrating from mTLS to server-only TLS + credential auth:
- Remove the client keystore (
ssl-keystore) configuration from client driver properties — clients no longer present a certificate. - Add credential injection via
security-client-auth-init(or the equivalent driver API for non-Java clients). - Clients still need a truststore (or rely on the system trust store) to verify the server certificate.
Minimal client configuration example (Java thin client):
# Keep truststore to verify the server cert
ssl-enabled-components=all
ssl-truststore=/etc/geode/client-truststore.jks
ssl-truststore-password=<password>
ssl-endpoint-identification-enabled=true
# No ssl-keystore needed for server-only TLS
# Credential injection
security-client-auth-init=org.apache.geode.security.templates.UserPasswordAuthInit.create
security-username=myuser
security-password=mypassword
Server Certificate Rotation
Server keystores can still be rotated without restart using
FileWatchingX509ExtendedKeyManager. Write the new server keystore atomically
(create temp file, write, rename) to the path configured in ssl-keystore, and
the file watcher reloads the KeyManager transparently.
Security Considerations
- Even without mutual certificate authentication, confidentiality and integrity
are preserved by TLS. However, transport-level client identity assurances
(binding a TLS session to a certificate) are not available. Enforce strong
application-layer authentication in your
SecurityManager. - Protect credential stores. Do not store plaintext passwords in configuration files; set passwords from environment variables in start scripts, or use a secrets management system.
- Consider short-lived session tokens, rate limiting on login endpoints, and
audit logging within your
SecurityManager. - If supported by your client driver, use per-connection or per-operation credentials rather than long-lived shared secrets.
Verification
Enable JSSE debug logging to confirm the cipher suite and handshake flow:
-Djavax.net.debug=ssl,handshake
When ssl-require-authentication=false, the handshake completes without requesting
or presenting client certificates.
Common issues:
| Symptom | Likely cause |
|---|---|
SSLHandshakeException: PKIX path building failed | Client truststore does not contain the server's CA |
AuthenticationFailedException | SecurityManager rejected credentials; check logs for detail |
SSLHandshakeException requesting a client cert | A component still has ssl-require-authentication=true; verify per-component settings |
Phased Migration Path
If you need to migrate a running cluster without downtime:
- Deploy a
SecurityManagerthat accepts both the old certificate principal (extracted from existing mTLS sessions) and the new username/password credentials. This allows both old (cert) and new (credential) clients to coexist. - Gradually roll client drivers to credential-based auth.
- Once all clients use credential auth, change
ssl-require-authentication=falseon servers and remove client keystore configuration from clients. - (Optional) Remove the old CA from server truststores once no cert-based clients remain.
References
- Configuring SSL — component SSL properties
- Authentication —
AuthInitializeandSecurityManagerconcepts - Public CA Client Authentication EKU Mitigations — overview and other mitigation options
SSLConfigandSSLConfigurationFactory:geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.javaSocketCreator:geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.javaFileWatchingX509ExtendedKeyManager:geode-core/src/main/java/org/apache/geode/internal/net/filewatch/FileWatchingX509ExtendedKeyManager.javaAuthInitializetest templates:geode-core/src/test/java/org/apache/geode/security/templates/UserPasswordAuthInit.java