# Rosenpass in Docker Rosenpass provides post-quantum-secure key exchange for VPNs. It generates symmetric keys used by [WireGuard](https://www.wireguard.com/papers/wireguard.pdf) or other applications. The protocol enhances "Post-Quantum WireGuard" ([PQWG](https://eprint.iacr.org/2020/379)) with a cookie mechanism for better security against state disruption attacks. Prebuilt Docker images are available for easy deployment: - [`ghcr.io/rosenpass/rosenpass`](https://github.com/rosenpass/rosenpass/pkgs/container/rosenpass) – the core key exchange tool - [`ghcr.io/rosenpass/rp`](https://github.com/rosenpass/rosenpass/pkgs/container/rp) – a frontend for setting up WireGuard VPNs The entrypoint of the `rosenpass` image is the `rosenpass` executable, whose documentation can be found [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp_manual/). Similarly, the entrypoint of the `rp` image is the `rp` executable, with its documentation available [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp1/). ## Usage - Standalone Key Exchange The `ghcr.io/rosenpass/rosenpass` image can be used in a server-client setup to exchange quantum-secure shared keys. This setup uses rosenpass as a standalone application, without using any other component such as wireguard. What follows, is a simple setup for illustrative purposes. Create a docker network that is used to connect the containers: ```bash docker network create -d bridge rp export NET=rp ``` Generate the server and client key pairs: ```bash mkdir ./workdir-client ./workdir-server docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \ gen-keys --public-key=workdir/server-public --secret-key=workdir/server-secret docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \ gen-keys --public-key=workdir/client-public --secret-key=workdir/client-secret # share the public keys between client and server cp workdir-client/client-public workdir-server/client-public cp workdir-server/server-public workdir-client/server-public ``` Start the server container: ```bash docker run --name "rpserver" --network ${NET} \ -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \ exchange \ private-key workdir/server-secret \ public-key workdir/server-public \ listen 0.0.0.0:9999 \ peer public-key workdir/client-public \ outfile workdir/server-sharedkey ``` Find out the ip address of the server container: ```bash EP="rpserver" EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP) ``` Run the client container and perform the key exchange: ```bash docker run --name "rpclient" --network ${NET} \ -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \ exchange \ private-key workdir/client-secret \ public-key workdir/client-public \ peer public-key workdir/server-public endpoint ${EP}:9999 \ outfile workdir/client-sharedkey ``` Now the containers will exchange shared keys and each put them into their respective outfile. Comparing the outfiles shows that these shared keys equal: ```bash cmp workdir-server/server-sharedkey workdir-client/client-sharedkey ``` It is now possible to set add these keys as pre-shared keys within a wireguard interface. For example as the server, ```bash PREKEY=$(cat workdir-server/server-sharedkey) wg set peer preshared-key <(echo "$PREKEY") ``` ## Usage - Combined with wireguard The `ghcr.io/rosenpass/rp` image can be used to build a VPN with WireGuard and Rosenpass. In this example, we run two containers on the same system and connect them with a bridge network within the docker overlay network. Create the named docker network, to be able to connect the containers. Create a docker network that is used to connect the containers: ```bash docker network create -d bridge rp export NET=rp ``` Generate the server and client secret keys and extract public keys. ```bash mkdir -p ./workdir-server ./workdir-client # server docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \ genkey workdir/server.rosenpass-secret docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \ pubkey workdir/server.rosenpass-secret workdir/server.rosenpass-public # client docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \ genkey workdir/client.rosenpass-secret docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \ pubkey workdir/client.rosenpass-secret workdir/client.rosenpass-public # share the public keys between client and server cp -r workdir-client/client.rosenpass-public workdir-server/client.rosenpass-public cp -r workdir-server/server.rosenpass-public workdir-client/server.rosenpass-public ``` Start the server container. Note that the `NET_ADMIN` capability is neccessary, the rp command will create and manage wireguard interfaces. Also make sure the `wireguard` kernel module is loaded by the host. (`lsmod | grep wireguard`) ```bash docker run --name "rpserver" --network ${NET} -it -d --rm -v ./workdir-server:/workdir \ --cap-add=NET_ADMIN \ ghcr.io/rosenpass/rp \ exchange workdir/server.rosenpass-secret dev rosenpass0 \ listen 0.0.0.0:9999 peer workdir/client.rosenpass-public allowed-ips 10.0.0.0/8 ``` Now find out the ip-address of the server container and then start the client container: ```bash EP="rpserver" EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP) docker run --name "rpclient" --network ${NET} -it -d --rm -v ./workdir-client:/workdir \ --cap-add=NET_ADMIN \ ghcr.io/rosenpass/rp \ exchange workdir/client.rosenpass-secret dev rosenpass1 \ peer workdir/server.rosenpass-public endpoint ${EP}:9999 allowed-ips 10.0.0.1 ``` Inside the docker containers assign the IP addresses: ```bash # server docker exec -it rpserver ip a add 10.0.0.1/24 dev rosenpass0 # client docker exec -it rpclient ip a add 10.0.0.2/24 dev rosenpass1 ``` Done! The two containers should now be connected through a wireguard VPN (Port 1000) with pre-shared keys exchanged by rosenpass (Port 9999). Now, test the connection by starting a shell inside the client container, and ping the server through the VPN: ```bash # client docker exec -it rpclient bash apt update; apt install iputils-ping ping 10.0.0.1 ``` The ping command should continuously show ping-logs: ``` PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.119 ms 64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.132 ms 64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.394 ms ... ``` While the ping is running, you may stop the server container, and verify that the ping-log halts. In another terminal do: ``` docker stop -t 1 rpserver ``` ## Building the Docker Images Locally Clone the Rosenpass repository: ``` git clone https://github.com/rosenpass/rosenpass cd rosenpass ``` Build the rp image from the root of the repository as follows: ``` docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rp --target rp . ``` Build the rosenpass image from the root of the repostiry with the following command: ``` docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rosenpass --target rosenpass . ```