Awesome
What
This tool is a more advanced adduser
/ useradd
for your Alpine and BusyBox based Docker images.
For example, this tool may create a custom OS user with a custom ID inside pre-made Docker images, which perhaps already have a custom user defined and rebuilding the Docker image just to have your custom user in it is not an option.
Why
Reason 1
Now, more and more server apps try to go with the current meta of being available on Kubernetes, etc. This is a good idea, however it's often not well executed.
Almost all of the popular server apps are not cloud-native. Their structure is still of some legacy kind.
Examples are Mattermost, Gitea, Nextcloud.
These server apps have Helm Charts available. However, applying best practices, especially the ones regarding security are not easy to achieve.
Especially, when talking about the podSecurityContext
. The fsGroup
option is either not respected properly, which leads to broken deployments, or it's not even available and you have to add it yourself to the Helm Chart.
For example, take the Gitea Helm Chart as an example. You are allowed to set the podSecurityContext
:
https://gitea.com/gitea/helm-chart/src/commit/d94226765d6e1f197a3112e1b1abbcd73a8bea33/values.yaml#L19-L20
But, if you provide your custom fsGroup
value, then the deployment will be broken. Why?
https://github.com/go-gitea/gitea/blob/66f2210feca0b50d305a46a203c2b3d2f4d3790b/Dockerfile.rootless#L39-L48
Because the user and group ID of 1000
is hard-coded into the Docker image.
Now, imagine you have an sshfs
mount, which requires you using the user of the ID 9234
.
The hard-coded 1000
inside the image breaks usage of this sshfs
mount, just because it does not let you define a custom user with a custom ID.
To make all this work more smoothly, this tool aims to delete the existing user in that Docker image and then recreate it with your custom user, which has an ID defined by you, instead of being forced to use the randomly chosen hard-coded user ID.
Reason 2
You may just as well use this tool as a better adduser
where the actual adduser
or useradd
(like the one in Alpine) have arbitrary and unnecessary restrictions, like for example limiting the UID/GID size to 256000.
How
Example using the rootless Docker image for Gitea:
## Get the binary.
## The default Docker Tag provides the Alpine (musl) based binary.
FROM akito13/userdef AS base
## Pull the image you want to modify the executing user of.
FROM gitea/gitea:1.16.5-linux-amd64-rootless
## We temporarily need to use the root user,
## as we are doing administrative tasks, like e.g. modifying an OS user.
USER root:root
COPY --from=base /userdef /userdef
## 1. Change the existing user.
## 2. Use that user to `chown` relevant folders.
## 3. Remove the binary, because the user has been changed,
## i.e. our job is done here.
RUN /userdef -h=/var/lib/gitea/git -n=git -u=9234 -g=9234 && \
chown git:git -R /var/lib/gitea /etc/gitea && \
rm -f /userdef
## Switch to the now relevant executing user.
USER 9234:9234
## Taken from https://github.com/go-gitea/gitea/blob/66f2210feca0b50d305a46a203c2b3d2f4d3790b/Dockerfile.rootless#L71-L72
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD []
This way, you get the behaviour of the original Docker image, but instead being forced to use the hard-coded user ID, you adjust the user inside the image to the one you specify.
For a live example, run nimble example
.
CLI Usage
Usage:
userdef -n=<user-name> -u=<user-id> -h=<user-home>
[-g=<user-group-id>] [-l | -l=[true|false]]
[-c=<path-to-config-file> | <path-to-config-file>]
Examples:
userdef --help
userdef -h=/var/lib/gitea/git -n=git -u=9234 -g=9234
userdef -h=/home/langlang -n=langlang -u=290111 -g=290111 --long
userdef -h=/overwrites/home/value/in/userdef.json -l=true /path/to/userdef.json
Options:
-n, --name Name of the user to modify or add.
-u, --uid User ID.
-h, --home Path to user's home.
-c, --config (Optional) Provide path to configuration file.
-g, --gid (Optional) Group ID. If empty, then GID will be same as UID.
-l, --long (Optional) Whether long IDs (greater than 256000) are guaranteed to be supported.
-v, --version App version information.
--help This help text.
Hints:
* If a user with the provided name already exists,
then it will be deleted and a new one will be created,
to replace the original one.
* Providing a configuration file works by using the `--config` option or
by providing the path without using any option.
* You may replace the equal signs with colons when providing CLI arguments.
Example: userdef -h:/home/langlang -n:langlang -u:290111 -g:290111 --long
* You also may replace the equal signs with nothing when providing CLI arguments.
Example: userdef -h/home/langlang -nlanglang -u290111 -g290111 --long
Alternative Sources
Last week i bought a chain saw with a twisted handle. Perhaps i wasn't careful, but by accident it chopped one of my arm off, then i thought to myself "gosh, this is POWERFUL!". [...]
---- Xah Lee
If you are one of those enthusiastic Linux fans, who want to do anything possible on Linux, even if it does not make sense, do not worry, I have you covered.
Installing the binary using Nim's package manager:
nimble install userdef
Installing the binary using Github Releases:
curl -fsSLo userdef https://github.com/theAkito/userdef/releases/download/0.3.0/userdef-github-0.3.0-linux-amd64
chmod +x userdef
mv userdef /usr/bin/userdef
Where
Docker containers running Docker images based on Linux. You will need it most likely on BusyBox based images, like Alpine.
Only Linux is officially supported.
Works on libc
(normal Linux) and musl
(Alpine, Busybox, etc.) based Docker images.
For further information on this topic, please visit this project's Docker Hub page.
Goals
- Reliability
Project Status
Stable Beta.
This app is well tested & works, but needs more testing and feedback from 3rd parties. --> Please help!
TODO
Make ID adjustableMake Name adjustableRead from config.jsonSupport long and short IDsAdd base DockerfileAdd support for multi-arch Docker imageAdd some kind of Continuous Delivery for binary in Docker imageAdd meaningful example in READMEAdd libc based Docker images for binary provision (Alpine is musl based)Add CLI Usage Info to READMEPublish to NimblePublish to Awesome DockerUse Nimscript instead of Bash for Build scriptsAddnim.cfg
for optimisednimble install
buildTest with GID different from UIDProvide BUILD_VERSION, BUILD_REVISION, BUILD_DATE in Docker Release imagesAdd Github ReleaseUse nim-useradd library for the backend- Add meaningful practical examples
- Parse root Dockerfile and extract correct original user ID and user name
License
Copyright © 2022-2023 Akito the@akito.ooo
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.