diff --git a/.github/workflows/pr-test.yaml b/.github/workflows/pr-test.yaml index 608349b7..3106cd9b 100644 --- a/.github/workflows/pr-test.yaml +++ b/.github/workflows/pr-test.yaml @@ -22,7 +22,6 @@ jobs: SITE_NAME: UKA PYTHONUNBUFFERED: 1 - steps: - name: Checkout repository (with submodules) uses: actions/checkout@v3 @@ -37,50 +36,60 @@ jobs: echo "VERSION=$VERSION" echo "version=$VERSION" >> $GITHUB_OUTPUT - - name: Build Docker image for real project (MEVIS) - run: | - chmod +x buildDockerImageAndStartupKits.sh - ./buildDockerImageAndStartupKits.sh -p application/provision/project_MEVIS_test.yml + - name: Build Docker image and startup kits for test project + run: ./buildDockerImageAndStartupKits.sh -p tests/provision/dummy_project_for_testing.yml -c tests/local_vpn/client_configs - - name: Show workspace path for MEVIS project + - name: Show workspace path for test project run: | echo "WORKSPACE_PATH: ${{ env.WORKSPACE_PATH }}" - find workspace -maxdepth 1 -type d -name "odelia_*_MEVIS_test" || echo "No workspace found" + find workspace -maxdepth 1 -type d -name "odelia_*_dummy_project_for_testing" || echo "No workspace found" + + - name: Run integration test checking documentation on github + continue-on-error: false + run: | + ./runIntegrationTests.sh check_files_on_github - - name: Build Docker image and dummy startup kits - run: ./buildDockerImageAndStartupKits.sh -p tests/provision/dummy_project_for_testing.yml --use-docker-cache + - name: Run controller unit tests + continue-on-error: false + run: | + ./runIntegrationTests.sh run_unit_tests_controller - - name: Prepare dummy trainings - continue-on-error: true + - name: Run dummy training standalone + continue-on-error: false run: | - ./runTestsInDocker.sh prepare_dummy_trainings - echo "Dummy training project prepared" + ./runIntegrationTests.sh run_dummy_training_standalone - - name: Run dummy training + - name: Run dummy training in simulation mode continue-on-error: false run: | - ./runTestsInDocker.sh run_dummy_training - echo "Dummy training finished" - echo "=== Checking log output ===" - ls -lh workspace/*/prod_00/client_A/logs || echo "No logs found for dummy training" + ./runIntegrationTests.sh run_dummy_training_simulation_mode - - name: Run 3D CNN tests + - name: Run dummy training in proof-of-concept mode continue-on-error: false run: | - ./runTestsInDocker.sh run_3dcnn_tests - echo "3D CNN tests check finished" - echo "=== Checking synthetic log output ===" - ls -lh workspace/*/prod_00/client_A/logs || echo "No logs found for 3D CNN tests" + ./runIntegrationTests.sh run_dummy_training_poc_mode - - name: Run Unit Tests inside Docker - continue-on-error: true + - name: Run 3DCNN training in simulation mode + continue-on-error: false run: | - ./runTestsInDocker.sh run_tests - echo "=== [LOG CHECK] ===" - docker logs $(docker ps -a -q --latest) | grep -i "error" && echo "Error found in logs" || echo "No error found" + ./runIntegrationTests.sh run_3dcnn_simulation_mode - - name: Cleanup training artifacts - continue-on-error: true + - name: Run integration test creating startup kits + continue-on-error: false + run: | + ./runIntegrationTests.sh create_startup_kits + + - name: Run intergration test listing licenses + continue-on-error: false + run: | + ./runIntegrationTests.sh run_list_licenses + + - name: Run integration test Docker GPU preflight check + continue-on-error: false + run: | + ./runIntegrationTests.sh run_docker_gpu_preflight_check + + - name: Run integration test Data access preflight check + continue-on-error: false run: | - ./runTestsInDocker.sh cleanup - echo "Cleanup finished" + ./runIntegrationTests.sh run_data_access_preflight_check diff --git a/_buildStartupKits.sh b/_buildStartupKits.sh index 29755d27..47f064c8 100755 --- a/_buildStartupKits.sh +++ b/_buildStartupKits.sh @@ -2,25 +2,32 @@ set -euo pipefail -if [ "$#" -ne 2 ]; then - echo "Usage: _buildStartupKits.sh SWARM_PROJECT.yml VERSION_STRING" +if [ "$#" -lt 3 ]; then + echo "Usage: _buildStartupKits.sh SWARM_PROJECT.yml VERSION_STRING CONTAINER_NAME [VPN_CREDENTIALS_DIR]" exit 1 fi PROJECT_YML=$1 VERSION=$2 +CONTAINER_NAME=$3 +MOUNT_VPN_CREDENTIALS_DIR="" +if [ "$#" -eq 4 ]; then + MOUNT_VPN_CREDENTIALS_DIR="-v $4:/vpn_credentials/" +fi sed -i 's#__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_STARTUP_KITS__#'$VERSION'#' $PROJECT_YML -echo "Building startup kits for project $PROJECT_YML with version $VERSION" + +ARGUMENTS="$PROJECT_YML $VERSION" + +echo "Building startup kits: $ARGUMENTS" docker run --rm \ -u $(id -u):$(id -g) \ -v /etc/passwd:/etc/passwd \ -v /etc/group:/etc/group \ -v ./:/workspace/ \ + $MOUNT_VPN_CREDENTIALS_DIR \ -w /workspace/ \ - -e PROJECT_YML=$PROJECT_YML \ - -e VERSION=$VERSION \ - jefftud/odelia:$VERSION \ - /bin/bash -c "nvflare provision -p \$PROJECT_YML && ./_generateStartupKitArchives.sh \$PROJECT_YML \$VERSION"|| { echo "Docker run failed"; exit 1; } + $CONTAINER_NAME \ + /bin/bash -c "nvflare provision -p $PROJECT_YML && ./_generateStartupKitArchives.sh $ARGUMENTS"|| { echo "Docker run failed"; exit 1; } sed -i 's#'$VERSION'#__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_STARTUP_KITS__#' $PROJECT_YML diff --git a/_generateStartupKitArchives.sh b/_generateStartupKitArchives.sh index ea842b41..e76161fc 100755 --- a/_generateStartupKitArchives.sh +++ b/_generateStartupKitArchives.sh @@ -7,7 +7,14 @@ TARGET_FOLDER=`ls -d $OUTPUT_FOLDER/prod_* | tail -n 1` LONG_VERSION=$2 cd $TARGET_FOLDER + for startupkit in `ls .`; do + VPN_CREDENTIALS_FILE=/vpn_credentials/${startupkit}_client.ovpn + if [[ -f $VPN_CREDENTIALS_FILE ]]; then + cp $VPN_CREDENTIALS_FILE ${startupkit}/startup/vpn_client.ovpn + else + echo "$VPN_CREDENTIALS_FILE does not exist, omitting VPN credentials for ${startupkit} in startup kit" + fi zip -rq ${startupkit}_$LONG_VERSION.zip $startupkit echo "Generated startup kit $TARGET_FOLDER/${startupkit}_$LONG_VERSION.zip" done diff --git a/_runTestsInsideDocker.sh b/_runTestsInsideDocker.sh deleted file mode 100755 index d3d07c18..00000000 --- a/_runTestsInsideDocker.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -run_controller_unit_tests_with_coverage () { - # run unit tests of ODELIA swarm learning and report coverage - export MPLCONFIGDIR=/tmp - cd /MediSwarm/tests/unit_tests/controller - PYTHONPATH=/MediSwarm/controller/controller python3 -m coverage run --source=/MediSwarm/controller/controller -m unittest discover - coverage report -m - rm .coverage -} - -run_nvflare_unit_tests () { - cd /MediSwarm/docker_config/NVFlare - ./runtest.sh -c -r - coverage report -m - cd .. -} - -run_minimal_example_standalone () { - # run standalone version of minimal example - cd /MediSwarm/application/jobs/minimal_training_pytorch_cnn/app/custom/ - export TRAINING_MODE="local_training" - ./main.py -} - -run_minimal_example_simulation_mode () { - # run simulation mode for minimal example - cd /MediSwarm - export TRAINING_MODE="swarm" - nvflare simulator -w /tmp/minimal_training_pytorch_cnn -n 2 -t 2 application/jobs/minimal_training_pytorch_cnn -c simulated_node_0,simulated_node_1 -} - -run_minimal_example_proof_of_concept_mode () { - # run proof-of-concept mode for minimal example - cd /MediSwarm - export TRAINING_MODE="swarm" - nvflare poc prepare -c poc_client_0 poc_client_1 - nvflare poc prepare-jobs-dir -j application/jobs/ - nvflare poc start -ex admin@nvidia.com - sleep 15 - echo "Will submit job now after sleeping 15 seconds to allow the background process to complete" - nvflare job submit -j application/jobs/minimal_training_pytorch_cnn - sleep 60 - echo "Will shut down now after sleeping 60 seconds to allow the background process to complete" - sleep 2 - nvflare poc stop -} - -run_controller_unit_tests_with_coverage -# uncomment the following line to run NVFlare's unit tests (takes about 2 minutes and will install python packages in the container) -# run_nvflare_unit_tests -run_minimal_example_standalone -run_minimal_example_simulation_mode -run_minimal_example_proof_of_concept_mode diff --git a/assets/readme/README.developer.md b/assets/readme/README.developer.md index fb6aafc3..1215e574 100644 --- a/assets/readme/README.developer.md +++ b/assets/readme/README.developer.md @@ -24,22 +24,24 @@ The project description specifies the swarm nodes etc. to be used for a swarm tr kits, running local trainings in the startup kit), you can manually push the image to DockerHub, provided you have the necessary rights. Make sure you are not re-using a version number for this purpose. -## Running Local Tests +## Running Tests ```bash - ./runTestsInDocker.sh + ./runIntegrationTests.sh ``` You should see 1. several expected errors and warnings printed from unit tests that should succeed overall, and a coverage report -2. output of a successful simulation run with two nodes -3. output of a successful proof-of-concept run run with two nodes -4. output of a set of startup kits being generated -5. output of a dummy training run using one of the startup kits -6. TODO update this to what the tests output now +2. output of a successful simulation run of a dummy training with two nodes +3. output of a successful proof-of-concept run of a dummy training with two nodes +4. output of a successful simulation run of a 3D CNN training using synthetic data with two nodes +5. output of a set of startup kits being generated +6. output of a Docker/GPU preflight check using one of the startup kits +7. output of a data access preflight check using one of the startup kits +8. output of a dummy training run in a swarm consisting of one server and two client nodes -Optionally, uncomment running NVFlare unit tests in `_runTestsInsideDocker.sh`. +Optionally, uncomment running NVFlare unit tests. ## Distributing Startup Kits @@ -93,3 +95,7 @@ export CONFIG=original run in the swarm 3. Use the local tests to check if the code is swarm-ready 4. TODO more detailed instructions + +## Continuous Integration + +Tests to be executed after pushing to github are defined in `.github/workflows/pr-test.yaml`. diff --git a/assets/readme/README.operator.md b/assets/readme/README.operator.md index 101d5266..3c88b6a1 100644 --- a/assets/readme/README.operator.md +++ b/assets/readme/README.operator.md @@ -19,17 +19,25 @@ For example, add the following line (replace `` with the server's actual IP dl3.tud.de dl3 ``` +TODO describe this in participant REAME if needed + ## Create Startup Kits ### Via Script (recommended) 1. Use, e.g., the file `application/provision/project_MEVIS_test.yml`, adapt as needed (network protocol etc.) -2. Call `buildStartupKits.sh /path/to/project_configuration.yml` to build the startup kits +2. Call `buildDockerImageAndStartupKits.sh -p /path/to/project_configuration.yml -c /path/to/directory/with/VPN/credentials` to build the Docker image and the startup kits + - swarm nodes (admin, server, clients) are configured in `project_configuration.yml` + - the directory with VPN credentials should contain one `.ovpn` file per node + - use `-c tests/local_vpn/client_configs/` to build startup kits for the integration tests 3. Startup kits are generated to `workspace//prod_00/` -4. Deploy startup kits to the respective server/clients +4. Deploy startup kits to the respective server/client operators +5. Push the Docker image to the registry ### Via the Dashboard (not recommended) +Build the Docker image as described above. + ```bash docker run -d --rm \ --ipc=host -p 8443:8443 \ @@ -69,14 +77,14 @@ Access the dashboard at `https://localhost:8443` log in with the admin credentia 2. Client Sites > approve client sites 3. Project Home > freeze project -## Download startup kits +#### Download startup kits After setting up the project admin configuration, server and clients can download their startup kits. Store the passwords somewhere, they are only displayed once (or you can download them again). ## Starting a Swarm Training -1. Connect the *server* host to the VPN as described above. +1. Connect the *server* host to the VPN as described above. (TODO update documentation, this step is not needed if the Docker container handles the VPN connection.) 2. Start the *server* startup kit using the respective `startup/docker.sh` script with the option to start the server 3. Provide the *client* startup kits to the swarm participants (be aware that email providers or other channels may prevent encrypted archives) diff --git a/buildDockerImageAndStartupKits.sh b/buildDockerImageAndStartupKits.sh index 1767cfef..3786b95b 100755 --- a/buildDockerImageAndStartupKits.sh +++ b/buildDockerImageAndStartupKits.sh @@ -13,20 +13,20 @@ DOCKER_BUILD_ARGS="--no-cache --progress=plain"; while [[ "$#" -gt 0 ]]; do case $1 in -p) PROJECT_FILE="$2"; shift ;; + -c) VPN_CREDENTIALS_DIR="$2"; shift ;; --use-docker-cache) DOCKER_BUILD_ARGS="";; *) echo "Unknown parameter passed: $1"; exit 1 ;; esac shift done -if [ -z "$PROJECT_FILE" ]; then - echo "Usage: buildDockerImageAndStartupKits.sh -p [--use-docker-cache]" +if [[ -z "$PROJECT_FILE" || -z "$VPN_CREDENTIALS_DIR" ]]; then + echo "Usage: buildDockerImageAndStartupKits.sh -p -c [--use-docker-cache]" exit 1 fi VERSION=`./getVersionNumber.sh` -DOCKER_IMAGE=jefftud/odelia:$VERSION - +CONTAINER_VERSION_ID=`git rev-parse --short HEAD` # prepare clean version of source code repository clone for building Docker image @@ -41,14 +41,15 @@ git clean -x -q -f . cd ../.. rm .git -rf chmod a+rX . -R -sed -i 's#__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_DOCKER_IMAGE__#'$VERSION'#' docker_config/master_template.yml -cd $CWD +# replacements in copy of source code +sed -i 's#__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_DOCKER_IMAGE__#'$VERSION'#' docker_config/master_template.yml +sed -i 's#__REPLACED_BY_CONTAINER_VERSION_IDENTIFIER_WHEN_BUILDING_DOCKER_IMAGE__#'$CONTAINER_VERSION_ID'#' docker_config/master_template.yml # prepare pre-trained model weights for being included in Docker image -MODEL_WEIGHTS_FILE='docker_config/torch_home_cache/hub/checkpoints/dinov2_vits14_pretrain.pth' -MODEL_LICENSE_FILE='docker_config/torch_home_cache/hub/facebookresearch_dinov2_main/LICENSE' +MODEL_WEIGHTS_FILE=$CWD'/docker_config/torch_home_cache/hub/checkpoints/dinov2_vits14_pretrain.pth' +MODEL_LICENSE_FILE=$CWD'/docker_config/torch_home_cache/hub/facebookresearch_dinov2_main/LICENSE' if [[ ! -f $MODEL_WEIGHTS_FILE || ! -f $MODEL_LICENSE_FILE ]]; then echo "Pre-trained model not available. Attempting download" HUBDIR=$(dirname $(dirname $MODEL_LICENSE_FILE)) @@ -61,22 +62,26 @@ if [[ ! -f $MODEL_WEIGHTS_FILE || ! -f $MODEL_LICENSE_FILE ]]; then fi if echo 2e405cee1bad14912278296d4f42e993 $MODEL_WEIGHTS_FILE | md5sum --check - && echo 153d2db1c329326a2d9f881317ea942e $MODEL_LICENSE_FILE | md5sum --check -; then - cp -r ./docker_config/torch_home_cache $CLEAN_SOURCE_DIR/torch_home_cache + cp -r $CWD/docker_config/torch_home_cache $CLEAN_SOURCE_DIR/torch_home_cache else exit 1 fi chmod a+rX $CLEAN_SOURCE_DIR/torch_home_cache -R +cd $CWD # build and print follow-up steps +CONTAINER_NAME=`grep " docker_image: " $PROJECT_FILE | sed 's/ docker_image: //' | sed 's#__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_STARTUP_KITS__#'$VERSION'#'` +echo $CONTAINER_NAME -docker build $DOCKER_BUILD_ARGS -t $DOCKER_IMAGE $CLEAN_SOURCE_DIR -f docker_config/Dockerfile_ODELIA +docker build $DOCKER_BUILD_ARGS -t $CONTAINER_NAME $CLEAN_SOURCE_DIR -f docker_config/Dockerfile_ODELIA -echo "Docker image $DOCKER_IMAGE built successfully" -echo "./_buildStartupKits.sh $PROJECT_FILE $VERSION" -./_buildStartupKits.sh $PROJECT_FILE $VERSION +echo "Docker image $CONTAINER_NAME built successfully" +echo "./_buildStartupKits.sh $PROJECT_FILE $VERSION $CONTAINER_NAME" +VPN_CREDENTIALS_DIR=$(realpath $VPN_CREDENTIALS_DIR) +./_buildStartupKits.sh $PROJECT_FILE $VERSION $CONTAINER_NAME $VPN_CREDENTIALS_DIR echo "Startup kits built successfully" rm -rf $CLEAN_SOURCE_DIR -echo "If you wish, manually push $DOCKER_IMAGE now" +echo "If you wish, manually push $CONTAINER_NAME now" diff --git a/docker_config/Dockerfile_ODELIA b/docker_config/Dockerfile_ODELIA index 2d2f018d..269889b7 100644 --- a/docker_config/Dockerfile_ODELIA +++ b/docker_config/Dockerfile_ODELIA @@ -189,6 +189,21 @@ RUN apt install -y \ xdg-user-dirs=0.17-2ubuntu4 \ xz-utils=5.2.5-2ubuntu1 +# openvpn iputils-ping net-tools sudo and dependencies at fixed versions +# TODO remove tools only needed for debugging +RUN apt install -y \ + iproute2=5.15.0-1ubuntu2 \ + iputils-ping=3:20211215-1ubuntu0.1 \ + libatm1=1:2.5.1-4build2 \ + libbpf0=1:0.5.0-1ubuntu22.04.1 \ + libcap2-bin=1:2.44-1ubuntu0.22.04.2 \ + libelf1=0.186-1ubuntu0.1 \ + liblzo2-2=2.10-2build3 \ + libpam-cap=1:2.44-1ubuntu0.22.04.2 \ + libpkcs11-helper1=1.28-1ubuntu0.22.04.1 \ + net-tools=1.60+git20181103.0eebece-1ubuntu5.4 \ + openvpn=2.5.11-0ubuntu0.22.04.1 + # Clean up apt cache RUN rm -rf /var/lib/apt/lists/* @@ -343,3 +358,9 @@ RUN ln -s /MediSwarm /fl_admin/transfer/MediSwarm # Copy pre-trained model weights to image COPY ./torch_home_cache /torch_home + +# allow creating home directory for local user inside container if needed +RUN chmod a+rwx /home + +# allow starting VPN connection by non-root users +RUN chmod gu+s /usr/sbin/openvpn diff --git a/docker_config/master_template.yml b/docker_config/master_template.yml index 0a2306db..c3f3d9d2 100644 --- a/docker_config/master_template.yml +++ b/docker_config/master_template.yml @@ -334,6 +334,9 @@ authz_def: | fl_admin_sh: | #!/usr/bin/env bash + + openvpn ./vpn_client.ovpn >> nohup_vpn.out 2>&1 & + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" python3 -m nvflare.fuel.hci.tools.admin -m $DIR/.. -s fed_admin.json @@ -367,6 +370,9 @@ start_ovsr_sh: | start_cln_sh: | #!/usr/bin/env bash + + openvpn ./vpn_client.ovpn >> nohup_vpn.out 2>&1 & + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" all_arguments="${@}" doCloud=false @@ -392,6 +398,9 @@ start_cln_sh: | start_svr_sh: | #!/usr/bin/env bash + + openvpn ./vpn_client.ovpn >> nohup_vpn.out 2>&1 & + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" all_arguments="${@}" doCloud=false @@ -670,7 +679,7 @@ docker_cln_sh: | chmod -R 777 "$MY_SCRATCH_DIR" # Networking & Cleanup - NETARG="--net=host" + NETARG="--cap-add=NET_ADMIN --device /dev/net/tun" rm -rf ../pid.fl ../daemon_pid.fl # Docker image and container name @@ -680,8 +689,12 @@ docker_cln_sh: | docker pull "$DOCKER_IMAGE" fi - CONTAINER_NAME=odelia_swarm_client_{~~client_name~~} + CONTAINER_NAME=odelia_swarm_client_{~~client_name~~}___REPLACED_BY_CONTAINER_VERSION_IDENTIFIER_WHEN_BUILDING_DOCKER_IMAGE__ DOCKER_OPTIONS_A="--name=$CONTAINER_NAME --gpus=$GPU2USE -u $(id -u):$(id -g)" + DOCKER_OPTIONS_A+=" --add-host dl3.tud.de:72.24.4.65 --add-host dl3:72.24.4.65" + if [[ ! -z "$ODELIA_ADDITIONAL_DOCKER_OPTIONS" ]]; then + DOCKER_OPTIONS_A+=" ${ODELIA_ADDITIONAL_DOCKER_OPTIONS}" + fi DOCKER_MOUNTS="-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group -v $DIR/..:/startupkit/ -v $MY_SCRATCH_DIR:/scratch/" if [[ ! -z "$MY_DATA_DIR" ]]; then DOCKER_MOUNTS+=" -v $MY_DATA_DIR:/data/:ro" @@ -754,33 +767,42 @@ docker_svr_sh: | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" # to use host network, use line below - NETARG="--net=host" + NETARG="--cap-add=NET_ADMIN --device /dev/net/tun" # or to expose specific ports, use line below #NETARG="-p {~~admin_port~~}:{~~admin_port~~} -p {~~fed_learn_port~~}:{~~fed_learn_port~~}" + # TODO check if admin rights are needed and make sure output files are readable and deletable by non-root users on the host + DOCKER_IMAGE={~~docker_image~~} if [ -z "$NOPULL" ]; then echo "Updating docker image" docker pull $DOCKER_IMAGE fi svr_name="${SVR_NAME:-flserver}" - CONTAINER_NAME=odelia_swarm_server_$svr_name + CONTAINER_NAME=odelia_swarm_server_${svr_name}___REPLACED_BY_CONTAINER_VERSION_IDENTIFIER_WHEN_BUILDING_DOCKER_IMAGE__ rm -rf ../pid.fl ../daemon_pid.fl # clean up potential leftovers from previous run + ADDITIONAL_DOCKER_OPTIONS=" --add-host dl3.tud.de:72.24.4.65 --add-host dl3:72.24.4.65" + if [[ ! -z "$ODELIA_ADDITIONAL_DOCKER_OPTIONS" ]]; then + ADDITIONAL_DOCKER_OPTIONS+=" ${ODELIA_ADDITIONAL_DOCKER_OPTIONS}" + fi + echo "Starting docker with $DOCKER_IMAGE as $CONTAINER_NAME" # Run docker with appropriate parameters if [ ! -z "$START_SERVER" ]; then docker run -d -t --rm --name=$CONTAINER_NAME \ + ${ADDITIONAL_DOCKER_OPTIONS} \ -v $DIR/..:/startupkit/ -w /startupkit/startup/ \ --ipc=host $NETARG $DOCKER_IMAGE \ /bin/bash -c "nohup ./start.sh >> nohup.out 2>&1 && chmod a+r nohup.out && /bin/bash" elif [ ! -z "$LIST_LICENSES" ]; then - docker run -it --rm --name=$CONTAINER_NAME \ + docker run --rm --name=$CONTAINER_NAME \ $DOCKER_IMAGE \ /bin/bash -c "pip-licenses -s -u --order=license" elif [ ! -z "$INTERACTIVE" ]; then docker run --rm -it --detach-keys="ctrl-x" --name=$CONTAINER_NAME \ + ${ADDITIONAL_DOCKER_OPTIONS} \ -v $DIR/..:/startupkit/ -w /startupkit/startup/ \ --ipc=host $NETARG $DOCKER_IMAGE \ /bin/bash -c "/bin/bash" @@ -804,17 +826,28 @@ docker_adm_sh: | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" # To use host network - NETARG="--net=host" + NETARG="--cap-add=NET_ADMIN --device /dev/net/tun" + + # TODO check if admin rights are needed and make sure output files are readable and deletable by non-root users on the host DOCKER_IMAGE={~~docker_image~~} if [ -z "$NOPULL" ]; then echo "Updating docker image" docker pull $DOCKER_IMAGE fi - CONTAINER_NAME=odelia_swarm_admin + CONTAINER_NAME=odelia_swarm_admin___REPLACED_BY_CONTAINER_VERSION_IDENTIFIER_WHEN_BUILDING_DOCKER_IMAGE__ + + ADDITIONAL_DOCKER_OPTIONS=" --add-host dl3.tud.de:72.24.4.65 --add-host dl3:72.24.4.65" + if [[ ! -z "$ODELIA_ADDITIONAL_DOCKER_OPTIONS" ]]; then + ADDITIONAL_DOCKER_OPTIONS+=" ${ODELIA_ADDITIONAL_DOCKER_OPTIONS}" + fi echo "Starting docker with $DOCKER_IMAGE as $CONTAINER_NAME" - docker run --rm -it --name=fladmin -v $DIR/../local/:/fl_admin/local/ -v $DIR/../startup/:/fl_admin/startup/ -w /fl_admin/startup/ $NETARG $DOCKER_IMAGE /bin/bash -c "./fl_admin.sh" + docker run --rm -it --name=$CONTAINER_NAME \ + ${ADDITIONAL_DOCKER_OPTIONS} \ + -v $DIR/../local/:/fl_admin/local/ -v $DIR/../startup/:/fl_admin/startup/ \ + -w /fl_admin/startup/ $NETARG $DOCKER_IMAGE \ + /bin/bash -c "./fl_admin.sh" compose_yaml: | services: diff --git a/runIntegrationTests.sh b/runIntegrationTests.sh new file mode 100755 index 00000000..3433195b --- /dev/null +++ b/runIntegrationTests.sh @@ -0,0 +1,543 @@ +#!/usr/bin/env bash + +set -e + +VERSION=$(./getVersionNumber.sh) +CONTAINER_VERSION_SUFFIX=$(git rev-parse --short HEAD) +DOCKER_IMAGE=localhost:5000/odelia:$VERSION +PROJECT_DIR="workspace/odelia_${VERSION}_dummy_project_for_testing" +SYNTHETIC_DATA_DIR=$(mktemp -d) +SCRATCH_DIR=$(mktemp -d) +CWD=$(pwd) +PROJECT_FILE="tests/provision/dummy_project_for_testing.yml" +if [ -z "$GPU_FOR_TESTING" ]; then + export GPU_FOR_TESTING="all" +fi + + +check_files_on_github () { + echo "[Run] Test whether expected content is available on github" + + LICENSE_ON_GITHUB=$(curl -L https://github.com/KatherLab/MediSwarm/raw/refs/heads/main/LICENSE) + if echo "$LICENSE_ON_GITHUB" | grep -q "MIT License" ; then + echo "Downloaded and verified license from github" + else + echo "Could not download and verify license" + exit 1 + fi + + MAIN_README=$(curl -L https://github.com/KatherLab/MediSwarm/raw/refs/heads/main/README.md) + for ROLE in 'Swarm Participant' 'Developer' 'Swarm Operator'; + do + if echo "$MAIN_README" | grep -qie "$ROLE" ; then + echo "Instructions for $ROLE found" + else + echo "Instructions for role $ROLE missing" + exit 1 + fi + done + + PARTICIPANT_README=$(curl -L https://github.com/KatherLab/MediSwarm/raw/refs/heads/main/assets/readme/README.participant.md) + for EXPECTED_KEYWORDS in 'Prerequisites' 'RAM' 'Ubuntu' 'VPN' 'Prepare Dataset' './docker.sh' 'Local Training' 'Start Swarm Node'; + do + if echo "$PARTICIPANT_README" | grep -qie "$EXPECTED_KEYWORDS" ; then + echo "Instructions on $EXPECTED_KEYWORDS found" + else + echo "Instructions on $EXPECTED_KEYWORDS missing" + exit 1 + fi + done + + SWARM_OPERATOR_README=$(curl -L https://github.com/KatherLab/MediSwarm/raw/refs/heads/main/assets/readme/README.operator.md) + for EXPECTED_KEYWORDS in 'Create Startup Kits' 'Starting a Swarm Training'; + do + if echo "$SWARM_OPERATOR_README" | grep -qie "$EXPECTED_KEYWORDS" ; then + echo "Instructions on $EXPECTED_KEYWORDS found" + else + echo "Instructions on $EXPECTED_KEYWORDS missing" + exit 1 + fi + done + + APC_DEVELOPER_README=$(curl -L https://github.com/KatherLab/MediSwarm/raw/refs/heads/main/assets/readme/README.developer.md) + for EXPECTED_KEYWORDS in 'Contributing Application Code'; + do + if echo "$APC_DEVELOPER_README" | grep -qie "$EXPECTED_KEYWORDS" ; then + echo "Instructions on $EXPECTED_KEYWORDS found" + else + echo "Instructions on $EXPECTED_KEYWORDS missing" + exit 1 + fi + done + + DUMMY_TRAINING_APC=$(curl -L https://raw.githubusercontent.com/KatherLab/MediSwarm/refs/heads/main/application/jobs/minimal_training_pytorch_cnn/app/custom/main.py) + for EXPECTED_KEYWORDS in 'python3'; + do + if echo "$DUMMY_TRAINING_APC" | grep -qie "$EXPECTED_KEYWORDS" ; then + echo "Dummy Training ApC: $EXPECTED_KEYWORDS found" + else + echo "Dummy Training ApC: $EXPECTED_KEYWORDS missing" + exit 1 + fi + done +} + + +_run_test_in_docker() { + echo "[Run]" $1 "inside Docker ..." + docker run --rm \ + --shm-size=16g \ + --ipc=host \ + --ulimit memlock=-1 \ + --ulimit stack=67108864 \ + -u $(id -u):$(id -g) \ + -v /etc/passwd:/etc/passwd -v /etc/group:/etc/group \ + -v "$SYNTHETIC_DATA_DIR":/data \ + -v "$SCRATCH_DIR":/scratch \ + --gpus="$GPU_FOR_TESTING" \ + --entrypoint=/MediSwarm/$1 \ + "$DOCKER_IMAGE" +} + + +run_unit_tests_controller(){ + echo "[Run] Controller unit tests" + _run_test_in_docker tests/integration_tests/_run_controller_unit_tests_with_coverage.sh +} + +run_dummy_training_standalone(){ + echo "[Run] Minimal example, standalone" + _run_test_in_docker tests/integration_tests/_run_minimal_example_standalone.sh +} + +run_dummy_training_simulation_mode(){ + echo "[Run] Minimal example, simulation mode" + _run_test_in_docker tests/integration_tests/_run_minimal_example_simulation_mode.sh +} + +run_dummy_training_poc_mode(){ + echo "[Run] Minimal example, proof-of-concept mode" + _run_test_in_docker tests/integration_tests/_run_minimal_example_proof_of_concept_mode.sh +} + +run_nvflare_unit_tests(){ + echo "[Run] NVFlare unit tests" + _run_test_in_docker tests/unit_tests/_run_nvflare_unit_tests.sh +} + + +create_startup_kits_and_check_contained_files () { + echo "[Prepare] Startup kits for test project ..." + + if [ ! -d "$PROJECT_DIR"/prod_00 ]; then + ./_buildStartupKits.sh $PROJECT_FILE $VERSION $DOCKER_IMAGE + fi + if [ -d "$PROJECT_DIR"/prod_01 ]; then + echo '$PROJECT_DIR/prod_01 exists, please remove/rename it' + exit 1 + fi + ./_buildStartupKits.sh $PROJECT_FILE $VERSION $DOCKER_IMAGE + + for FILE in 'client.crt' 'client.key' 'docker.sh' 'rootCA.pem'; + do + if [ -f "$PROJECT_DIR/prod_01/client_A/startup/$FILE" ] ; then + echo "$FILE found" + else + echo "$FILE missing" + exit 1 + fi + done + + ZIP_CONTENT=$(unzip -tv "$PROJECT_DIR/prod_01/client_B_${VERSION}.zip") + for FILE in 'client.crt' 'client.key' 'docker.sh' 'rootCA.pem'; + do + if echo "$ZIP_CONTENT" | grep -q "$FILE" ; then + echo "$FILE found in zip" + else + echo "$FILE missing in zip" + exit 1 + fi + done +} + + +create_synthetic_data () { + echo "[Prepare] Synthetic data ..." + docker run --rm \ + -u $(id -u):$(id -g) \ + -v /etc/passwd:/etc/passwd -v /etc/group:/etc/group \ + -v "$SYNTHETIC_DATA_DIR":/synthetic_data \ + -w /MediSwarm \ + $DOCKER_IMAGE \ + /bin/bash -c "python3 application/jobs/ODELIA_ternary_classification/app/scripts/create_synthetic_dataset/create_synthetic_dataset.py /synthetic_data" +} + + +run_list_licenses () { + cd "$PROJECT_DIR"/prod_00 + cd testserver.local/startup + LICENSES_LISTED=$(./docker.sh --list_licenses --no_pull) + + for EXPECTED_KEYWORDS in 'scikit-learn' 'torch' 'nvflare_mediswarm' 'BSD License' 'MIT License'; + do + if echo "$LICENSES_LISTED" | grep -qie "$EXPECTED_KEYWORDS" ; then + echo "Instructions on $EXPECTED_KEYWORDS found" + else + echo "Instructions on $EXPECTED_KEYWORDS missing" + exit 1 + fi + done + + cd "$CWD" +} + + +run_docker_gpu_preflight_check () { + # requires having built a startup kit + echo "[Run] Docker/GPU preflight check (local dummy training via startup kit) ..." + cd "$PROJECT_DIR/prod_00/client_A/startup/" + CONSOLE_OUTPUT=docker_gpu_preflight_check_console_output.txt + ./docker.sh --scratch_dir "$SCRATCH_DIR"/client_A --GPU device=$GPU_FOR_TESTING --dummy_training --no_pull 2>&1 | tee "$CONSOLE_OUTPUT" + + if grep -q "Epoch 1: 100%" "$CONSOLE_OUTPUT" && grep -q "Training completed successfully" "$CONSOLE_OUTPUT"; then + echo "Expected output of Docker/GPU preflight check found" + else + echo "Missing expected output of Docker/GPU preflight check" + exit 1 + fi + + cd "$CWD" +} + + +run_data_access_preflight_check () { + # requires having built a startup kit and synthetic dataset + echo "[Run] Data access preflight check..." + cd "$PROJECT_DIR"/prod_00 + cd client_A/startup + CONSOLE_OUTPUT=data_access_preflight_check_console_output.txt + ./docker.sh --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir "$SCRATCH_DIR"/client_A --GPU device=$GPU_FOR_TESTING --preflight_check --no_pull 2>&1 | tee $CONSOLE_OUTPUT + + if grep -q "Train set: 18, Val set: 6" "$CONSOLE_OUTPUT" && grep -q "Epoch 0: 100%" "$CONSOLE_OUTPUT"; then + echo "Expected output of Docker/GPU preflight check found" + else + echo "Missing expected output of Docker/GPU preflight check" + exit 1 + fi + + cd "$CWD" +} + + +run_3dcnn_simulation_mode () { + # requires having built a startup kit and synthetic dataset + echo "[Run] Simulation mode of 3DCNN training in Docker" + _run_test_in_docker tests/integration_tests/_run_3dcnn_simulation_mode.sh +} + + +start_testing_vpn () { + echo "[Prepare] Start local VPN server for testing ..." + + cp -r tests/local_vpn "$PROJECT_DIR"/prod_00/ + chmod a+rX "$PROJECT_DIR"/prod_00/local_vpn -R + cd "$PROJECT_DIR"/prod_00/local_vpn + ./run_docker_openvpnserver.sh + cd "$CWD" +} + + +kill_testing_vpn () { + echo "[Cleanup] Kill local VPN server Docker container ..." + docker kill odelia_testing_openvpnserver +} + + +start_server_and_clients () { + echo "[Run] Start server and client Docker containers ..." + export ODELIA_ADDITIONAL_DOCKER_OPTIONS="--add-host testserver.local:10.8.0.4" + cd "$PROJECT_DIR"/prod_00 + cd testserver.local/startup + ./docker.sh --no_pull --start_server + cd ../.. + sleep 10 + + cd client_A/startup + ./docker.sh --no_pull --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir "$SCRATCH_DIR"/client_A --GPU device=$GPU_FOR_TESTING --start_client + cd ../.. + cd client_B/startup + ./docker.sh --no_pull --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir "$SCRATCH_DIR"/client_B --GPU device=$GPU_FOR_TESTING --start_client + sleep 8 + + cd "$CWD" +} + + +start_registry_docker_and_push () { + docker run -d --rm -p 5000:5000 --name local_test_registry_$CONTAINER_VERSION_SUFFIX registry:3 + sleep 3 + docker push localhost:5000/odelia:$VERSION +} + + +run_container_with_pulling () { + docker rmi localhost:5000/odelia:$VERSION + cd "$PROJECT_DIR"/prod_00 + cd testserver.local/startup + OUTPUT=$(./docker.sh --list_licenses) + + if echo "$OUTPUT" | grep -qie "Status: Downloaded newer image for localhost:5000/odelia:$VERSION" ; then + echo "Image pulled successfully" + else + echo "Instructions on $EXPECTED_KEYWORDS missing" + exit 1 + fi + + cd "$CWD" +} + + +kill_registry_docker () { + docker kill local_test_registry_$CONTAINER_VERSION_SUFFIX +} + + +verify_wrong_client_does_not_connect () { + echo "[Run] Verify that client with outdated startup kit does not connect ..." + + cp -r "$PROJECT_DIR"/prod_01 "$PROJECT_DIR"/prod_wrong_client + cd "$PROJECT_DIR"/prod_wrong_client + cd testserver.local/startup + ./docker.sh --no_pull --start_server + cd ../.. + sleep 10 + + rm client_A -rf + tar xvf "$CWD"/tests/integration_tests/outdated_startup_kit.tar.gz + sed -i 's#DOCKER_IMAGE=localhost:5000/odelia:1.0.1-dev.250919.095c1b7#DOCKER_IMAGE='$DOCKER_IMAGE'#' client_A/startup/docker.sh + sed -i 's#CONTAINER_NAME=odelia_swarm_client_client_A_095c1b7#CONTAINER_NAME=odelia_swarm_client_client_A_'$CONTAINER_VERSION_SUFFIX'#' client_A/startup/docker.sh + + cd client_A/startup + ./docker.sh --no_pull --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir "$SCRATCH_DIR"/client_A --GPU device=$GPU_FOR_TESTING --start_client + cd ../.. + + sleep 20 + + CONSOLE_OUTPUT_SERVER=testserver.local/startup/nohup.out + CONSOLE_OUTPUT_CLIENT=client_A/startup/nohup.out + + if grep -q "Total clients: 1" $CONSOLE_OUTPUT_SERVER; then + echo "Connection with non-authorized client" + exit 1 + else + echo "Connection rejected successfully by server" + fi + + if grep -q "SSLCertVerificationError" $CONSOLE_OUTPUT_CLIENT; then + echo "Connection rejected successfully by client" + else + echo "Could not verify that connection was rejected" + exit 1 + fi + + docker kill odelia_swarm_server_flserver_$CONTAINER_VERSION_SUFFIX odelia_swarm_client_client_A_$CONTAINER_VERSION_SUFFIX + rm -rf "$PROJECT_DIR"/prod_wrong_client + + cd "$CWD" +} + + +run_dummy_training_in_swarm () { + echo "[Run] Dummy training in swarm ..." + + cd "$PROJECT_DIR"/prod_00 + cd admin@test.odelia/startup + "$CWD"/tests/integration_tests/_submitDummyTraining.exp + docker kill odelia_swarm_admin_$CONTAINER_VERSION_SUFFIX + sleep 60 + cd "$CWD" + + cd "$PROJECT_DIR"/prod_00/testserver.local/startup + CONSOLE_OUTPUT=nohup.out + for EXPECTED_OUTPUT in 'Total clients: 2' 'updated status of client client_A on round 4' 'updated status of client client_B on round 4' 'all_done=True' 'Server runner finished.' \ + 'Start to the run Job: [0-9a-f]\{8\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{12\}' 'updated status of client client_B on round 4'; + do + if grep -q --regexp="$EXPECTED_OUTPUT" "$CONSOLE_OUTPUT"; then + echo "Expected output $EXPECTED_OUTPUT found" + else + echo "Expected output $EXPECTED_OUTPUT missing" + exit 1 + fi + done + cd "$CWD" + + cd "$PROJECT_DIR"/prod_00/client_A/startup + CONSOLE_OUTPUT=nohup.out + for EXPECTED_OUTPUT in 'Sending training result to aggregation client' 'Epoch 9: 100%' 'val/AUC_ROC'; + do + if grep -q "$EXPECTED_OUTPUT" "$CONSOLE_OUTPUT"; then + echo "Expected output $EXPECTED_OUTPUT found" + else + echo "Expected output $EXPECTED_OUTPUT missing" + exit 1 + fi + done + cd "$CWD" + + for EXPECTED_OUTPUT in 'validation metric .* from client' 'aggregating [0-9]* update(s) at round [0-9]*'; + do + if grep -q --regexp="$EXPECTED_OUTPUT" "$PROJECT_DIR"/prod_00/client_?/startup/nohup.out; then + echo "Expected output $EXPECTED_OUTPUT found" + else + echo "Expected output $EXPECTED_OUTPUT missing" + exit 1 + fi + done + + cd "$PROJECT_DIR"/prod_00/client_A/ + FILES_PRESENT=$(find . -type f -name "*.*") + for EXPECTED_FILE in 'custom/minimal_training.py' 'best_FL_global_model.pt' 'FL_global_model.pt' ; + do + if echo "$FILES_PRESENT" | grep -q "$EXPECTED_FILE" ; then + echo "Expected file $EXPECTED_FILE found" + else + echo "Expected file $EXPECTED_FILE missing" + exit 1 + fi + done + + actualsize=$(wc -c <*/app_client_A/best_FL_global_model.pt) + if [ $actualsize -le 1048576 ]; then + echo "Checkpoint file size OK" + else + echo "Checkpoint too large: " $actualsize + exit 1 + fi + + cd "$CWD" +} + + +kill_server_and_clients () { + echo "[Cleanup] Kill server and client Docker containers ..." + docker kill odelia_swarm_server_flserver_$CONTAINER_VERSION_SUFFIX odelia_swarm_client_client_A_$CONTAINER_VERSION_SUFFIX odelia_swarm_client_client_B_$CONTAINER_VERSION_SUFFIX +} + + +cleanup_temporary_data () { + echo "[Cleanup] Removing synthetic data, scratch directory, dummy workspace ..." + rm -rf "$SYNTHETIC_DATA_DIR" + rm -rf "$SCRATCH_DIR" + rm -rf "$PROJECT_DIR" +} + + +case "$1" in + check_files_on_github) + check_files_on_github + ;; + + run_unit_tests_controller) + run_unit_tests_controller + cleanup_temporary_data + ;; + + run_dummy_training_standalone) + run_dummy_training_standalone + cleanup_temporary_data + ;; + + run_dummy_training_simulation_mode) + run_dummy_training_simulation_mode + cleanup_temporary_data + ;; + + run_dummy_training_poc_mode) + run_dummy_training_poc_mode + cleanup_temporary_data + ;; + + run_3dcnn_simulation_mode) + create_synthetic_data + run_3dcnn_simulation_mode + cleanup_temporary_data + ;; + + create_startup_kits) + create_startup_kits_and_check_contained_files + cleanup_temporary_data + ;; + + run_list_licenses) + create_startup_kits_and_check_contained_files + run_list_licenses + cleanup_temporary_data + ;; + + run_docker_gpu_preflight_check) + create_startup_kits_and_check_contained_files + run_docker_gpu_preflight_check + cleanup_temporary_data + ;; + + run_data_access_preflight_check) + create_startup_kits_and_check_contained_files + create_synthetic_data + run_data_access_preflight_check + cleanup_temporary_data + ;; + + push_pull_image) + create_startup_kits_and_check_contained_files + start_registry_docker_and_push + run_container_with_pulling + kill_registry_docker + # TODO add to CI if we want this (takes several minutes) + ;; + + check_wrong_startup_kit) + create_startup_kits_and_check_contained_files + create_synthetic_data + verify_wrong_client_does_not_connect + cleanup_temporary_data + # TODO add to CI if we want this + ;; + + run_dummy_training_in_swarm) + create_startup_kits_and_check_contained_files + create_synthetic_data + start_testing_vpn + start_server_and_clients + run_dummy_training_in_swarm + kill_server_and_clients + kill_testing_vpn + cleanup_temporary_data + # TODO add to CI if we want this (currently not working) + ;; + + all | "") + check_files_on_github + run_unit_tests_controller + run_dummy_training_standalone + run_dummy_training_simulation_mode + run_dummy_training_poc_mode + # run_nvflare_unit_tests # uncomment to enable NVFlare unit tests + create_synthetic_data + run_3dcnn_simulation_mode + create_startup_kits_and_check_contained_files + start_registry_docker_and_push + run_container_with_pulling + kill_registry_docker + run_docker_gpu_preflight_check + run_data_access_preflight_check + start_testing_vpn + start_server_and_clients + kill_testing_vpn + verify_wrong_client_does_not_connect + run_dummy_training_in_swarm + kill_server_and_clients + cleanup_temporary_data + ;; + + *) echo "Unknown argument: $1"; exit 1 ;; +esac diff --git a/runTestsInDocker.sh b/runTestsInDocker.sh deleted file mode 100755 index 329ee6cf..00000000 --- a/runTestsInDocker.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash - -set -e - -VERSION=$(./getVersionNumber.sh) -DOCKER_IMAGE=jefftud/odelia:$VERSION -PROJECT_DIR="workspace/odelia_${VERSION}_dummy_project_for_testing" -CWD=$(pwd) -if [ -z "$GPU_FOR_TESTING" ]; then - export GPU_FOR_TESTING="all" -fi - - -run_tests () { - echo "[Run] Unit tests inside Docker..." - docker run --rm \ - --shm-size=16g \ - --ipc=host \ - --ulimit memlock=-1 \ - --ulimit stack=67108864 \ - -v /tmp:/scratch \ - --gpus="$GPU_FOR_TESTING" \ - --entrypoint=/MediSwarm/_runTestsInsideDocker.sh \ - "$DOCKER_IMAGE" -} - -prepare_dummy_trainings () { - echo "[Prepare] Startup kits for dummy project..." - rm -rf "$PROJECT_DIR" - ./_buildStartupKits.sh tests/provision/dummy_project_for_testing.yml "$VERSION" -} - -run_dummy_training () { - echo "[Run] Dummy training session..." - cd "$PROJECT_DIR/prod_00/client_A/startup/" - ./docker.sh --data_dir /tmp/ --scratch_dir /tmp/scratch --GPU "$GPU_FOR_TESTING" --no_pull --dummy_training - cd "$CWD" -} - -run_3dcnn_tests () { - echo "[Run] Synthetic data + 3D CNN preflight check..." - SYNTHETIC_DATA_DIR=$(mktemp -d) - - # create synthetic data - docker run --rm \ - -u $(id -u):$(id -g) \ - -v "$SYNTHETIC_DATA_DIR":/synthetic_data \ - -w /MediSwarm \ - jefftud/odelia:$VERSION \ - /bin/bash -c "python3 application/jobs/ODELIA_ternary_classification/app/scripts/create_synthetic_dataset/create_synthetic_dataset.py /synthetic_data" - - # run tests using synthetic data - cd "$PROJECT_DIR/prod_00/client_A/startup/" - # preflight check (standalone) and swarm simulation mode - ./docker.sh --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir /tmp/scratch --GPU "$GPU_FOR_TESTING" --no_pull --preflight_check - ./docker.sh --data_dir "$SYNTHETIC_DATA_DIR" --scratch_dir /tmp/scratch --GPU "$GPU_FOR_TESTING" --no_pull --run_script /MediSwarm/_run3DdcnnptlTestsInDocker.sh - - cd "$CWD" - - # clean up synthetic data - rm -rf "$SYNTHETIC_DATA_DIR" || echo "Warning: cleanup failed" -} - - -cleanup_dummy_trainings () { - echo "[Cleanup] Removing dummy workspace..." - rm -rf "$PROJECT_DIR" -} - -case "$1" in - run_tests) run_tests ;; - prepare_dummy_trainings) prepare_dummy_trainings ;; - run_dummy_training) run_dummy_training ;; - run_3dcnn_tests) run_3dcnn_tests ;; - cleanup) cleanup_dummy_trainings ;; - all | "") - run_tests - prepare_dummy_trainings - run_dummy_training - run_3dcnn_tests - cleanup_dummy_trainings - ;; - *) echo "Unknown argument: $1"; exit 1 ;; -esac diff --git a/scripts/ci/update_apt_versions.sh b/scripts/ci/update_apt_versions.sh index 75d6732a..0d1d00ec 100755 --- a/scripts/ci/update_apt_versions.sh +++ b/scripts/ci/update_apt_versions.sh @@ -4,6 +4,7 @@ set -e DOCKERFILE_PATH="docker_config/Dockerfile_ODELIA" LOG_PATH=$(mktemp) PROJECT_YML="tests/provision/dummy_project_for_testing.yml" +VPN_TEST_CREDENTIALS="tests/local_vpn/client_configs/" echo "[INFO] Removing APT version pins from Dockerfile..." scripts/dev_utils/dockerfile_update_removeVersionApt.py "$DOCKERFILE_PATH" @@ -14,7 +15,7 @@ git config user.name "GitHub CI" git commit "$DOCKERFILE_PATH" -m "WIP: remove apt versions for rebuild" || echo "[INFO] No version pin removal change to commit." echo "[INFO] Rebuilding Docker image and capturing logs..." -if ! ./buildDockerImageAndStartupKits.sh -p "$PROJECT_YML" > "$LOG_PATH" 2>&1; then +if ! ./buildDockerImageAndStartupKits.sh -p "$PROJECT_YML" -c "$VPN_TEST_CREDENTIALS" > "$LOG_PATH" 2>&1; then echo "Build failed. Output:" cat "$LOG_PATH" exit 1 diff --git a/scripts/dev_utils/remove_old_odelia_docker_images.sh b/scripts/dev_utils/remove_old_odelia_docker_images.sh index 7da4ee25..5f25f6d3 100755 --- a/scripts/dev_utils/remove_old_odelia_docker_images.sh +++ b/scripts/dev_utils/remove_old_odelia_docker_images.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash export OLD_ODELIA_DOCKER_IMAGES=$(docker image list | grep jefftud/odelia | sed 's|jefftud/odelia *[0-9a-z.-]* *||' | sed 's| *.*||' | tail -n +2) +export OLD_ODELIA_DOCKER_IMAGES_LOCAL=$(docker image list | grep localhost:5000/odelia | sed 's|localhost:5000/odelia *[0-9a-z.-]* *||' | sed 's| *.*||' | tail -n +2) echo "All docker images:" @@ -8,12 +9,12 @@ docker image list echo "The following Docker images are old ODELIA docker images:" -echo "$OLD_ODELIA_DOCKER_IMAGES" +echo "$OLD_ODELIA_DOCKER_IMAGES" "$OLD_ODELIA_DOCKER_IMAGES_LOCAL" read -p "Delete these Docker images, unless they have additional tags? (y/n): " answer if [[ "$answer" == "y" ]]; then - for image in $OLD_ODELIA_DOCKER_IMAGES; do + for image in $OLD_ODELIA_DOCKER_IMAGES $OLD_ODELIA_DOCKER_IMAGES_LOCAL; do docker rmi $image done fi diff --git a/_run3DdcnnptlTestsInDocker.sh b/tests/integration_tests/_run_3dcnn_simulation_mode.sh similarity index 84% rename from _run3DdcnnptlTestsInDocker.sh rename to tests/integration_tests/_run_3dcnn_simulation_mode.sh index 7fb7a877..a39da49d 100755 --- a/_run3DdcnnptlTestsInDocker.sh +++ b/tests/integration_tests/_run_3dcnn_simulation_mode.sh @@ -11,11 +11,13 @@ run_3dcnn_simulation_mode () { sed -i 's/num_rounds = .*/num_rounds = 2/' ${TMPDIR}/ODELIA_ternary_classification/app/config/config_fed_server.conf export TRAINING_MODE="swarm" export SITE_NAME="client_A" + export DATA_DIR=/data + export SCRATCH_DIR=/scratch + export TORCH_HOME=/torch_home + export MODEL_NAME=MST + export CONFIG=unilateral nvflare simulator -w /tmp/ODELIA_ternary_classification -n 2 -t 2 ${TMPDIR}/ODELIA_ternary_classification -c client_A,client_B - unset TRAINING_MODE - unset SITE_NAME rm -rf ${TMPDIR} - unset TMPDIR } run_3dcnn_simulation_mode diff --git a/tests/integration_tests/_run_controller_unit_tests_with_coverage.sh b/tests/integration_tests/_run_controller_unit_tests_with_coverage.sh new file mode 100755 index 00000000..46e6e11c --- /dev/null +++ b/tests/integration_tests/_run_controller_unit_tests_with_coverage.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e + +run_controller_unit_tests_with_coverage () { + # run unit tests of ODELIA swarm learning and report coverage + export MPLCONFIGDIR=/tmp + export COVERAGE_FILE=/tmp/.MediSwarm_coverage + cd /MediSwarm/tests/unit_tests/controller + PYTHONPATH=/MediSwarm/controller/controller python3 -m coverage run --source=/MediSwarm/controller/controller -m unittest discover + coverage report -m + rm "$COVERAGE_FILE" +} + +run_controller_unit_tests_with_coverage diff --git a/tests/integration_tests/_run_minimal_example_proof_of_concept_mode.sh b/tests/integration_tests/_run_minimal_example_proof_of_concept_mode.sh new file mode 100755 index 00000000..ee26a4d0 --- /dev/null +++ b/tests/integration_tests/_run_minimal_example_proof_of_concept_mode.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -e + +run_minimal_example_proof_of_concept_mode () { + # run proof-of-concept mode for minimal example + mkdir -p ~/.nvflare + cd /MediSwarm + export TRAINING_MODE="swarm" + nvflare poc prepare -c poc_client_0 poc_client_1 + nvflare poc prepare-jobs-dir -j application/jobs/ + nvflare poc start -ex admin@nvidia.com + sleep 15 + echo "Will submit job now after sleeping 15 seconds to allow the background process to complete" + nvflare job submit -j application/jobs/minimal_training_pytorch_cnn + sleep 60 + echo "Will shut down now after sleeping 60 seconds to allow the background process to complete" + sleep 2 + nvflare poc stop +} + +run_minimal_example_proof_of_concept_mode diff --git a/tests/integration_tests/_run_minimal_example_simulation_mode.sh b/tests/integration_tests/_run_minimal_example_simulation_mode.sh new file mode 100755 index 00000000..e1fd931f --- /dev/null +++ b/tests/integration_tests/_run_minimal_example_simulation_mode.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +run_minimal_example_simulation_mode () { + # run simulation mode for minimal example + cd /MediSwarm + export TRAINING_MODE="swarm" + nvflare simulator -w /tmp/minimal_training_pytorch_cnn -n 2 -t 2 application/jobs/minimal_training_pytorch_cnn -c simulated_node_0,simulated_node_1 +} + +run_minimal_example_simulation_mode diff --git a/tests/integration_tests/_run_minimal_example_standalone.sh b/tests/integration_tests/_run_minimal_example_standalone.sh new file mode 100755 index 00000000..f0106342 --- /dev/null +++ b/tests/integration_tests/_run_minimal_example_standalone.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +run_minimal_example_standalone () { + # run standalone version of minimal example + cd /MediSwarm/application/jobs/minimal_training_pytorch_cnn/app/custom/ + export TRAINING_MODE="local_training" + ./main.py +} + +run_minimal_example_standalone diff --git a/tests/integration_tests/_submitDummyTraining.exp b/tests/integration_tests/_submitDummyTraining.exp new file mode 100755 index 00000000..7d69997c --- /dev/null +++ b/tests/integration_tests/_submitDummyTraining.exp @@ -0,0 +1,15 @@ +#!/usr/bin/env expect + +spawn ./docker.sh --no_pull +expect "User Name: " +send "admin@test.odelia\r" +expect "> " +send "submit_job MediSwarm/application/jobs/minimal_training_pytorch_cnn\r" +expect "> " +send "sys_info client\r" +expect "> " +send "sys_info server\r" +expect "> " +send "list_jobs\r" +expect "> " +send "list_jobs\r" diff --git a/tests/integration_tests/outdated_startup_kit.tar.gz b/tests/integration_tests/outdated_startup_kit.tar.gz new file mode 100644 index 00000000..ba3a984e Binary files /dev/null and b/tests/integration_tests/outdated_startup_kit.tar.gz differ diff --git a/tests/local_vpn/Dockerfile_openvpnserver b/tests/local_vpn/Dockerfile_openvpnserver new file mode 100644 index 00000000..8270f8fa --- /dev/null +++ b/tests/local_vpn/Dockerfile_openvpnserver @@ -0,0 +1,11 @@ +FROM ubuntu:22.04 + +RUN apt update +RUN apt install -y easy-rsa openvpn openssl ufw joe patch +RUN apt install -y openssh-server net-tools + +RUN useradd ca_user + +COPY _openvpn_certificate_creation.sh / +COPY _openvpn_start.sh / +RUN chmod u+x /*.sh diff --git a/tests/local_vpn/README.txt b/tests/local_vpn/README.txt new file mode 100644 index 00000000..5cc3e826 --- /dev/null +++ b/tests/local_vpn/README.txt @@ -0,0 +1,17 @@ +# Following https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04 +# but on 22.04 + +Setup +----- +./create_openvpn_certificates.sh builds a docker image and creates certificates and .ovpn config files for the clients specified in _openvpn_certificate_creation.sh +Modify server_config/server.conf and client_configs/client.conf to modify network configuration. +Files to use on the server and client are created in server_config/ and client_configs/ + +Usage +----- +./openvpn_start.sh builds a docker image and starts OpenVPN server in the docker container. +Modify _openvpn_start.sh for further firewall etc. configuration. + +Disclaimer +---------- +This configuration is not necessarily secure and should not be re-used unless you know what you are doing. diff --git a/tests/local_vpn/_build_docker.sh b/tests/local_vpn/_build_docker.sh new file mode 100755 index 00000000..0df1ce0f --- /dev/null +++ b/tests/local_vpn/_build_docker.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# TODO should this be named "latest"? Do we need to pin versions? +# TODO think about splitting building certificates from running the VPN container + +docker build -t odelia_testing_openvpnserver:latest . -f Dockerfile_openvpnserver diff --git a/tests/local_vpn/_openvpn_certificate_creation.sh b/tests/local_vpn/_openvpn_certificate_creation.sh new file mode 100644 index 00000000..a815f001 --- /dev/null +++ b/tests/local_vpn/_openvpn_certificate_creation.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# Roughly following https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04 +# but on 22.04 + +chown ca_user:ca_user /home/ca_user/ -R +chmod a+rwX /home/ca_user/ -R +/bin/su - -c '/home/ca_user/ca_setup.sh' ca_user + +mkdir ~/easy-rsa +ln -s /usr/share/easy-rsa/* ~/easy-rsa/ +cd ~/easy-rsa + +echo 'set_var EASYRSA_ALGO "ec"' > vars +echo 'set_var EASYRSA_DIGEST "sha512"' >> vars + +./easyrsa init-pki + +rm /server_config/ca.crt \ + /server_config/server.crt \ + /server_config/server.key \ + /server_config/ta.key -f + +rm -rf /client_configs/keys +mkdir -p /client_configs/keys/ + +export EASYRSA_BATCH=1 +./easyrsa gen-req server nopass + +cp ~/easy-rsa/pki/reqs/server.req /tmp/ +chmod a+r /tmp/server.req +/bin/su - -c "export EASYRSA_BATCH=1 && cd ~/easy-rsa/ && ./easyrsa import-req /tmp/server.req server && ./easyrsa sign-req server server" ca_user + +cd ~/easy-rsa +openvpn --genkey secret ta.key +cp ta.key /client_configs/keys/ +cp /home/ca_user/easy-rsa/pki/ca.crt /client_configs/keys/ + +# copy/create files to where they are needed +cp /home/ca_user/easy-rsa/pki/ca.crt /server_config/ +cp /home/ca_user/easy-rsa/pki/issued/server.crt /server_config/ +cp ~/easy-rsa/pki/private/server.key /server_config/ +cp ~/easy-rsa/ta.key /server_config/ + +mkdir /server_config/ccd + +i=4 +for client in testserver.local admin@test.odelia client_A client_B; do + cd ~/easy-rsa + EASYRSA_BATCH=1 EASYRSA_REQ_CN=$client ./easyrsa gen-req $client nopass + cp pki/private/$client.key /client_configs/keys/ + + cp ~/easy-rsa/pki/reqs/$client.req /tmp/ + chmod a+r /tmp/$client.req + /bin/su - -c "export EASYRSA_BATCH=1 && cd ~/easy-rsa/ && ./easyrsa import-req /tmp/$client.req $client && ./easyrsa sign-req client $client" ca_user + cp /home/ca_user/easy-rsa/pki/issued/$client.crt /client_configs/keys/ + + cd /client_configs + ./make_ovpn.sh $client + + echo "ifconfig-push 10.8.0."$i" 255.0.0.0" > /server_config/ccd/$client + i=$((i+1)) +done + +chmod a+rwX /client_configs -R +chmod a+rwX /server_config -R +chmod a+rwX /home/ca_user -R diff --git a/tests/local_vpn/_openvpn_start.sh b/tests/local_vpn/_openvpn_start.sh new file mode 100644 index 00000000..62d1a864 --- /dev/null +++ b/tests/local_vpn/_openvpn_start.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf +sysctl -p + +echo "MTBhMTEsMTkKPiAjIFNUQVJUIE9QRU5WUE4gUlVMRVMKPiAjIE5BVCB0YWJsZSBydWxlcwo+ICpuYXQKPiA6UE9TVFJPVVRJTkcgQUNDRVBUIFswOjBdCj4gIyBBbGxvdyB0cmFmZmljIGZyb20gT3BlblZQTiBjbGllbnQgdG8gZXRoMCAoY2hhbmdlIHRvIHRoZSBpbnRlcmZhY2UgeW91IGRpc2NvdmVyZWQhKQo+IC1BIFBPU1RST1VUSU5HIC1zIDEwLjguMC4wLzggLW8gZXRoMCAtaiBNQVNRVUVSQURFCj4gQ09NTUlUCj4gIyBFTkQgT1BFTlZQTiBSVUxFUwo+IAo=" | base64 -d > before.rules.patch +patch /etc/ufw/before.rules before.rules.patch +rm before.rules.patch + +echo "MTljMTkKPCBERUZBVUxUX0ZPUldBUkRfUE9MSUNZPSJEUk9QIgotLS0KPiBERUZBVUxUX0ZPUldBUkRfUE9MSUNZPSJBQ0NFUFQiCg==" | base64 -d > ufw.patch +patch /etc/default/ufw ufw.patch +rm ufw.patch + +ufw allow 9194/udp +ufw allow OpenSSH +ufw disable +ufw enable + +cp /server_config/ca.crt /etc/openvpn/server/ +cp /server_config/server.conf /etc/openvpn/server/ +cp /server_config/server.crt /etc/openvpn/server/ +cp /server_config/server.key /etc/openvpn/server/ +cp /server_config/ta.key /etc/openvpn/server/ +cp /server_config/ccd /etc/openvpn/ccd -r + +# write log to folder on host +cd server_config + +nohup openvpn --duplicate-cn --client-to-client --config /etc/openvpn/server/server.conf & +sleep 2 +chmod a+r /server_config/nohup.out diff --git a/tests/local_vpn/client_configs/.gitignore b/tests/local_vpn/client_configs/.gitignore new file mode 100644 index 00000000..38156aad --- /dev/null +++ b/tests/local_vpn/client_configs/.gitignore @@ -0,0 +1 @@ +keys \ No newline at end of file diff --git a/tests/local_vpn/client_configs/admin@test.odelia_client.ovpn b/tests/local_vpn/client_configs/admin@test.odelia_client.ovpn new file mode 100644 index 00000000..8b9a87ee --- /dev/null +++ b/tests/local_vpn/client_configs/admin@test.odelia_client.ovpn @@ -0,0 +1,299 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel +# if you have more than one. On XP SP2, +# you may need to disable the firewall +# for the TAP adapter. +;dev-node MyTap + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +;proto tcp +proto udp + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +remote 172.17.0.1 9194 + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +;remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +;tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the data-ciphers option in the manpage +;cipher AES-256-CBC +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# Don't enable this unless it is also +# enabled in the server config file. +#comp-lzo + +# Set log file verbosity. +verb 3 + +# Silence repeating messages +;mute 20 + +key-direction 1 + +; script-security 2 +; up /etc/openvpn/update-resolv-conf +; down /etc/openvpn/update-resolv-conf + +; script-security 2 +; up /etc/openvpn/update-systemd-resolved +; down /etc/openvpn/update-systemd-resolved +; down-pre +; dhcp-option DOMAIN-ROUTE . + +-----BEGIN CERTIFICATE----- +MIIDQjCCAiqgAwIBAgIUBwqUYD1oxBKeImaMZfm44TsTAF0wDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQyWhcNMzUwOTIx +MTI0NjQyWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKGt+8oRY7cWPg1SahfIV3XAeeH1SQEFq4f2q+E9ZbWVnCg9 +b59hMzwYr84/j4V73Hlv2udLrkguvnT9KqqJY/0wo3Bd1swH2WLej1fo0+rVo24w +hzeLfeH1e4erZbzQk8XG68U7yNDHKYo+LIz9syBzZA4Bq12bHxDsZbJF7HUANzFR +j9Xg3dR7utPtG8ktmD83rV9/E97whblMpLmjmf2sbCqdLOKTkZnwp5mI47TTkhMj +9K0q7irHmbtZcPZQH5Z59GtqaCaRt8DKfeYniyoPnGVfzFberHHQ4C11pcRrdvgY +n14/W5myh6HESQD6umyCYooyXG7wfqIKujROQCMCAwEAAaOBjTCBijAdBgNVHQ4E +FgQUtMsHbl94qRV7OW5UNNjk2mJ+/U8wTgYDVR0jBEcwRYAUtMsHbl94qRV7OW5U +NNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQHCpRgPWjEEp4iZoxl ++bjhOxMAXTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAQEAGeryP/2JuOp7tzi7Ww9lFUx2DRcgq/FwnU4biotUfuLejHQt/IeIwRYs +dW6AToUYJak8Uy/AFffMootwLcC8z8FATBnxtokWNpxtscpbTSHbeS0HvXnXFaU8 +xxlzp9l5k+46MrrvdzFsjoRfVxs0FUHzWifBnObBziTLfHt+J71509uqRWX6JuTa +PDAT8CMcLKxxS4BcorWtAmc51lW/dQQ41HDJ8a6acltDAprmlnhd8ksWzpTjUDNR +/cfSMcVTpPxPSW/WchR5NlJKQEAf9B/xC+LQgDRSDLaZ8CvzRDgosllzJ+aIS7GK +GPec69LiKqpirZ7enwDM67R4DwIHKA== +-----END CERTIFICATE----- + + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 45:fc:0b:2c:a3:b7:9c:b6:f1:56:fd:47:cb:b2:12:12 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=ChangeMe + Validity + Not Before: Sep 23 12:46:43 2025 GMT + Not After : Dec 27 12:46:43 2027 GMT + Subject: CN=admin@test.odelia + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ca:33:a9:8e:be:5d:00:9e:ff:72:43:e9:e4:8b: + 8f:09:6e:56:38:7e:f8:57:e1:5f:e7:df:af:e1:22: + 69:1e:7a:9c:a3:43:84:8f:f8:cc:61:4e:61:dc:3a: + 56:02:77:13:65:09:4e:25:02:94:a9:94:3f:76:4f: + b8:6c:98:36:0c:52:cc:22:e7:16:97:2b:c2:c1:7c: + 14:db:f8:45:7a:b7:c8:b0:5c:a9:a1:d8:0c:ca:b0: + 4f:b3:a6:f3:05:f2:e7:43:ac:90:2c:32:4b:ae:b8: + d8:67:c0:0f:46:e2:e1:a7:d9:a4:cd:c7:5b:29:4e: + c4:38:aa:6b:43:c5:31:8e:a4:be:68:73:82:72:ca: + a4:df:81:80:c7:13:df:b7:e1:53:07:04:c0:d6:78: + 66:22:9a:fe:ba:95:0e:e5:cc:93:47:1f:f1:e9:86: + 77:3d:c4:54:cd:b8:c9:8a:2b:02:eb:84:0b:68:22: + 50:8f:16:7a:e5:d7:ec:3f:3f:25:f0:79:74:42:3a: + bb:2e:a3:dc:c0:d4:d3:05:8b:4e:01:a7:e8:ff:6d: + 94:1e:4d:de:f7:76:10:cc:62:66:d9:b4:1e:58:0c: + 52:de:46:1c:26:bc:71:ef:82:bb:25:f6:d7:14:19: + e6:3d:a1:e4:cc:0b:94:1f:c6:bb:37:81:4d:5c:76: + 6b:2b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + E5:EC:27:21:94:02:06:AC:C6:C7:DB:B6:13:25:9C:C3:60:1E:47:FE + X509v3 Authority Key Identifier: + keyid:B4:CB:07:6E:5F:78:A9:15:7B:39:6E:54:34:D8:E4:DA:62:7E:FD:4F + DirName:/CN=ChangeMe + serial:07:0A:94:60:3D:68:C4:12:9E:22:66:8C:65:F9:B8:E1:3B:13:00:5D + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 73:cb:0e:63:bf:1d:f5:04:37:d3:cc:9c:c8:d2:21:60:f0:ae: + 23:08:38:0b:77:31:9b:6f:b3:89:5f:5c:69:86:e8:69:47:b8: + da:04:56:8b:a2:f4:25:2b:48:c6:4f:1d:a2:8a:b3:b8:7c:a8: + d2:9e:89:9a:20:71:69:fb:9f:4d:39:8d:cb:9c:f2:58:bc:58: + 19:10:cd:be:1f:bd:6e:e4:af:fd:c6:eb:2f:83:39:e7:4b:2c: + bf:23:e1:9d:9e:81:80:86:41:df:9f:fc:3b:d3:29:7f:dc:fb: + a6:45:5c:38:0b:80:de:27:ef:23:f8:53:80:48:69:37:c9:9b: + aa:24:cc:ff:54:80:77:2b:ab:51:c7:02:4d:e7:49:01:af:f4: + d3:d1:89:09:4a:96:99:44:e2:0d:13:b1:9d:4b:47:73:70:22: + fc:a7:4f:20:90:00:a3:5b:96:c9:59:e7:0e:e1:25:e0:00:3c: + 66:a8:32:62:f1:42:bc:84:32:32:46:b7:ac:b9:ed:e7:45:47: + 3b:26:b7:2b:f2:ce:04:e9:64:9c:52:5d:e4:08:11:32:ff:e0: + ff:a9:d8:e5:1a:e7:f0:cc:21:25:f8:04:40:6a:e3:ed:5f:fc: + b2:15:0a:b7:cf:85:db:82:29:e2:27:ed:e8:94:f4:c3:01:77: + 04:d0:bf:7d +-----BEGIN CERTIFICATE----- +MIIDWTCCAkGgAwIBAgIQRfwLLKO3nLbxVv1Hy7ISEjANBgkqhkiG9w0BAQsFADAT +MREwDwYDVQQDDAhDaGFuZ2VNZTAeFw0yNTA5MjMxMjQ2NDNaFw0yNzEyMjcxMjQ2 +NDNaMBwxGjAYBgNVBAMMEWFkbWluQHRlc3Qub2RlbGlhMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAyjOpjr5dAJ7/ckPp5IuPCW5WOH74V+Ff59+v4SJp +Hnqco0OEj/jMYU5h3DpWAncTZQlOJQKUqZQ/dk+4bJg2DFLMIucWlyvCwXwU2/hF +erfIsFypodgMyrBPs6bzBfLnQ6yQLDJLrrjYZ8APRuLhp9mkzcdbKU7EOKprQ8Ux +jqS+aHOCcsqk34GAxxPft+FTBwTA1nhmIpr+upUO5cyTRx/x6YZ3PcRUzbjJiisC +64QLaCJQjxZ65dfsPz8l8Hl0Qjq7LqPcwNTTBYtOAafo/22UHk3e93YQzGJm2bQe +WAxS3kYcJrxx74K7JfbXFBnmPaHkzAuUH8a7N4FNXHZrKwIDAQABo4GfMIGcMAkG +A1UdEwQCMAAwHQYDVR0OBBYEFOXsJyGUAgasxsfbthMlnMNgHkf+ME4GA1UdIwRH +MEWAFLTLB25feKkVezluVDTY5Npifv1PoRekFTATMREwDwYDVQQDDAhDaGFuZ2VN +ZYIUBwqUYD1oxBKeImaMZfm44TsTAF0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYD +VR0PBAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQBzyw5jvx31BDfTzJzI0iFg8K4j +CDgLdzGbb7OJX1xphuhpR7jaBFaLovQlK0jGTx2iirO4fKjSnomaIHFp+59NOY3L +nPJYvFgZEM2+H71u5K/9xusvgznnSyy/I+GdnoGAhkHfn/w70yl/3PumRVw4C4De +J+8j+FOASGk3yZuqJMz/VIB3K6tRxwJN50kBr/TT0YkJSpaZROINE7GdS0dzcCL8 +p08gkACjW5bJWecO4SXgADxmqDJi8UK8hDIyRresue3nRUc7Jrcr8s4E6WScUl3k +CBEy/+D/qdjlGufwzCEl+ARAauPtX/yyFQq3z4XbginiJ+3olPTDAXcE0L99 +-----END CERTIFICATE----- + + +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDKM6mOvl0Anv9y +Q+nki48JblY4fvhX4V/n36/hImkeepyjQ4SP+MxhTmHcOlYCdxNlCU4lApSplD92 +T7hsmDYMUswi5xaXK8LBfBTb+EV6t8iwXKmh2AzKsE+zpvMF8udDrJAsMkuuuNhn +wA9G4uGn2aTNx1spTsQ4qmtDxTGOpL5oc4JyyqTfgYDHE9+34VMHBMDWeGYimv66 +lQ7lzJNHH/Hphnc9xFTNuMmKKwLrhAtoIlCPFnrl1+w/PyXweXRCOrsuo9zA1NMF +i04Bp+j/bZQeTd73dhDMYmbZtB5YDFLeRhwmvHHvgrsl9tcUGeY9oeTMC5Qfxrs3 +gU1cdmsrAgMBAAECggEARJO+9vWjLzm9ozBbXDLk4Sr1vRV6/rsmPssDqJR2GGs3 +Qrv8cqPMFVhzIjD6yL0/6617PlwgtV7dIzAoeVQqSIWwTEoZxE2IMPz3Sh9q2RMJ +0p6qvYQ72mZvsZt2otbeDnqxLvwj5O82HgHqbH04USgkl9H8Hgdjz2AlHwf7Jcgo +pwD48OtE8YFMof3/SFzKUJDPdsCsjGlWnDDJMjXrIR6BZdE7xxEX7L2VRcmVBQXR +lhAeNwYJNQ1qWGuXaSPx2BNa9BuTd66PwypsyPKwI63CJ6WkUh1bWsAviTBzr5Oz +u27eym4uK6mfXS6Pgv4VcM0kNUjnPd8p/XSaGQCfUQKBgQDLLuV9bhUyHPRbJbHC +WcXxNMiwUOpoyQY+KTj+p8mgXc9tB1TvL+dNi+vhc1mgHNactFnmyzx1S8eM2Wn9 +Aw1fxw42APUTw4rJh+l3UsuTBMZwQ3s6CeNFgX+PNHqHK/47xyXdmgipMB4Uz0JI +EPEe1avbLTymDCmbfJ3mFqLMuQKBgQD+w3VZhhI5OJSEQUkJs/sURQdBoD05rX/B +afz4ZqfRfLJscI3oG1oV8ZwMkoeA1ou5ovtxr/4XlGPhsopDa7sUMWbhEkm5Rssw +gPVmGE9HnM8tSG/8So7fbIXHCGcKRDD5JKnjPyqpP78wTzJeOrCfhbFP+dpiRJrJ +mEhn3V2tAwKBgQDDXHYgIkaTBrAVK6s9eeAPSndkwIiC9DbicfRxNpdxcIHPDWun +B+JY9554Cdc1UkUwK2D9vpCFH7XhQfLc6aBkZRrO5iC/PhcmK15Z8uv2knLS4q+L +YJJ79EXYRddCPRSYGaXY6xBEzRU/YQEUFeYhhcVWWqqj5bHj5PBVmZIzUQKBgQC3 +AOa6ETHkAr3EpzT1EGFqtQ86WAXC+duMrzr1oKAqPl3YwZ1ePs+edbk32sYViYhD +KE1g5CAtBf4dsWfaeHehUL9rK/zjZ3Qr+mbNGOdSNNUp3R/8Zf5thgIu7908pbFc +NrcGs2hMvarz49/1ikk3vgyZu4vhDRD3gTl5yq0wywKBgQCddStrC6gtOOaZofSL +bU6Le9TXyDbBfGiVpDxaD1rxdWylN3jQY9JSznmq7RGTR2TUVlqeFoCunaLc4VJi +N+np08niR1T/Mm+8HqLzYRROmLIozETrPomdgj1Ewa83lmI4/JSiNZbkFs+Jh6J1 +sGSrPFifkIAVP/C6PbVqj1Nn7A== +-----END PRIVATE KEY----- + + +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +488b61084812969fe8ad0f9dd40f56a2 +6cdadddfe345daef6b5c6d3c3e779fc5 +1f7d236966953482d2af085e3f8581b7 +d216f2d891972a463bbb22ca6c104b9d +f99dcb19d7d575a1d46e7918bb2556c6 +db9f51cd792c5e89e011586214692b95 +2a32a7fe85e4538c40e1d0aa2a9f8e15 +fcc0ce5d31974e3c2041b127776f7658 +878cb8245ed235ec996c2370c0fc0023 +699bc028b3412bc40209cba8233bc111 +fa1438095f99052d799fa718f3b04499 +472254d0286b4b2ce99db49e98a4cc25 +fd948bddcdcf08006a6d7bff40354e7b +5e93ea753a8ecc05de41ae34d280e7eb +99220e436bf8b7693a00667485631e28 +edba3e33b6f558dfa50b92eec6ac8b44 +-----END OpenVPN Static key V1----- + diff --git a/tests/local_vpn/client_configs/client.conf b/tests/local_vpn/client_configs/client.conf new file mode 100755 index 00000000..49669b71 --- /dev/null +++ b/tests/local_vpn/client_configs/client.conf @@ -0,0 +1,138 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel +# if you have more than one. On XP SP2, +# you may need to disable the firewall +# for the TAP adapter. +;dev-node MyTap + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +;proto tcp +proto udp + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +remote 172.17.0.1 9194 + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +;remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +;tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the data-ciphers option in the manpage +;cipher AES-256-CBC +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# Don't enable this unless it is also +# enabled in the server config file. +#comp-lzo + +# Set log file verbosity. +verb 3 + +# Silence repeating messages +;mute 20 + +key-direction 1 + +; script-security 2 +; up /etc/openvpn/update-resolv-conf +; down /etc/openvpn/update-resolv-conf + +; script-security 2 +; up /etc/openvpn/update-systemd-resolved +; down /etc/openvpn/update-systemd-resolved +; down-pre +; dhcp-option DOMAIN-ROUTE . diff --git a/tests/local_vpn/client_configs/client_A_client.ovpn b/tests/local_vpn/client_configs/client_A_client.ovpn new file mode 100644 index 00000000..1506b75d --- /dev/null +++ b/tests/local_vpn/client_configs/client_A_client.ovpn @@ -0,0 +1,299 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel +# if you have more than one. On XP SP2, +# you may need to disable the firewall +# for the TAP adapter. +;dev-node MyTap + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +;proto tcp +proto udp + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +remote 172.17.0.1 9194 + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +;remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +;tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the data-ciphers option in the manpage +;cipher AES-256-CBC +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# Don't enable this unless it is also +# enabled in the server config file. +#comp-lzo + +# Set log file verbosity. +verb 3 + +# Silence repeating messages +;mute 20 + +key-direction 1 + +; script-security 2 +; up /etc/openvpn/update-resolv-conf +; down /etc/openvpn/update-resolv-conf + +; script-security 2 +; up /etc/openvpn/update-systemd-resolved +; down /etc/openvpn/update-systemd-resolved +; down-pre +; dhcp-option DOMAIN-ROUTE . + +-----BEGIN CERTIFICATE----- +MIIDQjCCAiqgAwIBAgIUBwqUYD1oxBKeImaMZfm44TsTAF0wDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQyWhcNMzUwOTIx +MTI0NjQyWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKGt+8oRY7cWPg1SahfIV3XAeeH1SQEFq4f2q+E9ZbWVnCg9 +b59hMzwYr84/j4V73Hlv2udLrkguvnT9KqqJY/0wo3Bd1swH2WLej1fo0+rVo24w +hzeLfeH1e4erZbzQk8XG68U7yNDHKYo+LIz9syBzZA4Bq12bHxDsZbJF7HUANzFR +j9Xg3dR7utPtG8ktmD83rV9/E97whblMpLmjmf2sbCqdLOKTkZnwp5mI47TTkhMj +9K0q7irHmbtZcPZQH5Z59GtqaCaRt8DKfeYniyoPnGVfzFberHHQ4C11pcRrdvgY +n14/W5myh6HESQD6umyCYooyXG7wfqIKujROQCMCAwEAAaOBjTCBijAdBgNVHQ4E +FgQUtMsHbl94qRV7OW5UNNjk2mJ+/U8wTgYDVR0jBEcwRYAUtMsHbl94qRV7OW5U +NNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQHCpRgPWjEEp4iZoxl ++bjhOxMAXTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAQEAGeryP/2JuOp7tzi7Ww9lFUx2DRcgq/FwnU4biotUfuLejHQt/IeIwRYs +dW6AToUYJak8Uy/AFffMootwLcC8z8FATBnxtokWNpxtscpbTSHbeS0HvXnXFaU8 +xxlzp9l5k+46MrrvdzFsjoRfVxs0FUHzWifBnObBziTLfHt+J71509uqRWX6JuTa +PDAT8CMcLKxxS4BcorWtAmc51lW/dQQ41HDJ8a6acltDAprmlnhd8ksWzpTjUDNR +/cfSMcVTpPxPSW/WchR5NlJKQEAf9B/xC+LQgDRSDLaZ8CvzRDgosllzJ+aIS7GK +GPec69LiKqpirZ7enwDM67R4DwIHKA== +-----END CERTIFICATE----- + + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 54:bc:c2:64:c6:73:20:54:74:58:b8:6a:6e:10:38:76 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=ChangeMe + Validity + Not Before: Sep 23 12:46:43 2025 GMT + Not After : Dec 27 12:46:43 2027 GMT + Subject: CN=client_A + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c8:62:8c:53:02:a0:a3:8b:17:bc:80:97:f8:0f: + 63:35:7d:75:1d:b4:36:bd:75:17:ac:36:35:0b:6a: + ec:38:b3:7f:d6:1f:ef:c2:90:dc:b3:d5:1e:11:65: + 36:5c:63:b8:ef:7c:d2:eb:05:4c:61:54:02:93:8b: + 84:6b:8b:1c:ca:3e:6e:d5:b4:b0:2c:6f:a4:36:db: + fc:d4:a3:8c:23:da:f0:be:cf:d3:16:dd:44:4d:77: + ce:53:1d:5e:14:e2:c3:67:b1:9a:25:44:f9:b3:b1: + f6:13:a6:0d:5e:16:49:cc:cd:52:b8:8c:2c:8e:ac: + 87:17:ff:ff:c1:8a:e3:f5:3c:71:69:9f:14:a2:85: + 37:0e:4b:16:24:83:08:4e:58:b7:60:36:98:c7:2e: + 4b:bb:d7:b2:e0:aa:95:bb:22:7d:a6:bf:da:71:95: + c0:fe:d6:bb:93:06:27:2f:b9:4c:47:85:f5:80:2b: + f1:1b:c8:03:bb:5a:8d:13:e9:0e:1a:23:c1:92:7a: + 7a:41:43:93:f3:3a:ca:36:0b:a2:dc:b8:fc:61:7d: + 7b:af:3e:7a:fc:ad:ac:d4:04:f4:ec:57:18:ae:c8: + 4d:c3:ec:5c:bd:72:c0:b0:8e:24:fe:13:44:93:b0: + c3:78:3c:99:23:74:dd:44:8f:e3:ac:1b:12:8d:d8: + 74:e9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + DF:E6:D3:15:9C:F9:C3:F9:4E:C9:60:28:FA:6B:38:CA:1C:72:F7:B2 + X509v3 Authority Key Identifier: + keyid:B4:CB:07:6E:5F:78:A9:15:7B:39:6E:54:34:D8:E4:DA:62:7E:FD:4F + DirName:/CN=ChangeMe + serial:07:0A:94:60:3D:68:C4:12:9E:22:66:8C:65:F9:B8:E1:3B:13:00:5D + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 6c:de:92:45:ed:e7:01:63:d9:63:29:65:b7:75:e6:ed:31:44: + 8b:a7:7c:06:0c:02:87:15:bd:f2:e3:3e:e0:8b:74:87:44:d3: + 8a:f6:86:6d:3e:2f:1c:e7:b9:1d:b5:42:4d:60:76:1c:4f:8d: + a7:9c:81:a6:57:8b:62:85:76:15:f8:f8:0d:ef:2c:85:27:f5: + 2a:1d:36:84:88:77:72:f7:52:85:93:b8:0f:0b:97:54:e9:23: + 76:d6:1d:44:09:57:3e:ee:33:72:87:02:91:2e:50:fc:a2:88: + 42:88:6d:de:26:21:cc:79:96:61:9f:d9:1e:12:54:7c:96:f7: + 49:4a:08:f9:72:26:d7:40:59:fc:ab:8b:01:3d:b6:e2:4d:19: + fc:ff:1a:39:78:65:e0:13:9a:33:be:99:d6:fb:30:ea:a4:0b: + 41:32:eb:0e:f8:1c:95:e7:16:a0:3f:8e:2c:43:17:10:3c:f7: + b3:98:71:59:2d:17:94:32:a1:9b:85:39:2f:fa:2e:f9:45:dc: + 6e:c9:11:de:94:e1:10:52:87:04:43:e1:9b:4e:39:7b:c6:1e: + 55:a8:82:7c:77:d1:4a:cb:4c:8f:cb:ee:3f:b6:c7:6f:8a:3d: + 1a:a9:9e:9a:16:a4:3e:10:c0:49:95:5a:7c:c0:13:35:15:e8: + 1f:1f:f8:1a +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIQVLzCZMZzIFR0WLhqbhA4djANBgkqhkiG9w0BAQsFADAT +MREwDwYDVQQDDAhDaGFuZ2VNZTAeFw0yNTA5MjMxMjQ2NDNaFw0yNzEyMjcxMjQ2 +NDNaMBMxETAPBgNVBAMMCGNsaWVudF9BMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAyGKMUwKgo4sXvICX+A9jNX11HbQ2vXUXrDY1C2rsOLN/1h/vwpDc +s9UeEWU2XGO473zS6wVMYVQCk4uEa4scyj5u1bSwLG+kNtv81KOMI9rwvs/TFt1E +TXfOUx1eFOLDZ7GaJUT5s7H2E6YNXhZJzM1SuIwsjqyHF///wYrj9TxxaZ8UooU3 +DksWJIMITli3YDaYxy5Lu9ey4KqVuyJ9pr/acZXA/ta7kwYnL7lMR4X1gCvxG8gD +u1qNE+kOGiPBknp6QUOT8zrKNgui3Lj8YX17rz56/K2s1AT07FcYrshNw+xcvXLA +sI4k/hNEk7DDeDyZI3TdRI/jrBsSjdh06QIDAQABo4GfMIGcMAkGA1UdEwQCMAAw +HQYDVR0OBBYEFN/m0xWc+cP5TslgKPprOMoccveyME4GA1UdIwRHMEWAFLTLB25f +eKkVezluVDTY5Npifv1PoRekFTATMREwDwYDVQQDDAhDaGFuZ2VNZYIUBwqUYD1o +xBKeImaMZfm44TsTAF0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0PBAQDAgeA +MA0GCSqGSIb3DQEBCwUAA4IBAQBs3pJF7ecBY9ljKWW3debtMUSLp3wGDAKHFb3y +4z7gi3SHRNOK9oZtPi8c57kdtUJNYHYcT42nnIGmV4tihXYV+PgN7yyFJ/UqHTaE +iHdy91KFk7gPC5dU6SN21h1ECVc+7jNyhwKRLlD8oohCiG3eJiHMeZZhn9keElR8 +lvdJSgj5cibXQFn8q4sBPbbiTRn8/xo5eGXgE5ozvpnW+zDqpAtBMusO+ByV5xag +P44sQxcQPPezmHFZLReUMqGbhTkv+i75RdxuyRHelOEQUocEQ+GbTjl7xh5VqIJ8 +d9FKy0yPy+4/tsdvij0aqZ6aFqQ+EMBJlVp8wBM1FegfH/ga +-----END CERTIFICATE----- + + +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIYoxTAqCjixe8 +gJf4D2M1fXUdtDa9dResNjULauw4s3/WH+/CkNyz1R4RZTZcY7jvfNLrBUxhVAKT +i4RrixzKPm7VtLAsb6Q22/zUo4wj2vC+z9MW3URNd85THV4U4sNnsZolRPmzsfYT +pg1eFknMzVK4jCyOrIcX///BiuP1PHFpnxSihTcOSxYkgwhOWLdgNpjHLku717Lg +qpW7In2mv9pxlcD+1ruTBicvuUxHhfWAK/EbyAO7Wo0T6Q4aI8GSenpBQ5PzOso2 +C6LcuPxhfXuvPnr8razUBPTsVxiuyE3D7Fy9csCwjiT+E0STsMN4PJkjdN1Ej+Os +GxKN2HTpAgMBAAECggEAWxr3KryclY6lTZZ3wZgZZpXyO/2WD8BfcXQ53MWRvdva +iNt/Ukozle2U3JrUQuAyEmyBpsoDZpLgEv4RSCX5AnitQquCl8lwc2LEilcLXbfq +0g5CLniOV9xbKc3F2yAYcJo+d6hrEQid1WQfWsIubpeBfxd4IKwPRdmmCfRgXTv+ +a7TVI9pRmFNg7J9Cs2VEqf7SdMX8U+7bPJfvHZ+aWYO5d9ZWhMSW5EB43QlgcVg2 +Eof1AjvkBY4NOOsb2uWkw7HiKloT95L8PR6I9bSCesJU58oGDPJyQKG58ANk5alh +9qPgzK5RnkMxzO+aEEzZ5x8NYacx51JwcScI6r5/ewKBgQDgMQSg+h+JZmGY1nuY +5OM6OiGoyHq8PAogPzWEO4N5I26kmkiTiLzyr4dzvPNx+1uOCuSQpt/qBB9rli1w +y1PQkrXMtfrHv83AWep1bFgripgwsGTKRTq0t9Obl5zzkV2OaBlGJP+gaBnfEbM4 +htchBFEyTMfoobFz9+Xv8mvHBwKBgQDk0NcZ7xoqx1PY4f8bbpAIOj8VhJopsZBm +Jv/jzJq8JREMXU54y8VkaT3ihY5tq/7DhPvpeVy87UI6urEaxoK5D3xAdoMVsBy0 +SVkfAMTjqU5PpZahPTL1vyvrH9EvJSfW1/qhtdyxZzw5p0T2Ro1ZEEC/GTRAZZuV +LgUHt594jwKBgQCtzJJgEUedhucmSzAqCVc2bpZleHXds1XORfJA/rofkR5XMNwO +s7R3FyiUyuiXdls1tLAYi6WOj3+kMhosFRR23yVc+77cV480DQC74zA/IQR2ymh4 +fk7ShqffORwNnqW+nmjpfglF2y4jRl9/9NiV2fjwW6GmcKNW2dlBuNdgxQKBgEKu +pfEV4D9VRZcwDWNWLj1nlBjWQwMhjx5mAS7G4tUvzC8ZRhQn9keT8AgCugY2GJGs +QKnCx4b7cdChtZlC/relzqUOpJb+cu8LbSB+3eIm5f6KGEK3DhHV+5uS8yhVIK4Y +1R6pXD6LAl8e4xcOaoTpGqVWWAboVZX9ClQ8bAn7AoGADM9OTA+hc/LicOO/oqp+ +lJ3XKBbQMvWZY0fhGvm0DSYLZi7cBOBCBwJXvfq278Cq1u+i2QHW9hV64Dcbt0TQ +l74cqQpoXZ7ZYFUUmYsEh3smL8K1u176Yig9LbVjUBD2eF02J+OXGWJtDQwyI696 +04gCGQhFI98vaM11YlS+skk= +-----END PRIVATE KEY----- + + +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +488b61084812969fe8ad0f9dd40f56a2 +6cdadddfe345daef6b5c6d3c3e779fc5 +1f7d236966953482d2af085e3f8581b7 +d216f2d891972a463bbb22ca6c104b9d +f99dcb19d7d575a1d46e7918bb2556c6 +db9f51cd792c5e89e011586214692b95 +2a32a7fe85e4538c40e1d0aa2a9f8e15 +fcc0ce5d31974e3c2041b127776f7658 +878cb8245ed235ec996c2370c0fc0023 +699bc028b3412bc40209cba8233bc111 +fa1438095f99052d799fa718f3b04499 +472254d0286b4b2ce99db49e98a4cc25 +fd948bddcdcf08006a6d7bff40354e7b +5e93ea753a8ecc05de41ae34d280e7eb +99220e436bf8b7693a00667485631e28 +edba3e33b6f558dfa50b92eec6ac8b44 +-----END OpenVPN Static key V1----- + diff --git a/tests/local_vpn/client_configs/client_B_client.ovpn b/tests/local_vpn/client_configs/client_B_client.ovpn new file mode 100644 index 00000000..6229c033 --- /dev/null +++ b/tests/local_vpn/client_configs/client_B_client.ovpn @@ -0,0 +1,299 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel +# if you have more than one. On XP SP2, +# you may need to disable the firewall +# for the TAP adapter. +;dev-node MyTap + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +;proto tcp +proto udp + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +remote 172.17.0.1 9194 + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +;remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +;tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the data-ciphers option in the manpage +;cipher AES-256-CBC +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# Don't enable this unless it is also +# enabled in the server config file. +#comp-lzo + +# Set log file verbosity. +verb 3 + +# Silence repeating messages +;mute 20 + +key-direction 1 + +; script-security 2 +; up /etc/openvpn/update-resolv-conf +; down /etc/openvpn/update-resolv-conf + +; script-security 2 +; up /etc/openvpn/update-systemd-resolved +; down /etc/openvpn/update-systemd-resolved +; down-pre +; dhcp-option DOMAIN-ROUTE . + +-----BEGIN CERTIFICATE----- +MIIDQjCCAiqgAwIBAgIUBwqUYD1oxBKeImaMZfm44TsTAF0wDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQyWhcNMzUwOTIx +MTI0NjQyWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKGt+8oRY7cWPg1SahfIV3XAeeH1SQEFq4f2q+E9ZbWVnCg9 +b59hMzwYr84/j4V73Hlv2udLrkguvnT9KqqJY/0wo3Bd1swH2WLej1fo0+rVo24w +hzeLfeH1e4erZbzQk8XG68U7yNDHKYo+LIz9syBzZA4Bq12bHxDsZbJF7HUANzFR +j9Xg3dR7utPtG8ktmD83rV9/E97whblMpLmjmf2sbCqdLOKTkZnwp5mI47TTkhMj +9K0q7irHmbtZcPZQH5Z59GtqaCaRt8DKfeYniyoPnGVfzFberHHQ4C11pcRrdvgY +n14/W5myh6HESQD6umyCYooyXG7wfqIKujROQCMCAwEAAaOBjTCBijAdBgNVHQ4E +FgQUtMsHbl94qRV7OW5UNNjk2mJ+/U8wTgYDVR0jBEcwRYAUtMsHbl94qRV7OW5U +NNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQHCpRgPWjEEp4iZoxl ++bjhOxMAXTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAQEAGeryP/2JuOp7tzi7Ww9lFUx2DRcgq/FwnU4biotUfuLejHQt/IeIwRYs +dW6AToUYJak8Uy/AFffMootwLcC8z8FATBnxtokWNpxtscpbTSHbeS0HvXnXFaU8 +xxlzp9l5k+46MrrvdzFsjoRfVxs0FUHzWifBnObBziTLfHt+J71509uqRWX6JuTa +PDAT8CMcLKxxS4BcorWtAmc51lW/dQQ41HDJ8a6acltDAprmlnhd8ksWzpTjUDNR +/cfSMcVTpPxPSW/WchR5NlJKQEAf9B/xC+LQgDRSDLaZ8CvzRDgosllzJ+aIS7GK +GPec69LiKqpirZ7enwDM67R4DwIHKA== +-----END CERTIFICATE----- + + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + e0:1a:9b:9d:b6:2e:8a:b3:15:ba:a5:92:33:3d:75:01 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=ChangeMe + Validity + Not Before: Sep 23 12:46:43 2025 GMT + Not After : Dec 27 12:46:43 2027 GMT + Subject: CN=client_B + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:f1:4b:16:3d:95:5e:bd:9f:34:53:d6:a0:80: + 7c:0c:3b:36:65:32:0c:b5:a2:98:12:92:81:66:73: + 68:dd:ec:e3:b4:86:f8:7c:32:c1:1b:01:3b:47:07: + 61:fb:e4:d4:40:cf:9e:b6:1f:b8:10:8d:ac:39:f6: + 76:5d:84:5c:fb:38:f6:5d:cd:fe:60:dd:58:b9:fa: + ee:6b:61:62:53:e1:aa:31:b0:b8:36:8e:6b:b1:7c: + 08:8a:5f:1c:f3:03:29:3b:4f:bc:12:74:60:af:97: + 39:63:c2:77:f1:73:8d:b1:f5:80:f2:a2:e9:6b:4d: + 83:bf:7a:95:ee:30:6b:e1:e0:a4:6c:b4:e6:75:f9: + 92:3c:17:a0:17:1d:37:4b:5f:b3:2d:7a:ab:20:5e: + 27:22:82:31:5d:67:bb:58:3e:53:06:02:d9:17:84: + fa:2a:56:48:10:12:d8:5f:c2:00:f0:8c:d8:29:09: + ed:bf:d1:c2:30:74:2f:33:3f:7e:38:88:3a:fc:13: + f1:ed:5b:90:30:8e:7a:c5:b2:89:0f:21:e6:ad:8d: + a4:ca:30:e3:f8:5f:52:8e:cb:eb:13:6d:ce:cb:7c: + 21:ae:ab:b5:58:cd:85:1f:93:98:7f:ad:3f:1f:b0: + 95:14:74:20:ed:82:be:28:47:77:80:a8:8b:a7:33: + 41:7f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 6B:AB:8A:5C:11:80:8B:38:1F:B9:4B:7E:DC:AF:5A:B4:CF:41:74:4F + X509v3 Authority Key Identifier: + keyid:B4:CB:07:6E:5F:78:A9:15:7B:39:6E:54:34:D8:E4:DA:62:7E:FD:4F + DirName:/CN=ChangeMe + serial:07:0A:94:60:3D:68:C4:12:9E:22:66:8C:65:F9:B8:E1:3B:13:00:5D + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 49:2f:45:4f:07:f9:cf:26:0a:0c:a6:45:a9:cc:ca:e6:be:1f: + 24:47:b5:a7:5b:f0:00:e3:6d:15:b7:cd:1f:98:33:7a:dd:b4: + 2d:1a:c0:fe:34:84:ec:53:f8:b0:88:7c:30:9f:f3:43:5b:19: + 5b:dc:57:e4:18:fe:d7:cf:eb:50:03:8a:bf:03:d5:9c:79:92: + ad:5f:fe:12:a5:39:74:4e:e1:e0:48:af:31:62:a7:e8:e6:9a: + e9:e2:d7:40:52:d5:ab:22:e3:0b:9c:78:18:83:76:ba:5e:fe: + 6f:aa:96:f4:76:0f:88:ac:56:18:bc:e6:da:b7:55:ab:42:b7: + 74:2b:94:00:c8:e5:a1:66:63:41:b5:a9:48:7d:15:ce:d1:eb: + 14:50:3e:d0:a7:78:f4:92:0f:e3:ee:0d:df:5d:2c:ce:85:bf: + 73:39:32:dc:17:39:d4:39:11:11:f4:0b:ad:4d:af:88:1a:d4: + c4:bf:b9:1c:ed:e8:21:d4:b7:48:01:55:ff:a7:2b:86:b4:dd: + b4:54:fb:1f:0d:96:2b:da:15:c7:13:d2:1d:34:d5:13:dd:f4: + 6a:20:5a:e8:00:b8:60:88:5c:76:7e:77:82:6f:1b:a7:4c:41: + fb:4f:0f:1a:df:46:1f:09:79:a0:1c:16:c1:cd:7a:48:1c:91: + 1f:db:06:92 +-----BEGIN CERTIFICATE----- +MIIDUTCCAjmgAwIBAgIRAOAam522LoqzFbqlkjM9dQEwDQYJKoZIhvcNAQELBQAw +EzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQzWhcNMjcxMjI3MTI0 +NjQzWjATMREwDwYDVQQDDAhjbGllbnRfQjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL/xSxY9lV69nzRT1qCAfAw7NmUyDLWimBKSgWZzaN3s47SG+Hwy +wRsBO0cHYfvk1EDPnrYfuBCNrDn2dl2EXPs49l3N/mDdWLn67mthYlPhqjGwuDaO +a7F8CIpfHPMDKTtPvBJ0YK+XOWPCd/FzjbH1gPKi6WtNg796le4wa+HgpGy05nX5 +kjwXoBcdN0tfsy16qyBeJyKCMV1nu1g+UwYC2ReE+ipWSBAS2F/CAPCM2CkJ7b/R +wjB0LzM/fjiIOvwT8e1bkDCOesWyiQ8h5q2NpMow4/hfUo7L6xNtzst8Ia6rtVjN +hR+TmH+tPx+wlRR0IO2CvihHd4Coi6czQX8CAwEAAaOBnzCBnDAJBgNVHRMEAjAA +MB0GA1UdDgQWBBRrq4pcEYCLOB+5S37cr1q0z0F0TzBOBgNVHSMERzBFgBS0ywdu +X3ipFXs5blQ02OTaYn79T6EXpBUwEzERMA8GA1UEAwwIQ2hhbmdlTWWCFAcKlGA9 +aMQSniJmjGX5uOE7EwBdMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAsGA1UdDwQEAwIH +gDANBgkqhkiG9w0BAQsFAAOCAQEASS9FTwf5zyYKDKZFqczK5r4fJEe1p1vwAONt +FbfNH5gzet20LRrA/jSE7FP4sIh8MJ/zQ1sZW9xX5Bj+18/rUAOKvwPVnHmSrV/+ +EqU5dE7h4EivMWKn6Oaa6eLXQFLVqyLjC5x4GIN2ul7+b6qW9HYPiKxWGLzm2rdV +q0K3dCuUAMjloWZjQbWpSH0VztHrFFA+0Kd49JIP4+4N310szoW/czky3Bc51DkR +EfQLrU2viBrUxL+5HO3oIdS3SAFV/6crhrTdtFT7Hw2WK9oVxxPSHTTVE930aiBa +6AC4YIhcdn53gm8bp0xB+08PGt9GHwl5oBwWwc16SByRH9sGkg== +-----END CERTIFICATE----- + + +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/8UsWPZVevZ80 +U9aggHwMOzZlMgy1opgSkoFmc2jd7OO0hvh8MsEbATtHB2H75NRAz562H7gQjaw5 +9nZdhFz7OPZdzf5g3Vi5+u5rYWJT4aoxsLg2jmuxfAiKXxzzAyk7T7wSdGCvlzlj +wnfxc42x9YDyoulrTYO/epXuMGvh4KRstOZ1+ZI8F6AXHTdLX7MteqsgXicigjFd +Z7tYPlMGAtkXhPoqVkgQEthfwgDwjNgpCe2/0cIwdC8zP344iDr8E/HtW5AwjnrF +sokPIeatjaTKMOP4X1KOy+sTbc7LfCGuq7VYzYUfk5h/rT8fsJUUdCDtgr4oR3eA +qIunM0F/AgMBAAECggEAKNI2d+ptBBMr8sMJ2GS6/RbywJ7eWRrVYM3Lu3A8E0a4 +PsKdwjxBGW8vnjGRwzKteYMua+lfChY3VLR4A/eMltlMfDK9MPiiUBtv7WJuuQw7 +WAoPg3rSqJKKdnM4Au7fLAAPLZWWooF08SSAwdcjgX+HBxNitTFtHaIClP+zUfxI +av/bwDbUj928Lo/WZ/UtS0v+Bq8C+B4c/udYN7k4VDTuKvVv0KqJTn0deQ1fGBxt +a61HcLPOjBO9wnakcZMtmcz9bi9ziKIsOvoontTPTNP9M2p11mJMdndZvBW6sue0 +zb31Kd1QLlk6LkLEbp32SwA265QofOvc2Xf8Gr0G8QKBgQDjIhdhvkZqP3cl4jCw +IlPR7Y7TCWECXh9v76MLKIvmLXo5mO8b/DeQBTMQ5N+PW7/6eB5GDFi+B+foqEbk +NbpawtvDSglhGjyj0X6XqYHMpBSBLQuEvw03BiOgJddkE1BA2HVBvfr5JS7eRoZZ +sjOX+OBmpb1ie6hH7QIFbHbrzQKBgQDYVkFD6tKyUI8QhGqLf6xPvLha9gTwCG8m +uQe+fjVFZ2f/Cru5/sNl/xMiW2y1Sq37L8mLmY1hdxSGfkDzfcKdF6I1//woZmfK +cXWFTpqEBYTbVQGktZb37KasNdp4hREavWc3xKdiJOfbxVk+9cO4zSPyfMIpN/Km +YxwCApXOewKBgQDe8W+R+XqUf4csIEE6Ife0b0Fp1CLseAbTkJyxLzNi0/DM6FiL +V54SN4hQZNcrmBtwdscAas4QeSIhNEuhZTtuKyYbImjibyZmhhOEOlW10Lhvsw9D +VWRbRiNh5sLs8Cgt/knaJeha9Sxz8TWehVQvL5LULoseR9J+Bx2cxUJVYQKBgQCh +nqb5l3g7ESYgf9ydRQ+1LldIVV3Q+WwYsMkRTnZ72EoAZsNiq+rMy2g/FbA8LIOY +EdZvfZL7CpyB8daSUhTPibV8xDZc9Ex8GJFkuxmCoiDkPziQFb2okNrf8we5XCgw +Iun25urpzoqNTH1lJPRInrFJWl0vsAWOuqJU+hty+wKBgBDc7Ym9zMUaB1rLatwd +ECejBcvAPpD7rwEqmdzj9DTfzCOaUwsHwsQAEwg1tFrhuK5W44FtAP8y4eWn3Krt +ExPgrA5JxWnmI297Pa9YDuB6eczSdxKH2AxE0vz552ZPnO5eTZIQZAgIuVGZZxmR +KcXzTlbubo5w1jJpvbczHhA5 +-----END PRIVATE KEY----- + + +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +488b61084812969fe8ad0f9dd40f56a2 +6cdadddfe345daef6b5c6d3c3e779fc5 +1f7d236966953482d2af085e3f8581b7 +d216f2d891972a463bbb22ca6c104b9d +f99dcb19d7d575a1d46e7918bb2556c6 +db9f51cd792c5e89e011586214692b95 +2a32a7fe85e4538c40e1d0aa2a9f8e15 +fcc0ce5d31974e3c2041b127776f7658 +878cb8245ed235ec996c2370c0fc0023 +699bc028b3412bc40209cba8233bc111 +fa1438095f99052d799fa718f3b04499 +472254d0286b4b2ce99db49e98a4cc25 +fd948bddcdcf08006a6d7bff40354e7b +5e93ea753a8ecc05de41ae34d280e7eb +99220e436bf8b7693a00667485631e28 +edba3e33b6f558dfa50b92eec6ac8b44 +-----END OpenVPN Static key V1----- + diff --git a/tests/local_vpn/client_configs/make_ovpn.sh b/tests/local_vpn/client_configs/make_ovpn.sh new file mode 100755 index 00000000..6a73d7f7 --- /dev/null +++ b/tests/local_vpn/client_configs/make_ovpn.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# First argument: Client identifier + +KEY_DIR=./keys +BASE_CONFIG=./client.conf + +cat ${BASE_CONFIG} \ + <(echo -e '') \ + ${KEY_DIR}/ca.crt \ + <(echo -e '\n') \ + ${KEY_DIR}/${1}.crt \ + <(echo -e '\n') \ + ${KEY_DIR}/${1}.key \ + <(echo -e '\n') \ + ${KEY_DIR}/ta.key \ + <(echo -e '') \ + > ${1}_client.ovpn diff --git a/tests/local_vpn/client_configs/testserver.local_client.ovpn b/tests/local_vpn/client_configs/testserver.local_client.ovpn new file mode 100644 index 00000000..4d11e13f --- /dev/null +++ b/tests/local_vpn/client_configs/testserver.local_client.ovpn @@ -0,0 +1,299 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel +# if you have more than one. On XP SP2, +# you may need to disable the firewall +# for the TAP adapter. +;dev-node MyTap + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +;proto tcp +proto udp + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +remote 172.17.0.1 9194 + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +;remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +;tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the data-ciphers option in the manpage +;cipher AES-256-CBC +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# Don't enable this unless it is also +# enabled in the server config file. +#comp-lzo + +# Set log file verbosity. +verb 3 + +# Silence repeating messages +;mute 20 + +key-direction 1 + +; script-security 2 +; up /etc/openvpn/update-resolv-conf +; down /etc/openvpn/update-resolv-conf + +; script-security 2 +; up /etc/openvpn/update-systemd-resolved +; down /etc/openvpn/update-systemd-resolved +; down-pre +; dhcp-option DOMAIN-ROUTE . + +-----BEGIN CERTIFICATE----- +MIIDQjCCAiqgAwIBAgIUBwqUYD1oxBKeImaMZfm44TsTAF0wDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQyWhcNMzUwOTIx +MTI0NjQyWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKGt+8oRY7cWPg1SahfIV3XAeeH1SQEFq4f2q+E9ZbWVnCg9 +b59hMzwYr84/j4V73Hlv2udLrkguvnT9KqqJY/0wo3Bd1swH2WLej1fo0+rVo24w +hzeLfeH1e4erZbzQk8XG68U7yNDHKYo+LIz9syBzZA4Bq12bHxDsZbJF7HUANzFR +j9Xg3dR7utPtG8ktmD83rV9/E97whblMpLmjmf2sbCqdLOKTkZnwp5mI47TTkhMj +9K0q7irHmbtZcPZQH5Z59GtqaCaRt8DKfeYniyoPnGVfzFberHHQ4C11pcRrdvgY +n14/W5myh6HESQD6umyCYooyXG7wfqIKujROQCMCAwEAAaOBjTCBijAdBgNVHQ4E +FgQUtMsHbl94qRV7OW5UNNjk2mJ+/U8wTgYDVR0jBEcwRYAUtMsHbl94qRV7OW5U +NNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQHCpRgPWjEEp4iZoxl ++bjhOxMAXTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAQEAGeryP/2JuOp7tzi7Ww9lFUx2DRcgq/FwnU4biotUfuLejHQt/IeIwRYs +dW6AToUYJak8Uy/AFffMootwLcC8z8FATBnxtokWNpxtscpbTSHbeS0HvXnXFaU8 +xxlzp9l5k+46MrrvdzFsjoRfVxs0FUHzWifBnObBziTLfHt+J71509uqRWX6JuTa +PDAT8CMcLKxxS4BcorWtAmc51lW/dQQ41HDJ8a6acltDAprmlnhd8ksWzpTjUDNR +/cfSMcVTpPxPSW/WchR5NlJKQEAf9B/xC+LQgDRSDLaZ8CvzRDgosllzJ+aIS7GK +GPec69LiKqpirZ7enwDM67R4DwIHKA== +-----END CERTIFICATE----- + + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:44:23:c7:c0:5f:a4:2c:ee:c7:77:80:f9:48:36:04 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=ChangeMe + Validity + Not Before: Sep 23 12:46:42 2025 GMT + Not After : Dec 27 12:46:42 2027 GMT + Subject: CN=testserver.local + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b4:ef:06:2e:ca:f4:e5:1f:b4:1e:d0:ca:d4:a1: + ef:03:4d:14:b6:e8:4e:e9:26:e0:c5:96:d7:0a:36: + a5:4c:6d:92:5b:05:e8:0e:57:14:64:c1:84:1f:7c: + f4:99:3a:c7:4a:41:92:5a:c1:99:c1:0c:33:d6:81: + f2:49:e3:7a:10:d1:2e:24:b8:3e:d1:00:a6:c0:a4: + 56:a5:17:7d:70:df:74:e5:0c:97:5e:67:2f:05:0a: + 81:8b:24:5b:22:b5:87:62:12:4a:92:b2:e2:b7:3b: + d6:39:20:dc:22:76:58:61:5c:a4:6d:d5:33:4b:a6: + 54:00:7f:43:69:ce:0a:d6:3a:21:d2:8c:59:1e:e7: + 66:ad:77:6b:fe:56:d3:12:ca:bd:18:55:c9:71:e4: + 8b:da:67:28:b3:63:6b:6f:31:e2:b5:89:15:af:ea: + 1a:9a:7f:31:b3:f1:ba:32:21:59:96:81:71:9f:69: + 13:86:d2:db:c5:aa:0c:a7:95:3b:68:a3:9d:46:a9: + 61:c9:04:13:53:44:3e:60:81:5e:da:54:43:b2:90: + 75:33:dc:4a:9a:ed:2e:f0:82:ef:1f:e6:72:7f:6b: + 20:64:67:9b:d3:66:e4:99:64:6a:62:7f:47:83:c3: + 50:f3:bc:fe:e2:7a:c8:65:99:82:2c:89:3b:2c:78: + 32:e3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + D0:06:2F:3A:D8:9B:F3:9D:7D:B5:8A:F6:5D:CE:8A:83:89:5D:AB:B0 + X509v3 Authority Key Identifier: + keyid:B4:CB:07:6E:5F:78:A9:15:7B:39:6E:54:34:D8:E4:DA:62:7E:FD:4F + DirName:/CN=ChangeMe + serial:07:0A:94:60:3D:68:C4:12:9E:22:66:8C:65:F9:B8:E1:3B:13:00:5D + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 01:81:34:a1:ad:9d:9f:e7:cf:a1:ae:e5:8b:6f:d8:b3:eb:ac: + f7:8f:09:8c:f5:ad:64:96:a5:45:58:c6:92:6e:f8:e2:21:06: + 2d:2a:89:fb:61:d5:eb:6b:56:78:d7:28:31:f7:58:2c:52:bf: + b2:ed:48:92:0c:49:b1:70:30:78:14:41:76:d4:c4:be:3c:15: + b8:4f:27:6d:a9:87:3b:45:b9:a4:76:3d:23:51:6a:9d:ca:24: + 63:ba:50:ed:4c:b9:ad:8f:c8:57:54:44:16:53:35:0a:c6:c8: + 25:2e:57:7c:32:28:57:bd:e4:6d:98:a8:96:31:d9:42:bb:65: + 25:0e:2a:d9:a5:94:17:2c:6c:bb:f7:c6:d6:e9:b2:df:a2:66: + f6:cb:73:43:97:dc:5c:b5:34:a3:0a:8b:84:ba:71:4e:81:83: + 8d:5e:2c:99:7f:12:89:b3:90:27:1a:0c:e8:c6:d5:51:8f:9f: + ea:49:b9:24:64:68:64:40:98:21:82:eb:52:7c:8b:10:48:61: + b5:01:d4:42:6c:2e:13:f1:07:52:0d:cf:05:cd:06:70:0c:63: + aa:e1:dc:93:2b:bb:8e:eb:11:3e:59:6f:12:90:37:29:d8:45: + fc:d3:52:87:b4:a2:55:54:f2:17:d8:f4:32:52:39:3a:cf:0d: + 2c:a0:d4:e3 +-----BEGIN CERTIFICATE----- +MIIDWDCCAkCgAwIBAgIQC0Qjx8BfpCzux3eA+Ug2BDANBgkqhkiG9w0BAQsFADAT +MREwDwYDVQQDDAhDaGFuZ2VNZTAeFw0yNTA5MjMxMjQ2NDJaFw0yNzEyMjcxMjQ2 +NDJaMBsxGTAXBgNVBAMMEHRlc3RzZXJ2ZXIubG9jYWwwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC07wYuyvTlH7Qe0MrUoe8DTRS26E7pJuDFltcKNqVM +bZJbBegOVxRkwYQffPSZOsdKQZJawZnBDDPWgfJJ43oQ0S4kuD7RAKbApFalF31w +33TlDJdeZy8FCoGLJFsitYdiEkqSsuK3O9Y5INwidlhhXKRt1TNLplQAf0NpzgrW +OiHSjFke52atd2v+VtMSyr0YVclx5IvaZyizY2tvMeK1iRWv6hqafzGz8boyIVmW +gXGfaROG0tvFqgynlTtoo51GqWHJBBNTRD5ggV7aVEOykHUz3Eqa7S7wgu8f5nJ/ +ayBkZ5vTZuSZZGpif0eDw1DzvP7ieshlmYIsiTsseDLjAgMBAAGjgZ8wgZwwCQYD +VR0TBAIwADAdBgNVHQ4EFgQU0AYvOtib8519tYr2Xc6Kg4ldq7AwTgYDVR0jBEcw +RYAUtMsHbl94qRV7OW5UNNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1l +ghQHCpRgPWjEEp4iZoxl+bjhOxMAXTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNV +HQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAAGBNKGtnZ/nz6Gu5Ytv2LPrrPeP +CYz1rWSWpUVYxpJu+OIhBi0qifth1etrVnjXKDH3WCxSv7LtSJIMSbFwMHgUQXbU +xL48FbhPJ22phztFuaR2PSNRap3KJGO6UO1Mua2PyFdURBZTNQrGyCUuV3wyKFe9 +5G2YqJYx2UK7ZSUOKtmllBcsbLv3xtbpst+iZvbLc0OX3Fy1NKMKi4S6cU6Bg41e +LJl/EomzkCcaDOjG1VGPn+pJuSRkaGRAmCGC61J8ixBIYbUB1EJsLhPxB1INzwXN +BnAMY6rh3JMru47rET5ZbxKQNynYRfzTUoe0olVU8hfY9DJSOTrPDSyg1OM= +-----END CERTIFICATE----- + + +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07wYuyvTlH7Qe +0MrUoe8DTRS26E7pJuDFltcKNqVMbZJbBegOVxRkwYQffPSZOsdKQZJawZnBDDPW +gfJJ43oQ0S4kuD7RAKbApFalF31w33TlDJdeZy8FCoGLJFsitYdiEkqSsuK3O9Y5 +INwidlhhXKRt1TNLplQAf0NpzgrWOiHSjFke52atd2v+VtMSyr0YVclx5IvaZyiz +Y2tvMeK1iRWv6hqafzGz8boyIVmWgXGfaROG0tvFqgynlTtoo51GqWHJBBNTRD5g +gV7aVEOykHUz3Eqa7S7wgu8f5nJ/ayBkZ5vTZuSZZGpif0eDw1DzvP7ieshlmYIs +iTsseDLjAgMBAAECggEADhFrsfsL3D4r0Mg74m6OLqaGpCDJ9JeWRdFlpPX8wkWJ +af8P56reULs53QI9OSYjKriQevKvVB2bxjj9BWu6KPvqvOYqftuwcNgWTeiBU2O8 +gLa1lPHW68BrtCLpMc4FhHBBph23QmH/qm94o6FUsTVKf6kNFPu4xP/K1mYz3NYv +ejQGXFtmi1bJFo+wf5KhUOg1devz4gWYodGPZlJ2M3tbFLv3Xaaj9k776rSkXmD8 +DQvP5yND0j1x9N6hT/tE2f0pSZmO1iu2782ER2LN2C12FEQKtEReGi9Pm+DkPl/u +KqgxUeIAQazmppP8cfIJH6SK7RXNvHZjCnXKigaJmQKBgQDVR6Gh+mArDXFfalqg +Me2V13On4exe3zwIqHOYxHLcEHqWyLsSKa+xa+CUCfJpc0Nux51SnDaxBOwYBNqT +rYRLxXyN5ocJWpdguiBP8nXdTFVC8XwZtLC2QH+2UK322AUTBmFV85xIVofeLgY/ +H/GOqdi7wIGfg/vdyJUxMnhFdQKBgQDZLMcVo62FEgyPB90ZE3KnGdJJlFHHKkj8 +AC0R20Rd6Y3oDFuoHmKaV1vo5ePthjHhyMgJ2VHIPih3+jt5mQf/zaveHKfrwg4F +rlPbqsY08tWM51qQ1wKgyKi4ASZKWzYQUZBhZrd2YXLyN0EQzMtTLTjaPHIpDVnP +r+w37/+T9wKBgQCRJ0Y3Ekr/IhAF60Ewg6p5739UQ+t2CiI2lkbOMu0lHsX/9y9y +RhLAAnZ+6mIkKIE9VPeacJy8T2hLVIpaNZ6zXv3NKZa/4/rgpuw03QQgj8H7ZJSc +fiBCeZUxxKkRNaYGc7ItKDY1+UZRDSvNLHVfLfNGnNbbdJ0nLUt0hy/ZvQKBgHsj +0J6MeE8DtOtE4jDdvhzRn1LpLpVnfIqm7uc5FMLLMxNoLnBdCjvJXOvprht4A8Cq +QAKVnrGTzQ56bE6+XrLEw7blOLGNDrZZ6mKbqldLeZqzc768q1jPbhsnS7bNkRIf +rWYM/+m3x51fhx0nggJfmeTkcTalw07nyWDOTHRxAoGAQ7poaI25mTTwyX4J4adK +n1BMrrFns7ztHdbWD+P2T1MnJ/ibURPwXCdFuxKCEBtyoEiFTBZRLuB4N4UUwGe3 +pFmgWL4d+qPrCfOyksn0YyTjBtoBPrxSccWrNeKBqePewmnQk0SRLN8w8hoiJFgV +zGLzeXsIRbDfvPT3ZUT3zgI= +-----END PRIVATE KEY----- + + +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +488b61084812969fe8ad0f9dd40f56a2 +6cdadddfe345daef6b5c6d3c3e779fc5 +1f7d236966953482d2af085e3f8581b7 +d216f2d891972a463bbb22ca6c104b9d +f99dcb19d7d575a1d46e7918bb2556c6 +db9f51cd792c5e89e011586214692b95 +2a32a7fe85e4538c40e1d0aa2a9f8e15 +fcc0ce5d31974e3c2041b127776f7658 +878cb8245ed235ec996c2370c0fc0023 +699bc028b3412bc40209cba8233bc111 +fa1438095f99052d799fa718f3b04499 +472254d0286b4b2ce99db49e98a4cc25 +fd948bddcdcf08006a6d7bff40354e7b +5e93ea753a8ecc05de41ae34d280e7eb +99220e436bf8b7693a00667485631e28 +edba3e33b6f558dfa50b92eec6ac8b44 +-----END OpenVPN Static key V1----- + diff --git a/tests/local_vpn/create_openvpn_certificates.sh b/tests/local_vpn/create_openvpn_certificates.sh new file mode 100755 index 00000000..91aef0dc --- /dev/null +++ b/tests/local_vpn/create_openvpn_certificates.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +./_build_docker.sh + +docker run --rm -v ./ca_user:/home/ca_user -v ./client_configs:/client_configs -v ./server_config:/server_config -p 9194:9194/udp --cap-add=NET_ADMIN --privileged --name odelia_testing_openvpnserver odelia_testing_openvpnserver:latest /bin/bash -c "./_openvpn_certificate_creation.sh" diff --git a/tests/local_vpn/run_docker_openvpnserver.sh b/tests/local_vpn/run_docker_openvpnserver.sh new file mode 100755 index 00000000..f501f811 --- /dev/null +++ b/tests/local_vpn/run_docker_openvpnserver.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +./_build_docker.sh + +docker run -d -t --rm -v ./ca_user:/home/ca_user -v ./server_config:/server_config -p 9194:9194/udp --cap-add=NET_ADMIN --privileged --name odelia_testing_openvpnserver odelia_testing_openvpnserver:latest /bin/bash -c "./_openvpn_start.sh && /bin/bash" diff --git a/tests/local_vpn/server_config/.gitignore b/tests/local_vpn/server_config/.gitignore new file mode 100644 index 00000000..23de1ea2 --- /dev/null +++ b/tests/local_vpn/server_config/.gitignore @@ -0,0 +1,2 @@ +nohup.out +ipp.txt \ No newline at end of file diff --git a/tests/local_vpn/server_config/ca.crt b/tests/local_vpn/server_config/ca.crt new file mode 100644 index 00000000..02ee2179 --- /dev/null +++ b/tests/local_vpn/server_config/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQjCCAiqgAwIBAgIUBwqUYD1oxBKeImaMZfm44TsTAF0wDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIQ2hhbmdlTWUwHhcNMjUwOTIzMTI0NjQyWhcNMzUwOTIx +MTI0NjQyWjATMREwDwYDVQQDDAhDaGFuZ2VNZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKGt+8oRY7cWPg1SahfIV3XAeeH1SQEFq4f2q+E9ZbWVnCg9 +b59hMzwYr84/j4V73Hlv2udLrkguvnT9KqqJY/0wo3Bd1swH2WLej1fo0+rVo24w +hzeLfeH1e4erZbzQk8XG68U7yNDHKYo+LIz9syBzZA4Bq12bHxDsZbJF7HUANzFR +j9Xg3dR7utPtG8ktmD83rV9/E97whblMpLmjmf2sbCqdLOKTkZnwp5mI47TTkhMj +9K0q7irHmbtZcPZQH5Z59GtqaCaRt8DKfeYniyoPnGVfzFberHHQ4C11pcRrdvgY +n14/W5myh6HESQD6umyCYooyXG7wfqIKujROQCMCAwEAAaOBjTCBijAdBgNVHQ4E +FgQUtMsHbl94qRV7OW5UNNjk2mJ+/U8wTgYDVR0jBEcwRYAUtMsHbl94qRV7OW5U +NNjk2mJ+/U+hF6QVMBMxETAPBgNVBAMMCENoYW5nZU1lghQHCpRgPWjEEp4iZoxl ++bjhOxMAXTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAQEAGeryP/2JuOp7tzi7Ww9lFUx2DRcgq/FwnU4biotUfuLejHQt/IeIwRYs +dW6AToUYJak8Uy/AFffMootwLcC8z8FATBnxtokWNpxtscpbTSHbeS0HvXnXFaU8 +xxlzp9l5k+46MrrvdzFsjoRfVxs0FUHzWifBnObBziTLfHt+J71509uqRWX6JuTa +PDAT8CMcLKxxS4BcorWtAmc51lW/dQQ41HDJ8a6acltDAprmlnhd8ksWzpTjUDNR +/cfSMcVTpPxPSW/WchR5NlJKQEAf9B/xC+LQgDRSDLaZ8CvzRDgosllzJ+aIS7GK +GPec69LiKqpirZ7enwDM67R4DwIHKA== +-----END CERTIFICATE----- diff --git a/tests/local_vpn/server_config/ccd/admin@test.odelia b/tests/local_vpn/server_config/ccd/admin@test.odelia new file mode 100644 index 00000000..3e8f368e --- /dev/null +++ b/tests/local_vpn/server_config/ccd/admin@test.odelia @@ -0,0 +1 @@ +ifconfig-push 10.8.0.5 255.0.0.0 diff --git a/tests/local_vpn/server_config/ccd/client_A b/tests/local_vpn/server_config/ccd/client_A new file mode 100644 index 00000000..2009193e --- /dev/null +++ b/tests/local_vpn/server_config/ccd/client_A @@ -0,0 +1 @@ +ifconfig-push 10.8.0.6 255.0.0.0 diff --git a/tests/local_vpn/server_config/ccd/client_B b/tests/local_vpn/server_config/ccd/client_B new file mode 100644 index 00000000..da607617 --- /dev/null +++ b/tests/local_vpn/server_config/ccd/client_B @@ -0,0 +1 @@ +ifconfig-push 10.8.0.7 255.0.0.0 diff --git a/tests/local_vpn/server_config/ccd/testserver.local b/tests/local_vpn/server_config/ccd/testserver.local new file mode 100644 index 00000000..75bd4873 --- /dev/null +++ b/tests/local_vpn/server_config/ccd/testserver.local @@ -0,0 +1 @@ +ifconfig-push 10.8.0.4 255.0.0.0 diff --git a/tests/local_vpn/server_config/server.conf b/tests/local_vpn/server_config/server.conf new file mode 100755 index 00000000..8d90cd74 --- /dev/null +++ b/tests/local_vpn/server_config/server.conf @@ -0,0 +1,304 @@ +################################################# +# Sample OpenVPN 2.0 config file for # +# multi-client server. # +# # +# This file is for the server side # +# of a many-clients <-> one-server # +# OpenVPN configuration. # +# # +# OpenVPN also supports # +# single-machine <-> single-machine # +# configurations (See the Examples page # +# on the web site for more info). # +# # +# This config should work on Windows # +# or Linux/BSD systems. Remember on # +# Windows to quote pathnames and use # +# double backslashes, e.g.: # +# "C:\\Program Files\\OpenVPN\\config\\foo.key" # +# # +# Comments are preceded with '#' or ';' # +################################################# + +# Which local IP address should OpenVPN +# listen on? (optional) +;local a.b.c.d + +# Which TCP/UDP port should OpenVPN listen on? +# If you want to run multiple OpenVPN instances +# on the same machine, use a different port +# number for each one. You will need to +# open up this port on your firewall. +port 9194 + +# TCP or UDP server? +;proto tcp +proto udp + +# "dev tun" will create a routed IP tunnel, +# "dev tap" will create an ethernet tunnel. +# Use "dev tap0" if you are ethernet bridging +# and have precreated a tap0 virtual interface +# and bridged it with your ethernet interface. +# If you want to control access policies +# over the VPN, you must create firewall +# rules for the the TUN/TAP interface. +# On non-Windows systems, you can give +# an explicit unit number, such as tun0. +# On Windows, use "dev-node" for this. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel if you +# have more than one. On XP SP2 or higher, +# you may need to selectively disable the +# Windows firewall for the TAP adapter. +# Non-Windows systems usually don't need this. +;dev-node MyTap + +# SSL/TLS root certificate (ca), certificate +# (cert), and private key (key). Each client +# and the server must have their own cert and +# key file. The server and all clients will +# use the same ca file. +# +# See the "easy-rsa" directory for a series +# of scripts for generating RSA certificates +# and private keys. Remember to use +# a unique Common Name for the server +# and each of the client certificates. +# +# Any X509 key management system can be used. +# OpenVPN can also use a PKCS #12 formatted key file +# (see "pkcs12" directive in man page). +ca /etc/openvpn/server/ca.crt +cert /etc/openvpn/server/server.crt +key /etc/openvpn/server/server.key # This file should be kept secret + +# Diffie hellman parameters. +# Generate your own with: +# openssl dhparam -out dh1024.pem 1024 +# Substitute 2048 for 1024 if you are using +# 2048 bit keys. +;dh dh1024.pem +dh none + +# Configure server mode and supply a VPN subnet +# for OpenVPN to draw client addresses from. +# The server will take 10.8.0.1 for itself, +# the rest will be made available to clients. +# Each client will be able to reach the server +# on 10.8.0.1. Comment this line out if you are +# ethernet bridging. See the man page for more info. +server 10.8.0.0 255.255.255.0 + +# Maintain a record of client <-> virtual IP address +# associations in this file. If OpenVPN goes down or +# is restarted, reconnecting clients can be assigned +# the same virtual IP address from the pool that was +# previously assigned. +ifconfig-pool-persist ipp.txt + +# Configure server mode for ethernet bridging. +# You must first use your OS's bridging capability +# to bridge the TAP interface with the ethernet +# NIC interface. Then you must manually set the +# IP/netmask on the bridge interface, here we +# assume 10.8.0.4/255.255.255.0. Finally we +# must set aside an IP range in this subnet +# (start=10.8.0.50 end=10.8.0.100) to allocate +# to connecting clients. Leave this line commented +# out unless you are ethernet bridging. +;server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100 + +# Configure server mode for ethernet bridging +# using a DHCP-proxy, where clients talk +# to the OpenVPN server-side DHCP server +# to receive their IP address allocation +# and DNS server addresses. You must first use +# your OS's bridging capability to bridge the TAP +# interface with the ethernet NIC interface. +# Note: this mode only works on clients (such as +# Windows), where the client-side TAP adapter is +# bound to a DHCP client. +;server-bridge + +# Push routes to the client to allow it +# to reach other private subnets behind +# the server. Remember that these +# private subnets will also need +# to know to route the OpenVPN client +# address pool (10.8.0.0/255.255.255.0) +# back to the OpenVPN server. +;push "route 192.168.10.0 255.255.255.0" +;push "route 192.168.20.0 255.255.255.0" + +# To assign specific IP addresses to specific +# clients or if a connecting client has a private +# subnet behind it that should also have VPN access, +# use the subdirectory "ccd" for client-specific +# configuration files (see man page for more info). + +# EXAMPLE: Suppose the client +# having the certificate common name "Thelonious" +# also has a small subnet behind his connecting +# machine, such as 192.168.40.128/255.255.255.248. +# First, uncomment out these lines: +;client-config-dir ccd +;route 192.168.40.128 255.255.255.248 +# Then create a file ccd/Thelonious with this line: +# iroute 192.168.40.128 255.255.255.248 +# This will allow Thelonious' private subnet to +# access the VPN. This example will only work +# if you are routing, not bridging, i.e. you are +# using "dev tun" and "server" directives. + +# EXAMPLE: Suppose you want to give +# Thelonious a fixed VPN IP address of 10.9.0.1. +# First uncomment out these lines: +client-config-dir /server_config/ccd +;route 10.9.0.0 255.255.255.252 +# Then add this line to ccd/Thelonious: +# ifconfig-push 10.9.0.1 10.9.0.2 + +# Suppose that you want to enable different +# firewall access policies for different groups +# of clients. There are two methods: +# (1) Run multiple OpenVPN daemons, one for each +# group, and firewall the TUN/TAP interface +# for each group/daemon appropriately. +# (2) (Advanced) Create a script to dynamically +# modify the firewall in response to access +# from different clients. See man +# page for more info on learn-address script. +;learn-address ./script + +# If enabled, this directive will configure +# all clients to redirect their default +# network gateway through the VPN, causing +# all IP traffic such as web browsing and +# and DNS lookups to go through the VPN +# (The OpenVPN server machine may need to NAT +# or bridge the TUN/TAP interface to the internet +# in order for this to work properly). +;push "redirect-gateway def1 bypass-dhcp" + +# Certain Windows-specific network settings +# can be pushed to clients, such as DNS +# or WINS server addresses. CAVEAT: +# http://openvpn.net/faq.html#dhcpcaveats +# The addresses below refer to the public +# DNS servers provided by opendns.com. +;push "dhcp-option DNS 208.67.222.222" +;push "dhcp-option DNS 208.67.220.220" + +# Uncomment this directive to allow different +# clients to be able to "see" each other. +# By default, clients will only see the server. +# To force clients to only see the server, you +# will also need to appropriately firewall the +# server's TUN/TAP interface. +;client-to-client + +# Uncomment this directive if multiple clients +# might connect with the same certificate/key +# files or common names. This is recommended +# only for testing purposes. For production use, +# each client should have its own certificate/key +# pair. +# +# IF YOU HAVE NOT GENERATED INDIVIDUAL +# CERTIFICATE/KEY PAIRS FOR EACH CLIENT, +# EACH HAVING ITS OWN UNIQUE "COMMON NAME", +# UNCOMMENT THIS LINE OUT. +;duplicate-cn + +# The keepalive directive causes ping-like +# messages to be sent back and forth over +# the link so that each side knows when +# the other side has gone down. +# Ping every 10 seconds, assume that remote +# peer is down if no ping received during +# a 120 second time period. +keepalive 2 10 + +# For extra security beyond that provided +# by SSL/TLS, create an "HMAC firewall" +# to help block DoS attacks and UDP port flooding. +# +# Generate with: +# openvpn --genkey --secret ta.key +# +# The server and each client must have +# a copy of this key. +# The second parameter should be '0' +# on the server and '1' on the clients. +;tls-auth ta.key 0 # This file is secret +tls-crypt /etc/openvpn/server/ta.key + +# Select a cryptographic cipher. +# This config item must be copied to +# the client config file as well. +;cipher BF-CBC # Blowfish (default) +;cipher AES-128-CBC # AES +;cipher DES-EDE3-CBC # Triple-DES +cipher AES-256-GCM + +auth SHA256 + +# Enable compression on the VPN link. +# If you enable it here, you must also +# enable it in the client config file. +;comp-lzo + +# The maximum number of concurrently connected +# clients we want to allow. +;max-clients 100 + +# It's a good idea to reduce the OpenVPN +# daemon's privileges after initialization. +# +# You can uncomment this out on +# non-Windows systems. +user nobody +group nogroup + +# The persist options will try to avoid +# accessing certain resources on restart +# that may no longer be accessible because +# of the privilege downgrade. +persist-key +persist-tun + +# Output a short status file showing +# current connections, truncated +# and rewritten every minute. +status openvpn-status.log + +# By default, log messages will go to the syslog (or +# on Windows, if running as a service, they will go to +# the "\Program Files\OpenVPN\log" directory). +# Use log or log-append to override this default. +# "log" will truncate the log file on OpenVPN startup, +# while "log-append" will append to it. Use one +# or the other (but not both). +;log openvpn.log +;log-append openvpn.log + +# Set the appropriate level of log +# file verbosity. +# +# 0 is silent, except for fatal errors +# 4 is reasonable for general usage +# 5 and 6 can help to debug connection problems +# 9 is extremely verbose +verb 3 + +# Silence repeating messages. At most 20 +# sequential messages of the same message +# category will be output to the log. +;mute 20 diff --git a/tests/local_vpn/server_config/server.crt b/tests/local_vpn/server_config/server.crt new file mode 100644 index 00000000..8a6bcc20 --- /dev/null +++ b/tests/local_vpn/server_config/server.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 61:74:e5:68:11:63:be:bb:fa:fa:4d:63:12:ad:fa:6a + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=ChangeMe + Validity + Not Before: Sep 23 12:46:42 2025 GMT + Not After : Dec 27 12:46:42 2027 GMT + Subject: CN=ChangeMe + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ae:66:65:3b:39:6e:aa:39:39:7f:f1:be:18:c4: + 52:60:c3:3c:63:77:2a:fd:d0:79:22:6a:5f:b7:ab: + 9d:94:27:89:9a:5c:2d:b7:ea:66:91:f7:06:57:24: + 38:bd:55:71:2d:ff:9a:dd:b3:ed:0c:bf:1b:8c:93: + 27:63:d4:a1:a7:00:55:68:c5:a0:c4:9e:d3:51:d7: + ec:f8:9d:7e:b1:a4:84:80:78:9b:76:58:61:b9:89: + c9:94:e5:ad:ca:61:33:e0:f7:f3:35:0a:fc:6c:28: + b5:53:57:52:01:0a:e1:60:f1:42:f0:a4:d3:e1:4e: + 25:12:83:01:ba:f5:1a:96:44:33:17:b8:69:bc:a4: + b1:2e:b1:e0:e3:50:c6:6f:dc:f7:12:16:40:21:63: + db:14:b1:b1:fe:6f:76:84:f7:ef:a0:bb:0b:dc:03: + 44:b6:2a:f0:61:7b:7c:4a:7a:51:9b:ab:01:8f:10: + a8:db:10:62:c3:72:3b:2c:fc:b5:03:e2:73:e6:1d: + d0:3e:a5:83:f5:ae:30:4c:d8:79:28:d1:d1:5c:61: + 84:2d:8c:0d:8d:39:ce:a6:15:21:0b:4b:cd:29:28: + 72:ed:9e:63:7d:73:bd:70:f3:29:4f:c5:c4:95:ef: + dc:a7:28:27:af:36:91:e0:53:ef:4e:7d:ba:50:34: + 83:51 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 5C:FC:F9:A1:E6:BE:75:F7:02:23:72:3B:F2:09:B5:A9:D2:8C:A1:3B + X509v3 Authority Key Identifier: + keyid:B4:CB:07:6E:5F:78:A9:15:7B:39:6E:54:34:D8:E4:DA:62:7E:FD:4F + DirName:/CN=ChangeMe + serial:07:0A:94:60:3D:68:C4:12:9E:22:66:8C:65:F9:B8:E1:3B:13:00:5D + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:ChangeMe + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 6c:df:63:30:de:ae:e7:4a:07:be:c3:c6:78:fe:91:f4:89:c1: + 41:fc:58:d3:52:e8:bd:ab:6b:a1:68:d5:8a:36:4f:6f:21:68: + 2a:07:c6:cd:56:7f:8b:f9:0d:00:f7:9f:ba:2f:84:79:08:a2: + 53:8b:4b:76:6b:49:59:bb:9a:51:45:63:c3:25:ce:d2:46:61: + fe:2c:86:d4:ae:f7:bb:de:c2:f1:4f:8d:46:6e:a6:f3:cb:25: + 72:75:e7:eb:c6:a2:10:34:8a:a9:ca:9c:b4:ba:9c:e0:50:6d: + cd:91:a9:97:37:be:d7:40:e1:21:ba:a8:fe:8f:0d:96:2d:19: + a0:10:41:8b:cf:16:4a:a3:83:24:96:62:11:0f:e1:76:5d:46: + 1e:60:1d:2f:9d:1c:87:de:b0:1b:f7:26:61:13:af:41:44:01: + b6:dd:40:de:94:20:04:5e:68:42:79:7b:13:03:b0:6c:5f:d2: + ff:3c:15:6b:ca:21:57:69:61:de:05:68:b1:9e:e5:f8:be:c2: + 38:c7:1f:53:2e:da:7b:fd:26:fa:83:8e:5d:06:70:d9:7d:9e: + c1:75:99:70:f7:3e:66:e4:95:8e:43:ec:4a:9d:bd:0f:d7:08: + 64:f1:5f:f8:94:46:6e:46:20:44:5f:71:0b:2e:e2:0d:87:eb: + 69:cb:86:af +-----BEGIN CERTIFICATE----- +MIIDZTCCAk2gAwIBAgIQYXTlaBFjvrv6+k1jEq36ajANBgkqhkiG9w0BAQsFADAT +MREwDwYDVQQDDAhDaGFuZ2VNZTAeFw0yNTA5MjMxMjQ2NDJaFw0yNzEyMjcxMjQ2 +NDJaMBMxETAPBgNVBAMMCENoYW5nZU1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArmZlOzluqjk5f/G+GMRSYMM8Y3cq/dB5Impft6udlCeJmlwtt+pm +kfcGVyQ4vVVxLf+a3bPtDL8bjJMnY9ShpwBVaMWgxJ7TUdfs+J1+saSEgHibdlhh +uYnJlOWtymEz4PfzNQr8bCi1U1dSAQrhYPFC8KTT4U4lEoMBuvUalkQzF7hpvKSx +LrHg41DGb9z3EhZAIWPbFLGx/m92hPfvoLsL3ANEtirwYXt8SnpRm6sBjxCo2xBi +w3I7LPy1A+Jz5h3QPqWD9a4wTNh5KNHRXGGELYwNjTnOphUhC0vNKShy7Z5jfXO9 +cPMpT8XEle/cpygnrzaR4FPvTn26UDSDUQIDAQABo4G0MIGxMAkGA1UdEwQCMAAw +HQYDVR0OBBYEFFz8+aHmvnX3AiNyO/IJtanSjKE7ME4GA1UdIwRHMEWAFLTLB25f +eKkVezluVDTY5Npifv1PoRekFTATMREwDwYDVQQDDAhDaGFuZ2VNZYIUBwqUYD1o +xBKeImaMZfm44TsTAF0wEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWg +MBMGA1UdEQQMMAqCCENoYW5nZU1lMA0GCSqGSIb3DQEBCwUAA4IBAQBs32Mw3q7n +Sge+w8Z4/pH0icFB/FjTUui9q2uhaNWKNk9vIWgqB8bNVn+L+Q0A95+6L4R5CKJT +i0t2a0lZu5pRRWPDJc7SRmH+LIbUrve73sLxT41GbqbzyyVydefrxqIQNIqpypy0 +upzgUG3NkamXN77XQOEhuqj+jw2WLRmgEEGLzxZKo4MklmIRD+F2XUYeYB0vnRyH +3rAb9yZhE69BRAG23UDelCAEXmhCeXsTA7BsX9L/PBVryiFXaWHeBWixnuX4vsI4 +xx9TLtp7/Sb6g45dBnDZfZ7BdZlw9z5m5JWOQ+xKnb0P1whk8V/4lEZuRiBEX3EL +LuINh+tpy4av +-----END CERTIFICATE----- diff --git a/tests/local_vpn/server_config/server.key b/tests/local_vpn/server_config/server.key new file mode 100644 index 00000000..b73e742e --- /dev/null +++ b/tests/local_vpn/server_config/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuZmU7OW6qOTl/ +8b4YxFJgwzxjdyr90Hkial+3q52UJ4maXC236maR9wZXJDi9VXEt/5rds+0MvxuM +kydj1KGnAFVoxaDEntNR1+z4nX6xpISAeJt2WGG5icmU5a3KYTPg9/M1CvxsKLVT +V1IBCuFg8ULwpNPhTiUSgwG69RqWRDMXuGm8pLEuseDjUMZv3PcSFkAhY9sUsbH+ +b3aE9++guwvcA0S2KvBhe3xKelGbqwGPEKjbEGLDcjss/LUD4nPmHdA+pYP1rjBM +2Hko0dFcYYQtjA2NOc6mFSELS80pKHLtnmN9c71w8ylPxcSV79ynKCevNpHgU+9O +fbpQNINRAgMBAAECggEAQBXzfBxiLJ4joX7hRnOZ++GyZrCLNUKuyLVDIBipqqAO +whC+Yhd6Aog+JbZzPSvRD8CeFXsBEE6HnpQShO5FSrtmJz58EdR1Pd11QHSLclbM +s/Ld2dKncokN8K+nubcXW8NxdRvo3wvkedAcG7L2V+vAF/LRwzi2icNnVt6rmuyw +Z/W5/HERlt4IAikKDQhBZrtGx5Cbjun5ekjN2sWFVB7TT2u6o/BsYQ7ljGUZt9uQ +DStfOURAv5BE8eYyWQIxd7fPCfY3UNxpJUPxvuDxpeCwITzD5v8qoVSBBH1lvQ7s +i61/Cr7dfwNsAtlMzrERxRmMR5WQzsfxPvfqhb3IuwKBgQDZo8zBAEXiTnNSl3W5 +1bs1ab8AFTfTzeY2Th2SxDZLdcy5I3dirwfusyQkv5eoRWi5Vx/fNXIh5OJos2Fu +M0CxuuJVP2dkXzBJrazAkzlDhEsG/MGMaIE/p3aFQeyID1EZcN3u3Z9StEbW4B8y +I/8dTgJCnBzfHs2HH80VbQHsZwKBgQDNI44tqevSW6XwwXz1sYJy5NBPrksRLEcU +rhm6rsLMhKXHUJa0KDeOeM9sjiBBrCL/pOkqwcnLUsqZ8pIQIEhwaIBfHznblgxZ +jCho3ZjYm4/Is9XD/lcS2yU5ialRI9kFz6qTkOlO0XonIwJs4NiITbuzfopr2BGh +IlzXcrC/hwKBgQCUl6IvT4lnJprUE/bbx1JG+IjgfJweLyDziMfmMbLEOIxrBwz2 +wnwO/B48PNdFmwYSLKrlEa939raiN37Y54NPFUJ8Y4qq29azJzGgVaQuNb+n6KAY +xi0gkax49PaSOqrrTMUp1gR2SgFnqaOC71K55k3ivoVzzKsUi6DQ9RjwFwKBgEiD +/BuaSJmo+iT8UO8NW96/kf/IzhJ5A3uE++VpJ8ViUrP9gfiXiuQbQr/OEgsFDa4v +HpmVvX7ZenMnM4jt0I2j81Us1agRB7aT/CjtxL01aIN7RuKswx0QSL1pM2hScsJC +Ibtea4sIM9Un5BCW/xRX3jVaUxZCYCEE46rpiR97AoGBAJdQQnQAxYS2Ua7Jj0go +0SgG99w7ONZjSupTTr4VpMaXmh6CBke44RulMUA+PwB1XtfVpxx8xhuPq2d6y79T +o5OLbEjdLPq8A8S0n5eXMD7FXXG8TYPpcqoO2Hqhgu9q1vRgqPopIcRuhhp5wdCp +iIGJHhwsI9sYN6wnGydeOH9U +-----END PRIVATE KEY----- diff --git a/tests/local_vpn/server_config/ta.key b/tests/local_vpn/server_config/ta.key new file mode 100644 index 00000000..2bf036ac --- /dev/null +++ b/tests/local_vpn/server_config/ta.key @@ -0,0 +1,21 @@ +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +488b61084812969fe8ad0f9dd40f56a2 +6cdadddfe345daef6b5c6d3c3e779fc5 +1f7d236966953482d2af085e3f8581b7 +d216f2d891972a463bbb22ca6c104b9d +f99dcb19d7d575a1d46e7918bb2556c6 +db9f51cd792c5e89e011586214692b95 +2a32a7fe85e4538c40e1d0aa2a9f8e15 +fcc0ce5d31974e3c2041b127776f7658 +878cb8245ed235ec996c2370c0fc0023 +699bc028b3412bc40209cba8233bc111 +fa1438095f99052d799fa718f3b04499 +472254d0286b4b2ce99db49e98a4cc25 +fd948bddcdcf08006a6d7bff40354e7b +5e93ea753a8ecc05de41ae34d280e7eb +99220e436bf8b7693a00667485631e28 +edba3e33b6f558dfa50b92eec6ac8b44 +-----END OpenVPN Static key V1----- diff --git a/tests/provision/dummy_project_for_testing.yml b/tests/provision/dummy_project_for_testing.yml index 7e259592..ea544be7 100644 --- a/tests/provision/dummy_project_for_testing.yml +++ b/tests/provision/dummy_project_for_testing.yml @@ -4,11 +4,11 @@ description: > Test setup. participants: - - name: server.local + - name: testserver.local type: server org: Test_Org - fed_learn_port: 8002 - admin_port: 8003 + fed_learn_port: 8012 + admin_port: 8013 - name: client_A type: client org: Test_Org @@ -29,12 +29,12 @@ builders: args: config_folder: config scheme: http - docker_image: jefftud/odelia:__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_STARTUP_KITS__ + docker_image: localhost:5000/odelia:__REPLACED_BY_CURRENT_VERSION_NUMBER_WHEN_BUILDING_STARTUP_KITS__ overseer_agent: path: nvflare.ha.dummy_overseer_agent.DummyOverseerAgent overseer_exists: false args: - sp_end_point: odeliatempvm.local:8002:8003 + sp_end_point: testserver.local:8012:8013 - path: nvflare.lighter.impl.cert.CertBuilder - path: nvflare.lighter.impl.signature.SignatureBuilder diff --git a/tests/unit_tests/_run_nvflare_unit_tests.sh b/tests/unit_tests/_run_nvflare_unit_tests.sh new file mode 100755 index 00000000..890406c2 --- /dev/null +++ b/tests/unit_tests/_run_nvflare_unit_tests.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +run_nvflare_unit_tests () { + cd /MediSwarm/docker_config/NVFlare + ./runtest.sh -c -r + coverage report -m + cd .. +} + +run_nvflare_unit_tests