diff --git a/README.md b/README.md index 52a7d00..7a9b194 100644 --- a/README.md +++ b/README.md @@ -60,30 +60,41 @@ Built on Rust, on top of **Cloudflare’s Pingora engine**, **Aralez** delivers ### `main.yaml` -| Key | Example Value | Description | -|----------------------------------|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **threads** | 12 | Number of running daemon threads. Optional, defaults to 1 | -| **runuser** | aralez | Optional. Username for running aralez after dropping root privileges (requires launch as root) | -| **rungroup** | aralez | Optional. Group for running aralez after dropping root privileges (requires launch as root) | -| **daemon** | false | Run in background (boolean) | -| **upstream_keepalive_pool_size** | 500 | Pool size for upstream keepalive connections | -| **pid_file** | /tmp/aralez.pid | Path to PID file | -| **config_address** | 0.0.0.0:3000 | HTTP API address for pushing upstreams.yaml from remote location | -| **proxy_tls_grade** | high, medium, unsafe | Grade of TLS ciphers. `high` matches Qualys SSL Labs A+ (defaults to `medium`) | -| **proxy_address_http** | 0.0.0.0:6193 | Aralez HTTP bind address | -| **proxy_address_tls** | 0.0.0.0:6194 | Aralez HTTPS bind address (Optional) | -| **proxy_configs** | /etc/aralez/ | Direcotry containing configuration files, must be writeable by user `aralez` | -| **upstreams_conf** | /etc/aralez/upstreams.yaml | Location of the upstreams file | -| **access_log** | access | Configure access logging. Values: `access, error` | -| **log_level** | info | Log level: `info`, `warn`, `error`, `debug`, `trace`, `off` | -| **log_file** | /tmp/aralez.log, 20, 5, compress | Optional, the location of log file, file size in megabytes, number of log files to keep, compress files .valueas are separated by comma. Defaults to None, 100, 5, No | -| **hc_method** | HEAD | Healthcheck method: HEAD, GET, POST (UPPERCASE) | -| **hc_interval** | 2 | Interval for health checks in seconds | -| **file_server_folder** | /some/local/folder | Optional. Local folder to serve | -| **file_server_address** | 127.0.0.1:3002 | Optional. Local address for file server | -| **config_api_enabled** | true | Enable/disable remote config push capability | -| **cache_size_mb** | 50 | Optional. Enable internal cache with size in megabytes of value. Cache is entirely disabled when this line is commented out. | -| **cache_ttl** | 10 | Optional. Set Default TTL in seconds for cached items, works if cache control headers are not set via upstream. Defaults to 60 if cache_size_mb is set. | +| Key | Example Value | Description | +|----------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **threads** | `12` | Number of running daemon threads. Optional, defaults to 1 | +| **runuser** | `aralez` | Optional. Username for running aralez after dropping root privileges (requires launch as root) | +| **rungroup** | `aralez` | Optional. Group for running aralez after dropping root privileges (requires launch as root) | +| **daemon** | `false` | Run in background (boolean) | +| **upstream_keepalive_pool_size** | `500` | Pool size for upstream keepalive connections | +| **pid_file** | `/tmp/aralez.pid` | Path to PID file | +| **upgrade_sock** | `/tmp/aralez.sock` | Path to socket file | +| **config_address** | `0.0.0.0:3000` | HTTP API address for pushing upstreams.yaml from remote location | +| **proxy_tls_grade** | `high, medium, unsafe` | Grade of TLS ciphers. `high` matches Qualys SSL Labs A+ (defaults to `medium`) | +| **proxy_address_http** | `0.0.0.0:6193` | Aralez HTTP bind address | +| **proxy_address_tls** | `0.0.0.0:6194` | Aralez HTTPS bind address (Optional) | +| **proxy_configs** | `/etc/aralez/` | Direcotry containing configuration files, must be writeable by user `aralez` | +| **upstreams_conf** | `/etc/aralez/upstreams.yaml` | Location of the upstreams file | +| **access_log** | `access` | Configure access logging. Values: `access, error` | +| **log_level** | `info` | Log level: `info`, `warn`, `error`, `debug`, `trace`, `off` | +| **log_file** | `/tmp/aralez.log, 20, 5, compress` | Optional, the location of log file, file size in megabytes, number of log files to keep, compress files .valueas are separated by comma. Defaults to None, 100, 5, No | +| **log_pattern** | `{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}` | Optional log pattern, defaults to `{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}`. See log4rs official [documentation](https://docs.rs/log4rs/latest/log4rs/encode/pattern/struct.PatternEncoderDeserializer.html#configuration) | +| **hc_method** | `HEAD` | Healthcheck method: HEAD, GET, POST (UPPERCASE) | +| **hc_interval** | `2` | Interval for health checks in seconds | +| **file_server_folder** | `/some/local/folder` | Optional. Local folder to serve | +| **file_server_address** | `127.0.0.1:3002` | Optional. Local address for file server | +| **config_api_enabled** | `true` | Enable/disable remote config push capability | +| **cache_size_mb** | `50` | Optional. Enable internal cache with size in megabytes of value. Cache is entirely disabled when this line is commented out. | +| **cache_enabled** | `bool` | Optional. Disabled by default | +| **cache_storage** | `memory, redis://host:port` | Optional Defaults to memory works with Redis, Valkey, Dragonfly (requires redis:// prefix) | +| **cache_ttl** | `60` | Optional. Set internal cache with size in megabytes of value. Defaults to 50Mb if cache_enabled: true | +| **tcp_keepalive_idle** | `60` | Seconds of inactivity before the kernel starts sending keepalive probes to a downstream client. Defaults to 60 | +| **tcp_keepalive_interval** | `10` | Seconds between individual keepalive probes if the client does not respond. Defaults to 10 | +| **tcp_keepalive_count** | `5` | Number of unanswered probes before the kernel declares the connection dead and closes it. Defaults to 5 | +| **cluster_member** | `master, worker` | Optional. Enables cluster mode, Sets node type to master or worker. Disabled by default | +| **worker_nodes** | `http(s)://host:port,http(s)://host:port` | Required is if cluster_member: master. Comma separated list of worker nodes http(s)://host:port | +| **log_structured** | `elasticsearch` | Optional. Enables structured logging and sets backend type. Only elasticsearch et the moment. | +| **acme_dns_provider** | `cloudflare, route53, digitalocean, etc` | Optional. Enable ACME DNS-01 challenge, sets DNS provider. ONly coudflare, route53, digitalocean at the moment. | --- diff --git a/etc/main.yaml b/etc/main.yaml index 9716122..91873c1 100644 --- a/etc/main.yaml +++ b/etc/main.yaml @@ -14,15 +14,15 @@ config_api_enabled: true # Boolean to enable/disable remote config push capabili config_address: 127.0.0.1:3000 # HTTP API address for pushing upstreams.yaml from remote location proxy_address_http: 0.0.0.0:80 # Proxy HTTP bind address proxy_address_tls: 0.0.0.0:443 # Optional, Proxy TLS bind address -proxy_configs: /opt/aralez/asyncweb/etc # Mandatory if proxy_address_tls set, should contain a certificate and key files strictly in a format {NAME}.crt, {NAME}.key. +proxy_configs: /opt/aralez/etc # Mandatory if proxy_address_tls set, should contain a certificate and key files strictly in a format {NAME}.crt, {NAME}.key. proxy_tls_grade: high # Grade of TLS suite for proxy (high, medium, unsafe), matching grades of Qualys SSL Labs upstreams_conf: /opt/aralez/etc/upstreams.yaml # the location of upstreams file file_server_folder: /opt/aralez/public # Optional, local folder to serve -file_server_address: 0.0.0.0:3002 # Optional, Local address for file server. Can set as upstream for public access. +file_server_address: 127.0.0.1:3002 # Optional, Local address for file server. Can set as upstream for public access. log_level: info # info, warn, error, debug, trace, off log_file: /tmp/aralez.log, 20, 5, compress # Optional, the location of log file, file size in megabytes, number of log files to keep, compress files .valueas are separated by comma. log_pattern: "{d(%Y-%m-%d %H:%M:%S)} {h({l})} {t} - {m} {n}" # Optional log pattern, defaults to "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}" -access_log: error # all, error, (Off if commented) +access_log: error # all, error, (Off by default) hc_method: HEAD # Healthcheck method (HEAD, GET, POST are supported) UPPERCASE hc_interval: 2 #Interval for health checks in seconds tcp_keepalive_idle: 60 # Seconds of inactivity before the kernel starts sending keepalive probes to a downstream client diff --git a/etc/upstreams.yaml b/etc/upstreams.yaml index fdc2b21..e5a7a3e 100644 --- a/etc/upstreams.yaml +++ b/etc/upstreams.yaml @@ -130,7 +130,7 @@ upstreams: "/": healthcheck: false servers: - - "127.0.0.1:3000" + - "127.0.0.1:8000" "/.well-known/acme-challenge": healthcheck: false servers: diff --git a/src/core/webserver.rs b/src/core/webserver.rs index 82d1923..05ce37a 100644 --- a/src/core/webserver.rs +++ b/src/core/webserver.rs @@ -6,7 +6,9 @@ use crate::utils::metrics::{MEMORY_USAGE, OPEN_FILES, get_memory_usage, get_open use crate::utils::tools::{Die, upstreams_liveness_json, upstreams_to_json}; use crate::utils::types::{Config, Configuration, UpstreamsDashMap}; use axum::body::Body; +use axum::extract::ConnectInfo; use axum::extract::{Query, State}; +use axum::http::HeaderMap; use axum::http::{Response, StatusCode}; use axum::response::IntoResponse; use axum::routing::{any, get, post}; @@ -106,31 +108,45 @@ pub async fn run_server(config: &APIUpstreamProvider, mut to_return: mpsc::Sende info!("Exiting..."); } -async fn conf(State(st): State, Query(params): Query>, content: String) -> impl IntoResponse { +async fn conf( + State(st): State, + ConnectInfo(addr): ConnectInfo, + Query(params): Query>, + headers: HeaderMap, + content: String, +) -> impl IntoResponse { if !st.config_api_enabled { return (StatusCode::FORBIDDEN, "Config API is disabled !\n").into_response(); } + let api_key = headers.get("API-KEY").and_then(|v| v.to_str().ok()); + let query_key = params.get("key").map(|k| k.as_str()); + let authorized = match st.master_key.as_deref() { + Some(master_key) if !master_key.is_empty() => api_key == Some(master_key) || query_key == Some(master_key), + _ => false, + }; + if !authorized { + warn!("Unauthorised access to /conf endpoint from {}", addr.ip()); + return (StatusCode::UNAUTHORIZED, "Unauthorized: Invalid API-KEY\n").into_response(); + } + let strcontent = content.as_str(); let parsed = noyalib::from_str::(strcontent); match parsed { Ok(_) => { - if params.contains_key("save") { - tokio::spawn(async move { apply_config(content.as_str(), st, true).await }); - } else { - tokio::spawn(async move { apply_config(content.as_str(), st, false).await }); - } + let save = params.contains_key("save"); + tokio::spawn(async move { + apply_config(&content, st, save).await; + }); (StatusCode::OK, "Accepted! Applying in background\n").into_response() } Err(err) => { error!("Failed to parse upstreams file: {}", err); - (StatusCode::BAD_GATEWAY, format!("Failed: {}\n", err)).into_response() + (StatusCode::BAD_REQUEST, format!("Failed: {}\n", err)).into_response() } } } -use axum::extract::ConnectInfo; -use axum::http::HeaderMap; async fn workerconf(State(st): State, ConnectInfo(addr): ConnectInfo, headers: HeaderMap, content: String) -> impl IntoResponse { let api_key = headers.get("API-KEY").and_then(|v| v.to_str().ok()); if api_key != st.master_key.as_deref() {