add cluster x kube-sign

This commit is contained in:
Mikaël Cluseau
2025-07-02 21:11:35 +02:00
parent 4b33c64042
commit 7f4307f009
3 changed files with 51 additions and 4 deletions

View File

@ -5,7 +5,7 @@ edition = "2024"
[dependencies] [dependencies]
bytes = "1.10.1" bytes = "1.10.1"
clap = { version = "4.5.40", features = ["derive"] } clap = { version = "4.5.40", features = ["derive", "env"] }
clap_complete = { version = "4.5.54", features = ["unstable-dynamic"] } clap_complete = { version = "4.5.54", features = ["unstable-dynamic"] }
env_logger = "0.11.8" env_logger = "0.11.8"
eyre = "0.6.12" eyre = "0.6.12"

View File

@ -45,11 +45,20 @@ enum ClusterCommand {
user_public_key: String, user_public_key: String,
#[arg(long, default_value = "root")] #[arg(long, default_value = "root")]
principal: String, principal: String,
#[arg(long, default_value = "+1d")] #[arg(long, default_value = "1d")]
validity: String, validity: String,
#[arg(long)] #[arg(long)]
options: Vec<String>, options: Vec<String>,
}, },
KubeSign {
csr: String,
#[arg(long, default_value = "anonymous", env = "USER")]
user: String,
#[arg(long)]
group: Option<String>,
#[arg(long, default_value = "1d")]
validity: String,
},
} }
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
@ -87,7 +96,7 @@ async fn main() -> Result<()> {
}) => { }) => {
let pub_key = tokio::fs::read_to_string(user_public_key).await?; let pub_key = tokio::fs::read_to_string(user_public_key).await?;
let cert = cluster let cert = cluster
.sign_ssh_user_pubkey(&dls::SshSignReq { .ssh_userca_sign(&dls::SshSignReq {
pub_key, pub_key,
principal, principal,
validity: Some(validity).filter(|s| s != ""), validity: Some(validity).filter(|s| s != ""),
@ -96,6 +105,23 @@ async fn main() -> Result<()> {
.await?; .await?;
write_raw(&cert); write_raw(&cert);
} }
Some(CC::KubeSign {
csr,
user,
group,
validity,
}) => {
let csr = tokio::fs::read_to_string(csr).await?;
let cert = cluster
.kube_sign(&dls::KubeSignReq {
csr,
user,
group,
validity: Some(validity).filter(|s| s != ""),
})
.await?;
write_raw(&cert);
}
} }
} }
C::Hosts => write_json(&dls.hosts().await?), C::Hosts => write_json(&dls.hosts().await?),

View File

@ -96,7 +96,7 @@ impl<'t> Cluster<'t> {
.await .await
} }
pub async fn sign_ssh_user_pubkey(&self, sign_req: &SshSignReq) -> Result<Vec<u8>> { pub async fn ssh_userca_sign(&self, sign_req: &SshSignReq) -> Result<Vec<u8>> {
let req = self.dls.req( let req = self.dls.req(
Method::POST, Method::POST,
format!("clusters/{}/ssh/user-ca/sign", self.name), format!("clusters/{}/ssh/user-ca/sign", self.name),
@ -106,6 +106,14 @@ impl<'t> Cluster<'t> {
let resp = do_req(req, &self.dls.token).await?; let resp = do_req(req, &self.dls.token).await?;
Ok(resp.bytes().await.map_err(Error::Read)?.to_vec()) Ok(resp.bytes().await.map_err(Error::Read)?.to_vec())
} }
pub async fn kube_sign(&self, sign_req: &KubeSignReq) -> Result<Vec<u8>> {
let req = (self.dls).req(Method::POST, format!("clusters/{}/kube/sign", self.name))?;
let req = req.json(sign_req);
let resp = do_req(req, &self.dls.token).await?;
Ok(resp.bytes().await.map_err(Error::Read)?.to_vec())
}
} }
pub struct Host<'t> { pub struct Host<'t> {
@ -164,8 +172,21 @@ pub struct SshSignReq {
pub options: Vec<String>, pub options: Vec<String>,
} }
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct KubeSignReq {
#[serde(rename = "CSR")]
pub csr: String,
pub user: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub validity: Option<String>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)] #[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ServerError { struct ServerError {
#[serde(default)]
code: u16, code: u16,
message: String, message: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]