refactor: SDK images and secrets modules with submodule splits
Split images.rs (1809L) into mod.rs + builders.rs (per-service build functions). Split secrets.rs (1727L) into mod.rs + seeding.rs (KV get_or_create, seed_openbao) + db_engine.rs (PostgreSQL static roles). Moves BuildTarget enum from cli.rs into images/mod.rs with conditional clap::ValueEnum derive behind the "cli" feature.
This commit is contained in:
107
sunbeam-sdk/src/secrets/db_engine.rs
Normal file
107
sunbeam-sdk/src/secrets/db_engine.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
//! OpenBao database secrets engine configuration.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use k8s_openapi::api::core::v1::Pod;
|
||||
use kube::api::{Api, ListParams};
|
||||
|
||||
use crate::error::{Result, ResultExt};
|
||||
use crate::kube as k;
|
||||
use crate::openbao::BaoClient;
|
||||
use crate::output::ok;
|
||||
|
||||
use super::{rand_token, PG_USERS};
|
||||
|
||||
/// Enable OpenBao database secrets engine and create PostgreSQL static roles.
|
||||
pub async fn configure_db_engine(bao: &BaoClient) -> Result<()> {
|
||||
ok("Configuring OpenBao database secrets engine...");
|
||||
let pg_rw = "postgres-rw.data.svc.cluster.local:5432";
|
||||
|
||||
let _ = bao.enable_secrets_engine("database", "database").await;
|
||||
|
||||
// ── vault PG user setup ─────────────────────────────────────────────
|
||||
let client = k::get_client().await?;
|
||||
let pods: Api<Pod> = Api::namespaced(client.clone(), "data");
|
||||
let lp = ListParams::default().labels("cnpg.io/cluster=postgres,role=primary");
|
||||
let pod_list = pods.list(&lp).await?;
|
||||
let cnpg_pod = pod_list
|
||||
.items
|
||||
.first()
|
||||
.and_then(|p| p.metadata.name.as_deref())
|
||||
.ctx("Could not find CNPG primary pod for vault user setup.")?
|
||||
.to_string();
|
||||
|
||||
let existing_vault_pass = bao.kv_get_field("secret", "vault", "pg-password").await?;
|
||||
let vault_pg_pass = if existing_vault_pass.is_empty() {
|
||||
let new_pass = rand_token();
|
||||
let mut vault_data = HashMap::new();
|
||||
vault_data.insert("pg-password".to_string(), new_pass.clone());
|
||||
bao.kv_put("secret", "vault", &vault_data).await?;
|
||||
ok("vault KV entry written.");
|
||||
new_pass
|
||||
} else {
|
||||
ok("vault KV entry already present -- skipping write.");
|
||||
existing_vault_pass
|
||||
};
|
||||
|
||||
let create_vault_sql = concat!(
|
||||
"DO $$ BEGIN ",
|
||||
"IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'vault') THEN ",
|
||||
"CREATE USER vault WITH LOGIN CREATEROLE; ",
|
||||
"END IF; ",
|
||||
"END $$;"
|
||||
);
|
||||
|
||||
psql_exec(&cnpg_pod, create_vault_sql).await?;
|
||||
psql_exec(
|
||||
&cnpg_pod,
|
||||
&format!("ALTER USER vault WITH PASSWORD '{vault_pg_pass}';"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
for user in PG_USERS {
|
||||
psql_exec(
|
||||
&cnpg_pod,
|
||||
&format!("GRANT {user} TO vault WITH ADMIN OPTION;"),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
ok("vault PG user configured with ADMIN OPTION on all service roles.");
|
||||
|
||||
let conn_url = format!(
|
||||
"postgresql://{{{{username}}}}:{{{{password}}}}@{pg_rw}/postgres?sslmode=disable"
|
||||
);
|
||||
|
||||
bao.write_db_config(
|
||||
"cnpg-postgres",
|
||||
"postgresql-database-plugin",
|
||||
&conn_url,
|
||||
"vault",
|
||||
&vault_pg_pass,
|
||||
"*",
|
||||
)
|
||||
.await?;
|
||||
ok("DB engine connection configured (vault user).");
|
||||
|
||||
let rotation_stmt = r#"ALTER USER "{{name}}" WITH PASSWORD '{{password}}';"#;
|
||||
|
||||
for user in PG_USERS {
|
||||
bao.write_db_static_role(user, "cnpg-postgres", user, 86400, &[rotation_stmt])
|
||||
.await?;
|
||||
ok(&format!(" static-role/{user}"));
|
||||
}
|
||||
|
||||
ok("Database secrets engine configured.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute a psql command on the CNPG primary pod.
|
||||
async fn psql_exec(cnpg_pod: &str, sql: &str) -> Result<(i32, String)> {
|
||||
k::kube_exec(
|
||||
"data",
|
||||
cnpg_pod,
|
||||
&["psql", "-U", "postgres", "-c", sql],
|
||||
Some("postgres"),
|
||||
)
|
||||
.await
|
||||
}
|
||||
1106
sunbeam-sdk/src/secrets/mod.rs
Normal file
1106
sunbeam-sdk/src/secrets/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
542
sunbeam-sdk/src/secrets/seeding.rs
Normal file
542
sunbeam-sdk/src/secrets/seeding.rs
Normal file
@@ -0,0 +1,542 @@
|
||||
//! OpenBao KV seeding — init/unseal, idempotent credential generation, VSO auth.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use k8s_openapi::api::core::v1::Pod;
|
||||
use kube::api::{Api, ListParams};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::kube as k;
|
||||
use crate::openbao::BaoClient;
|
||||
use crate::output::{ok, warn};
|
||||
|
||||
use super::{
|
||||
gen_dkim_key_pair, gen_fernet_key, port_forward, rand_token, rand_token_n, scw_config,
|
||||
wait_pod_running, delete_resource, GITEA_ADMIN_USER, SMTP_URI,
|
||||
};
|
||||
|
||||
/// Internal result from seed_openbao, used by cmd_seed.
|
||||
pub struct SeedResult {
|
||||
pub creds: HashMap<String, String>,
|
||||
pub ob_pod: String,
|
||||
pub root_token: String,
|
||||
}
|
||||
|
||||
/// Read-or-create pattern: reads existing KV values, only generates missing ones.
|
||||
pub async fn get_or_create(
|
||||
bao: &BaoClient,
|
||||
path: &str,
|
||||
fields: &[(&str, &dyn Fn() -> String)],
|
||||
dirty_paths: &mut HashSet<String>,
|
||||
) -> Result<HashMap<String, String>> {
|
||||
let existing = bao.kv_get("secret", path).await?.unwrap_or_default();
|
||||
let mut result = HashMap::new();
|
||||
for (key, default_fn) in fields {
|
||||
let val = existing.get(*key).filter(|v| !v.is_empty()).cloned();
|
||||
if let Some(v) = val {
|
||||
result.insert(key.to_string(), v);
|
||||
} else {
|
||||
result.insert(key.to_string(), default_fn());
|
||||
dirty_paths.insert(path.to_string());
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Initialize/unseal OpenBao, generate/read credentials idempotently, configure VSO auth.
|
||||
pub async fn seed_openbao() -> Result<Option<SeedResult>> {
|
||||
let client = k::get_client().await?;
|
||||
let pods: Api<Pod> = Api::namespaced(client.clone(), "data");
|
||||
let lp = ListParams::default().labels("app.kubernetes.io/name=openbao,component=server");
|
||||
let pod_list = pods.list(&lp).await?;
|
||||
|
||||
let ob_pod = match pod_list
|
||||
.items
|
||||
.first()
|
||||
.and_then(|p| p.metadata.name.as_deref())
|
||||
{
|
||||
Some(name) => name.to_string(),
|
||||
None => {
|
||||
ok("OpenBao pod not found -- skipping.");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
ok(&format!("OpenBao ({ob_pod})..."));
|
||||
let _ = wait_pod_running("data", &ob_pod, 120).await;
|
||||
|
||||
let pf = port_forward("data", &ob_pod, 8200).await?;
|
||||
let bao_url = format!("http://127.0.0.1:{}", pf.local_port);
|
||||
let bao = BaoClient::new(&bao_url);
|
||||
|
||||
// ── Init / Unseal ───────────────────────────────────────────────────
|
||||
let mut unseal_key = String::new();
|
||||
let mut root_token = String::new();
|
||||
|
||||
let status = bao.seal_status().await.unwrap_or_else(|_| {
|
||||
crate::openbao::SealStatusResponse {
|
||||
initialized: false,
|
||||
sealed: true,
|
||||
progress: 0,
|
||||
t: 0,
|
||||
n: 0,
|
||||
}
|
||||
});
|
||||
|
||||
let mut already_initialized = status.initialized;
|
||||
if !already_initialized {
|
||||
if let Ok(Some(_)) = k::kube_get_secret("data", "openbao-keys").await {
|
||||
already_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !already_initialized {
|
||||
ok("Initializing OpenBao...");
|
||||
match bao.init(1, 1).await {
|
||||
Ok(init) => {
|
||||
unseal_key = init.unseal_keys_b64[0].clone();
|
||||
root_token = init.root_token.clone();
|
||||
let mut data = HashMap::new();
|
||||
data.insert("key".to_string(), unseal_key.clone());
|
||||
data.insert("root-token".to_string(), root_token.clone());
|
||||
k::create_secret("data", "openbao-keys", data).await?;
|
||||
ok("Initialized -- keys stored in secret/openbao-keys.");
|
||||
}
|
||||
Err(e) => {
|
||||
warn(&format!(
|
||||
"Init failed -- resetting OpenBao storage for local dev... ({e})"
|
||||
));
|
||||
let _ = delete_resource("data", "pvc", "data-openbao-0").await;
|
||||
let _ = delete_resource("data", "pod", &ob_pod).await;
|
||||
warn("OpenBao storage reset. Run --seed again after the pod restarts.");
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok("Already initialized.");
|
||||
if let Ok(key) = k::kube_get_secret_field("data", "openbao-keys", "key").await {
|
||||
unseal_key = key;
|
||||
}
|
||||
if let Ok(token) = k::kube_get_secret_field("data", "openbao-keys", "root-token").await {
|
||||
root_token = token;
|
||||
}
|
||||
}
|
||||
|
||||
// Unseal if needed
|
||||
let status = bao.seal_status().await.unwrap_or_else(|_| {
|
||||
crate::openbao::SealStatusResponse {
|
||||
initialized: true,
|
||||
sealed: true,
|
||||
progress: 0,
|
||||
t: 0,
|
||||
n: 0,
|
||||
}
|
||||
});
|
||||
if status.sealed && !unseal_key.is_empty() {
|
||||
ok("Unsealing...");
|
||||
bao.unseal(&unseal_key).await?;
|
||||
}
|
||||
|
||||
if root_token.is_empty() {
|
||||
warn("No root token available -- skipping KV seeding.");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let bao = BaoClient::with_token(&bao_url, &root_token);
|
||||
|
||||
// ── KV seeding ──────────────────────────────────────────────────────
|
||||
ok("Seeding KV (idempotent -- existing values preserved)...");
|
||||
let _ = bao.enable_secrets_engine("secret", "kv").await;
|
||||
let _ = bao
|
||||
.write(
|
||||
"sys/mounts/secret/tune",
|
||||
&serde_json::json!({"options": {"version": "2"}}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut dirty_paths: HashSet<String> = HashSet::new();
|
||||
|
||||
let hydra = get_or_create(
|
||||
&bao,
|
||||
"hydra",
|
||||
&[
|
||||
("system-secret", &rand_token as &dyn Fn() -> String),
|
||||
("cookie-secret", &rand_token),
|
||||
("pairwise-salt", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let smtp_uri_fn = || SMTP_URI.to_string();
|
||||
let kratos = get_or_create(
|
||||
&bao,
|
||||
"kratos",
|
||||
&[
|
||||
("secrets-default", &rand_token as &dyn Fn() -> String),
|
||||
("secrets-cookie", &rand_token),
|
||||
("smtp-connection-uri", &smtp_uri_fn),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let seaweedfs = get_or_create(
|
||||
&bao,
|
||||
"seaweedfs",
|
||||
&[
|
||||
("access-key", &rand_token as &dyn Fn() -> String),
|
||||
("secret-key", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let gitea_admin_user_fn = || GITEA_ADMIN_USER.to_string();
|
||||
let gitea = get_or_create(
|
||||
&bao,
|
||||
"gitea",
|
||||
&[
|
||||
(
|
||||
"admin-username",
|
||||
&gitea_admin_user_fn as &dyn Fn() -> String,
|
||||
),
|
||||
("admin-password", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let hive_local_fn = || "hive-local".to_string();
|
||||
let hive = get_or_create(
|
||||
&bao,
|
||||
"hive",
|
||||
&[
|
||||
("oidc-client-id", &hive_local_fn as &dyn Fn() -> String),
|
||||
("oidc-client-secret", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let devkey_fn = || "devkey".to_string();
|
||||
let livekit = get_or_create(
|
||||
&bao,
|
||||
"livekit",
|
||||
&[
|
||||
("api-key", &devkey_fn as &dyn Fn() -> String),
|
||||
("api-secret", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let people = get_or_create(
|
||||
&bao,
|
||||
"people",
|
||||
&[("django-secret-key", &rand_token as &dyn Fn() -> String)],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let login_ui = get_or_create(
|
||||
&bao,
|
||||
"login-ui",
|
||||
&[
|
||||
("cookie-secret", &rand_token as &dyn Fn() -> String),
|
||||
("csrf-cookie-secret", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let sw_access = seaweedfs.get("access-key").cloned().unwrap_or_default();
|
||||
let sw_secret = seaweedfs.get("secret-key").cloned().unwrap_or_default();
|
||||
let empty_fn = || String::new();
|
||||
let sw_access_fn = {
|
||||
let v = sw_access.clone();
|
||||
move || v.clone()
|
||||
};
|
||||
let sw_secret_fn = {
|
||||
let v = sw_secret.clone();
|
||||
move || v.clone()
|
||||
};
|
||||
|
||||
let kratos_admin = get_or_create(
|
||||
&bao,
|
||||
"kratos-admin",
|
||||
&[
|
||||
("cookie-secret", &rand_token as &dyn Fn() -> String),
|
||||
("csrf-cookie-secret", &rand_token),
|
||||
("admin-identity-ids", &empty_fn),
|
||||
("s3-access-key", &sw_access_fn),
|
||||
("s3-secret-key", &sw_secret_fn),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let docs = get_or_create(
|
||||
&bao,
|
||||
"docs",
|
||||
&[
|
||||
("django-secret-key", &rand_token as &dyn Fn() -> String),
|
||||
("collaboration-secret", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let meet = get_or_create(
|
||||
&bao,
|
||||
"meet",
|
||||
&[
|
||||
("django-secret-key", &rand_token as &dyn Fn() -> String),
|
||||
("application-jwt-secret-key", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let drive = get_or_create(
|
||||
&bao,
|
||||
"drive",
|
||||
&[("django-secret-key", &rand_token as &dyn Fn() -> String)],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let projects = get_or_create(
|
||||
&bao,
|
||||
"projects",
|
||||
&[("secret-key", &rand_token as &dyn Fn() -> String)],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let cal_django_fn = || rand_token_n(50);
|
||||
let calendars = get_or_create(
|
||||
&bao,
|
||||
"calendars",
|
||||
&[
|
||||
("django-secret-key", &cal_django_fn as &dyn Fn() -> String),
|
||||
("salt-key", &rand_token),
|
||||
("caldav-inbound-api-key", &rand_token),
|
||||
("caldav-outbound-api-key", &rand_token),
|
||||
("caldav-internal-api-key", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// DKIM key pair — generated together since keys are coupled.
|
||||
let existing_messages = bao.kv_get("secret", "messages").await?.unwrap_or_default();
|
||||
let (dkim_private, dkim_public) = if existing_messages
|
||||
.get("dkim-private-key")
|
||||
.filter(|v| !v.is_empty())
|
||||
.is_some()
|
||||
{
|
||||
(
|
||||
existing_messages
|
||||
.get("dkim-private-key")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
existing_messages
|
||||
.get("dkim-public-key")
|
||||
.cloned()
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
gen_dkim_key_pair()
|
||||
};
|
||||
|
||||
let dkim_priv_fn = {
|
||||
let v = dkim_private.clone();
|
||||
move || v.clone()
|
||||
};
|
||||
let dkim_pub_fn = {
|
||||
let v = dkim_public.clone();
|
||||
move || v.clone()
|
||||
};
|
||||
let socks_proxy_fn = || format!("sunbeam:{}", rand_token());
|
||||
let sunbeam_fn = || "sunbeam".to_string();
|
||||
|
||||
let messages = get_or_create(
|
||||
&bao,
|
||||
"messages",
|
||||
&[
|
||||
("django-secret-key", &rand_token as &dyn Fn() -> String),
|
||||
("salt-key", &rand_token),
|
||||
("mda-api-secret", &rand_token),
|
||||
(
|
||||
"oidc-refresh-token-key",
|
||||
&gen_fernet_key as &dyn Fn() -> String,
|
||||
),
|
||||
("dkim-private-key", &dkim_priv_fn),
|
||||
("dkim-public-key", &dkim_pub_fn),
|
||||
("rspamd-password", &rand_token),
|
||||
("socks-proxy-users", &socks_proxy_fn),
|
||||
("mta-out-smtp-username", &sunbeam_fn),
|
||||
("mta-out-smtp-password", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let admin_fn = || "admin".to_string();
|
||||
let collabora = get_or_create(
|
||||
&bao,
|
||||
"collabora",
|
||||
&[
|
||||
("username", &admin_fn as &dyn Fn() -> String),
|
||||
("password", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let tuwunel = get_or_create(
|
||||
&bao,
|
||||
"tuwunel",
|
||||
&[
|
||||
("oidc-client-id", &empty_fn as &dyn Fn() -> String),
|
||||
("oidc-client-secret", &empty_fn),
|
||||
("turn-secret", &empty_fn),
|
||||
("registration-token", &rand_token),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let grafana = get_or_create(
|
||||
&bao,
|
||||
"grafana",
|
||||
&[("admin-password", &rand_token as &dyn Fn() -> String)],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let scw_access_fn = || scw_config("access-key");
|
||||
let scw_secret_fn = || scw_config("secret-key");
|
||||
let scaleway_s3 = get_or_create(
|
||||
&bao,
|
||||
"scaleway-s3",
|
||||
&[
|
||||
("access-key-id", &scw_access_fn as &dyn Fn() -> String),
|
||||
("secret-access-key", &scw_secret_fn),
|
||||
],
|
||||
&mut dirty_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// ── Write dirty paths ───────────────────────────────────────────────
|
||||
if dirty_paths.is_empty() {
|
||||
ok("All OpenBao KV secrets already present -- skipping writes.");
|
||||
} else {
|
||||
let mut sorted_paths: Vec<&String> = dirty_paths.iter().collect();
|
||||
sorted_paths.sort();
|
||||
ok(&format!(
|
||||
"Writing new secrets to OpenBao KV ({})...",
|
||||
sorted_paths
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
));
|
||||
|
||||
let all_paths: &[(&str, &HashMap<String, String>)] = &[
|
||||
("hydra", &hydra),
|
||||
("kratos", &kratos),
|
||||
("seaweedfs", &seaweedfs),
|
||||
("gitea", &gitea),
|
||||
("hive", &hive),
|
||||
("livekit", &livekit),
|
||||
("people", &people),
|
||||
("login-ui", &login_ui),
|
||||
("kratos-admin", &kratos_admin),
|
||||
("docs", &docs),
|
||||
("meet", &meet),
|
||||
("drive", &drive),
|
||||
("projects", &projects),
|
||||
("calendars", &calendars),
|
||||
("messages", &messages),
|
||||
("collabora", &collabora),
|
||||
("tuwunel", &tuwunel),
|
||||
("grafana", &grafana),
|
||||
("scaleway-s3", &scaleway_s3),
|
||||
];
|
||||
|
||||
for (path, data) in all_paths {
|
||||
if dirty_paths.contains(*path) {
|
||||
bao.kv_patch("secret", path, data).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Kubernetes auth for VSO ─────────────────────────────────────────
|
||||
ok("Configuring Kubernetes auth for VSO...");
|
||||
let _ = bao.auth_enable("kubernetes", "kubernetes").await;
|
||||
|
||||
bao.write(
|
||||
"auth/kubernetes/config",
|
||||
&serde_json::json!({
|
||||
"kubernetes_host": "https://kubernetes.default.svc.cluster.local"
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let policy_hcl = concat!(
|
||||
"path \"secret/data/*\" { capabilities = [\"read\"] }\n",
|
||||
"path \"secret/metadata/*\" { capabilities = [\"read\", \"list\"] }\n",
|
||||
"path \"database/static-creds/*\" { capabilities = [\"read\"] }\n",
|
||||
);
|
||||
bao.write_policy("vso-reader", policy_hcl).await?;
|
||||
|
||||
bao.write(
|
||||
"auth/kubernetes/role/vso",
|
||||
&serde_json::json!({
|
||||
"bound_service_account_names": "default",
|
||||
"bound_service_account_namespaces": "ory,devtools,storage,lasuite,matrix,media,data,monitoring",
|
||||
"policies": "vso-reader",
|
||||
"ttl": "1h"
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Build credentials map
|
||||
let mut creds = HashMap::new();
|
||||
let field_map: &[(&str, &str, &HashMap<String, String>)] = &[
|
||||
("hydra-system-secret", "system-secret", &hydra),
|
||||
("hydra-cookie-secret", "cookie-secret", &hydra),
|
||||
("hydra-pairwise-salt", "pairwise-salt", &hydra),
|
||||
("kratos-secrets-default", "secrets-default", &kratos),
|
||||
("kratos-secrets-cookie", "secrets-cookie", &kratos),
|
||||
("s3-access-key", "access-key", &seaweedfs),
|
||||
("s3-secret-key", "secret-key", &seaweedfs),
|
||||
("gitea-admin-password", "admin-password", &gitea),
|
||||
("hive-oidc-client-id", "oidc-client-id", &hive),
|
||||
("hive-oidc-client-secret", "oidc-client-secret", &hive),
|
||||
("people-django-secret", "django-secret-key", &people),
|
||||
("livekit-api-key", "api-key", &livekit),
|
||||
("livekit-api-secret", "api-secret", &livekit),
|
||||
(
|
||||
"kratos-admin-cookie-secret",
|
||||
"cookie-secret",
|
||||
&kratos_admin,
|
||||
),
|
||||
("messages-dkim-public-key", "dkim-public-key", &messages),
|
||||
];
|
||||
|
||||
for (cred_key, field_key, source) in field_map {
|
||||
creds.insert(
|
||||
cred_key.to_string(),
|
||||
source.get(*field_key).cloned().unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Some(SeedResult {
|
||||
creds,
|
||||
ob_pod,
|
||||
root_token,
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user