mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
Check for same version with backup/restore (#2789)
This commit is contained in:
parent
1e4f6e85ca
commit
c1235a7186
16
README.md
16
README.md
|
@ -146,8 +146,8 @@ elements in a simpler and correct way out of the box in comparison.
|
|||
<details>
|
||||
<summary>Rauthy</summary>
|
||||
|
||||
Rauthy is a minimal OIDC provider. It supports WebAuthn just like Kanidm - they actually use our library
|
||||
for it!
|
||||
Rauthy is a minimal OIDC provider. It supports WebAuthn just like Kanidm - they actually use our
|
||||
library for it!
|
||||
|
||||
Rauthy only provides support for OIDC and so is unable to support other use cases like RADIUS and
|
||||
unix authentication.
|
||||
|
@ -160,15 +160,15 @@ then Kanidm will support those.
|
|||
<details>
|
||||
<summary>Authentik / Authelia / Zitadel</summary>
|
||||
|
||||
Authentik is an IDM provider written in Python and, Authelia and Zitadel are written in Go.
|
||||
all similar to Kanidm in the features it offers but notably all have weaker support for
|
||||
unix authentication and do not support the same level of authentication policy as Kanidm. Notably,
|
||||
all are missing WebAuthn Attestation.
|
||||
Authentik is an IDM provider written in Python and, Authelia and Zitadel are written in Go. all
|
||||
similar to Kanidm in the features it offers but notably all have weaker support for unix
|
||||
authentication and do not support the same level of authentication policy as Kanidm. Notably, all
|
||||
are missing WebAuthn Attestation.
|
||||
|
||||
All three use an external SQL server such as PostgreSQL. This can create a potential single source
|
||||
of failure and performance limitation compared to Kanidm which opted to write our own high
|
||||
performance database and replication system instead based on our experience with enterprise
|
||||
LDAP servers.
|
||||
performance database and replication system instead based on our experience with enterprise LDAP
|
||||
servers.
|
||||
|
||||
</details>
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ With any Identity Management (IDM) software, it's important you have the capabil
|
|||
case of a disaster - be that physical damage or a mistake. Kanidm supports backup and restore of the
|
||||
database with three methods.
|
||||
|
||||
It is important that you only attempt to restore data with the same version of the server that the
|
||||
backup originated from.
|
||||
|
||||
## Method 1 - Automatic Backup
|
||||
|
||||
Automatic backups can be generated online by a `kanidmd server` instance by including the
|
||||
|
|
|
@ -97,6 +97,14 @@ pub fn apply_profile() {
|
|||
println!("cargo:rustc-env=KANIDM_PRE_RELEASE=1");
|
||||
}
|
||||
|
||||
// For some checks we only want the series (i.e. exclude the patch version).
|
||||
let version_major = env!("CARGO_PKG_VERSION_MAJOR");
|
||||
let version_minor = env!("CARGO_PKG_VERSION_MINOR");
|
||||
println!(
|
||||
"cargo:rustc-env=KANIDM_PKG_SERIES={}.{}",
|
||||
version_major, version_minor
|
||||
);
|
||||
|
||||
match profile_cfg.cpu_flags {
|
||||
CpuOptLevel::apple_m1 => println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-cpu=apple_m1"),
|
||||
CpuOptLevel::none => {}
|
||||
|
|
|
@ -132,6 +132,10 @@ pub enum OperationError {
|
|||
// Value Errors
|
||||
VL0001ValueSshPublicKeyString,
|
||||
|
||||
// DB low level errors.
|
||||
DB0001MismatchedRestoreVersion,
|
||||
DB0002MismatchedRestoreVersion,
|
||||
|
||||
// SCIM
|
||||
SC0001IncomingSshPublicKey,
|
||||
// Migration
|
||||
|
|
|
@ -56,18 +56,15 @@ pub struct DbEntry {
|
|||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DbBackup {
|
||||
V1(Vec<DbEntry>),
|
||||
V2 {
|
||||
db_s_uuid: Uuid,
|
||||
db_d_uuid: Uuid,
|
||||
db_ts_max: Duration,
|
||||
entries: Vec<DbEntry>,
|
||||
},
|
||||
V3 {
|
||||
// Because of untagged, this has to be in order of newest
|
||||
// to oldest as untagged does a first-match when deserialising.
|
||||
V5 {
|
||||
version: String,
|
||||
db_s_uuid: Uuid,
|
||||
db_d_uuid: Uuid,
|
||||
db_ts_max: Duration,
|
||||
keyhandles: BTreeMap<KeyHandleId, KeyHandle>,
|
||||
repl_meta: DbReplMeta,
|
||||
entries: Vec<DbEntry>,
|
||||
},
|
||||
V4 {
|
||||
|
@ -78,6 +75,20 @@ pub enum DbBackup {
|
|||
repl_meta: DbReplMeta,
|
||||
entries: Vec<DbEntry>,
|
||||
},
|
||||
V3 {
|
||||
db_s_uuid: Uuid,
|
||||
db_d_uuid: Uuid,
|
||||
db_ts_max: Duration,
|
||||
keyhandles: BTreeMap<KeyHandleId, KeyHandle>,
|
||||
entries: Vec<DbEntry>,
|
||||
},
|
||||
V2 {
|
||||
db_s_uuid: Uuid,
|
||||
db_d_uuid: Uuid,
|
||||
db_ts_max: Duration,
|
||||
entries: Vec<DbEntry>,
|
||||
},
|
||||
V1(Vec<DbEntry>),
|
||||
}
|
||||
|
||||
fn from_vec_dbval1(attr_val: NonEmpty<DbValueV1>) -> Result<DbValueSetV2, OperationError> {
|
||||
|
|
|
@ -901,7 +901,9 @@ pub trait BackendTransaction {
|
|||
|
||||
let keyhandles = idlayer.get_key_handles()?;
|
||||
|
||||
let bak = DbBackup::V4 {
|
||||
let bak = DbBackup::V5 {
|
||||
// remember env is evaled at compile time.
|
||||
version: env!("KANIDM_PKG_SERIES").to_string(),
|
||||
db_s_uuid,
|
||||
db_d_uuid,
|
||||
db_ts_max,
|
||||
|
@ -1756,8 +1758,8 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
OperationError::SerdeJsonError
|
||||
})?;
|
||||
|
||||
let (dbentries, repl_meta) = match dbbak {
|
||||
DbBackup::V1(dbentries) => (dbentries, None),
|
||||
let (dbentries, repl_meta, maybe_version) = match dbbak {
|
||||
DbBackup::V1(dbentries) => (dbentries, None, None),
|
||||
DbBackup::V2 {
|
||||
db_s_uuid,
|
||||
db_d_uuid,
|
||||
|
@ -1768,7 +1770,7 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
idlayer.write_db_s_uuid(db_s_uuid)?;
|
||||
idlayer.write_db_d_uuid(db_d_uuid)?;
|
||||
idlayer.set_db_ts_max(db_ts_max)?;
|
||||
(entries, None)
|
||||
(entries, None, None)
|
||||
}
|
||||
DbBackup::V3 {
|
||||
db_s_uuid,
|
||||
|
@ -1782,7 +1784,7 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
idlayer.write_db_d_uuid(db_d_uuid)?;
|
||||
idlayer.set_db_ts_max(db_ts_max)?;
|
||||
idlayer.set_key_handles(keyhandles)?;
|
||||
(entries, None)
|
||||
(entries, None, None)
|
||||
}
|
||||
DbBackup::V4 {
|
||||
db_s_uuid,
|
||||
|
@ -1797,8 +1799,34 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
idlayer.write_db_d_uuid(db_d_uuid)?;
|
||||
idlayer.set_db_ts_max(db_ts_max)?;
|
||||
idlayer.set_key_handles(keyhandles)?;
|
||||
(entries, Some(repl_meta))
|
||||
(entries, Some(repl_meta), None)
|
||||
}
|
||||
DbBackup::V5 {
|
||||
version,
|
||||
db_s_uuid,
|
||||
db_d_uuid,
|
||||
db_ts_max,
|
||||
keyhandles,
|
||||
repl_meta,
|
||||
entries,
|
||||
} => {
|
||||
// Do stuff.
|
||||
idlayer.write_db_s_uuid(db_s_uuid)?;
|
||||
idlayer.write_db_d_uuid(db_d_uuid)?;
|
||||
idlayer.set_db_ts_max(db_ts_max)?;
|
||||
idlayer.set_key_handles(keyhandles)?;
|
||||
(entries, Some(repl_meta), Some(version))
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(version) = maybe_version {
|
||||
if version != env!("KANIDM_PKG_SERIES") {
|
||||
error!("The provided backup data is from server version {} and is unable to be restored on this instance ({})", version, env!("KANIDM_PKG_SERIES"));
|
||||
return Err(OperationError::DB0001MismatchedRestoreVersion);
|
||||
}
|
||||
} else {
|
||||
error!("The provided backup data is from an older server version and is unable to be restored.");
|
||||
return Err(OperationError::DB0002MismatchedRestoreVersion);
|
||||
};
|
||||
|
||||
// Rebuild the RUV from the backup.
|
||||
|
@ -2587,31 +2615,12 @@ mod tests {
|
|||
|
||||
// Now here, we need to tamper with the file.
|
||||
let serialized_string = fs::read_to_string(&db_backup_file_name).unwrap();
|
||||
trace!(?serialized_string);
|
||||
let mut dbbak: DbBackup = serde_json::from_str(&serialized_string).unwrap();
|
||||
|
||||
match &mut dbbak {
|
||||
DbBackup::V1(_) => {
|
||||
// We no longer use these format versions!
|
||||
unreachable!()
|
||||
}
|
||||
DbBackup::V2 {
|
||||
db_s_uuid: _,
|
||||
db_d_uuid: _,
|
||||
db_ts_max: _,
|
||||
entries,
|
||||
} => {
|
||||
let _ = entries.pop();
|
||||
}
|
||||
DbBackup::V3 {
|
||||
db_s_uuid: _,
|
||||
db_d_uuid: _,
|
||||
db_ts_max: _,
|
||||
keyhandles: _,
|
||||
entries,
|
||||
} => {
|
||||
let _ = entries.pop();
|
||||
}
|
||||
DbBackup::V4 {
|
||||
DbBackup::V5 {
|
||||
version: _,
|
||||
db_s_uuid: _,
|
||||
db_d_uuid: _,
|
||||
db_ts_max: _,
|
||||
|
@ -2621,6 +2630,10 @@ mod tests {
|
|||
} => {
|
||||
let _ = entries.pop();
|
||||
}
|
||||
_ => {
|
||||
// We no longer use these format versions!
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let serialized_entries_str = serde_json::to_string_pretty(&dbbak).unwrap();
|
||||
|
|
Loading…
Reference in a new issue