Introduce TLS-related rabbitmq.conf settings for definition import

currently only used by the HTTPS mechanism but can be used by
any other.
This commit is contained in:
Michael Klishin 2021-08-17 20:42:53 +03:00
parent f3a5235408
commit 6a0058fe7c
No known key found for this signature in database
GPG Key ID: E80EDCFA0CDB21EE
5 changed files with 207 additions and 6 deletions

View File

@ -159,9 +159,101 @@ end}.
{mapping, "definitions.https.url", "rabbit.definitions.url",
[{datatype, string}]}.
%% Client-side TLS settings used by e.g. HTTPS definition loading mechanism.
%% These can be reused by other clients.
{mapping, "definitions.tls.verify", "rabbit.definitions.ssl_options.verify", [
{datatype, {enum, [verify_peer, verify_none]}}]}.
{mapping, "definitions.tls.fail_if_no_peer_cert", "rabbit.definitions.ssl_options.fail_if_no_peer_cert", [
{datatype, {enum, [true, false]}}]}.
{mapping, "definitions.tls.cacertfile", "rabbit.definitions.ssl_options.cacertfile",
[{datatype, string}, {validators, ["file_accessible"]}]}.
{mapping, "definitions.tls.certfile", "rabbit.definitions.ssl_options.certfile",
[{datatype, string}, {validators, ["file_accessible"]}]}.
{mapping, "definitions.tls.cacerts.$name", "rabbit.definitions.ssl_options.cacerts",
[{datatype, string}]}.
{translation, "rabbit.definitions.ssl_options.cacerts",
fun(Conf) ->
Settings = cuttlefish_variable:filter_by_prefix("definitions.tls.cacerts", Conf),
[ list_to_binary(V) || {_, V} <- Settings ]
end}.
{mapping, "definitions.tls.cert", "rabbit.definitions.ssl_options.cert",
[{datatype, string}]}.
{translation, "rabbit.definitions.ssl_options.cert",
fun(Conf) ->
list_to_binary(cuttlefish:conf_get("definitions.tls.cert", Conf))
end}.
{mapping, "definitions.tls.reuse_session", "rabbit.definitions.ssl_options.reuse_session",
[{datatype, {enum, [true, false]}}]}.
{mapping, "definitions.tls.crl_check", "rabbit.definitions.ssl_options.crl_check",
[{datatype, [{enum, [true, false, peer, best_effort]}]}]}.
{mapping, "definitions.tls.depth", "rabbit.definitions.ssl_options.depth",
[{datatype, integer}, {validators, ["byte"]}]}.
{mapping, "definitions.tls.dh", "rabbit.definitions.ssl_options.dh",
[{datatype, string}]}.
{translation, "rabbit.definitions.ssl_options.dh",
fun(Conf) ->
list_to_binary(cuttlefish:conf_get("definitions.tls.dh", Conf))
end}.
{translation, "rabbit.definitions.ssl_options.key",
fun(Conf) ->
case cuttlefish_variable:filter_by_prefix("definitions.tls.key", Conf) of
[{[_,_,Key], Val}|_] -> {list_to_atom(Key), list_to_binary(Val)};
_ -> cuttlefish:unset()
end
end}.
{mapping, "definitions.tls.keyfile", "rabbit.definitions.ssl_options.keyfile",
[{datatype, string}, {validators, ["file_accessible"]}]}.
{mapping, "definitions.tls.log_alert", "rabbit.definitions.ssl_options.log_alert",
[{datatype, {enum, [true, false]}}]}.
{mapping, "definitions.tls.password", "rabbit.definitions.ssl_options.password",
[{datatype, string}]}.
{mapping, "definitions.tls.secure_renegotiate", "rabbit.definitions.ssl_options.secure_renegotiate",
[{datatype, {enum, [true, false]}}]}.
{mapping, "definitions.tls.reuse_sessions", "rabbit.definitions.ssl_options.reuse_sessions",
[{datatype, {enum, [true, false]}}]}.
{mapping, "definitions.tls.versions.$version", "rabbit.definitions.ssl_options.versions",
[{datatype, atom}]}.
{translation, "rabbit.definitions.ssl_options.versions",
fun(Conf) ->
Settings = cuttlefish_variable:filter_by_prefix("definitions.tls.versions", Conf),
[V || {_, V} <- Settings]
end}.
{mapping, "definitions.tls.ciphers.$cipher", "rabbit.definitions.ssl_options.ciphers",
[{datatype, string}]}.
{translation, "rabbit.definitions.ssl_options.ciphers",
fun(Conf) ->
Settings = cuttlefish_variable:filter_by_prefix("definitions.tls.ciphers", Conf),
lists:reverse([V || {_, V} <- Settings])
end}.
{mapping, "definitions.tls.log_level", "rabbit.definitions.ssl_options.log_level",
[{datatype, {enum, [emergency, alert, critical, error, warning, notice, info, debug]}}]}.
%%
%% Security / AAA
%% ==============
%% Seed User, Authentication, Access Control
%%
%% The default "guest" user is only permitted to access the server
@ -283,13 +375,16 @@ end}.
fun(Conf) ->
case cuttlefish_variable:filter_by_prefix("ssl_options.key", Conf) of
[{[_,_,Key], Val}|_] -> {list_to_atom(Key), list_to_binary(Val)};
_ -> undefined
_ -> cuttlefish:unset()
end
end}.
{mapping, "ssl_options.keyfile", "rabbit.ssl_options.keyfile",
[{datatype, string}, {validators, ["file_accessible"]}]}.
{mapping, "ssl_options.log_level", "rabbit.ssl_options.log_level",
[{datatype, {enum, [emergency, alert, critical, error, warning, notice, info, debug]}}]}.
{mapping, "ssl_options.log_alert", "rabbit.ssl_options.log_alert",
[{datatype, {enum, [true, false]}}]}.

View File

@ -15,7 +15,7 @@
-import(rabbit_misc, [pget/2]).
-import(rabbit_misc, [pget/2, pget/3]).
-import(rabbit_data_coercion, [to_binary/1]).
-import(rabbit_definitions, [import_raw/1]).
@ -38,9 +38,20 @@ is_enabled() ->
end.
load(Proplist) ->
rabbit_log:debug("Definitions proprties: ~p", [Proplist]),
URL = pget(url, Proplist),
%% TODO
HTTPOptions = [],
TLSOptions0 = [
%% avoids a peer verification warning emitted by default if no certificate chain and peer verification
%% settings are provided: these are not essential in this particular case (client-side downloads that likely
%% will happen from a local trusted source)
{log_level, error},
%% use TLSv1.2 by default
{versions, ['tlsv1.2']}
],
TLSOptions = pget(ssl_options, Proplist, TLSOptions0),
HTTPOptions = [
{ssl, TLSOptions}
],
load_from_url(URL, HTTPOptions).
@ -54,6 +65,7 @@ load_from_url(URL, HTTPOptions0) ->
{body_format, binary}
],
HTTPOptions = HTTPOptions0 ++ [
{connect_timeout, 120000},
{autoredirect, true}
],
rabbit_log:info("Applying definitions from remote URL"),

View File

@ -683,6 +683,52 @@ credential_validator.regexp = ^abc\\d+",
]}],
[]},
%% modern configuration key, HTTPS source
{definition_files, "definitions.import_backend = https
definitions.https.url = https://rabbitmq.eng.megacorp.local/env-1/case1.json
definitions.tls.versions.1 = tlsv1.2
definitions.tls.log_level = error
definitions.tls.secure_renegotiate = true
definitions.tls.ciphers.1 = ECDHE-ECDSA-AES256-GCM-SHA384
definitions.tls.ciphers.2 = ECDHE-RSA-AES256-GCM-SHA384
definitions.tls.ciphers.3 = ECDH-ECDSA-AES256-GCM-SHA384
definitions.tls.ciphers.4 = ECDH-RSA-AES256-GCM-SHA384
definitions.tls.ciphers.5 = DHE-RSA-AES256-GCM-SHA384
definitions.tls.ciphers.6 = DHE-DSS-AES256-GCM-SHA384
definitions.tls.ciphers.7 = ECDHE-ECDSA-AES128-GCM-SHA256
definitions.tls.ciphers.8 = ECDHE-RSA-AES128-GCM-SHA256
definitions.tls.ciphers.9 = ECDH-ECDSA-AES128-GCM-SHA256
definitions.tls.ciphers.10 = ECDH-RSA-AES128-GCM-SHA256
definitions.tls.ciphers.11 = DHE-RSA-AES128-GCM-SHA256
definitions.tls.ciphers.12 = DHE-DSS-AES128-GCM-SHA256",
[{rabbit, [
{definitions, [
{import_backend, rabbit_definitions_import_https},
{url, "https://rabbitmq.eng.megacorp.local/env-1/case1.json"},
{ssl_options, [
{log_level, error},
{secure_renegotiate, true},
{versions, ['tlsv1.2']},
{ciphers, [
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDH-ECDSA-AES256-GCM-SHA384",
"ECDH-RSA-AES256-GCM-SHA384",
"DHE-RSA-AES256-GCM-SHA384",
"DHE-DSS-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDH-ECDSA-AES128-GCM-SHA256",
"ECDH-RSA-AES128-GCM-SHA256",
"DHE-RSA-AES128-GCM-SHA256",
"DHE-DSS-AES128-GCM-SHA256"
]}
]}
]}]}],
[]},
%%
%% Raft
%%

View File

@ -19,6 +19,7 @@ all() ->
{group, boot_time_import_using_classic_source},
%% uses rabbit.definitions with import_backend set to local_filesystem
{group, boot_time_import_using_modern_local_filesystem_source},
{group, boot_time_import_using_public_https_source},
{group, roundtrip},
{group, import_on_a_running_node}
].
@ -55,6 +56,10 @@ groups() ->
import_on_a_booting_node_using_modern_local_filesystem_source
]},
{boot_time_import_using_public_https_source, [], [
import_on_a_booting_node_using_public_https_source
]},
{roundtrip, [], [
export_import_round_trip_case1,
export_import_round_trip_case2
@ -98,6 +103,38 @@ init_per_group(boot_time_import_using_modern_local_filesystem_source = Group, Co
]}
]}),
rabbit_ct_helpers:run_setup_steps(Config2, rabbit_ct_broker_helpers:setup_steps());
init_per_group(boot_time_import_using_public_https_source = Group, Config) ->
Config1 = rabbit_ct_helpers:set_config(Config, [
{rmq_nodename_suffix, Group},
{rmq_nodes_count, 1}
]),
Config2 = rabbit_ct_helpers:merge_app_env(Config1,
{rabbit, [
{definitions, [
{import_backend, rabbit_definitions_import_https},
{url, "https://gist.githubusercontent.com/michaelklishin/e73b0114728d9391425d0644304f264a/raw/f15642771f099c60b6fa93f75d46a4246bb47c45/upstream.definitions.json"},
{ssl_options, [
{log_level, error},
{secure_renegotiate, true},
{versions, ['tlsv1.2']},
{ciphers, [
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDH-ECDSA-AES256-GCM-SHA384",
"ECDH-RSA-AES256-GCM-SHA384",
"DHE-RSA-AES256-GCM-SHA384",
"DHE-DSS-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDH-ECDSA-AES128-GCM-SHA256",
"ECDH-RSA-AES128-GCM-SHA256",
"DHE-RSA-AES128-GCM-SHA256",
"DHE-DSS-AES128-GCM-SHA256"
]}
]}
]}
]}),
rabbit_ct_helpers:run_setup_steps(Config2, rabbit_ct_broker_helpers:setup_steps());
init_per_group(Group, Config) ->
Config1 = rabbit_ct_helpers:set_config(Config, [
{rmq_nodename_suffix, Group}
@ -199,6 +236,14 @@ import_on_a_booting_node_using_modern_local_filesystem_source(Config) ->
{error, timeout} -> ct:fail("virtual host ~p was not imported on boot", [VHost])
end.
import_on_a_booting_node_using_public_https_source(Config) ->
VHost = <<"bunny_testbed">>,
%% verify that virtual host eventually starts
case rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_vhost, await_running_on_all_nodes, [VHost, 3000]) of
ok -> ok;
{error, timeout} -> ct:fail("virtual host ~p was not imported on boot", [VHost])
end.
%%
%% Implementation
%%

View File

@ -48,6 +48,9 @@ consistent release schedule.
definitions.import_backend = https
definitions.https.url = https://rabbitmq.eng.megacorp.local/env-1/definitions.json
definitions.tls.versions.1 = tlsv1.2
definitions.tls.log_level = error
```
GitHub issue: [#3249](https://github.com/rabbitmq/rabbitmq-server/issues/3249)