diff --git a/auth/src/access_token.rs b/auth/src/access_token.rs index db99be3..524e20b 100644 --- a/auth/src/access_token.rs +++ b/auth/src/access_token.rs @@ -14,7 +14,6 @@ const JWT_SECRET_BYTES: usize = 24; lazy_static::lazy_static! { pub static ref USER_TOKEN_DURATION: Duration = Duration::days(7); - pub static ref DEPLOYMENT_TOKEN_DURATION: Duration = Duration::hours(1); } pub(crate) async fn get_jwt_secret() -> Result, AuthError> { @@ -53,30 +52,28 @@ impl AccessToken { DateTime::from_timestamp(self.exp as i64, 0) .ok_or_else(|| AuthError::NaiveDateTimeConvertOverflow(self.exp)) } -} -impl From<&User> for AccessToken { - fn from(user: &User) -> Self { + pub fn for_deployment(deployment: &Deployment, duration: Duration) -> Self { let iat = chrono::Utc::now(); - let exp = iat + *USER_TOKEN_DURATION; + let exp = iat + duration; Self { iat: iat.timestamp() as usize, nbf: iat.timestamp() as usize, exp: exp.timestamp() as usize, - identity: user.into(), + identity: deployment.into(), } } } -impl From<&Deployment> for AccessToken { - fn from(deployment: &Deployment) -> Self { +impl From<&User> for AccessToken { + fn from(user: &User) -> Self { let iat = chrono::Utc::now(); - let exp = iat + *DEPLOYMENT_TOKEN_DURATION; + let exp = iat + *USER_TOKEN_DURATION; Self { iat: iat.timestamp() as usize, nbf: iat.timestamp() as usize, exp: exp.timestamp() as usize, - identity: deployment.into(), + identity: user.into(), } } } diff --git a/auth/src/lib.rs b/auth/src/lib.rs index 8c9e1b4..2ed7431 100644 --- a/auth/src/lib.rs +++ b/auth/src/lib.rs @@ -9,7 +9,7 @@ mod actix_traits; pub const API_TOKEN_HEADER: &str = "x-platz-token"; -pub use access_token::{AccessToken, DEPLOYMENT_TOKEN_DURATION, USER_TOKEN_DURATION}; +pub use access_token::{AccessToken, USER_TOKEN_DURATION}; pub use api_token::generate_api_token; pub use error::AuthError; pub use identity::ApiIdentity; diff --git a/k8s-agent/src/config.rs b/k8s-agent/src/config.rs index 359271b..834a24b 100644 --- a/k8s-agent/src/config.rs +++ b/k8s-agent/src/config.rs @@ -1,3 +1,4 @@ +use anyhow::{Context, Result}; use url::Url; #[derive(clap::Parser)] @@ -18,10 +19,26 @@ pub struct Config { #[arg( long, env = "PLATZ_DISABLE_DEPLOYMENT_CREDENTIALS", - default_value = "false" + default_value_t = false )] pub disable_deployment_credentials: bool, + /// How often to refresh deployment credentials. + #[arg( + long, + env = "PLATZ_DEPLOYMENT_CREDENTIALS_REFRESH_INTERVAL", + default_value = "20m" + )] + pub deployment_credentials_refresh_interval: humantime::Duration, + + /// Lifetime of issued deployment credential tokens. + #[arg( + long, + env = "PLATZ_DEPLOYMENT_CREDENTIALS_TOKEN_DURATION", + default_value = "1h" + )] + pub deployment_credentials_token_duration: humantime::Duration, + #[arg(long, env = "PLATZ_OWN_URL")] pub platz_url: Url, } @@ -30,4 +47,9 @@ impl Config { pub fn should_refresh_deployment_credintials(&self) -> bool { !self.disable_deployment_credentials } + + pub fn deployment_token_duration(&self) -> Result { + chrono::Duration::from_std(self.deployment_credentials_token_duration.into()) + .context("PLATZ_DEPLOYMENT_CREDENTIALS_TOKEN_DURATION is out of range") + } } diff --git a/k8s-agent/src/deployment_creds/mod.rs b/k8s-agent/src/deployment_creds/mod.rs index c9eb0c4..f661d38 100644 --- a/k8s-agent/src/deployment_creds/mod.rs +++ b/k8s-agent/src/deployment_creds/mod.rs @@ -1,8 +1,8 @@ use crate::{config::Config, k8s::tracker::K8S_TRACKER, task_runner::apply_secret}; -use anyhow::Result; -use futures::future::try_join_all; +use anyhow::{Result, bail}; +use futures::future::join_all; use maplit::btreemap; -use platz_auth::{AccessToken, DEPLOYMENT_TOKEN_DURATION}; +use platz_auth::AccessToken; use platz_db::schema::deployment::Deployment; use tokio::{ select, @@ -18,8 +18,21 @@ const REFRESH_CREDS_SLEEP_BETWEEN_CHUNKS: time::Duration = time::Duration::from_ #[tracing::instrument(err, skip_all, name = "d-creds")] pub async fn start(config: &Config) -> Result<()> { debug!("starting"); - let refresh_every = *DEPLOYMENT_TOKEN_DURATION / 2; - let mut interval = interval(refresh_every.to_std()?); + let refresh_every: time::Duration = config.deployment_credentials_refresh_interval.into(); + let token_duration: time::Duration = config.deployment_credentials_token_duration.into(); + if refresh_every.is_zero() { + bail!("PLATZ_DEPLOYMENT_CREDENTIALS_REFRESH_INTERVAL must be greater than zero"); + } + if refresh_every >= token_duration { + bail!( + "PLATZ_DEPLOYMENT_CREDENTIALS_REFRESH_INTERVAL ({}) must be shorter than \ + PLATZ_DEPLOYMENT_CREDENTIALS_TOKEN_DURATION ({}), otherwise credentials would \ + expire before being refreshed", + config.deployment_credentials_refresh_interval, + config.deployment_credentials_token_duration, + ); + } + let mut interval = interval(refresh_every); let mut k8s_events_rx = K8S_TRACKER.outbound_notifications_rx().await; loop { @@ -45,19 +58,24 @@ pub async fn start(config: &Config) -> Result<()> { async fn refresh_credentials(config: &Config) -> Result<()> { debug!("started"); + let token_duration = config.deployment_token_duration()?; let cluster_ids = K8S_TRACKER.get_ids().await; for deploy_chunk in Deployment::find_by_cluster_ids(cluster_ids) .await? .chunks(REFRESH_CREDS_CHUNK_SIZE) { - try_join_all( + join_all( deploy_chunk .iter() .filter(|deployment| deployment.enabled) - .map(|deployment| apply_deployment_credentials(deployment, &config.platz_url)), + .map(|deployment| { + apply_deployment_credentials(deployment, &config.platz_url, token_duration) + }), ) - .await?; + .await + .into_iter() + .collect::>>()?; time::sleep(REFRESH_CREDS_SLEEP_BETWEEN_CHUNKS).await; } @@ -68,9 +86,10 @@ async fn refresh_credentials(config: &Config) -> Result<()> { pub(crate) async fn apply_deployment_credentials( deployment: &Deployment, platz_url: &Url, + token_duration: chrono::Duration, ) -> Result<()> { debug!("applying"); - let access_token = AccessToken::from(deployment); + let access_token = AccessToken::for_deployment(deployment, token_duration); apply_secret( deployment.cluster_id, &deployment.namespace_name().await?, diff --git a/k8s-agent/src/task_runner/install_and_upgrade.rs b/k8s-agent/src/task_runner/install_and_upgrade.rs index a5409a0..6d0d94f 100644 --- a/k8s-agent/src/task_runner/install_and_upgrade.rs +++ b/k8s-agent/src/task_runner/install_and_upgrade.rs @@ -36,7 +36,12 @@ impl RunnableDeploymentOperation for DeploymentInstallTask { deployment_to_namespace(deployment).await?, ) .await?; - apply_deployment_credentials(deployment, &config.platz_url).await?; + apply_deployment_credentials( + deployment, + &config.platz_url, + config.deployment_token_duration()?, + ) + .await?; match run_helm(config, "install", deployment, task).await { Ok(output) => { deployment.set_revision(Some(task.id)).await?; @@ -131,7 +136,12 @@ impl RunnableDeploymentOperation for DeploymentRecreaseTask { deployment_to_namespace(deployment).await?, ) .await?; - apply_deployment_credentials(deployment, &config.platz_url).await?; + apply_deployment_credentials( + deployment, + &config.platz_url, + config.deployment_token_duration()?, + ) + .await?; Ok("".to_owned()) } }