Skip to content

Commit 1b6405b

Browse files
authored
Introduces immutability to OCI image by running everything as non-root user _daemon_ (#22)
1 parent 9937b72 commit 1b6405b

File tree

5 files changed

+207
-72
lines changed

5 files changed

+207
-72
lines changed

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,20 @@ To pull the image from the GitHub Container Registry, run the following command:
360360
sudo docker pull ghcr.io/openprinting/ghostscript-printer-app:latest
361361
```
362362

363+
Create a Docker volume:
364+
```sh
365+
sudo docker volume create ghostscript-printer-app
366+
```
367+
363368
To run the container after pulling the image from the GitHub Container Registry, use:
364369
```sh
365370
sudo docker run -d \
366371
--name ghostscript-printer-app \
367372
--network host \
368373
-e PORT=<port> \
374+
-v ghostscript-printer-app:/var/lib/ghostscript-printer-app \
375+
-v /dev/bus/usb:/dev/bus/usb:ro \
376+
--device-cgroup-rule='c 189:* rmw' \
369377
ghcr.io/openprinting/ghostscript-printer-app:latest
370378
```
371379

@@ -375,20 +383,32 @@ Alternatively, you can pull the image from Docker Hub, by running:
375383
sudo docker pull openprinting/ghostscript-printer-app
376384
```
377385

386+
Create a Docker volume:
387+
```sh
388+
sudo docker volume create ghostscript-printer-app
389+
```
390+
378391
To run the container after pulling the image from Docker Hub, use:
379392
```sh
380393
sudo docker run -d \
381394
--name ghostscript-printer-app \
382395
--network host \
383396
-e PORT=<port> \
397+
-v ghostscript-printer-app:/var/lib/ghostscript-printer-app \
398+
-v /dev/bus/usb:/dev/bus/usb:ro \
399+
--device-cgroup-rule='c 189:* rmw' \
384400
openprinting/ghostscript-printer-app:latest
385401
```
386402

387403
- `PORT` is an optional environment variable used to start the printer-app on a specified port. If not provided, it will start on the default port 8000 or, if port 8000 is busy, on 8001 and so on.
388404
- **The container must be started in `--network host` mode** to allow the Printer-Application instance inside the container to access and discover printers available in the local network where the host system is in.
389405
- Alternatively using the internal network of the Docker instance (`-p <port>:8000` instead of `--network host -e PORT=<port>`) only gives access to local printers running on the host system itself.
406+
- `-v ghostscript-printer-app:/var/lib/ghostscript-printer-app` maps a volume for persistent storage.
407+
- The following volume and device settings are crucial for USB printer access:
408+
- `-v /dev/bus/usb:/dev/bus/usb:ro` mounts the host's USB device directory read-only inside the container for USB printer access.
409+
- `--device-cgroup-rule='c 189:* rmw'` allows the container to read, write, and mknod to USB devices.
390410

391-
### Setting Up and Running gutenprint-printer-app locally
411+
### Setting Up and Running ghostscript-printer-app locally
392412

393413
#### Prerequisites
394414

@@ -424,18 +444,30 @@ Once the rock is built, you need to compile docker image from it.
424444
sudo rockcraft.skopeo --insecure-policy copy oci-archive:<rock_image> docker-daemon:ghostscript-printer-app:latest
425445
```
426446

447+
Create a Docker volume:
448+
```sh
449+
sudo docker volume create ghostscript-printer-app
450+
```
451+
427452
**Run the ghostscript-printer-app Docker Container**
428453

429454
```sh
430455
sudo docker run -d \
431456
--name ghostscript-printer-app \
432457
--network host \
433458
-e PORT=<port> \
459+
-v ghostscript-printer-app:/var/lib/ghostscript-printer-app \
460+
-v /dev/bus/usb:/dev/bus/usb:ro \
461+
--device-cgroup-rule='c 189:* rmw' \
434462
ghostscript-printer-app:latest
435463
```
436464
- `PORT` is an optional environment variable used to start the printer-app on a specified port. If not provided, it will start on the default port 8000 or, if port 8000 is busy, on 8001 and so on.
437465
- **The container must be started in `--network host` mode** to allow the Printer-Application instance inside the container to access and discover printers available in the local network where the host system is in.
438466
- Alternatively using the internal network of the Docker instance (`-p <port>:8000` instead of `--network host -e PORT=<port>`) only gives access to local printers running on the host system itself.
467+
- `-v ghostscript-printer-app:/var/lib/ghostscript-printer-app` maps a volume for persistent storage.
468+
- The following volume and device settings are crucial for USB printer access:
469+
- `-v /dev/bus/usb:/dev/bus/usb:ro` mounts the host's USB device directory read-only inside the container for USB printer access.
470+
- `--device-cgroup-rule='c 189:* rmw'` allows the container to read, write, and mknod to USB devices.
439471

440472
#### Setting up
441473

rockcraft.yaml

Lines changed: 147 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ platforms:
1515
amd64:
1616
armhf:
1717

18+
run-user: _daemon_
19+
1820
services:
19-
dbus:
20-
command: /scripts/run-dbus.sh
21+
avahi-daemon:
22+
command: /scripts/run-avahi.sh
2123
override: replace
2224
on-failure: restart
2325
startup: enabled
@@ -27,7 +29,7 @@ services:
2729
override: replace
2830
on-failure: shutdown
2931
startup: enabled
30-
after: [dbus]
32+
after: [avahi-daemon]
3133

3234
parts:
3335
pappl:
@@ -780,6 +782,7 @@ parts:
780782
stage-packages:
781783
- libsnmp40
782784
- python3-dev
785+
- libavahi-client-dev
783786
organize:
784787
ghostscript-printer-app/current/etc/hp/hplip.conf: etc/hp/hplip.conf
785788
prime:
@@ -1449,32 +1452,158 @@ parts:
14491452
- usr/share/ghostscript-printer-app
14501453
- -var
14511454
- -usr/share/man
1455+
after: [avahi, pappl-retrofit, pappl, ghostscript, libcupsfilters, libppd, cups-filters, foomatic-db]
1456+
1457+
avahi:
1458+
plugin: autotools
1459+
source: https://github.com/avahi/avahi.git
1460+
source-type: git
1461+
autotools-configure-parameters:
1462+
- --prefix=/usr
1463+
- --disable-qt3
1464+
- --disable-qt4
1465+
- --disable-qt5
1466+
- --disable-gtk
1467+
- --disable-gtk3
1468+
- --disable-gdbm
1469+
- --disable-python
1470+
- --disable-pygtk
1471+
- --disable-python-dbus
1472+
- --disable-mono
1473+
- --disable-monodoc
1474+
- --disable-manpages
1475+
- --disable-xmltoman
1476+
- --with-avahi-user=_daemon_
1477+
- --with-avahi-group=_daemon_
1478+
# - --with-avahi-priv-access-group=netdev
1479+
# - --with-distro=debian
1480+
- --disable-gobject
1481+
- --datadir=/usr/share
1482+
- --libdir=/usr/lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR}
1483+
- --with-systemdsystemunitdir=/usr/lib/systemd/system
1484+
- --localstatedir=/var
1485+
- --sysconfdir=/etc
1486+
build-packages:
1487+
- g++
1488+
- gcc
1489+
- gettext
1490+
- intltool
1491+
- libdaemon-dev
1492+
- libdbus-1-dev
1493+
- libevent-dev
1494+
- libexpat1-dev
1495+
- libglib2.0-dev
1496+
- libsystemd-dev
1497+
- xmltoman
1498+
override-build: |
1499+
craftctl default
1500+
# for reference sort systemd service files
1501+
sed -i \
1502+
-e 's|\(.*\)avahi-daemon -s.*|\1avahi-daemon -s --no-drop-root|g' \
1503+
-e 's|\(.*\)avahi-daemon -r.*|\1avahi-daemon -r --no-drop-root|g' \
1504+
${CRAFT_PART_INSTALL}/usr/lib/systemd/system/avahi-daemon.service
1505+
mkdir -p \
1506+
${CRAFT_PART_INSTALL}/usr/lib/systemd/system/multi-user.target.wants
1507+
ln -sf \
1508+
../avahi-daemon.service \
1509+
${CRAFT_PART_INSTALL}/usr/lib/systemd/system/multi-user.target.wants/avahi-daemon.service
1510+
build-environment:
1511+
- LD_LIBRARY_PATH: "${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$CRAFT_STAGE/usr/lib"
1512+
override-prime: |
1513+
set -eux
1514+
craftctl default
1515+
sed -i 's/use-ipv6=yes/use-ipv6=no/' ${CRAFT_PRIME}/etc/avahi/avahi-daemon.conf
1516+
sed -i 's|<user>messagebus</user>|<user>_daemon_</user>|; /<policy user="root">/,/<\/policy>/d' $CRAFT_PRIME/usr/share/dbus-1/system.conf
1517+
sed -i 's/<policy group="netdev">/<policy group="_daemon_">/g; s/<policy user="root">/<policy user="_daemon_">/g' $CRAFT_PRIME/usr/share/dbus-1/system.d/avahi-dbus.conf
1518+
stage-packages:
1519+
- libdaemon0
1520+
- libevent-2.1-7
1521+
- avahi-utils
1522+
- mdns-scan
1523+
# - libavahi-client3
1524+
# - libavahi-common3
1525+
stage:
1526+
- etc/avahi
1527+
- usr
1528+
- -usr/lib/**/libavahi-client.a
1529+
- -usr/lib/**/libavahi-common.a
1530+
- -usr/lib/**/libavahi-client.so*
1531+
- -usr/lib/**/libavahi-common.so*
1532+
- -usr/lib/**/*.acd
1533+
- -usr/lib/**/*.la
1534+
- -usr/lib/**/avahi
1535+
- -usr/lib/**/libavahi-glib*
1536+
- -usr/lib/**/libavahi-libevent*
1537+
- -usr/lib/**/libevent-*
1538+
# - -usr/lib/**/libnss_mdns*
1539+
- -usr/lib/**/pkgconfig
1540+
- -usr/include
1541+
- -usr/share/doc
1542+
- -usr/share/man
1543+
- -usr/share/locale
14521544
after: [pappl-retrofit, pappl, ghostscript, libcupsfilters, libppd, cups-filters, foomatic-db]
14531545

1454-
avahi-daemon:
1546+
utils:
14551547
plugin: nil
14561548
overlay-packages:
1457-
- avahi-daemon
1458-
- avahi-utils
1459-
- libnss-mdns
1460-
- mdns-scan
1461-
- dbus
14621549
- python3
1550+
- dbus
1551+
- libnss-mdns
1552+
override-prime: |
1553+
set -eux
1554+
craftctl default
1555+
1556+
# Set up Avahi Daemon runtime directory
1557+
mkdir -p "$CRAFT_PRIME/var/run/avahi-daemon"
1558+
chown 584792:584792 "$CRAFT_PRIME/var/run/avahi-daemon"
1559+
chmod 777 "$CRAFT_PRIME/var/run/avahi-daemon"
1560+
1561+
# Set up D-Bus runtime directory
1562+
mkdir -p "$CRAFT_PRIME/var/run/dbus"
1563+
chown 584792:584792 "$CRAFT_PRIME/var/run/dbus"
1564+
chmod 777 "$CRAFT_PRIME/var/run/dbus"
1565+
1566+
# Set up the CUPS SSL server root directory
1567+
CUPS_SERVERROOT="$CRAFT_PRIME/etc/cups/ssl"
1568+
mkdir -p "$CUPS_SERVERROOT"
1569+
chown 584792:584792 "$CUPS_SERVERROOT"
1570+
chmod 770 "$CUPS_SERVERROOT"
1571+
1572+
# Set up the state directory and file for the printer app
1573+
STATE_DIR="$CRAFT_PRIME/var/lib/ghostscript-printer-app"
1574+
mkdir -p "$STATE_DIR"
1575+
chown 584792:584792 "$STATE_DIR"
1576+
chmod 770 "$STATE_DIR"
1577+
1578+
# Create a state file inside the state directory
1579+
STATE_FILE="$STATE_DIR/ghostscript-printer-app.state"
1580+
touch "$STATE_FILE"
1581+
chown 584792:584792 "$STATE_FILE"
1582+
chmod 644 "$STATE_FILE"
1583+
1584+
# Ensure the spool directory is owned properly
1585+
SPOOL_DIR="$CRAFT_PRIME/var/spool/ghostscript-printer-app"
1586+
mkdir -p "$SPOOL_DIR"
1587+
chown 584792:584792 "$SPOOL_DIR"
1588+
chmod 770 "$SPOOL_DIR"
1589+
1590+
# Create and set permissions for the application log file
1591+
touch $CRAFT_PRIME/ghostscript-printer-app.log
1592+
chown 584792:584792 $CRAFT_PRIME/ghostscript-printer-app.log
1593+
chmod 644 $CRAFT_PRIME/ghostscript-printer-app.log
1594+
1595+
# Setting up permissions to USB backend
1596+
USB_BACKEND="$CRAFT_PRIME/usr/lib/ghostscript-printer-app/backend/usb"
1597+
chmod u+s "$USB_BACKEND"
1598+
after: [ghostscript-printer-app, avahi, pappl-retrofit, pappl, ghostscript, libcupsfilters, libppd, cups-filters, foomatic-db]
14631599

14641600
scripts:
14651601
plugin: dump
14661602
source: scripts/
14671603
organize:
1468-
run-dbus.sh: /scripts/run-dbus.sh
14691604
start-server.sh: /scripts/start-server.sh
1605+
run-avahi.sh: /scripts/run-avahi.sh
14701606
override-prime: |
14711607
set -eux
14721608
craftctl default
1473-
# Ensure the run-dbus.sh script has executable permissions
1474-
if [ -f "$CRAFT_PRIME/scripts/run-dbus.sh" ]; then
1475-
chmod +x "$CRAFT_PRIME/scripts/run-dbus.sh"
1476-
fi
1477-
# Ensure the start-server.sh script has executable permissions
1478-
if [ -f "$CRAFT_PRIME/scripts/start-server.sh" ]; then
1479-
chmod +x "$CRAFT_PRIME/scripts/start-server.sh"
1480-
fi
1609+
chmod +x $CRAFT_PRIME/scripts/*

scripts/run-avahi.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
set -eux
3+
4+
# Start dbus-daemon in the background
5+
/usr/bin/dbus-daemon --system --nofork &
6+
7+
# Wait for the D-Bus system bus to be ready
8+
while [ ! -e /var/run/dbus/system_bus_socket ]; do
9+
echo "Waiting for dbus-daemon to initialize..."
10+
sleep 1
11+
done
12+
13+
# Start avahi-daemon after dbus-daemon is ready
14+
/usr/sbin/avahi-daemon -f /etc/avahi/avahi-daemon.conf --no-drop-root --debug
15+
16+
# Keep the container running
17+
exec tail -f /dev/null

scripts/run-dbus.sh

Lines changed: 0 additions & 32 deletions
This file was deleted.

scripts/start-server.sh

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,16 @@ if [ -n "${PORT:-}" ]; then
99
fi
1010
fi
1111

12-
# Ensure the /etc/cups/ssl directory exists with proper permissions
13-
CUPS_SERVERROOT="/etc/cups/ssl"
14-
if [ ! -d "$CUPS_SERVERROOT" ]; then
15-
mkdir -p "$CUPS_SERVERROOT"
16-
fi
17-
chmod 755 "$CUPS_SERVERROOT"
18-
19-
# Ensure /var/lib/ghostscript-printer-app directory exists
20-
STATE_DIR="/var/lib/ghostscript-printer-app"
21-
22-
if [ ! -d "$STATE_DIR" ]; then
23-
mkdir -p "$STATE_DIR"
24-
fi
25-
chmod 755 "$STATE_DIR"
12+
# Wait for avahi-daemon to initialize
13+
while true; do
14+
if [ -f "/var/run/avahi-daemon/pid" ] || [ -f "/run/avahi-daemon/pid" ]; then
15+
echo "avahi-daemon is active. Starting ps-printer-app..."
16+
break
17+
fi
2618

27-
# Ensure ghostscript-printer-app.state file exists
28-
STATE_FILE="$STATE_DIR/ghostscript-printer-app.state"
29-
if [ ! -f "$STATE_FILE" ]; then
30-
touch "$STATE_FILE"
31-
fi
32-
chmod 755 "$STATE_FILE"
19+
echo "Waiting for avahi-daemon to initialize..."
20+
sleep 1
21+
done
3322

3423
# Start the ghostscript-printer-app server
35-
ghostscript-printer-app -o log-file=/ghostscript-printer-app.log ${PORT:+-o server-port=$PORT} server
24+
ghostscript-printer-app -o log-file="/ghostscript-printer-app.log" ${PORT:+-o server-port="$PORT"} server

0 commit comments

Comments
 (0)