Module: Kamal::Commands::Proxy::CertTransfer

Included in:
Loadbalancer, Kamal::Commands::Proxy
Defined in:
lib/kamal/commands/proxy/cert_transfer.rb

Overview

Certificate store transfer, shared by the proxy and loadbalancer command builders (kamal proxy export_certs / import_certs).

Archives leave through the apps-config bind mount — the one container path that is also a host path — and arrive through stdin into a one-off container: a bind-mounted source would need host permissions the container user cannot be guaranteed to have, and the store must be written as the image's own user or the proxy cannot read it afterwards.

The including class provides container_name, cert_store_volume_args (the config volume mount) and one_off_image (the image tokens for a one-off container).

Constant Summary collapse

CERT_ARCHIVE_FILENAME =
"certs-export.tar.gz"
CERT_IMPORT_STAGING_FILENAME =
"certs-import"
CONTAINER_IMPORT_PATH =
"/tmp/kamal-cert-import"

Instance Method Summary collapse

Instance Method Details

#certs_archive_container_pathObject



59
60
61
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 59

def certs_archive_container_path
  File.join config.proxy_boot.apps_container_directory, CERT_ARCHIVE_FILENAME
end

#certs_archive_host_pathObject



55
56
57
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 55

def certs_archive_host_path
  File.join config.proxy_boot.apps_directory, CERT_ARCHIVE_FILENAME
end

#certs_import_host_pathObject



63
64
65
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 63

def certs_import_host_path
  File.join config.proxy_boot.host_directory, CERT_IMPORT_STAGING_FILENAME
end

#export_certsObject

Through the RPC socket of the running container, under the proxy's own certificate write lock, so a backup taken mid-renewal is never torn.



20
21
22
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 20

def export_certs
  docker :exec, container_name, "kamal-proxy", :export, :certs, certs_archive_container_path
end

#export_certs_offlineObject

Reads the data directory offline over the config volume — only safe when the container is stopped, which Kamal::Cli::Proxy guarantees.



26
27
28
29
30
31
32
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 26

def export_certs_offline
  docker :run, "--rm",
    *cert_store_volume_args,
    *config.proxy_boot.apps_volume.docker_args,
    *one_off_image,
    "kamal-proxy", :export, :certs, certs_archive_container_path
end

#import_certs(traefik_acme: false, resolver: nil, force: false, verify: false) ⇒ Object

Offline by design (kamal-proxy import has no RPC path): the one-off container mounts the config volume — creating it when no proxy has booted yet, which is the Traefik-migration case — and the staged source streams through stdin.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 38

def import_certs(traefik_acme: false, resolver: nil, force: false, verify: false)
  source_flag = traefik_acme ? "traefik-acme" : "archive"
  # Base#shell single-quotes the payload and escapes embedded apostrophes -
  # without that, an apostrophe in a resolver name would end the quoting and
  # run whatever follows on the target host.
  import_command = shell [
    "cat > #{CONTAINER_IMPORT_PATH} &&",
    "kamal-proxy import certs",
    *optionize({ source_flag => CONTAINER_IMPORT_PATH, resolver: resolver, force: force || nil, verify: verify || nil }.compact, with: "=")
  ]

  [
    *docker(:run, "--rm", "--interactive", *cert_store_volume_args, *one_off_image, *import_command),
    "<", certs_import_host_path
  ]
end

#remove_certs_archiveObject



67
68
69
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 67

def remove_certs_archive
  remove_file certs_archive_host_path
end

#remove_certs_importObject



71
72
73
# File 'lib/kamal/commands/proxy/cert_transfer.rb', line 71

def remove_certs_import
  remove_file certs_import_host_path
end