Skip to content

Log Client Certificate Identity Information in Access Logs#145

Open
geigerj0 wants to merge 3 commits intocloudfoundry:mainfrom
geigerj0:make-accesslogger-log-tls-peer-cert-info
Open

Log Client Certificate Identity Information in Access Logs#145
geigerj0 wants to merge 3 commits intocloudfoundry:mainfrom
geigerj0:make-accesslogger-log-tls-peer-cert-info

Conversation

@geigerj0
Copy link
Copy Markdown

@geigerj0 geigerj0 commented May 5, 2026

Problem

BBS currently does not include TLS peer certificate information in its access logs, making it difficult to reliably identify authenticated clients. At the moment, only the client IP address is logged, while no certificate-based identity information about the caller is recorded.

"remote_addr": r.RemoteAddr,

Solution

This PR enhances the LogWrap middleware to include TLS peer certificate information in request logs whenever such information is available.

If an access logger is configured via access_log_path, the TLS peer certificate details are logged at the INFO level and therefore written to the access log.

Backward Compatibility

Breaking Change? No

Contact Me

Feel free to reach out directly via Slack: https://cloudfoundry.slack.com/team/U0578H2V37D

@geigerj0 geigerj0 requested a review from a team as a code owner May 5, 2026 12:10
@geigerj0 geigerj0 changed the title Make accesslogger log tls peer cert info Log TLS Peer Certificate Information in Access Logs May 5, 2026
Comment on lines +30 to +43
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
indexLeafCertConnectionIsVerifiedAgainst := 0 // see also https://github.com/golang/go/blob/e929fb78e47dc191a402d34ca949d2e0c67e31b8/src/crypto/tls/common.go#L281-L282
cert := r.TLS.PeerCertificates[indexLeafCertConnectionIsVerifiedAgainst]

lagerData["peer_cert_subject_common_name"] = cert.Subject.CommonName
lagerData["peer_cert_subject_organizational_unit"] = cert.Subject.OrganizationalUnit
lagerData["peer_cert_subject_organization"] = cert.Subject.Organization

lagerData["peer_cert_issuer_common_name"] = cert.Issuer.CommonName
lagerData["peer_cert_issuer_organizational_unit"] = cert.Issuer.OrganizationalUnit
lagerData["peer_cert_issuer_organization"] = cert.Issuer.Organization
}

return lagerData
Copy link
Copy Markdown
Author

@geigerj0 geigerj0 May 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: this causes the LogWrap-middleware to always log peer cert information. however, the related log messages are being emitted with log level DEBUG and thus will more or less never be visible because no one runs this with DEBUG productively

} else {
return func(w http.ResponseWriter, r *http.Request) {
requestLog := logger.Session("request")
requestLog.Debug("serving", lagerDataFromReq(r))
defer requestLog.Debug("done", lagerDataFromReq(r))

Comment on lines +34 to +40
lagerData["peer_cert_subject_common_name"] = cert.Subject.CommonName
lagerData["peer_cert_subject_organizational_unit"] = cert.Subject.OrganizationalUnit
lagerData["peer_cert_subject_organization"] = cert.Subject.Organization

lagerData["peer_cert_issuer_common_name"] = cert.Issuer.CommonName
lagerData["peer_cert_issuer_organizational_unit"] = cert.Issuer.OrganizationalUnit
lagerData["peer_cert_issuer_organization"] = cert.Issuer.Organization
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can definitely discuss these key names (peer_cert_*), maybe you have a better idea

When("request has TLS peer certificates", func() {
BeforeEach(func() {
accessLogger = lagertest.NewTestLogger("")
accessLogger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.INFO)) // peer cert information should be logged at INFO level
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is very important to test that the log messages appear also for INFO-logging because this is the level the access logger is being set up with:

accessLogger.RegisterSink(lager.NewWriterSink(file, lager.INFO))

@geigerj0 geigerj0 changed the title Log TLS Peer Certificate Information in Access Logs Log Client Certificate Identity Information in Access Logs May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant