Skip to content

Commit 28084c6

Browse files
authored
identity: add a metric tracking when the proxy's cert expires (#787)
This branch adds a new `identity_cert_expiration_timestamp_seconds` to the proxy's Prometheus metric. When identity is enabled, this metric will report the time at which the proxy's current certificate expires, in seconds since the Unix epoch. Closes linkerd/linkerd2#5379
1 parent f1be3a6 commit 28084c6

File tree

8 files changed

+75
-1
lines changed

8 files changed

+75
-1
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,7 @@ dependencies = [
14171417
"http-body",
14181418
"linkerd2-error",
14191419
"linkerd2-identity",
1420+
"linkerd2-metrics",
14201421
"linkerd2-proxy-api",
14211422
"linkerd2-proxy-transport",
14221423
"pin-project 0.4.22",

linkerd/app/src/identity.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub use linkerd2_app_core::proxy::identity::{
2-
certify, Crt, CrtKey, Csr, InvalidName, Key, Local, Name, TokenSource, TrustAnchors,
2+
certify, metrics, Crt, CrtKey, Csr, InvalidName, Key, Local, Name, TokenSource, TrustAnchors,
33
};
44
use linkerd2_app_core::{
55
control, dns,
@@ -80,6 +80,13 @@ impl Identity {
8080
}
8181
}
8282

83+
pub fn metrics(&self) -> metrics::Report {
84+
match self {
85+
Identity::Disabled => metrics::Report::disabled(),
86+
Identity::Enabled { ref local, .. } => local.metrics(),
87+
}
88+
}
89+
8390
pub fn task(self) -> Task {
8491
match self {
8592
Identity::Disabled => Box::pin(async {}),

linkerd/app/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ impl Config {
7575
/// It is currently required that this be run on a Tokio runtime, since some
7676
/// services are created eagerly and must spawn tasks to do so.
7777
pub async fn build(self, log_level: trace::Handle) -> Result<App, Error> {
78+
use metrics::FmtMetrics;
79+
7880
let Config {
7981
admin,
8082
dns,
@@ -94,6 +96,7 @@ impl Config {
9496

9597
let identity = info_span!("identity")
9698
.in_scope(|| identity.build(dns.resolver.clone(), metrics.control.clone()))?;
99+
let report = report.and_then(identity.metrics());
97100

98101
let (drain_tx, drain_rx) = drain::channel();
99102

linkerd/identity/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ impl CrtKey {
331331
pub fn tls_server_config(&self) -> Arc<rustls::ServerConfig> {
332332
self.server_config.clone()
333333
}
334+
335+
pub fn expiry(&self) -> SystemTime {
336+
self.expiry
337+
}
334338
}
335339

336340
impl fmt::Debug for CrtKey {

linkerd/proxy/identity/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ publish = false
99
futures = "0.3"
1010
linkerd2-error = { path = "../../error" }
1111
linkerd2-identity = { path = "../../identity" }
12+
linkerd2-metrics = { path = "../../metrics" }
1213
linkerd2-proxy-api = { git = "https://github.com/linkerd/linkerd2-proxy-api", tag = "v0.1.16" }
1314
linkerd2-proxy-transport = { path = "../transport" }
1415
tokio = { version = "0.3", features = ["time", "sync"] }

linkerd/proxy/identity/src/certify.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ impl Local {
164164
}
165165
Ok(self)
166166
}
167+
168+
pub fn metrics(&self) -> crate::metrics::Report {
169+
crate::metrics::Report::new(self.crt_key.clone())
170+
}
167171
}
168172

169173
impl tls::client::HasConfig for Local {

linkerd/proxy/identity/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![deny(warnings, rust_2018_idioms)]
22

33
pub mod certify;
4+
pub mod metrics;
45

56
pub use self::certify::{AwaitCrt, CrtKeySender, Local};
67
pub use linkerd2_identity::{Crt, CrtKey, Csr, InvalidName, Key, Name, TokenSource, TrustAnchors};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use crate::CrtKey;
2+
use linkerd2_metrics::{metrics, FmtMetrics, Gauge};
3+
use std::{fmt, time::UNIX_EPOCH};
4+
use tokio::sync::watch;
5+
6+
#[derive(Debug, Clone)]
7+
pub struct Report {
8+
crt_key_watch: Option<watch::Receiver<Option<CrtKey>>>,
9+
}
10+
11+
metrics! {
12+
identity_cert_expiration_timestamp_seconds: Gauge {
13+
"Time when the this proxy's current mTLS identity certificate will expire (in seconds since the UNIX epoch)"
14+
}
15+
}
16+
17+
impl Report {
18+
pub(crate) fn new(watch: watch::Receiver<Option<CrtKey>>) -> Self {
19+
Self {
20+
crt_key_watch: Some(watch),
21+
}
22+
}
23+
24+
pub fn disabled() -> Self {
25+
Self {
26+
crt_key_watch: None,
27+
}
28+
}
29+
}
30+
31+
impl FmtMetrics for Report {
32+
fn fmt_metrics(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33+
let dur = if let Some(watch) = self.crt_key_watch.as_ref() {
34+
if let Some(ref crt_key) = *(watch.borrow()) {
35+
crt_key
36+
.expiry()
37+
.duration_since(UNIX_EPOCH)
38+
.map_err(|error| {
39+
tracing::warn!(%error, "an identity would expire before the beginning of the UNIX epoch, something is probably wrong");
40+
fmt::Error
41+
})?
42+
} else {
43+
return Ok(());
44+
}
45+
} else {
46+
return Ok(());
47+
};
48+
49+
identity_cert_expiration_timestamp_seconds.fmt_help(f)?;
50+
identity_cert_expiration_timestamp_seconds.fmt_metric(f, &Gauge::from(dur.as_secs()))?;
51+
Ok(())
52+
}
53+
}

0 commit comments

Comments
 (0)