1

I have a Helm Chart. Which on deployment creates the following Kubernetes resources:

  1. A SSL enabled Service
  2. A Container created with my Docker image which internally runs a Java process that communicates with the above service.
  3. Kubernetes Secrets (SSL certificates and access keys), that are mounted inside the above container.

The problem is my Container can not talk to my Service unless I add the SSL certificate to Java certificates. I do this by running the following command manually inside my docker with root user.

cd ${JAVA_HOME}/jre/lib/security 

keytool -keystore cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias myservicecert -file /home/myuser/.myservice/certs/public.crt

I want to automate the above steps but facing issues:

  • I can not perform above steps inside the Dockerfile since the certificate is not available at that time. Obivious.
  • I can not add these steps in entrypoint.sh file of the docker because entrypoint file is executed by a different user than the root.
  • Another solution that I could think of is that change the permission of path ${JAVA_HOME}/jre/lib/security/cacerts to 777 so that I can run these commands in entrypoint.sh without an issue. But I am not sure if this is the correct way to go due to security reasons. Suggestions on this ?
  • I do not want to set a custom location for certificates using Djavax.net.ssl.trustStore because then java will not have access to root certificates.

What is correct way to achieve this?

Neelesh
  • 533
  • 2
  • 15

2 Answers2

1

TL;DR

You can add the certificate to the keystore in an initContainer. The keystore can be shared between the initContainer and the container using a volume.


In this example we're mounting the tls-secret to the pod as a Kubernetes Secret. The tls-secret contains the tls.crt which needs to be added to the keystore. We add the certificate to the keystore in the initContainer after copying the security files into a volume which is mounted to the pod's container.

apiVersion: v1
kind: Pod
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  containers:
  - name: myapp
    image: openjdk:8-jdk-slim-buster
    command:
    - bash
    - -c
    - |
      keytool -list -keystore /usr/local/openjdk-8/jre/lib/security/cacerts -alias local
      sleep infinity
    volumeMounts:
    - mountPath: /usr/local/openjdk-8/jre/lib/security
      name: cacerts
  initContainers:
  - name: init-cacerts
    image: openjdk:8-jdk-slim-buster
    command:
    - bash
    - -c
    - |
      cp -R /usr/local/openjdk-8/jre/lib/security/* /cacerts/
      keytool -import -noprompt -trustcacerts -alias local -file /security/tls.crt -keystore /cacerts/cacerts -storepass changeit
      keytool -list -keystore /cacerts/cacerts -alias local
    volumeMounts:
    - mountPath: /cacerts
      name: cacerts
    - mountPath: /security
      name: tls
  volumes:
  - name: cacerts
    emptyDir: {}
  - name: tls
    secret:
      secretName: tls-secret
      defaultMode: 0400

shared keystore

masseyb
  • 2,503
  • 1
  • 11
  • 17
  • It will replace the original `cacerts` with the one from `init-container` right ? So any additional certificates added by base image will be lost. – Neelesh Apr 16 '21 at 10:13
  • Yes. Just an example. Can mount and add all the certs you want. – masseyb Apr 16 '21 at 10:34
0

The easiest way is probably to allow running the keytool command using sudo.

You may need to install sudo in your Dockerfile and then you can set up /etc/sudoers to allow the user running entrypoint.sh to run that specific command (without a password). Have a look at this answer on Unix for how to do it.

All you need to do then is locate the certificate and run

sudo keytool -keystore cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias myservicecert -file /home/myuser/.myservice/certs/public.crt

In entrypoint.sh

Alternatively you can install a script when building your container that sets up the certificate and installs it and allow that to be run with sudo. That way you don't open up the possibility to add more certificates if someone gains access to the container

Raniz
  • 10,048
  • 1
  • 28
  • 61
  • I did install `sudo` in Dockerfile and modified `/etc/sudoers` accordingly. But i still can't run any command with `sudo` option. Some restriction put by base image may be. ERROR : `effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?` – Neelesh Apr 16 '21 at 10:09
  • Sounds like something is off with your system. Search for the error and see if you can find a solution. [Here's](https://stackoverflow.com/questions/18607003/sudo-effective-uid-is-not-0-is-sudo-installed-setuid-root) one possible solution. – Raniz Apr 16 '21 at 16:52