How to add a new internal user to a rock¶
You can declare run-user in rockcraft.yaml
to specify which user you want to run a rock’s services with. If you don’t
specify a user, the services run as root by default. The run-user
key
only accepts a limited number of users, which could be a constraint for certain
container applications.
Mandatory packages or slices¶
To add a new internal user or group to a rock, two packages or their respective slices are needed:
base-files
: to create the base folders such as/root
and/home
,base-passwd
: to produce/etc/passwd
and/etc/group
files.
Creating the user and/or group¶
Invoking the useradd
and groupadd
commands can take place in a part’s
build step. This can be done by writing those commands in
override-build
field. However, the changes made by those commands will be
only applied on the build instance, and will not be available in the resulting
rock. Hence, $CRAFT_PART_INSTALL
should be passed as the root directory to
those two commands.
A full example¶
The following rockcraft.yaml
illustrates how to use the useradd
command
in the override-build
field inside a part.
For an example of how to access the user inside the rock, here’s a simple Python web service. The script will return an HTTP response containing the user that is running the web service:
#!/usr/bin/python3.12
import getpass
print(
f"""\
Content-Type: text/html
Serving by {getpass.getuser()} on port 8080\
"""
)
Then, add a service to rockcraft.yaml
that runs the web service:
services:
web-service:
override: replace
command: python3.12 -m http.server --cgi 8080
startup: enabled
user: myuser
working-dir: /
In the override-build
section of the part, let’s create a new user and a
new group. We will also copy the Python script to a cgi-bin
folder, and
give it the execute permission:
override-build: |
craftctl default
groupadd --root ${CRAFT_PART_INSTALL} mygroup
useradd -d /home/myuser -s /bin/bash --root ${CRAFT_PART_INSTALL} -g mygroup myuser
mkdir ${CRAFT_PART_INSTALL}/cgi-bin/
cp serve_user.py ${CRAFT_PART_INSTALL}/cgi-bin/
chmod +x ${CRAFT_PART_INSTALL}/cgi-bin/serve_user.py
The final rockcraft.yaml
file will look like this:
name: internal-user
base: bare
build-base: [email protected]
version: 'latest'
summary: Add an internal user inside a rock
description: Add an internal user inside a rock, and run a service with it.
platforms:
amd64:
services:
web-service:
override: replace
command: python3.12 -m http.server --cgi 8080
startup: enabled
user: myuser
working-dir: /
parts:
my-part:
plugin: nil
source-type: local
source: .
stage-packages:
- base-passwd_data
- base-files_base
- python3.12_standard
override-build: |
craftctl default
groupadd --root ${CRAFT_PART_INSTALL} mygroup
useradd -d /home/myuser -s /bin/bash --root ${CRAFT_PART_INSTALL} -g mygroup myuser
mkdir ${CRAFT_PART_INSTALL}/cgi-bin/
cp serve_user.py ${CRAFT_PART_INSTALL}/cgi-bin/
chmod +x ${CRAFT_PART_INSTALL}/cgi-bin/serve_user.py
With the part and web service in place, build the rock:
rockcraft pack
Next, we will convert the rock from an OCI archive to a Docker image using Skopeo:
sudo rockcraft.skopeo --insecure-policy copy oci-archive:internal-user_latest_amd64.rock docker-daemon:internal-user:latest
We can now check which internal user is running the service by running the image container:
id=$(docker run -d -p 8080:8080 internal-user:latest --verbose)
sleep 5
curl -s http://127.0.0.1:8080/cgi-bin/serve_user.py | grep "Serving by myuser"
docker rm -f "$id"
The response should contain the new user name:
Serving by myuser on port 8080