Skip to content

Commit 55c1a54

Browse files
committed
Add a JWT-SVID authentication method
Using this method, the client will fetch its JWT-SVID and send it in the authentication field. The socket endpoint is found through the SPIFFE_ENDPOINT_SOCKET environment variable. Signed-off-by: Hugues de Valon <[email protected]>
1 parent 921a603 commit 55c1a54

File tree

5 files changed

+44
-6
lines changed

5 files changed

+44
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ log = "0.4.11"
1919
derivative = "2.1.1"
2020
zeroize = "1.1.0"
2121
users = "0.10.0"
22+
spiffe = { path = "../../rust-spiffe/spiffe" }
2223

2324
[dev-dependencies]
2425
mockstream = "0.0.3"

src/auth.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// Copyright 2020 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
33
//! Client app authentication data
4+
use crate::error::{ClientErrorKind, Error, Result};
5+
use log::error;
46
use parsec_interface::requests::{request::RequestAuth, AuthType};
7+
use spiffe::workload::jwt::JWTClient;
8+
use std::convert::TryFrom;
9+
use std::env;
510

611
/// Authentication data used in Parsec requests
712
#[derive(Clone, Debug)]
@@ -19,6 +24,10 @@ pub enum Authentication {
1924
/// Used for authentication via Peer Credentials provided by Unix
2025
/// operating systems for Domain Socket connections.
2126
UnixPeerCredentials,
27+
/// Authentication using JWT SVID tokens. The will fetch its JWT-SVID and pass it in the
28+
/// Authentication field. The socket endpoint is found through the SPIFFE_ENDPOINT_SOCKET
29+
/// environment variable.
30+
JwtSvid,
2231
}
2332

2433
impl Authentication {
@@ -28,18 +37,40 @@ impl Authentication {
2837
Authentication::None => AuthType::NoAuth,
2938
Authentication::Direct(_) => AuthType::Direct,
3039
Authentication::UnixPeerCredentials => AuthType::UnixPeerCredentials,
40+
Authentication::JwtSvid => AuthType::JwtSvid,
3141
}
3242
}
3343
}
3444

35-
impl From<&Authentication> for RequestAuth {
36-
fn from(data: &Authentication) -> Self {
45+
impl TryFrom<&Authentication> for RequestAuth {
46+
type Error = Error;
47+
48+
fn try_from(data: &Authentication) -> Result<Self> {
3749
match data {
38-
Authentication::None => RequestAuth::new(Vec::new()),
39-
Authentication::Direct(name) => RequestAuth::new(name.bytes().collect()),
50+
Authentication::None => Ok(RequestAuth::new(Vec::new())),
51+
Authentication::Direct(name) => Ok(RequestAuth::new(name.bytes().collect())),
4052
Authentication::UnixPeerCredentials => {
4153
let current_uid = users::get_current_uid();
42-
RequestAuth::new(current_uid.to_le_bytes().to_vec())
54+
Ok(RequestAuth::new(current_uid.to_le_bytes().to_vec()))
55+
}
56+
Authentication::JwtSvid => {
57+
let client = JWTClient::new(
58+
&env::var("SPIFFE_ENDPOINT_SOCKET").map_err(|e| {
59+
error!(
60+
"Can not read the SPIFFE_ENDPOINT_SOCKET environment variable ({}).",
61+
e
62+
);
63+
Error::Client(ClientErrorKind::Spiffe)
64+
})?,
65+
None,
66+
);
67+
let audience = String::from("parsec");
68+
69+
let result = client.fetch(audience, None).map_err(|e| {
70+
error!("Error while fetching the JWT-SVID ({}).", e);
71+
Error::Client(ClientErrorKind::Spiffe)
72+
})?;
73+
Ok(RequestAuth::new(result.svid().as_bytes().into()))
4374
}
4475
}
4576
}

src/core/basic_client.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ impl BasicClient {
258258
AuthType::UnixPeerCredentials => {
259259
self.auth_data = Authentication::UnixPeerCredentials
260260
}
261+
AuthType::JwtSvid => self.auth_data = Authentication::JwtSvid,
261262
auth => {
262263
warn!(
263264
"Authenticator of type \"{:?}\" not supported by this client library",

src/core/operation_client.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use parsec_interface::operations_protobuf::ProtobufConverter;
1212
use parsec_interface::requests::{
1313
request::RequestHeader, Opcode, ProviderID, Request, Response, ResponseStatus,
1414
};
15+
use std::convert::TryInto;
1516

1617
/// Low-level client optimised for communicating with the Parsec service at an operation level.
1718
///
@@ -66,7 +67,7 @@ impl OperationClient {
6667
Ok(Request {
6768
header,
6869
body,
69-
auth: auth.into(),
70+
auth: auth.try_into()?,
7071
})
7172
}
7273

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub enum ClientErrorKind {
4242
NoAuthenticator,
4343
/// Required parameter was not provided
4444
MissingParam,
45+
/// Error while using the SPIFFE Workload API
46+
Spiffe,
4547
}
4648

4749
impl From<ClientErrorKind> for Error {
@@ -74,6 +76,7 @@ impl PartialEq for ClientErrorKind {
7476
ClientErrorKind::NoProvider => matches!(other, ClientErrorKind::NoProvider),
7577
ClientErrorKind::NoAuthenticator => matches!(other, ClientErrorKind::NoAuthenticator),
7678
ClientErrorKind::MissingParam => matches!(other, ClientErrorKind::MissingParam),
79+
ClientErrorKind::Spiffe => matches!(other, ClientErrorKind::Spiffe),
7780
}
7881
}
7982
}
@@ -93,6 +96,7 @@ impl fmt::Display for ClientErrorKind {
9396
ClientErrorKind::NoProvider => write!(f, "client is missing an implicit provider"),
9497
ClientErrorKind::NoAuthenticator => write!(f, "service is not reporting any authenticators or none of the reported ones are supported by the client"),
9598
ClientErrorKind::MissingParam => write!(f, "one of the `Option` parameters was required but was not provided"),
99+
ClientErrorKind::Spiffe => write!(f, "error using the SPIFFE Workload API"),
96100
}
97101
}
98102
}

0 commit comments

Comments
 (0)