mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-26 00:24:55 +01:00
Implement a simple audit log
This commit is contained in:
parent
19abba371e
commit
4858a6a6fb
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -401,7 +401,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"time",
|
"time 0.1.43",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -532,7 +532,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diflouroborane"
|
name = "diflouroborane"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"async-rustls",
|
"async-rustls",
|
||||||
@ -561,12 +561,14 @@ dependencies = [
|
|||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_dhall",
|
"serde_dhall",
|
||||||
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-async",
|
"slog-async",
|
||||||
"slog-term",
|
"slog-term",
|
||||||
"smol",
|
"smol",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"time 0.3.5",
|
||||||
"toml",
|
"toml",
|
||||||
"uuid",
|
"uuid",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
@ -1077,6 +1079,12 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.55"
|
version = "0.3.55"
|
||||||
@ -1725,6 +1733,17 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.74"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha-1"
|
name = "sha-1"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@ -1974,6 +1993,16 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -38,6 +38,9 @@ flexbuffers = "2.0.0"
|
|||||||
bincode = "2.0.0-dev"
|
bincode = "2.0.0-dev"
|
||||||
|
|
||||||
serde_dhall = { version = "0.10.1", default-features = false }
|
serde_dhall = { version = "0.10.1", default-features = false }
|
||||||
|
# Audit log uses serde_json for now
|
||||||
|
serde_json = "1.0.74"
|
||||||
|
time = { version = "0.3.5", features = ["serde"] }
|
||||||
|
|
||||||
uuid = { version = "0.8.2", features = ["serde", "v4"] }
|
uuid = { version = "0.8.2", features = ["serde", "v4"] }
|
||||||
|
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
-- access into them.
|
-- access into them.
|
||||||
db_path = "/tmp/bffh",
|
db_path = "/tmp/bffh",
|
||||||
|
|
||||||
|
-- Audit log path. Bffh will log state changes into this file, one per line.
|
||||||
|
-- Audit log entries are for now JSON:
|
||||||
|
-- {"timestamp":1641497361,"machine":"Testmachine","state":{"state":{"InUse":{"uid":"Testuser","subuid":null,"realm":null}}}}
|
||||||
|
auditlog_path = "/tmp/bffh.audit",
|
||||||
|
|
||||||
-- In dhall you can also easily import definitions from other files, e.g. you could write
|
-- In dhall you can also easily import definitions from other files, e.g. you could write
|
||||||
-- roles = ./roles.dhall
|
-- roles = ./roles.dhall
|
||||||
roles = {
|
roles = {
|
||||||
@ -192,14 +197,14 @@
|
|||||||
-- Initiators are configured almost the same way as Actors, refer to actor documentation for more details
|
-- Initiators are configured almost the same way as Actors, refer to actor documentation for more details
|
||||||
-- The below '{=}' is what you need if you want to define *no* initiators at all and only use the API with apps
|
-- The below '{=}' is what you need if you want to define *no* initiators at all and only use the API with apps
|
||||||
-- to let people use machines.
|
-- to let people use machines.
|
||||||
initiators = {=},
|
-- initiators = {=},
|
||||||
-- The "Dummy" initiator will try to use and return a machine as the given user every few seconds. It's good to
|
-- The "Dummy" initiator will try to use and return a machine as the given user every few seconds. It's good to
|
||||||
-- test your system but will spam your log so is disabled by default.
|
-- test your system but will spam your log so is disabled by default.
|
||||||
--{ Initiator = { module = "Dummy", params = { uid = "Testuser" } } }
|
initiators = { Initiator = { module = "Dummy", params = { uid = "Testuser" } } },
|
||||||
|
|
||||||
-- Linking up machines to initiators. Similar to actors a machine can have several initiators assigned but an
|
-- Linking up machines to initiators. Similar to actors a machine can have several initiators assigned but an
|
||||||
-- initiator can only be assigned to one machine.
|
-- initiator can only be assigned to one machine.
|
||||||
-- The below is once again how you have to define *no* initiators.
|
-- The below is once again how you have to define *no* initiators.
|
||||||
init_connections = [] : List { machine : Text, initiator : Text }
|
--init_connections = [] : List { machine : Text, initiator : Text }
|
||||||
-- init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
|
init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
|
||||||
}
|
}
|
43
src/audit.rs
Normal file
43
src/audit.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io;
|
||||||
|
use std::io::{LineWriter, Write};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::time::Instant;
|
||||||
|
use crate::Config;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use serde_json::Serializer;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
use crate::db::machine::{MachineIdentifier, MachineState};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AuditLog {
|
||||||
|
writer: Mutex<LineWriter<File>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AuditLogLine {
|
||||||
|
timestamp: i64,
|
||||||
|
machine: MachineIdentifier,
|
||||||
|
state: MachineState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuditLog {
|
||||||
|
pub fn new(config: &Config) -> io::Result<Self> {
|
||||||
|
let fd = OpenOptions::new().create(true).append(true).open(&config.auditlog_path)?;
|
||||||
|
let writer = Mutex::new(LineWriter::new(fd));
|
||||||
|
Ok(Self { writer })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log(&self, machine: &MachineIdentifier, state: &MachineState) -> io::Result<()> {
|
||||||
|
let timestamp = OffsetDateTime::now_utc().unix_timestamp();
|
||||||
|
let line = AuditLogLine { timestamp, machine: machine.clone(), state: state.clone() };
|
||||||
|
|
||||||
|
let mut guard = self.writer.lock().unwrap();
|
||||||
|
let mut writer: &mut LineWriter<File> = &mut *guard;
|
||||||
|
|
||||||
|
let mut ser = Serializer::new(&mut writer);
|
||||||
|
line.serialize(&mut ser).expect("failed to serialize audit log line");
|
||||||
|
writer.write("\n".as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,7 @@ pub struct Config {
|
|||||||
pub init_connections: Box<[InitiatorConn]>,
|
pub init_connections: Box<[InitiatorConn]>,
|
||||||
|
|
||||||
pub db_path: PathBuf,
|
pub db_path: PathBuf,
|
||||||
|
pub auditlog_path: PathBuf,
|
||||||
|
|
||||||
pub roles: HashMap<String, RoleConfig>,
|
pub roles: HashMap<String, RoleConfig>,
|
||||||
|
|
||||||
@ -136,6 +137,7 @@ impl Default for Config {
|
|||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
auditlog_path: PathBuf::from("/var/log/bffh/audit.log"),
|
||||||
db_path: PathBuf::from("/run/bffh/database"),
|
db_path: PathBuf::from("/run/bffh/database"),
|
||||||
roles: HashMap::new(),
|
roles: HashMap::new(),
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use crate::db::user::UserId;
|
|||||||
|
|
||||||
pub mod internal;
|
pub mod internal;
|
||||||
use internal::Internal;
|
use internal::Internal;
|
||||||
|
use crate::audit::AuditLog;
|
||||||
|
|
||||||
pub type MachineIdentifier = String;
|
pub type MachineIdentifier = String;
|
||||||
pub type Priority = u64;
|
pub type Priority = u64;
|
||||||
@ -73,11 +74,13 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
|
pub fn init(log: Logger, config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
|
||||||
let mut flags = lmdb::DatabaseFlags::empty();
|
let mut flags = lmdb::DatabaseFlags::empty();
|
||||||
//flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
|
//flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
|
||||||
let machdb = env.create_db(Some("machines"), flags)?;
|
let machdb = env.create_db(Some("machines"), flags)?;
|
||||||
debug!(&log, "Opened machine db successfully.");
|
debug!(&log, "Opened machine db successfully.");
|
||||||
|
|
||||||
Ok(Internal::new(log, env, machdb))
|
let audit = AuditLog::new(config)?;
|
||||||
|
|
||||||
|
Ok(Internal::new(log, audit, env, machdb))
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,22 @@ use std::sync::Arc;
|
|||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use lmdb::{Environment, Transaction, RwTransaction, Cursor, RoTransaction};
|
use lmdb::{Environment, Transaction, RwTransaction, Cursor, RoTransaction};
|
||||||
|
use crate::audit::AuditLog;
|
||||||
|
|
||||||
use super::{MachineIdentifier, MachineState};
|
use super::{MachineIdentifier, MachineState};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Internal {
|
pub struct Internal {
|
||||||
log: Logger,
|
log: Logger,
|
||||||
|
audit: AuditLog,
|
||||||
env: Arc<Environment>,
|
env: Arc<Environment>,
|
||||||
db: lmdb::Database,
|
db: lmdb::Database,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internal {
|
impl Internal {
|
||||||
pub fn new(log: Logger, env: Arc<Environment>, db: lmdb::Database) -> Self {
|
pub fn new(log: Logger, audit: AuditLog, env: Arc<Environment>, db: lmdb::Database) -> Self {
|
||||||
Self { log, env, db }
|
Self { log, audit, env, db }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_with_txn<T: Transaction>(&self, txn: &T, id: &String)
|
pub fn get_with_txn<T: Transaction>(&self, txn: &T, id: &String)
|
||||||
@ -47,6 +49,7 @@ impl Internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(&self, id: &MachineIdentifier, status: &MachineState) -> Result<()> {
|
pub fn put(&self, id: &MachineIdentifier, status: &MachineState) -> Result<()> {
|
||||||
|
self.audit.log(id, status)?;
|
||||||
let mut txn = self.env.begin_rw_txn()?;
|
let mut txn = self.env.begin_rw_txn()?;
|
||||||
self.put_with_txn(&mut txn, id, status)?;
|
self.put_with_txn(&mut txn, id, status)?;
|
||||||
txn.commit().map_err(Into::into)
|
txn.commit().map_err(Into::into)
|
||||||
|
@ -295,7 +295,7 @@ impl Inner {
|
|||||||
Box::pin(self.state.signal_cloned().dedupe_cloned())
|
Box::pin(self.state.signal_cloned().dedupe_cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_state(&mut self, new_state: MachineState) -> MachineState {
|
fn replace_state(&self, new_state: MachineState) -> MachineState {
|
||||||
self.db.put(&self.id, &new_state);
|
self.db.put(&self.id, &new_state);
|
||||||
self.state.replace(new_state)
|
self.state.replace(new_state)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ mod actor;
|
|||||||
mod initiator;
|
mod initiator;
|
||||||
mod space;
|
mod space;
|
||||||
|
|
||||||
|
mod audit;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
Loading…
Reference in New Issue
Block a user