fix(ocsp): allow disabling ocsp without touching url

This commit is contained in:
Thales Macedo Garitezi 2022-11-07 17:50:02 -03:00
parent 26d2ed3d31
commit 11175b55f8
4 changed files with 46 additions and 12 deletions

View File

@ -1521,6 +1521,12 @@ listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem
## Value: File ## Value: File
listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem
## Wheter to enable OCSP for the listener.
##
## Value: boolean
## Default: false
## listener.ssl.external.enable_ocsp = true
## URL for the OCSP responder to check the server certificate against. ## URL for the OCSP responder to check the server certificate against.
## ##
## Value: String ## Value: String

View File

@ -1679,6 +1679,11 @@ end}.
{datatype, {duration, ms}} {datatype, {duration, ms}}
]}. ]}.
{mapping, "listener.ssl.$name.enable_ocsp", "emqx.listeners", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "listener.ssl.$name.ocsp_responder_url", "emqx.listeners", [ {mapping, "listener.ssl.$name.ocsp_responder_url", "emqx.listeners", [
{datatype, string} {datatype, string}
]}. ]}.
@ -2237,6 +2242,7 @@ end}.
{supported_subprotocols, string:tokens(cuttlefish:conf_get(Prefix ++ ".supported_subprotocols", Conf, ""), ", ")}, {supported_subprotocols, string:tokens(cuttlefish:conf_get(Prefix ++ ".supported_subprotocols", Conf, ""), ", ")},
{peer_cert_as_username, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_username", Conf, undefined)}, {peer_cert_as_username, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_username", Conf, undefined)},
{peer_cert_as_clientid, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_clientid", Conf, undefined)}, {peer_cert_as_clientid, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_clientid", Conf, undefined)},
{ocsp_enabled, cuttlefish:conf_get(Prefix ++ ".enable_ocsp", Conf, undefined)},
{ocsp_responder_url, cuttlefish:conf_get(Prefix ++ ".ocsp_responder_url", Conf, undefined)}, {ocsp_responder_url, cuttlefish:conf_get(Prefix ++ ".ocsp_responder_url", Conf, undefined)},
{ocsp_issuer_pem, cuttlefish:conf_get(Prefix ++ ".ocsp_issuer_pem", Conf, undefined)}, {ocsp_issuer_pem, cuttlefish:conf_get(Prefix ++ ".ocsp_issuer_pem", Conf, undefined)},
{ocsp_refresh_interval, cuttlefish:conf_get(Prefix ++ ".ocsp_refresh_interval", Conf, undefined)}, {ocsp_refresh_interval, cuttlefish:conf_get(Prefix ++ ".ocsp_refresh_interval", Conf, undefined)},

View File

@ -48,6 +48,11 @@
-define(CALL_TIMEOUT, 20_000). -define(CALL_TIMEOUT, 20_000).
-define(RETRY_TIMEOUT, 5_000). -define(RETRY_TIMEOUT, 5_000).
-define(REFRESH_TIMER(LID), {refresh_timer, LID}). -define(REFRESH_TIMER(LID), {refresh_timer, LID}).
-ifdef(TEST).
-define(MIN_REFRESH_INTERVAL, timer:seconds(5)).
-else.
-define(MIN_REFRESH_INTERVAL, timer:minutes(1)).
-endif.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% API %% API
@ -93,10 +98,10 @@ inject_sni_fun(Listener = #{proto := Proto, name := Name, opts := Options0}) ->
%% because otherwise an anonymous function will end up in %% because otherwise an anonymous function will end up in
%% `app.*.config'... %% `app.*.config'...
ListenerID = emqx_listeners:identifier(Listener), ListenerID = emqx_listeners:identifier(Listener),
case proplists:get_value(ocsp_responder_url, Options0, undefined) of case proplists:get_bool(ocsp_enabled, Options0) of
undefined -> false ->
Options0; Options0;
_URL -> true ->
SSLOpts0 = proplists:get_value(ssl_options, Options0, []), SSLOpts0 = proplists:get_value(ssl_options, Options0, []),
SNIFun = fun(SN) -> emqx_ocsp_cache:sni_fun(SN, ListenerID) end, SNIFun = fun(SN) -> emqx_ocsp_cache:sni_fun(SN, ListenerID) end,
Options1 = proplists:delete(ssl_options, Options0), Options1 = proplists:delete(ssl_options, Options0),
@ -142,8 +147,7 @@ handle_call({register_listener, ListenerID}, _From, State0) ->
?LOG(debug, "registering ocsp cache for ~p", [ListenerID]), ?LOG(debug, "registering ocsp cache for ~p", [ListenerID]),
#{opts := Opts} = emqx_listeners:find_by_id(ListenerID), #{opts := Opts} = emqx_listeners:find_by_id(ListenerID),
RefreshInterval0 = proplists:get_value(ocsp_refresh_interval, Opts), RefreshInterval0 = proplists:get_value(ocsp_refresh_interval, Opts),
MinimumRefrshInterval = timer:minutes(1), RefreshInterval = max(RefreshInterval0, ?MIN_REFRESH_INTERVAL),
RefreshInterval = max(RefreshInterval0, MinimumRefrshInterval),
State = State0#{{refresh_interval, ListenerID} => RefreshInterval}, State = State0#{{refresh_interval, ListenerID} => RefreshInterval},
{reply, ok, ensure_timer(ListenerID, State, 0)}; {reply, ok, ensure_timer(ListenerID, State, 0)};
handle_call(Call, _From, State) -> handle_call(Call, _From, State) ->
@ -177,7 +181,8 @@ code_change(_Vsn, State, _Extra) ->
ListenersToPatch = ListenersToPatch =
lists:filter( lists:filter(
fun(#{opts := Opts}) -> fun(#{opts := Opts}) ->
undefined =/= proplists:get_value(ocsp_responder_url, Opts) undefined =/= proplists:get_value(ocsp_responder_url, Opts) andalso
false =/= proplists:get_bool(ocsp_enabled, Opts)
end, end,
emqx:get_env(listeners, [])), emqx:get_env(listeners, [])),
PatchedListeners = [L#{opts => ?MODULE:inject_sni_fun(L)} || L <- ListenersToPatch], PatchedListeners = [L#{opts => ?MODULE:inject_sni_fun(L)} || L <- ListenersToPatch],

View File

@ -96,10 +96,10 @@ init_per_testcase(t_openssl_client, Config) ->
, {cacertfile, CACert} , {cacertfile, CACert}
]), ]),
Opts1 = proplists:delete(ssl_options, Opts0), Opts1 = proplists:delete(ssl_options, Opts0),
Opts2 = [ {ocsp_responder_url, "http://127.0.0.1:9877"} Opts2 = emqx_misc:merge_opts(Opts1, [ {ocsp_enabled, true}
, {ocsp_issuer_pem, IssuerPem} , {ocsp_responder_url, "http://127.0.0.1:9877"}
, {ssl_options, SSLOpts2} , {ocsp_issuer_pem, IssuerPem}
| Opts1], , {ssl_options, SSLOpts2}]),
Listeners = [ SSLListener0#{opts => Opts2} Listeners = [ SSLListener0#{opts => Opts2}
| Listeners1], | Listeners1],
application:set_env(emqx, listeners, Listeners), application:set_env(emqx, listeners, Listeners),
@ -109,7 +109,18 @@ init_per_testcase(t_openssl_client, Config) ->
end, end,
OCSPResponderPort = spawn_openssl_ocsp_responder(Config), OCSPResponderPort = spawn_openssl_ocsp_responder(Config),
{os_pid, OCSPOSPid} = erlang:port_info(OCSPResponderPort, os_pid), {os_pid, OCSPOSPid} = erlang:port_info(OCSPResponderPort, os_pid),
ensure_port_open(9877), %%%%%%%% Warning!!!
%% Apparently, openssl 3.0.7 introduced a bug in the responder
%% that makes it hang forever if one probes the port with
%% `gen_tcp:open' / `gen_tcp:close'... Comment this out if
%% openssl gets updated in CI or in your local machine.
case openssl_version() of
"3." ++ _ ->
%% hope that the responder has started...
ok;
_ ->
ensure_port_open(9877)
end,
ct:sleep(1_000), ct:sleep(1_000),
emqx_ct_helpers:start_apps([], Handler), emqx_ct_helpers:start_apps([], Handler),
ct:sleep(1_000), ct:sleep(1_000),
@ -134,6 +145,7 @@ init_per_testcase(_TestCase, Config) ->
, name => "test_ocsp" , name => "test_ocsp"
, opts => [ {ssl_options, [{certfile, , opts => [ {ssl_options, [{certfile,
filename:join(DataDir, "server.pem")}]} filename:join(DataDir, "server.pem")}]}
, {ocsp_enabled, true}
, {ocsp_responder_url, "http://localhost:9877"} , {ocsp_responder_url, "http://localhost:9877"}
, {ocsp_issuer_pem, , {ocsp_issuer_pem,
filename:join(DataDir, "ocsp-issuer.pem")} filename:join(DataDir, "ocsp-issuer.pem")}
@ -291,6 +303,11 @@ get_sni_fun(ListenerID) ->
SSLOpts = proplists:get_value(ssl_options, Opts), SSLOpts = proplists:get_value(ssl_options, Opts),
proplists:get_value(sni_fun, SSLOpts). proplists:get_value(sni_fun, SSLOpts).
openssl_version() ->
"OpenSSL " ++ Res = os:cmd("openssl version"),
{match, [Version]} = re:run(Res, "^([^ ]+)", [{capture, first, list}]),
Version.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Test cases %% Test cases
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -417,7 +434,7 @@ t_refresh_periodically(_Config) ->
false false
end, end,
_NEvents = 2, _NEvents = 2,
_Timeout = 5_000), _Timeout = 10_000),
ok = emqx_ocsp_cache:register_listener(ListenerID), ok = emqx_ocsp_cache:register_listener(ListenerID),
?assertMatch({ok, [_, _]}, snabbkaffe:receive_events(SubRef)), ?assertMatch({ok, [_, _]}, snabbkaffe:receive_events(SubRef)),
assert_http_get(2), assert_http_get(2),