From 2974a6c4b8019b7450a7e60458ab2bab2ab5053a Mon Sep 17 00:00:00 2001 From: Guillaume Bau Date: Tue, 6 May 2025 13:46:07 +0200 Subject: [PATCH 1/4] Tezt/Cloud/Ssh: allow root ssh connections Allow root ssh connections using key pairs Upload the generated key to the host --- tezt/lib_cloud/deployement.ml | 77 +++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/tezt/lib_cloud/deployement.ml b/tezt/lib_cloud/deployement.ml index 0ef9614317b9..78714b40dba4 100644 --- a/tezt/lib_cloud/deployement.ml +++ b/tezt/lib_cloud/deployement.ml @@ -302,6 +302,82 @@ end module Ssh_host = struct type t = {point : string * string * int; agents : Agent.t list} + (* This function allows to setup the prerequisites to run the deployment + of containers on a vm which can be connected to via ssh. + Multiple hosts are currently supported: + - a gcp debian vm + - a qemu vm + - a physical machine. + All that is required is that the host can be contacted either via root + account or a sudo enabled account. *) + let initial_host_provisionning user host port = + let runner = + Runner.create + ~ssh_user:user + ~ssh_port:port + ~address:host + ~ssh_id:(Env.ssh_private_key_filename ()) + () + in + let* () = + (* Allows direct connections as root on debian, using key authentication. + This is not unsecure (as key logging is secure) as long as users + logging in as root are careful. This allows to not be embarrassed with sudo *) + if user = "root" then Lwt.return_unit + else + let* _ = + Process.spawn + ~runner + "sudo" + [ + "sed"; + "-i"; + "s/PermitRootLogin no/PermitRootLogin prohibit-password/"; + "/etc/ssh/sshd_config"; + ] + |> Process.wait + in + with_open_in (Env.ssh_public_key_filename ()) @@ fun fd -> + let ssh_public_key_content = input_line fd in + let* () = + Process.spawn ~runner "sudo" ["mkdir"; "-p"; "/root/.ssh"] + |> Process.check + in + let* () = + Process.spawn + ~runner + "sh" + [ + "-c"; + Format.asprintf + "echo %s | sudo tee -a /root/.ssh/authorized_keys" + ssh_public_key_content; + ] + |> Process.check + in + Process.spawn ~runner "sudo" ["systemctl"; "restart"; "ssh.service"] + |> Process.check + in + (* Setup a new runner for root connections *) + let runner = + Runner.create + ~ssh_user:"root" + ~ssh_port:port + ~address:host + ~ssh_id:(Env.ssh_private_key_filename ()) + () + in + let user = "root" in + (* Upload the key to the host via ssh *) + let* () = + Process.run + "scp" + (["-i"; Env.ssh_private_key_filename (); iam_key_filename] + @ (if port <> 22 then ["-p"; string_of_int port] else []) + @ [Format.asprintf "%s@%s:%s" user host iam_key_filename]) + in + Lwt.return_unit + let deploy_proxy runner = let configuration = Proxy.make_config () in let next_available_port = @@ -357,6 +433,7 @@ module Ssh_host = struct let deploy ~user ~host ~port ~(configurations : Agent.Configuration.t list) () = + let* () = initial_host_provisionning user host port in let proxy_runner = Runner.create ~ssh_user:"root" ~ssh_port:port ~address:host () in -- GitLab From 1b295a7ff0fac4563184b8602d76437b94d8e673 Mon Sep 17 00:00:00 2001 From: Guillaume Bau Date: Tue, 6 May 2025 13:49:35 +0200 Subject: [PATCH 2/4] Tezt/Cloud/Ssh_host: add docker installation --- tezt/lib_cloud/deployement.ml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tezt/lib_cloud/deployement.ml b/tezt/lib_cloud/deployement.ml index 78714b40dba4..225045273723 100644 --- a/tezt/lib_cloud/deployement.ml +++ b/tezt/lib_cloud/deployement.ml @@ -368,6 +368,13 @@ module Ssh_host = struct () in let user = "root" in + (* Installs docker *) + Log.report "Installing docker" ; + let* () = Process.spawn ~runner "apt-get" ["update"] |> Process.check in + let* () = + Process.spawn ~runner "apt-get" ["install"; "-y"; "docker.io"; "libev4"] + |> Process.check + in (* Upload the key to the host via ssh *) let* () = Process.run -- GitLab From 0b553cde68cb3a593513235c70e37736875826a8 Mon Sep 17 00:00:00 2001 From: Guillaume Bau Date: Tue, 6 May 2025 13:50:30 +0200 Subject: [PATCH 3/4] Tezt/Cloud/Ssh: create an iam key to allow pull from gcp docker registry --- tezt/lib_cloud/deployement.ml | 96 +++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tezt/lib_cloud/deployement.ml b/tezt/lib_cloud/deployement.ml index 225045273723..9ae520583f09 100644 --- a/tezt/lib_cloud/deployement.ml +++ b/tezt/lib_cloud/deployement.ml @@ -375,6 +375,83 @@ module Ssh_host = struct Process.spawn ~runner "apt-get" ["install"; "-y"; "docker.io"; "libev4"] |> Process.check in + let* project = Env.project_id () in + (* Generate locally an access token to access to gcp docker registry *) + let* iam_key_filename = + let service_account_name = Format.asprintf "%s-id" Env.tezt_cloud in + let* service_account = + (* FIXME: service_account_fullname is strictly bound to dal team and should + be configured and stored in a tezt-cloud ~/.config directory. + Here, preserving backward compatibility with terraform naming *) + let service_account_fullname = + Format.asprintf "%s-id@nl-dal.iam.gserviceaccount.com" Env.tezt_cloud + in + (* Delete service account if exists. Do not fail if it does not *) + let* _ = + Process.spawn + "gcloud" + ["iam"; "service-accounts"; "delete"; service_account_fullname] + |> Process.wait + in + let* () = + Process.spawn + "gcloud" + [ + "iam"; + "service-accounts"; + "create"; + "--project"; + project; + service_account_name; + "--display-name"; + service_account_name; + ] + |> Process.check + in + Lwt.return service_account_fullname + in + Log.report "waiting for the iam account to become valid" ; + let* () = Lwt_unix.sleep 3.0 in + let iam_key_filename = "/tmp/iam-keys" in + let* () = + Process.spawn + "gcloud" + [ + "iam"; + "service-accounts"; + "keys"; + "create"; + iam_key_filename; + "--iam-account"; + service_account; + "--project"; + project; + ] + |> Process.check + in + Log.report "waiting for the iam key to become valid" ; + let* () = Lwt_unix.sleep 3.0 in + let* () = + Process.spawn + "gcloud" + [ + "artifacts"; + "repositories"; + "add-iam-policy-binding"; + Format.asprintf "%s-docker-registry" Env.tezt_cloud; + "--location"; + "europe-west1"; + "--member"; + Format.asprintf "serviceAccount:%s" service_account; + "--role"; + "roles/artifactregistry.reader"; + ] + |> Process.check + in + Log.report "waiting for the iam key binding to become valid" ; + let* () = Lwt_unix.sleep 3.0 in + Lwt.return iam_key_filename + in (* Upload the key to the host via ssh *) let* () = Process.run @@ -383,6 +460,25 @@ module Ssh_host = struct @ (if port <> 22 then ["-p"; string_of_int port] else []) @ [Format.asprintf "%s@%s:%s" user host iam_key_filename]) in + let* () = + let rec retry () = + let* status = + Process.spawn + ~runner + "sh" + [ + "-c"; + Format.asprintf + "cat %s | docker login -u _json_key --password-stdin \ + https://europe-west1-docker.pkg.dev" + iam_key_filename; + ] + |> Process.wait + in + match status with WEXITED 0 -> Lwt.return_unit | _ -> retry () + in + retry () + in Lwt.return_unit let deploy_proxy runner = -- GitLab From d8fbc02b2d382168379b6a00f3191e8f32789137 Mon Sep 17 00:00:00 2001 From: Guillaume Bau Date: Wed, 21 May 2025 17:08:46 +0200 Subject: [PATCH 4/4] Tezt/Cloud update readme for ssh-host support --- tezt/lib_cloud/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tezt/lib_cloud/README.md b/tezt/lib_cloud/README.md index 326609df3b6f..f5955a1cd978 100644 --- a/tezt/lib_cloud/README.md +++ b/tezt/lib_cloud/README.md @@ -441,3 +441,18 @@ You should see the name servers you just added. ControlPath ~/.ssh/master-%r@%h:%p ControlPersist 120 ``` + +# Deploying on non-gcp machines via ssh. + +You need ssh access to the machine, and the ssh-key to be loaded in your +ssh-agent. If the login used to connect to the machine is not 'root', +`tezt-cloud` will automatically enable 'root' connections by key pair. + +At this point, the machine is expected to be a debian. It does not need to be +provisionned, it will be provisionned automatically, by installing docker and +setting up docker repository access. + +The following command should deploy and start an experiment: +``` +dune exec tezt/tests/cloud/main.exe -- DAL -v --bootstrap --vms-limit 0 --ssh-host my.ssh.machine +``` -- GitLab