Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ services:
- .:/boulder:cached
- ./.gocache:/root/.cache/go-build:cached
- ./test/certs/.softhsm-tokens/:/var/lib/softhsm/tokens/:cached
- pkimetal-socket:/var/run/pkimetal
networks:
bouldernet:
ipv4_address: 10.77.77.77
Expand Down Expand Up @@ -141,7 +142,10 @@ services:
- bouldernet

bpkimetal:
image: ghcr.io/pkimetal/pkimetal:v1.20.0
image: ghcr.io/pkimetal/pkimetal:v1.32.0
volumes:
- pkimetal-socket:/var/run/pkimetal
- ./test/config/pkimetal.yaml:/config.yaml:ro
networks:
- bouldernet

Expand Down Expand Up @@ -208,3 +212,6 @@ networks:
driver: default
config:
- subnet: 64.112.117.128/25

volumes:
pkimetal-socket:
41 changes: 35 additions & 6 deletions linter/lints/rfc/lint_cert_via_pkimetal.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/url"
"slices"
Expand All @@ -21,6 +22,7 @@ import (
// both certs and CRLs using PKIMetal.
type PKIMetalConfig struct {
Addr string `toml:"addr" comment:"The address where a pkilint REST API can be reached."`
Socket string `toml:"socket" comment:"The Unix socket path where a pkilint REST API can be reached. If set, this takes precedence over Addr."`
Severity string `toml:"severity" comment:"The minimum severity of findings to report (meta, debug, info, notice, warning, error, bug, or fatal)."`
Timeout time.Duration `toml:"timeout" comment:"How long, in nanoseconds, to wait before giving up."`
IgnoreLints []string `toml:"ignore_lints" comment:"The unique Validator:Code IDs of lint findings which should be ignored."`
Expand All @@ -35,9 +37,36 @@ func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResu
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

apiURL, err := url.JoinPath(pkim.Addr, endpoint)
if err != nil {
return nil, fmt.Errorf("constructing pkimetal url: %w", err)
// Create HTTP client based on whether we're using Unix socket or HTTP
var client *http.Client
var apiURL string
var err error

if pkim.Socket != "" {
// Use Unix socket connection
client = &http.Client{
Timeout: timeout,
Transport: &http.Transport{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To enable connection reuse, we shouldn't create a new http.Client (and importantly, http.Transport) for each request.

This code is a bit more verbose than it needs to be: Only the dummy value in place of pkim.Addr and Transport needs to change if pkim.Socket is set.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Refactored to store the HTTP client in the struct for reuse across requests, enabling connection pooling. The code now only conditionally sets the Transport and base URL, eliminating duplication. Changes in commit 86c1eb9.

DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", pkim.Socket)
},
},
}
// For Unix sockets, we use a dummy HTTP URL. The hostname is ignored since
// the custom DialContext overrides the connection mechanism to use the socket path.
apiURL, err = url.JoinPath("http://localhost", endpoint)
if err != nil {
return nil, fmt.Errorf("constructing pkimetal url: %w", err)
}
} else {
// Use regular HTTP connection
client = &http.Client{
Timeout: timeout,
}
apiURL, err = url.JoinPath(pkim.Addr, endpoint)
if err != nil {
return nil, fmt.Errorf("constructing pkimetal url: %w", err)
}
}

// reqForm matches PKIMetal's documented form-urlencoded request format. It
Expand All @@ -56,7 +85,7 @@ func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResu
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("making POST request to pkimetal API: %s (timeout %s)", err, timeout)
}
Expand Down Expand Up @@ -141,8 +170,8 @@ func (l *certViaPKIMetal) Configure() any {

func (l *certViaPKIMetal) CheckApplies(c *x509.Certificate) bool {
// This lint applies to all certificates issued by Boulder, as long as it has
// been configured with an address to reach out to. If not, skip it.
return l.Addr != ""
// been configured with an address or socket to reach out to. If not, skip it.
return l.Addr != "" || l.Socket != ""
}

func (l *certViaPKIMetal) Execute(c *x509.Certificate) *lint.LintResult {
Expand Down
4 changes: 2 additions & 2 deletions linter/lints/rfc/lint_crl_via_pkimetal.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func (l *crlViaPKIMetal) Configure() any {

func (l *crlViaPKIMetal) CheckApplies(c *x509.RevocationList) bool {
// This lint applies to all CRLs issued by Boulder, as long as it has
// been configured with an address to reach out to. If not, skip it.
return l.Addr != ""
// been configured with an address or socket to reach out to. If not, skip it.
return l.Addr != "" || l.Socket != ""
}

func (l *crlViaPKIMetal) Execute(c *x509.RevocationList) *lint.LintResult {
Expand Down
2 changes: 2 additions & 0 deletions test/config-next/pkimetal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server:
webserverPath: /var/run/pkimetal/pkimetal.sock
4 changes: 2 additions & 2 deletions test/config-next/zlint.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[e_pkimetal_lint_cabf_serverauth_cert]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = [
Expand All @@ -22,7 +22,7 @@ ignore_lints = [
]

[e_pkimetal_lint_cabf_serverauth_crl]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = []
2 changes: 2 additions & 0 deletions test/config/pkimetal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server:
webserverPath: /var/run/pkimetal/pkimetal.sock
4 changes: 2 additions & 2 deletions test/config/zlint.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[e_pkimetal_lint_cabf_serverauth_cert]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = [
Expand All @@ -18,7 +18,7 @@ ignore_lints = [
]

[e_pkimetal_lint_cabf_serverauth_crl]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = []
Loading