mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-05 20:40:02 -08:00
Add integration tests (#672)
This commit is contained in:
166
.github/workflows/integration.yml
vendored
Normal file
166
.github/workflows/integration.yml
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
name: Integration Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
integration-tests-x86_64-linux:
|
||||
name: Integration tests x86_64-linux
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Extract the reference of before and after for the integration tests.
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
REF_BEFORE=""
|
||||
REF_AFTER="path:../../"
|
||||
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
echo "This CI run was triggered in the context of a pull request."
|
||||
REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "This CI run was triggered in the context of a push."
|
||||
REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
else
|
||||
echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
exit 1
|
||||
fi
|
||||
echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
- name: Check
|
||||
run: |
|
||||
cd ./tests/integration
|
||||
nix flake check --print-build-logs --system x86_64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL WE GET AN ARM64 RUNNER THAT SUPPORTS KVM
|
||||
#integration-tests-aarch64-linux:
|
||||
# name: Integration tests aarch64-linux
|
||||
# runs-on:
|
||||
# - ubicloud-standard-2-arm-ubuntu-2204
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# #git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# #git checkout -B ${{ github.ref_name }}
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# # export QEMU_OPTS="-machine virt -cpu cortex-a57"
|
||||
# nix flake check --print-build-logs --system aarch64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
#integration-tests-i686-linux:
|
||||
# name: Integration tests i686-linux
|
||||
# timeout-minutes: 144000
|
||||
# runs-on:
|
||||
# - ubicloud-standard-8-ubuntu-2204
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# nix flake check --print-build-logs --system i686-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL THIS ISSUE WITH NIXOS TESTS ON DARWIN GETS RESOLVED: https://github.com/NixOS/nixpkgs/issues/294725
|
||||
#integration-tests-aarch64-darwin:
|
||||
# name: Integration tests aarch64-darwin
|
||||
# runs-on:
|
||||
# - warp-macos-13-arm64-6x
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# nix flake check --print-build-logs --system aarch64-darwin --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
4
.github/workflows/nix.yaml
vendored
4
.github/workflows/nix.yaml
vendored
@@ -76,7 +76,9 @@ jobs:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
run: |
|
||||
nix flake check . --print-build-logs
|
||||
nix log /nix/store/3yvnay268gr9jpx3k1y2g3490j6ybssk-vm-test-run-rosenpass-with-key-exchangers.drv
|
||||
x86_64-linux---default:
|
||||
name: Build x86_64-linux.default
|
||||
runs-on:
|
||||
|
||||
122
flake.lock
generated
122
flake.lock
generated
@@ -18,6 +18,24 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -38,6 +56,27 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1728193676,
|
||||
@@ -59,11 +98,58 @@
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-vm-test": "nix-vm-test",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rosenpassOld": "rosenpassOld",
|
||||
"rust-overlay": "rust-overlay_2",
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
}
|
||||
},
|
||||
"rosenpassOld": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nix-vm-test": "nix-vm-test_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754748821,
|
||||
"narHash": "sha256-mMggTZDC97lLvKNOLtDz3GBjjxXFD++e1s0RZsVH/vI=",
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
@@ -98,7 +184,43 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
|
||||
14
flake.nix
14
flake.nix
@@ -13,6 +13,10 @@
|
||||
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
# Older version of rosenpass, referenced here for backwards compatibility
|
||||
rosenpassOld.url = "github:rosenpass/rosenpass?rev=916a9ebb7133f0b22057fb097a473217f261928a";
|
||||
rosenpassOld.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs =
|
||||
@@ -23,6 +27,7 @@
|
||||
nix-vm-test,
|
||||
rust-overlay,
|
||||
treefmt-nix,
|
||||
rosenpassOld,
|
||||
...
|
||||
}@inputs:
|
||||
nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [
|
||||
@@ -183,7 +188,14 @@
|
||||
};
|
||||
|
||||
checks =
|
||||
{
|
||||
import ./tests/integration/integration-checks.nix {
|
||||
inherit system;
|
||||
pkgs = inputs.nixpkgs;
|
||||
lib = nixpkgs.lib;
|
||||
rosenpassNew = self.packages.${system}.default;
|
||||
rosenpassOld = rosenpassOld.packages.${system}.default;
|
||||
}
|
||||
// {
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
formatting = treefmtEval.config.build.check self;
|
||||
|
||||
@@ -72,6 +72,8 @@ rustPlatform.buildRustPackage {
|
||||
package
|
||||
];
|
||||
|
||||
configFileVersion = "1";
|
||||
|
||||
doCheck = true;
|
||||
|
||||
cargoLock = {
|
||||
|
||||
29
tests/integration/README.md
Normal file
29
tests/integration/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Integration Tests
|
||||
|
||||
This directory contains integration tests for rosenpass in the form of a nix flake. Put simply, in order to run the integration tests for the main branch as they are on github right now, just run the following on a linux machine with nix installed and flakes enabled:
|
||||
|
||||
```
|
||||
nix flake check
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
The integration tests recognize two rosenpass versions, a new version and an old version. If not adapted, both are set to the version of the current main branch of rosenpass on github. We describe below how to change this.
|
||||
All integration tests install rosenpass on virtual machines, run the key exchange, create a connection via wireguard that uses rosenpass and then checks whether all peers can ping each other via wireguard. Overall there are four integration tests:
|
||||
|
||||
- `basicConnectivity` -- This test only uses the new rosenpass version and checks whether the key exchange between two peers works such that they can ping each other.
|
||||
- `backwardClient` -- This test is the same as the `basicConnectivity` test, but with the client using the old rosenpass version.
|
||||
- `backwardServer` -- This test is the same as the `backwardClient` test, but with the server using the old rosenpass version.
|
||||
- `multiPeer` -- This test again only uses the new rosenpass version, but with three peers. The first peer acts as a server towards the other two peers. The second peer acts as a client towards the first peer and as a server towards the third peer. The third peer acts as a client towards all peers.
|
||||
|
||||
## Testing specific versions
|
||||
|
||||
You can specify specific versions of rosenpass to test compatability. The proper way to do so is by overriding the respective inputs to the nix flake. As an example, say you want to test the compatability of your local version of rosenpass with the branch `new-feature` on github. You can achieve this by running the following command:
|
||||
|
||||
```
|
||||
nix flake check --override-input rosenpass-old ../../ --override-input rosenpass-new github:rosenpass/rosenpass/new-feature
|
||||
```
|
||||
|
||||
## Usage in the CI
|
||||
|
||||
In the CI, the integration tests are used differently, depending on whether the CI run is triggered by a push to the main branch or by a pull request. If the CI run is triggered by a pull request, then the result of merging the main branch and the PR branch is set as the new version and the current state of the main branch is set as the old version. For push events, the CI is only triggered if the push is onto the main branch. In that case, the state before the push event is considered the old version and the state after the push event is considered as the new version.
|
||||
320
tests/integration/flake.lock
generated
Normal file
320
tests/integration/flake.lock
generated
Normal file
@@ -0,0 +1,320 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1751413152,
|
||||
"narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "77826244401ea9de6e3bac47c2db46005e1f30b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-new",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-old",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1735563628,
|
||||
"narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728193676,
|
||||
"narHash": "sha256-PbDWAIjKJdlVg+qQRhzdSor04bAPApDqIv2DofTyynk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ecbc1ca8ffd6aea8372ad16be9ebbb39889e55b6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1728193676,
|
||||
"narHash": "sha256-PbDWAIjKJdlVg+qQRhzdSor04bAPApDqIv2DofTyynk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ecbc1ca8ffd6aea8372ad16be9ebbb39889e55b6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rosenpass-new": "rosenpass-new",
|
||||
"rosenpass-old": "rosenpass-old"
|
||||
}
|
||||
},
|
||||
"rosenpass-new": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-vm-test": "nix-vm-test",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752081615,
|
||||
"narHash": "sha256-g9jC1HNCMSMPzArA8RCPGaxCCFH6dzQuq20RDsRwRT8=",
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "3e03e479350551d11b81bde1bb55f5fdf8246f7c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rosenpass",
|
||||
"ref": "main",
|
||||
"repo": "rosenpass",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rosenpass-old": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nix-vm-test": "nix-vm-test_2",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"rust-overlay": "rust-overlay_2",
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752081615,
|
||||
"narHash": "sha256-g9jC1HNCMSMPzArA8RCPGaxCCFH6dzQuq20RDsRwRT8=",
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "3e03e479350551d11b81bde1bb55f5fdf8246f7c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rosenpass",
|
||||
"ref": "main",
|
||||
"repo": "rosenpass",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-new",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-old",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-new",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpass-old",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
46
tests/integration/flake.nix
Normal file
46
tests/integration/flake.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
description = "Integration tests for rosenpass";
|
||||
|
||||
inputs = {
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
# Override or change these inputs for testing new Integrations. They are overriden automatically when run in the CI
|
||||
rosenpass-old.url = "github:rosenpass/rosenpass/main";
|
||||
rosenpass-new.url = "github:rosenpass/rosenpass/main";
|
||||
};
|
||||
outputs =
|
||||
inputs:
|
||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = [
|
||||
"i686-linux"
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
perSystem =
|
||||
{ system, lib, ... }:
|
||||
let
|
||||
# Since other parts of the CI are already doing the unit tests, we deactivate them here.
|
||||
rosenpassOld = inputs.rosenpass-old.packages.${system}.default.overrideAttrs (old: {
|
||||
doCheck = false;
|
||||
});
|
||||
rosenpassNew = inputs.rosenpass-new.packages.${system}.default.overrideAttrs (new: {
|
||||
doCheck = false;
|
||||
});
|
||||
defaultChecks = import ./integration-checks.nix {
|
||||
inherit
|
||||
system
|
||||
lib
|
||||
rosenpassNew
|
||||
rosenpassOld
|
||||
;
|
||||
pkgs = inputs.nixpkgs;
|
||||
};
|
||||
in
|
||||
{
|
||||
checks = defaultChecks;
|
||||
};
|
||||
};
|
||||
}
|
||||
111
tests/integration/integration-checks.nix
Normal file
111
tests/integration/integration-checks.nix
Normal file
@@ -0,0 +1,111 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
system,
|
||||
rosenpassOld,
|
||||
rosenpassNew,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# The current version of ipython fails to build on i686 linux.
|
||||
# We therefore pin an older version that works for the time beeing.
|
||||
ipythonOverlay = final: prev: {
|
||||
python313 = prev.python313.override {
|
||||
packageOverrides = python-final: python-prev: {
|
||||
ipython = python-prev.ipython.overridePythonAttrs (old: {
|
||||
version = "8.37.0";
|
||||
src = python-final.fetchPypi {
|
||||
pname = "ipython";
|
||||
version = "8.37.0";
|
||||
hash = "sha256-yoFYQeGkGh5rc6CwjzA4r5siUlZNAfxAU1bTQDMBIhY=";
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
basicConnectivityOverlay = final: prev: {
|
||||
rosenpass-peer-a = rosenpassNew;
|
||||
rosenpass-peer-b = rosenpassNew;
|
||||
};
|
||||
|
||||
backwardServerOverlay = final: prev: {
|
||||
rosenpass-peer-a = rosenpassOld;
|
||||
rosenpass-peer-b = rosenpassNew;
|
||||
};
|
||||
|
||||
backwardClientOverlay = final: prev: {
|
||||
rosenpass-peer-a = rosenpassNew;
|
||||
rosenpass-peer-b = rosenpassOld;
|
||||
};
|
||||
|
||||
multiPeerOverlay = final: prev: {
|
||||
rosenpass-peer-a = rosenpassNew;
|
||||
rosenpass-peer-b = rosenpassNew;
|
||||
rosenpass-peer-c = rosenpassNew;
|
||||
};
|
||||
|
||||
pkgsBasicConnectivity = import pkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
basicConnectivityOverlay
|
||||
ipythonOverlay
|
||||
];
|
||||
};
|
||||
|
||||
pkgsBackwardServer = import pkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
backwardServerOverlay
|
||||
ipythonOverlay
|
||||
];
|
||||
};
|
||||
|
||||
pkgsBackwardClient = import pkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
backwardClientOverlay
|
||||
ipythonOverlay
|
||||
];
|
||||
};
|
||||
|
||||
pkgsMultiPeer = import pkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
multiPeerOverlay
|
||||
ipythonOverlay
|
||||
];
|
||||
};
|
||||
|
||||
generatedChecks = {
|
||||
basicConnectivity = pkgsBasicConnectivity.testers.runNixOSTest (
|
||||
import ./rpsc-test.nix {
|
||||
pkgs = pkgsBasicConnectivity;
|
||||
inherit lib;
|
||||
}
|
||||
);
|
||||
|
||||
backwardServer = pkgsBackwardServer.testers.runNixOSTest (
|
||||
import ./rpsc-test.nix {
|
||||
pkgs = pkgsBackwardServer;
|
||||
inherit lib;
|
||||
}
|
||||
);
|
||||
|
||||
backwardClient = pkgsBackwardClient.testers.runNixOSTest (
|
||||
import ./rpsc-test.nix {
|
||||
pkgs = pkgsBackwardClient;
|
||||
inherit lib;
|
||||
}
|
||||
);
|
||||
|
||||
multiPeer = pkgsMultiPeer.testers.runNixOSTest (
|
||||
import ./rpsc-test.nix {
|
||||
pkgs = pkgsMultiPeer;
|
||||
inherit lib;
|
||||
multiPeer = true;
|
||||
}
|
||||
);
|
||||
};
|
||||
in
|
||||
generatedChecks
|
||||
43
tests/integration/rp-key-exchange.nix
Normal file
43
tests/integration/rp-key-exchange.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.rosenpassKeyExchange;
|
||||
in
|
||||
{
|
||||
options.services.rosenpassKeyExchange = {
|
||||
create = lib.mkEnableOption "rosenpass key-exchange";
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Should the service be enabled";
|
||||
default = true;
|
||||
};
|
||||
config = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to rosenpass configuration";
|
||||
};
|
||||
rosenpassVersion = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
description = "Rosenpass package to use";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.create {
|
||||
systemd.services.rp-exchange = {
|
||||
description = "Rosenpass Key Exchanger";
|
||||
wantedBy = [ ] ++ lib.optional cfg.enable "multi-user.target"; # If we set enable to this, then the service will be masked and cannot be enabled. Doing it this way allows us to enable it.
|
||||
requires = [ "network-online.target" ];
|
||||
script = ''
|
||||
${cfg.rosenpassVersion}/bin/rosenpass exchange-config ${cfg.config}
|
||||
'';
|
||||
serviceConfig = {
|
||||
Restart = "always";
|
||||
RestartSec = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
104
tests/integration/rp-key-sync.nix
Normal file
104
tests/integration/rp-key-sync.nix
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.rosenpassKeySync;
|
||||
servicePrefix = "rp-key-sync-";
|
||||
timerPrefix = "rp-key-sync-timer-";
|
||||
rpKeySyncOpts =
|
||||
{ name, ... }:
|
||||
{
|
||||
# Each instance of ths service is defined by the following information:
|
||||
options = {
|
||||
create = lib.mkEnableOption "RP Keysync for ${name}";
|
||||
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Should the service be enabled";
|
||||
default = true;
|
||||
};
|
||||
|
||||
wgInterface = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Wireguard interface name";
|
||||
};
|
||||
|
||||
rpHost = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "network address of the host that runs rosenpass";
|
||||
};
|
||||
|
||||
peerPubkeyFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Public key of wireguard peer";
|
||||
};
|
||||
|
||||
remoteKeyPath = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Location of the .osk file on the key exchange server";
|
||||
};
|
||||
|
||||
endpoint = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "IP address of the peer to connect via.";
|
||||
};
|
||||
|
||||
allowedIps = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "IP addresses on the WireGuard VPN the peer is allowed to use";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.services.rosenpassKeySync = {
|
||||
instances = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule rpKeySyncOpts);
|
||||
default = { };
|
||||
description = "RP key sync instances";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.services = lib.mapAttrs' (instanceName: instanceCfg: {
|
||||
name = "${servicePrefix}${instanceName}";
|
||||
value = {
|
||||
description = "Rosenpass Key Downloader ${instanceName}";
|
||||
wantedBy = [ ] ++ lib.optional instanceCfg.enable "multi-user.target"; # If we set enable to this, then the service will be masked and cannot be enabled. Doing it this way allows us to enable it.
|
||||
requires = [ "network-online.target" ];
|
||||
# The script downloads the key generated by rosenpass from the key exchange node and sets it as the preshared key for the specified wireguard peer.
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
PEER_PUB_KEY=$(cat ${instanceCfg.peerPubkeyFile})
|
||||
${pkgs.openssh}/bin/ssh ${instanceCfg.rpHost} "cat ${instanceCfg.remoteKeyPath}" \
|
||||
| ${pkgs.wireguard-tools}/bin/wg \
|
||||
set ${instanceCfg.wgInterface} \
|
||||
peer $PEER_PUB_KEY \
|
||||
endpoint ${instanceCfg.endpoint} \
|
||||
allowed-ips ${instanceCfg.allowedIps} \
|
||||
preshared-key /dev/stdin
|
||||
'';
|
||||
serviceConfig = {
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
};
|
||||
};
|
||||
}) (lib.filterAttrs (_: cfg: cfg.create) cfg.instances); # this creates one systemd service (as above) per configured instance.
|
||||
|
||||
systemd.timers = lib.mapAttrs' (instanceName: instanceCfg: {
|
||||
name = "${timerPrefix}${instanceName}";
|
||||
value = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
requires = [ "network-online.target" ];
|
||||
OnUnitActiveSec = "1m";
|
||||
Unit = "${servicePrefix}${instanceName}.service";
|
||||
};
|
||||
};
|
||||
}) (lib.filterAttrs (_: cfg: cfg.create) cfg.instances); # this creates one systemd timer (as above) per configured instance.
|
||||
};
|
||||
}
|
||||
584
tests/integration/rpsc-test.nix
Normal file
584
tests/integration/rpsc-test.nix
Normal file
@@ -0,0 +1,584 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
multiPeer ? false,
|
||||
...
|
||||
}:
|
||||
let
|
||||
wgInterface = "mywg";
|
||||
wgPort = 51820;
|
||||
rpPort = 51821;
|
||||
|
||||
rosenpassKeyFolder = "/var/secrets";
|
||||
wireguardKeyFolder = "/var/wgKeys";
|
||||
keyExchangePathAB = "/root/peer-ab.osk";
|
||||
keyExchangePathBA = "/root/peer-ba.osk";
|
||||
keyExchangePathAC = "/root/peer-ac.osk";
|
||||
keyExchangePathCA = "/root/peer-ca.osk";
|
||||
keyExchangePathBC = "/root/peer-bc.osk";
|
||||
keyExchangePathCB = "/root/peer-cb.osk";
|
||||
|
||||
getConfigFileVersion =
|
||||
rosenpassVersion:
|
||||
let
|
||||
configFileVersion =
|
||||
if builtins.hasAttr "configFileVersion" rosenpassVersion then
|
||||
rosenpassVersion.configFileVersion
|
||||
else
|
||||
"0";
|
||||
in
|
||||
configFileVersion;
|
||||
|
||||
peerAConfigFileVersion = getConfigFileVersion pkgs.rosenpass-peer-a;
|
||||
peerBConfigFileVersion = getConfigFileVersion pkgs.rosenpass-peer-b;
|
||||
peerCConfigFileVersion = if multiPeer then getConfigFileVersion pkgs.rosenpass-peer-c else null;
|
||||
|
||||
staticConfig =
|
||||
{
|
||||
peerA = {
|
||||
innerIp = "10.100.0.1";
|
||||
wgPrivateKeyFile = "${wireguardKeyFolder}/peerA.sk";
|
||||
wgPublicKeyFile = "${wireguardKeyFolder}/peerA.pk";
|
||||
rosenpassConfig = builtins.toFile "peer-a.toml" (
|
||||
''
|
||||
public_key = "${rosenpassKeyFolder}/self.pk"
|
||||
secret_key = "${rosenpassKeyFolder}/self.sk"
|
||||
listen = ["[::]:${builtins.toString rpPort}"]
|
||||
verbosity = "Verbose"
|
||||
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-b.pk"
|
||||
endpoint = "peerbkeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathAB}"
|
||||
''
|
||||
+ (lib.optionalString multiPeer ''
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-c.pk"
|
||||
endpoint = "peerckeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathAC}"
|
||||
'')
|
||||
);
|
||||
};
|
||||
peerB = {
|
||||
innerIp = "10.100.0.2";
|
||||
wgPrivateKeyFile = "${wireguardKeyFolder}/peerB.sk";
|
||||
wgPublicKeyFile = "${wireguardKeyFolder}/peerB.pk";
|
||||
rosenpassConfig = builtins.toFile "peer-b.toml" (
|
||||
''
|
||||
public_key = "${rosenpassKeyFolder}/self.pk"
|
||||
secret_key = "${rosenpassKeyFolder}/self.sk"
|
||||
listen = ["[::]:${builtins.toString rpPort}"]
|
||||
verbosity = "Verbose"
|
||||
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-a.pk"
|
||||
endpoint = "peerakeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathBA}"
|
||||
''
|
||||
+ (lib.optionalString multiPeer ''
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-c.pk"
|
||||
endpoint = "peerckeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathBC}"
|
||||
'')
|
||||
);
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs multiPeer {
|
||||
# peerC is only defined if we are in a multiPeer context.
|
||||
peerC = {
|
||||
innerIp = "10.100.0.3";
|
||||
wgPrivateKeyFile = "${wireguardKeyFolder}/peerC.sk";
|
||||
wgPublicKeyFile = "${wireguardKeyFolder}/peerC.pk";
|
||||
rosenpassConfig = builtins.toFile "peer-c.toml" ''
|
||||
public_key = "${rosenpassKeyFolder}/self.pk"
|
||||
secret_key = "${rosenpassKeyFolder}/self.sk"
|
||||
listen = ["[::]:${builtins.toString rpPort}"]
|
||||
verbosity = "Verbose"
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-a.pk"
|
||||
endpoint = "peerakeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathCA}"
|
||||
[[peers]]
|
||||
public_key = "${rosenpassKeyFolder}/peer-b.pk"
|
||||
endpoint = "peerckeyexchanger:${builtins.toString rpPort}"
|
||||
key_out = "${keyExchangePathCB}"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
inherit (import (pkgs.path + "/nixos/tests/ssh-keys.nix") pkgs)
|
||||
snakeOilPublicKey
|
||||
snakeOilPrivateKey
|
||||
;
|
||||
|
||||
# All hosts in this scenario use the same key pair
|
||||
# The script takes the host as parameter and prepares passwordless login
|
||||
prepareSshLogin = pkgs.writeShellScriptBin "prepare-ssh-login" ''
|
||||
set -euo pipefail
|
||||
mkdir -p /root/.ssh
|
||||
cp ${snakeOilPrivateKey} /root/.ssh/id_ecdsa
|
||||
chmod 0400 /root/.ssh/id_ecdsa
|
||||
${pkgs.openssh}/bin/ssh -o StrictHostKeyChecking=no "$1" true
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "rosenpass with key exchangers";
|
||||
defaults = {
|
||||
imports = [
|
||||
./rp-key-exchange.nix
|
||||
./rp-key-sync.nix
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [ "d ${rosenpassKeyFolder} 0400 root root - -" ];
|
||||
};
|
||||
|
||||
nodes =
|
||||
{
|
||||
# peerA and peerB are the only neccessary peers unless we are in the multiPeer test.
|
||||
peerA = {
|
||||
networking.firewall.allowedUDPPorts = [ wgPort ];
|
||||
|
||||
# Each instance of the key sync service loads a symmetric key from a rosenpass keyexchanger node and sets it as the preshared key for the appropriate wireguard tunnel.
|
||||
services.rosenpassKeySync.instances =
|
||||
{
|
||||
AB = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerakeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerB.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathAB;
|
||||
endpoint = "peerB:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerB.innerIp}/32";
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs multiPeer {
|
||||
AC = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerakeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerC.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathAC;
|
||||
endpoint = "peerC:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerC.innerIp}/32";
|
||||
};
|
||||
};
|
||||
};
|
||||
peerB = {
|
||||
networking.firewall.allowedUDPPorts = [ wgPort ];
|
||||
|
||||
# Each instance of the key sync service loads a symmetric key from a rosenpass keyexchanger node and sets it as the preshared key for the appropriate wireguard tunnel.
|
||||
services.rosenpassKeySync.instances =
|
||||
{
|
||||
BA = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerbkeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerA.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathBA;
|
||||
endpoint = "peerA:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerA.innerIp}/32";
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs multiPeer {
|
||||
BC = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerbkeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerC.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathBC;
|
||||
endpoint = "peerC:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerC.innerIp}/32";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# The key exchanger node for peerA is the node that actually runs rosenpass. It takes the rosenpass confguration for peerA and runs it.
|
||||
# The key sync services of peerA will ssh into this node and download the exchanged keys from here.
|
||||
peerakeyexchanger = {
|
||||
services.openssh.enable = true;
|
||||
users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
|
||||
networking.firewall.allowedUDPPorts = [ rpPort ];
|
||||
|
||||
services.rosenpassKeyExchange = {
|
||||
create = true;
|
||||
enable = false;
|
||||
config = staticConfig.peerA.rosenpassConfig;
|
||||
rosenpassVersion = pkgs.rosenpass-peer-a;
|
||||
};
|
||||
};
|
||||
|
||||
# The key exchanger node for peerB is the node that actually runs rosenpass. It takes the rosenpass confguration for peerB and runs it.
|
||||
# The key sync services of peerB will ssh into this node and download the exchanged keys from here.
|
||||
peerbkeyexchanger = {
|
||||
services.openssh.enable = true;
|
||||
users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
|
||||
|
||||
services.rosenpassKeyExchange = {
|
||||
create = true;
|
||||
enable = false;
|
||||
config = staticConfig.peerB.rosenpassConfig;
|
||||
rosenpassVersion = pkgs.rosenpass-peer-b;
|
||||
};
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs multiPeer {
|
||||
peerC = {
|
||||
networking.firewall.allowedUDPPorts = [ wgPort ];
|
||||
|
||||
# Each instance of the key sync service loads a symmetric key from a rosenpass keyexchanger node and sets it as the preshared key for the appropriate wireguard tunnel.
|
||||
services.rosenpassKeySync.instances = {
|
||||
CA = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerckeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerA.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathCA;
|
||||
endpoint = "peerA:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerA.innerIp}/32";
|
||||
};
|
||||
CB = {
|
||||
create = true;
|
||||
enable = false;
|
||||
inherit wgInterface;
|
||||
rpHost = "peerckeyexchanger";
|
||||
peerPubkeyFile = staticConfig.peerB.wgPublicKeyFile;
|
||||
remoteKeyPath = keyExchangePathCB;
|
||||
endpoint = "peerB:${builtins.toString wgPort}";
|
||||
allowedIps = "${staticConfig.peerB.innerIp}/32";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# The key exchanger node for peerC is the node that actually runs rosenpass. It takes the rosenpass confguration for peerC and runs it.
|
||||
# The key sync services of peerC will ssh into this node and download the exchanged keys from here.
|
||||
peerckeyexchanger = {
|
||||
services.openssh.enable = true;
|
||||
users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
|
||||
networking.firewall.allowedUDPPorts = [ rpPort ];
|
||||
|
||||
services.rosenpassKeyExchange = {
|
||||
create = true;
|
||||
enable = false;
|
||||
config = staticConfig.peerC.rosenpassConfig;
|
||||
rosenpassVersion = pkgs.rosenpass-peer-c;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
interactive = {
|
||||
defaults = {
|
||||
users.extraUsers.root.initialPassword = "";
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "yes";
|
||||
PermitEmptyPasswords = "yes";
|
||||
};
|
||||
};
|
||||
security.pam.services.sshd.allowNullPassword = true;
|
||||
environment.systemPackages = [
|
||||
prepareSshLogin
|
||||
(pkgs.writeShellScriptBin "watch-wg" ''
|
||||
${pkgs.procps}/bin/watch -n1 \
|
||||
${pkgs.wireguard-tools}/bin/wg show all preshared-keys
|
||||
'')
|
||||
];
|
||||
};
|
||||
nodes.peerA = {
|
||||
virtualisation.forwardPorts = [
|
||||
{
|
||||
from = "host";
|
||||
host.port = 2222;
|
||||
guest.port = 22;
|
||||
}
|
||||
];
|
||||
};
|
||||
nodes.peerB = {
|
||||
virtualisation.forwardPorts = [
|
||||
{
|
||||
from = "host";
|
||||
host.port = 2223;
|
||||
guest.port = 22;
|
||||
}
|
||||
];
|
||||
};
|
||||
nodes.peerC = {
|
||||
virtualisation.forwardPorts = [
|
||||
{
|
||||
from = "host";
|
||||
host.port = 2224;
|
||||
guest.port = 22;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = (''
|
||||
start_all()
|
||||
|
||||
print("""Config file versions supported by peers
|
||||
peerA: ${peerAConfigFileVersion}
|
||||
peerB: ${peerBConfigFileVersion}
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC: ${peerCConfigFileVersion}
|
||||
''}
|
||||
""")
|
||||
|
||||
for m in [peerA, peerB, peerakeyexchanger, peerbkeyexchanger]:
|
||||
m.wait_for_unit("network-online.target")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
for m in [peerC, peerckeyexchanger]:
|
||||
m.wait_for_unit("network-online.target")
|
||||
''}
|
||||
|
||||
# Generate the normal wireguard key pairs
|
||||
peerA.succeed("mkdir ${wireguardKeyFolder}")
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg genkey > ${staticConfig.peerA.wgPrivateKeyFile}")
|
||||
peerA.succeed("cat ${staticConfig.peerA.wgPrivateKeyFile} | ${pkgs.wireguard-tools}/bin/wg pubkey > ${staticConfig.peerA.wgPublicKeyFile}")
|
||||
peerAWgSk = peerA.succeed("cat ${staticConfig.peerA.wgPrivateKeyFile} | tr -d '\n'")
|
||||
peerAWgPk = peerA.succeed("cat ${staticConfig.peerA.wgPublicKeyFile} | tr -d '\n'")
|
||||
peerA.succeed("echo -n AR/yvSvMAzW6eS27PsRHUMWwC8cLhaD96t42cysxrb0= > ${wireguardKeyFolder}/peerB.psk")
|
||||
|
||||
peerB.succeed("mkdir ${wireguardKeyFolder}")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg genkey > ${staticConfig.peerB.wgPrivateKeyFile}")
|
||||
peerB.succeed("cat ${staticConfig.peerB.wgPrivateKeyFile} | ${pkgs.wireguard-tools}/bin/wg pubkey > ${staticConfig.peerB.wgPublicKeyFile}")
|
||||
peerBWgSk = peerB.succeed("cat ${staticConfig.peerB.wgPrivateKeyFile} | tr -d '\n'")
|
||||
peerBWgPk = peerB.succeed("cat ${staticConfig.peerB.wgPublicKeyFile} | tr -d '\n'")
|
||||
peerB.succeed("echo -n o25fjoIOI623cnRyhvD4YEGtuSY4BFRZmY3UHvZ0BCA= > ${wireguardKeyFolder}/peerA.psk")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("mkdir ${wireguardKeyFolder}")
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg genkey > ${staticConfig.peerC.wgPrivateKeyFile}")
|
||||
peerC.succeed("cat ${staticConfig.peerC.wgPrivateKeyFile} | ${pkgs.wireguard-tools}/bin/wg pubkey > ${staticConfig.peerC.wgPublicKeyFile}")
|
||||
peerCWgSk = peerC.succeed("cat ${staticConfig.peerC.wgPrivateKeyFile} | tr -d '\n'")
|
||||
peerCWgPk = peerC.succeed("cat ${staticConfig.peerC.wgPublicKeyFile} | tr -d '\n'")
|
||||
peerA.succeed("echo -n LfWvJCN8h7NhS+JWRG7GMIY20JxUV4WUs7MJ45ZGoCE= > ${wireguardKeyFolder}/peerC.psk")
|
||||
peerB.succeed("echo -n GsYTUd/4Ph7wMy5r+W1no9yGe0UeZlmCPeiyu4tb6yM= > ${wireguardKeyFolder}/peerC.psk")
|
||||
peerC.succeed("echo -n s9aIG1pY6nj2lH6p61tP8WRETNgQvoTfgel5BmVjYeI= > ${wireguardKeyFolder}/peerA.psk")
|
||||
peerC.succeed("echo -n DYlFqWg/M6EfnMolBO+b4DFNrRyS6YWr4lM/2xRE1FQ= > ${wireguardKeyFolder}/peerB.psk")
|
||||
''}
|
||||
|
||||
# Distribute the respective public keys
|
||||
peerA.succeed(f"echo -n {peerBWgPk} > ${wireguardKeyFolder}/peerB.pk")
|
||||
peerB.succeed(f"echo -n {peerAWgPk} > ${wireguardKeyFolder}/peerA.pk")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.succeed(f"echo -n {peerCWgPk} > ${wireguardKeyFolder}/peerC.pk")
|
||||
peerB.succeed(f"echo -n {peerCWgPk} > ${wireguardKeyFolder}/peerC.pk")
|
||||
peerC.succeed(f"echo -n {peerAWgPk} > ${wireguardKeyFolder}/peerA.pk")
|
||||
peerC.succeed(f"echo -n {peerBWgPk} > ${wireguardKeyFolder}/peerB.pk")
|
||||
''}
|
||||
|
||||
# Make the wireguard public keys readable for the key-sync service.
|
||||
peerA.succeed("chmod -R 0555 ${wireguardKeyFolder}")
|
||||
peerB.succeed("chmod -R 0555 ${wireguardKeyFolder}")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("chmod -R 0555 ${wireguardKeyFolder}")
|
||||
''}
|
||||
|
||||
# Set up wireguard on peerA
|
||||
peerA.succeed("ip link add ${wgInterface} type wireguard")
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg set ${wgInterface} private-key ${staticConfig.peerA.wgPrivateKeyFile} listen-port ${builtins.toString wgPort}")
|
||||
peerA.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerBWgPk} allowed-ips ${staticConfig.peerB.innerIp}/32 endpoint peerB:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerB.psk")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerCWgPk} allowed-ips ${staticConfig.peerC.innerIp}/32 endpoint peerC:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerC.psk")
|
||||
''}
|
||||
peerA.succeed("ip addr add ${staticConfig.peerA.innerIp}/32 dev ${wgInterface}")
|
||||
peerA.succeed("ip link set ${wgInterface} up")
|
||||
peerA.succeed("ip route add ${staticConfig.peerB.innerIp} dev ${wgInterface} scope link")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.succeed("ip route add ${staticConfig.peerC.innerIp} dev ${wgInterface} scope link")
|
||||
''}
|
||||
|
||||
# Set up wireguard on peerB
|
||||
peerB.succeed("ip link add ${wgInterface} type wireguard")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg set ${wgInterface} private-key ${staticConfig.peerB.wgPrivateKeyFile} listen-port ${builtins.toString wgPort}")
|
||||
peerB.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerAWgPk} allowed-ips ${staticConfig.peerA.innerIp}/32 endpoint peerA:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerA.psk")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerB.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerCWgPk} allowed-ips ${staticConfig.peerC.innerIp}/32 endpoint peerC:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerC.psk")
|
||||
''}
|
||||
peerB.succeed("ip addr add ${staticConfig.peerB.innerIp}/32 dev ${wgInterface}")
|
||||
peerB.succeed("ip link set ${wgInterface} up")
|
||||
peerB.succeed("ip route add ${staticConfig.peerA.innerIp} dev ${wgInterface} scope link")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerB.succeed("ip route add ${staticConfig.peerC.innerIp} dev ${wgInterface} scope link")
|
||||
''}
|
||||
|
||||
# Set up wireguard on peerC
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("ip link add ${wgInterface} type wireguard")
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg set ${wgInterface} private-key ${staticConfig.peerC.wgPrivateKeyFile} listen-port ${builtins.toString wgPort}")
|
||||
peerC.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerAWgPk} allowed-ips ${staticConfig.peerA.innerIp}/32 endpoint peerA:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerA.psk")
|
||||
peerC.succeed(f"${pkgs.wireguard-tools}/bin/wg set ${wgInterface} peer {peerBWgPk} allowed-ips ${staticConfig.peerB.innerIp}/32 endpoint peerB:${builtins.toString wgPort} preshared-key ${wireguardKeyFolder}/peerB.psk")
|
||||
peerC.succeed("ip addr add ${staticConfig.peerC.innerIp}/32 dev ${wgInterface}")
|
||||
peerC.succeed("ip link set ${wgInterface} up")
|
||||
peerC.succeed("ip route add ${staticConfig.peerA.innerIp} dev ${wgInterface} scope link")
|
||||
peerC.succeed("ip route add ${staticConfig.peerB.innerIp} dev ${wgInterface} scope link")
|
||||
''}
|
||||
|
||||
def debugPrintNetState():
|
||||
# Dump current state of WireGuard tunnels
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
''}
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
''}
|
||||
|
||||
# Dump current network config
|
||||
peerA.succeed("ip addr 1>&2")
|
||||
peerA.succeed("ip route 1>&2")
|
||||
peerakeyexchanger.succeed("ip addr 1>&2")
|
||||
peerakeyexchanger.succeed("ip route 1>&2")
|
||||
|
||||
peerB.succeed("ip addr 1>&2")
|
||||
peerB.succeed("ip route 1>&2")
|
||||
peerbkeyexchanger.succeed("ip addr 1>&2")
|
||||
peerbkeyexchanger.succeed("ip route 1>&2")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("ip addr 1>&2")
|
||||
peerC.succeed("ip route 1>&2")
|
||||
peerckeyexchanger.succeed("ip addr 1>&2")
|
||||
peerckeyexchanger.succeed("ip route 1>&2")
|
||||
''}
|
||||
|
||||
debugPrintNetState()
|
||||
|
||||
# The wireguard connection can't work because the sync services fail on
|
||||
# non-recognized SSH host keys, we didn't deploy the secrets and because the preshared keyes don't match.
|
||||
peerB.fail("ping -W 2 -c 1 ${staticConfig.peerA.innerIp}")
|
||||
peerA.fail("ping -W 2 -c 1 ${staticConfig.peerB.innerIp}")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.fail("ping -W 2 -c 1 ${staticConfig.peerC.innerIp}")
|
||||
peerB.fail("ping -W 2 -c 1 ${staticConfig.peerC.innerIp}")
|
||||
peerC.fail("ping -W 2 -c 1 ${staticConfig.peerA.innerIp}")
|
||||
peerC.fail("ping -W 2 -c 1 ${staticConfig.peerB.innerIp}")
|
||||
''}
|
||||
|
||||
# In admin-reality, this should be done with your favorite secret
|
||||
# provisioning/deployment tool
|
||||
# In reality, admins would carefully manage known SSH host keys with
|
||||
# their favorite secret provisioning/deployment tool
|
||||
peerA.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerakeyexchanger")
|
||||
peerB.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerbkeyexchanger")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerckeyexchanger")
|
||||
''}
|
||||
peerakeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerbkeyexchanger")
|
||||
peerbkeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerakeyexchanger")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerakeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerckeyexchanger")
|
||||
peerbkeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerckeyexchanger")
|
||||
peerckeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerakeyexchanger")
|
||||
peerckeyexchanger.succeed("${prepareSshLogin}/bin/prepare-ssh-login peerbkeyexchanger")
|
||||
''}
|
||||
|
||||
# Generate the rosenpass key pairs.
|
||||
peerakeyexchanger.succeed(
|
||||
"${pkgs.rosenpass-peer-a}/bin/rosenpass gen-keys -p ${rosenpassKeyFolder}/self.pk -s ${rosenpassKeyFolder}/self.sk"
|
||||
)
|
||||
peerbkeyexchanger.succeed(
|
||||
"${pkgs.rosenpass-peer-b}/bin/rosenpass gen-keys -p ${rosenpassKeyFolder}/self.pk -s ${rosenpassKeyFolder}/self.sk"
|
||||
)
|
||||
${lib.optionalString multiPeer ''
|
||||
peerckeyexchanger.succeed(
|
||||
"${pkgs.rosenpass-peer-c}/bin/rosenpass gen-keys -p ${rosenpassKeyFolder}/self.pk -s ${rosenpassKeyFolder}/self.sk"
|
||||
)
|
||||
''}
|
||||
|
||||
peerakeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerbkeyexchanger:${rosenpassKeyFolder}/peer-a.pk"
|
||||
)
|
||||
peerbkeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerakeyexchanger:${rosenpassKeyFolder}/peer-b.pk"
|
||||
)
|
||||
${lib.optionalString multiPeer ''
|
||||
peerakeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerckeyexchanger:${rosenpassKeyFolder}/peer-a.pk"
|
||||
)
|
||||
peerbkeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerckeyexchanger:${rosenpassKeyFolder}/peer-b.pk"
|
||||
)
|
||||
peerckeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerakeyexchanger:${rosenpassKeyFolder}/peer-c.pk"
|
||||
)
|
||||
peerckeyexchanger.succeed(
|
||||
"scp ${rosenpassKeyFolder}/self.pk peerbkeyexchanger:${rosenpassKeyFolder}/peer-c.pk"
|
||||
)
|
||||
''}
|
||||
|
||||
# Until now, the services were disbaled and didn't start (using the enable option of the services)
|
||||
peerakeyexchanger.succeed("systemctl start rp-exchange.service")
|
||||
peerbkeyexchanger.succeed("systemctl start rp-exchange.service")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
peerckeyexchanger.succeed("systemctl start rp-exchange.service")
|
||||
''}
|
||||
|
||||
# Wait for the service to have started.
|
||||
for m in [peerbkeyexchanger, peerakeyexchanger]:
|
||||
m.wait_for_unit("rp-exchange.service")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
peerckeyexchanger.wait_for_unit("rp-exchange.service")
|
||||
''}
|
||||
|
||||
debugPrintNetState()
|
||||
|
||||
# Start key sync services and wait for them to start.
|
||||
peerA.succeed("systemctl start rp-key-sync-AB.service")
|
||||
peerB.succeed("systemctl start rp-key-sync-BA.service")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.succeed("systemctl start rp-key-sync-AC.service")
|
||||
peerB.succeed("systemctl start rp-key-sync-BC.service")
|
||||
peerC.succeed("systemctl start rp-key-sync-CA.service")
|
||||
peerC.succeed("systemctl start rp-key-sync-CB.service")
|
||||
''}
|
||||
|
||||
peerA.wait_for_unit("rp-key-sync-AB.service")
|
||||
peerB.wait_for_unit("rp-key-sync-BA.service")
|
||||
|
||||
${lib.optionalString multiPeer ''
|
||||
peerA.wait_for_unit("rp-key-sync-AC.service")
|
||||
peerB.wait_for_unit("rp-key-sync-BC.service")
|
||||
peerC.wait_for_unit("rp-key-sync-CA.service")
|
||||
peerC.wait_for_unit("rp-key-sync-CB.service")
|
||||
''}
|
||||
|
||||
debugPrintNetState()
|
||||
|
||||
# Voila!
|
||||
peerB.succeed("ping -c 1 -W 10 ${staticConfig.peerA.innerIp}")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("ping -c 1 -W 10 ${staticConfig.peerA.innerIp}")
|
||||
peerC.succeed("ping -c 1 -W 10 ${staticConfig.peerB.innerIp}")
|
||||
peerA.succeed("ping -c 1 -W 10 ${staticConfig.peerC.innerIp}")
|
||||
peerB.succeed("ping -c 1 -W 10 ${staticConfig.peerC.innerIp}")
|
||||
''}
|
||||
peerA.succeed("ping -c 1 -W 10 ${staticConfig.peerB.innerIp}")
|
||||
|
||||
# Dump current state of WireGuard tunnels
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg show all 1>&2")
|
||||
''}
|
||||
peerA.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
peerB.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
${lib.optionalString multiPeer ''
|
||||
peerC.succeed("${pkgs.wireguard-tools}/bin/wg show all preshared-keys 1>&2")
|
||||
''}
|
||||
|
||||
'');
|
||||
}
|
||||
Reference in New Issue
Block a user