1. Overview

Alpine Linux is a lightweight Linux distribution that has become popular for building Docker images. It incorporates the Busybox Linux core utilities and the Musl Libc C standard library implementation. Docker images created with Alpine Linux have a small memory footprint compared to those created with the majority of other Linux distributions.

The root user is the default user in the official Alpine Linux Docker image. This tutorial will examine how we can create other user accounts for our image and use them by default.

2. The Dockerfile

The Dockerfile USER command sets the default user account and group during the image build phase. The account specified will be used in all subsequent RUN commands. The account has to be created in the Dockerfile or it has to pre-exist in the Alpine Docker image:

FROM alpine:latest
RUN adduser -D baeldung
USER baeldung

Here, we create the user account baeldung with the adduser command. Moreover, by using the -D option, the user is created without a password. The USER command sets the current user to baeldung.

Next, we build an image and run a new container to test our Dockerfile:

$ sudo docker image build -q -t baeldung-alpine .
$ sudo docker container run --rm -it baeldung-alpine
/ $ whoami

Indeed, the logged-on user is baeldung. Note that the Alpine distribution doesn’t have the useradd command.

3. Setting a Password

To set a password in the Dockerfile, we use the chpasswd command:

FROM alpine
RUN adduser baeldung;echo 'baeldung:123' | chpasswd
USER baeldung

As can be seen, we use the pipe operator to send input to the chpasswd command. The chpasswd command accepts string input in the user:password format.

4. Dealing With Permissions

Until now, we’ve created a new user and set a password. We should note, however, that our user has limited privileges. We can verify this if we try to install a package with the apk command:

$ apk add apache2
ERROR: Unable to lock database: Permission denied
ERROR: Failed to open apk database: Permission denied

Indeed, our user lacks the required permissions to install new packages. Moreover, if we try to use the sudo command to run commands as root, we’ll find out that it’s missing from the official Alpine image.

To overcome missing permissions, we can install the sudo package and permit our user to run the sudo command.

However, since the motivation for using the Alpine Docker image is the low memory footprint, we may want to use the doas package instead. The doas package is a lightweight alternative to the sudo package. Let’s modify our Dockerfile to install the doas package:

FROM alpine
RUN     apk add doas; \
        adduser baeldung; \
        echo 'baeldung:123' | chpasswd; \
        echo 'permit baeldung as root' > /etc/doas.d/doas.conf
USER baeldung

Here, we do most of the work in the RUN command:

  1. Install the doas package with the apk command
  2. Create the baeldung user with the adduser command
  3. Set a password with the chpasswd command
  4. Create the /etc/doas.d/doas.conf file
  5. Use doas.conf to permit the baeldung user to run commands as root with the doas command

As a result, the container will start with the baeldung user.

5. Add User to Group

Instead of permitting our user to run commands as root, we should add our user to the wheel group. The wheel group is equivalent to the sudo group in Debian-like systems for permitting a user to run commands as root.

The doas command, however, isn’t configured to grant root permissions to the members of the wheel group by default. To allow this, we have to configure it the doas.conf file. Let’s modify our Dockerfile once more:

FROM alpine
RUN     apk add doas; \
        adduser baeldung -G wheel; \
        echo 'baeldung:123' | chpasswd; \
        echo 'permit :wheel as root' > /etc/doas.d/doas.conf
USER baeldung

Here, the adduser command creates the user baeldung as before, but now, it adds the user to the wheel group.

Moreover, we configure the doas.conf file to permit the wheel group to run commands as root. Note here that we’ve placed a colon character in front of the group name.

To verify that the user can run commands as root, let’s build and run our image:

$ sudo docker image build -qt baeldung-alpine .
$ sudo docker container run --rm -it baeldung-alpine
/ $ whoami
/ $ doas ls -all /root
doas (baeldung@cc3e91fba527) password:
total 8
drwx------ 2 root root 4096 Aug 9 08:47 .
drwxr-xr-x 1 root root 4096 Sep 17 13:01 ..

As we can see, after building the image, we create a new container. In the container, we first check the user that is running the shell. As expected, it’s the baeldung user.

Then, we try to access the /root folder with the help of the doas command. After entering our password, we can list the contents of the /root folder.

6. Other Options

Apart from adding a user to a group and setting the user’s password, there are a few more interesting options in the adduser command and the doas command configuration.

6.1. Creating a System User

A system user can be used for running background services. System users have a different range of user IDs and may not be present on a login screen. We can create a system user with the adduser command:

$ adduser -S baeldung

Here, we used the -S option to create a system user. In addition, the –system option has the same effect.

6.2. Disable doas Password

Although this may pose security risks, we can configure the doas command so that it doesn’t ask for a password when a user wants to execute a command as root. This is configured in the /etc/doas.d/doas.conf file:

$ echo 'permit nopass :wheel as root' >> /etc/doas.d/doas.conf

6.3. Persistent Password

Another option of the doas command configuration is to make the password persistent. In other words, if the user enters their password once, then the doas command won’t ask for it over and over in subsequent executions:

$ echo 'permit persist :wheel as root' >> /etc/doas.d/doas.conf

As a result, the doas command won’t ask for a password every time. Note that for added security, the password will persist only for a limited amount of time.

7. Creating a User With Entrypoint Script

In the previous sections, we saw how we can create a user as part of our image definition. Another option is to create an ENTRYPOINT script and create the user in that script. Docker will execute the ENTRYPOINT script upon container start. Let’s create a sample script and save it to the file entrypoint.sh:

apk add doas
adduser baeldung -D -G wheel
echo 'baeldung:123' | chpasswd
echo 'permit :wheel as root' > /etc/doas.d/doas.conf
su baeldung

The above script is similar to the shell commands we entered in the Dockerfile examples of the previous sections. So, to recap:

  • Install the doas package
  • Create the baeldung user
  • Add the baeldung user to the wheel group
  • Set a password for the baeldung user
  • Configure the wheel group in the doas configuration
  • Switch from root to the baeldung user

Next, we edit our Dockerfile so that it uses the entrypoint.sh script:

FROM alpine:latest
COPY entrypoint.sh /root/entrypoint.sh
ENTRYPOINT /root/entrypoint.sh

An important note is that we should grant the execute privilege to entrypoint.sh, otherwise our container will fail to execute it.

Now, let’s build and run our container and verify that the user is created:

$ sudo docker container run --rm -it baeldung-alpine:latest
/ $ whoami
/ $ groups

Indeed, after running, we are currently logged in with the baeldung user. Then, we use the groups command to verify that our user belongs to the wheel group.

8. Conclusion

In this article, we examined how we can create a new user in an Alpine Linux Docker container and permit the user to run commands as an administrator. Finally, we looked at some interesting options for the corresponding commands.