This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 7e80bd65262a444fbb89ab4ddb7f7aabe3ec063a Author: Pranjul Kalsi <[email protected]> AuthorDate: Thu Jan 15 11:36:25 2026 +0530 feat(jvm): Implement review feedback and improve multi-certificate support with secure password handling --- docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 90 ++++- docs/modules/traits/pages/jvm.adoc | 28 +- e2e/common/traits/jvm_test.go | 62 ++-- helm/camel-k/crds/camel-k-crds.yaml | 409 +++++++++++++-------- pkg/apis/camel/v1/trait/jvm.go | 36 +- pkg/apis/camel/v1/trait/zz_generated.deepcopy.go | 42 ++- .../camel.apache.org_integrationplatforms.yaml | 102 +++-- .../camel.apache.org_integrationprofiles.yaml | 102 +++-- .../crd/bases/camel.apache.org_integrations.yaml | 102 +++-- .../config/crd/bases/camel.apache.org_pipes.yaml | 103 ++++-- pkg/trait/init_containers.go | 35 +- pkg/trait/init_containers_test.go | 54 ++- pkg/trait/jvm.go | 31 +- pkg/trait/jvm_cacert.go | 106 ++++-- pkg/trait/jvm_test.go | 164 ++++++--- 15 files changed, 967 insertions(+), 499 deletions(-) diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index d1effbd3a..f34bf5175 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -6443,6 +6443,37 @@ Defines a set of pods (namely those matching the label selector, relative to the integration pod(s) should not be co-located with. +|=== + +[#_camel_apache_org_v1_trait_BaseTruststore] +=== BaseTruststore + +*Appears on:* + +* <<#_camel_apache_org_v1_trait_JVMTrait, JVMTrait>> + +BaseTruststore represents an existing truststore to use as the base for adding certificates. + +[cols="2,2a",options="header"] +|=== +|Field +|Description + +|`truststorePath` + +string +| + + +Path to the base truststore file. + +|`passwordPath` + +string +| + + +Path to a file containing the password for the base truststore. + + |=== [#_camel_apache_org_v1_trait_BuilderTrait] @@ -6626,6 +6657,37 @@ When using `pod` strategy, annotation to use for the builder pod. The list of manifest platforms to use to build a container image (default `linux/amd64`). +|=== + +[#_camel_apache_org_v1_trait_CACertConfig] +=== CACertConfig + +*Appears on:* + +* <<#_camel_apache_org_v1_trait_JVMTrait, JVMTrait>> + +CACertConfig associates a CA certificate with its password file. + +[cols="2,2a",options="header"] +|=== +|Field +|Description + +|`certPath` + +string +| + + +Path to the PEM-encoded CA certificate file to import. + +|`passwordPath` + +string +| + + +Path to a file containing the password for importing this certificate. + + |=== [#_camel_apache_org_v1_trait_CamelTrait] @@ -7836,44 +7898,40 @@ The Jar dependency which will run the application. Leave it empty for managed In A list of JVM agents to download and execute with format `<agent-name>;<agent-url>[;<jvm-agent-options>]`. -|`caCerts` + -[]string +|`caCertificates` + +*xref:#_camel_apache_org_v1_trait_CACertConfig[[\]CACertConfig]* | -A list of paths to PEM-encoded CA certificates to import into the truststore. -Certificates must be mounted via the mount trait. +A list of CA certificates to import into the truststore. Certificates must be mounted via the mount trait. -|`caCert` + -string +|`baseTruststore` + +*xref:#_camel_apache_org_v1_trait_BaseTruststore[BaseTruststore]* | -Path to a PEM-encoded CA certificate file. Use CACerts for multiple certificates. +Optional base truststore to use as the starting point for adding certificates. |`caCertMountPath` + string | -The path where the generated truststore will be mounted. -Default: "/etc/camel/conf.d/_truststore" +The path where the generated truststore will be mounted (default `/etc/camel/conf.d/_truststore`). -|`caCertPassword` + +|`caCert` + string | -Path to a custom truststore password file. -Default: uses "changeit" if not specified. +Deprecated: Use CACertificates instead. Path to a PEM-encoded CA certificate file. -|`caCertUseSystemTruststore` + -bool +|`caCertPassword` + +string | -If true, the JDK's default cacerts is copied as the base truststore. -Default: false (empty truststore). +Deprecated: Use CACertificates instead. Path to a file containing the truststore password. |=== diff --git a/docs/modules/traits/pages/jvm.adoc b/docs/modules/traits/pages/jvm.adoc index 39a7f7641..34f128d9f 100755 --- a/docs/modules/traits/pages/jvm.adoc +++ b/docs/modules/traits/pages/jvm.adoc @@ -63,29 +63,25 @@ Deprecated: no longer in use. | []string | A list of JVM agents to download and execute with format `<agent-name>;<agent-url>[;<jvm-agent-options>]`. -| jvm.ca-certs -| []string -| A list of paths to PEM-encoded CA certificates to import into the truststore. -Certificates must be mounted via the mount trait. +| jvm.ca-certificates +| []github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait.CACertConfig +| A list of CA certificates to import into the truststore. Certificates must be mounted via the mount trait. -| jvm.ca-cert -| string -| Path to a PEM-encoded CA certificate file. Use CACerts for multiple certificates. +| jvm.base-truststore +| github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait.BaseTruststore +| Optional base truststore to use as the starting point for adding certificates. | jvm.ca-cert-mount-path | string -| The path where the generated truststore will be mounted. -Default: "/etc/camel/conf.d/_truststore" +| The path where the generated truststore will be mounted (default `/etc/camel/conf.d/_truststore`). -| jvm.ca-cert-password +| jvm.ca-cert | string -| Path to a custom truststore password file. -Default: uses "changeit" if not specified. +| Deprecated: Use CACertificates instead. Path to a PEM-encoded CA certificate file. -| jvm.ca-cert-use-system-truststore -| bool -| If true, the JDK's default cacerts is copied as the base truststore. -Default: false (empty truststore). +| jvm.ca-cert-password +| string +| Deprecated: Use CACertificates instead. Path to a file containing the truststore password. |=== diff --git a/e2e/common/traits/jvm_test.go b/e2e/common/traits/jvm_test.go index f2a8fc5ea..189c5b7cf 100644 --- a/e2e/common/traits/jvm_test.go +++ b/e2e/common/traits/jvm_test.go @@ -91,8 +91,7 @@ func TestJVMTrait(t *testing.T) { g.Eventually(IntegrationLogs(t, ctx, ns, name), TestTimeoutShort).Should(ContainSubstring("Hello World!")) }) - t.Run("JVM trait CA cert", func(t *testing.T) { - // Generate a valid self-signed certificate + t.Run("JVM trait CA cert (deprecated fields)", func(t *testing.T) { certPem, err := generateSelfSignedCert() require.NoError(t, err) @@ -113,6 +112,7 @@ func TestJVMTrait(t *testing.T) { "--name", name, "-t", "mount.configs=secret:test-ca-cert", "-t", "mount.configs=secret:test-ca-password", + // Using deprecated fields for backward compatibility test "-t", "jvm.ca-cert=/etc/camel/conf.d/_secrets/test-ca-cert/ca.crt", "-t", "jvm.ca-cert-password=/etc/camel/conf.d/_secrets/test-ca-password/password", ).Execute()).To(Succeed()) @@ -130,37 +130,36 @@ func TestJVMTrait(t *testing.T) { }) t.Run("JVM trait multiple CA certs", func(t *testing.T) { - // Generate two valid self-signed certificates + // Test the new ca-certificates field with multiple certificates, each with its own password cert1Pem, err := generateSelfSignedCert() require.NoError(t, err) cert2Pem, err := generateSelfSignedCert() require.NoError(t, err) + // Create secrets with both cert and password together caCert1Data := make(map[string]string) caCert1Data["ca.crt"] = string(cert1Pem) + caCert1Data["password"] = "test-password-1" err = CreatePlainTextSecret(t, ctx, ns, "test-ca-cert-1", caCert1Data) require.NoError(t, err) caCert2Data := make(map[string]string) caCert2Data["ca.crt"] = string(cert2Pem) + caCert2Data["password"] = "test-password-2" err = CreatePlainTextSecret(t, ctx, ns, "test-ca-cert-2", caCert2Data) require.NoError(t, err) - passwordData := make(map[string]string) - passwordData["password"] = "test-password-123" - err = CreatePlainTextSecret(t, ctx, ns, "test-multi-ca-password", passwordData) - require.NoError(t, err) - name := RandomizedSuffixName("multicacert") g.Expect(KamelRun(t, ctx, ns, "./files/Java.java", "--name", name, "-t", "mount.configs=secret:test-ca-cert-1", "-t", "mount.configs=secret:test-ca-cert-2", - "-t", "mount.configs=secret:test-multi-ca-password", - "-t", "jvm.ca-certs=/etc/camel/conf.d/_secrets/test-ca-cert-1/ca.crt", - "-t", "jvm.ca-certs=/etc/camel/conf.d/_secrets/test-ca-cert-2/ca.crt", - "-t", "jvm.ca-cert-password=/etc/camel/conf.d/_secrets/test-multi-ca-password/password", + // Using new ca-certificates field: each certificate with its own password path + "-t", "jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/test-ca-cert-1/ca.crt", + "-t", "jvm.ca-certificates[0].password-path=/etc/camel/conf.d/_secrets/test-ca-cert-1/password", + "-t", "jvm.ca-certificates[1].cert-path=/etc/camel/conf.d/_secrets/test-ca-cert-2/ca.crt", + "-t", "jvm.ca-certificates[1].password-path=/etc/camel/conf.d/_secrets/test-ca-cert-2/password", ).Execute()).To(Succeed()) g.Eventually(IntegrationPodPhase(t, ctx, ns, name), TestTimeoutLong*2).Should(Equal(corev1.PodRunning)) @@ -175,19 +174,22 @@ func TestJVMTrait(t *testing.T) { g.Expect(initContainerNames).To(ContainElement("generate-truststore")) }) - t.Run("JVM trait CA cert with system truststore", func(t *testing.T) { - // Generate a valid self-signed certificate + t.Run("JVM trait CA cert with base truststore", func(t *testing.T) { + // Test the new base-truststore field (replaces ca-cert-use-system-truststore) certPem, err := generateSelfSignedCert() require.NoError(t, err) + // Create secret with cert and password caCertData := make(map[string]string) caCertData["ca.crt"] = string(certPem) + caCertData["password"] = "test-password-456" err = CreatePlainTextSecret(t, ctx, ns, "test-ca-sys", caCertData) require.NoError(t, err) - passwordData := make(map[string]string) - passwordData["password"] = "test-password-456" - err = CreatePlainTextSecret(t, ctx, ns, "test-ca-sys-password", passwordData) + // Create secret for base truststore password (JDK cacerts uses "changeit") + baseTsPassData := make(map[string]string) + baseTsPassData["password"] = "changeit" + err = CreatePlainTextSecret(t, ctx, ns, "base-ts-password", baseTsPassData) require.NoError(t, err) name := RandomizedSuffixName("syscacert") @@ -195,10 +197,12 @@ func TestJVMTrait(t *testing.T) { "./files/Java.java", "--name", name, "-t", "mount.configs=secret:test-ca-sys", - "-t", "mount.configs=secret:test-ca-sys-password", - "-t", "jvm.ca-certs=/etc/camel/conf.d/_secrets/test-ca-sys/ca.crt", - "-t", "jvm.ca-cert-password=/etc/camel/conf.d/_secrets/test-ca-sys-password/password", - "-t", "jvm.ca-cert-use-system-truststore=true", + "-t", "mount.configs=secret:base-ts-password", + // Using new base-truststore field with JDK cacerts as base + "-t", "jvm.base-truststore.truststore-path=/opt/java/openjdk/lib/security/cacerts", + "-t", "jvm.base-truststore.password-path=/etc/camel/conf.d/_secrets/base-ts-password/password", + "-t", "jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/test-ca-sys/ca.crt", + "-t", "jvm.ca-certificates[0].password-path=/etc/camel/conf.d/_secrets/test-ca-sys/password", ).Execute()).To(Succeed()) g.Eventually(IntegrationPodPhase(t, ctx, ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) @@ -213,22 +217,26 @@ func TestJVMTrait(t *testing.T) { g.Expect(initContainerNames).To(ContainElement("generate-truststore")) }) - t.Run("JVM trait CA cert with default password", func(t *testing.T) { + t.Run("JVM trait CA cert single certificate", func(t *testing.T) { + // Test single certificate with the new ca-certificates field certPem, err := generateSelfSignedCert() require.NoError(t, err) + // Create secret with both cert and password caCertData := make(map[string]string) caCertData["ca.crt"] = string(certPem) - err = CreatePlainTextSecret(t, ctx, ns, "test-ca-default-pass", caCertData) + caCertData["password"] = "changeit" + err = CreatePlainTextSecret(t, ctx, ns, "test-ca-single", caCertData) require.NoError(t, err) - // Note: No password secret is provided, will use default "changeit" - name := RandomizedSuffixName("defaultpass") + name := RandomizedSuffixName("singlecert") g.Expect(KamelRun(t, ctx, ns, "./files/Java.java", "--name", name, - "-t", "mount.configs=secret:test-ca-default-pass", - "-t", "jvm.ca-certs=/etc/camel/conf.d/_secrets/test-ca-default-pass/ca.crt", + "-t", "mount.configs=secret:test-ca-single", + // Using new ca-certificates field with explicit password + "-t", "jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/test-ca-single/ca.crt", + "-t", "jvm.ca-certificates[0].password-path=/etc/camel/conf.d/_secrets/test-ca-single/password", ).Execute()).To(Succeed()) g.Eventually(IntegrationPodPhase(t, ctx, ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) diff --git a/helm/camel-k/crds/camel-k-crds.yaml b/helm/camel-k/crds/camel-k-crds.yaml index 1bdcfb2ab..bb582cbac 100644 --- a/helm/camel-k/crds/camel-k-crds.yaml +++ b/helm/camel-k/crds/camel-k-crds.yaml @@ -4775,31 +4775,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -7268,31 +7283,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -9661,31 +9691,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -12031,31 +12076,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -21259,31 +21319,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -23585,31 +23660,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -34177,31 +34267,47 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password + for the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. - Use CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. + Path to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. + Path to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into + the truststore. Certificates must be mounted via the + mount trait. items: - type: string + description: CACertConfig associates a CA certificate + with its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -36433,31 +36539,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath diff --git a/pkg/apis/camel/v1/trait/jvm.go b/pkg/apis/camel/v1/trait/jvm.go index 232205e1d..7c5d904c9 100644 --- a/pkg/apis/camel/v1/trait/jvm.go +++ b/pkg/apis/camel/v1/trait/jvm.go @@ -17,6 +17,22 @@ limitations under the License. package trait +// CACertConfig associates a CA certificate with its password file. +type CACertConfig struct { + // Path to the PEM-encoded CA certificate file to import. + CertPath string `json:"certPath,omitempty" property:"cert-path"` + // Path to a file containing the password for importing this certificate. + PasswordPath string `json:"passwordPath,omitempty" property:"password-path"` +} + +// BaseTruststore represents an existing truststore to use as the base for adding certificates. +type BaseTruststore struct { + // Path to the base truststore file. + TruststorePath string `json:"truststorePath,omitempty" property:"truststore-path"` + // Path to a file containing the password for the base truststore. + PasswordPath string `json:"passwordPath,omitempty" property:"password-path"` +} + // The JVM trait is used to configure the JVM that runs the Integration. This trait is configured only for Integration and related IntegrationKits // (bound to a container image) built by Camel K operator. If the system detects the usage of a different container image (ie, built externally), then, the // trait is disabled by the platform. @@ -45,18 +61,14 @@ type JVMTrait struct { Jar string `json:"jar,omitempty" property:"jar"` // A list of JVM agents to download and execute with format `<agent-name>;<agent-url>[;<jvm-agent-options>]`. Agents []string `json:"agents,omitempty" property:"agents"` - // A list of paths to PEM-encoded CA certificates to import into the truststore. - // Certificates must be mounted via the mount trait. - CACerts []string `json:"caCerts,omitempty" property:"ca-certs"` - // Path to a PEM-encoded CA certificate file. Use CACerts for multiple certificates. - CACert string `json:"caCert,omitempty" property:"ca-cert"` - // The path where the generated truststore will be mounted. - // Default: "/etc/camel/conf.d/_truststore" + // A list of CA certificates to import into the truststore. Certificates must be mounted via the mount trait. + CACertificates []CACertConfig `json:"caCertificates,omitempty" property:"ca-certificates"` + // Optional base truststore to use as the starting point for adding certificates. + BaseTruststore *BaseTruststore `json:"baseTruststore,omitempty" property:"base-truststore"` + // The path where the generated truststore will be mounted (default `/etc/camel/conf.d/_truststore`). CACertMountPath string `json:"caCertMountPath,omitempty" property:"ca-cert-mount-path"` - // Path to a custom truststore password file. - // Default: uses "changeit" if not specified. + // Deprecated: Use CACertificates instead. Path to a PEM-encoded CA certificate file. + CACert string `json:"caCert,omitempty" property:"ca-cert"` + // Deprecated: Use CACertificates instead. Path to a file containing the truststore password. CACertPassword string `json:"caCertPassword,omitempty" property:"ca-cert-password"` - // If true, the JDK's default cacerts is copied as the base truststore. - // Default: false (empty truststore). - CACertUseSystemTruststore *bool `json:"caCertUseSystemTruststore,omitempty" property:"ca-cert-use-system-truststore"` } diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go index ed7752e52..8cd29b192 100644 --- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go @@ -51,6 +51,21 @@ func (in *AffinityTrait) DeepCopy() *AffinityTrait { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseTruststore) DeepCopyInto(out *BaseTruststore) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseTruststore. +func (in *BaseTruststore) DeepCopy() *BaseTruststore { + if in == nil { + return nil + } + out := new(BaseTruststore) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BuilderTrait) DeepCopyInto(out *BuilderTrait) { *out = *in @@ -131,6 +146,21 @@ func (in *BuilderTrait) DeepCopy() *BuilderTrait { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CACertConfig) DeepCopyInto(out *CACertConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CACertConfig. +func (in *CACertConfig) DeepCopy() *CACertConfig { + if in == nil { + return nil + } + out := new(CACertConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CamelTrait) DeepCopyInto(out *CamelTrait) { *out = *in @@ -581,14 +611,14 @@ func (in *JVMTrait) DeepCopyInto(out *JVMTrait) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.CACerts != nil { - in, out := &in.CACerts, &out.CACerts - *out = make([]string, len(*in)) + if in.CACertificates != nil { + in, out := &in.CACertificates, &out.CACertificates + *out = make([]CACertConfig, len(*in)) copy(*out, *in) } - if in.CACertUseSystemTruststore != nil { - in, out := &in.CACertUseSystemTruststore, &out.CACertUseSystemTruststore - *out = new(bool) + if in.BaseTruststore != nil { + in, out := &in.BaseTruststore, &out.BaseTruststore + *out = new(BaseTruststore) **out = **in } } diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml index 3308ff925..3bd65993a 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml @@ -1501,31 +1501,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -3994,31 +4009,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml index 1db55503a..4cc3ea37f 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml @@ -1367,31 +1367,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -3737,31 +3752,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml index 4adf8f7fe..e9d7b0178 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml @@ -8205,31 +8205,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -10531,31 +10546,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath diff --git a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml index c325d43c1..a183f0500 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml @@ -8261,31 +8261,47 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password + for the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. - Use CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. + Path to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. + Path to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into + the truststore. Certificates must be mounted via the + mount trait. items: - type: string + description: CACertConfig associates a CA certificate + with its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath @@ -10517,31 +10533,46 @@ spec: items: type: string type: array + baseTruststore: + description: Optional base truststore to use as the starting + point for adding certificates. + properties: + passwordPath: + description: Path to a file containing the password for + the base truststore. + type: string + truststorePath: + description: Path to the base truststore file. + type: string + type: object caCert: - description: Path to a PEM-encoded CA certificate file. Use - CACerts for multiple certificates. + description: 'Deprecated: Use CACertificates instead. Path + to a PEM-encoded CA certificate file.' type: string caCertMountPath: - description: |- - The path where the generated truststore will be mounted. - Default: "/etc/camel/conf.d/_truststore" + description: The path where the generated truststore will + be mounted (default `/etc/camel/conf.d/_truststore`). type: string caCertPassword: - description: |- - Path to a custom truststore password file. - Default: uses "changeit" if not specified. + description: 'Deprecated: Use CACertificates instead. Path + to a file containing the truststore password.' type: string - caCertUseSystemTruststore: - description: |- - If true, the JDK's default cacerts is copied as the base truststore. - Default: false (empty truststore). - type: boolean - caCerts: - description: |- - A list of paths to PEM-encoded CA certificates to import into the truststore. - Certificates must be mounted via the mount trait. + caCertificates: + description: A list of CA certificates to import into the + truststore. Certificates must be mounted via the mount trait. items: - type: string + description: CACertConfig associates a CA certificate with + its password file. + properties: + certPath: + description: Path to the PEM-encoded CA certificate + file to import. + type: string + passwordPath: + description: Path to a file containing the password + for importing this certificate. + type: string + type: object type: array classpath: description: Additional JVM classpath (use `Linux` classpath diff --git a/pkg/trait/init_containers.go b/pkg/trait/init_containers.go index 1654b9afe..0468942d1 100644 --- a/pkg/trait/init_containers.go +++ b/pkg/trait/init_containers.go @@ -94,41 +94,34 @@ func (t *initContainersTrait) Configure(e *Environment) (bool, *TraitCondition, // Set the CA cert truststore init container if configured if ok && jvm.hasCACerts() { var allCommands []string - effectivePassword := jvm.getEffectiveTruststorePassword() - if jvm.useSystemTruststore() { - copyCmd := fmt.Sprintf("cp %s %s", jdkCacertsPath, jvm.getTrustStorePath()) + if jvm.hasBaseTruststore() { + baseTruststore := jvm.getBaseTruststore() + copyCmd := fmt.Sprintf("cp %s %s", baseTruststore.TruststorePath, jvm.getTrustStorePath()) allCommands = append(allCommands, copyCmd) - if jvm.hasCustomPassword() { + entries := jvm.getAllCACertEntries() + if len(entries) > 0 { changePassCmd := fmt.Sprintf( - "keytool -storepasswd -keystore %s -storepass %s -new %s", - jvm.getTrustStorePath(), jdkCacertsDefaultPassword, effectivePassword, + "keytool -storepasswd -keystore %s -storepass:file %s -new $(cat %s)", + jvm.getTrustStorePath(), baseTruststore.PasswordPath, entries[0].PasswordPath, ) allCommands = append(allCommands, changePassCmd) } } - certPaths := jvm.getAllCACertPaths() - for i, certPath := range certPaths { - var cmd string - if jvm.hasCustomPassword() { - cmd = fmt.Sprintf( - "keytool -importcert -noprompt -alias custom-ca-%d -storepass:file %s -keystore %s -file %s", - i, jvm.getCACertPasswordPath(), jvm.getTrustStorePath(), certPath, - ) - } else { - cmd = fmt.Sprintf( - "keytool -importcert -noprompt -alias custom-ca-%d -storepass %s -keystore %s -file %s", - i, jdkCacertsDefaultPassword, jvm.getTrustStorePath(), certPath, - ) - } + certEntries := jvm.getAllCACertEntries() + for i, entry := range certEntries { + cmd := fmt.Sprintf( + "keytool -importcert -noprompt -alias custom-ca-%d -storepass:file %s -keystore %s -file %s", + i, entry.PasswordPath, jvm.getTrustStorePath(), entry.CertPath, + ) allCommands = append(allCommands, cmd) } fullCommand := strings.Join(allCommands, " && ") // Wrap in bash shell when there are multiple commands or shell features are used - if len(allCommands) > 1 || jvm.useSystemTruststore() { + if len(allCommands) > 1 || jvm.hasBaseTruststore() { fullCommand = fmt.Sprintf("/bin/bash -c \"%s\"", fullCommand) } caCertTask := containerTask{ diff --git a/pkg/trait/init_containers_test.go b/pkg/trait/init_containers_test.go index 9fef79054..3a8f477d1 100644 --- a/pkg/trait/init_containers_test.go +++ b/pkg/trait/init_containers_test.go @@ -394,8 +394,12 @@ func TestApplyInitContainerWithCACert(t *testing.T) { Spec: v1.IntegrationSpec{ Traits: v1.Traits{ JVM: &trait.JVMTrait{ - CACert: "/etc/camel/conf.d/_secrets/my-ca/ca.crt", - CACertPassword: "/etc/camel/conf.d/_secrets/truststore-pass/password", + CACertificates: []trait.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/my-ca/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/truststore-pass/password", + }, + }, }, }, }, @@ -463,12 +467,20 @@ func TestApplyInitContainerWithMultipleCACerts(t *testing.T) { Spec: v1.IntegrationSpec{ Traits: v1.Traits{ JVM: &trait.JVMTrait{ - CACerts: []string{ - "/etc/camel/conf.d/_secrets/ca1/ca.crt", - "/etc/camel/conf.d/_secrets/ca2/ca.crt", - "/etc/camel/conf.d/_secrets/ca3/ca.crt", + CACertificates: []trait.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/ca1/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/pass1/password", + }, + { + CertPath: "/etc/camel/conf.d/_secrets/ca2/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/pass2/password", + }, + { + CertPath: "/etc/camel/conf.d/_secrets/ca3/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/pass3/password", + }, }, - CACertPassword: "/etc/camel/conf.d/_secrets/truststore-pass/password", }, }, }, @@ -545,11 +557,14 @@ func TestApplyInitContainerWithCACertsBackwardCompatibility(t *testing.T) { Spec: v1.IntegrationSpec{ Traits: v1.Traits{ JVM: &trait.JVMTrait{ - CACerts: []string{ - "/etc/camel/conf.d/_secrets/ca1/ca.crt", + CACertificates: []trait.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/ca1/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/pass1/password", + }, }, CACert: "/etc/camel/conf.d/_secrets/ca2/ca.crt", - CACertPassword: "/etc/camel/conf.d/_secrets/truststore-pass/password", + CACertPassword: "/etc/camel/conf.d/_secrets/pass2/password", }, }, }, @@ -588,7 +603,7 @@ func TestApplyInitContainerWithCACertsBackwardCompatibility(t *testing.T) { assert.Contains(t, commandStr, "/etc/camel/conf.d/_secrets/ca2/ca.crt") } -func TestApplyInitContainerWithSystemTruststore(t *testing.T) { +func TestApplyInitContainerWithBaseTruststore(t *testing.T) { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: "my-it", @@ -617,11 +632,16 @@ func TestApplyInitContainerWithSystemTruststore(t *testing.T) { Spec: v1.IntegrationSpec{ Traits: v1.Traits{ JVM: &trait.JVMTrait{ - CACerts: []string{ - "/etc/camel/conf.d/_secrets/my-ca/ca.crt", + CACertificates: []trait.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/my-ca/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/truststore-pass/password", + }, + }, + BaseTruststore: &trait.BaseTruststore{ + TruststorePath: "/opt/java/openjdk/lib/security/cacerts", + PasswordPath: "/etc/camel/conf.d/_secrets/base-truststore-pass/password", }, - CACertPassword: "/etc/camel/conf.d/_secrets/truststore-pass/password", - CACertUseSystemTruststore: ptr.To(true), }, }, }, @@ -659,9 +679,9 @@ func TestApplyInitContainerWithSystemTruststore(t *testing.T) { commandStr := strings.Join(initContainer.Command, " ") assert.Contains(t, commandStr, "/bin/bash") - assert.Contains(t, commandStr, "cp $JAVA_HOME/lib/security/cacerts") + assert.Contains(t, commandStr, "cp /opt/java/openjdk/lib/security/cacerts") assert.Contains(t, commandStr, "keytool -storepasswd") - assert.Contains(t, commandStr, "-storepass changeit") + assert.Contains(t, commandStr, "-storepass:file /etc/camel/conf.d/_secrets/base-truststore-pass/password") assert.Contains(t, commandStr, "keytool -importcert") assert.Contains(t, commandStr, "/etc/camel/conf.d/_secrets/my-ca/ca.crt") assert.Contains(t, commandStr, "&&") diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go index d7c01a9cb..22120eb65 100644 --- a/pkg/trait/jvm.go +++ b/pkg/trait/jvm.go @@ -104,7 +104,25 @@ func (t *jvmTrait) Configure(e *Environment) (bool, *TraitCondition, error) { t.jvmAgentArgs = jvmAgentArgs } - return true, nil, nil + if err := t.validateCACertConfig(); err != nil { + return false, nil, err + } + + var condition *TraitCondition + //nolint:staticcheck + if t.CACert != "" || t.CACertPassword != "" { + m := "The ca-cert and ca-cert-password parameters are deprecated and may be removed in future releases. Use ca-certificates instead." + t.L.Info(m) + condition = NewIntegrationCondition( + "JVM", + v1.IntegrationConditionTraitInfo, + corev1.ConditionTrue, + TraitConfigurationReason, + m, + ) + } + + return true, condition, nil } func (t *jvmTrait) Apply(e *Environment) error { @@ -376,12 +394,19 @@ func getLegacyCamelQuarkusDependenciesPaths() *sets.Set { // configureCACert configures the CA certificate truststore and returns the JVM arguments. func (t *jvmTrait) configureCaCert() []string { - if t.CACert == "" { + if !t.hasCACerts() { + return nil + } + + // Get the password path from the first certificate entry + // All certificates use the same truststore, so we use the first entry's password + entries := t.getAllCACertEntries() + if len(entries) == 0 { return nil } return []string{ "-Djavax.net.ssl.trustStore=" + t.getTrustStorePath(), - fmt.Sprintf("-Djavax.net.ssl.trustStorePassword=$(%s)", truststorePasswordEnvVar), + fmt.Sprintf("-Djavax.net.ssl.trustStorePassword=$(cat %s)", entries[0].PasswordPath), } } diff --git a/pkg/trait/jvm_cacert.go b/pkg/trait/jvm_cacert.go index 87ecd4cdd..54ddc9216 100644 --- a/pkg/trait/jvm_cacert.go +++ b/pkg/trait/jvm_cacert.go @@ -18,21 +18,28 @@ limitations under the License. package trait import ( - "k8s.io/utils/ptr" + "errors" + "fmt" + + traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" ) const ( - defaultCACertMountPath = "/etc/camel/conf.d/_truststore" - caCertVolumeName = "jvm-truststore" - trustStoreName = "truststore.jks" - truststorePasswordEnvVar = "TRUSTSTORE_PASSWORD" - jdkCacertsPath = "$JAVA_HOME/lib/security/cacerts" - jdkCacertsDefaultPassword = "changeit" + defaultCACertMountPath = "/etc/camel/conf.d/_truststore" + caCertVolumeName = "jvm-truststore" + trustStoreName = "truststore.jks" ) -// hasCACerts returns true if any CA certificates are configured (either via CACerts array or CACert). +// CACertEntry represents a resolved CA certificate configuration. +type CACertEntry struct { + CertPath string + PasswordPath string +} + +// hasCACerts returns true if any CA certificates are configured. func (t *jvmTrait) hasCACerts() bool { - return len(t.CACerts) > 0 || t.CACert != "" + //nolint:staticcheck + return len(t.CACertificates) > 0 || t.CACert != "" } func (t *jvmTrait) getCACertMountPath() string { @@ -47,50 +54,77 @@ func (t *jvmTrait) getTrustStorePath() string { return t.getCACertMountPath() + "/" + trustStoreName } -// hasCustomPassword returns true if a custom password file path is provided. -func (t *jvmTrait) hasCustomPassword() bool { - return t.CACertPassword != "" +// hasBaseTruststore returns true if a base truststore is configured. +func (t *jvmTrait) hasBaseTruststore() bool { + return t.BaseTruststore != nil && t.BaseTruststore.TruststorePath != "" && t.BaseTruststore.PasswordPath != "" } -// getEffectiveTruststorePassword returns the password for the truststore. -func (t *jvmTrait) getEffectiveTruststorePassword() string { - if t.hasCustomPassword() { - return "$(cat " + t.CACertPassword + ")" - } - - return jdkCacertsDefaultPassword +// getBaseTruststore returns the base truststore configuration if set. +func (t *jvmTrait) getBaseTruststore() *traitv1.BaseTruststore { + return t.BaseTruststore } -// getAllCACertPaths returns all configured CA certificate paths. -// It merges the CACert (if set) with the CACerts array. -func (t *jvmTrait) getAllCACertPaths() []string { - var paths []string +// getAllCACertEntries returns all configured CA certificate entries. +func (t *jvmTrait) getAllCACertEntries() []CACertEntry { + var entries []CACertEntry - paths = append(paths, t.CACerts...) + for _, cert := range t.CACertificates { + if cert.CertPath != "" && cert.PasswordPath != "" { + entries = append(entries, CACertEntry{ + CertPath: cert.CertPath, + PasswordPath: cert.PasswordPath, + }) + } + } - if t.CACert != "" { + //nolint:staticcheck + if t.CACert != "" && t.CACertPassword != "" { found := false - for _, p := range paths { - if p == t.CACert { + for _, e := range entries { + //nolint:staticcheck + if e.CertPath == t.CACert { found = true break } } if !found { - paths = append(paths, t.CACert) + entries = append(entries, CACertEntry{ + //nolint:staticcheck + CertPath: t.CACert, + //nolint:staticcheck + PasswordPath: t.CACertPassword, + }) } } - return paths + return entries } -// getCACertPasswordPath returns the user-provided password file path. -func (t *jvmTrait) getCACertPasswordPath() string { - return t.CACertPassword -} +// validateCACertConfig validates the CA certificate configuration. +func (t *jvmTrait) validateCACertConfig() error { + for i, cert := range t.CACertificates { + if cert.CertPath != "" && cert.PasswordPath == "" { + return fmt.Errorf("CACertificates[%d]: password path is required when certificate path is specified", i) + } + if cert.CertPath == "" && cert.PasswordPath != "" { + return fmt.Errorf("CACertificates[%d]: certificate path is required when password path is specified", i) + } + } + + //nolint:staticcheck + if t.CACert != "" && t.CACertPassword == "" { + return errors.New("ca-cert-password is required when ca-cert is specified") + } + + if t.BaseTruststore != nil { + if t.BaseTruststore.TruststorePath != "" && t.BaseTruststore.PasswordPath == "" { + return errors.New("base-truststore password path is required when truststore path is specified") + } + if t.BaseTruststore.TruststorePath == "" && t.BaseTruststore.PasswordPath != "" { + return errors.New("base-truststore truststore path is required when password path is specified") + } + } -// useSystemTruststore returns true if JDK's default cacerts should be used as base. -func (t *jvmTrait) useSystemTruststore() bool { - return ptr.Deref(t.CACertUseSystemTruststore, false) + return nil } diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go index f0290a530..37ae9633e 100644 --- a/pkg/trait/jvm_test.go +++ b/pkg/trait/jvm_test.go @@ -722,8 +722,12 @@ func TestApplyJvmTraitAgentFail(t *testing.T) { func TestApplyJvmTraitWithCACert(t *testing.T) { trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform) - trait.CACert = "/etc/camel/conf.d/_secrets/my-ca/ca.crt" - trait.CACertPassword = "/etc/camel/conf.d/_secrets/truststore-pass/password" + trait.CACertificates = []traitv1.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/my-ca/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/truststore-pass/password", + }, + } d := appsv1.Deployment{ Spec: appsv1.DeploymentSpec{ @@ -749,13 +753,17 @@ func TestApplyJvmTraitWithCACert(t *testing.T) { require.NoError(t, err) assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStore=/etc/camel/conf.d/_truststore/truststore.jks") - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD)") + assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStorePassword=$(cat /etc/camel/conf.d/_secrets/truststore-pass/password)") } func TestApplyJvmTraitWithCustomCACertMountPath(t *testing.T) { trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform) - trait.CACert = "/etc/camel/conf.d/_secrets/my-ca/ca.crt" - trait.CACertPassword = "/etc/camel/conf.d/_secrets/truststore-pass/password" + trait.CACertificates = []traitv1.CACertConfig{ + { + CertPath: "/etc/camel/conf.d/_secrets/my-ca/ca.crt", + PasswordPath: "/etc/camel/conf.d/_secrets/truststore-pass/password", + }, + } trait.CACertMountPath = "/custom/truststore/path" d := appsv1.Deployment{ @@ -782,94 +790,136 @@ func TestApplyJvmTraitWithCustomCACertMountPath(t *testing.T) { require.NoError(t, err) assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStore=/custom/truststore/path/truststore.jks") - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD)") + assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args, "-Djavax.net.ssl.trustStorePassword=$(cat /etc/camel/conf.d/_secrets/truststore-pass/password)") } -func TestGetAllCACertPaths(t *testing.T) { +func TestGetAllCACertEntries(t *testing.T) { trait, _ := createNominalJvmTest(v1.IntegrationKitTypePlatform) - trait.CACerts = []string{"/path/to/ca1.crt", "/path/to/ca2.crt"} + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca1.crt", PasswordPath: "/path/to/pass1"}, + {CertPath: "/path/to/ca2.crt", PasswordPath: "/path/to/pass2"}, + } trait.CACert = "" - paths := trait.getAllCACertPaths() - assert.Len(t, paths, 2) - assert.Contains(t, paths, "/path/to/ca1.crt") - assert.Contains(t, paths, "/path/to/ca2.crt") - - trait.CACerts = nil + trait.CACertPassword = "" + entries := trait.getAllCACertEntries() + assert.Len(t, entries, 2) + assert.Equal(t, "/path/to/ca1.crt", entries[0].CertPath) + assert.Equal(t, "/path/to/pass1", entries[0].PasswordPath) + assert.Equal(t, "/path/to/ca2.crt", entries[1].CertPath) + assert.Equal(t, "/path/to/pass2", entries[1].PasswordPath) + + trait.CACertificates = nil trait.CACert = "/path/to/legacy.crt" - paths = trait.getAllCACertPaths() - assert.Len(t, paths, 1) - assert.Contains(t, paths, "/path/to/legacy.crt") - - trait.CACerts = []string{"/path/to/ca1.crt", "/path/to/ca2.crt"} - trait.CACert = "/path/to/ca3.crt" - paths = trait.getAllCACertPaths() - assert.Len(t, paths, 3) - assert.Contains(t, paths, "/path/to/ca1.crt") - assert.Contains(t, paths, "/path/to/ca2.crt") - assert.Contains(t, paths, "/path/to/ca3.crt") - - trait.CACerts = []string{"/path/to/ca1.crt"} - trait.CACert = "/path/to/ca1.crt" - paths = trait.getAllCACertPaths() - assert.Len(t, paths, 1) - assert.Contains(t, paths, "/path/to/ca1.crt") - - trait.CACerts = nil + trait.CACertPassword = "/path/to/legacy-pass" + entries = trait.getAllCACertEntries() + assert.Len(t, entries, 1) + assert.Equal(t, "/path/to/legacy.crt", entries[0].CertPath) + assert.Equal(t, "/path/to/legacy-pass", entries[0].PasswordPath) + + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca1.crt", PasswordPath: "/path/to/pass1"}, + } + trait.CACert = "/path/to/ca2.crt" + trait.CACertPassword = "/path/to/pass2" + entries = trait.getAllCACertEntries() + assert.Len(t, entries, 2) + + trait.CACertificates = nil trait.CACert = "" - paths = trait.getAllCACertPaths() - assert.Len(t, paths, 0) + trait.CACertPassword = "" + entries = trait.getAllCACertEntries() + assert.Len(t, entries, 0) } func TestHasCACerts(t *testing.T) { trait, _ := createNominalJvmTest(v1.IntegrationKitTypePlatform) - trait.CACerts = nil + trait.CACertificates = nil trait.CACert = "" assert.False(t, trait.hasCACerts()) - trait.CACerts = []string{"/path/to/ca1.crt"} + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca1.crt", PasswordPath: "/path/to/pass1"}, + } trait.CACert = "" assert.True(t, trait.hasCACerts()) - trait.CACerts = nil + trait.CACertificates = nil trait.CACert = "/path/to/legacy.crt" assert.True(t, trait.hasCACerts()) - trait.CACerts = []string{"/path/to/ca1.crt"} + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca1.crt", PasswordPath: "/path/to/pass1"}, + } trait.CACert = "/path/to/ca2.crt" assert.True(t, trait.hasCACerts()) } -func TestHasCustomPassword(t *testing.T) { +func TestHasBaseTruststore(t *testing.T) { trait, _ := createNominalJvmTest(v1.IntegrationKitTypePlatform) - trait.CACertPassword = "" - assert.False(t, trait.hasCustomPassword()) + trait.BaseTruststore = nil + assert.False(t, trait.hasBaseTruststore()) + + trait.BaseTruststore = &traitv1.BaseTruststore{} + assert.False(t, trait.hasBaseTruststore()) - trait.CACertPassword = "/path/to/password" - assert.True(t, trait.hasCustomPassword()) + trait.BaseTruststore = &traitv1.BaseTruststore{ + TruststorePath: "/path/to/cacerts", + } + assert.False(t, trait.hasBaseTruststore()) + + trait.BaseTruststore = &traitv1.BaseTruststore{ + PasswordPath: "/path/to/pass", + } + assert.False(t, trait.hasBaseTruststore()) + + trait.BaseTruststore = &traitv1.BaseTruststore{ + TruststorePath: "/opt/java/openjdk/lib/security/cacerts", + PasswordPath: "/path/to/pass", + } + assert.True(t, trait.hasBaseTruststore()) } -func TestGetEffectiveTruststorePassword(t *testing.T) { +func TestValidateCACertConfig(t *testing.T) { trait, _ := createNominalJvmTest(v1.IntegrationKitTypePlatform) + trait.CACertificates = nil + trait.CACert = "" trait.CACertPassword = "" - assert.Equal(t, "changeit", trait.getEffectiveTruststorePassword()) + trait.BaseTruststore = nil + assert.NoError(t, trait.validateCACertConfig()) - trait.CACertPassword = "/path/to/password" - assert.Equal(t, "$(cat /path/to/password)", trait.getEffectiveTruststorePassword()) -} + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca.crt", PasswordPath: "/path/to/pass"}, + } + assert.NoError(t, trait.validateCACertConfig()) -func TestUseSystemTruststore(t *testing.T) { - trait, _ := createNominalJvmTest(v1.IntegrationKitTypePlatform) + trait.CACertificates = []traitv1.CACertConfig{ + {CertPath: "/path/to/ca.crt", PasswordPath: ""}, + } + assert.Error(t, trait.validateCACertConfig()) + + trait.CACertificates = nil + trait.CACert = "/path/to/ca.crt" + trait.CACertPassword = "" + assert.Error(t, trait.validateCACertConfig()) - trait.CACertUseSystemTruststore = nil - assert.False(t, trait.useSystemTruststore()) + trait.CACert = "/path/to/ca.crt" + trait.CACertPassword = "/path/to/pass" + assert.NoError(t, trait.validateCACertConfig()) - trait.CACertUseSystemTruststore = ptr.To(false) - assert.False(t, trait.useSystemTruststore()) + trait.CACert = "" + trait.CACertPassword = "" + trait.BaseTruststore = &traitv1.BaseTruststore{ + TruststorePath: "/path/to/cacerts", + } + assert.Error(t, trait.validateCACertConfig()) - trait.CACertUseSystemTruststore = ptr.To(true) - assert.True(t, trait.useSystemTruststore()) + trait.BaseTruststore = &traitv1.BaseTruststore{ + TruststorePath: "/path/to/cacerts", + PasswordPath: "/path/to/pass", + } + assert.NoError(t, trait.validateCACertConfig()) }
