From acdafbc116ac2348dcf41055402dbb5ecfad8be2 Mon Sep 17 00:00:00 2001 From: Milas Bowman Date: Wed, 27 Jul 2022 16:25:27 -0400 Subject: [PATCH] ci: run SSH integration tests (#3012) Fix & enable SSH integration test suite. This also adds a new test for connecting to unknown hosts when using the Python SSH implementation (Paramiko). See #2932 for more info. Because of the above, some of the config/static key files have been moved around and adjusted. Signed-off-by: Milas Bowman --- .github/workflows/ci.yml | 2 +- Makefile | 41 ++++++++++++++----- tests/Dockerfile | 4 +- tests/Dockerfile-ssh-dind | 19 ++++----- tests/ssh-keys/authorized_keys | 1 - tests/ssh-keys/config | 3 -- tests/ssh/base.py | 4 ++ tests/{ssh-keys => ssh/config/client}/id_rsa | 0 .../config/client}/id_rsa.pub | 0 tests/ssh/config/server/known_ed25519 | 7 ++++ tests/ssh/config/server/known_ed25519.pub | 1 + tests/ssh/config/server/sshd_config | 3 ++ tests/ssh/config/server/unknown_ed25519 | 7 ++++ tests/ssh/config/server/unknown_ed25519.pub | 1 + tests/ssh/connect_test.py | 22 ++++++++++ 15 files changed, 86 insertions(+), 29 deletions(-) delete mode 100755 tests/ssh-keys/authorized_keys delete mode 100644 tests/ssh-keys/config rename tests/{ssh-keys => ssh/config/client}/id_rsa (100%) rename tests/{ssh-keys => ssh/config/client}/id_rsa.pub (100%) create mode 100644 tests/ssh/config/server/known_ed25519 create mode 100644 tests/ssh/config/server/known_ed25519.pub create mode 100644 tests/ssh/config/server/sshd_config create mode 100644 tests/ssh/config/server/unknown_ed25519 create mode 100644 tests/ssh/config/server/unknown_ed25519.pub create mode 100644 tests/ssh/connect_test.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2987b49..296bf0dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - variant: [ "integration-dind", "integration-dind-ssl" ] + variant: [ "integration-dind", "integration-dind-ssl", "integration-dind-ssh" ] steps: - uses: actions/checkout@v3 diff --git a/Makefile b/Makefile index 27144d4d..ae6ae34e 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,21 @@ clean: .PHONY: build-dind-ssh build-dind-ssh: - docker build -t docker-dind-ssh -f tests/Dockerfile-ssh-dind --build-arg ENGINE_VERSION=${TEST_ENGINE_VERSION} --build-arg API_VERSION=${TEST_API_VERSION} --build-arg APT_MIRROR . + docker build \ + --pull \ + -t docker-dind-ssh \ + -f tests/Dockerfile-ssh-dind \ + --build-arg ENGINE_VERSION=${TEST_ENGINE_VERSION} \ + --build-arg API_VERSION=${TEST_API_VERSION} \ + --build-arg APT_MIRROR . .PHONY: build-py3 build-py3: - docker build -t docker-sdk-python3 -f tests/Dockerfile --build-arg APT_MIRROR . + docker build \ + --pull \ + -t docker-sdk-python3 \ + -f tests/Dockerfile \ + --build-arg APT_MIRROR . .PHONY: build-docs build-docs: @@ -61,6 +71,7 @@ integration-dind-py3: build-py3 setup-network --detach \ --name dpy-dind-py3 \ --network dpy-tests \ + --pull=always \ --privileged \ docker:${TEST_ENGINE_VERSION}-dind \ dockerd -H tcp://0.0.0.0:2375 --experimental @@ -85,16 +96,23 @@ integration-dind-py3: build-py3 setup-network docker rm -vf dpy-dind-py3 -.PHONY: integration-ssh-py3 -integration-ssh-py3: build-dind-ssh build-py3 setup-network - docker rm -vf dpy-dind-py3 || : - docker run -d --network dpy-tests --name dpy-dind-py3 --privileged\ +.PHONY: integration-dind-ssh +integration-dind-ssh: build-dind-ssh build-py3 setup-network + docker rm -vf dpy-dind-ssh || : + docker run -d --network dpy-tests --name dpy-dind-ssh --privileged \ docker-dind-ssh dockerd --experimental - # start SSH daemon - docker exec dpy-dind-py3 sh -c "/usr/sbin/sshd" - docker run -t --rm --env="DOCKER_HOST=ssh://dpy-dind-py3" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ - --network dpy-tests docker-sdk-python3 py.test tests/ssh/${file} - docker rm -vf dpy-dind-py3 + # start SSH daemon for known key + docker exec dpy-dind-ssh sh -c "/usr/sbin/sshd -h /etc/ssh/known_ed25519 -p 22" + docker exec dpy-dind-ssh sh -c "/usr/sbin/sshd -h /etc/ssh/unknown_ed25519 -p 2222" + docker run \ + --tty \ + --rm \ + --env="DOCKER_HOST=ssh://dpy-dind-ssh" \ + --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}" \ + --env="UNKNOWN_DOCKER_SSH_HOST=ssh://dpy-dind-ssh:2222" \ + --network dpy-tests \ + docker-sdk-python3 py.test tests/ssh/${file} + docker rm -vf dpy-dind-ssh .PHONY: integration-dind-ssl @@ -110,6 +128,7 @@ integration-dind-ssl: build-dind-certs build-py3 setup-network --name dpy-dind-ssl \ --network dpy-tests \ --network-alias docker \ + --pull=always \ --privileged \ --volume /tmp \ --volumes-from dpy-dind-certs \ diff --git a/tests/Dockerfile b/tests/Dockerfile index 1d60cfe4..e24da47d 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -11,7 +11,9 @@ RUN apt-get update && apt-get -y install --no-install-recommends \ pass # Add SSH keys and set permissions -COPY tests/ssh-keys /root/.ssh +COPY tests/ssh/config/client /root/.ssh +COPY tests/ssh/config/server/known_ed25519.pub /root/.ssh/known_hosts +RUN sed -i '1s;^;dpy-dind-ssh ;' /root/.ssh/known_hosts RUN chmod -R 600 /root/.ssh COPY ./tests/gpg-keys /gpg-keys diff --git a/tests/Dockerfile-ssh-dind b/tests/Dockerfile-ssh-dind index 6f080182..22c707a0 100644 --- a/tests/Dockerfile-ssh-dind +++ b/tests/Dockerfile-ssh-dind @@ -1,23 +1,18 @@ ARG API_VERSION=1.41 -ARG ENGINE_VERSION=20.10.17 +ARG ENGINE_VERSION=20.10 FROM docker:${ENGINE_VERSION}-dind -RUN apk add --no-cache \ +RUN apk add --no-cache --upgrade \ openssh -# Add the keys and set permissions -RUN ssh-keygen -A - -# copy the test SSH config -RUN echo "IgnoreUserKnownHosts yes" > /etc/ssh/sshd_config && \ - echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config && \ - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config +COPY tests/ssh/config/server /etc/ssh/ +RUN chmod -R 600 /etc/ssh # set authorized keys for client paswordless connection -COPY tests/ssh-keys/authorized_keys /root/.ssh/authorized_keys -RUN chmod 600 /root/.ssh/authorized_keys +COPY tests/ssh/config/client/id_rsa.pub /root/.ssh/authorized_keys +RUN chmod -R 600 /root/.ssh -RUN echo "root:root" | chpasswd +# RUN echo "root:root" | chpasswd RUN ln -s /usr/local/bin/docker /usr/bin/docker EXPOSE 22 diff --git a/tests/ssh-keys/authorized_keys b/tests/ssh-keys/authorized_keys deleted file mode 100755 index 33252fe5..00000000 --- a/tests/ssh-keys/authorized_keys +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/BiXkbL9oEbE3PJv1S2p12XK5BHW3qQT5Rf+CYG0ATYyMPIVM6+IXVyf3QNxpnvPXvbPBQJCs0qHeuPwZy2Gsbt35QnmlgrczFPiXXosCD2N+wrcOQPZGuLjQyUUP2yJRVSTLpp8zk2F8w3laGIB3Jk1hUcMUExemKxQYk/L40b5rXKkarLk5awBuicjRStMrchPRHZ2n715TG+zSvf8tB/UHRXKYPqai/Je5eiH3yGUzCY4zn+uEoqAFb4V8lpIj8Rw3EXmCYVwG0vg+44QIQ2gJnIhTlcmxwkynvZn97nug4NLlGJQ+sDCnIvMapycHfGkNlBz3fFtu/ORsxPpZbTNg/9noa3Zf8OpIwvE/FHNPqDctGltwxEgQxj5fE34x0fYnF08tejAUJJCZE3YsGgNabsS4pD+kRhI83eFZvgj3Q1AeTK0V9bRM7jujcc9Rz+V9Gb5zYEHN/l8PxEVlj0OlURf9ZlknNQK8xRh597jDXTfVQKCMO/nRaWH2bq0= diff --git a/tests/ssh-keys/config b/tests/ssh-keys/config deleted file mode 100644 index 8dd13540..00000000 --- a/tests/ssh-keys/config +++ /dev/null @@ -1,3 +0,0 @@ -Host * - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null diff --git a/tests/ssh/base.py b/tests/ssh/base.py index 4825227f..4b91add4 100644 --- a/tests/ssh/base.py +++ b/tests/ssh/base.py @@ -2,6 +2,8 @@ import os import shutil import unittest +import pytest + import docker from .. import helpers from docker.utils import kwargs_from_env @@ -68,6 +70,8 @@ class BaseIntegrationTest(unittest.TestCase): client.close() +@pytest.mark.skipif(not os.environ.get('DOCKER_HOST', '').startswith('ssh://'), + reason='DOCKER_HOST is not an SSH target') class BaseAPIIntegrationTest(BaseIntegrationTest): """ A test case for `APIClient` integration tests. It sets up an `APIClient` diff --git a/tests/ssh-keys/id_rsa b/tests/ssh/config/client/id_rsa similarity index 100% rename from tests/ssh-keys/id_rsa rename to tests/ssh/config/client/id_rsa diff --git a/tests/ssh-keys/id_rsa.pub b/tests/ssh/config/client/id_rsa.pub similarity index 100% rename from tests/ssh-keys/id_rsa.pub rename to tests/ssh/config/client/id_rsa.pub diff --git a/tests/ssh/config/server/known_ed25519 b/tests/ssh/config/server/known_ed25519 new file mode 100644 index 00000000..b79f217b --- /dev/null +++ b/tests/ssh/config/server/known_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCGsfNXVP18N7XC6IQGuuxXQRbTxlPGLj+5/CByj9eg4QAAAJgIMffcCDH3 +3AAAAAtzc2gtZWQyNTUxOQAAACCGsfNXVP18N7XC6IQGuuxXQRbTxlPGLj+5/CByj9eg4Q +AAAEDeXnt5AuNk4oTHjMU1vUsEwh64fuEPu4hXsG6wCVt/6Iax81dU/Xw3tcLohAa67FdB +FtPGU8YuP7n8IHKP16DhAAAAEXJvb3RAMGRkZmQyMWRkYjM3AQIDBA== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/ssh/config/server/known_ed25519.pub b/tests/ssh/config/server/known_ed25519.pub new file mode 100644 index 00000000..ec0296e9 --- /dev/null +++ b/tests/ssh/config/server/known_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIax81dU/Xw3tcLohAa67FdBFtPGU8YuP7n8IHKP16Dh docker-py integration tests known diff --git a/tests/ssh/config/server/sshd_config b/tests/ssh/config/server/sshd_config new file mode 100644 index 00000000..970dca33 --- /dev/null +++ b/tests/ssh/config/server/sshd_config @@ -0,0 +1,3 @@ +IgnoreUserKnownHosts yes +PubkeyAuthentication yes +PermitRootLogin yes diff --git a/tests/ssh/config/server/unknown_ed25519 b/tests/ssh/config/server/unknown_ed25519 new file mode 100644 index 00000000..b79f217b --- /dev/null +++ b/tests/ssh/config/server/unknown_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCGsfNXVP18N7XC6IQGuuxXQRbTxlPGLj+5/CByj9eg4QAAAJgIMffcCDH3 +3AAAAAtzc2gtZWQyNTUxOQAAACCGsfNXVP18N7XC6IQGuuxXQRbTxlPGLj+5/CByj9eg4Q +AAAEDeXnt5AuNk4oTHjMU1vUsEwh64fuEPu4hXsG6wCVt/6Iax81dU/Xw3tcLohAa67FdB +FtPGU8YuP7n8IHKP16DhAAAAEXJvb3RAMGRkZmQyMWRkYjM3AQIDBA== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/ssh/config/server/unknown_ed25519.pub b/tests/ssh/config/server/unknown_ed25519.pub new file mode 100644 index 00000000..a24403ed --- /dev/null +++ b/tests/ssh/config/server/unknown_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIax81dU/Xw3tcLohAa67FdBFtPGU8YuP7n8IHKP16Dh docker-py integration tests unknown diff --git a/tests/ssh/connect_test.py b/tests/ssh/connect_test.py new file mode 100644 index 00000000..3d33a96d --- /dev/null +++ b/tests/ssh/connect_test.py @@ -0,0 +1,22 @@ +import os +import unittest + +import docker +import paramiko.ssh_exception +import pytest +from .base import TEST_API_VERSION + + +class SSHConnectionTest(unittest.TestCase): + @pytest.mark.skipif('UNKNOWN_DOCKER_SSH_HOST' not in os.environ, + reason='Unknown Docker SSH host not configured') + def test_ssh_unknown_host(self): + with self.assertRaises(paramiko.ssh_exception.SSHException) as cm: + docker.APIClient( + version=TEST_API_VERSION, + timeout=60, + # test only valid with Paramiko + use_ssh_client=False, + base_url=os.environ['UNKNOWN_DOCKER_SSH_HOST'], + ) + self.assertIn('not found in known_hosts', str(cm.exception))