Skip to content

Commit

Permalink
Merge pull request #17 from dduportal/feat/improve-sec
Browse files Browse the repository at this point in the history
breaking!(security): 💥 run as `nobody` user by default, supports read-only RootFS and control packages content

BREAKING CHANGE: default user, volumes and configurations are changed
  • Loading branch information
dduportal authored Sep 1, 2023
2 parents 9c023af + fa2c025 commit fcb867a
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 59 deletions.
43 changes: 24 additions & 19 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
FROM debian:stable

VOLUME /srv/releases/jenkins

EXPOSE 873
FROM debian:bookworm-20230814-slim

ARG TINI_VERSION=v0.19.0

## URL source: COPY cannot be used
# hadolint ignore=DL3020
ADD "https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini" /bin/tini

RUN chmod +x /bin/tini

COPY config/rsyncd.conf /etc/rsyncd.conf

COPY config/jenkins.motd /etc/jenkins.motd

## We always want the latest rsync version
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get install -y --no-install-recommends rsync && \
apt-get install --yes --no-install-recommends ca-certificates curl rsync && \
curl --silent --show-error --location --output /bin/tini \
"https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-$(dpkg --print-architecture)" && \
chmod +x /bin/tini && \
apt-get remove --purge --yes ca-certificates curl && \
apt-get autoremove --purge --yes && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["/bin/tini", "--"]
ARG RSYNCD_DIR=/rsyncd
ENV RSYNCD_DIR="${RSYNCD_DIR}"
RUN mkdir -p "${RSYNCD_DIR}/run" "${RSYNCD_DIR}/data" /etc/rsyncd.d && \
chown -R nobody:nogroup "${RSYNCD_DIR}"

COPY rsyncd.conf /etc/rsyncd.conf

WORKDIR /rsyncd/data

VOLUME ["/rsyncd/run","/rsyncd/data","/tmp"]

EXPOSE 873

USER nobody:nogroup

ENTRYPOINT ["/bin/tini","--"]

CMD [ "/usr/bin/rsync","--no-detach","--daemon","--config","/etc/rsyncd.conf" ]
CMD ["/usr/bin/rsync", "--no-detach","--daemon","--config","/etc/rsyncd.conf"]
2 changes: 1 addition & 1 deletion Jenkinsfile_k8s
Original file line number Diff line number Diff line change
@@ -1 +1 @@
parallelDockerUpdatecli([imageName: 'rsyncd'])
parallelDockerUpdatecli([imageName: 'rsyncd', rebuildImageOnPeriodicJob: false, buildDockerConfig : [targetplatforms: 'linux/amd64,linux/arm64']])
40 changes: 35 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
# README

This docker image is a rsync daemon, that serve files from directory /srv/releases/jenkins
This docker image is a rsync daemon, that serve files from directory /srv/releases/jenkins

## Testing
## Build the image

* `make run`
* `make shell`
```shell
docker build --tag rsyncd ./
```

`make test`, test that we can download, and more importantly that we can't upload
## Test the image

- Unit testing the image with [`container-structure-test`](https://github.com/GoogleContainerTools/container-structure-test):

```shell
container-structure-test test --image=rsyncd --config=cst.yml
```

- Manual acceptance testing of the the image with [`docker compose`](https://docs.docker.com/compose/):

```shell
$ cd ./tests
$ docker compose up --build --detach
$ sleep 2
$ rsync -av rsync://localhost:1873/jenkins
========================
==== JENKINS MIRROR ====
========================

**Read Only**

Feel free to reach out on https://www.jenkins.io/chat/#jenkins-infra/ with any question you may have

receiving file list ... done
drwxr-xr-x 96 2023/08/31 20:24:33 .
-rw-r--r-- 12 2023/08/31 20:24:37 sample.txt

sent 16 bytes received 111 bytes 254.00 bytes/sec
total size is 12 speedup is 0.09
```
34 changes: 0 additions & 34 deletions config/rsyncd.conf

This file was deleted.

50 changes: 50 additions & 0 deletions cst.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
schemaVersion: 2.0.0

metadataTest:
entrypoint: ["/bin/tini", "--"]
cmd: ["/usr/bin/rsync","--no-detach","--daemon","--config","/etc/rsyncd.conf"]
exposedPorts:
- "873"
user: nobody:nogroup
volumes: ["/rsyncd/data", "/rsyncd/run", "/tmp"]
workdir: /rsyncd/data

fileExistenceTests:
- name: "Rsyncd configuration file"
path: "/etc/rsyncd.conf"
shouldExist: true
uid: 0
gid: 0
- name: "Rsyncd configuration dir"
path: "/etc/rsyncd.d"
shouldExist: true
uid: 0
gid: 0
- name: "Tini process wrapper"
path: "/bin/tini"
shouldExist: true
isExecutableBy: "any"
uid: 0
gid: 0
- name: "Rsync"
path: "/usr/bin/rsync"
shouldExist: true
isExecutableBy: "any"
uid: 0
gid: 0
- name: "Rsync run dir"
path: "/rsyncd/data"
shouldExist: true
uid: 65534
gid: 65534
- name: "Rsync data dir"
path: "/rsyncd/run"
shouldExist: true
uid: 65534
gid: 65534

commandTests:
- name: "Tini is installed with the correct version"
command: "tini"
args: ["--version"]
expectedOutput: ["0.19.0"]
28 changes: 28 additions & 0 deletions rsyncd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# /etc/rsyncd: configuration file for
rsync daemon mode

# See rsyncd.conf man page for more options.

### Inside a restricted Docker container, no need to chroot / setuid / setgid
### You can override through the conf.d directory
# uid = nobody
# gid = nogroup
# use chroot = yes

max connections = 0

exclude = lost+found/
transfer logging = yes
log file = /dev/stdout
ignore nonreadable = yes
dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
port = 873
pid file = /rsyncd/run/rsyncd.pid

# Timeout in seconds
timeout = 300

# Merge any /etc/rsyncd.d/*.inc files (for global values that should stay in effect),
&merge /etc/rsyncd.d
# And then include any /etc/rsyncd.d/*.conf files (defining modules without any global-value cross-talk).
&include /etc/rsyncd.d
1 change: 1 addition & 0 deletions tests/data/jenkins/sample.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World
15 changes: 15 additions & 0 deletions tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Start this "lightly hardened" test with the command "docker compose up -d --build"
# Then check the result with the command "rsync -av rsync://localhost:1873/jenkins"
# which should shows the sample.txt file with the motd as header

services:
rsyncd-readonly-jenkins:
build: ../
read_only: true
user: 65534:65534 # nobody:nogroup
volumes:
- ./data:/rsyncd/data:ro
- ./rsyncd.d:/etc/rsyncd.d:ro
- ./jenkins.motd:/etc/jenkins.motd:ro
ports:
- 1873:873
File renamed without changes.
3 changes: 3 additions & 0 deletions tests/rsyncd.d/jenkins.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[jenkins]
path = /rsyncd/data/jenkins
comment = "Jenkins Read-Only Mirror"
7 changes: 7 additions & 0 deletions tests/rsyncd.d/rsyncd.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Read Only Service
# Any attempted uploads will fail
read only = true
# Downloads will be possible if file permissions on the daemon side allow them
write only = false

motd file = /etc/jenkins.motd

0 comments on commit fcb867a

Please sign in to comment.