Skip to content

feat: build non-root image variants#310

Merged
thomascube merged 6 commits intomasterfrom
feature/non-root-306
Apr 15, 2025
Merged

feat: build non-root image variants#310
thomascube merged 6 commits intomasterfrom
feature/non-root-306

Conversation

@thomascube
Copy link
Copy Markdown
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

@thomascube thomascube requested a review from pabzm January 3, 2025 20:28
@thomascube
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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
Copy Markdown
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.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 5, 2025

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

2 similar comments
@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 5, 2025

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

@thomascube
Copy link
Copy Markdown
Member Author

@pabzm Sorry for the delay! Tests are finally passing. Please review again.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 1, 2025

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

Copy link
Copy Markdown
Member

@pabzm pabzm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a rebase onto the "master" branch to build (currently fails at apt-get update), but otherwise it looks good to me! I tested the apache-nonroot image with docker and rootless podman, and both works. 👍

@pabzm pabzm self-requested a review April 4, 2025 15:12
@pabzm pabzm mentioned this pull request Apr 4, 2025
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 force-pushed the feature/non-root-306 branch from 1fee4bb to b5c4aab Compare April 15, 2025 19:33
@thomascube
Copy link
Copy Markdown
Member Author

Rebased to master and builds are passing.

@thomascube thomascube merged commit ef4b8cc into master Apr 15, 2025
6 checks passed
@thomascube thomascube deleted the feature/non-root-306 branch April 15, 2025 19:46
luixxiul pushed a commit to mother-of-all-self-hosting/ansible-role-roundcube that referenced this pull request Mar 22, 2026
It has been implemented by roundcube/roundcubemail-docker#310. See: https://github.com/roundcube/roundcubemail-docker/blob/master/README.md#nonroot-image

- Remove added capabilities thanks to nonroot image

Signed-off-by: Suguru Hirahara <did:key:z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5>
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