Skip to content

Commit

Permalink
Add validations for host/ssl roles
Browse files Browse the repository at this point in the history
Roles with SSL can only have one server.
Two roles with SSL can't use the same host.
  • Loading branch information
djmb committed Sep 18, 2024
1 parent fd0cdc1 commit 63f854e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 3 deletions.
16 changes: 16 additions & 0 deletions lib/kamal/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def initialize(raw_config, destination: nil, version: nil, validate: true)
ensure_retain_containers_valid
ensure_valid_service_name
ensure_no_traefik_reboot_hooks
ensure_one_host_for_ssl_roles
ensure_unique_hosts_for_ssl_roles
end


Expand Down Expand Up @@ -349,6 +351,20 @@ def ensure_no_traefik_reboot_hooks
true
end

def ensure_one_host_for_ssl_roles
roles.each(&:ensure_one_host_for_ssl)

true
end

def ensure_unique_hosts_for_ssl_roles
hosts = roles.select(&:ssl?).map { |role| role.proxy.host }
duplicates = hosts.tally.filter_map { |host, count| host if count > 1 }

raise Kamal::ConfigurationError, "Different roles can't share the same host for SSL: #{duplicates.join(", ")}" if duplicates.any?

true
end

def role_names
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
Expand Down
4 changes: 4 additions & 0 deletions lib/kamal/configuration/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def ssl?
proxy_config.fetch("ssl", false)
end

def host
proxy_config["host"]
end

def deploy_options
{
host: proxy_config["host"],
Expand Down
10 changes: 10 additions & 0 deletions lib/kamal/configuration/role.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ def running_proxy?
@running_proxy
end

def ssl?
running_proxy? && proxy.ssl?
end

def stop_args
# When deploying with the proxy, kamal-proxy will drain request before returning so we don't need to wait.
timeout = running_proxy? ? nil : config.drain_timeout
Expand Down Expand Up @@ -145,6 +149,12 @@ def asset_volume_directory(version = config.version)
File.join config.assets_directory, "volumes", [ name, version ].join("-")
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}"
end
end

private
def initialize_specialized_proxy
proxy_specializations = specializations["proxy"]
Expand Down
31 changes: 31 additions & 0 deletions test/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,35 @@ class ConfigurationTest < ActiveSupport::TestCase
end
end
end

test "proxy ssl roles with no host" do
@deploy_with_roles[:servers]["workers"]["proxy"] = { "ssl" => true }

exception = assert_raises(Kamal::ConfigurationError) do
Kamal::Configuration.new(@deploy_with_roles)
end

assert_equal "servers/workers/proxy: Must set a host to enable automatic SSL", exception.message
end

test "proxy ssl roles with multiple servers" do
@deploy_with_roles[:servers]["workers"]["proxy"] = { "ssl" => true, "host" => "foo.example.com" }

exception = assert_raises(Kamal::ConfigurationError) do
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
end

test "two proxy ssl roles with same host" do
@deploy_with_roles[:servers]["web"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "host" => "foo.example.com" } }
@deploy_with_roles[:servers]["workers"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "host" => "foo.example.com" } }

exception = assert_raises(Kamal::ConfigurationError) do
Kamal::Configuration.new(@deploy_with_roles)
end

assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
end
end
2 changes: 1 addition & 1 deletion test/integration/main_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class MainTest < IntegrationTest
assert_match /Proxy Host: vm2/, details
assert_match /App Host: vm1/, details
assert_match /App Host: vm2/, details
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION}/, details
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}/, details
assert_match /registry:4443\/app:#{first_version}/, details

audit = kamal :audit, capture: true
Expand Down
4 changes: 2 additions & 2 deletions test/integration/proxy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ class ProxyTest < IntegrationTest

private
def assert_proxy_running
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
end

def assert_proxy_not_running
assert_no_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
assert_no_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
end

def proxy_details
Expand Down

0 comments on commit 63f854e

Please sign in to comment.