From 2a0a200cbfc71180fbf1c5a16179392861be9806 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Wed, 27 Jan 2021 11:17:44 +0000 Subject: [PATCH] Add SPIFFE authentication via the new crate As the number of dependencies introduced by the new crate is high, add it as a separate feature. The functionality is the same as the `spiffe` branch but with a released crate named "spiffe". Signed-off-by: Hugues de Valon --- Cargo.toml | 2 ++ README.md | 3 ++- src/auth.rs | 23 +++++++++++++++++++++++ src/core/basic_client.rs | 2 ++ src/error.rs | 5 +++++ tests/ci.sh | 1 + 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 39ae4ad..7f53ab2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,12 @@ derivative = "2.1.1" zeroize = "1.1.0" users = "0.10.0" url = "2.2.0" +spiffe = { version = "0.1.1", optional = true } [dev-dependencies] mockstream = "0.0.3" [features] default = [] +spiffe-auth = ["spiffe"] testing = ["parsec-interface/testing"] diff --git a/README.md b/README.md index 6ef6cc4..2e18c68 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ This repository contains a Rust client for consuming the API provided by the [Parsec service](https://github.com/parallaxsecond/parsec). The low-level functionality that this library uses for IPC is implemented in the [interface crate](https://github.com/parallaxsecond/parsec-interface-rs). -Check out the `spiffe` branch for JWT SVID authentication feature. +When using the JWT-SVID authentication method, the client will expect the `SPIFFE_ENDPOINT_SOCKET` environment variable to contain the path of the Workload API endpoint. +See the [SPIFFE Workload Endpoint](https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE_Workload_Endpoint.md#4-locating-the-endpoint) for more information. ## Locating the Parsec endpoint diff --git a/src/auth.rs b/src/auth.rs index c8ceebf..0279493 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -21,6 +21,11 @@ pub enum Authentication { /// Used for authentication via Peer Credentials provided by Unix /// operating systems for Domain Socket connections. UnixPeerCredentials, + /// Authentication using JWT SVID tokens. The will fetch its JWT-SVID and pass it in the + /// Authentication field. The socket endpoint is found through the SPIFFE_ENDPOINT_SOCKET + /// environment variable. + #[cfg(feature = "spiffe-auth")] + JwtSvid, } impl Authentication { @@ -30,6 +35,8 @@ impl Authentication { Authentication::None => AuthType::NoAuth, Authentication::Direct(_) => AuthType::Direct, Authentication::UnixPeerCredentials => AuthType::UnixPeerCredentials, + #[cfg(feature = "spiffe-auth")] + Authentication::JwtSvid => AuthType::JwtSvid, } } } @@ -45,6 +52,20 @@ impl TryFrom<&Authentication> for RequestAuth { let current_uid = users::get_current_uid(); Ok(RequestAuth::new(current_uid.to_le_bytes().to_vec())) } + #[cfg(feature = "spiffe-auth")] + Authentication::JwtSvid => { + use crate::error::ClientErrorKind; + use log::error; + use spiffe::workload_api::client::WorkloadApiClient; + + let client = WorkloadApiClient::default().unwrap(); + let token = client.fetch_jwt_token(&["parsec"], None).map_err(|e| { + error!("Error while fetching the JWT-SVID ({}).", e); + Error::Client(ClientErrorKind::Spiffe(e)) + })?; + + Ok(RequestAuth::new(token.as_bytes().into())) + } } } } @@ -57,6 +78,8 @@ impl PartialEq for Authentication { (Authentication::Direct(app_name), Authentication::Direct(other_app_name)) => { app_name == other_app_name } + #[cfg(feature = "spiffe-auth")] + (Authentication::JwtSvid, Authentication::JwtSvid) => true, _ => false, } } diff --git a/src/core/basic_client.rs b/src/core/basic_client.rs index 2463b4c..13c2aec 100644 --- a/src/core/basic_client.rs +++ b/src/core/basic_client.rs @@ -263,6 +263,8 @@ impl BasicClient { AuthType::UnixPeerCredentials => { self.auth_data = Authentication::UnixPeerCredentials } + #[cfg(feature = "spiffe-auth")] + AuthType::JwtSvid => self.auth_data = Authentication::JwtSvid, auth => { warn!( "Authenticator of type \"{:?}\" not supported by this client library", diff --git a/src/error.rs b/src/error.rs index 81ee5f9..503ff1b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -48,6 +48,9 @@ pub enum ClientErrorKind { InvalidSocketAddress, /// The socket URL is invalid InvalidSocketUrl, + /// Error while using the SPIFFE Workload API + #[cfg(feature = "spiffe-auth")] + Spiffe(spiffe::workload_api::client::ClientError), } impl From for Error { @@ -80,6 +83,8 @@ impl fmt::Display for ClientErrorKind { ClientErrorKind::NotFound => write!(f, "one of the resources required in the operation was not found"), ClientErrorKind::InvalidSocketAddress => write!(f, "the socket address provided in the URL is not valid"), ClientErrorKind::InvalidSocketUrl => write!(f, "the socket URL is invalid"), + #[cfg(feature = "spiffe-auth")] + ClientErrorKind::Spiffe(error) => error.fmt(f), } } } diff --git a/tests/ci.sh b/tests/ci.sh index 746db3e..b111365 100755 --- a/tests/ci.sh +++ b/tests/ci.sh @@ -13,6 +13,7 @@ set -euf -o pipefail ################ RUST_BACKTRACE=1 cargo build RUST_BACKTRACE=1 cargo build --features testing +RUST_BACKTRACE=1 cargo build --features spiffe-auth RUST_BACKTRACE=1 cargo build --no-default-features #################