Skip to content

Commit

Permalink
auth-server: Add management key and gate key management API
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Oct 24, 2024
1 parent 0049346 commit bf849d6
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 90 deletions.
324 changes: 258 additions & 66 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions auth/auth-server-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![deny(clippy::needless_pass_by_ref_mut)]
#![feature(trivial_bounds)]

use serde::Deserialize;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// The Renegade API key header
Expand All @@ -26,7 +26,7 @@ pub const API_KEYS_PATH: &str = "api-keys";
pub const DEACTIVATE_API_KEY_PATH: &str = "/api-keys/{id}/deactivate";

/// A request to create a new API key
#[derive(Debug, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateApiKeyRequest {
/// The API key id
pub id: Uuid,
Expand Down
11 changes: 8 additions & 3 deletions auth/auth-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ rand = "0.8.5"

# === Renegade Dependencies === #
auth-server-api = { path = "../auth-server-api" }
renegade-common = { package = "common", git = "https://github.com/renegade-fi/renegade.git" }
renegade-util = { package = "util", git = "https://github.com/renegade-fi/renegade.git" }
renegade-api = { package = "external-api", git = "https://github.com/renegade-fi/renegade.git", features = [
# renegade-common = { package = "common", git = "https://github.com/renegade-fi/renegade.git" }
# renegade-util = { package = "util", git = "https://github.com/renegade-fi/renegade.git" }
# renegade-api = { package = "external-api", git = "https://github.com/renegade-fi/renegade.git", features = [
# "auth",
# ] }
renegade-common = { package = "common", path = "/Users/joeykraut/work/renegade/common" }
renegade-util = { package = "util", path = "/Users/joeykraut/work/renegade/util" }
renegade-api = { package = "external-api", path = "/Users/joeykraut/work/renegade/external-api", features = [
"auth",
] }

Expand Down
34 changes: 28 additions & 6 deletions auth/auth-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ pub(crate) mod models;
pub(crate) mod schema;
mod server;

use auth_server_api::API_KEYS_PATH;
use auth_server_api::{CreateApiKeyRequest, API_KEYS_PATH};
use bytes::Bytes;
use clap::Parser;
use http::HeaderMap;
use renegade_util::telemetry::configure_telemetry;
use reqwest::StatusCode;
use serde::Deserialize;
use serde_json::json;
use std::net::SocketAddr;
use std::sync::Arc;
use thiserror::Error;
use tracing::{error, info};
use uuid::Uuid;
use warp::{Filter, Rejection, Reply};
use warp::{filters::path::FullPath, Filter, Rejection, Reply};

use server::Server;

Expand All @@ -48,6 +51,10 @@ pub struct Cli {
/// The encryption key used to encrypt/decrypt database values
#[arg(long, env = "ENCRYPTION_KEY")]
pub encryption_key: String,
/// The management key for the auth server, used to authenticate management
/// requests
#[arg(long, env = "MANAGEMENT_KEY")]
pub management_key: String,
/// The URL of the relayer
#[arg(long, env = "RELAYER_URL")]
pub relayer_url: String,
Expand Down Expand Up @@ -86,6 +93,12 @@ impl ApiError {
pub fn internal<T: ToString>(msg: T) -> Self {
Self::InternalError(msg.to_string())
}

/// Create a new bad request error
#[allow(clippy::needless_pass_by_value)]
pub fn bad_request<T: ToString>(msg: T) -> Self {
Self::BadRequest(msg.to_string())
}
}

// Implement warp::reject::Reject for ApiError
Expand Down Expand Up @@ -126,17 +139,26 @@ async fn main() {
// Add an API key
let add_api_key = warp::path(API_KEYS_PATH)
.and(warp::post())
.and(warp::body::json())
.and(warp::path::full())
.and(warp::header::headers_cloned())
.and(warp::body::bytes())
.and(with_server(server.clone()))
.and_then(|request, server: Arc<Server>| async move { server.add_key(request).await });
.and_then(|path, headers, body, server: Arc<Server>| async move {
server.add_key(path, headers, body).await
});

// Expire an API key
let expire_api_key = warp::path(API_KEYS_PATH)
.and(warp::path::param::<Uuid>())
.and(warp::path("deactivate"))
.and(warp::path::full())
.and(warp::header::headers_cloned())
.and(warp::body::bytes())
.and(warp::post())
.and(with_server(server.clone()))
.and_then(|id: Uuid, server: Arc<Server>| async move { server.expire_key(id).await });
.and_then(|id, path, headers, body, server: Arc<Server>| async move {
server.expire_key(id, path, headers, body).await
});

// --- Proxied Routes --- //

Expand All @@ -155,7 +177,7 @@ async fn main() {
// Bind the server and listen
info!("Starting auth server on port {}", listen_addr.port());
let routes =
ping.or(add_api_key).or(expire_api_key).or(atomic_match_path).recover(handle_rejection);
ping.or(atomic_match_path).or(expire_api_key).or(add_api_key).recover(handle_rejection);
warp::serve(routes).bind(listen_addr).await;
}

Expand Down
13 changes: 13 additions & 0 deletions auth/auth-server/src/server/api_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@ use auth_server_api::RENEGADE_API_KEY_HEADER;
use http::HeaderMap;
use renegade_api::auth::validate_expiring_auth;
use renegade_common::types::wallet::keychain::HmacKey;
use serde::Serialize;
use uuid::Uuid;
use warp::filters::path::FullPath;

use crate::{error::AuthServerError, ApiError};

use super::{helpers::aes_decrypt, Server};

impl Server {
/// Authorize a management request
pub fn authorize_management_request(
&self,
path: FullPath,
headers: &HeaderMap,
body: &[u8],
) -> Result<(), ApiError> {
validate_expiring_auth(path.as_str(), headers, body, &self.management_key)
.map_err(|_| ApiError::Unauthorized)
}

/// Authorize a request
pub(crate) async fn authorize_request(
&self,
Expand Down
35 changes: 29 additions & 6 deletions auth/auth-server/src/server/handle_key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

use crate::models::NewApiKey;
use auth_server_api::CreateApiKeyRequest;
use bytes::Bytes;
use http::HeaderMap;
use uuid::Uuid;
use warp::{reject::Rejection, reply::Reply};
use warp::{filters::path::FullPath, reject::Rejection, reply::Reply};

use crate::ApiError;

Expand All @@ -14,18 +16,39 @@ use super::{

impl Server {
/// Add a new API key to the database
pub async fn add_key(&self, req: CreateApiKeyRequest) -> Result<impl Reply, Rejection> {
pub async fn add_key(
&self,
path: FullPath,
headers: HeaderMap,
body: Bytes,
) -> Result<impl Reply, Rejection> {
// Check management auth on the request
self.authorize_management_request(path, &headers, &body)?;

// Deserialize the request
let req: CreateApiKeyRequest =
serde_json::from_slice(&body).map_err(ApiError::bad_request)?;

// Add the key to the database
let encrypted_secret = aes_encrypt(&req.secret, &self.encryption_key)?;
let new_key = NewApiKey::new(req.id, encrypted_secret, req.description);
self.add_key_query(new_key)
.await
.map_err(|e| warp::reject::custom(ApiError::InternalError(e.to_string())))?;
self.add_key_query(new_key).await.map_err(ApiError::internal)?;

Ok(empty_json_reply())
}

/// Expire an existing API key
pub async fn expire_key(&self, key_id: Uuid) -> Result<impl Reply, Rejection> {
pub async fn expire_key(
&self,
key_id: Uuid,
path: FullPath,
headers: HeaderMap,
body: Bytes,
) -> Result<impl Reply, Rejection> {
// Check management auth on the request
self.authorize_management_request(path, &headers, &body)?;

// Expire the key
self.expire_key_query(key_id)
.await
.map_err(|e| warp::reject::custom(ApiError::InternalError(e.to_string())))?;
Expand Down
10 changes: 6 additions & 4 deletions auth/auth-server/src/server/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub fn aes_decrypt(value: &str, key: &[u8]) -> Result<String, AuthServerError> {

#[cfg(test)]
mod tests {
use renegade_common::types::wallet::keychain::HmacKey;

use super::*;

/// Tests AES encryption and decryption
Expand All @@ -66,11 +68,11 @@ mod tests {
assert_eq!(value, decrypted);
}

/// Generate an encryption key, base64 encode it, and print it
/// Generate a management key
#[test]
pub fn generate_encryption_key() {
let key = Aes128Gcm::generate_key(&mut thread_rng());
let encoded = general_purpose::STANDARD.encode(&key);
fn test_generate_management_key() {
let key = HmacKey::random();
let encoded = general_purpose::STANDARD.encode(key.0);
println!("{}", encoded);
}
}
11 changes: 8 additions & 3 deletions auth/auth-server/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub struct Server {
pub relayer_url: String,
/// The admin key for the relayer
pub relayer_admin_key: HmacKey,
/// The management key for the auth server
pub management_key: HmacKey,
/// The encryption key for storing API secrets
pub encryption_key: Vec<u8>,
/// The HTTP client
Expand All @@ -53,18 +55,21 @@ impl Server {
// Setup the DB connection pool
let db_pool = create_db_pool(&args.database_url).await?;

// Parse the decryption key as a base64 encoded string
// Parse the decryption key, management key, and relayer admin key as
// base64 encoded strings
let encryption_key = general_purpose::STANDARD
.decode(&args.encryption_key)
.map_err(AuthServerError::encryption)?;

let management_key =
HmacKey::from_base64_string(&args.management_key).map_err(AuthServerError::setup)?;
let relayer_admin_key =
HmacKey::from_base64_string(&args.relayer_admin_key).map_err(AuthServerError::setup)?;

Ok(Self {
db_pool: Arc::new(db_pool),
relayer_url: args.relayer_url,
relayer_admin_key,
management_key,
encryption_key,
client: Client::new(),
})
Expand All @@ -84,7 +89,7 @@ impl Server {
body: Bytes,
) -> Result<Response<Bytes>, ApiError> {
// Admin authenticate the request
self.admin_authenticate(path, &mut headers, &body).await?;
self.admin_authenticate(path, &mut headers, &body)?;

// Forward the request to the relayer
let url = format!("{}{}", self.relayer_url, path);
Expand Down

0 comments on commit bf849d6

Please sign in to comment.