Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,21 @@ ENV KERL_DOC_TARGETS=""
ENV KERL_INSTALL_HTMLDOCS="no"
ENV KERL_INSTALL_MANPAGES="no"

RUN git clone https://github.com/asdf-vm/asdf.git --branch v0.6.3 "$HOME"/.asdf && \
echo '. $HOME/.asdf/asdf.sh' >> "$HOME"/.bashrc && \
echo '. $HOME/.asdf/asdf.sh' >> "$HOME"/.profile
# Install asdf and add it to PATH
RUN git clone https://github.com/asdf-vm/asdf.git --branch v0.6.3 /root/.asdf && \
echo '. /root/.asdf/asdf.sh' >> /root/.bashrc && \
echo '. /root/.asdf/asdf.sh' >> /root/.profile

ENV PATH="${PATH}:/root/.asdf/shims:/root/.asdf/bin"
ENV PATH="/root/.asdf/shims:/root/.asdf/bin:${PATH}"

RUN mkdir -p /opt/erlang/epp_proxy
WORKDIR /opt/erlang/epp_proxy

COPY .tool-versions ./

# Install plugins and tools with explicit sourcing of asdf.sh
RUN asdf plugin-add erlang
RUN . $HOME/.asdf/asdf.sh && asdf install
RUN source /root/.asdf/asdf.sh && asdf install
RUN asdf global erlang $(grep erlang .tool-versions | cut -d' ' -f2)
RUN asdf plugin-add ruby
RUN asdf plugin-add rebar
Expand Down
37 changes: 25 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,33 @@ Configuration for the application tries to emulate the mod_epp configuration as
to make migration easier. The configuration is placed in `config/sys.config` file, it takes a format
of Erlang property list.

There are three example configuration files in `config/`:

* `sys.config` – default configuration used for real deployments. Values such as `tls_port`,
`epp_session_url` and certificate paths are typically provided via environment variables (eg.
`${TLS_PORT}`, `${EPP_SESSION_URL}`), so the same file can be reused across environments.
* `docker.config` – configuration tuned for running inside Docker. It uses hardcoded ports,
certificate paths under `/opt/ca/...` and EPP endpoints pointing to the `epp` container
(eg. `http://epp:3000/epp/…`).
* `test.config` – local development/test configuration. It enables `dev_mode`, uses local ports
and points EPP endpoints to `http://localhost:9292/...`, with test CA material under
`test_ca/`.

*Configuration variables*

| Variable name | Expected values | Apache equivalent | Definition
-----------------------|------------------------------------|-----------------------|--------------------------------------------
| `dev_mode` | `true`, `false` | None | Enables TCP access without TLS.
| `tls_port` | `700` | Listen | At which port should we open a TLS socket. Default is 700.
| `tcp_port` | `70000` | Listen | At which port should we open a TCP socket. Only in `dev_mode`.
| `epp_session_url` | `https://example.com/epp/session` | EppSessionRoot | HTTP address of the session endpoints including schema and port.
| `epp_command_url` | `https://example.com/epp/command` | EppCommandRoot | HTTP address of the command endpoints including schema and port.
| `epp_error_url` | `https://example.com/epp/error` | EppErrorRoot | HTTP address of the error endpoints including schema and port.
| `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.
| Variable name | Expected values | Apache equivalent | Definition
-------------------------|------------------------------------|-----------------------|--------------------------------------------
| `dev_mode` | `true`, `false` | None | Enables TCP access without TLS.
| `tls_port` | `700` | Listen | At which port should we open a TLS socket. Default is 700.
| `tcp_port` | `70000` | Listen | At which port should we open a TCP socket. Only in `dev_mode`.
| `epp_session_url` | `https://example.com/epp/session` | EppSessionRoot | HTTP address of the session endpoints including schema and port.
| `epp_command_url` | `https://example.com/epp/command` | EppCommandRoot | HTTP address of the command endpoints including schema and port.
| `epp_error_url` | `https://example.com/epp/error` | EppErrorRoot | HTTP address of the error endpoints including schema and port.
| `require_client_certs` | `true`, `false` | None | Allows client to connect to epp_proxy without client certificate using TLS.
| `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.


Migrating from mod_epp
Expand Down
11 changes: 10 additions & 1 deletion apps/epp_proxy/src/epp_tls_acceptor.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ start_link(Port) ->
[]).

init(Port) ->
RequireClientCerts = require_client_certs(),
DefaultOptions = [binary, {packet, raw},
{active, false}, {reuseaddr, true},
{verify, verify_peer}, {depth, 1},
{verify, verify_peer}, {fail_if_no_peer_cert, RequireClientCerts}, {depth, 1},
{cacertfile, ca_cert_file()}, {certfile, cert_file()},
{keyfile, key_file()}],
Options = handle_crl_check_options(DefaultOptions),
Expand Down Expand Up @@ -82,6 +83,14 @@ key_file() ->
{ok, KeyFile} -> epp_util:path_for_file(KeyFile)
end.

%% Whether client certificates are required.
%% If not configured, default to true to preserve existing behavior.
require_client_certs() ->
case application:get_env(epp_proxy, require_client_certs) of
undefined -> true;
{ok, Bool} -> Bool
end.

crl_file() ->
case application:get_env(epp_proxy, crlfile_path) of
undefined -> undefined;
Expand Down
36 changes: 36 additions & 0 deletions apps/epp_proxy/test/tls_client_optional_cert_SUITE.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-module(tls_client_optional_cert_SUITE).

-include_lib("common_test/include/ct.hrl").

-export([all/0, init_per_suite/1, end_per_suite/1,
connect_without_client_cert_test/1, connect_with_client_cert_test/1]).

all() -> [connect_without_client_cert_test, connect_with_client_cert_test].

init_per_suite(Config) ->
application:set_env(epp_proxy, require_client_certs, false),
application:ensure_all_started(epp_proxy),
application:ensure_all_started(hackney),
CWD = code:priv_dir(epp_proxy),
WithCert = [binary,
{certfile, filename:join(CWD, "test_ca/certs/client.crt.pem")},
{keyfile, filename:join(CWD, "test_ca/private/client.key.pem")},
{active, false}],
[{with_cert, WithCert} | Config].

end_per_suite(Config) ->
application:unset_env(epp_proxy, require_client_certs),
application:stop(epp_proxy),
application:stop(hackney),
Config.

connect_without_client_cert_test(_Config) ->
{ok, Socket} = ssl:connect("localhost", 1443, [binary, {active, false}], 2000),
{ok, _Data} = ssl:recv(Socket, 0, 1200),
ok.

connect_with_client_cert_test(Config) ->
Options = proplists:get_value(with_cert, Config),
{ok, Socket} = ssl:connect("localhost", 1443, Options, 2000),
{ok, _Data} = ssl:recv(Socket, 0, 1200),
ok.
6 changes: 4 additions & 2 deletions config/docker.config
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
{epp_session_url, "http://epp:3000/epp/session/"},
{epp_command_url, "http://epp:3000/epp/command/"},
{epp_error_url, "http://epp:3000/epp/error/"},
%% Allows client to connect to epp_proxy without client certificate using TLS
{require_client_certs, true},
{cacertfile_path, "/opt/ca/certs/ca.crt.pem"},
{certfile_path, "/opt/ca/certs/apache.crt"},
{keyfile_path, "/opt/ca/private/apache.key"},
{crlfile_path, "/opt/ca/crl/crl.pem"}
{keyfile_path, "/opt/ca/private/apache.key"}
%% {crlfile_path, "/opt/ca/crl/crl.pem"}
]},
{lager, [
{handlers, [
Expand Down
2 changes: 2 additions & 0 deletions config/sys.config
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
{epp_session_url, "${EPP_SESSION_URL}"},
{epp_command_url, "${EPP_COMMAND_URL}"},
{epp_error_url, "${EPP_ERROR_URL}"},
%% Allows client to connect to epp_proxy without client certificate using TLS
{require_client_certs, true},
%% Path to root CA that should check the client certificates.
{cacertfile_path, "${CACERT_PATH}"},
%% Path to server's certficate file.
Expand Down
2 changes: 2 additions & 0 deletions config/test.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
{epp_session_url, "http://localhost:9292/session/"},
{epp_command_url, "http://localhost:9292/command/"},
{epp_error_url, "http://localhost:9292/error/"},
%% Allows client to connect to epp_proxy without client certificate using TLS
{require_client_certs, true},
%% Path to root CA that should check the client certificates.
{cacertfile_path, "test_ca/certs/ca.crt.pem"},
{certfile_path, "test_ca/certs/apache.crt"},
Expand Down