Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: build non-root image variants #310

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

thomascube
Copy link
Member

Adds an additional stage to the Dockerfile to create images with default user www-data. Publish as roundcube/roundcubemail-nonroot for distinction.

Execution of /usr/sbin/locale-gen won't work as non-root user and thus the locale is already set in the Docker image.

Refs: #306

Adds an additional stage to the Dockerfile to create images with default user www-data.
Publish as roundcube/roundcubemail-nonroot for distinction.

Execution of /usr/sbin/locale-gen won't work as non-root user and thus the locale is already set in the Docker image.

Refs: #306
@thomascube thomascube requested a review from pabzm January 3, 2025 20:28
@thomascube
Copy link
Member Author

@pabzm @maitredede a first test with a local Kubernetes cluster based on examples/kubernetes.yam worked as expected. This is the deployment resource I changed:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: roundcubemail
  labels:
    service: roundcubemail
spec:
  replicas: 1
  selector:
    matchLabels:
      service: roundcubemail
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        service: roundcubemail
    spec:
      initContainers:
      - name: init-volumes
        image: alpine:latest
        imagePullPolicy: IfNotPresent
        command: ["sh", "-c", "chown -R 82:82 /var/www/html /tmp/roundcube-temp"]
        volumeMounts:
        - name: www-data
          mountPath: /var/www/html
        - name: temp-data
          mountPath: /tmp/roundcube-temp  
      containers:
      - name: roundcubemail
        image: thomascube/roundcubemail:latest-fpm-alpine-nonroot
        imagePullPolicy: Always
        env: # removed for readability
        ports:
        - containerPort: 9000
        volumeMounts:
        - mountPath: /var/www/html
          name: www-data
        - mountPath: /tmp/roundcube-temp
          name: temp-data
        securityContext:
          runAsUser: 82
          runAsGroup: 82
      restartPolicy: Always
      volumes:
      - name: www-data
        persistentVolumeClaim:
          claimName: roundcubemail-www-pvc
      - name: temp-data
        persistentVolumeClaim:
          claimName: roundcubemail-temp-pvc

I needed to add an init-container to fix the permissions of the mounted persistent volumes. The roundcube container itself runs as user 82 (www-data). In my example I enforced it using securityContext but with the user being set in the image already, this actually isn't necessary.

@maitredede
Copy link

A namespace with security labels (https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels/) needs more things :

apiVersion: v1
kind: Namespace
metadata:
  name: mailserve
  labels:
    pod-security.kubernetes.io/enforce: restricted

The security context of the pod and the container must be adapted. I also added fsGroup, and set user/group at pod level, so the initcontainer is not required :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: roundcube
  labels:
    service: roundcube
spec:
  replicas: 1
  selector:
    matchLabels:
      service: roundcube
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        service: roundcube
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 82
        runAsGroup: 82
        fsGroup: 82
        seccompProfile:
          type: RuntimeDefault
      # initContainers:
      # - name: init-volumes
      #   image: alpine:latest
      #   imagePullPolicy: IfNotPresent
      #   command: ["sh", "-c", "chown -R 82:82 /var/www/html /tmp/roundcube-temp"]
      #   volumeMounts:
      #   - name: www-data
      #     mountPath: /var/www/html
      #   - name: temp-data
      #     mountPath: /tmp/roundcube-temp  
      containers:
      - name: roundcubemail
        image: thomascube/roundcubemail:latest-fpm-alpine-nonroot
        imagePullPolicy: Always
        env: # removed for readability
        ports:
        - containerPort: 9000
          name: php-fpm
        volumeMounts:
        - mountPath: /var/www/html
          name: www-data
        - mountPath: /tmp/roundcube-temp
          name: temp-data
        securityContext:
          # runAsUser: 82
          # runAsGroup: 82
          allowPrivilegeEscalation: false
          capabilities:
            drop:
              - ALL
      restartPolicy: Always
      volumes:
      - name: www-data
        persistentVolumeClaim:
          claimName: roundcubemail-www-pvc
      - name: temp-data
        persistentVolumeClaim:
          claimName: roundcubemail-temp-pvc
```yaml

@pabzm
Copy link
Member

pabzm commented Jan 17, 2025

I would prefer to publish the images with suffixed tags instead of a whole new namespace. It makes them more visible.

docker automates using privileged ports, but e.g. podman doesn't. So to be able to run these images it would either take to explicitly set the required capability, or to run on another port. Would you be open to make the apache process listen on port 8000 or similar? That could be done with a simple line of sed in the Dockerfile: RUN sed -i 's/^Listen 80$/Listen 8000/' /etc/apache2/ports.conf.

I think we should either find a way to apply a give locale, or die hard in case it is set. Silently swallowing a given locale is unpleasantly surprising to users, I think.

@thomascube
Copy link
Member Author

I would prefer to publish the images with suffixed tags instead of a whole new namespace. It makes them more visible.

OK. I wasn't sure which way to go here. Then I thought that we already have quite a matrix of tags and adding a non-root variant to it just makes it overly complex. But I'm fine with your suggestion.

make the apache process listen on port 8000 or similar?

I'll try to implement this.

find a way to apply a give locale, or die hard in case it is set.

So far I didn't succeed in finding a way without root privileges but somebody else might have an idea.

Copy link

github-actions bot commented Feb 5, 2025

@pabzm
🛎️ This PR has had no activity in two weeks.

1 similar comment
Copy link

@pabzm
🛎️ This PR has had no activity in two weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants