elastic/elasticsearch · error · SslConfigException

cannot specify [{}] without also setting [{}]

Error message

cannot specify [{}] without also setting [{}]

What it means

buildKeyConfig requires that PEM key material be specified as a pair: ssl.certificate AND ssl.key. Specifying only ssl.certificate means the public cert is present but the private key is missing, so the key manager cannot be built.

Source

Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java:389

        } else {
            return new CompositeTrustConfig(List.of(trustConfig, trust));
        }
    }

    public SslKeyConfig buildKeyConfig(Path basePath) {
        final String certificatePath = stringSetting(CERTIFICATE);
        final String keyPath = stringSetting(KEY);
        final String keyStorePath = stringSetting(KEYSTORE_PATH);

        if (certificatePath != null && keyStorePath != null) {
            throw new SslConfigException(
                "cannot specify both [" + settingPrefix + CERTIFICATE + "] and [" + settingPrefix + KEYSTORE_PATH + "]"
            );
        }

        if (certificatePath != null || keyPath != null) {
            if (keyPath == null) {
                throw new SslConfigException(
                    "cannot specify [" + settingPrefix + CERTIFICATE + "] without also setting [" + settingPrefix + KEY + "]"
                );
            }
            if (certificatePath == null) {
                throw new SslConfigException(
                    "cannot specify [" + settingPrefix + KEY + "] without also setting [" + settingPrefix + CERTIFICATE + "]"
                );
            }
            final char[] password = resolvePasswordSetting(KEY_SECURE_PASSPHRASE, KEY_LEGACY_PASSPHRASE);
            return new PemKeyConfig(certificatePath, keyPath, password, basePath);
        }

        if (keyStorePath != null) {
            final char[] storePassword = resolvePasswordSetting(KEYSTORE_SECURE_PASSWORD, KEYSTORE_LEGACY_PASSWORD);
            char[] keyPassword = resolvePasswordSetting(KEYSTORE_SECURE_KEY_PASSWORD, KEYSTORE_LEGACY_KEY_PASSWORD);
            if (keyPassword.length == 0) {
                keyPassword = storePassword;
            }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Add the matching ssl.key setting pointing to the PEM private key for the certificate.
  2. If you intended to use a keystore instead, remove ssl.certificate and set ssl.keystore.path.
  3. Validate that the key matches the cert (openssl x509/pkey modulus compare) after adding it.

Example fix

# before
xpack.security.http.ssl.certificate: "node.crt"
# after
xpack.security.http.ssl.certificate: "node.crt"
xpack.security.http.ssl.key: "node.key"
Defensive patterns

Strategy: validation

Validate before calling

void requirePemPair(Map<String,String> settings, String prefix) {
    boolean hasCert = settings.containsKey(prefix + "certificate");
    boolean hasKey  = settings.containsKey(prefix + "key");
    if (hasCert && !hasKey)
        throw new IllegalArgumentException(prefix + "certificate requires " + prefix + "key");
}

Prevention

When it happens

Trigger: ssl.certificate is set but ssl.key is not, under the same prefix (and ssl.keystore.path is not set as an alternative).

Common situations: Operator sets only the certificate path expecting the key to be auto-discovered; copy-paste that dropped the key line; secret-management system that injects only the cert.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/36be70ce0a56174e. Report an issue: GitHub.