diff --git a/Cargo.lock b/Cargo.lock index 5e98514..8d17b62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,6 +449,19 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bcrypt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b1866ecef4f2d06a0bb77880015fdf2b89e25a1c2e5addacb87e459c86dc67e" +dependencies = [ + "base64 0.22.1", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -479,6 +492,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "brotli" version = "6.0.0" @@ -529,9 +552,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "jobserver", "libc", @@ -565,6 +588,16 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1288,9 +1321,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.4" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", @@ -1548,6 +1581,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -1792,13 +1834,14 @@ dependencies = [ [[package]] name = "kuberest" -version = "1.1.4" +version = "1.1.5" dependencies = [ "actix-web", "anyhow", "argon2", "assert-json-diff", "base64 0.22.1", + "bcrypt", "chrono", "futures", "handlebars", @@ -1840,9 +1883,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linux-raw-sys" @@ -2005,9 +2048,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -3208,9 +3251,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] diff --git a/Cargo.toml b/Cargo.toml index cde840e..3ca7729 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kuberest" -version = "1.1.4" +version = "1.1.5" authors = ["Sébastien Huss "] edition = "2021" default-run = "controller" @@ -80,6 +80,7 @@ reqwest = { version = "0.12.4", features = ["rustls-tls"] } base64 = "0.22.1" rand = "0.8.5" argon2 = { version = "0.5.3", features = ["std"] } +bcrypt = "0.16.0" [dev-dependencies] assert-json-diff = "2.0.2" diff --git a/charts/kuberest/Chart.yaml b/charts/kuberest/Chart.yaml index d871d18..1c424dc 100644 --- a/charts/kuberest/Chart.yaml +++ b/charts/kuberest/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: kuberest description: Allow to Control remote REST api endpoints from the confort of your cluster type: application -version: "1.1.4" -appVersion: "1.1.4" +version: "1.1.5" +appVersion: "1.1.5" diff --git a/charts/kuberest/templates/rbac.yaml b/charts/kuberest/templates/rbac.yaml index 42e376f..5732c94 100644 --- a/charts/kuberest/templates/rbac.yaml +++ b/charts/kuberest/templates/rbac.yaml @@ -49,3 +49,45 @@ roleRef: kind: ClusterRole name: {{ include "controller.fullname" . }} apiGroup: rbac.authorization.k8s.io +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-view: 'true' + name: {{ include "controller.fullname" . }}:aggregate-to-view +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: ["get", "watch", "list"] +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-edit: 'true' + name: {{ include "controller.fullname" . }}:aggregate-to-edit +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: + - patch + - update +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-admin: 'true' + name: {{ include "controller.fullname" . }}:aggregate-to-admin +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints/status"] + verbs: + - update +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: + - create + - delete + - deletecollection diff --git a/deploy/operator/deployment.yaml b/deploy/operator/deployment.yaml index 09bb95b..d1babf1 100644 --- a/deploy/operator/deployment.yaml +++ b/deploy/operator/deployment.yaml @@ -8,7 +8,7 @@ metadata: labels: app: kuberest app.kubernetes.io/name: kuberest - app.kubernetes.io/version: "1.1.4" + app.kubernetes.io/version: "1.1.5" namespace: default automountServiceAccountToken: true --- @@ -33,6 +33,51 @@ rules: verbs: ["create"] --- # Source: kuberest/templates/rbac.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-view: 'true' + name: kuberest:aggregate-to-view +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: ["get", "watch", "list"] +--- +# Source: kuberest/templates/rbac.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-edit: 'true' + name: kuberest:aggregate-to-edit +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: + - patch + - update +--- +# Source: kuberest/templates/rbac.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-admin: 'true' + name: kuberest:aggregate-to-admin +rules: +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints/status"] + verbs: + - update +- apiGroups: ["kuberest.solidite.fr"] + resources: ["restendpoints"] + verbs: + - create + - delete + - deletecollection +--- +# Source: kuberest/templates/rbac.yaml # Binding the role to the account kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -57,7 +102,7 @@ metadata: labels: app: kuberest app.kubernetes.io/name: kuberest - app.kubernetes.io/version: "1.1.4" + app.kubernetes.io/version: "1.1.5" spec: type: ClusterIP ports: @@ -77,7 +122,7 @@ metadata: labels: app: kuberest app.kubernetes.io/name: kuberest - app.kubernetes.io/version: "1.1.4" + app.kubernetes.io/version: "1.1.5" spec: replicas: 1 selector: @@ -95,7 +140,7 @@ spec: {} containers: - name: kuberest - image: sebt3/kuberest:1.1.4 + image: sebt3/kuberest:1.1.5 imagePullPolicy: IfNotPresent securityContext: {} diff --git a/src/handlebarshandler.rs b/src/handlebarshandler.rs index 740e0b4..d8696d6 100644 --- a/src/handlebarshandler.rs +++ b/src/handlebarshandler.rs @@ -1,4 +1,8 @@ -use crate::{hasheshandlers::Argon, passwordhandler::Passwords, Error, Result, RhaiRes}; +use crate::{ + hasheshandlers::{self, Argon}, + passwordhandler::Passwords, + Error, Result, RhaiRes, +}; use base64::{engine::general_purpose::STANDARD, Engine as _}; use handlebars::{handlebars_helper, Handlebars}; use handlebars_misc_helpers::new_hbs; @@ -33,6 +37,13 @@ handlebars_helper!(argon_hash: |password:Value| Argon::new().hash(password.as_st warn!("handlebars::argon_hash failed to convert to string with: {e:?}"); String::new() })); +handlebars_helper!(bcrypt_hash: |password:Value| hasheshandlers::bcrypt_hash(password.as_str().unwrap_or_else(|| { + warn!("handlebars::bcrypt_hash received a non-string password: {:?}",password); + "" +}).to_string()).unwrap_or_else(|e| { + warn!("handlebars::bcrypt_hash failed to convert to string with: {e:?}"); + String::new() +})); handlebars_helper!(gen_password: |len:u32| Passwords::new().generate(len, 6, 2, 2)); handlebars_helper!(gen_password_alphanum: |len:u32| Passwords::new().generate(len, 8, 2, 0)); @@ -48,6 +59,7 @@ impl HandleBars<'_> { engine.register_helper("base64_encode", Box::new(base64_encode)); engine.register_helper("header_basic", Box::new(header_basic)); engine.register_helper("argon_hash", Box::new(argon_hash)); + engine.register_helper("bcrypt_hash", Box::new(bcrypt_hash)); engine.register_helper("gen_password", Box::new(gen_password)); engine.register_helper("gen_password_alphanum", Box::new(gen_password_alphanum)); // TODO: add more helpers diff --git a/src/hasheshandlers.rs b/src/hasheshandlers.rs index 256f8ca..4b6341d 100644 --- a/src/hasheshandlers.rs +++ b/src/hasheshandlers.rs @@ -3,6 +3,7 @@ use argon2::{ password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, Argon2, }; +use bcrypt::{hash, DEFAULT_COST}; #[derive(Clone, Debug)] pub struct Argon { @@ -36,3 +37,7 @@ impl Argon { self.hash(password).map_err(rhai_err) } } + +pub fn bcrypt_hash(password: String) -> Result { + hash(&password, DEFAULT_COST).map_err(Error::BcryptError) +} diff --git a/src/lib.rs b/src/lib.rs index 02ab2a9..d4f1146 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,9 @@ pub enum Error { #[error("Argon2 password_hash error {0}")] Argon2hash(#[from] argon2::password_hash::Error), + #[error("Bcrypt hash error {0}")] + BcryptError(#[from] bcrypt::BcryptError), + #[error("Unsupported method")] UnsupportedMethod, diff --git a/src/restendpoint.rs b/src/restendpoint.rs index 243a43f..2d07ddb 100644 --- a/src/restendpoint.rs +++ b/src/restendpoint.rs @@ -1012,9 +1012,11 @@ impl RestEndPoint { ) .unwrap_or_else(|e| { conditions.push(ApplicationCondition::write_failed(&format!( - "Templating write.{}.{}.values raised {e:?}", + "Templating write.{}.{}.values \n{}\nusing values: \n{}\nraised {e:?}", group.name.clone(), - item.name + item.name, + item.values.as_str(), + serde_yaml::to_string(&values).unwrap_or_default() ))); json!({}) }); @@ -1583,7 +1585,10 @@ impl RestEndPoint { } else if self.spec.teardown.is_none() { // no teardown script, only prepare client if there are some write to delete let status = self.status.clone().unwrap(); - do_prepare_client = status.owned_target.is_empty(); + do_prepare_client = !status.owned_target.is_empty(); + } + if !do_prepare_client { + tracing::info!("Skipping to prepare the client"); } let mut rhai = Script::new(); rhai.ctx.set_or_push("hbs", hbs.clone()); diff --git a/src/rhaihandler.rs b/src/rhaihandler.rs index 8b04bed..b5b5376 100644 --- a/src/rhaihandler.rs +++ b/src/rhaihandler.rs @@ -30,6 +30,9 @@ impl Script { .register_fn("log_info", |s: ImmutableString| tracing::info!("{s}")) .register_fn("log_warn", |s: ImmutableString| tracing::warn!("{s}")) .register_fn("log_error", |s: ImmutableString| tracing::error!("{s}")) + .register_fn("bcrypt_hash", |s: ImmutableString| { + crate::hasheshandlers::bcrypt_hash(s.to_string()).map_err(rhai_err) + }) .register_fn("gen_password", |len: u32| -> String { Passwords::new().generate(len, 6, 2, 2) })