mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-12 08:37:38 +02:00
directory: add logging http client to help with debugging outbound http requests (#2385)
This commit is contained in:
parent
aa0e6872de
commit
ac8ae3ef5b
13 changed files with 110 additions and 20 deletions
|
@ -226,7 +226,7 @@ func (srv *Server) ReleaseLease(ctx context.Context, req *databroker.ReleaseLeas
|
||||||
func (srv *Server) RenewLease(ctx context.Context, req *databroker.RenewLeaseRequest) (*emptypb.Empty, error) {
|
func (srv *Server) RenewLease(ctx context.Context, req *databroker.RenewLeaseRequest) (*emptypb.Empty, error) {
|
||||||
_, span := trace.StartSpan(ctx, "databroker.grpc.RenewLease")
|
_, span := trace.StartSpan(ctx, "databroker.grpc.RenewLease")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
log.Info(ctx).
|
log.Debug(ctx).
|
||||||
Str("peer", grpcutil.GetPeerAddr(ctx)).
|
Str("peer", grpcutil.GetPeerAddr(ctx)).
|
||||||
Str("name", req.GetName()).
|
Str("name", req.GetName()).
|
||||||
Str("id", req.GetId()).
|
Str("id", req.GetId()).
|
||||||
|
|
|
@ -12,8 +12,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,7 +57,10 @@ func WithLoginURL(loginURL *url.URL) Option {
|
||||||
// WithHTTPClient sets the http client to use for requests to the Azure APIs.
|
// WithHTTPClient sets the http client to use for requests to the Azure APIs.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "azure")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tomnomnom/linkheader"
|
"github.com/tomnomnom/linkheader"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
@ -47,7 +48,10 @@ func WithServiceAccount(serviceAccount *ServiceAccount) Option {
|
||||||
// WithHTTPClient sets the http client option.
|
// WithHTTPClient sets the http client option.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "github")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tomnomnom/linkheader"
|
"github.com/tomnomnom/linkheader"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
@ -45,7 +46,10 @@ func WithServiceAccount(serviceAccount *ServiceAccount) Option {
|
||||||
// WithHTTPClient sets the http client option.
|
// WithHTTPClient sets the http client option.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "azure")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
"google.golang.org/api/option"
|
"google.golang.org/api/option"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
@ -33,6 +34,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
|
httpClient *http.Client
|
||||||
serviceAccount *ServiceAccount
|
serviceAccount *ServiceAccount
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
@ -40,6 +42,16 @@ type config struct {
|
||||||
// An Option changes the configuration for the Google directory provider.
|
// An Option changes the configuration for the Google directory provider.
|
||||||
type Option func(cfg *config)
|
type Option func(cfg *config)
|
||||||
|
|
||||||
|
// WithHTTPClient sets the http client option.
|
||||||
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
|
return func(cfg *config) {
|
||||||
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "google")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithServiceAccount sets the service account in the Google configuration.
|
// WithServiceAccount sets the service account in the Google configuration.
|
||||||
func WithServiceAccount(serviceAccount *ServiceAccount) Option {
|
func WithServiceAccount(serviceAccount *ServiceAccount) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
|
@ -56,6 +68,7 @@ func WithURL(url string) Option {
|
||||||
|
|
||||||
func getConfig(options ...Option) *config {
|
func getConfig(options ...Option) *config {
|
||||||
cfg := new(config)
|
cfg := new(config)
|
||||||
|
WithHTTPClient(http.DefaultClient)(cfg)
|
||||||
WithURL(defaultProviderURL)(cfg)
|
WithURL(defaultProviderURL)(cfg)
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(cfg)
|
option(cfg)
|
||||||
|
@ -241,7 +254,10 @@ func (p *Provider) getAPIClient(ctx context.Context) (*admin.Service, error) {
|
||||||
|
|
||||||
ts := config.TokenSource(ctx)
|
ts := config.TokenSource(ctx)
|
||||||
|
|
||||||
p.apiClient, err = admin.NewService(ctx, option.WithTokenSource(ts), option.WithEndpoint(p.cfg.url))
|
p.apiClient, err = admin.NewService(ctx,
|
||||||
|
option.WithTokenSource(ts),
|
||||||
|
option.WithEndpoint(p.cfg.url),
|
||||||
|
option.WithHTTPClient(p.cfg.httpClient))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("google: failed creating admin service %w", err)
|
return nil, fmt.Errorf("google: failed creating admin service %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tomnomnom/linkheader"
|
"github.com/tomnomnom/linkheader"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
@ -61,7 +62,10 @@ func WithBatchSize(batchSize int) Option {
|
||||||
// WithHTTPClient sets the http client option.
|
// WithHTTPClient sets the http client option.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "okta")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
"github.com/pomerium/pomerium/pkg/grpc/directory"
|
||||||
)
|
)
|
||||||
|
@ -43,7 +44,10 @@ func WithBatchSize(batchSize int) Option {
|
||||||
// WithHTTPClient sets the http client option.
|
// WithHTTPClient sets the http client option.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "onelogin")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,10 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/encoding"
|
"github.com/pomerium/pomerium/internal/encoding"
|
||||||
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
|
@ -44,7 +47,10 @@ func WithEnvironmentID(environmentID string) Option {
|
||||||
// WithHTTPClient sets the http client option.
|
// WithHTTPClient sets the http client option.
|
||||||
func WithHTTPClient(httpClient *http.Client) Option {
|
func WithHTTPClient(httpClient *http.Client) Option {
|
||||||
return func(cfg *config) {
|
return func(cfg *config) {
|
||||||
cfg.httpClient = httpClient
|
cfg.httpClient = httputil.NewLoggingClient(httpClient,
|
||||||
|
func(evt *zerolog.Event) *zerolog.Event {
|
||||||
|
return evt.Str("provider", "ping")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,14 +12,61 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||||
"github.com/pomerium/pomerium/internal/telemetry/requestid"
|
"github.com/pomerium/pomerium/internal/telemetry/requestid"
|
||||||
"github.com/pomerium/pomerium/internal/tripper"
|
"github.com/pomerium/pomerium/internal/tripper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrTokenRevoked signifies a token revokation or expiration error
|
// ErrTokenRevoked signifies a token revocation or expiration error
|
||||||
var ErrTokenRevoked = errors.New("token expired or revoked")
|
var ErrTokenRevoked = errors.New("token expired or revoked")
|
||||||
|
|
||||||
|
type loggingRoundTripper struct {
|
||||||
|
base http.RoundTripper
|
||||||
|
customize []func(event *zerolog.Event) *zerolog.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l loggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
start := time.Now()
|
||||||
|
res, err := l.base.RoundTrip(req)
|
||||||
|
statusCode := http.StatusInternalServerError
|
||||||
|
if res != nil {
|
||||||
|
statusCode = res.StatusCode
|
||||||
|
}
|
||||||
|
evt := log.Debug(req.Context()).
|
||||||
|
Str("method", req.Method).
|
||||||
|
Str("authority", req.URL.Host).
|
||||||
|
Str("path", req.URL.Path).
|
||||||
|
Dur("duration", time.Since(start)).
|
||||||
|
Int("response-code", statusCode)
|
||||||
|
for _, f := range l.customize {
|
||||||
|
f(evt)
|
||||||
|
}
|
||||||
|
evt.Msg("outbound http-request")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoggingRoundTripper creates a http.RoundTripper that will log requests.
|
||||||
|
func NewLoggingRoundTripper(base http.RoundTripper, customize ...func(event *zerolog.Event) *zerolog.Event) http.RoundTripper {
|
||||||
|
if base == nil {
|
||||||
|
base = http.DefaultTransport
|
||||||
|
}
|
||||||
|
return loggingRoundTripper{base: base, customize: customize}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoggingClient creates a new http.Client that will log requests.
|
||||||
|
func NewLoggingClient(base *http.Client, customize ...func(event *zerolog.Event) *zerolog.Event) *http.Client {
|
||||||
|
if base == nil {
|
||||||
|
base = http.DefaultClient
|
||||||
|
}
|
||||||
|
newClient := new(http.Client)
|
||||||
|
*newClient = *base
|
||||||
|
newClient.Transport = NewLoggingRoundTripper(newClient.Transport, customize...)
|
||||||
|
return newClient
|
||||||
|
}
|
||||||
|
|
||||||
type httpClient struct {
|
type httpClient struct {
|
||||||
*http.Client
|
*http.Client
|
||||||
requestIDTripper http.RoundTripper
|
requestIDTripper http.RoundTripper
|
||||||
|
@ -33,14 +80,14 @@ func (c *httpClient) Do(req *http.Request) (*http.Response, error) {
|
||||||
return c.Client.Do(req)
|
return c.Client.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultClient avoids leaks by setting an upper limit for timeouts.
|
// defaultClient avoids leaks by setting an upper limit for timeouts.
|
||||||
var DefaultClient = &httpClient{
|
var defaultClient = &httpClient{
|
||||||
&http.Client{Timeout: 1 * time.Minute},
|
&http.Client{Timeout: 1 * time.Minute},
|
||||||
requestid.NewRoundTripper(http.DefaultTransport),
|
requestid.NewRoundTripper(http.DefaultTransport),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client provides a simple helper interface to make HTTP requests
|
// Do provides a simple helper interface to make HTTP requests
|
||||||
func Client(ctx context.Context, method, endpoint, userAgent string, headers map[string]string, params url.Values, response interface{}) error {
|
func Do(ctx context.Context, method, endpoint, userAgent string, headers map[string]string, params url.Values, response interface{}) error {
|
||||||
var body io.Reader
|
var body io.Reader
|
||||||
switch method {
|
switch method {
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
|
@ -66,7 +113,7 @@ func Client(ctx context.Context, method, endpoint, userAgent string, headers map
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := DefaultClient.Do(req)
|
resp, err := defaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,5 +21,5 @@ func TestDefaultClient(t *testing.T) {
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
|
req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
|
||||||
req = req.WithContext(requestid.WithValue(context.Background(), "foo"))
|
req = req.WithContext(requestid.WithValue(context.Background(), "foo"))
|
||||||
_, _ = DefaultClient.Do(req)
|
_, _ = defaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ func (p *Provider) userEmail(ctx context.Context, t *oauth2.Token, v interface{}
|
||||||
}
|
}
|
||||||
headers := map[string]string{"Authorization": fmt.Sprintf("token %s", t.AccessToken)}
|
headers := map[string]string{"Authorization": fmt.Sprintf("token %s", t.AccessToken)}
|
||||||
emailURL := githubAPIURL + emailPath
|
emailURL := githubAPIURL + emailPath
|
||||||
err := httputil.Client(ctx, http.MethodGet, emailURL, version.UserAgent(), headers, nil, &response)
|
err := httputil.Do(ctx, http.MethodGet, emailURL, version.UserAgent(), headers, nil, &response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ func (p *Provider) userInfo(ctx context.Context, t *oauth2.Token, v interface{})
|
||||||
"Authorization": fmt.Sprintf("token %s", t.AccessToken),
|
"Authorization": fmt.Sprintf("token %s", t.AccessToken),
|
||||||
"Accept": "application/vnd.github.v3+json",
|
"Accept": "application/vnd.github.v3+json",
|
||||||
}
|
}
|
||||||
err := httputil.Client(ctx, http.MethodGet, p.userEndpoint, version.UserAgent(), headers, nil, &response)
|
err := httputil.Do(ctx, http.MethodGet, p.userEndpoint, version.UserAgent(), headers, nil, &response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,7 +251,7 @@ func (p *Provider) Revoke(ctx context.Context, t *oauth2.Token) error {
|
||||||
params.Add("client_id", oa.ClientID)
|
params.Add("client_id", oa.ClientID)
|
||||||
params.Add("client_secret", oa.ClientSecret)
|
params.Add("client_secret", oa.ClientSecret)
|
||||||
|
|
||||||
err = httputil.Client(ctx, http.MethodPost, p.RevocationURL, version.UserAgent(), nil, params, nil)
|
err = httputil.Do(ctx, http.MethodPost, p.RevocationURL, version.UserAgent(), nil, params, nil)
|
||||||
if err != nil && errors.Is(err, httputil.ErrTokenRevoked) {
|
if err != nil && errors.Is(err, httputil.ErrTokenRevoked) {
|
||||||
return fmt.Errorf("internal/oidc: unexpected revoke error: %w", err)
|
return fmt.Errorf("internal/oidc: unexpected revoke error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ func (locker *Leaser) runOnce(ctx context.Context, resetBackoff func()) error {
|
||||||
resetBackoff()
|
resetBackoff()
|
||||||
leaseID := res.Id
|
leaseID := res.Id
|
||||||
|
|
||||||
log.Info(ctx).
|
log.Debug(ctx).
|
||||||
Str("lease_name", locker.leaseName).
|
Str("lease_name", locker.leaseName).
|
||||||
Str("lease_id", leaseID).
|
Str("lease_id", leaseID).
|
||||||
Msg("leaser: lease acquired")
|
Msg("leaser: lease acquired")
|
||||||
|
@ -136,7 +136,7 @@ func (locker *Leaser) withLease(ctx context.Context, leaseID string) error {
|
||||||
Duration: durationpb.New(locker.ttl),
|
Duration: durationpb.New(locker.ttl),
|
||||||
})
|
})
|
||||||
if status.Code(err) == codes.AlreadyExists {
|
if status.Code(err) == codes.AlreadyExists {
|
||||||
log.Info(ctx).
|
log.Debug(ctx).
|
||||||
Str("lease_name", locker.leaseName).
|
Str("lease_name", locker.leaseName).
|
||||||
Str("lease_id", leaseID).
|
Str("lease_id", leaseID).
|
||||||
Msg("leaser: lease lost")
|
Msg("leaser: lease lost")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue