Skip to content

Commit 2e872e2

Browse files
security: cache certificate expiration metrics as pointers
Changes in #130110 were added to add labelled ttl metrics to client certificates. It achieved this by changing the system which cached certificate expiries to cache on a composite struct of two metrics, rather than just an expiration metric. The struct itself housed the metrics as inline values, rather than pointers, so updates were registered in the cached values only, and not the registry in which they were reporting. This means that updates to client certificate expirations would not be reflected by the ttl or expiration metrics. This ticket modifies those elements so that they are not copied when they are pulled from the cache. Fixes: #142681 Epic: CRDB-40209 Release note (bug fix): Fixes bug in client certificate expiration metrics.
1 parent 0b153e7 commit 2e872e2

File tree

3 files changed

+54
-18
lines changed

3 files changed

+54
-18
lines changed

pkg/security/BUILD.bazel

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,82 +107,68 @@ go_test(
107107
"//pkg/util/uuid",
108108
"@com_github_cockroachdb_errors//:errors",
109109
"@com_github_go_ldap_ldap_v3//:ldap",
110+
"@com_github_prometheus_client_model//go",
110111
"@com_github_stretchr_testify//require",
111112
"@org_golang_x_exp//rand",
112113
] + select({
113114
"@io_bazel_rules_go//go/platform:aix": [
114115
"//pkg/util/log/eventpb",
115-
"@com_github_prometheus_client_model//go",
116116
"@org_golang_x_sys//unix",
117117
],
118118
"@io_bazel_rules_go//go/platform:android": [
119119
"//pkg/util/log/eventpb",
120-
"@com_github_prometheus_client_model//go",
121120
"@org_golang_x_sys//unix",
122121
],
123122
"@io_bazel_rules_go//go/platform:darwin": [
124123
"//pkg/util/log/eventpb",
125-
"@com_github_prometheus_client_model//go",
126124
"@org_golang_x_sys//unix",
127125
],
128126
"@io_bazel_rules_go//go/platform:dragonfly": [
129127
"//pkg/util/log/eventpb",
130-
"@com_github_prometheus_client_model//go",
131128
"@org_golang_x_sys//unix",
132129
],
133130
"@io_bazel_rules_go//go/platform:freebsd": [
134131
"//pkg/util/log/eventpb",
135-
"@com_github_prometheus_client_model//go",
136132
"@org_golang_x_sys//unix",
137133
],
138134
"@io_bazel_rules_go//go/platform:illumos": [
139135
"//pkg/util/log/eventpb",
140-
"@com_github_prometheus_client_model//go",
141136
"@org_golang_x_sys//unix",
142137
],
143138
"@io_bazel_rules_go//go/platform:ios": [
144139
"//pkg/util/log/eventpb",
145-
"@com_github_prometheus_client_model//go",
146140
"@org_golang_x_sys//unix",
147141
],
148142
"@io_bazel_rules_go//go/platform:js": [
149143
"//pkg/util/log/eventpb",
150-
"@com_github_prometheus_client_model//go",
151144
"@org_golang_x_sys//unix",
152145
],
153146
"@io_bazel_rules_go//go/platform:linux": [
154147
"//pkg/util/log/eventpb",
155-
"@com_github_prometheus_client_model//go",
156148
"@org_golang_x_sys//unix",
157149
],
158150
"@io_bazel_rules_go//go/platform:netbsd": [
159151
"//pkg/util/log/eventpb",
160-
"@com_github_prometheus_client_model//go",
161152
"@org_golang_x_sys//unix",
162153
],
163154
"@io_bazel_rules_go//go/platform:openbsd": [
164155
"//pkg/util/log/eventpb",
165-
"@com_github_prometheus_client_model//go",
166156
"@org_golang_x_sys//unix",
167157
],
168158
"@io_bazel_rules_go//go/platform:osx": [
169159
"//pkg/util/log/eventpb",
170-
"@com_github_prometheus_client_model//go",
171160
"@org_golang_x_sys//unix",
172161
],
173162
"@io_bazel_rules_go//go/platform:plan9": [
174163
"//pkg/util/log/eventpb",
175-
"@com_github_prometheus_client_model//go",
176164
"@org_golang_x_sys//unix",
177165
],
178166
"@io_bazel_rules_go//go/platform:qnx": [
179167
"//pkg/util/log/eventpb",
180-
"@com_github_prometheus_client_model//go",
181168
"@org_golang_x_sys//unix",
182169
],
183170
"@io_bazel_rules_go//go/platform:solaris": [
184171
"//pkg/util/log/eventpb",
185-
"@com_github_prometheus_client_model//go",
186172
"@org_golang_x_sys//unix",
187173
],
188174
"//conditions:default": [],

pkg/security/cert_expiry_cache.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ var ClientCertExpirationCacheCapacity = settings.RegisterIntSetting(
3535
settings.WithPublic)
3636

3737
type clientCertExpirationMetrics struct {
38-
expiration aggmetric.Gauge
39-
ttl aggmetric.Gauge
38+
expiration *aggmetric.Gauge
39+
ttl *aggmetric.Gauge
4040
}
4141

4242
// ClientCertExpirationCache contains a cache of gauge objects keyed by
@@ -189,7 +189,7 @@ func (c *ClientCertExpirationCache) MaybeUpsert(
189189
expiration := parentExpirationGauge.AddChild(key)
190190
expiration.Update(newExpiry)
191191
ttl := parentTTLGauge.AddFunctionalChild(ttlFunc(c.timeNow, newExpiry), key)
192-
c.mu.cache.Add(key, &clientCertExpirationMetrics{*expiration, *ttl})
192+
c.mu.cache.Add(key, &clientCertExpirationMetrics{expiration, ttl})
193193
}
194194
} else {
195195
log.Ops.Warningf(ctx, "no memory available to cache cert expiry: %v", err)

pkg/security/cert_expiry_cache_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/cockroachdb/cockroach/pkg/util/mon"
1919
"github.com/cockroachdb/cockroach/pkg/util/stop"
2020
"github.com/cockroachdb/cockroach/pkg/util/timeutil"
21+
io_prometheus_client "github.com/prometheus/client_model/go"
2122
"github.com/stretchr/testify/require"
2223
)
2324

@@ -120,6 +121,55 @@ func TestEntryCache(t *testing.T) {
120121
require.Equal(t, laterExpiration-(closerExpiration+20), ttl)
121122
}
122123

124+
// TestCacheMetricsSync verifies that the cache metrics are correctly synchronized
125+
// when entries are inserted and updated. It checks that the cache length and
126+
// expiration times are properly updated and reflected in the metrics.
127+
func TestCacheMetricsSync(t *testing.T) {
128+
defer leaktest.AfterTest(t)()
129+
130+
findChildMetric := func(metrics *aggmetric.AggGauge, childName string) *io_prometheus_client.Metric {
131+
var result *io_prometheus_client.Metric
132+
metrics.Each([]*io_prometheus_client.LabelPair{}, func(metric *io_prometheus_client.Metric) {
133+
if metric.GetLabel()[0].GetValue() == childName {
134+
result = metric
135+
}
136+
})
137+
return result
138+
}
139+
140+
const (
141+
fooUser = "foo"
142+
143+
laterExpiration = int64(1684359292)
144+
closerExpiration = int64(1584359292)
145+
)
146+
147+
ctx := context.Background()
148+
149+
timesource := timeutil.NewManualTime(timeutil.Unix(0, 123))
150+
// Create a cache with a capacity of 3.
151+
cache, expMetric, ttlMetric := newCache(
152+
ctx,
153+
&cluster.Settings{},
154+
3, /* capacity */
155+
timesource,
156+
)
157+
require.Equal(t, 0, cache.Len())
158+
159+
// insert.
160+
cache.MaybeUpsert(ctx, fooUser, laterExpiration, expMetric, ttlMetric)
161+
// update.
162+
cache.MaybeUpsert(ctx, fooUser, closerExpiration, expMetric, ttlMetric)
163+
164+
metricFloat := *(findChildMetric(expMetric, fooUser).Gauge.Value)
165+
expiration, found := cache.GetExpiration(fooUser)
166+
167+
// verify that both the cache and metric are in sync.
168+
require.Equal(t, true, found)
169+
require.Equal(t, closerExpiration, expiration)
170+
require.Equal(t, closerExpiration, int64(metricFloat))
171+
}
172+
123173
func TestPurgePastEntries(t *testing.T) {
124174
defer leaktest.AfterTest(t)()
125175

0 commit comments

Comments
 (0)