Skip to content

Commit 2869076

Browse files
authored
identity(spire): provide named pipe support for spire (#3970)
This change does two things: - adds support for `NamedPipes` to our SPIRE client. This will allow the client to connect to spire agents running on Windows hosts - renames the `LINKERD2_PROXY_IDENTITY_SPIRE_SOCKET` to `LINKERD2_PROXY_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS` and deprecates the former. Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
1 parent 99316f7 commit 2869076

File tree

3 files changed

+43
-48
lines changed

3 files changed

+43
-48
lines changed

linkerd/app/src/env.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,12 @@ pub const ENV_IDENTITY_IDENTITY_SERVER_ID: &str = "LINKERD2_PROXY_IDENTITY_SERVE
233233
pub const ENV_IDENTITY_IDENTITY_SERVER_NAME: &str = "LINKERD2_PROXY_IDENTITY_SERVER_NAME";
234234

235235
// If this config is set, then the proxy will be configured to use Spire as identity
236-
// provider
236+
// provider. On Unix systems this needs to be a path to a UDS while on Windows - a
237+
// named pipe path.
238+
pub const ENV_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS: &str =
239+
"LINKERD2_PROXY_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS";
237240
pub const ENV_IDENTITY_SPIRE_SOCKET: &str = "LINKERD2_PROXY_IDENTITY_SPIRE_SOCKET";
241+
238242
pub const IDENTITY_SPIRE_BASE: &str = "LINKERD2_PROXY_IDENTITY_SPIRE";
239243
const DEFAULT_SPIRE_BACKOFF: ExponentialBackoff =
240244
ExponentialBackoff::new_unchecked(Duration::from_millis(100), Duration::from_secs(1), 0.1);
@@ -909,8 +913,13 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
909913
let identity = {
910914
let tls = tls?;
911915

912-
match strings.get(ENV_IDENTITY_SPIRE_SOCKET)? {
913-
Some(socket) => match &tls.id {
916+
match parse_deprecated(
917+
strings,
918+
ENV_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS,
919+
ENV_IDENTITY_SPIRE_SOCKET,
920+
|s| Ok(s.to_string()),
921+
)? {
922+
Some(workload_api_addr) => match &tls.id {
914923
// TODO: perform stricter SPIFFE ID validation following:
915924
// https://github.com/spiffe/spiffe/blob/27b59b81ba8c56885ac5d4be73b35b9b3305fd7a/standards/SPIFFE-ID.md
916925
identity::Id::Uri(uri)
@@ -919,7 +928,7 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
919928
identity::Config::Spire {
920929
tls,
921930
client: spire::Config {
922-
socket_addr: std::sync::Arc::new(socket),
931+
workload_api_addr: std::sync::Arc::new(workload_api_addr),
923932
backoff: parse_backoff(
924933
strings,
925934
IDENTITY_SPIRE_BASE,

linkerd/app/src/identity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl Config {
109109
}
110110
}
111111
Self::Spire { client, tls } => {
112-
let addr = client.socket_addr.clone();
112+
let addr = client.workload_api_addr.clone();
113113
let spire = spire::client::Spire::new(tls.id.clone());
114114

115115
let (store, receiver, ready) = watch(tls, metrics.cert)?;

linkerd/app/src/spire.rs

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,26 @@ use tokio::sync::watch;
44

55
pub use linkerd_app_core::identity::client::spire as client;
66

7-
#[cfg(target_os = "linux")]
8-
const UNIX_PREFIX: &str = "unix:";
9-
#[cfg(target_os = "linux")]
107
const TONIC_DEFAULT_URI: &str = "http://[::]:50051";
118

129
#[derive(Clone, Debug)]
1310
pub struct Config {
14-
pub socket_addr: Arc<String>,
11+
pub workload_api_addr: Arc<String>,
1512
pub backoff: ExponentialBackoff,
1613
}
1714

1815
// Connects to SPIRE workload API via Unix Domain Socket
1916
pub struct Client {
20-
#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
2117
config: Config,
2218
}
2319

2420
// === impl Client ===
25-
26-
#[cfg(target_os = "linux")]
2721
impl From<Config> for Client {
2822
fn from(config: Config) -> Self {
2923
Self { config }
3024
}
3125
}
3226

33-
#[cfg(not(target_os = "linux"))]
34-
impl From<Config> for Client {
35-
fn from(_: Config) -> Self {
36-
panic!("Spire is supported on Linux only")
37-
}
38-
}
39-
40-
#[cfg(target_os = "linux")]
4127
impl tower::Service<()> for Client {
4228
type Response = tonic::Response<watch::Receiver<client::SvidUpdate>>;
4329
type Error = Error;
@@ -51,25 +37,43 @@ impl tower::Service<()> for Client {
5137
}
5238

5339
fn call(&mut self, _req: ()) -> Self::Future {
54-
let socket = self.config.socket_addr.clone();
40+
let addr = self.config.workload_api_addr.clone();
5541
let backoff = self.config.backoff;
5642
Box::pin(async move {
57-
use tokio::net::UnixStream;
5843
use tonic::transport::{Endpoint, Uri};
5944

60-
// Strip the 'unix:' prefix for tonic compatibility.
61-
let stripped_path = socket
62-
.strip_prefix(UNIX_PREFIX)
63-
.unwrap_or(socket.as_str())
64-
.to_string();
65-
6645
// We will ignore this uri because uds do not use it
6746
// if your connector does use the uri it will be provided
6847
// as the request to the `MakeConnection`.
6948
let chan = Endpoint::try_from(TONIC_DEFAULT_URI)?
7049
.connect_with_connector(tower::util::service_fn(move |_: Uri| {
71-
use futures::TryFutureExt;
72-
UnixStream::connect(stripped_path.clone()).map_ok(hyper_util::rt::TokioIo::new)
50+
#[cfg(unix)]
51+
{
52+
use futures::TryFutureExt;
53+
54+
// The 'unix:' scheme must be stripped from socket paths.
55+
let path = addr.strip_prefix("unix:").unwrap_or(addr.as_str());
56+
57+
tokio::net::UnixStream::connect(path.to_string())
58+
.map_ok(hyper_util::rt::TokioIo::new)
59+
}
60+
61+
#[cfg(windows)]
62+
{
63+
use tokio::net::windows::named_pipe;
64+
let named_pipe_path = addr.clone();
65+
let client = named_pipe::ClientOptions::new()
66+
.open(named_pipe_path.as_str())
67+
.map(hyper_util::rt::TokioIo::new);
68+
69+
futures::future::ready(client)
70+
}
71+
72+
#[cfg(not(any(unix, windows)))]
73+
{
74+
compile_error!("Spire is supported only on Windows and Unix systems.");
75+
futures::future::pending()
76+
}
7377
}))
7478
.await?;
7579

@@ -80,21 +84,3 @@ impl tower::Service<()> for Client {
8084
})
8185
}
8286
}
83-
84-
#[cfg(not(target_os = "linux"))]
85-
impl tower::Service<()> for Client {
86-
type Response = tonic::Response<watch::Receiver<client::SvidUpdate>>;
87-
type Error = Error;
88-
type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
89-
90-
fn poll_ready(
91-
&mut self,
92-
_cx: &mut std::task::Context<'_>,
93-
) -> std::task::Poll<Result<(), Self::Error>> {
94-
unimplemented!("Spire is supported on Linux only")
95-
}
96-
97-
fn call(&mut self, _req: ()) -> Self::Future {
98-
unimplemented!("Spire is supported on Linux only")
99-
}
100-
}

0 commit comments

Comments
 (0)