api: factor out auth logger and use for all API authentication failures
we have information here not available in the access log, especially if the /api2/extjs formatter is used, which encapsulates errors in a 200 response. So keep the auth log for now, but extend it use from create ticket calls to all authentication failures for API calls, this ensures one can also fail2ban tokens. Do that logging in a central place, which makes it simple but means that we do not have the user ID information available to include in the log. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
385681c9ab
commit
4fdf13f95f
|
@ -25,6 +25,9 @@ case "$1" in
|
||||||
sed -i '/^\s\+verify-schedule /d' /etc/proxmox-backup/datastore.cfg || true
|
sed -i '/^\s\+verify-schedule /d' /etc/proxmox-backup/datastore.cfg || true
|
||||||
fi
|
fi
|
||||||
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
|
fi
|
||||||
# FIXME: Remove in future version once we're sure no broken entries remain in anyone's files
|
# 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
|
if grep -q -e ':termproxy::[^@]\+: ' /var/log/proxmox-backup/tasks/active; then
|
||||||
|
|
|
@ -12,7 +12,6 @@ use proxmox::{http_err, list_subdirs_api_method};
|
||||||
use crate::tools::ticket::{self, Empty, Ticket};
|
use crate::tools::ticket::{self, Empty, Ticket};
|
||||||
use crate::auth_helpers::*;
|
use crate::auth_helpers::*;
|
||||||
use crate::api2::types::*;
|
use crate::api2::types::*;
|
||||||
use crate::tools::{FileLogOptions, FileLogger};
|
|
||||||
|
|
||||||
use crate::config::acl as acl_config;
|
use crate::config::acl as acl_config;
|
||||||
use crate::config::acl::{PRIVILEGES, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
|
use crate::config::acl::{PRIVILEGES, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
|
||||||
|
@ -144,20 +143,13 @@ fn create_ticket(
|
||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
rpcenv: &mut dyn RpcEnvironment,
|
rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
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) {
|
match authenticate_user(&username, &password, path, privs, port) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let ticket = Ticket::new("PBS", &username)?.sign(private_auth_key(), None)?;
|
let ticket = Ticket::new("PBS", &username)?.sign(private_auth_key(), None)?;
|
||||||
|
|
||||||
let token = assemble_csrf_prevention_token(csrf_secret(), &username);
|
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!({
|
Ok(json!({
|
||||||
"username": username,
|
"username": username,
|
||||||
|
@ -180,7 +172,7 @@ fn create_ticket(
|
||||||
username,
|
username,
|
||||||
err.to_string()
|
err.to_string()
|
||||||
);
|
);
|
||||||
auth_log.log(&msg);
|
crate::server::rest::auth_logger()?.log(&msg);
|
||||||
log::error!("{}", msg);
|
log::error!("{}", msg);
|
||||||
|
|
||||||
Err(http_err!(UNAUTHORIZED, "permission check failed."))
|
Err(http_err!(UNAUTHORIZED, "permission check failed."))
|
||||||
|
|
|
@ -16,9 +16,14 @@ pub const PROXMOX_BACKUP_RUN_DIR: &str = PROXMOX_BACKUP_RUN_DIR_M!();
|
||||||
/// namespaced directory for persistent logging
|
/// namespaced directory for persistent logging
|
||||||
pub const PROXMOX_BACKUP_LOG_DIR: &str = PROXMOX_BACKUP_LOG_DIR_M!();
|
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");
|
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
|
/// the PID filename for the unprivileged proxy daemon
|
||||||
pub const PROXMOX_BACKUP_PROXY_PID_FN: &str = concat!(PROXMOX_BACKUP_RUN_DIR_M!(), "/proxy.pid");
|
pub const PROXMOX_BACKUP_PROXY_PID_FN: &str = concat!(PROXMOX_BACKUP_RUN_DIR_M!(), "/proxy.pid");
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,15 @@ fn log_response(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn auth_logger() -> Result<FileLogger, Error> {
|
||||||
|
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<std::net::SocketAddr> {
|
fn get_proxied_peer(headers: &HeaderMap) -> Option<std::net::SocketAddr> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -687,6 +696,10 @@ async fn handle_request(
|
||||||
match auth_result {
|
match auth_result {
|
||||||
Ok(authid) => rpcenv.set_auth_id(Some(authid.to_string())),
|
Ok(authid) => rpcenv.set_auth_id(Some(authid.to_string())),
|
||||||
Err(err) => {
|
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)
|
// always delay unauthorized calls by 3 seconds (from start of request)
|
||||||
let err = http_err!(UNAUTHORIZED, "authentication failed - {}", err);
|
let err = http_err!(UNAUTHORIZED, "authentication failed - {}", err);
|
||||||
tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;
|
tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;
|
||||||
|
|
Loading…
Reference in New Issue