summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Klishin <michael@clojurewerkz.org>2021-08-17 20:42:53 +0300
committerMichael Klishin <michael@clojurewerkz.org>2021-08-17 20:42:53 +0300
commit6a0058fe7c09cd41b87570614e6d8f29b84a0965 (patch)
treea83c40f53b5b76277ba16257d09a3697740bceae
parentf3a52354087c4fa3cde6879502f9876a6f5175d2 (diff)
downloadrabbitmq-server-git-6a0058fe7c09cd41b87570614e6d8f29b84a0965.tar.gz
Introduce TLS-related rabbitmq.conf settings for definition import
currently only used by the HTTPS mechanism but can be used by any other.
-rw-r--r--deps/rabbit/priv/schema/rabbit.schema101
-rw-r--r--deps/rabbit/src/rabbit_definitions_import_https.erl18
-rw-r--r--deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets46
-rw-r--r--deps/rabbit/test/definition_import_SUITE.erl45
-rw-r--r--release-notes/3.9.4.md3
5 files changed, 207 insertions, 6 deletions
diff --git a/deps/rabbit/priv/schema/rabbit.schema b/deps/rabbit/priv/schema/rabbit.schema
index c4688b64a5..adb68b3927 100644
--- a/deps/rabbit/priv/schema/rabbit.schema
+++ b/deps/rabbit/priv/schema/rabbit.schema
@@ -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]}}]}.
diff --git a/deps/rabbit/src/rabbit_definitions_import_https.erl b/deps/rabbit/src/rabbit_definitions_import_https.erl
index 7115f2d2e8..f239400edd 100644
--- a/deps/rabbit/src/rabbit_definitions_import_https.erl
+++ b/deps/rabbit/src/rabbit_definitions_import_https.erl
@@ -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"),
diff --git a/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets b/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets
index 93fd8d855b..08ea31ff49 100644
--- a/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets
+++ b/deps/rabbit/test/config_schema_SUITE_data/rabbit.snippets
@@ -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
%%
diff --git a/deps/rabbit/test/definition_import_SUITE.erl b/deps/rabbit/test/definition_import_SUITE.erl
index f4bf62fcdb..eff4ba1707 100644
--- a/deps/rabbit/test/definition_import_SUITE.erl
+++ b/deps/rabbit/test/definition_import_SUITE.erl
@@ -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
%%
diff --git a/release-notes/3.9.4.md b/release-notes/3.9.4.md
index 6b445fea39..eef4d5b1e1 100644
--- a/release-notes/3.9.4.md
+++ b/release-notes/3.9.4.md
@@ -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)