Setup a LAN container registry with Podman and self-signed certs
2023-02-14
Prerequisites
- RHEL-compatible or Fedora-based Linux distribution
- a LAN (presumably with access to other machines on the LAN)
- Podman
- OpenSSL
Install the required packages:
sudo dnf install '@container-management' openssl-devel openssl
Self-signed certificate
The benefit of having at least a self-signed certificate is that you can encrypt the traffic to your container registry over your LAN. You know, in the event there is an unknown entity hiding in your house or office, snooping on your local HTTP traffic. A self-signed certificate is fine for LAN-wide access, because presumably you trust yourself; however, if you want something that is accessible from the public Internet then you’d want a certificate signed by a Certificate Authority, because other people on the public Internet using it don’t know if they should trust you to encrypt their HTTP traffic.
Create directories to hold the self-signed certificate and htpasswd authorization.
mkdir -p ~/registry/{auth,certs}
Create a subjectAltName configuration file (san.cnf). This will contain
information and configure some settings about the self-signed
certificate. The information I have in the [req_distinguished_name]
and [alt_names]
sections are for an example; you should enter
information that is relevant to your use-case.
Change into the ~/registry/certs
directory and create a file named
san.cnf
with the following contents:
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = US
stateOrProvinceName = Illinois
localityName = Chicago
commonName = 127.0.0.1: Self-signed certificate
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 10.0.0.128
DNS = something.local
Make sure to change the IP.1
and DNS
values to the LAN IP address
and hostname of your registry server machine.
Make sure you’re in the ~/registry/certs
directory. Now generate the
key:
openssl req -new -nodes -sha256 -keyout something.local.key -x509 -days 365 -out something.local.crt --config san.cnf
htpasswd authentication
Now we need generate an htpasswd file so that you can authenticate to the registry server. We’ll use the registry:2.7.0 container image with an entrypoint to do this. First, change into the auth subdirectory.
Note: you must use the 2.7.0 tag for the registry image, because it seems to be the only one that has the htpasswd command available for the entrypoint flag.
cd ../auth
podman run --rm --entrypoint htpasswd registry:2.7.0 -Bbn USERNAME PASSWORD > htpasswd
The USERNAME
and PASSWORD
you choose will be used with the
podman login
command to authenticate you to the registry server.
Deploy the registry server
Create a directory on the host to store the registry data:
sudo mkdir -p /var/lib/registry
To deploy the registry server, run:
Note: The port mapping of 443:443 is for if you have no other web server running on the machine running the registry server. If you do have another web server, then change the port mapping to 5000:5000.
sudo podman run \
--privileged \
-d \
--name registry \
-p 443:443 \
-v /var/lib/registry:/var/lib/registry:Z \
-v "$HOME/registry/auth:/auth:Z" \
-v "$HOME/registry/certs:/certs:Z" \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/something.local.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/something.local.key \
registry:latest
The registry container should run without incident. You can run
sudo podman logs registry
and sudo podman ps
to ensure everything is
as it should be.
If you get an error that tells you that 443 is a privileged port, you
can choose a port higher than 1024, or you can add the following line to
/etc/sysctl.conf
:
/etc/sysctl.conf
net.ipv4.ip_unprivileged_port_start=443
Then, to load the new value from /etc/sysctl.conf
, run:
sudo sysctl -p /etc/sysctl.conf
Accessing the registry from another machine
Since we’re using a self-signed certificate, we’re going to be our own
Certificate Authority (CA). We can use
~/registry/certs/something.local.crt
as our CA root certificate. So
we’ll need to copy the contents of that file to the clipboard or copy
the entire file to the machine from which you want to access the
registry.
Run these commands on the other machine
Copy something.local.crt
via SSH:
scp -v youruser@something.local:/home/youruser/registry/certs/something.local.crt .
Now we need to create a directory to store the CA in a place where the Docker daemon or Podman will look for it.
sudo mkdir -p /etc/containers/certs.d/something.local:443
If you’re running Docker on the other machine, then change
/etc/containers
to /etc/docker
. If you’re using a port other than
443, then make sure to use that port in the name of the CA directory.
Now copy or move the CA file to the newly created directory, and make
sure the resulting filename is ca.crt
:
sudo mv something.local.crt /etc/containers/certs.d/something.local:443/ca.crt
Now you can try to login to the registry with the USERNAME
and
PASSWORD
you created earlier:
podman login -u USERNAME -p PASSWORD something.local
If this works, you should see “Login succeeded!” printed to the console. You can now push and pull images to and from your self-hosted container image registry.
OPTIONAL: Using the container registry for ostree images
If you’re running an immutable ostree version of Fedora such as
Silverblue or Kinoite, you can use your self-hosted registry to store
customized container images to rebase to. Just make sure that the
registry is on a LAN server machine that is always up and running. To
rebase from a container image in your registry, we have to make sure
that rpm-ostree knows you’re authenticated to the registry. Run the
podman login
command with the following flags:
podman login -u USERNAME -p PASSWORD something.local -v
The -v
flag is especially important, as it will show the name of the
auth.json
file we need that contains the authentication info. The file
should be /run/user/1000/containers/auth.json
. We simply need to copy
that file to /etc/ostree
.
sudo cp -v /run/user/1000/containers/auth.json /etc/ostree/
Now rpm-ostree knows you’re authenticated. Assuming you’ve built and pushed your custom ostree container image to your self-hosted registry, you can rebase to it with the following command:
rpm-ostree rebase --experimental ostree-unverified-registry:something.local/custom_silverblue:latest