diff --git a/geode-book/master_middleman/source/subnavs/geode-subnav.erb b/geode-book/master_middleman/source/subnavs/geode-subnav.erb index f06a8914d46..e6afa6bb957 100644 --- a/geode-book/master_middleman/source/subnavs/geode-subnav.erb +++ b/geode-book/master_middleman/source/subnavs/geode-subnav.erb @@ -157,6 +157,20 @@ limitations under the License.
  • SSL Sample Implementation
  • +
  • + Mitigating Public CA Client Auth EKU Changes + +
  • diff --git a/geode-docs/security/public_ca_client_auth_eku_mitigations.html.md.erb b/geode-docs/security/public_ca_client_auth_eku_mitigations.html.md.erb new file mode 100644 index 00000000000..0831bfb6515 --- /dev/null +++ b/geode-docs/security/public_ca_client_auth_eku_mitigations.html.md.erb @@ -0,0 +1,147 @@ +--- +title: Mitigating Public CA Client Authentication EKU Changes +--- + + + +Public Certificate Authorities (CAs) are removing or restricting issuance +of the Client Authentication Extended Key Usage (EKU) from publicly-issued +leaf certificates. Deployments that relied on public-CA-signed client +certificates for mutual TLS (mTLS) client authentication must migrate to an +alternative approach. + +**This guide does not apply to you if:** + +- Your deployment already uses an enterprise or internal CA for mTLS, **or** +- Your deployment uses a public CA chain that includes client CA certificates + and those certificates are unaffected by the EKU policy change. + +**This guide applies to you if:** + +- Your deployment used public-CA-issued client certificates for mTLS, **and** +- Those certificates no longer contain the `clientAuth` EKU, or the CA will + no longer issue them. + +## Background + +<%=vars.product_name%> uses JSSE (`SSLContext`, `SSLEngine`, `SSLSocket`, +`TrustManager`, `KeyManager`) for all TLS connections. Per-component SSL +configuration is resolved via `SSLConfig` and `SSLConfigurationFactory`. +Keystores and truststores are watched at runtime by `FileWatchingX509ExtendedKeyManager` +and `FileWatchingX509ExtendedTrustManager`, backed by `PollingFileWatcher`, +which reloads credential material when files change on disk without a server +restart. + +When a Java TLS peer presents a certificate in a role that requires client +authentication, the JSSE stack checks that the certificate's Extended Key Usage +extension contains `id-kp-clientAuth` (OID 1.3.6.1.5.5.7.3.2). If that OID is +absent, the TLS handshake fails with an authentication error. Because public CAs +are ceasing to include this OID in publicly-issued leaf certificates, +public-CA-signed client certificates can no longer be used for mTLS. + +## Choosing a Mitigation + +Select the option that best fits your operational environment: + +| Scenario | Recommended option | +|---|---| +| You can operate or integrate with an enterprise PKI | [Internal / Enterprise CA for mTLS](ssl_internal_ca_mtls.html) | +| Client certificates are impractical; you prefer credential-based auth | [Server-only TLS + alternative client authentication](ssl_server_only_tls_alt_auth.html) | +| Servers must use a public-CA certificate (external trust) but clients need a controllable identity | [Hybrid: public-CA server certificates + private-CA client certificates](ssl_hybrid_public_server_private_client.html) | + +You may combine approaches: for example, running the hybrid model in production +while temporarily using server-only TLS + credentials during a phased migration. + +## Key <%=vars.product_name%> Features Used by All Mitigations + +- **Per-component SSL configuration** — `ssl-enabled-components` and associated + `ssl-keystore` / `ssl-truststore` properties allow independent TLS settings for + `cluster`, `server`, `locator`, `gateway`, `jmx`, and `web` components. See + [Configuring SSL](implementing_ssl.html). +- **`ssl-require-authentication`** — controls whether servers require client + certificates during the TLS handshake. Set to `true` for mTLS; `false` for + server-only TLS. +- **File-watching keystore reload** — `FileWatchingX509ExtendedKeyManager` and + `FileWatchingX509ExtendedTrustManager` automatically reload keystore and + truststore files when they are atomically replaced on disk. Configure by + pointing `ssl-keystore` / `ssl-truststore` at the watched path. +- **Pluggable authentication** — `AuthInitialize` (client-side credential + injection) and `SecurityManager` (server-side enforcement) support + username/password, token, and custom authentication without requiring client + certificates. + +## Migration Checklist + +1. **Inventory** — Identify all clients, members, and locators that present a + public-CA-signed client certificate during TLS handshake. +2. **Choose a mitigation** — Use the decision table above to select an approach + (or a phased combination). +3. **Provision credentials** — Issue replacement certificates from an internal/ + private CA, or configure application-layer authentication. +4. **Update truststores** — Update server truststores to include the new CA(s) + before rotating client credentials to avoid handshake failures during the + rollout. +5. **Deploy and verify** — Roll out the new configuration component by component. + Use `openssl s_client` and JSSE debug logging (`-Djavax.net.debug=ssl,handshake`) + to verify handshake behavior at each step. +6. **Remove old credentials** — Once all clients have migrated, remove the + public-CA trust anchor from server truststores if it is no longer needed. + +## Quick Verification + +Test that the server certificate chain and (if applicable) client certificate +chain are seen and accepted: + +```bash +# Server-only TLS verification (no client certificate required) +openssl s_client -connect geode-server.example.com:10334 -showcerts + +# mTLS verification (present client cert and key) +openssl s_client -connect geode-server.example.com:10334 \ + -cert client.crt -key client.key \ + -CAfile server-trust-anchor.pem -showcerts +``` + +Enable JSSE debug on client JVMs for detailed handshake tracing: + +```bash +java -Djavax.net.debug=ssl,handshake -jar my-geode-client.jar +``` + +## Mitigation Guides + +- **[Internal / Enterprise CA for mTLS](ssl_internal_ca_mtls.html)** + + Run an internal or enterprise CA (offline root + issuing intermediate, or + enterprise PKI automation such as HashiCorp Vault or Smallstep) to issue + client certificates. The internal CA is the trust anchor for client + authentication; public CA EKU policies are irrelevant. + +- **[Server-only TLS + Alternative Client Authentication](ssl_server_only_tls_alt_auth.html)** + + Retain TLS encryption for all connections but disable mandatory client + certificate authentication. Authenticate clients at the application layer + using <%=vars.product_name%>'s existing `AuthInitialize` / `SecurityManager` + framework (username/password, tokens, or a custom implementation). + +- **[Hybrid: Public-CA Server Certs + Private-CA Client Certs](ssl_hybrid_public_server_private_client.html)** + + Keep server certificates signed by a public CA (preserving external trust) + while issuing client certificates from an internal/private CA. Server + truststores include the private CA; client truststores use the public CA + (or the system trust store) for server certificate validation. diff --git a/geode-docs/security/ssl_hybrid_public_server_private_client.html.md.erb b/geode-docs/security/ssl_hybrid_public_server_private_client.html.md.erb new file mode 100644 index 00000000000..621a01a67c8 --- /dev/null +++ b/geode-docs/security/ssl_hybrid_public_server_private_client.html.md.erb @@ -0,0 +1,331 @@ +--- +title: Hybrid TLS — Public-CA Server Certs with Private-CA Client Certs +--- + + + +This page is part of the +[Public CA Client Authentication EKU Mitigation guide](public_ca_client_auth_eku_mitigations.html). +It describes a hybrid model in which <%=vars.product_name%> server certificates +are issued by a public CA (preserving external trust) while client certificates +are issued by an internal or private CA (preserving control over `clientAuth` EKU +and certificate lifecycle). + +## Summary + +**For Client/Server Topology:** + +| Certificate role | Issued by | +|---|---| +| Server certificate (servers / locators present to clients) | Public CA | +| Peer-to-peer certificates (servers / locators authenticate to each other) | Public CA | +| Client certificate (clients present to servers) | Internal / private CA | + +**For Peer-to-Peer (P2P) Topology:** + +| Certificate role | Issued by | +|---|---| +| Peer certificate (peers authenticate to each other) | Public CA | +| Client certificate (clients present to peers, if applicable) | Internal / private CA | + +**Why this model:** + +- Servers and peers are reachable from the public internet or from clients that + trust public CAs — keeping server/peer certificates public-CA-issued avoids distributing + a custom root to all clients. +- Servers and peers use public-CA-issued certificates to authenticate to each other + during cluster formation and peer-to-peer communication. +- Clients are controlled endpoints (application services, internal consumers) — + issuing their certificates from an internal CA provides full control over the + `clientAuth` EKU, certificate lifetime, and revocation. +- Public CA EKU policy changes for client certificates are irrelevant because + client certificates never come from the public CA. + +**When to choose this option:** + +- Your server endpoints are externally visible and must be trusted by external + clients using the public trust store. +- You can operate or integrate with an internal CA for client certificate + issuance. +- You want to retain full mTLS (mutual certificate authentication) rather than + switching to application-layer credential auth. + +## Architecture + +**For Client/Server Topology:** + +``` + Public CA trust chain + (server certificate) + Client ──────────────────────────────▶ Server + ◀────────────────────────────── Server + validates server certificate via + public CA / system trust store + + Private CA trust chain + (client cert) + Client ──────────────────────────────▶ Server + validates client certificate via + server truststore containing + private CA certificate + +``` + +**For Peer-to-Peer Topology:** + +``` + Public CA trust chain + (peer-to-peer) + Peer ◀──────────────────────────────▶ Peer + Each peer uses public-CA-issued certificate + to authenticate to other peers; + validation via public CA in peer truststore + + Private CA trust chain + (client-to-peer, if accepting clients) + Client ──────────────────────────────▶ Peer + validates client certificate via + peer truststore containing + private CA certificate +``` + +**Key trust relationships:** + +- **Server keystore** — contains the public-CA-issued server leaf certificate and + its private key (and intermediate chain). +- **Server truststore** — contains **both** the public CA (for validating other + servers/locators in peer-to-peer communication) **and** the private/internal CA + certificate(s) (for validating client certificates during the mTLS handshake). +- **Peer keystore** (P2P topology) — contains the public-CA-issued peer certificate + and its private key (for peer-to-peer authentication). +- **Peer truststore** (P2P topology) — contains **both** the public CA (for validating + other peers) **and** the private CA (for validating client certificates if the peer + accepts client connections). +- **Client keystore** — contains the private-CA-issued client leaf certificate + and its private key. +- **Client truststore** — contains the public CA root (or relies on the JVM + system trust store) to validate the server certificate. + +## Prerequisites + +- A server certificate chain issued by a public CA, valid for the server's + hostnames (DNS SANs). Obtain this from your public CA provider. +- An internal/private CA capable of issuing client leaf certificates with the + `clientAuth` EKU. Options include HashiCorp Vault PKI, Smallstep `step-ca`, + Active Directory Certificate Services, or a self-managed OpenSSL CA. +- Secure tooling to distribute keystores and truststores to servers and clients. + +## Step-by-Step Configuration + +### Step 1 — Prepare the server keystore (public CA) + +Obtain a server certificate from a public CA for your <%=vars.product_name%> server +hostnames. **Ensure the server certificate includes the `serverAuth` Extended Key +Usage and a `subjectAltName` (SAN) field with the server's DNS names** for hostname +verification. Convert the certificate and private key into a Java keystore (PKCS12 +or JKS format). See [SSL Sample Implementation](ssl_example.html) for keystore +preparation details. + +### Step 2 — Prepare the server truststore (both CAs) + +Import **both** CA certificates into the server truststore: + +1. Import your internal/private CA certificate(s) so servers can validate client + certificates issued by your internal CA. +2. Import the public CA certificate(s) so servers can validate other servers and + locators during peer-to-peer cluster communication. + +If your <%=vars.product_name%> cluster uses SSL for peer-to-peer communication +(e.g., `ssl-enabled-components=all` or includes `cluster`/`locator` components), +servers must trust the public CA that issued other members' certificates. + +### Step 3 — Issue client certificates from the internal CA + +Use your internal PKI to issue client certificates. **Ensure the client certificates +include the `clientAuth` Extended Key Usage** (required for client authentication +in mTLS). Without this EKU, the server will reject the client certificate with a +`certificate_unknown` TLS alert. Create a client keystore containing the client +private key and certificate chain. + +### Step 4 — Prepare the client truststore (public CA for server validation) + +Clients must be able to validate the server's public-CA-issued certificate. +In most cases the JVM system trust store already contains public CA roots and +no additional configuration is needed. If you need to use a custom truststore, +import the public CA root certificate(s). + +### Step 5 — Configure <%=vars.product_name%> server / locator + +``` pre +ssl-enabled-components=all + +# Server keystore: public-CA-issued server certificate +ssl-keystore=/etc/geode/server-keystore.jks +ssl-keystore-password= +ssl-keystore-type=JKS + +# Server truststore: BOTH public CA (for peer-to-peer) and private CA (for clients) +ssl-truststore=/etc/geode/server-truststore.jks +ssl-truststore-password= +ssl-truststore-type=JKS + +# Require client certificates in the TLS handshake +ssl-require-authentication=true + +# Validate server hostname from the client side +ssl-endpoint-identification-enabled=true +``` + +### Step 6 — Configure <%=vars.product_name%> client + +``` pre +ssl-enabled-components=all + +# Client keystore: private-CA-issued client certificate +ssl-keystore=/etc/geode/client-keystore.jks +ssl-keystore-password= +ssl-keystore-type=JKS + +# Client truststore: public CA root (validates server certificate) +# If using system trust store, ssl-use-default-context=true may be sufficient +ssl-truststore=/etc/geode/client-truststore.jks +ssl-truststore-password= +ssl-truststore-type=JKS + +# Require server certificate authentication +ssl-require-authentication=true + +ssl-endpoint-identification-enabled=true +``` + +## P2P Topology Configuration + +In a peer-to-peer (P2P) topology, all members are peers with equal standing. +Each peer acts as both a server (for other peers and clients) and a client (when +connecting to other peers). This requires careful certificate and trust store +configuration. + +**Key P2P requirements:** + +- Each peer presents a **public-CA-issued certificate** for peer-to-peer authentication + (so peers can authenticate each other using the public CA trust chain). +- Each peer's truststore must contain **both** CAs: + - The **public CA** (to validate certificates from other peers during cluster + formation and ongoing peer-to-peer communication). + - The **private CA** (to validate client certificates if the peer also accepts + client connections). + +**Example P2P member configuration:** + +``` pre +ssl-enabled-components=all + +# Peer keystore: public-CA-issued certificate (for peer-to-peer auth) +ssl-keystore=/etc/geode/peer-keystore.jks +ssl-keystore-password= +ssl-keystore-type=JKS + +# Peer truststore: BOTH public CA (other peers) and private CA (clients) +ssl-truststore=/etc/geode/peer-truststore.jks +ssl-truststore-password= +ssl-truststore-type=JKS + +ssl-require-authentication=true +ssl-endpoint-identification-enabled=true +``` + +**Client configuration for P2P clusters:** + +If clients connect to the P2P cluster, their configuration remains the same as +in the client/server topology described above (private-CA-issued client keystore, +public-CA truststore for server validation). + +## Certificate Rotation and Hot-Reload + +<%=vars.product_name%>'s `FileWatchingX509ExtendedKeyManager` and +`FileWatchingX509ExtendedTrustManager` monitor the configured keystore and +truststore paths and reload them when files change on disk — no restart required. + +**Rotation workflow:** + +| What rotates | Procedure | +|---|---| +| Server certificate (public CA renewal) | Write new `server-keystore.jks` atomically; `FileWatchingX509ExtendedKeyManager` reloads it | +| Client certificate (private CA rotation) | Automation writes new `client.p12` / JKS atomically; `FileWatchingX509ExtendedKeyManager` reloads it | +| Private CA rollover | Import new private CA certificate into `server-truststore.jks` before client certificates rotate; do a rolling truststore push or atomic file replacement | +| Public CA root renewal | Update `client-truststore.jks` on all clients and `server-truststore.jks` on all servers/locators (or rely on JVM trust store update) | + +Write files atomically — create a temp file, write it fully, then `rename()` it +into the watched path so the watcher reads a complete file. + +## Verification and Troubleshooting + +**Enable JSSE debug logging** to diagnose SSL/TLS handshake issues: + +``` +-Djavax.net.debug=ssl,handshake +``` + +**Common issues:** + +| Symptom | Likely cause | +|---|---| +| Server handshake fails: `PKIX path building failed` | Server truststore does not include the private CA that signed the client certificate | +| Client handshake fails: `PKIX path building failed` | Client truststore does not include the public CA that signed the server certificate | +| Peer-to-peer handshake fails: `PKIX path building failed` | Server/locator/peer truststore missing public CA needed to validate other cluster members | +| `certificate_unknown` TLS alert from server | Client certificate is missing the `clientAuth` EKU, or is not trusted — verify private CA import into server truststore and EKU presence | +| `certificate_unknown` TLS alert during P2P handshake | Peer certificate is missing the `serverAuth` EKU, or the peer's public CA is not trusted — verify public CA import into peer truststore and EKU presence | +| `No subject alternative names` | Server or peer certificate does not include a DNS SAN matching the hostname used by the connecting party | + +## Security Considerations + +- The hybrid model splits trust roots: public CA governs server identity; + private CA governs client identity. Compromise of one does not directly + compromise the other. +- Protect the private CA private key carefully. Prefer an offline root + online + issuing intermediate topology. Consider a Hardware Security Module (HSM) for the issuing intermediate. +- Keep client certificate lifetimes short (days to weeks) and automate renewal. +- **Verify certificate Extended Key Usage (EKU) requirements:** + * Server certificates **must** include the `serverAuth` EKU. + * Client certificates **must** include the `clientAuth` EKU. + * Peer certificates (P2P topology) **must** include the `serverAuth` EKU for + peer-to-peer authentication. + * Java JSSE enforces EKU checking by default and will reject certificates + without the appropriate EKU with a `certificate_unknown` alert. +- **Peer-to-peer authentication considerations:** + * In client/server topology, servers and locators use public-CA-issued + certificates to authenticate to each other during cluster formation and + peer-to-peer communication. The server truststore must contain both the + public CA (for peer validation) and the private CA (for client validation). + * In P2P topology, all peers use public-CA-issued certificates to + authenticate to each other. Each peer's truststore must contain both the + public CA (for peer validation) and the private CA (for client validation + if the peer accepts client connections). + +## References + +- [Configuring SSL](implementing_ssl.html) — complete property reference +- [Internal / Enterprise CA for mTLS](ssl_internal_ca_mtls.html) — detailed + internal-CA set-up guidance +- [Public CA Client Authentication EKU Mitigations](public_ca_client_auth_eku_mitigations.html) — overview and other mitigation options +- `SSLConfig` and `SSLConfigurationFactory`: + `geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java` +- `FileWatchingX509ExtendedKeyManager`: + `geode-core/src/main/java/org/apache/geode/internal/net/filewatch/FileWatchingX509ExtendedKeyManager.java` +- `SocketCreator`: + `geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java` diff --git a/geode-docs/security/ssl_internal_ca_mtls.html.md.erb b/geode-docs/security/ssl_internal_ca_mtls.html.md.erb new file mode 100644 index 00000000000..89be9d6f7ec --- /dev/null +++ b/geode-docs/security/ssl_internal_ca_mtls.html.md.erb @@ -0,0 +1,216 @@ +--- +title: Internal / Enterprise CA for mTLS +--- + + + +This page is part of the +[Public CA Client Authentication EKU Mitigation guide](public_ca_client_auth_eku_mitigations.html). +It describes how to use an internal or enterprise Certificate Authority (CA) to +issue client certificates so that <%=vars.product_name%> mutual TLS (mTLS) continues +to work after public CAs cease including the `clientAuth` EKU in publicly-issued +leaf certificates. + +## Summary + +Operate an internal or enterprise CA to issue client certificates (and optionally +server certificates) for <%=vars.product_name%> mTLS. This removes dependency on +public CA EKU policies, centralizes client identity issuance, and enables +fine-grained lifecycle control (rotation, short-lived certificates, automated +enrollment). + +**When to choose this option:** + +- You can operate or integrate with an internal PKI (self-managed CA, HashiCorp + Vault PKI, Smallstep, Active Directory Certificate Services, or similar). +- You want strong, certificate-based mutual authentication between clients and + servers with full lifecycle control. + +## Recommended CA Topology + +- **Offline root CA** — kept air-gapped or in cold storage; used only to sign + intermediate CA certificates. +- **Online issuing intermediate CA** — used to sign leaf certificates for servers + and clients. In the event the intermediate is compromised, only it (not the + root) needs to be rotated. +- Use separate issuing CAs per environment (production, staging, development) to + prevent cross-environment trust leakage. +- Enforce short certificate lifetimes for client leaf certificates (recommended: + 1–30 days) to minimise the impact of compromise and to avoid CRL/OCSP + complexity. Short-lived certificates with automation provide: + * Reduced compromise windows (compromised certificates expire quickly) + * Elimination of manual coordination for renewals + * Zero-downtime operations via <%=vars.product_name%>'s file-watching + credential managers + * Consistent security posture through automated enforcement of required + EKUs and extensions + +## Certificate Issuance + +Use your internal PKI tools (OpenSSL, HashiCorp Vault, Active Directory Certificate +Services, etc.) to issue certificates with your internal CA. Client certificates +**must include the `clientAuth` Extended Key Usage** to function with <%=vars.product_name%> +mTLS. + +**Key requirements:** + +- **Client certificates:** Must have `extendedKeyUsage=clientAuth` +- **Server certificates:** Must have `extendedKeyUsage=serverAuth` and must include + `subjectAltName` with DNS names or IP addresses for hostname verification + (when `ssl-endpoint-identification-enabled=true`) +- **Certificate chain:** Ensure leaf certificates are signed by a CA that is + trusted by the peer's truststore + +## Keystore and Truststore Preparation + +Prepare Java keystores (PKCS12 or JKS format) containing: + +- **Keystore:** Private key and certificate chain (for the component's identity) +- **Truststore:** CA certificates used to validate peer certificates + +<%=vars.product_name%> supports PKCS12 (recommended) and JKS keystore formats. +For detailed instructions on creating and managing keystores, see +[SSL Sample Implementation](ssl_example.html). + +**Key points:** + +- **Server truststores:** Import your internal CA certificate(s) to validate client + certificates +- **Client truststores:** Import CA certificate(s) to validate server certificates +- **Password protection:** Use environment variables, secure vaults, or file-based + configuration with restricted permissions + +## <%=vars.product_name%> Configuration + +**Server / locator (requires client certs from the internal CA):** + +``` pre +ssl-enabled-components=all +ssl-keystore=/etc/geode/server-keystore.jks +ssl-keystore-password= +ssl-keystore-type=JKS +ssl-truststore=/etc/geode/server-truststore.jks +ssl-truststore-password= +ssl-truststore-type=JKS +ssl-require-authentication=true +ssl-endpoint-identification-enabled=true +``` + +**Client (presents an internal-CA-issued client cert):** + +``` pre +ssl-enabled-components=all +ssl-keystore=/etc/geode/client-keystore.jks +ssl-keystore-password= +ssl-keystore-type=JKS +ssl-truststore=/etc/geode/client-truststore.jks +ssl-truststore-password= +ssl-truststore-type=JKS +ssl-require-authentication=true +ssl-endpoint-identification-enabled=true +``` + +The client truststore must contain the trust anchor used to verify the server's +certificate (the public CA root if the server used a public-CA cert, or the +internal root if the server cert was also issued by the internal CA). + +For component-specific keystores (different certs per role), use +`server-ssl-keystore`, `locator-ssl-keystore`, etc. + +## Rotation and Hot-Reload + +<%=vars.product_name%> ships `FileWatchingX509ExtendedKeyManager` and +`FileWatchingX509ExtendedTrustManager`, backed by `PollingFileWatcher`, which +monitor keystore and truststore files on disk and reload them when they change — +no server restart required. + +**Best practices for rotation tooling:** + +- Write new keystore/truststore files atomically: create a temporary file, write + it, then `rename()` it into the watched path so the file watcher sees a clean + update. +- Use short certificate lifetimes and automate renewal before expiry. Automation + tools such as HashiCorp Vault agent, Smallstep's `step-ca`, or custom ACME + clients can write renewed keystores atomically to the watched path. +- When rotating the issuing CA, stage the new CA cert in server truststores before + rotating client certificates to avoid handshake failures during the overlap + window. + +## Enrollment Automation + +If you operate an existing enterprise PKI automation platform, integrate it +rather than building a bespoke CA: + +- **HashiCorp Vault PKI**: Vault agent authenticates (using AppRole, Kubernetes + auth, or a token) and writes short-lived client certs atomically to + `/var/geode/`. `FileWatchingX509ExtendedKeyManager` picks up the rotation. +- **Smallstep (`step-ca` / `step` CLI)**: Use `step ca certificate` to enroll and + renew client certificates; integrate with `step-sds` or a custom renewer that + writes PKCS12/JKS files atomically. +- **ACME automation**: If your internal CA supports ACME, use an ACME client + (e.g., Certbot with a custom hook) to issue and renew client credentials. + +The key integration pattern in all cases: +1. Automation authenticates to the CA. +2. CA issues a short-lived client cert. +3. Automation writes the keystore atomically to the watched path. +4. `FileWatchingX509ExtendedKeyManager` reloads the credential without restart. + +## Revocation Strategy + +- **Short-lived certificates (recommended):** Use 1–30 day lifetimes with + automated renewal. Because certificates expire soon, CRL/OCSP infrastructure + is not required. +- **CRL or OCSP (longer-lived certs):** If longer certificate lifetimes are + required, publish a CRL distribution point or OCSP responder as part of your + internal CA, and configure the JVM trust policy accordingly. + +## Verification and Troubleshooting + +**Enable JSSE debug logging** to diagnose SSL/TLS handshake issues: + +``` +-Djavax.net.debug=ssl,handshake +``` + +**Common issues:** + +| Symptom | Likely cause | +|---|---| +| `PKIX path building failed` | Truststore does not include the CA that signed the peer's certificate | +| `certificate_unknown` alert | Client certificate lacks the required `clientAuth` Extended Key Usage, or server certificate lacks `serverAuth` EKU | +| `no available certificate` | Keystore path/password incorrect or file permissions restrict access | +| Handshake fails after rotation | New keystore file was not written atomically; file watcher may have read a partial file | +| `No subject alternative names` | Server certificate does not include a DNS SAN matching the hostname used by the client | + +Check <%=vars.product_name%> logs for messages from `FileWatchingX509ExtendedKeyManager` +(initialization and reload events) and for `SSLHandshakeException` details. + +## References + +- [Configuring SSL](implementing_ssl.html) — general SSL configuration for + <%=vars.product_name%> +- [SSL Sample Implementation](ssl_example.html) — example keystore/truststore + setup in <%=vars.product_name%> +- [Public CA Client Authentication EKU Mitigations](public_ca_client_auth_eku_mitigations.html) — overview and other mitigation options +- `FileWatchingX509ExtendedKeyManager`: + `geode-core/src/main/java/org/apache/geode/internal/net/filewatch/FileWatchingX509ExtendedKeyManager.java` +- `SSLConfig` and `SSLConfigurationFactory`: + `geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java` +- `SocketCreator`: + `geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java` diff --git a/geode-docs/security/ssl_overview.html.md.erb b/geode-docs/security/ssl_overview.html.md.erb index 7fa30463bf1..5ad9539548a 100644 --- a/geode-docs/security/ssl_overview.html.md.erb +++ b/geode-docs/security/ssl_overview.html.md.erb @@ -43,3 +43,13 @@ The SSL implementation ensures that only the applications identified by you can A simple example demonstrates the configuration and startup of <%=vars.product_name%> system components with SSL. +- **[Mitigating Public CA Client Authentication EKU Changes](public_ca_client_auth_eku_mitigations.html)** + + Provides guidance for deployments affected by public Certificate Authorities removing or restricting the Client Authentication EKU from publicly-issued certificates. Covers three mitigation strategies: + + - **[Internal / Enterprise CA for mTLS](ssl_internal_ca_mtls.html)** — Operate an internal or enterprise CA to issue client certificates. Removes reliance on public CA EKU policies entirely. + + - **[Server-only TLS with Alternative Client Authentication](ssl_server_only_tls_alt_auth.html)** — Retain TLS transport encryption and authenticate clients at the application layer using <%=vars.product_name%>'s `AuthInitialize` and `SecurityManager` framework instead of client certificates. + + - **[Hybrid: Public-CA Server Certs with Private-CA Client Certs](ssl_hybrid_public_server_private_client.html)** — Keep server certificates from a public CA while issuing client certificates from an internal CA, preserving external trust for server endpoints while maintaining control over client identity. + diff --git a/geode-docs/security/ssl_server_only_tls_alt_auth.html.md.erb b/geode-docs/security/ssl_server_only_tls_alt_auth.html.md.erb new file mode 100644 index 00000000000..886e1051a20 --- /dev/null +++ b/geode-docs/security/ssl_server_only_tls_alt_auth.html.md.erb @@ -0,0 +1,301 @@ +--- +title: Server-only TLS with Alternative Client Authentication +--- + + + +This page is part of the +[Public CA Client Authentication EKU Mitigation guide](public_ca_client_auth_eku_mitigations.html). +It describes how to configure <%=vars.product_name%> 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 <%=vars.product_name%> 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 `SecurityManager` implementations — + 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. + +<%=vars.product_name%> 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) + +``` pre +# 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= +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: + +``` pre +cluster-ssl-require-authentication=true +server-ssl-require-authentication=false +``` + +### Configure Application-layer Client Authentication + +<%=vars.product_name%> supports pluggable authentication through: + +- **`AuthInitialize`** — a client-side interface whose `getCredentials()` method + injects credentials (as a `Properties` object) into each connection attempt. +- **`SecurityManager`** — a server-side interface that receives the credentials + and enforces authentication and authorization. + +**Username / password (simplest approach):** + +``` pre +# 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: + +```java +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: + +```java +// 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:** + +``` pre +ssl-enabled-components=all +ssl-keystore=/etc/geode/peer-keystore.jks +ssl-keystore-password= +ssl-truststore=/etc/geode/peer-truststore.jks +ssl-truststore-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: + +```java +@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: + +1. **Remove** the client keystore (`ssl-keystore`) configuration from client + driver properties — clients no longer present a certificate. +2. **Add** credential injection via `security-client-auth-init` (or the + equivalent driver API for non-Java clients). +3. Clients still need a truststore (or rely on the system trust store) to verify + the server certificate. + +Minimal client configuration example (Java thin client): + +``` pre +# Keep truststore to verify the server cert +ssl-enabled-components=all +ssl-truststore=/etc/geode/client-truststore.jks +ssl-truststore-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: + +1. Deploy a `SecurityManager` that 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. +2. Gradually roll client drivers to credential-based auth. +3. Once all clients use credential auth, change `ssl-require-authentication=false` + on servers and remove client keystore configuration from clients. +4. (Optional) Remove the old CA from server truststores once no cert-based + clients remain. + +## References + +- [Configuring SSL](implementing_ssl.html) — component SSL properties +- [Authentication](authentication_overview.html) — `AuthInitialize` and + `SecurityManager` concepts +- [Public CA Client Authentication EKU Mitigations](public_ca_client_auth_eku_mitigations.html) — overview and other mitigation options +- `SSLConfig` and `SSLConfigurationFactory`: + `geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java` +- `SocketCreator`: + `geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java` +- `FileWatchingX509ExtendedKeyManager`: + `geode-core/src/main/java/org/apache/geode/internal/net/filewatch/FileWatchingX509ExtendedKeyManager.java` +- `AuthInitialize` test templates: + `geode-core/src/test/java/org/apache/geode/security/templates/UserPasswordAuthInit.java`