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

breaking!(security): 💥 run as nobody user by default, supports read-only RootFS and control packages content #17

Merged
merged 11 commits into from
Sep 1, 2023
Merged
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"]
Comment on lines +16 to +25
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Post-review: the build arg RSYNCD_DIR is not valuable since it cannot be consumed by the VOLUME:

  • either find a way to consume it for the WORKDIR and VOLUME to avoid repetition (I failed with multi platform builds while it works on single platform: smells like buildx issue)
  • or do not complexify code and duplicate paths


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"]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Post-review: incoherent formatting with spaces

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
Comment on lines +24 to +28
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Post review: add a comment about the & prefixes (link to rsyncd.conf reference?)

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"
Copy link
Contributor Author

@dduportal dduportal Sep 4, 2023

Choose a reason for hiding this comment

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

Post review: long flags

Suggested change
# Then check the result with the command "rsync -av rsync://localhost:1873/jenkins"
# Then check the result with the command "rsync --archive --verbose 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
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Post review: note about why a >1024 port in this test case

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
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Post-review: comment why the subdir (ref. stanza name which is an rsync module)

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