Skip to content

Commit 2b35181

Browse files
[release-1.24] Better support for root certificate (#1546)
* Better support for root certificates * Split the last element of the returned response from the CA. This allows support for multiple roots. Note this requires a change to Istio (which I am making) to rever the regression in 1.25.1 (istio/istio#55793). * Split root from chain in the config_dump. Without this, it is impossible to know if something is a root or intermediate. * add test * lint * format --------- Co-authored-by: John Howard <john.howard@solo.io>
1 parent 7449ac4 commit 2b35181

File tree

11 files changed

+250
-54
lines changed

11 files changed

+250
-54
lines changed

build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fn main() -> Result<(), anyhow::Error> {
7979
for line in String::from_utf8(output.stdout).unwrap().lines() {
8080
// Each line looks like `istio.io/pkg/version.buildGitRevision=abc`
8181
if let Some((key, value)) = line.split_once('=') {
82-
let key = key.split('.').last().unwrap();
82+
let key = key.split('.').next_back().unwrap();
8383
println!("cargo:rustc-env=ZTUNNEL_BUILD_{key}={value}");
8484
} else {
8585
println!("cargo:warning=invalid build output {line}");

src/admin.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub struct CertsDump {
8686
identity: String,
8787
state: String,
8888
cert_chain: Vec<CertDump>,
89+
root_certs: Vec<CertDump>,
8990
}
9091

9192
impl Service {
@@ -220,10 +221,12 @@ async fn dump_certs(cert_manager: &SecretManager) -> Vec<CertsDump> {
220221
Unavailable(err) => dump.state = format!("Unavailable: {err}"),
221222
Available(certs) => {
222223
dump.state = "Available".to_string();
223-
dump.cert_chain = std::iter::once(&certs.cert)
224-
.chain(certs.chain.iter())
224+
dump.cert_chain = certs
225+
.cert_and_intermediates()
226+
.iter()
225227
.map(dump_cert)
226228
.collect();
229+
dump.root_certs = certs.roots.iter().map(dump_cert).collect();
227230
}
228231
};
229232
dump
@@ -541,11 +544,13 @@ mod tests {
541544
let want = serde_json::json!([
542545
{
543546
"certChain": [],
547+
"rootCerts": [],
544548
"identity": "spiffe://error/ns/forgotten/sa/sa-failed",
545549
"state": "Unavailable: the identity is no longer needed"
546550
},
547551
{
548552
"certChain": [],
553+
"rootCerts": [],
549554
"identity": "spiffe://test/ns/test/sa/sa-pending",
550555
"state": "Initializing"
551556
},
@@ -557,6 +562,8 @@ mod tests {
557562
"serialNumber": "588850990443535479077311695632745359443207891470",
558563
"validFrom": "2023-03-11T05:57:26Z"
559564
},
565+
],
566+
"rootCerts": [
560567
{
561568
"expirationTime": "2296-12-24T18:31:28Z",
562569
"pem": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lVQytjLzYwZStGMWVFKzdWcXhuYVdjT09abm1Fd0RRWUpLb1pJaHZjTgpBUUVMQlFBd0dERVdNQlFHQTFVRUNnd05ZMngxYzNSbGNpNXNiMk5oYkRBZ0Z3MHlNekF6TVRFeE9ETXgKTWpoYUdBOHlNamsyTVRJeU5ERTRNekV5T0Zvd0dERVdNQlFHQTFVRUNnd05ZMngxYzNSbGNpNXNiMk5oCmJEQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU1lQ1R4UEp0dWQwVXh3KwpDYWFkZFdEN2ErUUV1UVkrQlBUS0pkbk1lajBzQk1mVU1iVDE2SkxrWU5GZ3JqMVVWSEhjcFNvSUhvY3AKMnNkMzJTWTRiZGJva1Fjb3ArQmp0azU1alE0NktMWXNKZ2IyTnd2WW8xdDhFMWFldEpxRkdWN3JtZVpiCkZZZWFpKzZxN2lNamxiQ0dBdTcvVW5LSnNkR25hSlFnTjhkdTBUMUtEZ2pxS1B5SHFkc3U5a2JwQ3FpRQpYTVJtdzQvQkVoRkd6bUlEMm9VREtCMzZkdVZiZHpTRW01MVF2Z1U1SUxYSWd5VnJlak41Q0ZzQytXK3gKamVPWExFenRmSEZVb3FiM3dXaGtCdUV4bXI4MUoyaEdXOXBVTEoyd2tRZ2RmWFA3Z3RNa0I2RXlLdy94CkllYU5tTHpQSUdyWDAxelFZSWRaVHVEd01ZMENBd0VBQWFOVE1GRXdIUVlEVlIwT0JCWUVGRDhrNGYxYQpya3V3UitVUmhLQWUySVRaS1o3Vk1COEdBMVVkSXdRWU1CYUFGRDhrNGYxYXJrdXdSK1VSaEtBZTJJVFoKS1o3Vk1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLcm5BZVNzClNTSzMvOHp4K2h6ajZTRlhkSkE5Q1EwMkdFSjdoSHJLaWpHV1ZZZGRhbDlkQWJTNXRMZC8vcUtPOXVJcwpHZXR5L09rMmJSUTZjcXFNbGdkTnozam1tcmJTbFlXbUlYSTB5SEdtQ2lTYXpIc1hWYkVGNkl3eTN0Y1IKNHZvWFdLSUNXUGgrQzJjVGdMbWVaMEV1ekZ4cTR3Wm5DZjQwd0tvQUo5aTFhd1NyQm5FOWpXdG5wNEY0CmhXbkpUcEdreTVkUkFMRTBsLzJBYnJsMzh3Z2ZNOHI0SW90bVBUaEZLbkZlSUhVN2JRMXJZQW9xcGJBaApDdjBCTjVQakFRUldNazZib28zZjBha1MwN25sWUlWcVhoeHFjWW5PZ3drZGxUdFg5TXFHSXEyNm44bjEKTldXd25tS09qTnNrNnFSbXVsRWdlR080dnhUdlNKWWIraFU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
@@ -575,6 +582,8 @@ mod tests {
575582
"serialNumber": "528170730419860468572163268563070820131458817969",
576583
"validFrom": "2023-03-11T06:57:26Z"
577584
},
585+
],
586+
"rootCerts": [
578587
{
579588
"expirationTime": "2296-12-24T18:31:28Z",
580589
"pem": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lVQytjLzYwZStGMWVFKzdWcXhuYVdjT09abm1Fd0RRWUpLb1pJaHZjTgpBUUVMQlFBd0dERVdNQlFHQTFVRUNnd05ZMngxYzNSbGNpNXNiMk5oYkRBZ0Z3MHlNekF6TVRFeE9ETXgKTWpoYUdBOHlNamsyTVRJeU5ERTRNekV5T0Zvd0dERVdNQlFHQTFVRUNnd05ZMngxYzNSbGNpNXNiMk5oCmJEQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU1lQ1R4UEp0dWQwVXh3KwpDYWFkZFdEN2ErUUV1UVkrQlBUS0pkbk1lajBzQk1mVU1iVDE2SkxrWU5GZ3JqMVVWSEhjcFNvSUhvY3AKMnNkMzJTWTRiZGJva1Fjb3ArQmp0azU1alE0NktMWXNKZ2IyTnd2WW8xdDhFMWFldEpxRkdWN3JtZVpiCkZZZWFpKzZxN2lNamxiQ0dBdTcvVW5LSnNkR25hSlFnTjhkdTBUMUtEZ2pxS1B5SHFkc3U5a2JwQ3FpRQpYTVJtdzQvQkVoRkd6bUlEMm9VREtCMzZkdVZiZHpTRW01MVF2Z1U1SUxYSWd5VnJlak41Q0ZzQytXK3gKamVPWExFenRmSEZVb3FiM3dXaGtCdUV4bXI4MUoyaEdXOXBVTEoyd2tRZ2RmWFA3Z3RNa0I2RXlLdy94CkllYU5tTHpQSUdyWDAxelFZSWRaVHVEd01ZMENBd0VBQWFOVE1GRXdIUVlEVlIwT0JCWUVGRDhrNGYxYQpya3V3UitVUmhLQWUySVRaS1o3Vk1COEdBMVVkSXdRWU1CYUFGRDhrNGYxYXJrdXdSK1VSaEtBZTJJVFoKS1o3Vk1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLcm5BZVNzClNTSzMvOHp4K2h6ajZTRlhkSkE5Q1EwMkdFSjdoSHJLaWpHV1ZZZGRhbDlkQWJTNXRMZC8vcUtPOXVJcwpHZXR5L09rMmJSUTZjcXFNbGdkTnozam1tcmJTbFlXbUlYSTB5SEdtQ2lTYXpIc1hWYkVGNkl3eTN0Y1IKNHZvWFdLSUNXUGgrQzJjVGdMbWVaMEV1ekZ4cTR3Wm5DZjQwd0tvQUo5aTFhd1NyQm5FOWpXdG5wNEY0CmhXbkpUcEdreTVkUkFMRTBsLzJBYnJsMzh3Z2ZNOHI0SW90bVBUaEZLbkZlSUhVN2JRMXJZQW9xcGJBaApDdjBCTjVQakFRUldNazZib28zZjBha1MwN25sWUlWcVhoeHFjWW5PZ3drZGxUdFg5TXFHSXEyNm44bjEKTldXd25tS09qTnNrNnFSbXVsRWdlR080dnhUdlNKWWIraFU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",

src/identity/caclient.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl CaClient {
8888
.await
8989
.map_err(Box::new)?
9090
.into_inner();
91+
9192
let leaf = resp
9293
.cert_chain
9394
.first()
@@ -101,12 +102,8 @@ impl CaClient {
101102
};
102103
let certs = tls::WorkloadCertificate::new(&private_key, leaf, chain)?;
103104
// Make the certificate actually matches the identity we requested.
104-
if self.enable_impersonated_identity && certs.cert.identity().as_ref() != Some(id) {
105-
error!(
106-
"expected identity {:?}, got {:?}",
107-
id,
108-
certs.cert.identity()
109-
);
105+
if self.enable_impersonated_identity && certs.identity().as_ref() != Some(id) {
106+
error!("expected identity {:?}, got {:?}", id, certs.identity());
110107
return Err(Error::SanError(id.to_owned()));
111108
}
112109
Ok(certs)
@@ -246,7 +243,7 @@ pub mod mock {
246243

247244
#[cfg(test)]
248245
mod tests {
249-
use std::iter;
246+
250247
use std::time::Duration;
251248

252249
use matches::assert_matches;
@@ -286,10 +283,7 @@ mod tests {
286283
);
287284

288285
let res = test_ca_client_with_response(IstioCertificateResponse {
289-
cert_chain: iter::once(certs.cert)
290-
.chain(certs.chain)
291-
.map(|c| c.as_pem())
292-
.collect(),
286+
cert_chain: certs.full_chain_and_roots(),
293287
})
294288
.await;
295289
assert_matches!(res, Err(Error::SanError(_)));
@@ -304,10 +298,7 @@ mod tests {
304298
);
305299

306300
let res = test_ca_client_with_response(IstioCertificateResponse {
307-
cert_chain: iter::once(certs.cert)
308-
.chain(certs.chain)
309-
.map(|c| c.as_pem())
310-
.collect(),
301+
cert_chain: certs.full_chain_and_roots(),
311302
})
312303
.await;
313304
assert_matches!(res, Ok(_));

src/test_helpers/ca.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl CaServer {
5858
Duration::from_secs(0),
5959
Duration::from_secs(100),
6060
);
61-
let root_cert = RootCert::Static(certs.chain.iter().map(|c| c.as_pem()).join("\n").into());
61+
let root_cert = RootCert::Static(certs.roots.iter().map(|c| c.as_pem()).join("\n").into());
6262
let acceptor = tls::mock::MockServerCertProvider::new(certs);
6363
let mut tls_stream = crate::hyper_util::tls_server(acceptor, listener);
6464
let srv = IstioCertificateServiceServer::new(server);

src/test_helpers/xds.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl AdsServer {
7373
Duration::from_secs(0),
7474
Duration::from_secs(100),
7575
);
76-
let root_cert = RootCert::Static(certs.chain.iter().map(|c| c.as_pem()).join("\n").into());
76+
let root_cert = RootCert::Static(certs.roots.iter().map(|c| c.as_pem()).join("\n").into());
7777
let acceptor = tls::mock::MockServerCertProvider::new(certs);
7878
let listener_addr_string = "https://".to_string() + &server_addr.to_string();
7979
let mut tls_stream = crate::hyper_util::tls_server(acceptor, listener);

src/tls/ca-key2.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCLIZGLab2juncQ
3+
yF3RQPXcJmuktVjdTGtNICS2CKcaToYKgYAmp6VPgTXHHB/fwNMsDnQb50szTgEl
4+
LPzGT4YapgWIz9JOFyPsSoXBvraVRBxT20dFD2ARK3ilGaoDkItlu4vL9QTNbgXF
5+
ucYmZkiD2GtLtNcqFNC75tm4IJ09NywzD88IA/8RHSZLy+2yeT6OI1O/3igs66xT
6+
HQTdmqNnqxeckyxtwxUafayfk9W7xGhxHK8pFRUfvnOl/Qm56RMlQfP7FBjg4bHS
7+
wL+FfDKBLItvcwO4i8lQpya0ZsqMTtxGT11nRDH5NZMT1w6kCKTyOECJUq2nZZ9b
8+
VeeoRmdNAgMBAAECggEAE66rx5htpMYp9mSWCxaAwYRo6XvjJqlbK6W+s8bNFvZh
9+
VYak8bL5OqJZkIGcy7tcVGj2CYWCuK8SD+eJmedhng77DPPzeSsiYJjZS8OWUk74
10+
n+9PKYiniz5GWrri946g/cMWn4OZypMEO4jQrJl/LDG3WhYq8y/PKKnbhoYMoH5i
11+
ebv8YLGzzPZm0Vd3JM+wvHkd/CoAvrEWXuhvgxEXyCfpNfStrRbf3Frsk7yRrTx7
12+
KbSINMvZPemRhaBewr1mU6HWsbu2W5sm2hpe1KmABrUFvDq7ad4LcAuQc54zhdbC
13+
WkR86+QSDXhCE+ZlR3TyjfGCcsBYzWnRNVmP+liNEQKBgQC/o82IFHv3AGnWKRC3
14+
+rULXHCLqrAiVaqaW442/OjzjesFbouKzL8V8wKw+ag/4wECIm5r6ogtMIhCOVXc
15+
bQEcGbvhIF5irh/8j0CpaEctiguJTOyy9tShYxJVzOYS44NsDAIyCdQIWYOzeNWP
16+
l7aaRNs1MFf9eD4I5ATqbF5f3QKBgQC521at9CvQTDoS4MrWuV2XcVlAAjz05voh
17+
8p7ergCEY5JLKU3k231zVVKaGns2ert6SyCNXD7xGC/Eo/9zEtG/xzoomNRfYixs
18+
czcNx/yRX/GUOWqG1SDFck5wfbrZ4jTgmhe8B2RG7t8J848dUZRb7eJ0s6gXdCW9
19+
xHprUdRmMQKBgD5XA7obp8PO357qFuUyagh7FqVobgmNQoUZ+WZL2V+5L9XBgyUw
20+
u4xhU+PMIv49UwultbPnREsm+XxJeHPPBchlWqe+RtXk/MTEuO0i3dyjhmMwoeMJ
21+
xluFheZhVAqa9hqEwYYTimT48Y3FZftjB+ShN4nS4xyyK8PqoOq9O+oFAoGAIbjF
22+
YmyiInoiM1isFQevDpJXYkDFtJ3QFqbB4p9popu6aH7HDlYwzeNWSHWzk2/zYj4N
23+
Wvi4xt/fkus6pzNr8UMBr2oDZocWjlrdS1fU4L+qwn0kcfBrsMeLqed2JqBffb0X
24+
v1sL+77Noy2Y8vXhWEiyRQBv6El/q43htGU1h5ECgYBXnJBFtYZ5J1CnFYOVGXD1
25+
Rqp0dYVEJdnwZZIVPyEPiMzpYZjUbuodwcMQyHlJzyPn2Pn60Lx+Ie/mNgkltVtl
26+
si2Di6ZLn9ok120YXRl4hufWGsA8b+cwPo72aIoAFP+K8LMRjHKGMS+XnHkX1N9/
27+
42G8+1ugr/men4HybDQV+w==
28+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)