From a525d45b4ddab04d5275b230c3a43b05159469b7 Mon Sep 17 00:00:00 2001 From: acidtib Date: Mon, 28 Apr 2025 00:34:24 -0600 Subject: [PATCH] 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