-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Backoffice : ajout doc/config pour plug rate limiter (#3652)
* Backoffice : ajout doc/config pour plug rate limiter * Améliorations suite à PR --------- Co-authored-by: Thibaut Barrère <[email protected]>
- Loading branch information
1 parent
7a4bdc8
commit abc05ee
Showing
8 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
69 changes: 69 additions & 0 deletions
69
apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
defmodule TransportWeb.Backoffice.RateLimiterLive do | ||
use Phoenix.LiveView | ||
import TransportWeb.Backoffice.JobsLive, only: [ensure_admin_auth_or_redirect: 3] | ||
import TransportWeb.Router.Helpers, only: [static_path: 2] | ||
import Helpers, only: [format_number: 1] | ||
|
||
@impl true | ||
def mount(_params, %{"current_user" => current_user} = _session, socket) do | ||
{:ok, | ||
ensure_admin_auth_or_redirect(socket, current_user, fn socket -> | ||
if connected?(socket), do: schedule_next_update_data() | ||
|
||
socket | ||
|> assign(%{ | ||
phoenix_ddos_max_2min_requests: env_value_to_int("PHOENIX_DDOS_MAX_2MIN_REQUESTS"), | ||
phoenix_ddos_max_1hour_requests: env_value_to_int("PHOENIX_DDOS_MAX_1HOUR_REQUESTS"), | ||
phoenix_ddos_safelist_ips: env_value_to_list("PHOENIX_DDOS_SAFELIST_IPS"), | ||
phoenix_ddos_blocklist_ips: env_value_to_list("PHOENIX_DDOS_BLOCKLIST_IPS"), | ||
log_user_agent: env_value("LOG_USER_AGENT"), | ||
block_user_agent_keywords: env_value_to_list("BLOCK_USER_AGENT_KEYWORDS"), | ||
allow_user_agents: env_value_to_list("ALLOW_USER_AGENTS") | ||
}) | ||
|> update_data() | ||
end)} | ||
end | ||
|
||
@impl true | ||
def handle_info(:update_data, socket) do | ||
schedule_next_update_data() | ||
{:noreply, update_data(socket)} | ||
end | ||
|
||
defp schedule_next_update_data do | ||
Process.send_after(self(), :update_data, 1000) | ||
end | ||
|
||
defp update_data(socket) do | ||
assign(socket, | ||
last_updated_at: (Time.utc_now() |> Time.truncate(:second) |> to_string()) <> " UTC", | ||
ips_in_jail: ips_in_jail() | ||
) | ||
end | ||
|
||
@impl true | ||
def handle_event("bail_ip_from_jail", %{"ip" => ip}, socket) do | ||
# See https://github.com/xward/phoenix_ddos/blob/feb07469ce318214cddb8e88ac18b5f94b3e31f2/lib/phoenix_ddos/core/jail.ex#L36 | ||
PhoenixDDoS.Jail.bail_out(ip) | ||
{:noreply, socket} | ||
end | ||
|
||
defp ips_in_jail do | ||
# See https://github.com/xward/phoenix_ddos/blob/master/lib/phoenix_ddos/core/jail.ex | ||
{:ok, keys} = Cachex.keys(:phoenix_ddos_jail) | ||
keys |> Enum.reject(&String.starts_with?(&1, "suspicious_")) | ||
end | ||
|
||
defp env_value(env_value), do: System.get_env(env_value) | ||
|
||
defp env_value_to_int(env_name) do | ||
env_name |> System.get_env("500") |> Integer.parse() |> elem(0) | ||
end | ||
|
||
defp env_value_to_list(env_name) do | ||
case System.get_env(env_name, "") do | ||
"" -> "<vide>" | ||
value -> value | ||
end | ||
end | ||
end |
101 changes: 101 additions & 0 deletions
101
apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.html.heex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<section class="pb-48"> | ||
<div class="container"> | ||
<h2>Plug</h2> | ||
<p> | ||
Le plug qui gère la logique de rate limiting, bloquer ou autoriser des requêtes est dans <a | ||
href="https://github.com/etalab/transport-site/blob/master/apps/transport/lib/transport_web/plugs/rate_limiter.ex" | ||
target="_blank" | ||
><code>TransportWeb.Plugs.RateLimiter</code></a>. | ||
</p> | ||
<p> | ||
Le comptage des requêtes et le blocage d'une adresse IP est effectué par la librairie <a href="https://github.com/xward/phoenix_ddos"><code>phoenix_ddos</code></a>. Le backend est Cachex, qui utilise la RAM. Ainsi un redémarrage de l'application | ||
<code>prod-site</code> | ||
réinitialise les compteurs et les adresses IPs bloquées. | ||
</p> | ||
|
||
<h2>Configuration</h2> | ||
<p> | ||
Plusieurs variables d'environnement permettent de configurer le fonctionnement. Il faut changer ces variables pour ajuster le comportement puis redémarrer l'application. | ||
</p> | ||
|
||
<h4>Volume de requêtes</h4> | ||
<ul> | ||
<li> | ||
<code>PHOENIX_DDOS_MAX_2MIN_REQUESTS</code> | ||
: nombre de requêtes max autorisée par IP par période de 2 minutes. Valeur actuelle : <%= format_number( | ||
@phoenix_ddos_max_2min_requests | ||
) %> | ||
</li> | ||
<li> | ||
<code>PHOENIX_DDOS_MAX_1HOUR_REQUESTS</code> | ||
: nombre de requêtes max autorisée par IP par période d'1 heure. Valeur actuelle : <%= format_number( | ||
@phoenix_ddos_max_1hour_requests | ||
) %> | ||
</li> | ||
</ul> | ||
|
||
<h4>Adresses IPs autorisées ou bloquées</h4> | ||
|
||
<ul> | ||
<li> | ||
<code>PHOENIX_DDOS_SAFELIST_IPS</code> | ||
: liste d'adresses IP <strong>toujours autorisées</strong>. Les valeurs doivent être séparées par des <code>|</code>. Valeur actuelle : | ||
<code><%= @phoenix_ddos_safelist_ips %></code> | ||
</li> | ||
<li> | ||
<code>PHOENIX_DDOS_BLOCKLIST_IPS</code> | ||
: liste d'adresses IP <strong>toujours bloquées</strong>. Les valeurs doivent être séparées par des <code>|</code>. Valeur actuelle : | ||
<code><%= @phoenix_ddos_blocklist_ips %></code> | ||
</li> | ||
</ul> | ||
|
||
<h4>User-Agents</h4> | ||
|
||
<ul> | ||
<li> | ||
<code>LOG_USER_AGENT</code> | ||
: active ou désactive le fait de logguer les user agents. Valeurs possible : <code>true</code> | ||
ou <code>false</code>. Valeur actuelle : <code><%= @log_user_agent %></code> | ||
</li> | ||
<li> | ||
<code>ALLOW_USER_AGENTS</code> | ||
: user agents <strong>toujours autorisés</strong>. Les valeurs doivent être séparées par des <code>|</code>. Valeur actuelle : | ||
<code><%= @allow_user_agents %></code> | ||
</li> | ||
<li> | ||
<code>BLOCK_USER_AGENT_KEYWORDS</code> | ||
: user agents <strong>toujours bloqués</strong>. Les valeurs doivent être séparées par des <code>|</code>. Valeur actuelle : | ||
<code><%= @block_user_agent_keywords %></code> | ||
</li> | ||
</ul> | ||
|
||
<h2>Adresses IPs bloquées</h2> | ||
<p> | ||
<a href="https://github.com/xward/phoenix_ddos"><code>phoenix_ddos</code></a> | ||
est la dépendance qui gère l'ajout/le retrait de la jail. | ||
</p> | ||
|
||
<p :if={Enum.empty?(@ips_in_jail)}> | ||
Personne n'est bloqué actuellement. | ||
</p> | ||
|
||
<div :if={Enum.count(@ips_in_jail) > 0}> | ||
<p> | ||
Adresses IPs actuellement dans la jail : | ||
</p> | ||
|
||
<ul> | ||
<%= for ip <- @ips_in_jail do %> | ||
<li> | ||
<%= ip %> | ||
<button class="button small" phx-click="bail_ip_from_jail" phx-value-ip={ip}> | ||
Retirer de la jail | ||
</button> | ||
</li> | ||
<% end %> | ||
</ul> | ||
</div> | ||
<p class="small">Dernière mise à jour: <%= @last_updated_at %></p> | ||
</div> | ||
</section> | ||
<script defer type="text/javascript" src={static_path(@socket, "/js/app.js")} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
apps/transport/test/transport_web/live_views/rate_limiter_live_test.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
defmodule TransportWeb.Backoffice.RateLimiterLiveTest do | ||
use ExUnit.Case, async: true | ||
use TransportWeb.LiveCase | ||
import TransportWeb.ConnCase, only: [setup_admin_in_session: 1] | ||
|
||
@endpoint TransportWeb.Endpoint | ||
@url "/backoffice/rate_limiter" | ||
|
||
setup do | ||
{:ok, conn: build_conn()} | ||
end | ||
|
||
test "requires login", %{conn: conn} do | ||
conn | ||
|> get(@url) | ||
|> html_response(302) | ||
end | ||
|
||
test "page can load", %{conn: conn} do | ||
conn | ||
|> setup_admin_in_session() | ||
|> get(@url) | ||
|> html_response(200) | ||
end | ||
end |