Skip to content

Commit

Permalink
Add logging to certpoolwatcher and client
Browse files Browse the repository at this point in the history
Logging now indicates what certificate (by file and X.509 name) is being watched

When an unverified certificate error is returned to the client, log the cert

Signed-off-by: Todd Short <[email protected]>
  • Loading branch information
tmshort committed Feb 3, 2025
1 parent 9b08aea commit 0d53099
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 2 deletions.
24 changes: 24 additions & 0 deletions internal/catalogmetadata/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package client

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
Expand All @@ -12,6 +14,9 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Check failure on line 16 in internal/catalogmetadata/client/client.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
ctrl "sigs.k8s.io/controller-runtime"

"github.com/go-logr/logr"

Check failure on line 19 in internal/catalogmetadata/client/client.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
"github.com/operator-framework/operator-registry/alpha/declcfg"

catalogd "github.com/operator-framework/operator-controller/catalogd/api/v1"
Expand Down Expand Up @@ -111,6 +116,24 @@ func (c *Client) PopulateCache(ctx context.Context, catalog *catalogd.ClusterCat
return c.cache.Put(catalog.Name, catalog.Status.ResolvedSource.Image.Ref, resp.Body, nil)
}

func logX509Error(err error, l logr.Logger) {
var cvErr *tls.CertificateVerificationError
if errors.As(err, &cvErr) {
n := 1
for _, cert := range cvErr.UnverifiedCertificates {
l.Error(err, "Unverified Cert", "n", n, "subject", cert.Subject, "issuer", cert.Issuer, "DNSNames", cert.DNSNames, "serial", cert.SerialNumber)
n = n + 1
}
return
}

var uaErr *x509.UnknownAuthorityError
if errors.As(err, &uaErr) {
l.Error(err, "Unknown Authority", "cert", "subject", uaErr.Cert.Subject, "issuer", uaErr.Cert.Issuer, "DNSNames", uaErr.Cert.DNSNames, "serial", uaErr.Cert.SerialNumber)
return
}
}

func (c *Client) doRequest(ctx context.Context, catalog *catalogd.ClusterCatalog) (*http.Response, error) {
if catalog.Status.URLs == nil {
return nil, fmt.Errorf("error: catalog %q has a nil status.urls value", catalog.Name)
Expand All @@ -133,6 +156,7 @@ func (c *Client) doRequest(ctx context.Context, catalog *catalogd.ClusterCatalog

resp, err := client.Do(req)
if err != nil {
logX509Error(err, ctrl.Log.WithName("catalog-client"))
return nil, fmt.Errorf("error performing request: %v", err)
}

Expand Down
83 changes: 83 additions & 0 deletions internal/httputil/certlog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package httputil

import (
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"path/filepath"

"github.com/go-logr/logr"
)

func logPath(path, action string, log logr.Logger) {
fi, err := os.Stat(path)
if err != nil {
log.Error(err, "error in os.Stat()", "path", path)
return
}
if !fi.IsDir() {
logFile(path, "", fmt.Sprintf("%s file", action), log)
return
}
action = fmt.Sprintf("%s directory", action)
dirEntries, err := os.ReadDir(path)
if err != nil {
log.Error(err, "error in os.ReadDir()", "path", path)
return
}
for _, e := range dirEntries {
file := filepath.Join(path, e.Name())
fi, err := os.Stat(file)
if err != nil {
log.Error(err, "error in os.Stat()", "file", file)
continue
}
if fi.IsDir() {
log.Info("ignoring subdirectory", "directory", file)
continue
}
logFile(e.Name(), path, action, log)
}
}

func logFile(filename, path, action string, log logr.Logger) {
filepath := filepath.Join(path, filename)
data, err := os.ReadFile(filepath)
if err != nil {
log.Error(err, "error in os.ReadFile()", "file", filename)
return
}
logPem(data, filename, path, action, log)
}

func logPem(data []byte, filename, path, action string, log logr.Logger) {
for len(data) > 0 {
var block *pem.Block
block, data = pem.Decode(data)
if block == nil {
log.Error(nil, "no block returned from pem.Decode()", "file", filename)
return
}
crt, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Error(err, "error in x509.ParseCertificate()", "file", filename)
return
}

args := []any{}
if path != "" {
args = append(args, "directory", path)
}
// Find an appopriate certificate identifier
args = append(args, "file", filename)
if s := crt.Subject.String(); s != "" {
args = append(args, "subject", s)
} else if crt.DNSNames != nil {
args = append(args, "DNSNames", crt.DNSNames)
} else if s := crt.SerialNumber.String(); s != "" {
args = append(args, "serial", s)
}
log.Info(action, args...)
}
}
9 changes: 7 additions & 2 deletions internal/httputil/certpoolwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ func NewCertPoolWatcher(caDir string, log logr.Logger) (*CertPoolWatcher, error)
// If the SSL_CERT_DIR or SSL_CERT_FILE environment variables are
// specified, this means that we have some control over the system root
// location, thus they may change, thus we should watch those locations.
watchPaths := strings.Split(os.Getenv("SSL_CERT_DIR"), ":")
watchPaths = append(watchPaths, caDir, os.Getenv("SSL_CERT_FILE"))
sslCertDir := os.Getenv("SSL_CERT_DIR")
sslCertFile := os.Getenv("SSL_CERT_FILE")
log.Info("SSL environment", "SSL_CERT_DIR", sslCertDir, "SSL_CERT_FILE", sslCertFile)

watchPaths := strings.Split(sslCertDir, ":")
watchPaths = append(watchPaths, caDir, sslCertFile)
watchPaths = slices.DeleteFunc(watchPaths, func(p string) bool {
if p == "" {
return true
Expand All @@ -66,6 +70,7 @@ func NewCertPoolWatcher(caDir string, log logr.Logger) (*CertPoolWatcher, error)
if err := watcher.Add(p); err != nil {
return nil, err
}
logPath(p, "watching certificate", log)
}

cpw := &CertPoolWatcher{
Expand Down
1 change: 1 addition & 0 deletions internal/httputil/certutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func NewCertPool(caDir string, log logr.Logger) (*x509.CertPool, error) {
if caCertPool.AppendCertsFromPEM(data) {
count++
}
logPem(data, e.Name(), caDir, "loading certificate file", log)
}

// Found no certs!
Expand Down

0 comments on commit 0d53099

Please sign in to comment.