Merge pull request #12970 from zmstone/0503-refactor-dashboard-listener

refactor: simplify https listener config for dashboard
This commit is contained in:
Zaiming (Stone) Shi 2024-05-04 08:38:29 +02:00 committed by GitHub
commit e7f0c83406
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 72 additions and 94 deletions

View File

@ -1,5 +1,16 @@
dashboard {
listeners.http {
listeners {
http {
## Comment out 'bind' (or set bind=0) to disable listener.
bind = 18083
}
https {
## Uncomment to enable
# bind = 18084
ssl_options {
certfile = "${EMQX_ETC_DIR}/certs/cert.pem"
keyfile = "${EMQX_ETC_DIR}/certs/key.pem"
}
}
}
}

View File

@ -101,8 +101,7 @@ fields("https") ->
enable(false),
bind(18084),
ssl_options()
| common_listener_fields() ++
hidden_server_ssl_options()
| common_listener_fields()
];
fields("ssl_options") ->
server_ssl_options().
@ -118,30 +117,8 @@ ssl_options() ->
}
)}.
hidden_server_ssl_options() ->
lists:map(
fun({K, V}) ->
{K, V#{
importance => ?IMPORTANCE_HIDDEN,
default => undefined,
required => false
}}
end,
server_ssl_options()
).
server_ssl_options() ->
Opts0 = emqx_schema:server_ssl_opts_schema(#{}, true),
exclude_fields(["fail_if_no_peer_cert"], Opts0).
exclude_fields([], Fields) ->
Fields;
exclude_fields([FieldName | Rest], Fields) ->
%% assert field exists
case lists:keytake(FieldName, 1, Fields) of
{value, _, New} -> exclude_fields(Rest, New);
false -> error({FieldName, Fields})
end.
emqx_schema:server_ssl_opts_schema(#{}, true).
common_listener_fields() ->
[
@ -217,6 +194,7 @@ enable(Bool) ->
#{
default => Bool,
required => false,
%% deprecated because we use port number =:= 0 to disable
deprecated => {since, "5.1.0"},
importance => ?IMPORTANCE_HIDDEN,
desc => ?DESC(listener_enable)
@ -300,15 +278,19 @@ validate_sample_interval(Second) ->
{error, Msg}
end.
https_converter(Conf = #{<<"ssl_options">> := _}, _Opts) ->
https_converter(undefined, _Opts) ->
%% no https listener configured
undefined;
https_converter(Conf, Opts) ->
convert_ssl_layout(Conf, Opts).
convert_ssl_layout(Conf = #{<<"ssl_options">> := _}, _Opts) ->
Conf;
https_converter(Conf = #{}, _Opts) ->
convert_ssl_layout(Conf = #{}, _Opts) ->
Keys = lists:map(fun({K, _}) -> list_to_binary(K) end, server_ssl_options()),
SslOpts = maps:with(Keys, Conf),
Conf1 = maps:without(Keys, Conf),
Conf1#{<<"ssl_options">> => SslOpts};
https_converter(Conf, _Opts) ->
Conf.
Conf1#{<<"ssl_options">> => SslOpts}.
-if(?EMQX_RELEASE_EDITION == ee).
sso_fields() ->

View File

@ -222,7 +222,7 @@ t_dashboard(_Config) ->
{ok, Dashboard = #{<<"listeners">> := Listeners}} = get_config("dashboard"),
Https1 = #{enable => true, bind => 18084},
?assertMatch(
{error, {"HTTP/1.1", 400, _}},
{ok, _},
update_config("dashboard", Dashboard#{<<"listeners">> => Listeners#{<<"https">> => Https1}})
),
@ -241,17 +241,20 @@ t_dashboard(_Config) ->
update_config("dashboard", Dashboard2)
),
KeyFile = emqx_common_test_helpers:app_path(emqx, filename:join(["etc", "certs", "key.pem"])),
CertFile = emqx_common_test_helpers:app_path(emqx, filename:join(["etc", "certs", "cert.pem"])),
CacertFile = emqx_common_test_helpers:app_path(
emqx, filename:join(["etc", "certs", "cacert.pem"])
),
FilePath = fun(Name) ->
iolist_to_binary(
emqx_common_test_helpers:app_path(emqx, filename:join(["etc", "certs", Name]))
)
end,
KeyFile = FilePath("key.pem"),
CertFile = FilePath("cert.pem"),
CacertFile = FilePath("cacert.pem"),
Https3 = #{
<<"bind">> => 18084,
<<"ssl_options">> => #{
<<"keyfile">> => list_to_binary(KeyFile),
<<"cacertfile">> => list_to_binary(CacertFile),
<<"certfile">> => list_to_binary(CertFile)
<<"keyfile">> => KeyFile,
<<"cacertfile">> => CacertFile,
<<"certfile">> => CertFile
}
},
Dashboard3 = Dashboard#{<<"listeners">> => Listeners#{<<"https">> => Https3}},
@ -260,16 +263,23 @@ t_dashboard(_Config) ->
Dashboard4 = Dashboard#{<<"listeners">> => Listeners#{<<"https">> => #{<<"bind">> => 0}}},
?assertMatch({ok, _}, update_config("dashboard", Dashboard4)),
{ok, Dashboard41} = get_config("dashboard"),
?assertEqual(
Https3#{<<"bind">> => 0},
?assertMatch(
#{
<<"bind">> := 0,
<<"ssl_options">> :=
#{
<<"keyfile">> := KeyFile,
<<"cacertfile">> := CacertFile,
<<"certfile">> := CertFile
}
},
read_conf([<<"dashboard">>, <<"listeners">>, <<"https">>]),
Dashboard41
),
?assertMatch({ok, _}, update_config("dashboard", Dashboard)),
{ok, Dashboard1} = get_config("dashboard"),
?assertNotEqual(Dashboard, Dashboard1),
?assertEqual(Dashboard, Dashboard1),
timer:sleep(1500),
ok.

View File

@ -10,14 +10,32 @@ dashboard {
cors = false
listeners.https {
## Port or Address to listen on, 0 means disable
bind = "0.0.0.0:18084" ## or just a port number, e.g. 18084
ssl_options {
## PEM format certificates chain.
## Server certificate as the first one,
## followed by its immediate issuer certificate
## then the issuer's issuer certificate, and so on.
## Root CA certificate is optional.
## The path prefix (only prefix) can be an environment variable.
certfile = "${EMQX_ETC_DIR}/certs/cert.pem"
## PEM format private key
keyfile = "${EMQX_ETC_DIR}/certs/key.pem"
## Optional. When need to verify client certificates, list trusted client's root CA certificates in this file
# cacertfile = "${EMQX_ETC_DIR}/certs/cacert.pem"
## Optional. Force client to send their certificate chain during TLS handshake.
# fail_if_no_peer_cert = true
}
## Socket acceptor pool size for TCP protocols
num_acceptors = 8
## Maximum number of simultaneous connections
## Maximum number of concurrent connections
max_connections = 512
## Defines the maximum length that the queue of pending connections can grow to
@ -32,51 +50,7 @@ dashboard {
## Disable IPv4-to-IPv6 mapping for the listener
ipv6_v6only = false
## Enable support for `HAProxy` header
## Enable support for ProxyProtocol v2 header
proxy_header = false
## Trusted PEM format CA certificates bundle file
cacertfile = "data/certs/cacert.pem"
## PEM format certificates chain file
certfile = "data/certs/cert.pem"
## PEM format private key file
keyfile = "data/certs/key.pem"
## Enable or disable peer verification
verify = verify_none ## use verify_peer to enable
## Enable TLS session reuse
reuse_sessions = true
## Maximum number of non-self-issued intermediate certificates that can follow the peer certificate in a valid certification path
depth = 10
## Which versions are to be supported
versions = [tlsv1.3, tlsv1.2]
## TLS cipher suite names
## Note: By default, all available suites are supported, you do not need to set this
ciphers = ["TLS_AES_256_GCM_SHA384","TLS_AES_128_GCM_SHA256"]
## Allows a client and a server to renegotiate the parameters of the SSL connection on the fly
secure_renegotiate = true
## Log level for SSL communication
## Type: emergency | alert | critical | error | warning | notice | info | debug | none | all
log_level = notice
## Hibernate the SSL process after idling for amount of time reducing its memory footprint
hibernate_after = 5s
## Forces the cipher to be set based on the server-specified order instead of the client-specified order
honor_cipher_order = true
## Setting this to false to disable client-initiated renegotiation
client_renegotiation = true
## Maximum time duration allowed for the handshake to complete
handshake_timeout = 15s
}
}

View File

@ -7,8 +7,9 @@ backlog.label:
"""Backlog"""
bind.desc:
"""Port without IP(18083) or port with specified IP(127.0.0.1:18083).
Disabled when setting bind to `0`."""
"""Bind the listener to a specified address and port number, for example `127.0.0.1:18083`.
If configured with just the port number (e.g. `18083`) it's equivalent to binding to all addresses `0.0.0.0`.
The listener is disabled if `bind` is `0`."""
bind.label:
"""Bind"""