Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions auth/src/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>, AuthError> {
Expand Down Expand Up @@ -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(),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 23 additions & 1 deletion k8s-agent/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use anyhow::{Context, Result};
use url::Url;

#[derive(clap::Parser)]
Expand All @@ -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,
}
Expand All @@ -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> {
chrono::Duration::from_std(self.deployment_credentials_token_duration.into())
.context("PLATZ_DEPLOYMENT_CREDENTIALS_TOKEN_DURATION is out of range")
}
}
37 changes: 28 additions & 9 deletions k8s-agent/src/deployment_creds/mod.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 {
Expand All @@ -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::<Result<Vec<_>>>()?;
time::sleep(REFRESH_CREDS_SLEEP_BETWEEN_CHUNKS).await;
}

Expand All @@ -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?,
Expand Down
14 changes: 12 additions & 2 deletions k8s-agent/src/task_runner/install_and_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;
Expand Down Expand Up @@ -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())
}
}
Expand Down
Loading