From 045410368dea196baa30e4ea6c7225ce12311b34 Mon Sep 17 00:00:00 2001 From: acidtib Date: Sat, 26 Apr 2025 01:03:15 -0600 Subject: [PATCH 1/4] add support for custom certificates --- lib/kamal/cli/app.rb | 1 + lib/kamal/cli/app/ssl_certificates.rb | 29 +++++++++++++++++ lib/kamal/commands/app/proxy.rb | 16 ++++++++++ lib/kamal/configuration.rb | 2 +- lib/kamal/configuration/accessory.rb | 3 +- lib/kamal/configuration/docs/proxy.yml | 12 ++++++- lib/kamal/configuration/proxy.rb | 33 +++++++++++++++++-- lib/kamal/configuration/proxy/boot.rb | 8 +++++ lib/kamal/configuration/role.rb | 5 +-- lib/kamal/configuration/validator/proxy.rb | 8 +++++ test/cli/app_test.rb | 16 ++++++++++ test/commands/app_test.rb | 8 +++-- test/configuration/proxy/boot_test.rb | 2 ++ test/configuration/proxy_test.rb | 37 ++++++++++++++++++++++ test/configuration_test.rb | 2 +- 15 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 lib/kamal/cli/app/ssl_certificates.rb diff --git a/lib/kamal/cli/app.rb b/lib/kamal/cli/app.rb index da2db238..22f88817 100644 --- a/lib/kamal/cli/app.rb +++ b/lib/kamal/cli/app.rb @@ -12,6 +12,7 @@ class Kamal::Cli::App < Kamal::Cli::Base KAMAL.roles_on(host).each do |role| Kamal::Cli::App::Assets.new(host, role, self).run + Kamal::Cli::App::SslCertificates.new(host, role, self).run end end diff --git a/lib/kamal/cli/app/ssl_certificates.rb b/lib/kamal/cli/app/ssl_certificates.rb new file mode 100644 index 00000000..5245c215 --- /dev/null +++ b/lib/kamal/cli/app/ssl_certificates.rb @@ -0,0 +1,29 @@ +class Kamal::Cli::App::SslCertificates + attr_reader :host, :role, :sshkit + delegate :execute, :info, to: :sshkit + + def initialize(host, role, sshkit) + @host = host + @role = role + @sshkit = sshkit + end + + def run + if role.running_proxy? && role.proxy.custom_ssl_certificate? + info "Writing SSL certificates for #{role.name} on #{host}" + execute *app.create_ssl_directory + if cert_content = role.proxy.certificate_pem_content + execute *app.write_certificate_file(cert_content) + end + if key_content = role.proxy.private_key_pem_content + execute *app.write_private_key_file(key_content) + end + execute *app.set_certificate_permissions + end + end + + private + def app + @app ||= KAMAL.app(role: role, host: host) + end +end diff --git a/lib/kamal/commands/app/proxy.rb b/lib/kamal/commands/app/proxy.rb index 6d015a0b..099e9e6c 100644 --- a/lib/kamal/commands/app/proxy.rb +++ b/lib/kamal/commands/app/proxy.rb @@ -21,6 +21,22 @@ module Kamal::Commands::App::Proxy remove_directory config.proxy_boot.app_directory end + def create_ssl_directory + make_directory(config.proxy_boot.tls_directory) + end + + def write_certificate_file(content) + [ :sh, "-c", Kamal::Utils.sensitive("cat > #{config.proxy_boot.tls_directory}/cert.pem << 'KAMAL_CERT_EOF'\n#{content}\nKAMAL_CERT_EOF", redaction: "cat > #{config.proxy_boot.tls_directory}/cert.pem << 'KAMAL_CERT_EOF'\n[CERTIFICATE CONTENT REDACTED]\nKAMAL_CERT_EOF") ] + end + + def write_private_key_file(content) + [ :sh, "-c", Kamal::Utils.sensitive("cat > #{config.proxy_boot.tls_directory}/key.pem << 'KAMAL_KEY_EOF'\n#{content}\nKAMAL_KEY_EOF", redaction: "cat > #{config.proxy_boot.tls_directory}/key.pem << 'KAMAL_KEY_EOF'\n[PRIVATE KEY CONTENT REDACTED]\nKAMAL_KEY_EOF") ] + end + + def set_certificate_permissions + [ :docker, :exec, "--user", "root", proxy_container_name, "chown", "-R", "kamal-proxy:kamal-proxy", config.proxy_boot.tls_container_directory ] + end + private def proxy_exec(*command) docker :exec, proxy_container_name, "kamal-proxy", *command diff --git a/lib/kamal/configuration.rb b/lib/kamal/configuration.rb index 26450170..d057c89a 100644 --- a/lib/kamal/configuration.rb +++ b/lib/kamal/configuration.rb @@ -63,7 +63,7 @@ class Kamal::Configuration @env = Env.new(config: @raw_config.env || {}, secrets: secrets) @logging = Logging.new(logging_config: @raw_config.logging) - @proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {}) + @proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {}, secrets: secrets) @proxy_boot = Proxy::Boot.new(config: self) @ssh = Ssh.new(config: self) @sshkit = Sshkit.new(config: self) diff --git a/lib/kamal/configuration/accessory.rb b/lib/kamal/configuration/accessory.rb index 62979627..fd410ab1 100644 --- a/lib/kamal/configuration/accessory.rb +++ b/lib/kamal/configuration/accessory.rb @@ -125,7 +125,8 @@ class Kamal::Configuration::Accessory Kamal::Configuration::Proxy.new \ config: config, proxy_config: accessory_config["proxy"], - context: "accessories/#{name}/proxy" + context: "accessories/#{name}/proxy", + secrets: config.secrets end def initialize_registry diff --git a/lib/kamal/configuration/docs/proxy.yml b/lib/kamal/configuration/docs/proxy.yml index 49c11ac8..a564fdf2 100644 --- a/lib/kamal/configuration/docs/proxy.yml +++ b/lib/kamal/configuration/docs/proxy.yml @@ -16,7 +16,6 @@ # It is disabled by default on all other roles but can be enabled by setting # `proxy: true` or providing a proxy configuration. proxy: - # Hosts # # The hosts that will be used to serve the app. The proxy will only route requests @@ -52,6 +51,17 @@ proxy: # Defaults to `false`: ssl: true + # Custom SSL certificate + # + # In scenarios where Let's Encrypt is not an option, or you already have your own + # certificates from a different Certificate Authority, you can configure kamal-proxy + # to load the certificate and the corresponding private key from disk. + # + # A reference to a secret (in this case, `CERTIFICATE_PEM` and `PRIVATE_KEY_PEM`) will look up the secret + # in the local environment: + certificate_pem: CERTIFICATE_PEM + private_key_pem: PRIVATE_KEY_PEM + # SSL redirect # # By default, kamal-proxy will redirect all HTTP requests to HTTPS when SSL is enabled. diff --git a/lib/kamal/configuration/proxy.rb b/lib/kamal/configuration/proxy.rb index b5afbaae..76baefc7 100644 --- a/lib/kamal/configuration/proxy.rb +++ b/lib/kamal/configuration/proxy.rb @@ -6,11 +6,12 @@ class Kamal::Configuration::Proxy delegate :argumentize, :optionize, to: Kamal::Utils - attr_reader :config, :proxy_config + attr_reader :config, :proxy_config, :secrets - def initialize(config:, proxy_config:, context: "proxy") + def initialize(config:, proxy_config:, secrets:, context: "proxy") @config = config @proxy_config = proxy_config + @secrets = secrets validate! @proxy_config, with: Kamal::Configuration::Validator::Proxy, context: context end @@ -26,10 +27,36 @@ class Kamal::Configuration::Proxy proxy_config["hosts"] || proxy_config["host"]&.split(",") || [] end + def custom_ssl_certificate? + proxy_config["certificate_pem"].present? && proxy_config["private_key_pem"].present? + end + + def certificate_pem_content + secrets[proxy_config["certificate_pem"]] + end + + def private_key_pem_content + secrets[proxy_config["private_key_pem"]] + end + + def certificate_pem + tls_file_path("cert.pem") + end + + def private_key_pem + tls_file_path("key.pem") + end + + def tls_file_path(filename) + File.join(config.proxy_boot.tls_container_directory, filename) if custom_ssl_certificate? + end + def deploy_options { host: hosts, tls: proxy_config["ssl"].presence, + "tls-certificate-path": certificate_pem, + "tls-private-key-path": private_key_pem, "deploy-timeout": seconds_duration(config.deploy_timeout), "drain-timeout": seconds_duration(config.drain_timeout), "health-check-interval": seconds_duration(proxy_config.dig("healthcheck", "interval")), @@ -65,7 +92,7 @@ class Kamal::Configuration::Proxy end def merge(other) - self.class.new config: config, proxy_config: proxy_config.deep_merge(other.proxy_config) + self.class.new config: config, proxy_config: proxy_config.deep_merge(other.proxy_config), secrets: secrets end private diff --git a/lib/kamal/configuration/proxy/boot.rb b/lib/kamal/configuration/proxy/boot.rb index 668c0cea..a4f4e83c 100644 --- a/lib/kamal/configuration/proxy/boot.rb +++ b/lib/kamal/configuration/proxy/boot.rb @@ -96,6 +96,14 @@ class Kamal::Configuration::Proxy::Boot File.join app_container_directory, "error_pages" end + def tls_directory + File.join app_directory, "tls" + end + + def tls_container_directory + File.join app_container_directory, "tls" + end + private def ensure_valid_bind_ips(bind_ips) bind_ips.present? && bind_ips.each do |ip| diff --git a/lib/kamal/configuration/role.rb b/lib/kamal/configuration/role.rb index c6bd8783..4fcc9913 100644 --- a/lib/kamal/configuration/role.rb +++ b/lib/kamal/configuration/role.rb @@ -150,8 +150,8 @@ class Kamal::Configuration::Role end def ensure_one_host_for_ssl - if running_proxy? && proxy.ssl? && hosts.size > 1 - raise Kamal::ConfigurationError, "SSL is only supported on a single server, found #{hosts.size} servers for role #{name}" + if running_proxy? && proxy.ssl? && hosts.size > 1 && !proxy.custom_ssl_certificate? + raise Kamal::ConfigurationError, "SSL is only supported on a single server unless you provide custom certificates, found #{hosts.size} servers for role #{name}" end end @@ -173,6 +173,7 @@ class Kamal::Configuration::Role @specialized_proxy = Kamal::Configuration::Proxy.new \ config: config, proxy_config: proxy_config, + secrets: config.secrets, context: "servers/#{name}/proxy" end end diff --git a/lib/kamal/configuration/validator/proxy.rb b/lib/kamal/configuration/validator/proxy.rb index b9e11cd9..1a938bc4 100644 --- a/lib/kamal/configuration/validator/proxy.rb +++ b/lib/kamal/configuration/validator/proxy.rb @@ -10,6 +10,14 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator if (config.keys & [ "host", "hosts" ]).size > 1 error "Specify one of 'host' or 'hosts', not both" end + + if config["certificate_pem"].present? && config["private_key_pem"].blank? + error "Missing private_key_pem setting (required when certificate_pem is present)" + end + + if config["private_key_pem"].present? && config["certificate_pem"].blank? + error "Missing certificate_pem setting (required when private_key_pem is present)" + end end end end diff --git a/test/cli/app_test.rb b/test/cli/app_test.rb index 94742d34..ebdb55e8 100644 --- a/test/cli/app_test.rb +++ b/test/cli/app_test.rb @@ -220,6 +220,22 @@ class CliAppTest < CliTestCase end end + test "boot with custom ssl certificate" do + Kamal::Configuration::Proxy.any_instance.stubs(:custom_ssl_certificate?).returns(true) + Kamal::Configuration::Proxy.any_instance.stubs(:certificate_pem_content).returns("CERTIFICATE CONTENT") + Kamal::Configuration::Proxy.any_instance.stubs(:private_key_pem_content).returns("PRIVATE KEY CONTENT") + + stub_running + run_command("boot", config: :with_proxy).tap do |output| + assert_match "Writing SSL certificates for web on 1.1.1.1", output + assert_match "mkdir -p .kamal/proxy/apps-config/app/tls", output + assert_match "sh -c [REDACTED]", output + assert_match "docker exec --user root kamal-proxy chown -R kamal-proxy:kamal-proxy", output + assert_match "--tls-certificate-path=\"/home/kamal-proxy/.apps-config/app/tls/cert.pem\"", output + assert_match "--tls-private-key-path=\"/home/kamal-proxy/.apps-config/app/tls/key.pem\"", output + end + end + test "start" do SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("999") # old version diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 33418a00..71422447 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -143,14 +143,18 @@ class CommandsAppTest < ActiveSupport::TestCase new_command.deploy(target: "172.1.0.2").join(" ") end + test "set certificate permissions" do + assert_equal \ + "docker exec --user root kamal-proxy chown -R kamal-proxy:kamal-proxy /home/kamal-proxy/.apps-config/app/tls", + new_command.set_certificate_permissions.join(" ") + end + test "remove" do assert_equal \ "docker exec kamal-proxy kamal-proxy remove app-web", new_command.remove.join(" ") end - - test "logs" do assert_equal \ "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1", diff --git a/test/configuration/proxy/boot_test.rb b/test/configuration/proxy/boot_test.rb index 90dee1b7..8028cddf 100644 --- a/test/configuration/proxy/boot_test.rb +++ b/test/configuration/proxy/boot_test.rb @@ -25,5 +25,7 @@ class ConfigurationProxyBootTest < ActiveSupport::TestCase assert_equal "/home/kamal-proxy/.apps-config/app", @proxy_boot_config.app_container_directory assert_equal ".kamal/proxy/apps-config/app/error_pages", @proxy_boot_config.error_pages_directory assert_equal "/home/kamal-proxy/.apps-config/app/error_pages", @proxy_boot_config.error_pages_container_directory + assert_equal ".kamal/proxy/apps-config/app/tls", @proxy_boot_config.tls_directory + assert_equal "/home/kamal-proxy/.apps-config/app/tls", @proxy_boot_config.tls_container_directory end end diff --git a/test/configuration/proxy_test.rb b/test/configuration/proxy_test.rb index 460d30cb..f225181d 100644 --- a/test/configuration/proxy_test.rb +++ b/test/configuration/proxy_test.rb @@ -45,6 +45,43 @@ class ConfigurationProxyTest < ActiveSupport::TestCase end end + test "ssl with certificate and private key from secrets" do + with_test_secrets("secrets" => "CERT_PEM=certificate\nKEY_PEM=private_key") do + @deploy[:proxy] = { + "ssl" => true, + "host" => "example.com", + "certificate_pem" => "CERT_PEM", + "private_key_pem" => "KEY_PEM" + } + + proxy = config.proxy + assert_equal "/home/kamal-proxy/.apps-config/app/tls/cert.pem", proxy.certificate_pem + assert_equal "/home/kamal-proxy/.apps-config/app/tls/key.pem", proxy.private_key_pem + end + end + + test "ssl with certificate and no private key" do + with_test_secrets("secrets" => "CERT_PEM=certificate") do + @deploy[:proxy] = { + "ssl" => true, + "host" => "example.com", + "certificate_pem" => "CERT_PEM" + } + assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? } + end + end + + test "ssl with private key and no certificate" do + with_test_secrets("secrets" => "KEY_PEM=private_key") do + @deploy[:proxy] = { + "ssl" => true, + "host" => "example.com", + "private_key_pem" => "KEY_PEM" + } + assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? } + end + end + private def config Kamal::Configuration.new(@deploy) diff --git a/test/configuration_test.rb b/test/configuration_test.rb index 73756c88..7f631e27 100644 --- a/test/configuration_test.rb +++ b/test/configuration_test.rb @@ -386,7 +386,7 @@ class ConfigurationTest < ActiveSupport::TestCase Kamal::Configuration.new(@deploy_with_roles) end - assert_equal "SSL is only supported on a single server, found 2 servers for role workers", exception.message + assert_equal "SSL is only supported on a single server unless you provide custom certificates, found 2 servers for role workers", exception.message end test "two proxy ssl roles with same host" do From a525d45b4ddab04d5275b230c3a43b05159469b7 Mon Sep 17 00:00:00 2001 From: acidtib Date: Mon, 28 Apr 2025 00:34:24 -0600 Subject: [PATCH 2/4] allow defining certificates directly within `ssl` hash instead of at the proxy root level --- lib/kamal/configuration/docs/proxy.yml | 11 ++++-- lib/kamal/configuration/proxy.rb | 14 +++++--- lib/kamal/configuration/validator.rb | 4 ++- lib/kamal/configuration/validator/proxy.rb | 12 ++++--- test/configuration/proxy_test.rb | 41 ++++++++++++++++------ 5 files changed, 59 insertions(+), 23 deletions(-) diff --git a/lib/kamal/configuration/docs/proxy.yml b/lib/kamal/configuration/docs/proxy.yml index a564fdf2..c79e6299 100644 --- a/lib/kamal/configuration/docs/proxy.yml +++ b/lib/kamal/configuration/docs/proxy.yml @@ -49,7 +49,7 @@ proxy: # unless you explicitly set `forward_headers: true` # # Defaults to `false`: - ssl: true + ssl: ... # Custom SSL certificate # @@ -59,8 +59,13 @@ proxy: # # A reference to a secret (in this case, `CERTIFICATE_PEM` and `PRIVATE_KEY_PEM`) will look up the secret # in the local environment: - certificate_pem: CERTIFICATE_PEM - private_key_pem: PRIVATE_KEY_PEM + # + # Examples: + # ssl: true # Enable SSL with Let's Encrypt + # ssl: false # Disable SSL + # ssl: # Enable custom SSL + # certificate_pem: CERTIFICATE_PEM + # private_key_pem: PRIVATE_KEY_PEM # SSL redirect # diff --git a/lib/kamal/configuration/proxy.rb b/lib/kamal/configuration/proxy.rb index 76baefc7..0f24fbe5 100644 --- a/lib/kamal/configuration/proxy.rb +++ b/lib/kamal/configuration/proxy.rb @@ -28,15 +28,21 @@ class Kamal::Configuration::Proxy end def custom_ssl_certificate? - proxy_config["certificate_pem"].present? && proxy_config["private_key_pem"].present? + ssl = proxy_config["ssl"] + return false unless ssl.is_a?(Hash) + ssl["certificate_pem"].present? && ssl["private_key_pem"].present? end def certificate_pem_content - secrets[proxy_config["certificate_pem"]] + ssl = proxy_config["ssl"] + return nil unless ssl.is_a?(Hash) + secrets[ssl["certificate_pem"]] end def private_key_pem_content - secrets[proxy_config["private_key_pem"]] + ssl = proxy_config["ssl"] + return nil unless ssl.is_a?(Hash) + secrets[ssl["private_key_pem"]] end def certificate_pem @@ -54,7 +60,7 @@ class Kamal::Configuration::Proxy def deploy_options { host: hosts, - tls: proxy_config["ssl"].presence, + tls: ssl? ? true : nil, "tls-certificate-path": certificate_pem, "tls-private-key-path": private_key_pem, "deploy-timeout": seconds_duration(config.deploy_timeout), diff --git a/lib/kamal/configuration/validator.rb b/lib/kamal/configuration/validator.rb index e67a4579..f658f5f4 100644 --- a/lib/kamal/configuration/validator.rb +++ b/lib/kamal/configuration/validator.rb @@ -24,7 +24,9 @@ class Kamal::Configuration::Validator example_value = example[key] if example_value == "..." - unless key.to_s == "proxy" && boolean?(value.class) + if key.to_s == "ssl" + validate_type! value, TrueClass, FalseClass, Hash + elsif key.to_s != "proxy" || !boolean?(value.class) validate_type! value, *(Array if key == :servers), Hash end elsif key == "hosts" diff --git a/lib/kamal/configuration/validator/proxy.rb b/lib/kamal/configuration/validator/proxy.rb index 1a938bc4..ab254d87 100644 --- a/lib/kamal/configuration/validator/proxy.rb +++ b/lib/kamal/configuration/validator/proxy.rb @@ -11,12 +11,14 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator error "Specify one of 'host' or 'hosts', not both" end - if config["certificate_pem"].present? && config["private_key_pem"].blank? - error "Missing private_key_pem setting (required when certificate_pem is present)" - end + if config["ssl"].is_a?(Hash) + if config["ssl"]["certificate_pem"].present? && config["ssl"]["private_key_pem"].blank? + error "Missing private_key_pem setting (required when certificate_pem is present)" + end - if config["private_key_pem"].present? && config["certificate_pem"].blank? - error "Missing certificate_pem setting (required when private_key_pem is present)" + if config["ssl"]["private_key_pem"].present? && config["ssl"]["certificate_pem"].blank? + error "Missing certificate_pem setting (required when private_key_pem is present)" + end end end end diff --git a/test/configuration/proxy_test.rb b/test/configuration/proxy_test.rb index f225181d..143fffc1 100644 --- a/test/configuration/proxy_test.rb +++ b/test/configuration/proxy_test.rb @@ -48,10 +48,11 @@ class ConfigurationProxyTest < ActiveSupport::TestCase test "ssl with certificate and private key from secrets" do with_test_secrets("secrets" => "CERT_PEM=certificate\nKEY_PEM=private_key") do @deploy[:proxy] = { - "ssl" => true, - "host" => "example.com", - "certificate_pem" => "CERT_PEM", - "private_key_pem" => "KEY_PEM" + "ssl" => { + "certificate_pem" => "CERT_PEM", + "private_key_pem" => "KEY_PEM" + }, + "host" => "example.com" } proxy = config.proxy @@ -60,12 +61,31 @@ class ConfigurationProxyTest < ActiveSupport::TestCase end end + test "deploy options with custom ssl certificates" do + with_test_secrets("secrets" => "CERT_PEM=certificate\nKEY_PEM=private_key") do + @deploy[:proxy] = { + "ssl" => { + "certificate_pem" => "CERT_PEM", + "private_key_pem" => "KEY_PEM" + }, + "host" => "example.com" + } + + proxy = config.proxy + options = proxy.deploy_options + assert_equal true, options[:tls] + assert_equal "/home/kamal-proxy/.apps-config/app/tls/cert.pem", options[:"tls-certificate-path"] + assert_equal "/home/kamal-proxy/.apps-config/app/tls/key.pem", options[:"tls-private-key-path"] + end + end + test "ssl with certificate and no private key" do with_test_secrets("secrets" => "CERT_PEM=certificate") do @deploy[:proxy] = { - "ssl" => true, - "host" => "example.com", - "certificate_pem" => "CERT_PEM" + "ssl" => { + "certificate_pem" => "CERT_PEM" + }, + "host" => "example.com" } assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? } end @@ -74,9 +94,10 @@ class ConfigurationProxyTest < ActiveSupport::TestCase test "ssl with private key and no certificate" do with_test_secrets("secrets" => "KEY_PEM=private_key") do @deploy[:proxy] = { - "ssl" => true, - "host" => "example.com", - "private_key_pem" => "KEY_PEM" + "ssl" => { + "private_key_pem" => "KEY_PEM" + }, + "host" => "example.com" } assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? } end From 1f847299c0b875d816f396dffc2cc636b16ab110 Mon Sep 17 00:00:00 2001 From: acidtib Date: Mon, 28 Apr 2025 13:33:03 -0600 Subject: [PATCH 3/4] improve custom SSL certificate documentation --- lib/kamal/configuration/docs/proxy.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/kamal/configuration/docs/proxy.yml b/lib/kamal/configuration/docs/proxy.yml index c79e6299..5f63c6ff 100644 --- a/lib/kamal/configuration/docs/proxy.yml +++ b/lib/kamal/configuration/docs/proxy.yml @@ -53,12 +53,10 @@ proxy: # Custom SSL certificate # - # In scenarios where Let's Encrypt is not an option, or you already have your own - # certificates from a different Certificate Authority, you can configure kamal-proxy - # to load the certificate and the corresponding private key from disk. - # - # A reference to a secret (in this case, `CERTIFICATE_PEM` and `PRIVATE_KEY_PEM`) will look up the secret - # in the local environment: + # In some cases, using Let's Encrypt for automatic certificate management is not an + # option, or you may already have SSL certificates issued by a different + # Certificate Authority (CA). Kamal supports loading custom SSL certificates + # directly from secrets. # # Examples: # ssl: true # Enable SSL with Let's Encrypt From 9219b87630b861ac4fb25ac452ea3770adb74795 Mon Sep 17 00:00:00 2001 From: acidtib Date: Tue, 29 Apr 2025 19:57:41 -0600 Subject: [PATCH 4/4] remove chown for TLS certificates in proxy container --- lib/kamal/cli/app/ssl_certificates.rb | 1 - lib/kamal/commands/app/proxy.rb | 4 ---- test/cli/app_test.rb | 1 - test/commands/app_test.rb | 6 ------ 4 files changed, 12 deletions(-) diff --git a/lib/kamal/cli/app/ssl_certificates.rb b/lib/kamal/cli/app/ssl_certificates.rb index 5245c215..22ac5095 100644 --- a/lib/kamal/cli/app/ssl_certificates.rb +++ b/lib/kamal/cli/app/ssl_certificates.rb @@ -18,7 +18,6 @@ class Kamal::Cli::App::SslCertificates if key_content = role.proxy.private_key_pem_content execute *app.write_private_key_file(key_content) end - execute *app.set_certificate_permissions end end diff --git a/lib/kamal/commands/app/proxy.rb b/lib/kamal/commands/app/proxy.rb index 099e9e6c..a23cc4ce 100644 --- a/lib/kamal/commands/app/proxy.rb +++ b/lib/kamal/commands/app/proxy.rb @@ -33,10 +33,6 @@ module Kamal::Commands::App::Proxy [ :sh, "-c", Kamal::Utils.sensitive("cat > #{config.proxy_boot.tls_directory}/key.pem << 'KAMAL_KEY_EOF'\n#{content}\nKAMAL_KEY_EOF", redaction: "cat > #{config.proxy_boot.tls_directory}/key.pem << 'KAMAL_KEY_EOF'\n[PRIVATE KEY CONTENT REDACTED]\nKAMAL_KEY_EOF") ] end - def set_certificate_permissions - [ :docker, :exec, "--user", "root", proxy_container_name, "chown", "-R", "kamal-proxy:kamal-proxy", config.proxy_boot.tls_container_directory ] - end - private def proxy_exec(*command) docker :exec, proxy_container_name, "kamal-proxy", *command diff --git a/test/cli/app_test.rb b/test/cli/app_test.rb index ebdb55e8..afa54844 100644 --- a/test/cli/app_test.rb +++ b/test/cli/app_test.rb @@ -230,7 +230,6 @@ class CliAppTest < CliTestCase assert_match "Writing SSL certificates for web on 1.1.1.1", output assert_match "mkdir -p .kamal/proxy/apps-config/app/tls", output assert_match "sh -c [REDACTED]", output - assert_match "docker exec --user root kamal-proxy chown -R kamal-proxy:kamal-proxy", output assert_match "--tls-certificate-path=\"/home/kamal-proxy/.apps-config/app/tls/cert.pem\"", output assert_match "--tls-private-key-path=\"/home/kamal-proxy/.apps-config/app/tls/key.pem\"", output end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 71422447..76f17676 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -143,12 +143,6 @@ class CommandsAppTest < ActiveSupport::TestCase new_command.deploy(target: "172.1.0.2").join(" ") end - test "set certificate permissions" do - assert_equal \ - "docker exec --user root kamal-proxy chown -R kamal-proxy:kamal-proxy /home/kamal-proxy/.apps-config/app/tls", - new_command.set_certificate_permissions.join(" ") - end - test "remove" do assert_equal \ "docker exec kamal-proxy kamal-proxy remove app-web",