diff --git a/debian/postinst b/debian/postinst index 300fdf46..af5ee097 100644 --- a/debian/postinst +++ b/debian/postinst @@ -25,6 +25,9 @@ case "$1" in sed -i '/^\s\+verify-schedule /d' /etc/proxmox-backup/datastore.cfg || true fi fi + if dpkg --compare-versions "$2" 'le' '0.9.5-1'; then + chown --quiet backup:backup /var/log/proxmox-backup/api/auth.log || true + fi fi # FIXME: Remove in future version once we're sure no broken entries remain in anyone's files if grep -q -e ':termproxy::[^@]\+: ' /var/log/proxmox-backup/tasks/active; then diff --git a/src/api2/access.rs b/src/api2/access.rs index 9b9e85c0..3b59b3d3 100644 --- a/src/api2/access.rs +++ b/src/api2/access.rs @@ -12,7 +12,6 @@ use proxmox::{http_err, list_subdirs_api_method}; use crate::tools::ticket::{self, Empty, Ticket}; use crate::auth_helpers::*; use crate::api2::types::*; -use crate::tools::{FileLogOptions, FileLogger}; use crate::config::acl as acl_config; use crate::config::acl::{PRIVILEGES, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY}; @@ -144,20 +143,13 @@ fn create_ticket( port: Option, rpcenv: &mut dyn RpcEnvironment, ) -> Result { - let logger_options = FileLogOptions { - append: true, - prefix_time: true, - ..Default::default() - }; - let mut auth_log = FileLogger::new("/var/log/proxmox-backup/api/auth.log", logger_options)?; - match authenticate_user(&username, &password, path, privs, port) { Ok(true) => { let ticket = Ticket::new("PBS", &username)?.sign(private_auth_key(), None)?; let token = assemble_csrf_prevention_token(csrf_secret(), &username); - auth_log.log(format!("successful auth for user '{}'", username)); + crate::server::rest::auth_logger()?.log(format!("successful auth for user '{}'", username)); Ok(json!({ "username": username, @@ -180,7 +172,7 @@ fn create_ticket( username, err.to_string() ); - auth_log.log(&msg); + crate::server::rest::auth_logger()?.log(&msg); log::error!("{}", msg); Err(http_err!(UNAUTHORIZED, "permission check failed.")) diff --git a/src/buildcfg.rs b/src/buildcfg.rs index 402f2c9d..c7e65032 100644 --- a/src/buildcfg.rs +++ b/src/buildcfg.rs @@ -16,9 +16,14 @@ pub const PROXMOX_BACKUP_RUN_DIR: &str = PROXMOX_BACKUP_RUN_DIR_M!(); /// namespaced directory for persistent logging pub const PROXMOX_BACKUP_LOG_DIR: &str = PROXMOX_BACKUP_LOG_DIR_M!(); -/// logfile for all API reuests handled by the proxy and privileged API daemons +/// logfile for all API reuests handled by the proxy and privileged API daemons. Note that not all +/// failed logins can be logged here with full information, use the auth log for that. pub const API_ACCESS_LOG_FN: &str = concat!(PROXMOX_BACKUP_LOG_DIR_M!(), "/api/access.log"); +/// logfile for any failed authentication, via ticket or via token, and new successfull ticket +/// creations. This file can be useful for fail2ban. +pub const API_AUTH_LOG_FN: &str = concat!(PROXMOX_BACKUP_LOG_DIR_M!(), "/api/auth.log"); + /// the PID filename for the unprivileged proxy daemon pub const PROXMOX_BACKUP_PROXY_PID_FN: &str = concat!(PROXMOX_BACKUP_RUN_DIR_M!(), "/proxy.pid"); diff --git a/src/server/rest.rs b/src/server/rest.rs index 0749b891..ea87c9c8 100644 --- a/src/server/rest.rs +++ b/src/server/rest.rs @@ -164,6 +164,15 @@ fn log_response( )); } } +pub fn auth_logger() -> Result { + let logger_options = tools::FileLogOptions { + append: true, + prefix_time: true, + owned_by_backup: true, + ..Default::default() + }; + FileLogger::new(crate::buildcfg::API_AUTH_LOG_FN, logger_options) +} fn get_proxied_peer(headers: &HeaderMap) -> Option { lazy_static! { @@ -687,6 +696,10 @@ async fn handle_request( match auth_result { Ok(authid) => rpcenv.set_auth_id(Some(authid.to_string())), Err(err) => { + let peer = peer.ip(); + auth_logger()? + .log(format!("authentication failure; rhost={} msg={}", peer, err)); + // always delay unauthorized calls by 3 seconds (from start of request) let err = http_err!(UNAUTHORIZED, "authentication failed - {}", err); tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;