how to add certificate to POD/Container 's cert store when root filesystem is read-only

Viewed 596

I have a .net core application which is dockerized and running in Kubernetes cluster (AKS).

I want to apply securityContext readOnlyRootFilesystem = true to satisfy the requirement Immutable (read-only) root filesystem should be enforced for containers.

securityContext: privileged: false readOnlyRootFilesystem: true

For .net core app I want to read TLS certificate and want to add into POD/Container's certificate store and to do this in startup I have below code,

var cert = new X509Certificate2(Convert.FromBase64String(File.ReadAllText(Environment.GetEnvironmentVariable("cert_path"))));
                AddCertificate(cert, StoreName.Root);

The problem is when I set readOnlyRootFilesystem = true, I am getting below error from the app,

EXCEPTION: System.Security.Cryptography.CryptographicException: The X509 certificate could not be added to the store. ---> System.IO.IOException: Read-only file system at System.IO.FileSystem.CreateDirectory(String fullPath)

It's saying for read only file system I can't add certificate. Is there a way to overcome this problem?

Update

If I set emptyDir: {}, I am getting below error? Where I can add it?

spec.template.spec.volumes[0].csi: Forbidden: may not specify more than 1 volume type

          volumeMounts:
        - name: secrets-store
          mountPath: /app/certs
      securityContext:
        privileged: false
        readOnlyRootFilesystem: true
        allowPrivilegeEscalation: false
        runAsNonRoot: true
        runAsUser: 1000   
  volumes:
  - name: secrets-store
    emptyDir: {}
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: azure-kvname
2 Answers

At the location you have defined as the path of the cert store, attach a volume that is not read-only. If you only want that data to last as long as the pod exists, an emptyDir type volume will fit the bill nicely.

For example, if you are creating pods with a deployment like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: ct
  name: ct
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ct
  template:
    metadata:
      labels:
        app: ct
    spec:
      containers:
      - image: myapp
        name: myapp
        env:
        - name: cert_path
          value: /etc/certstore
        securityContext:
          readOnlyRootFilesystem: true

You could set up the emptyDir as follows:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: ct
  name: ct
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ct
  template:
    metadata:
      labels:
        app: ct
    spec:
      containers:
      - image: myapp
        name: myapp
        env:
        - name: cert_path
          value: /etc/certstore
        securityContext:
          readOnlyRootFilesystem: true
        volumeMounts:
        - mountPath: /etc/certstore
          name: certstore
      volumes:
      - name: certstore
        emptyDir: {}

Other types of volumes would work as well. If you wanted to persist these certificates as your pods are cycled, then a persistentVolumeClaim could be used to get you a persistent volume.

The emptyDir won't be read-only, but the rest of the container's root filesystem will be, which should satisfy your security requirement.

Generally, the solution suggested by programmerq looks fine.

As for this error:

spec.template.spec.volumes[0].csi: Forbidden: may not specify more than 1 volume type

Once upon a time I got this error because I have tried to start a specific volume type, but went back to emptyDir using kubectl apply. However, the old volume still existed on the server side. kubectl tried to combine two volume specifications, which caused a problem.

On this site you can find an explanation:

  • If the admission plugin is turned on, the administrator may specify a default StorageClass. All PVCs that have no storageClassName can be bound only to PVs of that default. Specifying a default StorageClass is done by setting the annotation storageclass.kubernetes.io/is-default-class equal to "true" in a StorageClass object. If the administrator does not specify a default, the cluster responds to PVC creation as if the admission plugin were turned off. If more than one default is specified, the admission plugin forbids the creation of all PVCs.

See also this question.

Make sure your volume is created correctly, the old one does not exist and then try the solution suggested by programmerq.

Related