-
-
Notifications
You must be signed in to change notification settings - Fork 634
Use a unix socket to talk to pkimetal #8715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
0b3fce5
7b649db
b48b473
bf62423
d912f3b
9f5c6d3
747fce4
94af094
ab490d1
4f97ffa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,10 +6,12 @@ import ( | |
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net" | ||
| "net/http" | ||
| "net/url" | ||
| "slices" | ||
| "strings" | ||
| "sync" | ||
| "time" | ||
|
|
||
| "github.com/zmap/zcrypto/x509" | ||
|
|
@@ -20,10 +22,28 @@ import ( | |
| // PKIMetalConfig and its execute method provide a shared basis for linting | ||
| // 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:"Path to a unix socket where a pkilint REST API is listening."` | ||
| 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."` | ||
|
mcpherrinm marked this conversation as resolved.
Outdated
|
||
|
|
||
| clientOnce sync.Once | ||
| client *http.Client | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it makes sense to store these on the Config object. The only reason that .execute() is a method on the config object is that it is shared between both certViaPKIMetal and crlViaPKIMetal. It doesn't semantically belong there; having it be a method on the config struct was just a convenience. I think this PR should definitely store the http.Client on the certViaPKIMetal struct (and the crlViaPKIMetal struct), rather than on the config struct. And if you want to go farther for true code-matches-semantics, it should make
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. Yeah I was definitely just copying execute(), but can do
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I've made a refactor here to actually introduce a new linter/pkimetal package which contains just the code needed to Execute. I think this ends up being a lot neater, though it still has the somewhat unfortunate sync.Once that I don't love to get a reusable http client, but with the way Zlint's Configure() lifecycle is set up, I don't think we're going to do better without sidestepping zlint's config |
||
| } | ||
|
|
||
| func (pkim *PKIMetalConfig) httpClient() *http.Client { | ||
| pkim.clientOnce.Do(func() { | ||
| socket := pkim.Socket | ||
| pkim.client = &http.Client{ | ||
| Transport: &http.Transport{ | ||
| DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { | ||
| var d net.Dialer | ||
| return d.DialContext(ctx, "unix", socket) | ||
| }, | ||
| }, | ||
|
mcpherrinm marked this conversation as resolved.
Outdated
|
||
| } | ||
| }) | ||
| return pkim.client | ||
|
mcpherrinm marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResult, error) { | ||
|
|
@@ -35,7 +55,8 @@ 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) | ||
| // Host is ignored by our unix-socket transport, so any valid base works. | ||
| apiURL, err := url.JoinPath("http://pkimetal", endpoint) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("constructing pkimetal url: %w", err) | ||
| } | ||
|
|
@@ -56,7 +77,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 := pkim.httpClient().Do(req) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("making POST request to pkimetal API: %s (timeout %s)", err, timeout) | ||
| } | ||
|
|
@@ -141,8 +162,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 a socket to reach out to. If not, skip it. | ||
| return l.Socket != "" | ||
| } | ||
|
|
||
| func (l *certViaPKIMetal) Execute(c *x509.Certificate) *lint.LintResult { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| server: | ||
| # Disable the TCP webserver; we only listen on a unix socket so callers | ||
| # do not need any network access to reach pkimetal. | ||
|
mcpherrinm marked this conversation as resolved.
Outdated
|
||
| webserverPort: 0 | ||
| webserverPath: /var/run/pkimetal/pkimetal.sock | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/bin/bash | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a pretty straightforward port of wait-for-it.sh to support a socket. I think we could probably do this in docker-compose with a healthcheck and dependencies instead, but I figured that's too much changing at once |
||
|
|
||
| set -e -u | ||
|
|
||
| socket="${1}" | ||
| max_tries=40 | ||
|
|
||
| for n in $(seq 1 "${max_tries}"); do | ||
| if [ -S "${socket}" ]; then | ||
| echo "Socket ${socket} is ready" | ||
| exit 0 | ||
| fi | ||
| echo "$(date) - still waiting for socket ${socket}" | ||
| sleep 1 | ||
| done | ||
|
|
||
| echo "timed out waiting for socket ${socket}" | ||
| exit 1 | ||
Uh oh!
There was an error while loading. Please reload this page.