Files
ubicloud/rhizome/host/lib/cert_server_setup.rb
Benjamin Satzger af0d3ed67b Fix race with cert server leaving vm stuck in prep
When creating a VM attached to a load balancer, cert server puts a
certificate into the folder /vm/inhost_name/cert by executing
`sudo host/bin/setup-cert-server put-certificate inhost_name`

During that call, before writing the certs, it first creates the cert
folder using `mkdir_p` (as the root user). If  /vm/inhost_name
didn't exist yet at that point, the folder /vm/inhost_name was
created like this:

```
ll inhost_name
total 12
drwxr-xr-x 3 root root 4096 May  9 12:52 ./
drwxr-xr-x 7 root root 4096 May  9 12:52 ../
drwxr-xr-x 2 root root 4096 May  9 12:52 cert/
```

This is what subsequently happens to VM provisioning in that case:

* create_unix_user: succeeds but gives this warning
```
adduser: Warning: The home directory `/vm/inhost_name'
does not belong to the user you are currently creating.
```

* prep: Fails with `tee: /vm/inhost_name/prep.json: Permission denied`

As a fix, we use `mkdir` instead of `mkdir_p` and just ignore the
error indicating that the folder already exists. That way, it won't
create the /vm/inhost_name folder. Putting the certificate should
succeed after `create_unix_user` has created /vm/inhost_name.
2025-05-12 09:01:21 +02:00

146 lines
3.0 KiB
Ruby

# frozen_string_literal: true
require_relative "../../common/lib/util"
require_relative "../../common/lib/arch"
require_relative "vm_path"
require "fileutils"
require "json"
class CertServerSetup
def initialize(vm_name)
@vm_name = vm_name
end
def vp
@vp ||= VmPath.new(@vm_name)
end
def cert_folder
vp.q_cert
end
def cert_path
"#{cert_folder}/cert.pem"
end
def key_path
"#{cert_folder}/key.pem"
end
def service_name
"#{@vm_name}-metadata-endpoint"
end
def service_file_path
"/etc/systemd/system/#{service_name}.service"
end
def server_version
"0.1.5"
end
def server_main_path
File.join("", "opt", "metadata-endpoint-#{server_version}")
end
def vm_server_path
File.join(cert_folder, "metadata-endpoint-#{server_version}")
end
def package_url
arch = Arch.render(x64: "x86_64", arm64: "arm64")
"https://github.com/ubicloud/metadata-endpoint/releases/download/v#{server_version}/metadata-endpoint_Linux_#{arch}.tar.gz"
end
def setup
copy_server
create_service
enable_and_start_service
end
def stop_and_remove
stop_and_remove_service
remove_paths
end
def copy_server
unless File.exist?(server_main_path)
download_server
end
r "cp #{server_main_path}/metadata-endpoint #{vm_server_path}"
r "sudo chown #{@vm_name}:#{@vm_name} #{vm_server_path}"
end
def download_server
temp_tarball = "/tmp/metadata-endpoint-#{server_version}.tar.gz"
r "curl -L3 -o #{temp_tarball} #{package_url}"
FileUtils.mkdir_p(server_main_path)
FileUtils.cd server_main_path do
r "tar -xzf #{temp_tarball}"
end
FileUtils.rm_f(temp_tarball)
end
def create_service
service = "#{service_name}.service"
File.write("/etc/systemd/system/#{service}", <<CERT_SERVICE
[Unit]
Description=Certificate Server
After=network.target
[Service]
NetworkNamespacePath=/var/run/netns/#{@vm_name}
ExecStart=#{vm_server_path}
Restart=always
RestartSec=15
Type=simple
ProtectSystem=strict
PrivateDevices=yes
PrivateTmp=yes
ProtectHome=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
NoNewPrivileges=yes
ReadOnlyPaths=#{cert_path} #{key_path}
User=#{@vm_name}
Group=#{@vm_name}
Environment=VM_INHOST_NAME=#{@vm_name}
Environment=IPV6_ADDRESS="FD00:0B1C:100D:5AFE:CE::"
Environment=GOMEMLIMIT=9MiB
Environment=GOMAXPROCS=1
CPUQuota=50%
MemoryLimit=10M
CERT_SERVICE
)
r "systemctl daemon-reload"
end
def enable_and_start_service
r "systemctl enable --now #{service_name}"
end
def stop_and_remove_service
r "systemctl disable --now #{service_name}" if File.exist?(service_file_path)
r "systemctl daemon-reload"
FileUtils.rm_f(service_file_path)
end
def put_certificate(cert_payload, cert_key_payload)
begin
FileUtils.mkdir(cert_folder)
rescue Errno::EEXIST
end
safe_write_to_file(cert_path, cert_payload)
safe_write_to_file(key_path, cert_key_payload)
end
def remove_paths
FileUtils.rm_rf(cert_folder)
end
end