Skip to content

CAMEL-22497: Make HTTPS easier for camel.server#22194

Open
gnodet wants to merge 3 commits intomainfrom
florentine-november
Open

CAMEL-22497: Make HTTPS easier for camel.server#22194
gnodet wants to merge 3 commits intomainfrom
florentine-november

Conversation

@gnodet
Copy link
Contributor

@gnodet gnodet commented Mar 23, 2026

Summary

  • Move SSL configuration (camel.ssl.*) before HTTP server configuration so global SSL context is available when the server is created
  • Auto-enable useGlobalSslContextParameters on both HTTP server and management server when camel.ssl.enabled=true, removing the need to set it separately (respects explicit false)
  • Add camel.ssl.selfSigned=true option to generate a self-signed certificate for development use (explicit opt-in required — no auto-generation)
  • When SSL is enabled without a keystore or selfSigned, log a warning and skip SSL context creation
  • Mark camel.ssl.keystorePassword and camel.ssl.trustStorePassword with secret=true (fixes existing gap)
  • Self-signed certificate includes SAN extension (DNS:localhost, IP:127.0.0.1) for compatibility with modern HTTP clients
  • Uses pure JDK APIs for certificate generation (no internal sun.security dependencies)

With keystore (production)

camel.ssl.enabled=true
camel.ssl.keyStore=file:keystore.jks
camel.ssl.keystorePassword=changeit
# camel.server.useGlobalSslContextParameters is now auto-enabled

Self-signed for development (explicit opt-in)

camel.ssl.enabled=true
camel.ssl.selfSigned=true

Follow-up

[CAMEL-23250|https://issues.apache.org/jira/browse/CAMEL-23250] tracks broader improvements for warning/preventing plain-text secrets in configuration and flagging development-only settings like selfSigned and trustAllCertificates in production.

Test plan

  • testMainSSLSelfSigned — verifies self-signed cert generation with SAN extension and valid SSLContext creation
  • testMainSSLSelfSignedFluent — same test using fluent API
  • testSelfSignedCertificateGenerator — unit test verifying KeyStore, key entry, and SAN extension
  • All 15 SSL tests pass
  • CI green on JDK 17, 21, 25

- Move SSL configuration before HTTP server configuration so global SSL
  context is available when the server is created
- Auto-enable useGlobalSslContextParameters on HTTP server and management
  server when camel.ssl.enabled=true
- Generate self-signed certificate when SSL is enabled but no keystore
  is configured, for easy development use

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using build-all, build-dependents, skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions github-actions bot added the core label Mar 23, 2026
- Remove spurious @SuppressWarnings("restriction")
- Replace deprecated Date methods with java.time APIs
- Use wrapTag/encodeLength consistently in buildRdn
- Import StandardCharsets instead of using fully-qualified names
- Add SAN extension (DNS:localhost, IP:127.0.0.1) to self-signed cert
- Reuse SecureRandom instance instead of creating multiple
- Respect explicit camel.server.useGlobalSslContextParameters=false
  by checking if the property was explicitly set before auto-enabling
- Add test verifying SAN extension in generated certificate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • core/camel-main

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.

Build reactor — dependencies compiled but only changed modules were tested (4 modules)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Catalog [jar]
  • Camel :: Main
  • Camel :: Main [jar]

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a wise idea to add an hidden self signed certificate, even for development. If this is enabled I have the feeling it can expose potential security problems.

…s as secret

- Add camel.ssl.selfSigned property to explicitly opt-in to self-signed
  certificate generation instead of auto-generating when no keystore
  is configured
- Mark camel.ssl.keystorePassword and camel.ssl.trustStorePassword
  with secret=true in @metadata annotation
- When SSL is enabled without keystore or selfSigned, log a warning
  and skip SSL context creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
Copy link
Contributor Author

gnodet commented Mar 25, 2026

Claude Code on behalf of Guillaume Nodet

Thanks for the feedback @squakez! The latest push addresses the concerns raised:

Self-signed certificate is now explicit opt-in only:

  • Requires camel.ssl.selfSigned=true — no auto-generation when keystore is missing
  • When SSL is enabled without a keystore or selfSigned, a warning is logged and SSL context creation is skipped
  • The self-signed generation emits a WARN log: "Do NOT use this in production"

Secret annotations fixed:

  • camel.ssl.keystorePassword and camel.ssl.trustStorePassword are now marked secret=true (was missing)

Follow-up for broader secret/dev-setting warnings:

  • Created CAMEL-23250 to track:
    • Warning when plain-text secrets are used in configuration (instead of vault/env refs)
    • Flagging development-only settings (selfSigned, trustAllCertificates) when used in production profiles
    • Fixing PropertiesDevConsole JSON output which doesn't mask secrets

@gnodet gnodet requested a review from squakez March 25, 2026 18:09
@gnodet
Copy link
Contributor Author

gnodet commented Mar 25, 2026

Self-Signed Certificate Generation: Framework Comparison

For context on the approach we took with SelfSignedCertificateGenerator, here's how other frameworks handle self-signed certificate generation:

Netty

Used a two-tier fallback:

  1. BouncyCastle (preferred) — X509v3CertificateBuilder, JcaContentSignerBuilder, etc.
  2. OpenJDK internal APIs (fallback) — sun.security.x509.* classes (X509CertInfo, X509CertImpl, X500Name, etc.) via reflection

Both have downsides: BouncyCastle is a heavy optional dependency, and sun.security.x509 classes are internal JDK APIs increasingly restricted by module encapsulation. Netty has since added (PR #14263) a separate module with their own DER encoder — the same approach we took here.

Vert.x

Delegates entirely to Netty's SelfSignedCertificate (wraps new io.netty.handler.ssl.util.SelfSignedCertificate(fqdn)).

Quarkus

Uses SmallRye Certs library (io.smallrye.certs.CertificateGenerator) which depends on BouncyCastle (BouncyCastleProvider). Available via CLI: quarkus tls generate-certificate --self-signed.

Our Approach (Camel)

Our SelfSignedCertificateGenerator builds the DER-encoded X.509 certificate directly using standard JDK APIs only (KeyPairGenerator, Signature, CertificateFactory) — no internal APIs, no BouncyCastle dependency:

  • Lightest approach — zero extra dependencies
  • Most forward-compatible — no sun.security.x509 or --add-opens needed
  • Aligned with Netty's direction — they've already merged their own DER encoding module
  • Explicit opt-in — requires camel.ssl.selfSigned=true, just like Quarkus requires --self-signed

Claude Code on behalf of Guillaume Nodet

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to deeply think in the long term implications and the plethora of possibilities that can happen when we have a non opinionated and possibly a non-official JVM environment.

One potential scenario I invite you to diagnose is, what happen when I start doing a development with the selfsigned certificate on. Then, I'm happy with the development, and I turn the configuration off. The self signed certificate will be still there in the keystore.

Also, on environments where the JVM is shared among other processes, we are going to affect the same underlying keystore used by all processes (ie, what happen when we run in Tomcat or any other application server).

If we want to proceed with this scenario, my suggestion is to have this run in a component with a dedicated dependency and marked clearly with maven test scope. So, it will be up to the user to include/remove the dependency.

When we deal with security/threading and other core features that can have unforeseen side effects, I think we need to properly balance the tradeoff of introducing a feature vs potential disruption.


X509Certificate cert = generateCertificate(keyPair, random);

KeyStore ks = KeyStore.getInstance("PKCS12");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one may fail if security provider is broken or missing. Also, not reliable on FIPS environment or OSGI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PKCS12 is the default keystore type since JDK 9 and is provided by the built-in SunJSSE provider — if it's unavailable, no SSL functionality would work at all. For FIPS environments, self-signed certificates wouldn't be appropriate anyway (FIPS is a production/compliance requirement, selfSigned=true is explicitly for dev use). If generation does fail for any reason, the exception propagates clearly and the context won't start silently without SSL.

Copy link
Contributor Author

@gnodet gnodet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough review @squakez. Let me address each concern:

1. "The self-signed certificate will still be there in the keystore"

The certificate is generated entirely in-memory — it's never written to disk or to any system keystore. In SelfSignedCertificateGenerator.java:61, we call KeyStore.load(null, password.toCharArray()) where null means "create an empty in-memory keystore, don't read from any file". When the CamelContext stops, the KeyStore object is garbage collected. There is no persistent state.

2. "On environments where the JVM is shared (Tomcat, app servers), we affect the same underlying keystore"

The generated SSL context is set only on the CamelContext via camelContext.setSSLContextParameters(...) — it does not call SSLContext.setDefault() or modify the JVM-wide truststore/keystore. SSLContext.setDefault() is never called anywhere in the Camel codebase. The Vert.x HTTP server retrieves it from the CamelContext and applies it only to its own HttpServerOptions. Other processes, other webapps, or even other CamelContexts are unaffected.

More broadly, this feature targets standalone Camel applications (camel-main, JBang). In a Tomcat or app server scenario, you'd typically use Spring Boot or Quarkus which have their own SSL configuration mechanisms — camel-main and its camel.ssl.* properties wouldn't come into play.

3. "Separate component with test scope"

This feature is specifically for dev-time convenience (quickly enabling HTTPS without manually generating certificates), similar to how Quarkus offers quarkus tls generate-certificate --self-signed and Vert.x/Netty provide SelfSignedCertificate. It requires explicit opt-in via camel.ssl.selfSigned=true, and a WARN log is emitted at startup:

"Generating self-signed SSL certificate for development use. Do NOT use this in production."

Moving it to a test-scoped dependency would defeat the purpose — users need it at runtime during development, not just in tests.

4. Framework precedent

For reference, I posted a comparison of how other frameworks handle this. The approach is aligned with industry practice and Netty's own direction (they recently merged their own DER-based cert generation in PR #14263).

We also created CAMEL-23250 and #22269 to track broader improvements around warning on dev-only/insecure settings in production.

Claude Code on behalf of Guillaume Nodet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants