Merge pull request #13999 from rabbitmq/mk-pass-in-tls-certificate-password-as-a-function

TLS listener startup: wrap private key password option into a function
This commit is contained in:
Michael Klishin 2025-06-02 16:32:48 +04:00 committed by GitHub
commit 034ef2c99c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 3 deletions

View File

@ -257,7 +257,7 @@ define ct_master.erl
halt(0)
endef
PARALLEL_CT_SET_1_A = unit_cluster_formation_locking_mocks unit_cluster_formation_sort_nodes unit_collections unit_config_value_encryption unit_connection_tracking
PARALLEL_CT_SET_1_A = unit_rabbit_ssl unit_cluster_formation_locking_mocks unit_cluster_formation_sort_nodes unit_collections unit_config_value_encryption unit_connection_tracking
PARALLEL_CT_SET_1_B = amqp_address amqp_auth amqp_credit_api_v2 amqp_filtex amqp_dotnet amqp_jms signal_handling single_active_consumer unit_access_control_authn_authz_context_propagation unit_access_control_credential_validation unit_amqp091_content_framing unit_amqp091_server_properties unit_app_management
PARALLEL_CT_SET_1_C = amqp_proxy_protocol amqpl_consumer_ack amqpl_direct_reply_to backing_queue bindings rabbit_db_maintenance rabbit_db_msup rabbit_db_policy rabbit_db_queue rabbit_db_topic_exchange rabbit_direct_reply_to_prop cluster_limit cluster_minority term_to_binary_compat_prop topic_permission transactions unicode unit_access_control
PARALLEL_CT_SET_1_D = amqqueue_backward_compatibility channel_interceptor channel_operation_timeout classic_queue classic_queue_prop config_schema peer_discovery_dns peer_discovery_tmp_hidden_node per_node_limit per_user_connection_channel_limit

View File

@ -49,7 +49,8 @@ load(Proplist) ->
URL = pget(url, Proplist),
rabbit_log:info("Applying definitions from a remote URL"),
rabbit_log:debug("HTTPS URL: ~ts", [URL]),
TLSOptions = tls_options_or_default(Proplist),
TLSOptions0 = tls_options_or_default(Proplist),
TLSOptions = rabbit_ssl:wrap_password_opt(TLSOptions0),
HTTPOptions = http_options(TLSOptions),
load_from_url(URL, HTTPOptions).

View File

@ -297,7 +297,8 @@ start_ssl_listener(Listener, SslOpts, NumAcceptors) ->
-spec start_ssl_listener(
listener_config(), rabbit_types:infos(), integer(), integer()) -> 'ok' | {'error', term()}.
start_ssl_listener(Listener, SslOpts, NumAcceptors, ConcurrentConnsSupsCount) ->
start_ssl_listener(Listener, SslOpts0, NumAcceptors, ConcurrentConnsSupsCount) ->
SslOpts = rabbit_ssl:wrap_password_opt(SslOpts0),
start_listener(Listener, NumAcceptors, ConcurrentConnsSupsCount, 'amqp/ssl',
"TLS (SSL) listener", tcp_opts() ++ SslOpts).

View File

@ -15,6 +15,7 @@
cipher_suites_openssl/2, cipher_suites_openssl/1,
cipher_suites/1]).
-export([info/2, cert_info/2]).
-export([wrap_password_opt/1]).
%%--------------------------------------------------------------------------
@ -34,6 +35,22 @@
-type certificate() :: rabbit_cert_info:certificate().
-type cipher_suites_mode() :: default | all | anonymous.
-type tls_opts() :: [ssl:tls_server_option()] | [ssl:tls_client_option()].
-spec wrap_password_opt(tls_opts()) -> tls_opts().
wrap_password_opt(Opts0) ->
case proplists:get_value(password, Opts0) of
undefined ->
Opts0;
Fun when is_function(Fun) ->
Opts0;
Password ->
%% A password can be a value or a function returning that value.
%% See the key_pem_password/0 type in https://github.com/erlang/otp/pull/5843/files.
NewOpts = proplists:delete(password, Opts0),
Fun = fun() -> Password end,
[{password, Fun} | NewOpts]
end.
-spec cipher_suites(cipher_suites_mode()) -> ssl:ciphers().
cipher_suites(Mode) ->

View File

@ -0,0 +1,66 @@
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
%%
-module(unit_rabbit_ssl_SUITE).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
all() ->
[
{group, parallel_tests}
].
groups() ->
[
{parallel_tests, [], [
wrap_tls_opts_with_binary_password,
wrap_tls_opts_with_function_password
]}
].
wrap_tls_opts_with_binary_password(_Config) ->
Path = "/tmp/path/to/private_key.pem",
Bin = <<"s3krE7">>,
Opts0 = [
{keyfile, Path},
{password, Bin}
],
Opts = rabbit_ssl:wrap_password_opt(Opts0),
M = maps:from_list(Opts),
?assertEqual(Path, maps:get(keyfile, M)),
?assert(is_function(maps:get(password, M))),
F = maps:get(password, M),
?assertEqual(Bin, F()),
passed.
wrap_tls_opts_with_function_password(_Config) ->
Path = "/tmp/path/to/private_key.pem",
Bin = <<"s3krE7">>,
Fun = fun() -> Bin end,
Opts0 = [
{keyfile, Path},
{password, Fun}
],
Opts = rabbit_ssl:wrap_password_opt(Opts0),
M = maps:from_list(Opts),
?assertEqual(Path, maps:get(keyfile, M)),
?assert(is_function(maps:get(password, M))),
?assertEqual(Fun, maps:get(password, M)),
F = maps:get(password, M),
?assertEqual(Bin, F()),
passed.