Skip to content

Commit

Permalink
Use jwt secret from env var (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
smrtrfszm authored Dec 8, 2024
1 parent f3e15e6 commit b380634
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ jobs:
- bans licenses sources
steps:
- uses: actions/checkout@v2
- uses: EmbarkStudios/cargo-deny-action@v1
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check ${{ matrix.checks }}
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ serde_json = "1.0.120"
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread", "signal"] }
tracing = { version = "0.1.40", default-features = false }
uuid = { version = "1.10.0", default-features = false, features = ["v4"] }
ed25519-dalek = { version = "2.1.1", features = ["pkcs8", "rand_core"] }
2 changes: 2 additions & 0 deletions iam-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ path = "main.rs"

[dependencies]
anyhow.workspace = true
base64.workspace = true
clap = { version = "4.5.11", features = ["cargo", "env"] }
dotenvy.workspace = true
ed25519-dalek.workspace = true
iam-common.workspace = true
iam-entity.workspace = true
k8s-openapi = { version = "0.22.0", features = ["earliest"] }
Expand Down
45 changes: 44 additions & 1 deletion iam-cli/commands/setup.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use anyhow::Context;
use base64::{prelude::BASE64_STANDARD, Engine};
use clap::{Arg, ArgAction, ArgMatches, Command};
use ed25519_dalek::SigningKey;
use k8s_openapi::api::core::v1::Secret;
use kube::{
api::{ObjectMeta, PostParams},
Expand Down Expand Up @@ -39,7 +41,8 @@ pub fn command() -> Command {
pub async fn run(matches: &ArgMatches) -> anyhow::Result<()> {
let client = Client::try_default().await?;

create_admin_user(matches, client).await?;
create_jwt_secret_key(client.clone()).await?;
create_admin_user(matches, client.clone()).await?;

Ok(())
}
Expand Down Expand Up @@ -93,3 +96,43 @@ async fn create_admin_user(matches: &ArgMatches, client: Client) -> anyhow::Resu

Ok(())
}

async fn create_jwt_secret_key(client: Client) -> anyhow::Result<()> {
const SECRET_NAME: &str = "iam-jwt";

let key = SigningKey::generate(&mut OsRng);
let bytes = BASE64_STANDARD.encode(key.to_bytes());

let secrets: Api<Secret> = Api::default_namespaced(client);

if secrets
.get_opt(SECRET_NAME)
.await
.context("Failed to query iam-jwt secret")?
.is_some()
{
println!("iam-jwt secret already exists.");
return Ok(());
}

secrets
.create(
&PostParams::default(),
&Secret {
metadata: ObjectMeta {
name: Some(SECRET_NAME.to_owned()),
..Default::default()
},
string_data: Some({
let mut map = BTreeMap::new();
map.insert("IAM_JWT_SECRET_KEY".to_owned(), bytes);
map
}),
..Default::default()
},
)
.await
.context("Failed to create secret")?;

Ok(())
}
2 changes: 1 addition & 1 deletion iam-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ bytes = "1.6.1"
serde_json.workspace = true
mime.workspace = true
base64.workspace = true
ed25519-dalek = { version = "2.1.1", features = ["pkcs8", "rand_core"] }
ed25519-dalek.workspace = true
jose-jwk = { version = "0.1.2", default-features = false }
anyhow.workspace = true
2 changes: 1 addition & 1 deletion iam-common/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'de> Deserialize<'de> for Id {

struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
impl de::Visitor<'_> for Visitor {
type Value = Id;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
Expand Down
20 changes: 18 additions & 2 deletions iam-common/keys/key.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use ed25519_dalek::{pkcs8::EncodePrivateKey, SigningKey};
use base64::{prelude::BASE64_STANDARD, Engine};
use ed25519_dalek::{pkcs8::EncodePrivateKey, SecretKey, SigningKey, SECRET_KEY_LENGTH};
use jose_jwk::{Jwk, Okp, OkpCurves, Parameters};
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey};
use rand::rngs::OsRng;
use std::env;

pub struct Key {
pub(super) jwk: Jwk,
Expand All @@ -10,8 +12,14 @@ pub struct Key {
}

impl Key {
pub(super) fn generate() -> Key {
#[allow(unused)]
pub(super) fn generate() -> Self {
let private_key = SigningKey::generate(&mut OsRng);
Self::from_private_key(private_key.as_bytes())
}

pub(super) fn from_private_key(secret_key: &SecretKey) -> Self {
let private_key = SigningKey::from_bytes(secret_key);
let public_key = private_key.verifying_key();

let bytes = Box::new(public_key.to_bytes()) as Box<[u8]>;
Expand All @@ -38,6 +46,14 @@ impl Key {
}
}

// TODO: this is a temporary solution
pub(super) fn from_env() -> Self {
let key = env::var("IAM_JWT_SECRET_KEY").unwrap();
let key = BASE64_STANDARD.decode(key).unwrap();
assert_eq!(key.len(), SECRET_KEY_LENGTH);
Self::from_private_key(&key.try_into().unwrap())
}

pub fn get_alg(&self) -> Algorithm {
match self.jwk.key {
jose_jwk::Key::Okp(Okp {
Expand Down
2 changes: 1 addition & 1 deletion iam-common/keys/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct KeyManager {
impl KeyManager {
pub fn new() -> Self {
Self {
jwt_key: Key::generate(),
jwt_key: Key::from_env(),
}
}

Expand Down

0 comments on commit b380634

Please sign in to comment.