Merge remote-tracking branch 'origin/main' into cdoxsey/pass-config

This commit is contained in:
Caleb Doxsey 2022-09-08 13:29:50 -06:00
commit 8482a422ca
35 changed files with 418 additions and 254 deletions

View file

@ -20,7 +20,7 @@ jobs:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # pin@v2
with:
go-version: ${{ matrix.go-version }}

View file

@ -83,7 +83,7 @@ jobs:
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
- name: Bump psql environment
uses: mikefarah/yq@1c7dc0e88aad311c89889bc5ce5d8f96931a1bd0 # pin@v4.23.1
uses: mikefarah/yq@3d11b0545dbc0712c2045dc9e8b6c95b298e824e # pin@v4.23.1
with:
cmd:
yq eval '.pomerium.image.tag = "${{ needs.publish.outputs.sha-tag }}"' -i

View file

@ -31,7 +31,7 @@ jobs:
node-version: 16.x
- name: Set up Go
uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # pin@v2
with:
go-version: 1.18.x
@ -52,7 +52,7 @@ jobs:
run: gcloud auth configure-docker
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@68acf3b1adf004ac9c2f0a4259e85c5f66e99bef # pin@v2
uses: goreleaser/goreleaser-action@ff11ca24a9b39f2d36796d1fbd7a4e39c182630a # pin@v2
with:
version: v0.184.0
args: release --config .github/goreleaser.yaml
@ -122,7 +122,7 @@ jobs:
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
- name: Bump test environment
uses: mikefarah/yq@1c7dc0e88aad311c89889bc5ce5d8f96931a1bd0 # pin@v4.23.1
uses: mikefarah/yq@3d11b0545dbc0712c2045dc9e8b6c95b298e824e # pin@v4.23.1
with:
cmd: yq eval '.pomerium.image.tag = "${{ needs.goreleaser.outputs.tag }}"' -i projects/pomerium-demo/pomerium-demo/values.yaml

View file

@ -16,7 +16,7 @@ jobs:
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: ${{ matrix.go-version }}
@ -62,7 +62,7 @@ jobs:
go-version: [1.18.x]
node-version: [16.x]
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: ${{ matrix.go-version }}
@ -120,7 +120,7 @@ jobs:
idp: [auth0, azure, github, gitlab, google, oidc, okta, onelogin, ping]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: ${{ matrix.go-version }}
@ -166,7 +166,7 @@ jobs:
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: ${{ matrix.go-version }}
@ -223,7 +223,7 @@ jobs:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
with:
fetch-depth: 0
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: 1.18.x
- uses: actions/setup-python@b55428b1882923874294fa556849718a1d7f2ca5
@ -246,7 +246,7 @@ jobs:
needs:
- build
steps:
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: 1.18.x

View file

@ -13,13 +13,13 @@ RUN make yarn
COPY ./ui/ ./ui/
RUN make build-ui
FROM golang:1.19.0-buster@sha256:a7a23f1fba8390b1e038f017c85259c878f406301643653ec6e5b97e75668789 as build
FROM golang:1.19.0-buster@sha256:d84495e2ad12dfeb51dec3c9f170659ebd09db234d6990b3364f877785684a14 as build
WORKDIR /go/src/github.com/pomerium/pomerium
RUN apt-get update \
&& apt-get -y --no-install-recommends install zip
# cache depedency downloads
# cache dependency downloads
COPY go.mod go.sum ./
RUN go mod download
COPY . .
@ -30,7 +30,7 @@ RUN make build-go NAME=pomerium
RUN touch /config.yaml
# build our own root trust store from current stable
FROM debian:stable@sha256:b9b1f4a7df16fcf7f287802d827b80f481a1e4caecb62c40c2e26fdebdc2eab9 as casource
FROM debian:stable@sha256:3d2aa501c4cefd4415895b1d877dfbba0739cab1d58cbe8f1baa3f01b6739690 as casource
RUN apt-get update && apt-get install -y ca-certificates
# Remove expired root (https://github.com/pomerium/pomerium/issues/2653)
RUN rm /usr/share/ca-certificates/mozilla/DST_Root_CA_X3.crt && update-ca-certificates

View file

@ -13,13 +13,13 @@ RUN make yarn
COPY ./ui/ ./ui/
RUN make build-ui
FROM golang:1.19.0-buster@sha256:a7a23f1fba8390b1e038f017c85259c878f406301643653ec6e5b97e75668789 as build
FROM golang:1.19.0-buster@sha256:d84495e2ad12dfeb51dec3c9f170659ebd09db234d6990b3364f877785684a14 as build
WORKDIR /go/src/github.com/pomerium/pomerium
RUN apt-get update \
&& apt-get -y --no-install-recommends install zip
# cache depedency downloads
# cache dependency downloads
COPY go.mod go.sum ./
RUN go mod download
COPY . .

View file

@ -138,20 +138,25 @@ func (a *Authenticate) VerifySession(next http.Handler) http.Handler {
defer span.End()
state := a.state.Load()
idpID := r.FormValue(urlutil.QueryIdentityProviderID)
cfg := a.currentConfig.Load()
idp, err := cfg.Options.GetIdentityProviderForID(r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return err
}
sessionState, err := a.getSessionFromCtx(ctx)
if err != nil {
log.FromRequest(r).Info().
Err(err).
Str("idp_id", idpID).
Str("idp_id", idp.GetId()).
Msg("authenticate: session load error")
return a.reauthenticateOrFail(w, r, err)
}
if sessionState.IdentityProviderID != idpID {
if sessionState.IdentityProviderID != idp.GetId() {
log.FromRequest(r).Info().
Str("idp_id", idpID).
Str("idp_id", idp.GetId()).
Str("session_idp_id", sessionState.IdentityProviderID).
Str("id", sessionState.ID).
Msg("authenticate: session not associated with identity provider")
return a.reauthenticateOrFail(w, r, err)
@ -163,7 +168,7 @@ func (a *Authenticate) VerifySession(next http.Handler) http.Handler {
if _, err = session.Get(ctx, state.dataBrokerClient, sessionState.ID); err != nil {
log.FromRequest(r).Info().
Err(err).
Str("idp_id", idpID).
Str("idp_id", idp.GetId()).
Str("id", sessionState.ID).
Msg("authenticate: session not found in databroker")
return a.reauthenticateOrFail(w, r, err)
@ -187,6 +192,11 @@ func (a *Authenticate) SignIn(w http.ResponseWriter, r *http.Request) error {
defer span.End()
state := a.state.Load()
cfg := a.currentConfig.Load()
idp, err := cfg.Options.GetIdentityProviderForID(r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return err
}
redirectURL, err := urlutil.ParseAndValidateURL(r.FormValue(urlutil.QueryRedirectURI))
if err != nil {
@ -216,8 +226,8 @@ func (a *Authenticate) SignIn(w http.ResponseWriter, r *http.Request) error {
}
// start over if this is a different identity provider
if s == nil || s.IdentityProviderID != r.FormValue(urlutil.QueryIdentityProviderID) {
s = sessions.NewState(urlutil.QueryIdentityProviderID)
if s == nil || s.IdentityProviderID != idp.GetId() {
s = sessions.NewState(idp.GetId())
}
newSession := s.WithNewIssuer(state.redirectURL.Host, jwtAudience)
@ -277,7 +287,7 @@ func (a *Authenticate) signOutRedirect(w http.ResponseWriter, r *http.Request) e
cfg := a.currentConfig.Load()
idp, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
authenticator, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return err
}
@ -296,14 +306,14 @@ func (a *Authenticate) signOutRedirect(w http.ResponseWriter, r *http.Request) e
redirectString = uri
}
endSessionURL, err := idp.LogOut()
endSessionURL, err := authenticator.LogOut()
if err == nil && redirectString != "" {
params := url.Values{}
params.Add("id_token_hint", rawIDToken)
params.Add("post_logout_redirect_uri", redirectString)
endSessionURL.RawQuery = params.Encode()
redirectString = endSessionURL.String()
} else if !errors.Is(err, oidc.ErrSignoutNotImplemented) {
} else if err != nil && !errors.Is(err, oidc.ErrSignoutNotImplemented) {
log.Warn(r.Context()).Err(err).Msg("authenticate.SignOut: failed getting session")
}
if redirectString != "" {
@ -330,10 +340,15 @@ func (a *Authenticate) reauthenticateOrFail(w http.ResponseWriter, r *http.Reque
return httputil.NewError(http.StatusUnauthorized, err)
}
cfg := a.currentConfig.Load()
state := a.state.Load()
cfg := a.currentConfig.Load()
idp, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
idp, err := cfg.Options.GetIdentityProviderForID(r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return err
}
authenticator, err := a.cfg.getIdentityProvider(cfg, idp.GetId())
if err != nil {
return err
}
@ -346,7 +361,7 @@ func (a *Authenticate) reauthenticateOrFail(w http.ResponseWriter, r *http.Reque
enc := cryptutil.Encrypt(state.cookieCipher, []byte(redirectURL.String()), b)
b = append(b, enc...)
encodedState := base64.URLEncoding.EncodeToString(b)
signinURL, err := idp.GetSignInURL(encodedState)
signinURL, err := authenticator.GetSignInURL(encodedState)
if err != nil {
return httputil.NewError(http.StatusInternalServerError,
fmt.Errorf("failed to get sign in url: %w", err))
@ -381,8 +396,8 @@ func (a *Authenticate) getOAuthCallback(w http.ResponseWriter, r *http.Request)
ctx, span := trace.StartSpan(r.Context(), "authenticate.getOAuthCallback")
defer span.End()
cfg := a.currentConfig.Load()
state := a.state.Load()
cfg := a.currentConfig.Load()
// Error Authentication Response: rfc6749#section-4.1.2.1 & OIDC#3.1.2.6
//
@ -428,9 +443,13 @@ func (a *Authenticate) getOAuthCallback(w http.ResponseWriter, r *http.Request)
if err != nil {
return nil, httputil.NewError(http.StatusBadRequest, err)
}
idpID := redirectURL.Query().Get(urlutil.QueryIdentityProviderID)
idp, err := a.cfg.getIdentityProvider(cfg, idpID)
idp, err := cfg.Options.GetIdentityProviderForID(r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return nil, err
}
authenticator, err := a.cfg.getIdentityProvider(cfg, idp.GetId())
if err != nil {
return nil, err
}
@ -439,12 +458,12 @@ func (a *Authenticate) getOAuthCallback(w http.ResponseWriter, r *http.Request)
//
// Exchange the supplied Authorization Code for a valid user session.
var claims identity.SessionClaims
accessToken, err := idp.Authenticate(ctx, code, &claims)
accessToken, err := authenticator.Authenticate(ctx, code, &claims)
if err != nil {
return nil, fmt.Errorf("error redeeming authenticate code: %w", err)
}
s := sessions.NewState(idpID)
s := sessions.NewState(idp.GetId())
err = claims.Claims.Claims(&s)
if err != nil {
return nil, fmt.Errorf("error unmarshaling session state: %w", err)
@ -583,7 +602,7 @@ func (a *Authenticate) saveSessionToDataBroker(
state := a.state.Load()
cfg := a.currentConfig.Load()
idp, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
authenticator, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return err
}
@ -593,7 +612,7 @@ func (a *Authenticate) saveSessionToDataBroker(
s := &session.Session{
Id: sessionState.ID,
UserId: sessionState.UserID(idp.Name()),
UserId: sessionState.UserID(authenticator.Name()),
IssuedAt: timestamppb.Now(),
AccessedAt: timestamppb.Now(),
ExpiresAt: sessionExpiry,
@ -617,7 +636,7 @@ func (a *Authenticate) saveSessionToDataBroker(
Id: s.GetUserId(),
}
}
err = idp.UpdateUserInfo(ctx, accessToken, &managerUser)
err = authenticator.UpdateUserInfo(ctx, accessToken, &managerUser)
if err != nil {
return fmt.Errorf("authenticate: error retrieving user info: %w", err)
}
@ -648,13 +667,18 @@ func (a *Authenticate) saveSessionToDataBroker(
// databroker. If successful, it returns the original `id_token` of the session, if failed, returns
// and empty string.
func (a *Authenticate) revokeSession(ctx context.Context, w http.ResponseWriter, r *http.Request) string {
cfg := a.currentConfig.Load()
state := a.state.Load()
cfg := a.currentConfig.Load()
// clear the user's local session no matter what
defer state.sessionStore.ClearSession(w, r)
idp, err := a.cfg.getIdentityProvider(cfg, r.FormValue(urlutil.QueryIdentityProviderID))
idp, err := cfg.Options.GetIdentityProviderForID(r.FormValue(urlutil.QueryIdentityProviderID))
if err != nil {
return ""
}
authenticator, err := a.cfg.getIdentityProvider(cfg, idp.GetId())
if err != nil {
return ""
}
@ -667,7 +691,7 @@ func (a *Authenticate) revokeSession(ctx context.Context, w http.ResponseWriter,
if s, _ := session.Get(ctx, state.dataBrokerClient, sessionState.ID); s != nil && s.OauthToken != nil {
rawIDToken = s.GetIdToken().GetRaw()
if err := idp.Revoke(ctx, manager.FromOAuthToken(s.OauthToken)); err != nil {
if err := authenticator.Revoke(ctx, manager.FromOAuthToken(s.OauthToken)); err != nil {
log.Ctx(ctx).Warn().Err(err).Msg("authenticate: failed to revoke access token")
}
}

View file

@ -394,7 +394,7 @@ func TestAuthenticate_OAuthCallback(t *testing.T) {
{"bad timing - too soon", http.MethodGet, time.Now().Add(1 * time.Hour).Unix(), "", "", "", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"bad timing - expired", http.MethodGet, time.Now().Add(-1 * time.Hour).Unix(), "", "", "", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"bad base64", http.MethodGet, time.Now().Unix(), "", "", "^", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"too many seperators", http.MethodGet, time.Now().Unix(), "", "", "|ok|now|what", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"too many separators", http.MethodGet, time.Now().Unix(), "", "", "|ok|now|what", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"bad hmac", http.MethodGet, time.Now().Unix(), "", "NOTMAC", "", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
{"bad hmac", http.MethodGet, time.Now().Unix(), base64.URLEncoding.EncodeToString([]byte("malformed_state")), "", "", "", "code", "https://corp.pomerium.io", "https://authenticate.pomerium.io", &mstore.Store{}, identity.MockProvider{AuthenticateResponse: oauth2.Token{}}, "https://corp.pomerium.io", http.StatusBadRequest},
}
@ -474,6 +474,8 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
w.WriteHeader(http.StatusOK)
})
idp, _ := new(config.Options).GetIdentityProviderForID("")
tests := []struct {
name string
headers map[string]string
@ -487,7 +489,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"good",
nil,
&mstore.Store{Session: &sessions.State{ID: "xyz"}},
&mstore.Store{Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
nil,
identity.MockProvider{RefreshResponse: oauth2.Token{Expiry: time.Now().Add(10 * time.Minute)}},
http.StatusOK,
@ -495,7 +497,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"invalid session",
nil,
&mstore.Store{Session: &sessions.State{ID: "xyz"}},
&mstore.Store{Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
errors.New("hi"),
identity.MockProvider{},
http.StatusFound,
@ -503,7 +505,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"good refresh expired",
nil,
&mstore.Store{Session: &sessions.State{ID: "xyz"}},
&mstore.Store{Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
nil,
identity.MockProvider{RefreshResponse: oauth2.Token{Expiry: time.Now().Add(10 * time.Minute)}},
http.StatusOK,
@ -511,7 +513,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"expired,refresh error",
nil,
&mstore.Store{Session: &sessions.State{ID: "xyz"}},
&mstore.Store{Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
sessions.ErrExpired,
identity.MockProvider{RefreshError: errors.New("error")},
http.StatusFound,
@ -519,7 +521,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"expired,save error",
nil,
&mstore.Store{SaveError: errors.New("error"), Session: &sessions.State{ID: "xyz"}},
&mstore.Store{SaveError: errors.New("error"), Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
sessions.ErrExpired,
identity.MockProvider{RefreshResponse: oauth2.Token{Expiry: time.Now().Add(10 * time.Minute)}},
http.StatusFound,
@ -527,7 +529,7 @@ func TestAuthenticate_SessionValidatorMiddleware(t *testing.T) {
{
"expired XHR,refresh error",
map[string]string{"X-Requested-With": "XmlHttpRequest"},
&mstore.Store{Session: &sessions.State{ID: "xyz"}},
&mstore.Store{Session: &sessions.State{IdentityProviderID: idp.GetId(), ID: "xyz"}},
sessions.ErrExpired,
identity.MockProvider{RefreshError: errors.New("error")},
http.StatusUnauthorized,

View file

@ -26,6 +26,8 @@ type Config struct {
MetricsPort string
// DebugPort is the port the debug listener is running on.
DebugPort string
// ACMETLSPort is the port that handles the ACME TLS-ALPN challenge.
ACMETLSALPNPort string
// MetricsScrapeEndpoints additional metrics endpoints to scrape and provide part of metrics
MetricsScrapeEndpoints []MetricsScrapeEndpoint
@ -56,11 +58,12 @@ func (cfg *Config) Clone() *Config {
AutoCertificates: cfg.AutoCertificates,
EnvoyVersion: cfg.EnvoyVersion,
GRPCPort: cfg.GRPCPort,
HTTPPort: cfg.HTTPPort,
OutboundPort: cfg.OutboundPort,
MetricsPort: cfg.MetricsPort,
DebugPort: cfg.DebugPort,
GRPCPort: cfg.GRPCPort,
HTTPPort: cfg.HTTPPort,
OutboundPort: cfg.OutboundPort,
MetricsPort: cfg.MetricsPort,
DebugPort: cfg.DebugPort,
ACMETLSALPNPort: cfg.ACMETLSALPNPort,
MetricsScrapeEndpoints: endpoints,
}
@ -85,10 +88,11 @@ func (cfg *Config) Checksum() uint64 {
}
// AllocatePorts populates
func (cfg *Config) AllocatePorts(ports [5]string) {
func (cfg *Config) AllocatePorts(ports [6]string) {
cfg.GRPCPort = ports[0]
cfg.HTTPPort = ports[1]
cfg.OutboundPort = ports[2]
cfg.MetricsPort = ports[3]
cfg.DebugPort = ports[4]
cfg.ACMETLSALPNPort = ports[5]
}

View file

@ -116,12 +116,12 @@ func NewFileOrEnvironmentSource(
EnvoyVersion: envoyVersion,
}
ports, err := netutil.AllocatePorts(5)
ports, err := netutil.AllocatePorts(6)
if err != nil {
return nil, fmt.Errorf("allocating ports: %w", err)
}
cfg.AllocatePorts(*(*[5]string)(ports))
cfg.AllocatePorts(*(*[6]string)(ports))
metrics.SetConfigInfo(ctx, cfg.Options.Services, "local", cfg.Checksum(), true)

View file

@ -0,0 +1,53 @@
package envoyconfig
import (
"strconv"
envoy_config_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
envoy_config_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
"github.com/pomerium/pomerium/config"
)
// Pomerium implements the ACME TLS-ALPN protocol by adding a filter chain to the main HTTPS listener
// that matches the acme-tls/1 application protocol on incoming requests and forwards them to a listener
// started in the `autocert` package. The proxying is done using TCP so that the Go listener can terminate
// the TLS connection using the certmagic package.
const (
acmeTLSALPNApplicationProtocol = "acme-tls/1"
acmeTLSALPNClusterName = "pomerium-acme-tls-alpn"
)
func (b *Builder) buildACMETLSALPNCluster(
cfg *config.Config,
) *envoy_config_cluster_v3.Cluster {
port, _ := strconv.Atoi(cfg.ACMETLSALPNPort)
return &envoy_config_cluster_v3.Cluster{
Name: acmeTLSALPNClusterName,
LoadAssignment: &envoy_config_endpoint_v3.ClusterLoadAssignment{
ClusterName: acmeTLSALPNClusterName,
Endpoints: []*envoy_config_endpoint_v3.LocalityLbEndpoints{{
LbEndpoints: []*envoy_config_endpoint_v3.LbEndpoint{{
HostIdentifier: &envoy_config_endpoint_v3.LbEndpoint_Endpoint{
Endpoint: &envoy_config_endpoint_v3.Endpoint{
Address: buildAddress("127.0.0.1", port),
},
},
}},
}},
},
}
}
func (b *Builder) buildACMETLSALPNFilterChain() *envoy_config_listener_v3.FilterChain {
return &envoy_config_listener_v3.FilterChain{
FilterChainMatch: &envoy_config_listener_v3.FilterChainMatch{
ApplicationProtocols: []string{acmeTLSALPNApplicationProtocol},
},
Filters: []*envoy_config_listener_v3.Filter{
TCPProxyFilter(acmeTLSALPNClusterName),
},
}
}

View file

@ -0,0 +1,54 @@
package envoyconfig
import (
"testing"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/testutil"
)
func TestBuilder_buildACMETLSALPNCluster(t *testing.T) {
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
testutil.AssertProtoJSONEqual(t,
`{
"name": "pomerium-acme-tls-alpn",
"loadAssignment": {
"clusterName": "pomerium-acme-tls-alpn",
"endpoints": [{
"lbEndpoints": [{
"endpoint": {
"address": {
"socketAddress": {
"address": "127.0.0.1",
"portValue": 1234
}
}
}
}]
}]
}
}`,
b.buildACMETLSALPNCluster(&config.Config{
ACMETLSALPNPort: "1234",
}))
}
func TestBuilder_buildACMETLSALPNFilterChain(t *testing.T) {
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
testutil.AssertProtoJSONEqual(t,
`{
"filterChainMatch": {
"applicationProtocols": ["acme-tls/1"]
},
"filters": [{
"name": "tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"cluster": "pomerium-acme-tls-alpn",
"statPrefix": "acme_tls_alpn"
}
}]
}`,
b.buildACMETLSALPNFilterChain())
}

View file

@ -80,6 +80,7 @@ func (b *Builder) BuildClusters(ctx context.Context, cfg *config.Config) ([]*env
}
clusters := []*envoy_config_cluster_v3.Cluster{
b.buildACMETLSALPNCluster(cfg),
controlGRPC,
controlHTTP,
controlMetrics,

View file

@ -9,6 +9,7 @@ import (
envoy_extensions_filters_listener_proxy_protocol_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/listener/proxy_protocol/v3"
envoy_extensions_filters_listener_tls_inspector_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/listener/tls_inspector/v3"
envoy_extensions_filters_network_http_connection_manager "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
envoy_extensions_filters_network_tcp_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
"google.golang.org/protobuf/types/known/durationpb"
@ -89,6 +90,21 @@ func ProxyProtocolFilter() *envoy_config_listener_v3.ListenerFilter {
}
}
// TCPProxyFilter creates a new TCP Proxy filter.
func TCPProxyFilter(clusterName string) *envoy_config_listener_v3.Filter {
return &envoy_config_listener_v3.Filter{
Name: "tcp_proxy",
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
TypedConfig: protoutil.NewAny(&envoy_extensions_filters_network_tcp_proxy_v3.TcpProxy{
StatPrefix: "acme_tls_alpn",
ClusterSpecifier: &envoy_extensions_filters_network_tcp_proxy_v3.TcpProxy_Cluster{
Cluster: clusterName,
},
}),
},
}
}
// TLSInspectorFilter creates a new TLS inspector filter.
func TLSInspectorFilter() *envoy_config_listener_v3.ListenerFilter {
return &envoy_config_listener_v3.ListenerFilter{

View file

@ -107,7 +107,7 @@ func (b *Builder) buildMainListener(
return nil, err
}
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg, allDomains, "")
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg, allDomains)
if err != nil {
return nil, err
}
@ -126,7 +126,7 @@ func (b *Builder) buildMainListener(
chains, err := b.buildFilterChains(cfg, cfg.Options.Addr,
func(tlsDomain string, httpDomains []string) (*envoy_config_listener_v3.FilterChain, error) {
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg, httpDomains, tlsDomain)
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg, httpDomains)
if err != nil {
return nil, err
}
@ -243,8 +243,7 @@ func (b *Builder) buildMetricsListener(
}
func (b *Builder) buildFilterChains(
cfg *config.Config,
addr string,
cfg *config.Config, addr string,
callback func(tlsDomain string, httpDomains []string) (*envoy_config_listener_v3.FilterChain, error),
) ([]*envoy_config_listener_v3.FilterChain, error) {
allDomains, err := getAllRouteableDomains(cfg, addr)
@ -258,14 +257,9 @@ func (b *Builder) buildFilterChains(
}
var chains []*envoy_config_listener_v3.FilterChain
chains = append(chains, b.buildACMETLSALPNFilterChain())
for _, domain := range tlsDomains {
routeableDomains, err := getRouteableDomainsForTLSServerName(cfg, addr, domain)
if err != nil {
return nil, err
}
// first we match on SNI
chain, err := callback(domain, routeableDomains)
chain, err := callback(domain, allDomains)
if err != nil {
return nil, err
}
@ -284,7 +278,6 @@ func (b *Builder) buildFilterChains(
func (b *Builder) buildMainHTTPConnectionManagerFilter(
cfg *config.Config,
domains []string,
tlsDomain string,
) (*envoy_config_listener_v3.Filter, error) {
authorizeURLs, err := cfg.Options.GetInternalAuthorizeURLs()
if err != nil {
@ -349,9 +342,6 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter(
LuaFilter(luascripts.CleanUpstream),
LuaFilter(luascripts.RewriteHeaders),
}
if tlsDomain != "" && tlsDomain != "*" {
filters = append(filters, LuaFilter(fmt.Sprintf(luascripts.FixMisdirected, tlsDomain)))
}
filters = append(filters, HTTPRouterFilter())
var maxStreamDuration *durationpb.Duration
@ -630,36 +620,7 @@ func (b *Builder) buildDownstreamValidationContext(
return vc
}
func getRouteableDomainsForTLSServerName(
cfg *config.Config,
addr string,
tlsServerName string,
) ([]string, error) {
allDomains := sets.NewSorted[string]()
if addr == cfg.Options.Addr {
domains, err := cfg.Options.GetAllRouteableHTTPDomainsForTLSServerName(tlsServerName)
if err != nil {
return nil, err
}
allDomains.Add(domains...)
}
if addr == cfg.Options.GetGRPCAddr() {
domains, err := cfg.Options.GetAllRouteableGRPCDomainsForTLSServerName(tlsServerName)
if err != nil {
return nil, err
}
allDomains.Add(domains...)
}
return allDomains.ToSlice(), nil
}
func getAllRouteableDomains(
cfg *config.Config,
addr string,
) ([]string, error) {
func getAllRouteableDomains(cfg *config.Config, addr string) ([]string, error) {
allDomains := sets.NewSorted[string]()
if addr == cfg.Options.Addr {
@ -681,17 +642,14 @@ func getAllRouteableDomains(
return allDomains.ToSlice(), nil
}
func getAllTLSDomains(
cfg *config.Config,
addr string,
) ([]string, error) {
allDomains, err := getAllRouteableDomains(cfg, addr)
func getAllTLSDomains(cfg *config.Config, addr string) ([]string, error) {
domains := sets.NewSorted[string]()
routeableDomains, err := getAllRouteableDomains(cfg, addr)
if err != nil {
return nil, err
}
domains := sets.NewSorted[string]()
for _, hp := range allDomains {
for _, hp := range routeableDomains {
if d, _, err := net.SplitHostPort(hp); err == nil {
domains.Add(d)
} else {
@ -699,6 +657,16 @@ func getAllTLSDomains(
}
}
certs, err := cfg.AllCertificates()
if err != nil {
return nil, err
}
for i := range certs {
for _, domain := range cryptutil.GetCertificateDomains(&certs[i]) {
domains.Add(domain)
}
}
return domains.ToSlice(), nil
}

View file

@ -2,6 +2,7 @@ package envoyconfig
import (
"context"
"encoding/base64"
"os"
"path/filepath"
"testing"
@ -13,6 +14,7 @@ import (
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/config/envoyconfig/filemgr"
"github.com/pomerium/pomerium/internal/testutil"
"github.com/pomerium/pomerium/pkg/cryptutil"
)
const (
@ -113,7 +115,7 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
options := config.NewDefaultOptions()
options.SkipXffAppend = true
options.XffNumTrustedHops = 1
filter, err := b.buildMainHTTPConnectionManagerFilter(config.New(options), []string{"example.com"}, "*")
filter, err := b.buildMainHTTPConnectionManagerFilter(&config.Config{Options: options}, []string{"example.com"})
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"name": "envoy.filters.network.http_connection_manager",
@ -724,6 +726,11 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
}
func Test_getAllDomains(t *testing.T) {
cert, err := cryptutil.GenerateSelfSignedCertificate("*.unknown.example.com")
require.NoError(t, err)
certPEM, keyPEM, err := cryptutil.EncodeCertificate(cert)
require.NoError(t, err)
options := &config.Options{
Addr: "127.0.0.1:9000",
GRPCAddr: "127.0.0.1:9001",
@ -736,6 +743,8 @@ func Test_getAllDomains(t *testing.T) {
{Source: &config.StringURL{URL: mustParseURL(t, "https://b.example.com")}},
{Source: &config.StringURL{URL: mustParseURL(t, "https://c.example.com")}},
},
Cert: base64.StdEncoding.EncodeToString(certPEM),
Key: base64.StdEncoding.EncodeToString(keyPEM),
}
cfg := config.New(options)
t.Run("routable", func(t *testing.T) {
@ -785,9 +794,10 @@ func Test_getAllDomains(t *testing.T) {
})
t.Run("tls", func(t *testing.T) {
t.Run("http", func(t *testing.T) {
actual, err := getAllTLSDomains(cfg, "127.0.0.1:9000")
actual, err := getAllTLSDomains(&config.Config{Options: options}, "127.0.0.1:9000")
require.NoError(t, err)
expect := []string{
"*.unknown.example.com",
"a.example.com",
"authenticate.example.com",
"b.example.com",
@ -796,9 +806,10 @@ func Test_getAllDomains(t *testing.T) {
assert.Equal(t, expect, actual)
})
t.Run("grpc", func(t *testing.T) {
actual, err := getAllTLSDomains(cfg, "127.0.0.1:9001")
actual, err := getAllTLSDomains(&config.Config{Options: options}, "127.0.0.1:9001")
require.NoError(t, err)
expect := []string{
"*.unknown.example.com",
"authorize.example.com",
"cache.example.com",
}

View file

@ -13,7 +13,6 @@ var luascripts struct {
CleanUpstream string
RemoveImpersonateHeaders string
RewriteHeaders string
FixMisdirected string
}
func init() {
@ -22,7 +21,6 @@ func init() {
"luascripts/ext-authz-set-cookie.lua": &luascripts.ExtAuthzSetCookie,
"luascripts/remove-impersonate-headers.lua": &luascripts.RemoveImpersonateHeaders,
"luascripts/rewrite-headers.lua": &luascripts.RewriteHeaders,
"luascripts/fix-misdirected.lua": &luascripts.FixMisdirected,
}
err := fs.WalkDir(luaFS, "luascripts", func(p string, d fs.DirEntry, err error) error {

View file

@ -43,61 +43,6 @@ func TestLuaCleanUpstream(t *testing.T) {
}, headers)
}
func TestLuaFixMisdirected(t *testing.T) {
t.Run("request", func(t *testing.T) {
L := lua.NewState()
defer L.Close()
bs, err := luaFS.ReadFile("luascripts/fix-misdirected.lua")
require.NoError(t, err)
err = L.DoString(string(bs))
require.NoError(t, err)
headers := map[string]string{
":authority": "TEST",
}
metadata := map[string]interface{}{}
dynamicMetadata := map[string]map[string]interface{}{}
handle := newLuaResponseHandle(L, headers, metadata, dynamicMetadata)
err = L.CallByParam(lua.P{
Fn: L.GetGlobal("envoy_on_request"),
NRet: 0,
Protect: true,
}, handle)
require.NoError(t, err)
assert.Equal(t, map[string]map[string]interface{}{
"envoy.filters.http.lua": {
"request.authority": "TEST",
},
}, dynamicMetadata)
})
t.Run("empty metadata", func(t *testing.T) {
L := lua.NewState()
defer L.Close()
bs, err := luaFS.ReadFile("luascripts/fix-misdirected.lua")
require.NoError(t, err)
err = L.DoString(string(bs))
require.NoError(t, err)
headers := map[string]string{}
metadata := map[string]interface{}{}
dynamicMetadata := map[string]map[string]interface{}{}
handle := newLuaResponseHandle(L, headers, metadata, dynamicMetadata)
err = L.CallByParam(lua.P{
Fn: L.GetGlobal("envoy_on_response"),
NRet: 0,
Protect: true,
}, handle)
require.NoError(t, err)
})
}
func TestLuaRewriteHeaders(t *testing.T) {
L := lua.NewState()
defer L.Close()

View file

@ -1,28 +0,0 @@
function envoy_on_request(request_handle)
local headers = request_handle:headers()
local dynamic_meta = request_handle:streamInfo():dynamicMetadata()
local authority = headers:get(":authority")
-- store the authority header in the metadata so we can retrieve it in the response
dynamic_meta:set("envoy.filters.http.lua", "request.authority", authority)
end
function envoy_on_response(response_handle)
local headers = response_handle:headers()
local dynamic_meta = response_handle:streamInfo():dynamicMetadata()
local filter_meta = dynamic_meta:get("envoy.filters.http.lua")
if filter_meta == nil then
return
end
local authority = filter_meta["request.authority"]
local expected_authority = "%s"
-- if we got a 404 (no route found) and the authority header doesn't match
-- assume we've coalesced http/2 connections and return a 421
if headers:get(":status") == "404" and authority ~= expected_authority then
headers:replace(":status", "421")
end
end

View file

@ -244,7 +244,7 @@ type Options struct {
// these requests with this switch
ForwardAuthURLString string `mapstructure:"forward_auth_url" yaml:"forward_auth_url,omitempty"`
// DataBrokerURLString is the routable destination of the databroker service's gRPC endpiont.
// DataBrokerURLString is the routable destination of the databroker service's gRPC endpoint.
DataBrokerURLString string `mapstructure:"databroker_service_url" yaml:"databroker_service_url,omitempty"`
DataBrokerURLStrings []string `mapstructure:"databroker_service_urls" yaml:"databroker_service_urls,omitempty"`
DataBrokerInternalURLString string `mapstructure:"databroker_internal_service_url" yaml:"databroker_internal_service_url,omitempty"`

View file

@ -17,7 +17,7 @@ echo "=> create our random shared-secret and cookie-secret keys as envars"
kubectl create secret generic shared-secret --from-literal=shared-secret=$(head -c32 /dev/urandom | base64)
kubectl create secret generic cookie-secret --from-literal=cookie-secret=$(head -c32 /dev/urandom | base64)
echo "=> initiliaze secrets for TLS wild card for service use"
echo "=> initialize secrets for TLS wild card for service use"
kubectl create secret generic certificate \
--from-literal=certificate=$(base64 -i "$HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer")
kubectl create secret generic certificate-key \

28
go.mod
View file

@ -4,16 +4,16 @@ go 1.18
require (
contrib.go.opencensus.io/exporter/jaeger v0.2.1
contrib.go.opencensus.io/exporter/prometheus v0.4.1
contrib.go.opencensus.io/exporter/prometheus v0.4.2
contrib.go.opencensus.io/exporter/zipkin v0.1.2
github.com/CAFxX/httpcompression v0.0.8
github.com/DataDog/opencensus-go-exporter-datadog v0.0.0-20200406135749-5c268882acf0
github.com/VictoriaMetrics/fastcache v1.10.0
github.com/caddyserver/certmagic v0.16.3
github.com/caddyserver/certmagic v0.17.0
github.com/cenkalti/backoff/v4 v4.1.3
github.com/cespare/xxhash/v2 v2.1.2
github.com/client9/misspell v0.3.4
github.com/coreos/go-oidc/v3 v3.2.0
github.com/coreos/go-oidc/v3 v3.3.0
github.com/docker/docker v20.10.17+incompatible
github.com/envoyproxy/go-control-plane v0.10.3-0.20220819153403-8a9be01c9575
github.com/envoyproxy/protoc-gen-validate v0.6.7
@ -34,7 +34,7 @@ require (
github.com/hashicorp/golang-lru v0.5.4
github.com/jackc/pgconn v1.13.0
github.com/jackc/pgtype v1.12.0
github.com/jackc/pgx/v4 v4.17.0
github.com/jackc/pgx/v4 v4.17.2
github.com/martinlindhe/base36 v1.1.1
github.com/mholt/acmez v1.0.4
github.com/mitchellh/hashstructure/v2 v2.0.2
@ -52,8 +52,8 @@ require (
github.com/prometheus/procfs v0.8.0
github.com/rjeczalik/notify v0.9.3-0.20201210012515-e2a77dcc14cf
github.com/rs/cors v1.8.2
github.com/rs/zerolog v1.27.0
github.com/shirou/gopsutil/v3 v3.22.7
github.com/rs/zerolog v1.28.0
github.com/shirou/gopsutil/v3 v3.22.8
github.com/spf13/viper v1.12.0
github.com/stretchr/testify v1.8.0
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f
@ -62,15 +62,15 @@ require (
github.com/volatiletech/null/v9 v9.0.0
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
go.opencensus.io v0.23.0
go.uber.org/zap v1.22.0
go.uber.org/zap v1.23.0
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
google.golang.org/api v0.93.0
google.golang.org/api v0.94.0
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f
google.golang.org/grpc v1.48.0
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
gopkg.in/auth0.v5 v5.21.1
gopkg.in/yaml.v3 v3.0.1
@ -130,7 +130,7 @@ require (
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-critic/go-critic v0.6.3 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-toolsmith/astcast v1.0.0 // indirect
@ -177,7 +177,7 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/puddle v1.2.1 // indirect
github.com/jackc/puddle v1.3.0 // indirect
github.com/jgautheron/goconst v1.5.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
@ -225,7 +225,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/statsd_exporter v0.21.0 // indirect
github.com/prometheus/statsd_exporter v0.22.7 // indirect
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a // indirect
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect

62
go.sum
View file

@ -68,8 +68,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI=
contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0=
contrib.go.opencensus.io/exporter/prometheus v0.4.1 h1:oObVeKo2NxpdF/fIfrPsNj6K0Prg0R0mHM+uANlYMiM=
contrib.go.opencensus.io/exporter/prometheus v0.4.1/go.mod h1:t9wvfitlUjGXG2IXAZsuFq26mDGid/JwCEXp+gTG/9U=
contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg=
contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ=
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
contrib.go.opencensus.io/exporter/zipkin v0.1.2 h1:YqE293IZrKtqPnpwDPH/lOqTWD/s3Iwabycam74JV3g=
contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE=
@ -177,6 +177,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
@ -244,8 +245,8 @@ github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/bytecodealliance/wasmtime-go v0.36.0 h1:B6thr7RMM9xQmouBtUqm1RpkJjuLS37m6nxX+iwsQSc=
github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
github.com/caddyserver/certmagic v0.16.3 h1:1ZbiU7y5X0MnDjBTXywUbPMs/ScHbgCeeCy/LPh4IZk=
github.com/caddyserver/certmagic v0.16.3/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/caddyserver/certmagic v0.17.0 h1:AHHvvmv6SNcq0vK5BgCevQqYMV8GNprVk6FWZzx8d+Q=
github.com/caddyserver/certmagic v0.17.0/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
@ -407,8 +408,8 @@ github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmeka
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-oidc/v3 v3.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc=
github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
github.com/coreos/go-oidc/v3 v3.3.0 h1:Y1LV3mP+QT3MEycATZpAiwfyN+uxZLqVbAHJUuOJEe4=
github.com/coreos/go-oidc/v3 v3.3.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -564,8 +565,9 @@ github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxF
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
@ -944,13 +946,13 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo=
github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw=
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
@ -1340,9 +1342,9 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -1359,8 +1361,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8=
github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ=
github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0=
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA=
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
@ -1394,11 +1396,11 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -1426,8 +1428,8 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
github.com/shirou/gopsutil/v3 v3.22.7 h1:flKnuCMfUUrO+oAvwAd6GKZgnPzr098VA/UJ14nhJd4=
github.com/shirou/gopsutil/v3 v3.22.7/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -1518,6 +1520,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
@ -1710,8 +1713,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -1828,7 +1831,6 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@ -1867,8 +1869,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 h1:N9Vc/rorQUDes6B9CNdIxAn5jODGj2wzfrei2x4wNj4=
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1889,8 +1891,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -2044,6 +2046,7 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -2233,8 +2236,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.93.0 h1:T2xt9gi0gHdxdnRkVQhT8mIvPaXKNsDNWz+L696M66M=
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.94.0 h1:KtKM9ru3nzQioV1HLlUf1cR7vMYJIpgls5VhAYQXIwA=
google.golang.org/api v0.94.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -2381,8 +2384,9 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

View file

@ -3,9 +3,11 @@ package autocert
import (
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"net"
"net/http"
"sort"
"sync"
@ -43,11 +45,12 @@ type Manager struct {
src config.Source
acmeTemplate certmagic.ACMEIssuer
mu sync.RWMutex
config *config.Config
certmagic *certmagic.Config
acmeMgr *atomicutil.Value[*certmagic.ACMEIssuer]
srv *http.Server
mu sync.RWMutex
config *config.Config
certmagic *certmagic.Config
acmeMgr *atomicutil.Value[*certmagic.ACMEIssuer]
srv *http.Server
acmeTLSALPNListener net.Listener
*ocspCache
@ -152,7 +155,6 @@ func (mgr *Manager) getCertMagicConfig(ctx context.Context, cfg *config.Config)
if err != nil {
return nil, err
}
acmeMgr.DisableTLSALPNChallenge = true
mgr.certmagic.Issuers = []certmagic.Issuer{acmeMgr}
mgr.acmeMgr.Store(acmeMgr)
@ -207,6 +209,7 @@ func (mgr *Manager) renewConfigCerts(ctx context.Context) error {
cfg = mgr.src.GetConfig().Clone()
mgr.updateServer(ctx, cfg)
mgr.updateACMETLSALPNServer(ctx, cfg)
if err := mgr.updateAutocert(ctx, cfg); err != nil {
return err
}
@ -224,6 +227,7 @@ func (mgr *Manager) update(ctx context.Context, cfg *config.Config) error {
defer func() { mgr.config = cfg }()
mgr.updateServer(ctx, cfg)
mgr.updateACMETLSALPNServer(ctx, cfg)
return mgr.updateAutocert(ctx, cfg)
}
@ -324,6 +328,34 @@ func (mgr *Manager) updateServer(ctx context.Context, cfg *config.Config) {
mgr.srv = hsrv
}
func (mgr *Manager) updateACMETLSALPNServer(ctx context.Context, cfg *config.Config) {
addr := net.JoinHostPort("127.0.0.1", cfg.ACMETLSALPNPort)
if mgr.acmeTLSALPNListener != nil {
_ = mgr.acmeTLSALPNListener.Close()
mgr.acmeTLSALPNListener = nil
}
tlsConfig := mgr.certmagic.TLSConfig()
ln, err := tls.Listen("tcp", addr, tlsConfig)
if err != nil {
log.Error(ctx).Err(err).Msg("failed to run acme tls alpn server")
return
}
mgr.acmeTLSALPNListener = ln
go func() {
for {
conn, err := ln.Accept()
if errors.Is(err, net.ErrClosed) {
return
} else if err != nil {
continue
}
_ = conn.Close()
}
}()
}
func (mgr *Manager) handleHTTPChallenge(w http.ResponseWriter, r *http.Request) bool {
return mgr.acmeMgr.Load().HandleHTTPChallenge(w, r)
}
@ -347,6 +379,8 @@ func configureCertificateAuthority(acmeMgr *certmagic.ACMEIssuer, opts config.Au
}
if opts.Email != "" {
acmeMgr.Email = opts.Email
} else {
acmeMgr.Email = " " // intentionally set to a space so that certmagic doesn't prompt for an email address
}
return nil
}

View file

@ -262,12 +262,15 @@ func TestConfig(t *testing.T) {
var initialOCSPStaple []byte
var certValidTime *time.Time
mgr.OnConfigChange(ctx, func(ctx context.Context, cfg *config.Config) {
log.Info(ctx).Msg("OnConfigChange")
if len(cfg.AutoCertificates) == 0 {
return
}
cert := cfg.AutoCertificates[0]
if initialOCSPStaple == nil {
initialOCSPStaple = cert.OCSPStaple
} else {
if bytes.Compare(initialOCSPStaple, cert.OCSPStaple) != 0 {
if !bytes.Equal(initialOCSPStaple, cert.OCSPStaple) {
log.Info(ctx).Msg("OCSP updated")
ocspUpdated <- true
}
@ -393,6 +396,7 @@ func Test_configureCertificateAuthority(t *testing.T) {
expected: &certmagic.ACMEIssuer{
Agreed: true,
CA: certmagic.DefaultACME.CA,
Email: " ",
TestCA: certmagic.DefaultACME.TestCA,
},
wantErr: false,
@ -409,6 +413,7 @@ func Test_configureCertificateAuthority(t *testing.T) {
expected: &certmagic.ACMEIssuer{
Agreed: true,
CA: certmagic.DefaultACME.TestCA,
Email: " ",
TestCA: certmagic.DefaultACME.TestCA,
},
wantErr: false,

View file

@ -51,7 +51,7 @@ func RenderJSON(w http.ResponseWriter, code int, v interface{}) {
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
//
// adapted from std library to suppport error wrapping
// adapted from std library to support error wrapping
type HandlerFunc func(http.ResponseWriter, *http.Request) error
// ServeHTTP calls f(w, r) error.

View file

@ -25,7 +25,7 @@ func SetHeaders(headers map[string]string) func(next http.Handler) http.Handler
}
// ValidateSignature ensures the request is valid and has been signed with
// the correspdoning client secret key
// the corresponding client secret key
func ValidateSignature(sharedKey []byte) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {

View file

@ -46,7 +46,7 @@ func (s *Sorted[T]) ForEach(callback func(element T) bool) {
})
}
// Has returns true if the elment is in the set.
// Has returns true if the element is in the set.
func (s *Sorted[T]) Has(element T) bool {
return s.b.Has(element)
}

View file

@ -80,6 +80,7 @@ func Run(ctx context.Context, src config.Source) error {
Str("outbound-port", src.GetConfig().OutboundPort).
Str("metrics-port", src.GetConfig().MetricsPort).
Str("debug-port", src.GetConfig().DebugPort).
Str("acme-tls-alpn-port", src.GetConfig().ACMETLSALPNPort).
Msg("server started")
// create envoy server

View file

@ -166,7 +166,7 @@ func EncodePrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
func GenerateSelfSignedCertificate(domain string, configure ...func(*x509.Certificate)) (*tls.Certificate, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, fmt.Errorf("failed to geneate private key: %w", err)
return nil, fmt.Errorf("failed to generate private key: %w", err)
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
@ -219,6 +219,21 @@ func GenerateSelfSignedCertificate(domain string, configure ...func(*x509.Certif
return &cert, nil
}
// EncodeCertificate encodes a TLS certificate into PEM compatible byte slices.
// Returns `nil`, `nil` if there is an error marshaling the PKCS8 private key.
func EncodeCertificate(cert *tls.Certificate) (pemCertificateBytes, pemKeyBytes []byte, err error) {
if cert == nil || len(cert.Certificate) == 0 {
return nil, nil, nil
}
publicKeyBytes := cert.Certificate[0]
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(cert.PrivateKey)
if err != nil {
return nil, nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicKeyBytes}),
pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyBytes}), nil
}
// ParsePEMCertificate parses a PEM encoded certificate block.
func ParsePEMCertificate(raw []byte) (*x509.Certificate, error) {
data := raw

View file

@ -165,3 +165,18 @@ func TestPrivateKeyMarshaling(t *testing.T) {
t.Fatal("private key encoding did not match")
}
}
func TestEncodeCertificate(t *testing.T) {
t.Run("nil", func(t *testing.T) {
cert, key, err := EncodeCertificate(nil)
assert.NoError(t, err)
assert.Nil(t, cert)
assert.Nil(t, key)
})
t.Run("empty certificate", func(t *testing.T) {
cert, key, err := EncodeCertificate(&tls.Certificate{})
assert.NoError(t, err)
assert.Nil(t, cert)
assert.Nil(t, key)
})
}

View file

@ -63,6 +63,30 @@ func GetCertificateForDomain(certificates []tls.Certificate, domain string) (*tl
return GenerateSelfSignedCertificate(domain)
}
// GetCertificateDomains gets all the certificate's matching domain names.
// Will return an empty slice if certificate is nil, empty, or x509 parsing fails.
func GetCertificateDomains(cert *tls.Certificate) []string {
if cert == nil || len(cert.Certificate) == 0 {
return nil
}
xcert, err := x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return nil
}
var domains []string
if xcert.Subject.CommonName != "" {
domains = append(domains, xcert.Subject.CommonName)
}
for _, dnsName := range xcert.DNSNames {
if dnsName != "" {
domains = append(domains, dnsName)
}
}
return domains
}
func matchesDomain(cert *tls.Certificate, domain string) bool {
if cert == nil || len(cert.Certificate) == 0 {
return false

View file

@ -5,6 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetCertificateForDomain(t *testing.T) {
@ -62,3 +63,9 @@ func TestGetCertificateForDomain(t *testing.T) {
assert.NotNil(t, found)
})
}
func TestGetCertificateDomains(t *testing.T) {
cert, err := GenerateSelfSignedCertificate("www.example.com")
require.NoError(t, err)
assert.Equal(t, []string{"www.example.com"}, GetCertificateDomains(cert))
}

View file

@ -128,6 +128,17 @@ var migrations = []func(context.Context, pgx.Tx) error{
return err
}
return nil
},
4: func(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, `
ALTER TABLE `+schemaName+`.`+recordChangesTableName+`
ALTER data DROP NOT NULL
`)
if err != nil {
return err
}
return nil
},
}

View file

@ -5,7 +5,7 @@ PATH="$PATH:$(go env GOPATH)/bin"
export PATH
_project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)/.."
_envoy_version=1.23.0
_envoy_version=1.23.1
_dir="$_project_root/pkg/envoy/files"
_target="${TARGET:-"$(go env GOOS)-$(go env GOARCH)"}"