Skip to content

Commit 4261b07

Browse files
authored
add oTel instrumentation to pkcs11 context (#641)
1 parent e87c7bc commit 4261b07

7 files changed

Lines changed: 207 additions & 8 deletions

File tree

cmd/gen-cacert/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func main() {
148148
OrganizationalUnit: cc.OrganizationalUnit,
149149
CommonName: cc.CommonName,
150150
ValidityPeriod: cc.ValidityPeriod,
151-
}}, requireX509CACert, hostname, ips, uris, config.DefaultPKCS11Timeout)
151+
}}, requireX509CACert, hostname, ips, uris, config.DefaultPKCS11Timeout, false)
152152
if err != nil {
153153
log.Fatalf("unable to initialize cert signer: %v", err)
154154
}

cmd/sign-x509cert/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func main() {
143143
SessionPoolSize: 2,
144144
X509CACertLocation: caPath,
145145
CreateCACertIfNotExist: false,
146-
}}, requireX509CACert, "", nil, nil, config.DefaultPKCS11Timeout) // Hostname and ips should not be needed as CreateCACertIfNotExist is set to be false.
146+
}}, requireX509CACert, "", nil, nil, config.DefaultPKCS11Timeout, false) // Hostname and ips should not be needed as CreateCACertIfNotExist is set to be false.
147147

148148
if err != nil {
149149
log.Fatalf("unable to initialize cert signer: %v", err)

license_header

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Copyright 2024 Yahoo Inc.
1+
Copyright 2025 Yahoo Inc.
22
Licensed under the terms of the Apache License 2.0. Please see LICENSE file in project root for terms.

pkcs11/metrics.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// Copyright 2025 Yahoo Inc.
2+
// Licensed under the terms of the Apache License 2.0. Please see LICENSE file in project root for terms.
3+
4+
package pkcs11
5+
6+
import (
7+
"context"
8+
"time"
9+
10+
p11 "github.com/miekg/pkcs11"
11+
"go.opentelemetry.io/otel"
12+
"go.opentelemetry.io/otel/attribute"
13+
"go.opentelemetry.io/otel/metric"
14+
)
15+
16+
const (
17+
scopeName = "github.com/theparanoids/crypki/pkcs11"
18+
19+
pkcs11LatencyMetricName = "pkcs11_method_latency_ms"
20+
signerMetadataLatencyMetricName = "signer_method_latency_ms"
21+
)
22+
23+
var (
24+
meter = otel.GetMeterProvider().Meter(scopeName)
25+
signerLatencyMetric metric.Float64Histogram
26+
)
27+
28+
func init() {
29+
var err error
30+
if signerLatencyMetric, err = meter.Float64Histogram(
31+
signerMetadataLatencyMetricName,
32+
metric.WithUnit("ms"),
33+
metric.WithDescription("Measures the latency in ms for each signerMetadata method call")); err != nil {
34+
otel.Handle(err)
35+
}
36+
}
37+
38+
// ExportSignerMetadataLatencyMetric exports the latency of the signer metadata method.
39+
func ExportSignerMetadataLatencyMetric(operation string, method string, start time.Time) {
40+
durationMs := float64(time.Since(start).Microseconds()) / 1000.0
41+
signerLatencyMetric.Record(context.Background(),
42+
durationMs,
43+
metric.WithAttributes(
44+
attribute.String("signer.operation", operation),
45+
attribute.String("signer.method", method),
46+
),
47+
)
48+
}
49+
50+
// InstrumentedPKCS11Ctx is a wrapper around the PKCS11 context that collects oTel metrics.
51+
type InstrumentedPKCS11Ctx struct {
52+
PKCS11Ctx
53+
meter metric.Meter
54+
55+
methodLatencyMetrics metric.Float64Histogram
56+
}
57+
58+
// NewInstrumentedPKCS11Ctx creates a new InstrumentedPKCS11Ctx.
59+
func NewInstrumentedPKCS11Ctx(inner PKCS11Ctx) *InstrumentedPKCS11Ctx {
60+
instPKCS11Ctx := &InstrumentedPKCS11Ctx{
61+
PKCS11Ctx: inner,
62+
}
63+
64+
instPKCS11Ctx.meter = meter
65+
66+
var err error
67+
if instPKCS11Ctx.methodLatencyMetrics, err = instPKCS11Ctx.meter.Float64Histogram(
68+
pkcs11LatencyMetricName,
69+
metric.WithUnit("ms"),
70+
metric.WithDescription("Measures the latency in ms for each PKCS#11 method call")); err != nil {
71+
otel.Handle(err)
72+
}
73+
return instPKCS11Ctx
74+
}
75+
76+
func (i *InstrumentedPKCS11Ctx) exportLatency(method string, start time.Time) {
77+
durationMs := float64(time.Since(start).Microseconds()) / 1000.0
78+
i.methodLatencyMetrics.Record(context.Background(),
79+
durationMs,
80+
metric.WithAttributes(
81+
attribute.String("pkcs11.method", method),
82+
),
83+
)
84+
}
85+
86+
// GetAttributeValue gets the attribute value.
87+
func (i *InstrumentedPKCS11Ctx) GetAttributeValue(param1 p11.SessionHandle, param2 p11.ObjectHandle, param3 []*p11.Attribute) (ret1 []*p11.Attribute, ret2 error) {
88+
start := time.Now()
89+
ret1, ret2 = i.PKCS11Ctx.GetAttributeValue(param1, param2, param3)
90+
i.exportLatency("GetAttributeValue", start)
91+
return
92+
}
93+
94+
// SignInit initializes the signing.
95+
func (i *InstrumentedPKCS11Ctx) SignInit(param1 p11.SessionHandle, param2 []*p11.Mechanism, param3 p11.ObjectHandle) (ret1 error) {
96+
start := time.Now()
97+
ret1 = i.PKCS11Ctx.SignInit(param1, param2, param3)
98+
i.exportLatency("SignInit", start)
99+
return
100+
}
101+
102+
// Sign signs the data.
103+
func (i *InstrumentedPKCS11Ctx) Sign(param1 p11.SessionHandle, param2 []byte) (ret1 []byte, ret2 error) {
104+
start := time.Now()
105+
ret1, ret2 = i.PKCS11Ctx.Sign(param1, param2)
106+
i.exportLatency("Sign", start)
107+
return
108+
}
109+
110+
// Login logs in.
111+
func (i *InstrumentedPKCS11Ctx) Login(param1 p11.SessionHandle, param2 uint, param3 string) (ret1 error) {
112+
start := time.Now()
113+
ret1 = i.PKCS11Ctx.Login(param1, param2, param3)
114+
i.exportLatency("Login", start)
115+
return
116+
}
117+
118+
// GenerateRandom generates random data.
119+
func (i *InstrumentedPKCS11Ctx) GenerateRandom(param1 p11.SessionHandle, param2 int) (ret1 []byte, ret2 error) {
120+
start := time.Now()
121+
ret1, ret2 = i.PKCS11Ctx.GenerateRandom(param1, param2)
122+
i.exportLatency("GenerateRandom", start)
123+
return
124+
}
125+
126+
// FindObjectsInit initializes the object finding.
127+
func (i *InstrumentedPKCS11Ctx) FindObjectsInit(param1 p11.SessionHandle, param2 []*p11.Attribute) (ret1 error) {
128+
start := time.Now()
129+
ret1 = i.PKCS11Ctx.FindObjectsInit(param1, param2)
130+
i.exportLatency("FindObjectsInit", start)
131+
return
132+
}
133+
134+
// FindObjects finds the objects.
135+
func (i *InstrumentedPKCS11Ctx) FindObjects(param1 p11.SessionHandle, param2 int) (ret1 []p11.ObjectHandle, ret2 bool, ret3 error) {
136+
start := time.Now()
137+
ret1, ret2, ret3 = i.PKCS11Ctx.FindObjects(param1, param2)
138+
i.exportLatency("FindObjects", start)
139+
return
140+
}
141+
142+
// FindObjectsFinal finalizes the object finding.
143+
func (i *InstrumentedPKCS11Ctx) FindObjectsFinal(param1 p11.SessionHandle) (ret1 error) {
144+
start := time.Now()
145+
ret1 = i.PKCS11Ctx.FindObjectsFinal(param1)
146+
i.exportLatency("FindObjectsFinal", start)
147+
return
148+
}
149+
150+
// CloseSession closes the session.
151+
func (i *InstrumentedPKCS11Ctx) CloseSession(param1 p11.SessionHandle) (ret1 error) {
152+
start := time.Now()
153+
ret1 = i.PKCS11Ctx.CloseSession(param1)
154+
i.exportLatency("CloseSession", start)
155+
return
156+
}
157+
158+
// OpenSession opens a session.
159+
func (i *InstrumentedPKCS11Ctx) OpenSession(param1 uint, param2 uint) (ret1 p11.SessionHandle, ret2 error) {
160+
start := time.Now()
161+
ret1, ret2 = i.PKCS11Ctx.OpenSession(param1, param2)
162+
i.exportLatency("OpenSession", start)
163+
return
164+
}
165+
166+
// GetSlotList gets the slot list.
167+
func (i *InstrumentedPKCS11Ctx) GetSlotList(param1 bool) (ret1 []uint, ret2 error) {
168+
start := time.Now()
169+
ret1, ret2 = i.PKCS11Ctx.GetSlotList(param1)
170+
i.exportLatency("GetSlotList", start)
171+
return
172+
}
173+
174+
// GetSlotInfo gets the slot info.
175+
func (i *InstrumentedPKCS11Ctx) GetSlotInfo(param1 uint) (ret1 p11.SlotInfo, ret2 error) {
176+
start := time.Now()
177+
ret1, ret2 = i.PKCS11Ctx.GetSlotInfo(param1)
178+
i.exportLatency("GetSlotInfo", start)
179+
return
180+
}
181+
182+
// GetTokenInfo gets the token info.
183+
func (i *InstrumentedPKCS11Ctx) GetTokenInfo(param1 uint) (ret1 p11.TokenInfo, ret2 error) {
184+
start := time.Now()
185+
ret1, ret2 = i.PKCS11Ctx.GetTokenInfo(param1)
186+
i.exportLatency("GetTokenInfo", start)
187+
return
188+
}

pkcs11/signer.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,17 @@ func getSignerData(ctx context.Context, requestChan chan scheduler.Request, pool
121121
}
122122

123123
// NewCertSign initializes a CertSign object that interacts with PKCS11 compliant device.
124-
func NewCertSign(ctx context.Context, pkcs11ModulePath string, keys []config.KeyConfig, requireX509CACert map[string]bool, hostname string, ips []net.IP, uris []*url.URL, requestTimeout uint) (crypki.CertSign, error) {
124+
func NewCertSign(ctx context.Context, pkcs11ModulePath string, keys []config.KeyConfig, requireX509CACert map[string]bool, hostname string, ips []net.IP, uris []*url.URL, requestTimeout uint, enableOTel bool) (crypki.CertSign, error) {
125+
var p11ctx PKCS11Ctx
125126
p11ctx, err := initPKCS11Context(pkcs11ModulePath)
126127
if err != nil {
127128
return nil, fmt.Errorf("unable to initialize PKCS11 context: %v", err)
128129
}
129130

131+
if enableOTel {
132+
p11ctx = NewInstrumentedPKCS11Ctx(p11ctx)
133+
}
134+
130135
for idx, key := range keys {
131136
if key.TokenLabel != "" {
132137
if keys[idx].SlotNumber, err = findSlotNumber(p11ctx, key.TokenLabel); err != nil {
@@ -199,7 +204,7 @@ func (s *signer) SignSSHCert(ctx context.Context, reqChan chan scheduler.Request
199204
}
200205

201206
func (s *signer) GetX509CACert(ctx context.Context, reqChan chan scheduler.Request, keyIdentifier string) ([]byte, error) {
202-
const methodName = "GetSSHCertSigningKey"
207+
const methodName = "GetX509CACert"
203208
cert, ok := s.x509CACerts[keyIdentifier]
204209
if !ok {
205210
return nil, fmt.Errorf("unable to find CA cert for key identifier %q", keyIdentifier)

pkcs11/work.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,15 @@ func (w *Work) DoWork(workerCtx context.Context, worker *scheduler.Worker) {
110110
hStart = time.Now()
111111
switch w.work.method {
112112
case "GetSSHCertSigningKey", "GetX509CACert", "GetBlobSigningPublicKey":
113-
go w.work.signerData.getData(requestCtx, sResp.signer, w.work.pool, w.work.respChan, w.work.errChan, done)
113+
go func() {
114+
w.work.signerData.getData(requestCtx, sResp.signer, w.work.pool, w.work.respChan, w.work.errChan, done)
115+
ExportSignerMetadataLatencyMetric(w.work.method, "getData", hStart)
116+
}()
114117
case "SignSSHCert", "SignX509Cert", "SignBlob":
115-
go w.work.signerData.signData(requestCtx, sResp.signer, w.work.pool, w.work.respChan, w.work.errChan, done)
118+
go func() {
119+
w.work.signerData.signData(requestCtx, sResp.signer, w.work.pool, w.work.respChan, w.work.errChan, done)
120+
ExportSignerMetadataLatencyMetric(w.work.method, "signData", hStart)
121+
}()
116122
}
117123
case <-done:
118124
ht = time.Since(hStart).Nanoseconds() / time.Microsecond.Nanoseconds()

server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func Main() {
199199
log.Fatal(err)
200200
}
201201

202-
signer, err := pkcs11.NewCertSign(ctx, cfg.ModulePath, cfg.Keys, keyUsages[config.X509CertEndpoint], hostname, ips, nil, cfg.PKCS11RequestTimeout)
202+
signer, err := pkcs11.NewCertSign(ctx, cfg.ModulePath, cfg.Keys, keyUsages[config.X509CertEndpoint], hostname, ips, nil, cfg.PKCS11RequestTimeout, cfg.OTel.Enabled)
203203
if err != nil {
204204
log.Fatalf("unable to initialize cert signer: %v", err)
205205
}

0 commit comments

Comments
 (0)