Skip to content

Commit

Permalink
Add separate monitor for epp_tls_acceptor reloading
Browse files Browse the repository at this point in the history
  • Loading branch information
yulgolem committed Jul 28, 2020
1 parent d0a9be7 commit 328536f
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 50 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ of Erlang property list.
| `cacertfile_path` | `/opt/ca/ca.crt.pem` | SSLCACertificateFile | Where is the client root CA located. Can be inside apps/epp_proxy/priv or absolute path.
| `certfile_path` | `/opt/ca/server.crt.pem` | SSLCertificateFile | Where is the server certificate located. Can be inside apps/epp_proxy/priv or absolute path.
| `keyfile_path` | `/opt/ca/server.key.pem` | SSLCertificateKeyFile | Where is the server key located. Can be inside apps/epp_proxy/priv or absolute path.
| `crlfile_path` | `/opt/ca/crl.pem` | SSLCARevocationFile | Where is the CRL file located. Can be inside apps/epp_proxy/priv or absolute path. When not set, not CRL check is performed.
| `crlfile_path` | `/opt/ca/crl` | SSLCARevocationFile | Where is the CRL file located. Can be inside apps/epp_proxy/priv or absolute path. When not set, not CRL check is performed. CLRs in this directory must be rehashed by `c_rehash` command as per this solution (https://stackoverflow.com/posts/51480191/revisions)



Migrating from mod_epp
Expand Down
5 changes: 4 additions & 1 deletion apps/epp_proxy/src/epp_proxy_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ init([]) ->
MemoryMonitor = #{id => memory_monitor, type => worker,
modules => [memory_monitor],
start => {memory_monitor, start_link, []}},
TLSMonitor = #{id => epp_tls_monitor, type => worker,
modules => [epp_tls_monitor],
start => {epp_tls_monitor, start_link, []}},
SharedSpecs = [TLSAcceptor, PoolSupervisor,
MemoryMonitor],
MemoryMonitor, TLSMonitor],
ChildrenSpec = case ?DevMode of
{ok, true} -> [TCPAcceptor | SharedSpecs];
_ -> SharedSpecs
Expand Down
44 changes: 5 additions & 39 deletions apps/epp_proxy/src/epp_tls_acceptor.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@

-define(POOL_SUPERVISOR, epp_pool_supervisor).

-define(THIRTY_MINUTES_IN_MS, 30 * 30 * 1000).

-define(WORKER, epp_tls_worker).

%% gen_server callbacks
-export([handle_call/3, handle_cast/2, init/1,
start_link/1, terminate/2, handle_info/1, handle_info/2]).
start_link/1, terminate/2]).

-export([crl_file/0, crl_file/1]).
-export([crl_file/0]).

-record(state, {socket, port, options, timer}).
-record(state, {socket, port, options}).

start_link(Port) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, Port,
Expand All @@ -29,12 +27,11 @@ init(Port) ->
{cacertfile, ca_cert_file()}, {certfile, cert_file()},
{keyfile, key_file()}],
Options = handle_crl_check_options(DefaultOptions),
TimerReference = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), reload_clr_file),
{ok, ListenSocket} = ssl:listen(Port, Options),
gen_server:cast(self(), accept),
{ok,
#state{socket = ListenSocket, port = Port,
options = Options, timer = TimerReference}}.
options = Options}}.

%% Acceptor has only one state that goes in a loop:
%% 1. Listen for a connection from anyone.
Expand All @@ -55,35 +52,7 @@ handle_cast(accept,
State#state{socket = ListenSocket, port = Port,
options = Options}}.

handle_info(reload_crl_file) ->
case crl_file() of
undefined -> {noreply};
{ok, File} ->
ssl_crl_cache:insert({file, File}),
{noreply}
end.

handle_info(reload_crl_file, State = #state{socket = ListenSocket, port = Port,
options = _Options, timer = TimerReference}) ->
_ = erlang:cancel_timer(TimerReference, [{async, true}, {info, false}]),
TRef = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), reload_clr_file),
DefaultOptions = [binary, {packet, raw},
{active, false}, {reuseaddr, true},
{verify, verify_peer}, {depth, 1},
{cacertfile, ca_cert_file()}, {certfile, cert_file()},
{keyfile, key_file()}],
NewOptions = handle_crl_check_options(DefaultOptions),
ok = ssl:close(ListenSocket),
{ok, NewSocket} = ssl:listen(Port, NewOptions),
gen_server:cast(self(), accept),
{noreply, State#state{socket = NewSocket, port = Port,
options = NewOptions, timer = TRef}};
handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, State) ->
Timer = State#state.timer,
_ = erlang:cancel_timer(Timer, [{async, true}, {info, false}]),
terminate(_Reason, _State) ->
ok.

handle_call(_E, _From, State) -> {noreply, State}.
Expand Down Expand Up @@ -122,9 +91,6 @@ crl_file() ->
{ok, CrlFile} -> epp_util:path_for_file(CrlFile)
end.

crl_file(path) ->
epp_util:path_for_file(path).


%% In some environments, we do not perform a CRL check. Therefore, we need
%% different options proplist.
Expand Down
78 changes: 78 additions & 0 deletions apps/epp_proxy/src/epp_tls_monitor.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
%%%-------------------------------------------------------------------
%%% @doc
%%%
%%% Monitor module for reloading epp_tls_acceptor on runtime
%%% Used to renew CRLs once in 30 minutes
%%% @end
%%% Created: 20 Feb 2020
%%%-------------------------------------------------------------------
-module(epp_tls_monitor).

-behaviour(gen_server).

-define(THIRTY_MINUTES_IN_MS, 30 * 60 * 1000).

-export([init/1, start_link/0]).

-export([code_change/3, handle_call/3, handle_cast/2,
handle_info/2, terminate/2]).

-export([reload_acceptor/0]).

-record(state, {timer_ref :: timer:tref()}).

-type state() :: #state{}.

-spec start_link() -> ignore | {error, _} | {ok, pid()}.

start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
[]).

-spec init([]) -> {ok, state()}.

init([]) ->
TimerReference = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), reload_acceptor),
erlang:send(self(), reload_acceptor),
{ok, #state{timer_ref = TimerReference}}.

%%%-------------------------------------------------------------------
%%% GenServer callbacks
%%%-------------------------------------------------------------------
-spec handle_call(_, _, State) -> {stop,
not_implemented, State}.

handle_call(_M, _F, State) ->
{stop, not_implemented, State}.

-spec handle_cast(_, State) -> {stop, not_implemented,
State}.

handle_cast(_M, State) ->
{stop, not_implemented, State}.

-spec handle_info(reload_acceptor, _) -> {noreply, _}.

handle_info(reload_acceptor, State = #state{timer_ref = TimerReference}) ->
_ = erlang:cancel_timer(TimerReference, [{async, true}, {info, false}]),
TRef = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), reload_clr_file),
ok = reload_acceptor(),
{noreply, State#state{timer_ref = TRef}}.

-spec terminate(_, state()) -> ok.

terminate(_Reason, State) ->
_ = erlang:cancel_timer(State#state.timer_ref, [{async, true}, {info, false}]),
ok.

-spec code_change(_, _, _) -> {ok, _}.

code_change(_OldVersion, State, _Extra) -> {ok, State}.

%%%-------------------------------------------------------------------
%%% Internal functions
%%%-------------------------------------------------------------------
reload_acceptor() ->
supervisor:terminate_child(epp_proxy_sup, epp_tls_acceptor),
supervisor:restart_child(epp_proxy_sup, epp_tls_acceptor),
ok.
13 changes: 8 additions & 5 deletions apps/epp_proxy/src/memory_monitor.erl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ start_link() ->
-spec init([]) -> {ok, state()}.

init([]) ->
{ok, TimerReference} =
timer:send_interval(?THIRTY_MINUTES_IN_MS, log_usage),
TimerReference = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), log_usage),
erlang:send(self(), log_usage),
{ok, #state{timer_ref = TimerReference}}.

Expand All @@ -56,13 +55,17 @@ handle_cast(_M, State) ->

-spec handle_info(log_usage, _) -> {noreply, _}.

handle_info(log_usage, State) ->
ok = log_memory(), {noreply, State}.
handle_info(log_usage, State = #state{timer_ref = TimerReference}) ->
_ = erlang:cancel_timer(TimerReference, [{async, true}, {info, false}]),
TRef = erlang:send_after(?THIRTY_MINUTES_IN_MS, self(), reload_clr_file),
ok = log_memory(),
{noreply, State#state{timer_ref = TRef}}.

-spec terminate(_, state()) -> ok.

terminate(_Reason, State) ->
{ok, cancel} = timer:cancel(State#state.timer_ref), ok.
_ = erlang:cancel_timer(State#state.timer_ref, [{async, true}, {info, false}]),
ok.

-spec code_change(_, _, _) -> {ok, _}.

Expand Down
6 changes: 4 additions & 2 deletions apps/epp_proxy/test/tls_client_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ all() ->
init_per_suite(Config) ->
application:ensure_all_started(epp_proxy),
application:ensure_all_started(hackney),
ok = application:set_env(epp_proxy, crlfile_path, "test_ca/crl/first"),
CWD = code:priv_dir(epp_proxy),
Options = [binary,
{certfile, filename:join(CWD, "test_ca/certs/client.crt.pem")},
Expand Down Expand Up @@ -121,14 +122,15 @@ session_test_case(Config) ->
second_revoked_session_test_case(Config) ->
ok = application:set_env(epp_proxy, crlfile_path, "test_ca/crl/second"),

epp_tls_acceptor ! reload_crl_file,

epp_tls_monitor ! reload_acceptor,
ct:sleep({seconds, 5}),
Options = proplists:get_value(second_revoked_options, Config),

{error, Error} = ssl:connect("localhost", 1443, Options, 2000),
{tls_alert,
{certificate_revoked,
"received CLIENT ALERT: Fatal - Certificate Revoked"}} = Error,
%% "TLS client: In state cipher received SERVER ALERT: Fatal - Certificate Revoked\n "}} = Error,
ok.

valid_command_test_case(Config) ->
Expand Down
2 changes: 1 addition & 1 deletion config/test.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{cacertfile_path, "test_ca/certs/ca.crt.pem"},
{certfile_path, "test_ca/certs/apache.crt"},
{keyfile_path, "test_ca/private/apache.key"},
{crlfile_path, "test_ca/crl"}]},
{crlfile_path, "test_ca/crl/first"}]},


{lager, [
Expand Down
2 changes: 1 addition & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@

{plugins, [rebar3_auto,
{erl_tidy_prv_fmt, ".*", {git, "git://github.com/tsloughter/erl_tidy.git", {branch, "master"}}},
rebar3_appup_plugin]}.
rebar3_appup_plugin]}.

0 comments on commit 328536f

Please sign in to comment.