瀏覽代碼

Merge branch '1668-prometheus-access-restrictions' into 'develop'

[#1668] App metrics endpoint (Prometheus) access restrictions

Closes #1668

See merge request pleroma/pleroma!3093
tags/v2.2.0^2
feld rinpatch 3 年之前
父節點
當前提交
86b4149a13
共有 7 個檔案被更改,包括 203 行新增21 行删除
  1. +14
    -12
      CHANGELOG.md
  2. +6
    -1
      config/config.exs
  3. +37
    -0
      config/description.exs
  4. +24
    -2
      docs/API/prometheus.md
  5. +19
    -0
      lib/pleroma/helpers/inet_helper.ex
  6. +34
    -6
      lib/pleroma/web/endpoint.ex
  7. +69
    -0
      test/pleroma/web/endpoint/metrics_exporter_test.exs

+ 14
- 12
CHANGELOG.md 查看文件

@@ -5,14 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [2.2.0] - 2020-10-??

### Added
- Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
- Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
- Mix task option for force-unfollowing relays

### Changed

- **Breaking** Requires `libmagic` (or `file`) to guess file types.
- **Breaking:** App metrics endpoint (`/api/pleroma/app_metrics`) is disabled by default, check `docs/API/prometheus.md` on enabling and configuring.
- **Breaking:** Pleroma Admin API: emoji packs and files routes changed.
- **Breaking:** Sensitive/NSFW statuses no longer disable link previews.
- API: Empty parameter values for integer parameters are now ignored in non-strict validaton mode.
@@ -24,9 +20,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Minimum lifetime for ephmeral activities changed to 10 minutes and made configurable (`:min_lifetime` option).
- Introduced optional dependencies on `ffmpeg`, `ImageMagick`, `exiftool` software packages. Please refer to `docs/installation/optional/media_graphics_packages.md`.

### Removed

- **Breaking:** `Pleroma.Workers.Cron.StatsWorker` setting from Oban `:crontab` (moved to a simpler implementation).
- **Breaking:** `Pleroma.Workers.Cron.ClearOauthTokenWorker` setting from Oban `:crontab` (moved to scheduled jobs).
- **Breaking:** `Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker` setting from Oban `:crontab` (moved to scheduled jobs).
- Removed `:managed_config` option. In practice, it was accidentally removed with 2.0.0 release when frontends were
switched to a new configuration mechanism, however it was not officially removed until now.

### Added
- Media preview proxy (requires `ffmpeg` and `ImageMagick` to be installed and media proxy to be enabled; see `:media_preview_proxy` config for more details).
- Pleroma API: Importing the mutes users from CSV files.
- Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
- Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
- Mix task option for force-unfollowing relays
- App metrics: ability to restrict access to specified IP whitelist.


<details>
<summary>API Changes</summary>
@@ -37,13 +46,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

</details>

### Removed

- **Breaking:** `Pleroma.Workers.Cron.StatsWorker` setting from Oban `:crontab` (moved to a simpler implementation).
- **Breaking:** `Pleroma.Workers.Cron.ClearOauthTokenWorker` setting from Oban `:crontab` (moved to scheduled jobs).
- **Breaking:** `Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker` setting from Oban `:crontab` (moved to scheduled jobs).
- Removed `:managed_config` option. In practice, it was accidentally removed with 2.0.0 release when frontends were
switched to a new configuration mechanism, however it was not officially removed until now.

### Fixed



+ 6
- 1
config/config.exs 查看文件

@@ -637,7 +637,12 @@ config :pleroma, Pleroma.Emails.UserEmail,

config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false

config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter,
enabled: false,
auth: false,
ip_whitelist: [],
path: "/api/pleroma/app_metrics",
format: :text

config :pleroma, Pleroma.ScheduledActivity,
daily_user_limit: 25,


+ 37
- 0
config/description.exs 查看文件

@@ -3709,5 +3709,42 @@ config :pleroma, :config_description, [
suggestions: [2]
}
]
},
%{
group: :prometheus,
key: Pleroma.Web.Endpoint.MetricsExporter,
type: :group,
description: "Prometheus app metrics endpoint configuration",
children: [
%{
key: :enabled,
type: :boolean,
description: "[Pleroma extension] Enables app metrics endpoint."
},
%{
key: :ip_whitelist,
type: [{:list, :string}, {:list, :charlist}, {:list, :tuple}],
description:
"[Pleroma extension] If non-empty, restricts access to app metrics endpoint to specified IP addresses."
},
%{
key: :auth,
type: [:boolean, :tuple],
description: "Enables HTTP Basic Auth for app metrics endpoint.",
suggestion: [false, {:basic, "myusername", "mypassword"}]
},
%{
key: :path,
type: :string,
description: "App metrics endpoint URI path.",
suggestions: ["/api/pleroma/app_metrics"]
},
%{
key: :format,
type: :atom,
description: "App metrics endpoint output format.",
suggestions: [:text, :protobuf]
}
]
}
]

+ 24
- 2
docs/API/prometheus.md 查看文件

@@ -2,15 +2,37 @@

Pleroma includes support for exporting metrics via the [prometheus_ex](https://github.com/deadtrickster/prometheus.ex) library.

Config example:

```
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter,
enabled: true,
auth: {:basic, "myusername", "mypassword"},
ip_whitelist: ["127.0.0.1"],
path: "/api/pleroma/app_metrics",
format: :text
```

* `enabled` (Pleroma extension) enables the endpoint
* `ip_whitelist` (Pleroma extension) could be used to restrict access only to specified IPs
* `auth` sets the authentication (`false` for no auth; configurable to HTTP Basic Auth, see [prometheus-plugs](https://github.com/deadtrickster/prometheus-plugs#exporting) documentation)
* `format` sets the output format (`:text` or `:protobuf`)
* `path` sets the path to app metrics page


## `/api/pleroma/app_metrics`

### Exports Prometheus application metrics

* Method: `GET`
* Authentication: not required
* Authentication: not required by default (see configuration options above)
* Params: none
* Response: JSON
* Response: text

## Grafana

### Config example

The following is a config example to use with [Grafana](https://grafana.com)

```


+ 19
- 0
lib/pleroma/helpers/inet_helper.ex 查看文件

@@ -0,0 +1,19 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Helpers.InetHelper do
def parse_address(ip) when is_tuple(ip) do
{:ok, ip}
end

def parse_address(ip) when is_binary(ip) do
ip
|> String.to_charlist()
|> parse_address()
end

def parse_address(ip) do
:inet.parse_address(ip)
end
end

+ 34
- 6
lib/pleroma/web/endpoint.ex 查看文件

@@ -7,6 +7,8 @@ defmodule Pleroma.Web.Endpoint do

require Pleroma.Constants

alias Pleroma.Config

socket("/socket", Pleroma.Web.UserSocket)

plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint])
@@ -88,19 +90,19 @@ defmodule Pleroma.Web.Endpoint do
plug(Plug.Parsers,
parsers: [
:urlencoded,
{:multipart, length: {Pleroma.Config, :get, [[:instance, :upload_limit]]}},
{:multipart, length: {Config, :get, [[:instance, :upload_limit]]}},
:json
],
pass: ["*/*"],
json_decoder: Jason,
length: Pleroma.Config.get([:instance, :upload_limit]),
length: Config.get([:instance, :upload_limit]),
body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
)

plug(Plug.MethodOverride)
plug(Plug.Head)

secure_cookies = Pleroma.Config.get([__MODULE__, :secure_cookie_flag])
secure_cookies = Config.get([__MODULE__, :secure_cookie_flag])

cookie_name =
if secure_cookies,
@@ -108,7 +110,7 @@ defmodule Pleroma.Web.Endpoint do
else: "pleroma_key"

extra =
Pleroma.Config.get([__MODULE__, :extra_cookie_attrs])
Config.get([__MODULE__, :extra_cookie_attrs])
|> Enum.join(";")

# The session will be stored in the cookie and signed,
@@ -118,7 +120,7 @@ defmodule Pleroma.Web.Endpoint do
Plug.Session,
store: :cookie,
key: cookie_name,
signing_salt: Pleroma.Config.get([__MODULE__, :signing_salt], "CqaoopA2"),
signing_salt: Config.get([__MODULE__, :signing_salt], "CqaoopA2"),
http_only: true,
secure: secure_cookies,
extra: extra
@@ -138,8 +140,34 @@ defmodule Pleroma.Web.Endpoint do
use Prometheus.PlugExporter
end

defmodule MetricsExporterCaller do
@behaviour Plug

def init(opts), do: opts

def call(conn, opts) do
prometheus_config = Application.get_env(:prometheus, MetricsExporter, [])
ip_whitelist = List.wrap(prometheus_config[:ip_whitelist])

cond do
!prometheus_config[:enabled] ->
conn

ip_whitelist != [] and
!Enum.find(ip_whitelist, fn ip ->
Pleroma.Helpers.InetHelper.parse_address(ip) == {:ok, conn.remote_ip}
end) ->
conn

true ->
MetricsExporter.call(conn, opts)
end
end
end

plug(PipelineInstrumenter)
plug(MetricsExporter)

plug(MetricsExporterCaller)

plug(Pleroma.Web.Router)



+ 69
- 0
test/pleroma/web/endpoint/metrics_exporter_test.exs 查看文件

@@ -0,0 +1,69 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.Endpoint.MetricsExporterTest do
use Pleroma.Web.ConnCase

alias Pleroma.Web.Endpoint.MetricsExporter

defp config do
Application.get_env(:prometheus, MetricsExporter)
end

describe "with default config" do
test "does NOT expose app metrics", %{conn: conn} do
conn
|> get(config()[:path])
|> json_response(404)
end
end

describe "when enabled" do
setup do
initial_config = config()
on_exit(fn -> Application.put_env(:prometheus, MetricsExporter, initial_config) end)

Application.put_env(
:prometheus,
MetricsExporter,
Keyword.put(initial_config, :enabled, true)
)
end

test "serves app metrics", %{conn: conn} do
conn = get(conn, config()[:path])
assert response = response(conn, 200)

for metric <- [
"http_requests_total",
"http_request_duration_microseconds",
"phoenix_controller_render_duration",
"phoenix_controller_call_duration",
"telemetry_scrape_duration",
"erlang_vm_memory_atom_bytes_total"
] do
assert response =~ ~r/#{metric}/
end
end

test "when IP whitelist configured, " <>
"serves app metrics only if client IP is whitelisted",
%{conn: conn} do
Application.put_env(
:prometheus,
MetricsExporter,
Keyword.put(config(), :ip_whitelist, ["127.127.127.127", {1, 1, 1, 1}, '255.255.255.255'])
)

conn
|> get(config()[:path])
|> json_response(404)

conn
|> Map.put(:remote_ip, {127, 127, 127, 127})
|> get(config()[:path])
|> response(200)
end
end
end

Loading…
取消
儲存