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 { dashboard {
listeners.http { listeners {
http {
## Comment out 'bind' (or set bind=0) to disable listener.
bind = 18083 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), enable(false),
bind(18084), bind(18084),
ssl_options() ssl_options()
| common_listener_fields() ++ | common_listener_fields()
hidden_server_ssl_options()
]; ];
fields("ssl_options") -> fields("ssl_options") ->
server_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() -> server_ssl_options() ->
Opts0 = emqx_schema:server_ssl_opts_schema(#{}, true), 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.
common_listener_fields() -> common_listener_fields() ->
[ [
@ -217,6 +194,7 @@ enable(Bool) ->
#{ #{
default => Bool, default => Bool,
required => false, required => false,
%% deprecated because we use port number =:= 0 to disable
deprecated => {since, "5.1.0"}, deprecated => {since, "5.1.0"},
importance => ?IMPORTANCE_HIDDEN, importance => ?IMPORTANCE_HIDDEN,
desc => ?DESC(listener_enable) desc => ?DESC(listener_enable)
@ -300,15 +278,19 @@ validate_sample_interval(Second) ->
{error, Msg} {error, Msg}
end. 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; Conf;
https_converter(Conf = #{}, _Opts) -> convert_ssl_layout(Conf = #{}, _Opts) ->
Keys = lists:map(fun({K, _}) -> list_to_binary(K) end, server_ssl_options()), Keys = lists:map(fun({K, _}) -> list_to_binary(K) end, server_ssl_options()),
SslOpts = maps:with(Keys, Conf), SslOpts = maps:with(Keys, Conf),
Conf1 = maps:without(Keys, Conf), Conf1 = maps:without(Keys, Conf),
Conf1#{<<"ssl_options">> => SslOpts}; Conf1#{<<"ssl_options">> => SslOpts}.
https_converter(Conf, _Opts) ->
Conf.
-if(?EMQX_RELEASE_EDITION == ee). -if(?EMQX_RELEASE_EDITION == ee).
sso_fields() -> sso_fields() ->

View File

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

View File

@ -10,14 +10,32 @@ dashboard {
cors = false cors = false
listeners.https { listeners.https {
## Port or Address to listen on, 0 means disable ## Port or Address to listen on, 0 means disable
bind = "0.0.0.0:18084" ## or just a port number, e.g. 18084 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 ## Socket acceptor pool size for TCP protocols
num_acceptors = 8 num_acceptors = 8
## Maximum number of simultaneous connections ## Maximum number of concurrent connections
max_connections = 512 max_connections = 512
## Defines the maximum length that the queue of pending connections can grow to ## 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 ## Disable IPv4-to-IPv6 mapping for the listener
ipv6_v6only = false ipv6_v6only = false
## Enable support for `HAProxy` header ## Enable support for ProxyProtocol v2 header
proxy_header = false 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""" """Backlog"""
bind.desc: bind.desc:
"""Port without IP(18083) or port with specified IP(127.0.0.1:18083). """Bind the listener to a specified address and port number, for example `127.0.0.1:18083`.
Disabled when setting bind to `0`.""" 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.label:
"""Bind""" """Bind"""