Skip to content

Commit 0ed23ac

Browse files
authored
refactor(app/env): move tls config into submodule (#4439)
* refactor: invoke `watch()` by name directly Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(identity): inline `TlsParams` into `Config` this commit performs an incremental step, and inlines the tls parameters into the identity client's configuration. a temporary type alias is left in place for now, to avoid introducing noise here. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(app/env): move identity logic into submodule we now move the two functions responsible for parsing identity configuration (parse_tls_params and parse_linkerd_identity_config), into an identity submodule. we also move the block expression, which also performs some further steps, into a function named parse_identity_config. there is one wrinkle that is highlighted by this change, which is that we slightly delay the propagation of an error in the event of parameters being invalid. we'll change that later, but for now faithfully move code without making *any* behavioral alterations. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(app/env): move `parse_tls_params()` call Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(app/env): remove frivolous `pub` directives in the wake of our changes, we now have a single top-level function that's responsible for parsing our identity configuration. the other functions that parse one type of identity configuration, and parts of it, needn't be public. Signed-off-by: katelyn martin <kate@buoyant.io> * nit(app/env): address clippy lints Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(app): remove temporary type alias this commit addresses a lingering todo comment that was pointed out during review. this is straightforward to inline inside of a function's return signature. Signed-off-by: katelyn martin <kate@buoyant.io> --------- Signed-off-by: katelyn martin <kate@buoyant.io>
1 parent b136653 commit 0ed23ac

File tree

3 files changed

+213
-199
lines changed

3 files changed

+213
-199
lines changed

linkerd/app/src/env.rs

Lines changed: 3 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{dns, gateway, identity, inbound, outbound, policy, spire, trace_collector};
1+
use crate::{dns, gateway, inbound, outbound, policy, spire, trace_collector};
22
use linkerd_app_core::{
33
addr,
44
config::*,
@@ -14,6 +14,7 @@ use tracing::{debug, error, info, warn};
1414

1515
mod control;
1616
mod http2;
17+
mod identity;
1718
mod trace;
1819
mod types;
1920

@@ -433,8 +434,6 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
433434
let dns_min_ttl = parse(strings, ENV_DNS_MIN_TTL, parse_duration);
434435
let dns_max_ttl = parse(strings, ENV_DNS_MAX_TTL, parse_duration);
435436

436-
let tls = parse_tls_params(strings);
437-
438437
let hostname = strings.get(ENV_HOSTNAME);
439438

440439
let trace_collector_addr = parse_control_addr(strings, ENV_TRACE_COLLECTOR_SVC_BASE);
@@ -875,75 +874,7 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
875874
})
876875
.unwrap_or(super::tap::Config::Disabled);
877876

878-
let identity = {
879-
let tls = tls?;
880-
881-
match parse_deprecated(
882-
strings,
883-
ENV_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS,
884-
ENV_IDENTITY_SPIRE_SOCKET,
885-
|s| Ok(s.to_string()),
886-
)? {
887-
Some(workload_api_addr) => match &tls.id {
888-
// TODO: perform stricter SPIFFE ID validation following:
889-
// https://github.com/spiffe/spiffe/blob/27b59b81ba8c56885ac5d4be73b35b9b3305fd7a/standards/SPIFFE-ID.md
890-
identity::Id::Uri(uri)
891-
if uri.scheme().eq_ignore_ascii_case(SPIFFE_ID_URI_SCHEME) =>
892-
{
893-
identity::Config::Spire {
894-
tls,
895-
client: spire::Config {
896-
workload_api_addr: std::sync::Arc::new(workload_api_addr),
897-
backoff: parse_backoff(
898-
strings,
899-
IDENTITY_SPIRE_BASE,
900-
DEFAULT_SPIRE_BACKOFF,
901-
)?,
902-
},
903-
}
904-
}
905-
_ => {
906-
error!("Spire support requires a SPIFFE TLS Id");
907-
return Err(EnvError::InvalidEnvVar);
908-
}
909-
},
910-
None => {
911-
match (&tls.id, &tls.server_name) {
912-
(linkerd_app_core::identity::Id::Dns(id), sni) if id == sni => {}
913-
(_id, _sni) => {
914-
return Err(EnvError::TlsIdAndServerNameNotMatching);
915-
}
916-
};
917-
918-
let (addr, certify) = parse_linkerd_identity_config(strings)?;
919-
920-
// If the address doesn't have a server identity, then we're on localhost.
921-
let connect = if addr.addr.is_loopback() {
922-
inbound.proxy.connect.clone()
923-
} else {
924-
outbound.proxy.connect.clone()
925-
};
926-
let failfast_timeout = if addr.addr.is_loopback() {
927-
inbound.http_request_queue.failfast_timeout
928-
} else {
929-
outbound.http_request_queue.failfast_timeout
930-
};
931-
932-
identity::Config::Linkerd {
933-
certify,
934-
tls,
935-
client: ControlConfig {
936-
addr,
937-
connect,
938-
buffer: QueueConfig {
939-
capacity: DEFAULT_CONTROL_QUEUE_CAPACITY,
940-
failfast_timeout,
941-
},
942-
},
943-
}
944-
}
945-
}
946-
};
877+
let identity = self::identity::parse_identity_config(strings, &inbound, &outbound)?;
947878

948879
Ok(super::Config {
949880
admin,
@@ -1137,113 +1068,6 @@ pub fn parse_control_addr<S: Strings>(
11371068
}
11381069
}
11391070

1140-
pub fn parse_tls_params<S: Strings>(strings: &S) -> Result<identity::TlsParams, EnvError> {
1141-
let ta = parse(strings, ENV_IDENTITY_TRUST_ANCHORS, |s| {
1142-
if s.is_empty() {
1143-
return Err(ParseError::InvalidTrustAnchors);
1144-
}
1145-
Ok(s.to_string())
1146-
});
1147-
1148-
// The assumtion here is that if `ENV_IDENTITY_IDENTITY_LOCAL_NAME` has been set
1149-
// we will use that for both tls id and server name.
1150-
let (server_id_env_var, server_name_env_var) =
1151-
if strings.get(ENV_IDENTITY_IDENTITY_LOCAL_NAME)?.is_some() {
1152-
(
1153-
ENV_IDENTITY_IDENTITY_LOCAL_NAME,
1154-
ENV_IDENTITY_IDENTITY_LOCAL_NAME,
1155-
)
1156-
} else {
1157-
(
1158-
ENV_IDENTITY_IDENTITY_SERVER_ID,
1159-
ENV_IDENTITY_IDENTITY_SERVER_NAME,
1160-
)
1161-
};
1162-
1163-
let server_id = parse(strings, server_id_env_var, parse_identity);
1164-
let server_name = parse(strings, server_name_env_var, parse_dns_name);
1165-
1166-
if strings
1167-
.get(ENV_IDENTITY_DISABLED)?
1168-
.map(|d| !d.is_empty())
1169-
.unwrap_or(false)
1170-
{
1171-
error!("{ENV_IDENTITY_DISABLED} is no longer supported. Identity is must be enabled.");
1172-
return Err(EnvError::InvalidEnvVar);
1173-
}
1174-
1175-
match (ta?, server_id?, server_name?) {
1176-
(Some(trust_anchors_pem), Some(server_id), Some(server_name)) => {
1177-
let params = identity::TlsParams {
1178-
id: server_id,
1179-
server_name,
1180-
trust_anchors_pem,
1181-
};
1182-
Ok(params)
1183-
}
1184-
(trust_anchors_pem, server_id, server_name) => {
1185-
for (unset, name) in &[
1186-
(trust_anchors_pem.is_none(), ENV_IDENTITY_TRUST_ANCHORS),
1187-
(server_id.is_none(), server_id_env_var),
1188-
(server_name.is_none(), server_name_env_var),
1189-
] {
1190-
if *unset {
1191-
error!("{} must be set.", name);
1192-
}
1193-
}
1194-
Err(EnvError::InvalidEnvVar)
1195-
}
1196-
}
1197-
}
1198-
1199-
pub fn parse_linkerd_identity_config<S: Strings>(
1200-
strings: &S,
1201-
) -> Result<(ControlAddr, identity::client::linkerd::Config), EnvError> {
1202-
let control = parse_control_addr(strings, ENV_IDENTITY_SVC_BASE);
1203-
let dir = parse(strings, ENV_IDENTITY_DIR, |ref s| Ok(PathBuf::from(s)));
1204-
let tok = parse(strings, ENV_IDENTITY_TOKEN_FILE, |ref s| {
1205-
identity::client::linkerd::TokenSource::if_nonempty_file(s.to_string()).map_err(|e| {
1206-
error!("Could not read {ENV_IDENTITY_TOKEN_FILE}: {e}");
1207-
ParseError::InvalidTokenSource
1208-
})
1209-
});
1210-
1211-
let min_refresh = parse(strings, ENV_IDENTITY_MIN_REFRESH, parse_duration);
1212-
let max_refresh = parse(strings, ENV_IDENTITY_MAX_REFRESH, parse_duration);
1213-
1214-
match (control?, dir?, tok?, min_refresh?, max_refresh?) {
1215-
(Some(control), Some(dir), Some(token), min_refresh, max_refresh) => {
1216-
let certify = identity::client::linkerd::Config {
1217-
token,
1218-
min_refresh: min_refresh.unwrap_or(DEFAULT_IDENTITY_MIN_REFRESH),
1219-
max_refresh: max_refresh.unwrap_or(DEFAULT_IDENTITY_MAX_REFRESH),
1220-
documents: identity::client::linkerd::certify::Documents::load(dir).map_err(
1221-
|error| {
1222-
error!(%error, "Failed to read identity documents");
1223-
EnvError::InvalidEnvVar
1224-
},
1225-
)?,
1226-
};
1227-
1228-
Ok((control, certify))
1229-
}
1230-
(addr, end_entity_dir, token, _minr, _maxr) => {
1231-
let s = format!("{ENV_IDENTITY_SVC_BASE}_ADDR and {ENV_IDENTITY_SVC_BASE}_NAME");
1232-
let svc_env: &str = s.as_str();
1233-
for (unset, name) in &[
1234-
(addr.is_none(), svc_env),
1235-
(end_entity_dir.is_none(), ENV_IDENTITY_DIR),
1236-
(token.is_none(), ENV_IDENTITY_TOKEN_FILE),
1237-
] {
1238-
if *unset {
1239-
error!("{name} must be set.");
1240-
}
1241-
}
1242-
Err(EnvError::InvalidEnvVar)
1243-
}
1244-
}
1245-
}
1246-
12471071
#[cfg(test)]
12481072
impl Strings for std::collections::HashMap<&'static str, &'static str> {
12491073
fn get(&self, key: &str) -> Result<Option<String>, EnvError> {

linkerd/app/src/env/identity.rs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
use super::*;
2+
use crate::identity::Id;
3+
4+
pub fn parse_identity_config<S: Strings>(
5+
strings: &S,
6+
inbound: &inbound::Config,
7+
outbound: &outbound::Config,
8+
) -> Result<crate::identity::Config, EnvError> {
9+
let (id, server_name, trust_anchors_pem) = parse_tls_params(strings)?;
10+
11+
match parse_deprecated(
12+
strings,
13+
ENV_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS,
14+
ENV_IDENTITY_SPIRE_SOCKET,
15+
|s| Ok(s.to_string()),
16+
)? {
17+
Some(workload_api_addr) => match &id {
18+
// TODO: perform stricter SPIFFE ID validation following:
19+
// https://github.com/spiffe/spiffe/blob/27b59b81ba8c56885ac5d4be73b35b9b3305fd7a/standards/SPIFFE-ID.md
20+
crate::identity::Id::Uri(uri)
21+
if uri.scheme().eq_ignore_ascii_case(SPIFFE_ID_URI_SCHEME) =>
22+
{
23+
Ok(crate::identity::Config::Spire {
24+
id,
25+
server_name,
26+
trust_anchors_pem,
27+
client: spire::Config {
28+
workload_api_addr: std::sync::Arc::new(workload_api_addr),
29+
backoff: parse_backoff(
30+
strings,
31+
IDENTITY_SPIRE_BASE,
32+
DEFAULT_SPIRE_BACKOFF,
33+
)?,
34+
},
35+
})
36+
}
37+
_ => {
38+
error!("Spire support requires a SPIFFE TLS Id");
39+
Err(EnvError::InvalidEnvVar)
40+
}
41+
},
42+
None => {
43+
match (&id, &server_name) {
44+
(linkerd_app_core::identity::Id::Dns(id), sni) if id == sni => {}
45+
(_id, _sni) => {
46+
return Err(EnvError::TlsIdAndServerNameNotMatching);
47+
}
48+
};
49+
50+
let (addr, certify) = self::identity::parse_linkerd_identity_config(strings)?;
51+
52+
// If the address doesn't have a server identity, then we're on localhost.
53+
let connect = if addr.addr.is_loopback() {
54+
inbound.proxy.connect.clone()
55+
} else {
56+
outbound.proxy.connect.clone()
57+
};
58+
let failfast_timeout = if addr.addr.is_loopback() {
59+
inbound.http_request_queue.failfast_timeout
60+
} else {
61+
outbound.http_request_queue.failfast_timeout
62+
};
63+
64+
Ok(crate::identity::Config::Linkerd {
65+
certify,
66+
id,
67+
server_name,
68+
trust_anchors_pem,
69+
client: ControlConfig {
70+
addr,
71+
connect,
72+
buffer: QueueConfig {
73+
capacity: DEFAULT_CONTROL_QUEUE_CAPACITY,
74+
failfast_timeout,
75+
},
76+
},
77+
})
78+
}
79+
}
80+
}
81+
82+
fn parse_linkerd_identity_config<S: Strings>(
83+
strings: &S,
84+
) -> Result<(ControlAddr, crate::identity::client::linkerd::Config), EnvError> {
85+
let control = parse_control_addr(strings, ENV_IDENTITY_SVC_BASE);
86+
let dir = parse(strings, ENV_IDENTITY_DIR, |ref s| Ok(PathBuf::from(s)));
87+
let tok = parse(strings, ENV_IDENTITY_TOKEN_FILE, |ref s| {
88+
crate::identity::client::linkerd::TokenSource::if_nonempty_file(s.to_string()).map_err(
89+
|e| {
90+
error!("Could not read {ENV_IDENTITY_TOKEN_FILE}: {e}");
91+
ParseError::InvalidTokenSource
92+
},
93+
)
94+
});
95+
96+
let min_refresh = parse(strings, ENV_IDENTITY_MIN_REFRESH, parse_duration);
97+
let max_refresh = parse(strings, ENV_IDENTITY_MAX_REFRESH, parse_duration);
98+
99+
match (control?, dir?, tok?, min_refresh?, max_refresh?) {
100+
(Some(control), Some(dir), Some(token), min_refresh, max_refresh) => {
101+
let certify = crate::identity::client::linkerd::Config {
102+
token,
103+
min_refresh: min_refresh.unwrap_or(DEFAULT_IDENTITY_MIN_REFRESH),
104+
max_refresh: max_refresh.unwrap_or(DEFAULT_IDENTITY_MAX_REFRESH),
105+
documents: crate::identity::client::linkerd::certify::Documents::load(dir)
106+
.map_err(|error| {
107+
error!(%error, "Failed to read identity documents");
108+
EnvError::InvalidEnvVar
109+
})?,
110+
};
111+
112+
Ok((control, certify))
113+
}
114+
(addr, end_entity_dir, token, _minr, _maxr) => {
115+
let s = format!("{ENV_IDENTITY_SVC_BASE}_ADDR and {ENV_IDENTITY_SVC_BASE}_NAME");
116+
let svc_env: &str = s.as_str();
117+
for (unset, name) in &[
118+
(addr.is_none(), svc_env),
119+
(end_entity_dir.is_none(), ENV_IDENTITY_DIR),
120+
(token.is_none(), ENV_IDENTITY_TOKEN_FILE),
121+
] {
122+
if *unset {
123+
error!("{name} must be set.");
124+
}
125+
}
126+
Err(EnvError::InvalidEnvVar)
127+
}
128+
}
129+
}
130+
131+
fn parse_tls_params<S: Strings>(strings: &S) -> Result<(Id, dns::Name, String), EnvError> {
132+
let ta = parse(strings, ENV_IDENTITY_TRUST_ANCHORS, |s| {
133+
if s.is_empty() {
134+
return Err(ParseError::InvalidTrustAnchors);
135+
}
136+
Ok(s.to_string())
137+
});
138+
139+
// The assumtion here is that if `ENV_IDENTITY_IDENTITY_LOCAL_NAME` has been set
140+
// we will use that for both tls id and server name.
141+
let (server_id_env_var, server_name_env_var) =
142+
if strings.get(ENV_IDENTITY_IDENTITY_LOCAL_NAME)?.is_some() {
143+
(
144+
ENV_IDENTITY_IDENTITY_LOCAL_NAME,
145+
ENV_IDENTITY_IDENTITY_LOCAL_NAME,
146+
)
147+
} else {
148+
(
149+
ENV_IDENTITY_IDENTITY_SERVER_ID,
150+
ENV_IDENTITY_IDENTITY_SERVER_NAME,
151+
)
152+
};
153+
154+
let server_id = parse(strings, server_id_env_var, parse_identity);
155+
let server_name = parse(strings, server_name_env_var, parse_dns_name);
156+
157+
if strings
158+
.get(ENV_IDENTITY_DISABLED)?
159+
.map(|d| !d.is_empty())
160+
.unwrap_or(false)
161+
{
162+
error!("{ENV_IDENTITY_DISABLED} is no longer supported. Identity is must be enabled.");
163+
return Err(EnvError::InvalidEnvVar);
164+
}
165+
166+
match (ta?, server_id?, server_name?) {
167+
(Some(trust_anchors_pem), Some(server_id), Some(server_name)) => {
168+
Ok((server_id, server_name, trust_anchors_pem))
169+
}
170+
(trust_anchors_pem, server_id, server_name) => {
171+
for (unset, name) in &[
172+
(trust_anchors_pem.is_none(), ENV_IDENTITY_TRUST_ANCHORS),
173+
(server_id.is_none(), server_id_env_var),
174+
(server_name.is_none(), server_name_env_var),
175+
] {
176+
if *unset {
177+
error!("{} must be set.", name);
178+
}
179+
}
180+
Err(EnvError::InvalidEnvVar)
181+
}
182+
}
183+
}

0 commit comments

Comments
 (0)