Skip to content

Commit 55456ec

Browse files
committed
finished up integration tests
Signed-off-by: Eitan Yarmush <[email protected]>
1 parent 616704a commit 55456ec

File tree

7 files changed

+249
-34
lines changed

7 files changed

+249
-34
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
runs-on: ubuntu-latest
3838
env:
3939
SPIFFE_ENDPOINT_SOCKET: unix:/tmp/spire-agent/public/api.sock
40-
SPIFFE_ADMIN_ENDPOINT_SOCKET: unix:/tmp/spire-agent/admin/api.sock
40+
SPIRE_ADMIN_ENDPOINT_SOCKET: unix:/tmp/spire-agent/admin/api.sock
4141
needs: build
4242
steps:
4343
- name: Check out code

scripts/agent.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ agent {
99
# simple testing/evaluation purposes.
1010
insecure_bootstrap = true
1111

12-
admin_socket_path = "$STRIPPED_SPIFFE_ADMIN_ENDPOINT_SOCKET"
12+
admin_socket_path = "$STRIPPED_SPIRE_ADMIN_ENDPOINT_SOCKET"
1313
authorized_delegates = [
1414
"spiffe://example.org/myservice",
1515
]

scripts/run-spire.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ mkdir -p /tmp/spire-server
3737
bin/spire-server run -config conf/server/server.conf > "${spire_server_log_file}" 2>&1 &
3838
wait_for_service "bin/spire-server healthcheck" "SPIRE Server" "${spire_server_log_file}"
3939

40-
export STRIPPED_SPIFFE_ADMIN_ENDPOINT_SOCKET=$(echo $SPIFFE_ADMIN_ENDPOINT_SOCKET| cut -c6-)
40+
export STRIPPED_SPIRE_ADMIN_ENDPOINT_SOCKET=$(echo $SPIRE_ADMIN_ENDPOINT_SOCKET| cut -c6-)
4141
cat $SCRIPT_DIR/agent.conf | envsubst > "conf/agent/agent.conf"
4242

4343
# Run the SPIRE agent with the joint token

spire-api/Cargo.toml

+1-11
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,9 @@ prost-types = {version = "0.11"}
2323
tokio = { "version" = "1", features = ["net", "test-util"]}
2424
tokio-stream = "0.1"
2525
tower = { version = "0.4", features = ["util"] }
26-
thiserror = "1.0"
27-
url = "2.2"
28-
asn1 = { package = "simple_asn1", version = "0.6" }
29-
x509-parser = "0.15"
30-
pkcs8 = "0.10"
31-
jsonwebtoken = "8.3"
32-
jsonwebkey = { version = "0.3", features = ["jsonwebtoken", "jwt-convert"] }
33-
serde = { version = "1.0", features = ["derive"] }
34-
serde_json = "1.0"
35-
zeroize = { version = "1.6", features = ["zeroize_derive"] }
36-
time = "0.3"
3726

3827
[dev-dependencies]
28+
once_cell = "1.18"
3929

4030
[build-dependencies]
4131
tonic-build = { version = "0.9", default-features = false, features = ["prost"] }

spire-api/src/agent/delegated_identity.rs

+115-7
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,29 @@
88
99
use crate::proto::spire::api::agent::delegatedidentity::v1::{
1010
delegated_identity_client::DelegatedIdentityClient as DelegatedIdentityApiClient,
11-
SubscribeToX509BundlesRequest, SubscribeToX509BundlesResponse, SubscribeToX509sviDsRequest,
12-
SubscribeToX509sviDsResponse,
11+
FetchJwtsviDsRequest, SubscribeToX509BundlesRequest, SubscribeToX509BundlesResponse,
12+
SubscribeToX509sviDsRequest, SubscribeToX509sviDsResponse, SubscribeToJwtBundlesRequest,
13+
SubscribeToJwtBundlesResponse,
1314
};
15+
use crate::proto::spire::api::types::Jwtsvid as ProtoJwtSvid;
1416
use spiffe::bundle::x509::{X509Bundle, X509BundleSet};
17+
use spiffe::bundle::jwt::{JwtBundleSet, JwtBundle};
1518
use spiffe::spiffe_id::TrustDomain;
19+
use spiffe::svid::jwt::JwtSvid;
1620
use spiffe::svid::x509::X509Svid;
1721
use spiffe::workload_api::address::validate_socket_path;
1822
use tokio_stream::{Stream, StreamExt};
1923

2024
use crate::selectors::Selector;
2125
use spiffe::workload_api::client::{ClientError, DEFAULT_SVID};
2226
use std::convert::{Into, TryFrom};
27+
use std::str::FromStr;
2328
use tokio::net::UnixStream;
2429
use tonic::transport::{Endpoint, Uri};
2530
use tower::service_fn;
2631

2732
/// Name of the environment variable that holds the default socket endpoint path.
28-
pub const ADMIN_SOCKET_ENV: &str = "SPIFFE_ADMIN_ENDPOINT_SOCKET";
33+
pub const ADMIN_SOCKET_ENV: &str = "SPIRE_ADMIN_ENDPOINT_SOCKET";
2934

3035
/// Gets the endpoint socket endpoint path from the environment variable `ADMIN_SOCKET_ENV`,
3136
/// as described in [SPIFFE standard](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Workload_Endpoint.md#4-locating-the-endpoint).
@@ -132,7 +137,7 @@ impl DelegatedIdentityClient {
132137
///
133138
/// Returns [`ClientError`] if the gRPC call fails or if the SVID could not be parsed from the gRPC response.
134139
pub async fn fetch_x509_svid(
135-
mut self,
140+
&mut self,
136141
selectors: Vec<Selector>,
137142
) -> Result<X509Svid, ClientError> {
138143
let request = SubscribeToX509sviDsRequest {
@@ -172,7 +177,7 @@ impl DelegatedIdentityClient {
172177
///
173178
/// Individual stream items might also be errors if there's an issue processing the response for a specific update.
174179
pub async fn stream_x509_svids(
175-
mut self,
180+
&mut self,
176181
selectors: Vec<Selector>,
177182
) -> Result<impl Stream<Item = Result<X509Svid, ClientError>>, ClientError> {
178183
let request = SubscribeToX509sviDsRequest {
@@ -197,7 +202,7 @@ impl DelegatedIdentityClient {
197202
///
198203
/// The function returns a variant of [`ClientError`] if there is en error connecting to the Workload API or
199204
/// there is a problem processing the response.
200-
pub async fn fetch_x509_bundles(mut self) -> Result<X509BundleSet, ClientError> {
205+
pub async fn fetch_x509_bundles(&mut self) -> Result<X509BundleSet, ClientError> {
201206
let request = SubscribeToX509BundlesRequest::default();
202207

203208
let response: tonic::Response<tonic::Streaming<SubscribeToX509BundlesResponse>> =
@@ -227,7 +232,7 @@ impl DelegatedIdentityClient {
227232
///
228233
/// Individual stream items might also be errors if there's an issue processing the response for a specific update.
229234
pub async fn stream_x509_bundles(
230-
mut self,
235+
&mut self,
231236
) -> Result<impl Stream<Item = Result<X509BundleSet, ClientError>>, ClientError> {
232237
let request = SubscribeToX509BundlesRequest::default();
233238

@@ -242,6 +247,83 @@ impl DelegatedIdentityClient {
242247

243248
Ok(stream)
244249
}
250+
251+
/// Fetches a list of [`JwtSvid`] parsing the JWT token in the Workload API response, for the given audience and selectors.
252+
///
253+
/// # Arguments
254+
///
255+
/// * `audience` - A list of audiences to include in the JWT token. Cannot be empty nor contain only empty strings.
256+
/// * `selectors` - A list of selectors to filter the list of [`JwtSvid`].
257+
///
258+
/// # Errors
259+
///
260+
/// The function returns a variant of [`ClientError`] if there is en error connecting to the Workload API or
261+
/// there is a problem processing the response.
262+
pub async fn fetch_jwt_svids<T: AsRef<str> + ToString>(
263+
&mut self,
264+
audience: &[T],
265+
selectors: Vec<Selector>,
266+
) -> Result<Vec<JwtSvid>, ClientError> {
267+
let request = FetchJwtsviDsRequest {
268+
audience: audience.iter().map(|s| s.to_string()).collect(),
269+
selectors: selectors.into_iter().map(|s| s.into()).collect(),
270+
};
271+
272+
DelegatedIdentityClient::parse_jwt_svid_from_grpc_response(
273+
self.client
274+
.fetch_jwtsvi_ds(request)
275+
.await?
276+
.into_inner()
277+
.svids,
278+
)
279+
}
280+
281+
282+
283+
/// Watches the stream of [`JwtBundleSet`] updates.
284+
///
285+
/// This function establishes a stream with the Workload API to continuously receive updates for the [`JwtBundleSet`].
286+
/// The returned stream can be used to asynchronously yield new `JwtBundleSet` updates as they become available.
287+
///
288+
/// # Returns
289+
///
290+
/// Returns a stream of `Result<JwtBundleSet, ClientError>`. Each item represents an updated [`JwtBundleSet`] or an error if
291+
/// there was a problem processing an update from the stream.
292+
///
293+
/// # Errors
294+
///
295+
/// The function can return an error variant of [`ClientError`] in the following scenarios:
296+
///
297+
/// * There's an issue connecting to the Workload API.
298+
/// * An error occurs while setting up the stream.
299+
///
300+
/// Individual stream items might also be errors if there's an issue processing the response for a specific update.
301+
pub async fn stream_jwt_bundles(
302+
&mut self,
303+
) -> Result<impl Stream<Item = Result<JwtBundleSet, ClientError>>, ClientError> {
304+
let request = SubscribeToJwtBundlesRequest::default();
305+
let response = self.client.subscribe_to_jwt_bundles(request).await?;
306+
Ok(response.into_inner().map(|message| {
307+
message
308+
.map_err(ClientError::from)
309+
.and_then(DelegatedIdentityClient::parse_jwt_bundle_set_from_grpc_response)
310+
}))
311+
}
312+
313+
/// Fetches [`JwtBundleSet`] that is a set of [`JwtBundle`] keyed by the trust domain to which they belong.
314+
///
315+
/// # Errors
316+
///
317+
/// The function returns a variant of [`ClientError`] if there is en error connecting to the Workload API or
318+
/// there is a problem processing the response.
319+
pub async fn fetch_jwt_bundles(
320+
&mut self,
321+
) -> Result<JwtBundleSet, ClientError> {
322+
let request = SubscribeToJwtBundlesRequest::default();
323+
let response = self.client.subscribe_to_jwt_bundles(request).await?;
324+
let initial = response.into_inner().message().await?;
325+
DelegatedIdentityClient::parse_jwt_bundle_set_from_grpc_response(initial.ok_or(ClientError::EmptyResponse)?)
326+
}
245327
}
246328

247329
impl DelegatedIdentityClient {
@@ -266,6 +348,32 @@ impl DelegatedIdentityClient {
266348
.map_err(|e| e.into())
267349
}
268350

351+
fn parse_jwt_svid_from_grpc_response(
352+
svids: Vec<ProtoJwtSvid>,
353+
) -> Result<Vec<JwtSvid>, ClientError> {
354+
let result: Result<Vec<JwtSvid>, ClientError> = svids
355+
.iter()
356+
.map(|r| JwtSvid::from_str(&r.token).map_err(ClientError::InvalidJwtSvid))
357+
.collect();
358+
result
359+
}
360+
361+
fn parse_jwt_bundle_set_from_grpc_response(
362+
response: SubscribeToJwtBundlesResponse,
363+
) -> Result<JwtBundleSet, ClientError> {
364+
let mut bundle_set = JwtBundleSet::new();
365+
366+
for (td, bundle_data) in response.bundles.into_iter() {
367+
let trust_domain = TrustDomain::try_from(td)?;
368+
let bundle = JwtBundle::from_jwt_authorities(trust_domain, &bundle_data)
369+
.map_err(ClientError::from)?;
370+
371+
bundle_set.add_bundle(bundle);
372+
}
373+
374+
Ok(bundle_set)
375+
}
376+
269377
fn parse_x509_bundle_set_from_grpc_response(
270378
response: SubscribeToX509BundlesResponse,
271379
) -> Result<X509BundleSet, ClientError> {

spire-api/src/selectors.rs

-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ impl From<Unix> for String {
7474

7575
#[derive(Debug, Clone)]
7676
/// Represents SPIFFE identity selectors based on Unix process-related attributes.
77-
#[derive(Debug, Clone)]
7877
pub enum Unix {
7978
/// Specifies a selector for a Unix process ID (PID).
8079
Pid(u16),

0 commit comments

Comments
 (0)