# Transparently Distributing Your Private CA to Java Applications
> **Warning**: This tutorial requires an unreleased version of trust-manager that adds support for JKS: https://github.com/cert-manager/trust-manager/pull/122.
In this example, we will be configuring a pod that runs a Java application to transparently trust a private CA.
This tutorial works with Java applications running in Debian images. It needs to be adapted when using other distributions.
The first step is to install cert-manager and trust-manager:
```bash
helm upgrade -i -n cert-manager cert-manager jetstack/cert-manager --set installCRDs=true --wait --create-namespace
helm upgrade -i -n cert-manager trust-manager jetstack/trust-manager --wait
```
We will use a fake Jenkins server served over HTTPS using a certificate signed by a private CA managed by cert-maanger. Since deploying Jenkins requires lots of moving parts, we won't be deploying a real Jenkins instance. Instead, we will be creating an HTTP server that responds "I am a fake server". We will be using Caddy for that.
To deploy our fake Jenkins server, apply the following manifests:
```yaml
apiVersion: v1
kind: Service
metadata:
name: fakejenkins
namespace: cert-manager
spec:
selector:
name: fakejenkins
ports:
- protocol: TCP
port: 8443
targetPort: 8443
---
apiVersion: v1
kind: Pod
metadata:
name: fakejenkins
namespace: cert-manager
labels:
name: fakejenkins
spec:
containers:
- name: fakejenkins
image: caddy
ports:
- containerPort: 8443
volumeMounts:
- name: fakejenkinsfile
mountPath: /etc/Caddyfile
subPath: Caddyfile
- name: ca
mountPath: /var/run/secrets/ca
command:
["caddy", "run", "--config", "/etc/Caddyfile", "--adapter", "caddyfile"]
volumes:
- name: fakejenkinsfile
configMap:
name: fakejenkinsfile
- name: ca
secret:
secretName: trust-manager-example-ca-secret
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fakejenkinsfile
namespace: cert-manager
data:
Caddyfile: |
{
skip_install_trust
auto_https disable_redirects
}
https://fakejenkins.cert-manager.svc.cluster.local:8443 {
tls /var/run/secrets/ca/tls.crt /var/run/secrets/ca/tls.key
respond /cli* "I am a fake server" 200
header {
Content-Type "text/html"
X-Jenkins "2.387.2"
X-Hudson "1.395"
}
}
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: trust-manager-selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: trust-manager-example-ca
namespace: cert-manager
spec:
isCA: true
commonName: fakejenkins.cert-manager.svc.cluster.local
dnsNames: [fakejenkins.cert-manager.svc.cluster.local]
secretName: trust-manager-example-ca-secret
privateKey:
algorithm: ECDSA
size: 256
issuerRef:
name: trust-manager-selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
```
Now, let us create a bundle to distribute our private CA.
```yaml
apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
name: example-bundle
spec:
sources:
- secret:
name: trust-manager-example-ca-secret
key: tls.crt
target:
configMap:
key: "trust-bundle.pem"
additionalFormats:
jks:
key: trust-bundle.jks
```
> **Note**: The public CAs present in the container won't be available anymore. You have the possibility to distribute the public CAs along with your private CA by adding the source `useDefaultCAs: true`:
>
> ```yaml
> sources:
> - useDefaultCAs: true
> ```
Now, let us run a pod with `jenkins-cli.jar`. This pod relies on Java 8. Java 8 doesn't support loading PEM-encoded certificates. It only became possible to use PEM-encoded certificates with Java 11 and earlier.
```yaml
apiVersion: v1
kind: Pod
metadata:
name: jenkins
labels:
name: jenkins
spec:
volumes:
- name: trust-bundle-jks
configMap:
name: example-bundle
items:
- key: trust-bundle.jks
path: cacerts
terminationGracePeriodSeconds: 1
containers:
- name: jenkins
image: dynamictivity/jenkins-cli
env:
- name: JENKINS_URL
value: https://fakejenkins.cert-manager.svc.cluster.local:8443
volumeMounts:
- name: trust-bundle-jks
mountPath: /etc/ssl/certs/java/cacerts
subPath: cacerts
command: ["bash", "-c", "sleep 1000000"]
```
Let us see if the HTTPS connection works:
```bash
$ kubectl exec -it jenkins -- ./jenkins-cli-wrapper.sh
There's no Jenkins running at https://fakejenkins.cert-manager.svc.cluster.local:8443/cli?remoting=false, or is not serving the HTTP Duplex transport
```
This means that the TLS connection was successfully established. We can now check the contents of the Java trust store:
```bash
$ kubectl exec -i jenkins -- keytool -list -keystore /etc/ssl/certs/java/cacerts -storepass "changeit"
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
cn=fakejenkins.cert-manager.svc.cluster.local, Apr 14, 2023, trustedCertEntry,
Certificate fingerprint (SHA1): CC:63:19:3E:BA:58:17:23:64:2F:34:42:53:47:7D:41:2C:A7:95:5C
```
> **Warning**: right now, the JKS implementation uses a fixed password `changeit`.
>