mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-30 02:46:30 +02:00
Compare commits
13 commits
Author | SHA1 | Date | |
---|---|---|---|
|
9f591c0ac0 | ||
|
ed8c5d6999 | ||
|
c0848eecfe | ||
|
618ab8fe3f | ||
|
b139c4f425 | ||
|
dcb10b1727 | ||
|
839bedac80 | ||
|
cc22174159 | ||
|
a078f93986 | ||
|
98a5779d77 | ||
|
03064fae31 | ||
|
c8ad4c054d | ||
|
e23caa50cf |
99 changed files with 1530 additions and 1095 deletions
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
|||
- name: Set up Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 22.x
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/atomicutil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
|
|
@ -25,11 +25,11 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/middleware"
|
||||
"github.com/pomerium/pomerium/internal/sessions"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/identity"
|
||||
"github.com/pomerium/pomerium/pkg/identity/oidc"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// Handler returns the authenticate service's handler chain.
|
||||
|
@ -117,9 +117,6 @@ func (a *Authenticate) mountDashboard(r *mux.Router) {
|
|||
handlers.DeviceEnrolled(a.getUserInfoData(r)).ServeHTTP(w, r)
|
||||
return nil
|
||||
}))
|
||||
|
||||
cr := sr.PathPrefix("/callback").Subrouter()
|
||||
cr.Path("/").Handler(a.requireValidSignature(a.Callback)).Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
// RetrieveSession is the middleware used retrieve session by the sessionLoader
|
||||
|
@ -526,54 +523,6 @@ func (a *Authenticate) revokeSession(ctx context.Context, w http.ResponseWriter,
|
|||
return state.flow.RevokeSession(ctx, r, authenticator, sessionState)
|
||||
}
|
||||
|
||||
// Callback handles the result of a successful call to the authenticate service
|
||||
// and is responsible setting per-route sessions.
|
||||
func (a *Authenticate) Callback(w http.ResponseWriter, r *http.Request) error {
|
||||
redirectURLString := r.FormValue(urlutil.QueryRedirectURI)
|
||||
encryptedSession := r.FormValue(urlutil.QuerySessionEncrypted)
|
||||
|
||||
redirectURL, err := urlutil.ParseAndValidateURL(redirectURLString)
|
||||
if err != nil {
|
||||
return httputil.NewError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
rawJWT, err := a.saveCallbackSession(w, r, encryptedSession)
|
||||
if err != nil {
|
||||
return httputil.NewError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// if programmatic, encode the session jwt as a query param
|
||||
if isProgrammatic := r.FormValue(urlutil.QueryIsProgrammatic); isProgrammatic == "true" {
|
||||
q := redirectURL.Query()
|
||||
q.Set(urlutil.QueryPomeriumJWT, string(rawJWT))
|
||||
redirectURL.RawQuery = q.Encode()
|
||||
}
|
||||
httputil.Redirect(w, r, redirectURL.String(), http.StatusFound)
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveCallbackSession takes an encrypted per-route session token, decrypts
|
||||
// it using the shared service key, then stores it the local session store.
|
||||
func (a *Authenticate) saveCallbackSession(w http.ResponseWriter, r *http.Request, enctoken string) ([]byte, error) {
|
||||
state := a.state.Load()
|
||||
|
||||
// 1. extract the base64 encoded and encrypted JWT from query params
|
||||
encryptedJWT, err := base64.URLEncoding.DecodeString(enctoken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("proxy: malfromed callback token: %w", err)
|
||||
}
|
||||
// 2. decrypt the JWT using the cipher using the _shared_ secret key
|
||||
rawJWT, err := cryptutil.Decrypt(state.sharedCipher, encryptedJWT, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("proxy: callback token decrypt error: %w", err)
|
||||
}
|
||||
// 3. Save the decrypted JWT to the session store directly as a string, without resigning
|
||||
if err = state.sessionStore.SaveSession(w, r, rawJWT); err != nil {
|
||||
return nil, fmt.Errorf("proxy: callback session save failure: %w", err)
|
||||
}
|
||||
return rawJWT, nil
|
||||
}
|
||||
|
||||
func (a *Authenticate) getIdentityProviderIDForRequest(r *http.Request) string {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return ""
|
||||
|
|
|
@ -694,14 +694,6 @@ func (m mockDataBrokerServiceClient) Put(ctx context.Context, in *databroker.Put
|
|||
return m.put(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func mustParseURL(rawurl string) *url.URL {
|
||||
u, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// stubFlow is a stub implementation of the flow interface.
|
||||
type stubFlow struct {
|
||||
verifySignatureErr error
|
||||
|
|
|
@ -20,14 +20,3 @@ func (a *Authenticate) requireValidSignatureOnRedirect(next httputil.HandlerFunc
|
|||
return next(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// requireValidSignature validates the pomerium_signature.
|
||||
func (a *Authenticate) requireValidSignature(next httputil.HandlerFunc) http.Handler {
|
||||
return httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
err := a.state.Load().flow.VerifyAuthenticateSignature(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return next(w, r)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/atomicutil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/pomerium/pkg/storage"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// Authorize struct holds
|
||||
|
@ -149,6 +149,7 @@ func newPolicyEvaluator(
|
|||
evaluator.WithGoogleCloudServerlessAuthenticationServiceAccount(opts.GetGoogleCloudServerlessAuthenticationServiceAccount()),
|
||||
evaluator.WithJWTClaimsHeaders(opts.JWTClaimsHeaders),
|
||||
evaluator.WithJWTGroupsFilter(opts.JWTGroupsFilter),
|
||||
evaluator.WithDefaultJWTIssuerFormat(opts.JWTIssuerFormat),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ type evaluatorConfig struct {
|
|||
GoogleCloudServerlessAuthenticationServiceAccount string
|
||||
JWTClaimsHeaders config.JWTClaimHeaders
|
||||
JWTGroupsFilter config.JWTGroupsFilter
|
||||
DefaultJWTIssuerFormat config.JWTIssuerFormat
|
||||
}
|
||||
|
||||
// cacheKey() returns a hash over the configuration, except for the policies.
|
||||
|
@ -105,3 +106,10 @@ func WithJWTGroupsFilter(groups config.JWTGroupsFilter) Option {
|
|||
cfg.JWTGroupsFilter = groups
|
||||
}
|
||||
}
|
||||
|
||||
// WithDefaultJWTIssuerFormat sets the default JWT issuer format in the config.
|
||||
func WithDefaultJWTIssuerFormat(format config.JWTIssuerFormat) Option {
|
||||
return func(cfg *evaluatorConfig) {
|
||||
cfg.DefaultJWTIssuerFormat = format
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/errgrouputil"
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/contextutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/policy/criteria"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// Request contains the inputs needed for evaluation.
|
||||
|
@ -332,6 +332,7 @@ func updateStore(ctx context.Context, store *store.Store, cfg *evaluatorConfig)
|
|||
)
|
||||
store.UpdateJWTClaimHeaders(cfg.JWTClaimsHeaders)
|
||||
store.UpdateJWTGroupsFilter(cfg.JWTGroupsFilter)
|
||||
store.UpdateDefaultJWTIssuerFormat(cfg.DefaultJWTIssuerFormat)
|
||||
store.UpdateRoutePolicies(cfg.Policies)
|
||||
store.UpdateSigningKey(jwk)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/authorize/internal/store"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// HeadersResponse is the output from the headers.rego script.
|
||||
|
|
|
@ -247,18 +247,16 @@ func (e *headersEvaluatorEvaluation) getGroupIDs(ctx context.Context) []string {
|
|||
return make([]string, 0)
|
||||
}
|
||||
|
||||
func (e *headersEvaluatorEvaluation) getJWTPayloadIss() (string, error) {
|
||||
var issuerFormat string
|
||||
if e.request.Policy != nil {
|
||||
func (e *headersEvaluatorEvaluation) getJWTPayloadIss() string {
|
||||
issuerFormat := e.evaluator.store.GetDefaultJWTIssuerFormat()
|
||||
if e.request.Policy != nil && e.request.Policy.JWTIssuerFormat != "" {
|
||||
issuerFormat = e.request.Policy.JWTIssuerFormat
|
||||
}
|
||||
switch issuerFormat {
|
||||
case "uri":
|
||||
return fmt.Sprintf("https://%s/", e.request.HTTP.Hostname), nil
|
||||
case "", "hostOnly":
|
||||
return e.request.HTTP.Hostname, nil
|
||||
case config.JWTIssuerFormatURI:
|
||||
return fmt.Sprintf("https://%s/", e.request.HTTP.Hostname)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported JWT issuer format: %s", issuerFormat)
|
||||
return e.request.HTTP.Hostname
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,14 +410,9 @@ func (e *headersEvaluatorEvaluation) getJWTPayload(ctx context.Context) (map[str
|
|||
return e.cachedJWTPayload, nil
|
||||
}
|
||||
|
||||
iss, err := e.getJWTPayloadIss()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e.gotJWTPayload = true
|
||||
e.cachedJWTPayload = map[string]any{
|
||||
"iss": iss,
|
||||
"iss": e.getJWTPayloadIss(),
|
||||
"aud": e.getJWTPayloadAud(),
|
||||
"jti": e.getJWTPayloadJTI(),
|
||||
"iat": e.getJWTPayloadIAT(),
|
||||
|
|
|
@ -437,34 +437,59 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Equal(t, "u1@example.com", output.Headers.Get("X-Pomerium-Claim-Email"))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("issuer format", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestHeadersEvaluator_JWTIssuerFormat(t *testing.T) {
|
||||
privateJWK, _ := newJWK(t)
|
||||
|
||||
for _, tc := range []struct {
|
||||
format string
|
||||
input string
|
||||
output string
|
||||
store := store.New()
|
||||
store.UpdateSigningKey(privateJWK)
|
||||
|
||||
eval := func(_ *testing.T, input *Request) (*HeadersResponse, error) {
|
||||
ctx := context.Background()
|
||||
e := NewHeadersEvaluator(store)
|
||||
return e.Evaluate(ctx, input)
|
||||
}
|
||||
|
||||
hostname := "route.example.com"
|
||||
|
||||
cases := []struct {
|
||||
globalFormat config.JWTIssuerFormat
|
||||
routeFormat config.JWTIssuerFormat
|
||||
expected string
|
||||
}{
|
||||
{"", "example.com", "example.com"},
|
||||
{"hostOnly", "host-only.example.com", "host-only.example.com"},
|
||||
{"uri", "uri.example.com", "https://uri.example.com/"},
|
||||
} {
|
||||
{"", "", "route.example.com"},
|
||||
{"hostOnly", "", "route.example.com"},
|
||||
{"uri", "", "https://route.example.com/"},
|
||||
|
||||
{"", "hostOnly", "route.example.com"},
|
||||
{"hostOnly", "hostOnly", "route.example.com"},
|
||||
{"uri", "hostOnly", "route.example.com"},
|
||||
|
||||
{"", "uri", "https://route.example.com/"},
|
||||
{"hostOnly", "uri", "https://route.example.com/"},
|
||||
{"uri", "uri", "https://route.example.com/"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run("", func(t *testing.T) {
|
||||
store.UpdateDefaultJWTIssuerFormat(tc.globalFormat)
|
||||
output, err := eval(t,
|
||||
nil,
|
||||
&Request{
|
||||
HTTP: RequestHTTP{
|
||||
Hostname: tc.input,
|
||||
Hostname: hostname,
|
||||
},
|
||||
Policy: &config.Policy{
|
||||
JWTIssuerFormat: tc.format,
|
||||
JWTIssuerFormat: tc.routeFormat,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
m := decodeJWTAssertion(t, output.Headers)
|
||||
assert.Equal(t, tc.output, m["iss"], "unexpected issuer for format=%s", tc.format)
|
||||
}
|
||||
assert.Equal(t, tc.expected, m["iss"],
|
||||
"unexpected issuer for global format=%q, route format=%q",
|
||||
tc.globalFormat, tc.routeFormat)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadersEvaluator_JWTGroupsFilter(t *testing.T) {
|
||||
|
|
|
@ -11,11 +11,11 @@ import (
|
|||
"github.com/pomerium/pomerium/authorize/internal/store"
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/contextutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/policy"
|
||||
"github.com/pomerium/pomerium/pkg/policy/criteria"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// PolicyRequest is the input to policy evaluation.
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -54,8 +55,11 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
|
|||
|
||||
// load the session
|
||||
s, err := a.loadSession(ctx, hreq, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if errors.Is(err, sessions.ErrInvalidSession) {
|
||||
// ENG-2172: if this is an invalid session, don't evaluate policy, return forbidden
|
||||
return a.deniedResponse(ctx, in, int32(http.StatusForbidden), http.StatusText(http.StatusForbidden), nil)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("error loading session: %w", err)
|
||||
}
|
||||
|
||||
// if there's a session or service account, load the user
|
||||
|
@ -122,6 +126,7 @@ func (a *Authorize) loadSession(
|
|||
Str("request-id", requestID).
|
||||
Err(err).
|
||||
Msg("error creating session for incoming idp token")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessionState, _ := a.state.Load().sessionStore.LoadSessionStateAndCheckIDP(hreq)
|
||||
|
|
|
@ -21,9 +21,9 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/pomerium/pkg/storage"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// A Store stores data for the OPA rego policy evaluation.
|
||||
|
@ -33,6 +33,7 @@ type Store struct {
|
|||
googleCloudServerlessAuthenticationServiceAccount atomic.Pointer[string]
|
||||
jwtClaimHeaders atomic.Pointer[map[string]string]
|
||||
jwtGroupsFilter atomic.Pointer[config.JWTGroupsFilter]
|
||||
defaultJWTIssuerFormat atomic.Pointer[config.JWTIssuerFormat]
|
||||
signingKey atomic.Pointer[jose.JSONWebKey]
|
||||
}
|
||||
|
||||
|
@ -66,6 +67,13 @@ func (s *Store) GetJWTGroupsFilter() config.JWTGroupsFilter {
|
|||
return config.JWTGroupsFilter{}
|
||||
}
|
||||
|
||||
func (s *Store) GetDefaultJWTIssuerFormat() config.JWTIssuerFormat {
|
||||
if f := s.defaultJWTIssuerFormat.Load(); f != nil {
|
||||
return *f
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *Store) GetSigningKey() *jose.JSONWebKey {
|
||||
return s.signingKey.Load()
|
||||
}
|
||||
|
@ -89,6 +97,12 @@ func (s *Store) UpdateJWTGroupsFilter(groups config.JWTGroupsFilter) {
|
|||
s.jwtGroupsFilter.Store(&groups)
|
||||
}
|
||||
|
||||
// UpdateDefaultJWTIssuerFormat updates the JWT groups filter in the store.
|
||||
func (s *Store) UpdateDefaultJWTIssuerFormat(format config.JWTIssuerFormat) {
|
||||
// This isn't used by the Rego code, so we don't need to write it to the opastorage.Store instance.
|
||||
s.defaultJWTIssuerFormat.Store(&format)
|
||||
}
|
||||
|
||||
// UpdateRoutePolicies updates the route policies in the store.
|
||||
func (s *Store) UpdateRoutePolicies(routePolicies []*config.Policy) {
|
||||
s.write("/route_policies", routePolicies)
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
_ "github.com/pomerium/pomerium/internal/zero/bootstrap/writers/filesystem"
|
||||
_ "github.com/pomerium/pomerium/internal/zero/bootstrap/writers/k8s"
|
||||
zero_cmd "github.com/pomerium/pomerium/internal/zero/cmd"
|
||||
"github.com/pomerium/pomerium/pkg/cmd/pomerium"
|
||||
"github.com/pomerium/pomerium/pkg/envoy/files"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/hashutil"
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
||||
"github.com/pomerium/pomerium/pkg/policy/parser"
|
||||
)
|
||||
|
||||
|
@ -617,3 +618,50 @@ func (f JWTGroupsFilter) Equal(other JWTGroupsFilter) bool {
|
|||
}
|
||||
return f.set.Equal(other.set)
|
||||
}
|
||||
|
||||
type JWTIssuerFormat string
|
||||
|
||||
const (
|
||||
JWTIssuerFormatUnset JWTIssuerFormat = ""
|
||||
JWTIssuerFormatHostOnly JWTIssuerFormat = "hostOnly"
|
||||
JWTIssuerFormatURI JWTIssuerFormat = "uri"
|
||||
)
|
||||
|
||||
var knownJWTIssuerFormats = map[JWTIssuerFormat]struct{}{
|
||||
JWTIssuerFormatUnset: {},
|
||||
JWTIssuerFormatHostOnly: {},
|
||||
JWTIssuerFormatURI: {},
|
||||
}
|
||||
|
||||
func JWTIssuerFormatFromPB(format *configpb.IssuerFormat) JWTIssuerFormat {
|
||||
if format == nil {
|
||||
return JWTIssuerFormatUnset
|
||||
}
|
||||
|
||||
switch *format {
|
||||
case configpb.IssuerFormat_IssuerHostOnly:
|
||||
return JWTIssuerFormatHostOnly
|
||||
case configpb.IssuerFormat_IssuerURI:
|
||||
return JWTIssuerFormatURI
|
||||
default:
|
||||
return JWTIssuerFormatUnset
|
||||
}
|
||||
}
|
||||
|
||||
func (f JWTIssuerFormat) ToPB() *configpb.IssuerFormat {
|
||||
switch f {
|
||||
case JWTIssuerFormatUnset:
|
||||
return nil
|
||||
case JWTIssuerFormatHostOnly:
|
||||
return configpb.IssuerFormat_IssuerHostOnly.Enum()
|
||||
case JWTIssuerFormatURI:
|
||||
return configpb.IssuerFormat_IssuerURI.Enum()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (f JWTIssuerFormat) Valid() bool {
|
||||
_, ok := knownJWTIssuerFormats[f]
|
||||
return ok
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
func TestBuilder_buildACMETLSALPNCluster(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil, true)
|
||||
testutil.AssertProtoJSONEqual(t,
|
||||
`{
|
||||
"name": "pomerium-acme-tls-alpn",
|
||||
|
@ -34,7 +34,7 @@ func TestBuilder_buildACMETLSALPNCluster(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuilder_buildACMETLSALPNFilterChain(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil, true)
|
||||
testutil.AssertProtoJSONEqual(t,
|
||||
`{
|
||||
"filterChainMatch": {
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/config/otelconfig"
|
||||
"github.com/pomerium/pomerium/internal/telemetry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
func TestBuilder_BuildBootstrapAdmin(t *testing.T) {
|
||||
t.Setenv("TMPDIR", "/tmp")
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
adminCfg, err := b.BuildBootstrapAdmin(&config.Config{
|
||||
Options: &config.Options{
|
||||
|
@ -35,7 +35,7 @@ func TestBuilder_BuildBootstrapAdmin(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuilder_BuildBootstrapLayeredRuntime(t *testing.T) {
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil)
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil, true)
|
||||
staticCfg, err := b.BuildBootstrapLayeredRuntime(context.Background(), &config.Config{})
|
||||
assert.NoError(t, err)
|
||||
testutil.AssertProtoJSONEqual(t, `
|
||||
|
@ -61,7 +61,7 @@ func TestBuilder_BuildBootstrapLayeredRuntime(t *testing.T) {
|
|||
|
||||
func TestBuilder_BuildBootstrapStaticResources(t *testing.T) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil)
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil, true)
|
||||
staticCfg, err := b.BuildBootstrapStaticResources(context.Background(), &config.Config{}, false)
|
||||
assert.NoError(t, err)
|
||||
testutil.AssertProtoJSONEqual(t, `
|
||||
|
@ -105,14 +105,14 @@ func TestBuilder_BuildBootstrapStaticResources(t *testing.T) {
|
|||
`, staticCfg)
|
||||
})
|
||||
t.Run("bad gRPC address", func(t *testing.T) {
|
||||
b := New("xyz:zyx", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil)
|
||||
b := New("xyz:zyx", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil, true)
|
||||
_, err := b.BuildBootstrapStaticResources(context.Background(), &config.Config{}, false)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilder_BuildBootstrapStatsConfig(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
statsCfg, err := b.BuildBootstrapStatsConfig(&config.Config{
|
||||
Options: &config.Options{
|
||||
|
@ -132,7 +132,7 @@ func TestBuilder_BuildBootstrapStatsConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuilder_BuildBootstrap(t *testing.T) {
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil)
|
||||
b := New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil, true)
|
||||
t.Run("OverloadManager", func(t *testing.T) {
|
||||
bootstrap, err := b.BuildBootstrap(context.Background(), &config.Config{
|
||||
Options: &config.Options{
|
||||
|
|
|
@ -12,6 +12,7 @@ type Builder struct {
|
|||
localMetricsAddress string
|
||||
filemgr *filemgr.Manager
|
||||
reproxy *reproxy.Handler
|
||||
addIPV6InternalRanges bool
|
||||
}
|
||||
|
||||
// New creates a new Builder.
|
||||
|
@ -21,6 +22,7 @@ func New(
|
|||
localMetricsAddress string,
|
||||
fileManager *filemgr.Manager,
|
||||
reproxyHandler *reproxy.Handler,
|
||||
addIPV6InternalRanges bool,
|
||||
) *Builder {
|
||||
if reproxyHandler == nil {
|
||||
reproxyHandler = reproxy.New()
|
||||
|
@ -31,5 +33,6 @@ func New(
|
|||
localMetricsAddress: localMetricsAddress,
|
||||
filemgr: fileManager,
|
||||
reproxy: reproxyHandler,
|
||||
addIPV6InternalRanges: addIPV6InternalRanges,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// BuildClusters builds envoy clusters from the given config.
|
||||
|
|
|
@ -27,7 +27,7 @@ func Test_BuildClusters(t *testing.T) {
|
|||
|
||||
opts := config.NewDefaultOptions()
|
||||
ctx := context.Background()
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
clusters, err := b.BuildClusters(ctx, &config.Config{Options: opts})
|
||||
require.NoError(t, err)
|
||||
testutil.AssertProtoJSONFileEqual(t, "testdata/clusters.json", clusters)
|
||||
|
@ -38,7 +38,7 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
|||
cacheDir, _ := os.UserCacheDir()
|
||||
customCA := filepath.Join(cacheDir, "pomerium", "envoy", "files", "custom-ca-3133535332543131503345494c.pem")
|
||||
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
rootCABytes, _ := getCombinedCertificateAuthority(ctx, &config.Config{Options: &config.Options{}})
|
||||
rootCA := b.filemgr.BytesDataSource("ca.pem", rootCABytes).GetFilename()
|
||||
|
||||
|
@ -517,7 +517,7 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
|||
|
||||
func Test_buildCluster(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
rootCABytes, _ := getCombinedCertificateAuthority(ctx, &config.Config{Options: &config.Options{}})
|
||||
rootCA := b.filemgr.BytesDataSource("ca.pem", rootCABytes).GetFilename()
|
||||
o1 := config.NewDefaultOptions()
|
||||
|
@ -1012,7 +1012,7 @@ func Test_bindConfig(t *testing.T) {
|
|||
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer clearTimeout()
|
||||
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
t.Run("no bind config", func(t *testing.T) {
|
||||
cluster, err := b.buildPolicyCluster(ctx, &config.Config{Options: &config.Options{}}, &config.Policy{
|
||||
From: "https://from.example.com",
|
||||
|
|
|
@ -44,10 +44,10 @@ func ExtAuthzFilter(grpcClientTimeout *durationpb.Duration) *envoy_extensions_fi
|
|||
}
|
||||
|
||||
// HTTPConnectionManagerFilter creates a new HTTP connection manager filter.
|
||||
func HTTPConnectionManagerFilter(
|
||||
func (b *Builder) HTTPConnectionManagerFilter(
|
||||
httpConnectionManager *envoy_extensions_filters_network_http_connection_manager.HttpConnectionManager,
|
||||
) *envoy_config_listener_v3.Filter {
|
||||
applyGlobalHTTPConnectionManagerOptions(httpConnectionManager)
|
||||
b.applyGlobalHTTPConnectionManagerOptions(httpConnectionManager)
|
||||
return &envoy_config_listener_v3.Filter{
|
||||
Name: "envoy.filters.network.http_connection_manager",
|
||||
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
||||
|
|
|
@ -128,23 +128,29 @@ func (b *Builder) buildLocalReplyConfig(
|
|||
}, nil
|
||||
}
|
||||
|
||||
func applyGlobalHTTPConnectionManagerOptions(hcm *envoy_http_connection_manager.HttpConnectionManager) {
|
||||
func (b *Builder) applyGlobalHTTPConnectionManagerOptions(hcm *envoy_http_connection_manager.HttpConnectionManager) {
|
||||
if hcm.InternalAddressConfig == nil {
|
||||
// see doc comment on InternalAddressConfig for details
|
||||
hcm.InternalAddressConfig = &envoy_http_connection_manager.HttpConnectionManager_InternalAddressConfig{
|
||||
CidrRanges: []*envoy_config_core_v3.CidrRange{
|
||||
ranges := []*envoy_config_core_v3.CidrRange{
|
||||
// localhost
|
||||
{AddressPrefix: "127.0.0.1", PrefixLen: wrapperspb.UInt32(32)},
|
||||
{AddressPrefix: "::1", PrefixLen: wrapperspb.UInt32(128)},
|
||||
|
||||
// RFC1918
|
||||
{AddressPrefix: "10.0.0.0", PrefixLen: wrapperspb.UInt32(8)},
|
||||
{AddressPrefix: "192.168.0.0", PrefixLen: wrapperspb.UInt32(16)},
|
||||
{AddressPrefix: "172.16.0.0", PrefixLen: wrapperspb.UInt32(12)},
|
||||
|
||||
}
|
||||
if b.addIPV6InternalRanges {
|
||||
ranges = append(ranges, []*envoy_config_core_v3.CidrRange{
|
||||
// Localhost IPv6
|
||||
{AddressPrefix: "::1", PrefixLen: wrapperspb.UInt32(128)},
|
||||
// RFC4193
|
||||
{AddressPrefix: "fd00::", PrefixLen: wrapperspb.UInt32(8)},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
// see doc comment on InternalAddressConfig for details
|
||||
hcm.InternalAddressConfig = &envoy_http_connection_manager.HttpConnectionManager_InternalAddressConfig{
|
||||
CidrRanges: ranges,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
const listenerBufferLimit uint32 = 32 * 1024
|
||||
|
|
|
@ -51,7 +51,7 @@ func (b *Builder) buildEnvoyAdminHTTPConnectionManagerFilter() *envoy_config_lis
|
|||
},
|
||||
}})
|
||||
|
||||
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
return b.HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||
StatPrefix: "envoy-admin",
|
||||
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
||||
|
|
|
@ -98,7 +98,7 @@ func (b *Builder) buildGRPCHTTPConnectionManagerFilter() *envoy_config_listener_
|
|||
Routes: routes,
|
||||
}})
|
||||
|
||||
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
return b.HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||
StatPrefix: "grpc_ingress",
|
||||
// limit request first byte to last byte time
|
||||
|
|
|
@ -207,9 +207,6 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter(
|
|||
mgr.CodecType = envoy_extensions_filters_network_http_connection_manager.HttpConnectionManager_AUTO
|
||||
} else if cfg.Options.GetCodecType() == config.CodecTypeAuto || cfg.Options.GetCodecType() == config.CodecTypeHTTP2 {
|
||||
mgr.CodecType = cfg.Options.GetCodecType().ToEnvoy()
|
||||
mgr.Http2ProtocolOptions = &envoy_config_core_v3.Http2ProtocolOptions{
|
||||
AllowConnect: true,
|
||||
}
|
||||
} else {
|
||||
mgr.CodecType = cfg.Options.GetCodecType().ToEnvoy()
|
||||
}
|
||||
|
@ -236,7 +233,7 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter(
|
|||
}
|
||||
}
|
||||
|
||||
return HTTPConnectionManagerFilter(mgr), nil
|
||||
return b.HTTPConnectionManagerFilter(mgr), nil
|
||||
}
|
||||
|
||||
func newListenerAccessLog() *envoy_config_accesslog_v3.AccessLog {
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func Test_requireProxyProtocol(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil, true)
|
||||
t.Run("required", func(t *testing.T) {
|
||||
li, err := b.buildMainListener(context.Background(), &config.Config{Options: &config.Options{
|
||||
UseProxyProtocol: true,
|
||||
|
|
|
@ -121,7 +121,7 @@ func (b *Builder) buildMetricsHTTPConnectionManagerFilter() *envoy_config_listen
|
|||
},
|
||||
}})
|
||||
|
||||
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
return b.HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||
StatPrefix: "metrics",
|
||||
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
||||
|
|
|
@ -51,7 +51,7 @@ func TestBuildListeners(t *testing.T) {
|
|||
OutboundPort: "10003",
|
||||
MetricsPort: "10004",
|
||||
}
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
t.Run("enable grpc by default", func(t *testing.T) {
|
||||
cfg := cfg.Clone()
|
||||
lis, err := b.BuildListeners(ctx, cfg, false)
|
||||
|
@ -125,7 +125,7 @@ func Test_buildMetricsHTTPConnectionManagerFilter(t *testing.T) {
|
|||
certFileName := filepath.Join(cacheDir, "pomerium", "envoy", "files", "tls-crt-5a353247453159375849565a.pem")
|
||||
keyFileName := filepath.Join(cacheDir, "pomerium", "envoy", "files", "tls-key-3159554e32473758435257364b.pem")
|
||||
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
li, err := b.buildMetricsListener(&config.Config{
|
||||
Options: &config.Options{
|
||||
MetricsAddr: "127.0.0.1:9902",
|
||||
|
@ -143,7 +143,7 @@ func Test_buildMetricsHTTPConnectionManagerFilter(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil, true)
|
||||
|
||||
options := config.NewDefaultOptions()
|
||||
options.SkipXffAppend = true
|
||||
|
|
|
@ -42,7 +42,7 @@ func (b *Builder) buildOutboundListener(cfg *config.Config) (*envoy_config_liste
|
|||
func (b *Builder) buildOutboundHTTPConnectionManager() *envoy_config_listener_v3.Filter {
|
||||
rc := b.buildOutboundRouteConfiguration()
|
||||
|
||||
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
return b.HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||
StatPrefix: "grpc_egress",
|
||||
// limit request first byte to last byte time
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func Test_buildOutboundRoutes(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", nil, nil, true)
|
||||
routes := b.buildOutboundRoutes()
|
||||
testutil.AssertProtoJSONEqual(t, `[
|
||||
{
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// BuildRouteConfigurations builds the route configurations for the RDS service.
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}}
|
||||
b := New("grpc", "http", "metrics", filemgr.NewManager(), nil)
|
||||
b := New("grpc", "http", "metrics", filemgr.NewManager(), nil, true)
|
||||
routeConfiguration, err := b.buildMainRouteConfiguration(ctx, cfg)
|
||||
assert.NoError(t, err)
|
||||
testutil.AssertProtoJSONEqual(t, `{
|
||||
|
|
|
@ -113,9 +113,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"http2ProtocolOptions": {
|
||||
"allowConnect": true
|
||||
},
|
||||
"localReplyConfig": {
|
||||
"mappers": [
|
||||
{
|
||||
|
@ -234,10 +231,6 @@
|
|||
"addressPrefix": "127.0.0.1",
|
||||
"prefixLen": 32
|
||||
},
|
||||
{
|
||||
"addressPrefix": "::1",
|
||||
"prefixLen": 128
|
||||
},
|
||||
{
|
||||
"addressPrefix": "10.0.0.0",
|
||||
"prefixLen": 8
|
||||
|
@ -250,6 +243,10 @@
|
|||
"addressPrefix": "172.16.0.0",
|
||||
"prefixLen": 12
|
||||
},
|
||||
{
|
||||
"addressPrefix": "::1",
|
||||
"prefixLen": 128
|
||||
},
|
||||
{
|
||||
"addressPrefix": "fd00::",
|
||||
"prefixLen": 8
|
||||
|
|
|
@ -61,10 +61,6 @@
|
|||
"addressPrefix": "127.0.0.1",
|
||||
"prefixLen": 32
|
||||
},
|
||||
{
|
||||
"addressPrefix": "::1",
|
||||
"prefixLen": 128
|
||||
},
|
||||
{
|
||||
"addressPrefix": "10.0.0.0",
|
||||
"prefixLen": 8
|
||||
|
@ -77,6 +73,10 @@
|
|||
"addressPrefix": "172.16.0.0",
|
||||
"prefixLen": 12
|
||||
},
|
||||
{
|
||||
"addressPrefix": "::1",
|
||||
"prefixLen": 128
|
||||
},
|
||||
{
|
||||
"addressPrefix": "fd00::",
|
||||
"prefixLen": 8
|
||||
|
|
|
@ -82,7 +82,7 @@ func TestValidateCertificate(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_buildDownstreamTLSContext(t *testing.T) {
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil)
|
||||
b := New("local-grpc", "local-http", "local-metrics", filemgr.NewManager(), nil, true)
|
||||
|
||||
cacheDir, _ := os.UserCacheDir()
|
||||
clientCAFileName := filepath.Join(cacheDir, "pomerium", "envoy", "files", "client-ca-4e4c564e5a36544a4a33385a.pem")
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
extensions_uuidx "github.com/pomerium/envoy-custom/api/extensions/request_id/uuidx"
|
||||
extensions_pomerium_otel "github.com/pomerium/envoy-custom/api/extensions/tracers/pomerium_otel"
|
||||
"github.com/pomerium/pomerium/config/otelconfig"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/middleware"
|
||||
"github.com/pomerium/pomerium/internal/telemetry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||
metrics_const "github.com/pomerium/pomerium/pkg/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -96,12 +97,17 @@ func (mgr *MetricsManager) updateServer(ctx context.Context, cfg *Config) {
|
|||
return
|
||||
}
|
||||
|
||||
var labels map[string]string
|
||||
if cfg.Options.IsRuntimeFlagSet(RuntimeFlagAddExtraMetricsLabels) {
|
||||
labels = getCommonLabels(mgr.installationID)
|
||||
}
|
||||
|
||||
mgr.endpoints = append(cfg.MetricsScrapeEndpoints,
|
||||
MetricsScrapeEndpoint{
|
||||
Name: "envoy",
|
||||
URL: url.URL{Scheme: "http", Host: cfg.Options.MetricsAddr, Path: "/metrics/envoy"},
|
||||
})
|
||||
handler, err := metrics.PrometheusHandler(toInternalEndpoints(mgr.endpoints), mgr.installationID, defaultMetricsTimeout)
|
||||
handler, err := metrics.PrometheusHandler(toInternalEndpoints(mgr.endpoints), defaultMetricsTimeout, labels)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Err(err).Msg("metrics: failed to create prometheus handler")
|
||||
return
|
||||
|
@ -128,3 +134,17 @@ func toInternalEndpoints(src []MetricsScrapeEndpoint) []metrics.ScrapeEndpoint {
|
|||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func getCommonLabels(installationID string) map[string]string {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
hostname = "__none__"
|
||||
}
|
||||
m := map[string]string{
|
||||
metrics_const.HostnameLabel: hostname,
|
||||
}
|
||||
if installationID != "" {
|
||||
m[metrics_const.InstallationIDLabel] = installationID
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
|
|
@ -196,6 +196,12 @@ type Options struct {
|
|||
// List of JWT claims to insert as x-pomerium-claim-* headers on proxied requests
|
||||
JWTClaimsHeaders JWTClaimHeaders `mapstructure:"jwt_claims_headers" yaml:"jwt_claims_headers,omitempty"`
|
||||
|
||||
// JWTIssuerFormat controls the default format of the 'iss' claim in JWTs passed to upstream services.
|
||||
// Possible values:
|
||||
// - "hostOnly" (default): Issuer strings will be the hostname of the route, with no scheme or trailing slash.
|
||||
// - "uri": Issuer strings will be a complete URI, including the scheme and ending with a trailing slash.
|
||||
JWTIssuerFormat JWTIssuerFormat `mapstructure:"jwt_issuer_format" yaml:"jwt_issuer_format,omitempty"`
|
||||
|
||||
// BearerTokenFormat indicates how authorization bearer tokens are interepreted. Possible values:
|
||||
// - "default": Only Bearer tokens prefixed with Pomerium- will be interpreted by Pomerium.
|
||||
// - "idp_access_token": The Bearer token will be interpreted as an IdP access token.
|
||||
|
@ -761,6 +767,10 @@ func (o *Options) Validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if !o.JWTIssuerFormat.Valid() {
|
||||
return fmt.Errorf("config: unsupported jwt_issuer_format value %q", o.JWTIssuerFormat)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1499,8 +1509,6 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
|
|||
if settings.IdpAccessTokenAllowedAudiences != nil {
|
||||
values := slices.Clone(settings.IdpAccessTokenAllowedAudiences.Values)
|
||||
o.IDPAccessTokenAllowedAudiences = &values
|
||||
} else {
|
||||
o.IDPAccessTokenAllowedAudiences = nil
|
||||
}
|
||||
setSlice(&o.AuthorizeURLStrings, settings.AuthorizeServiceUrls)
|
||||
set(&o.AuthorizeInternalURLString, settings.AuthorizeInternalServiceUrl)
|
||||
|
@ -1510,10 +1518,13 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
|
|||
set(&o.SigningKey, settings.SigningKey)
|
||||
setMap(&o.SetResponseHeaders, settings.SetResponseHeaders)
|
||||
setMap(&o.JWTClaimsHeaders, settings.JwtClaimsHeaders)
|
||||
o.BearerTokenFormat = BearerTokenFormatFromPB(settings.BearerTokenFormat)
|
||||
setOptional(&o.BearerTokenFormat, BearerTokenFormatFromPB(settings.BearerTokenFormat))
|
||||
if len(settings.JwtGroupsFilter) > 0 {
|
||||
o.JWTGroupsFilter = NewJWTGroupsFilter(settings.JwtGroupsFilter)
|
||||
}
|
||||
if f := JWTIssuerFormatFromPB(settings.JwtIssuerFormat); f != JWTIssuerFormatUnset {
|
||||
o.JWTIssuerFormat = f
|
||||
}
|
||||
setDuration(&o.DefaultUpstreamTimeout, settings.DefaultUpstreamTimeout)
|
||||
set(&o.MetricsAddr, settings.MetricsAddress)
|
||||
set(&o.MetricsBasicAuth, settings.MetricsBasicAuth)
|
||||
|
@ -1624,6 +1635,7 @@ func (o *Options) ToProto() *config.Config {
|
|||
settings.JwtClaimsHeaders = o.JWTClaimsHeaders
|
||||
settings.BearerTokenFormat = o.BearerTokenFormat.ToPB()
|
||||
settings.JwtGroupsFilter = o.JWTGroupsFilter.ToSlice()
|
||||
settings.JwtIssuerFormat = o.JWTIssuerFormat.ToPB()
|
||||
copyOptionalDuration(&settings.DefaultUpstreamTimeout, o.DefaultUpstreamTimeout)
|
||||
copySrcToOptionalDest(&settings.MetricsAddress, &o.MetricsAddr)
|
||||
copySrcToOptionalDest(&settings.MetricsBasicAuth, &o.MetricsBasicAuth)
|
||||
|
|
|
@ -924,6 +924,8 @@ func TestOptions_GetAllRouteableHTTPHosts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOptions_ApplySettings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second)
|
||||
defer clearTimeout()
|
||||
|
||||
|
@ -989,6 +991,48 @@ func TestOptions_ApplySettings(t *testing.T) {
|
|||
})
|
||||
assert.Equal(t, NewJWTGroupsFilter([]string{"quux", "zulu"}), options.JWTGroupsFilter)
|
||||
})
|
||||
|
||||
t.Run("jwt_issuer_format", func(t *testing.T) {
|
||||
options := NewDefaultOptions()
|
||||
assert.Equal(t, JWTIssuerFormatUnset, options.JWTIssuerFormat)
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{
|
||||
JwtIssuerFormat: configpb.IssuerFormat_IssuerURI.Enum(),
|
||||
})
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{})
|
||||
assert.Equal(t, JWTIssuerFormatURI, options.JWTIssuerFormat)
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{
|
||||
JwtIssuerFormat: configpb.IssuerFormat_IssuerHostOnly.Enum(),
|
||||
})
|
||||
assert.Equal(t, JWTIssuerFormatHostOnly, options.JWTIssuerFormat)
|
||||
})
|
||||
|
||||
t.Run("bearer_token_format", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
options := NewDefaultOptions()
|
||||
assert.Nil(t, options.BearerTokenFormat)
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{
|
||||
BearerTokenFormat: configpb.BearerTokenFormat_BEARER_TOKEN_FORMAT_DEFAULT.Enum(),
|
||||
})
|
||||
assert.Equal(t, ptr(BearerTokenFormatDefault), options.BearerTokenFormat)
|
||||
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{})
|
||||
assert.Equal(t, ptr(BearerTokenFormatDefault), options.BearerTokenFormat, "should preserve existing bearer token format")
|
||||
})
|
||||
|
||||
t.Run("idp_access_token_allowed_audiences", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
options := NewDefaultOptions()
|
||||
assert.Nil(t, options.IDPAccessTokenAllowedAudiences)
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{
|
||||
IdpAccessTokenAllowedAudiences: &configpb.Settings_StringList{Values: []string{"x", "y", "z"}},
|
||||
})
|
||||
assert.Equal(t, ptr([]string{"x", "y", "z"}), options.IDPAccessTokenAllowedAudiences)
|
||||
options.ApplySettings(ctx, nil, &configpb.Settings{})
|
||||
assert.Equal(t, ptr([]string{"x", "y", "z"}), options.IDPAccessTokenAllowedAudiences,
|
||||
"should preserve idp access token allowed audiences")
|
||||
})
|
||||
}
|
||||
|
||||
func TestOptions_GetSetResponseHeaders(t *testing.T) {
|
||||
|
@ -1748,3 +1792,7 @@ func must[T any](t T, err error) T {
|
|||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ type Policy struct {
|
|||
// Possible values:
|
||||
// - "hostOnly" (default): Issuer strings will be the hostname of the route, with no scheme or trailing slash.
|
||||
// - "uri": Issuer strings will be a complete URI, including the scheme and ending with a trailing slash.
|
||||
JWTIssuerFormat string `mapstructure:"jwt_issuer_format" yaml:"jwt_issuer_format,omitempty"`
|
||||
JWTIssuerFormat JWTIssuerFormat `mapstructure:"jwt_issuer_format" yaml:"jwt_issuer_format,omitempty"`
|
||||
// BearerTokenFormat indicates how authorization bearer tokens are interepreted. Possible values:
|
||||
// - "default": Only Bearer tokens prefixed with Pomerium- will be interpreted by Pomerium
|
||||
// - "idp_access_token": The Bearer token will be interpreted as an IdP access token.
|
||||
|
@ -309,6 +309,7 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
|||
IDPClientID: pb.GetIdpClientId(),
|
||||
IDPClientSecret: pb.GetIdpClientSecret(),
|
||||
JWTGroupsFilter: NewJWTGroupsFilter(pb.JwtGroupsFilter),
|
||||
JWTIssuerFormat: JWTIssuerFormatFromPB(pb.JwtIssuerFormat),
|
||||
KubernetesServiceAccountToken: pb.GetKubernetesServiceAccountToken(),
|
||||
KubernetesServiceAccountTokenFile: pb.GetKubernetesServiceAccountTokenFile(),
|
||||
LogoURL: pb.GetLogoUrl(),
|
||||
|
@ -388,13 +389,6 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
|||
p.EnvoyOpts.Name = pb.Name
|
||||
}
|
||||
|
||||
switch pb.GetJwtIssuerFormat() {
|
||||
case configpb.IssuerFormat_IssuerHostOnly:
|
||||
p.JWTIssuerFormat = "hostOnly"
|
||||
case configpb.IssuerFormat_IssuerURI:
|
||||
p.JWTIssuerFormat = "uri"
|
||||
}
|
||||
|
||||
p.BearerTokenFormat = BearerTokenFormatFromPB(pb.BearerTokenFormat)
|
||||
|
||||
for _, rwh := range pb.RewriteResponseHeaders {
|
||||
|
@ -468,6 +462,7 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
|
|||
Id: p.ID,
|
||||
IdleTimeout: idleTimeout,
|
||||
JwtGroupsFilter: p.JWTGroupsFilter.ToSlice(),
|
||||
JwtIssuerFormat: p.JWTIssuerFormat.ToPB(),
|
||||
KubernetesServiceAccountToken: p.KubernetesServiceAccountToken,
|
||||
KubernetesServiceAccountTokenFile: p.KubernetesServiceAccountTokenFile,
|
||||
LogoUrl: p.LogoURL,
|
||||
|
@ -555,13 +550,6 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
|
|||
pb.LoadBalancingWeights = weights
|
||||
}
|
||||
|
||||
switch p.JWTIssuerFormat {
|
||||
case "", "hostOnly":
|
||||
pb.JwtIssuerFormat = configpb.IssuerFormat_IssuerHostOnly
|
||||
case "uri":
|
||||
pb.JwtIssuerFormat = configpb.IssuerFormat_IssuerURI
|
||||
}
|
||||
|
||||
pb.BearerTokenFormat = p.BearerTokenFormat.ToPB()
|
||||
|
||||
for _, rwh := range p.RewriteResponseHeaders {
|
||||
|
@ -698,6 +686,10 @@ func (p *Policy) Validate() error {
|
|||
p.compiledRegex, _ = regexp.Compile(rawRE)
|
||||
}
|
||||
|
||||
if !p.JWTIssuerFormat.Valid() {
|
||||
return fmt.Errorf("config: unsupported jwt_issuer_format value %q", p.JWTIssuerFormat)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -292,6 +292,22 @@ func TestPolicy_FromToPb(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, p.Redirect.HTTPSRedirect, policyFromProto.Redirect.HTTPSRedirect)
|
||||
})
|
||||
|
||||
t.Run("JWT issuer format", func(t *testing.T) {
|
||||
for f := range knownJWTIssuerFormats {
|
||||
p := &Policy{
|
||||
From: "https://pomerium.io",
|
||||
To: mustParseWeightedURLs(t, "http://localhost"),
|
||||
JWTIssuerFormat: f,
|
||||
}
|
||||
pbPolicy, err := p.ToProto()
|
||||
require.NoError(t, err)
|
||||
|
||||
policyFromPb, err := NewPolicyFromProto(pbPolicy)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, f, policyFromPb.JWTIssuerFormat)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicy_Matches(t *testing.T) {
|
||||
|
|
|
@ -25,6 +25,9 @@ var (
|
|||
// is deprecated pending removal in a future release, but this flag allows a temporary
|
||||
// opt-out from the deprecation.
|
||||
RuntimeFlagPomeriumJWTEndpoint = runtimeFlag("pomerium_jwt_endpoint", false)
|
||||
|
||||
// RuntimeFlagAddExtraMetricsLabels enables adding extra labels to metrics (host and installation id)
|
||||
RuntimeFlagAddExtraMetricsLabels = runtimeFlag("add_extra_metrics_labels", true)
|
||||
)
|
||||
|
||||
// RuntimeFlag is a runtime flag that can flip on/off certain features
|
||||
|
|
|
@ -202,7 +202,7 @@ func (c *incomingIDPTokenSessionCreator) createSessionAccessToken(
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error verifying access token: %w", err)
|
||||
} else if !res.Valid {
|
||||
return nil, fmt.Errorf("invalid access token")
|
||||
return nil, fmt.Errorf("%w: invalid access token", sessions.ErrInvalidSession)
|
||||
}
|
||||
|
||||
s = c.newSessionFromIDPClaims(cfg, sessionID, res.Claims)
|
||||
|
@ -265,7 +265,7 @@ func (c *incomingIDPTokenSessionCreator) createSessionForIdentityToken(
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error verifying identity token: %w", err)
|
||||
} else if !res.Valid {
|
||||
return nil, fmt.Errorf("invalid identity token")
|
||||
return nil, fmt.Errorf("%w: invalid identity token", sessions.ErrInvalidSession)
|
||||
}
|
||||
|
||||
s = c.newSessionFromIDPClaims(cfg, sessionID, res.Claims)
|
||||
|
@ -405,22 +405,8 @@ func (cfg *Config) GetIncomingIDPAccessTokenForPolicy(policy *Policy, r *http.Re
|
|||
bearerTokenFormat = *policy.BearerTokenFormat
|
||||
}
|
||||
|
||||
if token := r.Header.Get(httputil.HeaderPomeriumIDPAccessToken); token != "" {
|
||||
return token, true
|
||||
}
|
||||
|
||||
if auth := r.Header.Get(httputil.HeaderAuthorization); auth != "" {
|
||||
prefix := httputil.AuthorizationTypePomeriumIDPAccessToken + " "
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) {
|
||||
return auth[len(prefix):], true
|
||||
}
|
||||
|
||||
prefix = "Bearer " + httputil.AuthorizationTypePomeriumIDPAccessToken + "-"
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) {
|
||||
return auth[len(prefix):], true
|
||||
}
|
||||
|
||||
prefix = "Bearer "
|
||||
prefix := "Bearer "
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) &&
|
||||
bearerTokenFormat == BearerTokenFormatIDPAccessToken {
|
||||
return auth[len(prefix):], true
|
||||
|
@ -440,22 +426,8 @@ func (cfg *Config) GetIncomingIDPIdentityTokenForPolicy(policy *Policy, r *http.
|
|||
bearerTokenFormat = *policy.BearerTokenFormat
|
||||
}
|
||||
|
||||
if token := r.Header.Get(httputil.HeaderPomeriumIDPIdentityToken); token != "" {
|
||||
return token, true
|
||||
}
|
||||
|
||||
if auth := r.Header.Get(httputil.HeaderAuthorization); auth != "" {
|
||||
prefix := httputil.AuthorizationTypePomeriumIDPIdentityToken + " "
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) {
|
||||
return auth[len(prefix):], true
|
||||
}
|
||||
|
||||
prefix = "Bearer " + httputil.AuthorizationTypePomeriumIDPIdentityToken + "-"
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) {
|
||||
return auth[len(prefix):], true
|
||||
}
|
||||
|
||||
prefix = "Bearer "
|
||||
prefix := "Bearer "
|
||||
if strings.HasPrefix(strings.ToLower(auth), strings.ToLower(prefix)) &&
|
||||
bearerTokenFormat == BearerTokenFormatIDPIdentityToken {
|
||||
return auth[len(prefix):], true
|
||||
|
|
|
@ -206,24 +206,6 @@ func TestGetIncomingIDPAccessTokenForPolicy(t *testing.T) {
|
|||
name: "empty headers",
|
||||
expectedOK: false,
|
||||
},
|
||||
{
|
||||
name: "custom header",
|
||||
headers: http.Header{"X-Pomerium-Idp-Access-Token": {"access token via custom header"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "access token via custom header",
|
||||
},
|
||||
{
|
||||
name: "custom authorization",
|
||||
headers: http.Header{"Authorization": {"Pomerium-Idp-Access-Token access token via custom authorization"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "access token via custom authorization",
|
||||
},
|
||||
{
|
||||
name: "custom bearer",
|
||||
headers: http.Header{"Authorization": {"Bearer Pomerium-Idp-Access-Token-access token via custom bearer"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "access token via custom bearer",
|
||||
},
|
||||
{
|
||||
name: "bearer disabled",
|
||||
headers: http.Header{"Authorization": {"Bearer access token via bearer"}},
|
||||
|
@ -289,24 +271,6 @@ func TestGetIncomingIDPIdentityTokenForPolicy(t *testing.T) {
|
|||
name: "empty headers",
|
||||
expectedOK: false,
|
||||
},
|
||||
{
|
||||
name: "custom header",
|
||||
headers: http.Header{"X-Pomerium-Idp-Identity-Token": {"identity token via custom header"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "identity token via custom header",
|
||||
},
|
||||
{
|
||||
name: "custom authorization",
|
||||
headers: http.Header{"Authorization": {"Pomerium-Idp-Identity-Token identity token via custom authorization"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "identity token via custom authorization",
|
||||
},
|
||||
{
|
||||
name: "custom bearer",
|
||||
headers: http.Header{"Authorization": {"Bearer Pomerium-Idp-Identity-Token-identity token via custom bearer"}},
|
||||
expectedOK: true,
|
||||
expectedToken: "identity token via custom bearer",
|
||||
},
|
||||
{
|
||||
name: "bearer disabled",
|
||||
headers: http.Header{"Authorization": {"Bearer identity token via bearer"}},
|
||||
|
@ -496,12 +460,14 @@ func TestIncomingIDPTokenSessionCreator_CreateSession(t *testing.T) {
|
|||
cfg.Options.AuthenticateURLString = srv.URL
|
||||
cfg.Options.ClientSecret = "CLIENT_SECRET_1"
|
||||
cfg.Options.ClientID = "CLIENT_ID_1"
|
||||
bearerTokenFormatIDPAccessToken := BearerTokenFormatIDPAccessToken
|
||||
cfg.Options.BearerTokenFormat = &bearerTokenFormatIDPAccessToken
|
||||
route := &Policy{}
|
||||
route.IDPClientSecret = "CLIENT_SECRET_2"
|
||||
route.IDPClientID = "CLIENT_ID_2"
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://www.example.com", nil)
|
||||
require.NoError(t, err)
|
||||
req.Header.Set(httputil.HeaderPomeriumIDPAccessToken, "ACCESS_TOKEN")
|
||||
req.Header.Set("Authorization", "Bearer ACCESS_TOKEN")
|
||||
c := NewIncomingIDPTokenSessionCreator(
|
||||
func(_ context.Context, _, _ string) (*databroker.Record, error) {
|
||||
return nil, storage.ErrNotFound
|
||||
|
@ -537,12 +503,14 @@ func TestIncomingIDPTokenSessionCreator_CreateSession(t *testing.T) {
|
|||
cfg.Options.AuthenticateURLString = srv.URL
|
||||
cfg.Options.ClientSecret = "CLIENT_SECRET_1"
|
||||
cfg.Options.ClientID = "CLIENT_ID_1"
|
||||
bearerTokenFormatIDPIdentityToken := BearerTokenFormatIDPIdentityToken
|
||||
cfg.Options.BearerTokenFormat = &bearerTokenFormatIDPIdentityToken
|
||||
route := &Policy{}
|
||||
route.IDPClientSecret = "CLIENT_SECRET_2"
|
||||
route.IDPClientID = "CLIENT_ID_2"
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://www.example.com", nil)
|
||||
require.NoError(t, err)
|
||||
req.Header.Set(httputil.HeaderPomeriumIDPIdentityToken, "IDENTITY_TOKEN")
|
||||
req.Header.Set("Authorization", "Bearer IDENTITY_TOKEN")
|
||||
c := NewIncomingIDPTokenSessionCreator(
|
||||
func(_ context.Context, _, _ string) (*databroker.Record, error) {
|
||||
return nil, storage.ErrNotFound
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/atomicutil"
|
||||
"github.com/pomerium/pomerium/internal/events"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/envoy/files"
|
||||
|
@ -29,6 +28,7 @@ import (
|
|||
"github.com/pomerium/pomerium/pkg/identity"
|
||||
"github.com/pomerium/pomerium/pkg/identity/legacymanager"
|
||||
"github.com/pomerium/pomerium/pkg/identity/manager"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
|
14
go.mod
14
go.mod
|
@ -88,15 +88,15 @@ require (
|
|||
go.uber.org/automaxprocs v1.6.0
|
||||
go.uber.org/mock v0.5.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/net v0.37.0
|
||||
golang.org/x/oauth2 v0.27.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/sync v0.12.0
|
||||
golang.org/x/sys v0.31.0
|
||||
golang.org/x/time v0.10.0
|
||||
google.golang.org/api v0.223.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2
|
||||
google.golang.org/grpc v1.70.0
|
||||
google.golang.org/grpc v1.71.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
|
@ -230,7 +230,7 @@ require (
|
|||
github.com/zeebo/assert v1.3.1 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.34.0 // indirect
|
||||
|
@ -239,7 +239,7 @@ require (
|
|||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||
|
|
32
go.sum
32
go.sum
|
@ -690,8 +690,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
|||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslqHxblNE9j62Ws1NK8=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//snGVIM3Tx6QRzlQBao=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
|
@ -750,8 +750,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -827,8 +827,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
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=
|
||||
|
@ -851,8 +851,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -912,15 +912,15 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -931,8 +931,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -1061,8 +1061,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
|||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
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=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
|
|
@ -14,10 +14,10 @@ import (
|
|||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/grpc"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/user"
|
||||
"github.com/pomerium/pomerium/pkg/identity"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// timeNow is time.Now but pulled out as a variable for tests.
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/sessions"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/grpc"
|
||||
|
@ -33,6 +32,7 @@ import (
|
|||
"github.com/pomerium/pomerium/pkg/grpcutil"
|
||||
"github.com/pomerium/pomerium/pkg/identity"
|
||||
"github.com/pomerium/pomerium/pkg/identity/manager"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// Stateful implements the stateful authentication flow. In this flow, the
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/sessions"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/grpc"
|
||||
|
@ -31,6 +30,7 @@ import (
|
|||
"github.com/pomerium/pomerium/pkg/grpc/user"
|
||||
"github.com/pomerium/pomerium/pkg/hpke"
|
||||
"github.com/pomerium/pomerium/pkg/identity"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"go.opentelemetry.io/otel"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
|
|
@ -17,10 +17,10 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/middleware"
|
||||
"github.com/pomerium/pomerium/internal/telemetry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
hpke_handlers "github.com/pomerium/pomerium/pkg/hpke/handlers"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/requestid"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
func (srv *Server) addHTTPMiddleware(ctx context.Context, root *mux.Router, _ *config.Config) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
|
||||
"golang.org/x/net/nettest"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/health/grpc_health_v1"
|
||||
|
@ -27,7 +28,6 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/events"
|
||||
"github.com/pomerium/pomerium/internal/httputil/reproxy"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
"github.com/pomerium/pomerium/pkg/envoy/files"
|
||||
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/pomerium/pomerium/pkg/grpcutil"
|
||||
"github.com/pomerium/pomerium/pkg/httputil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/requestid"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
@ -177,6 +178,7 @@ func NewServer(
|
|||
srv.MetricsListener.Addr().String(),
|
||||
srv.filemgr,
|
||||
srv.reproxy,
|
||||
nettest.SupportsIPv6(),
|
||||
)
|
||||
|
||||
res, err := srv.buildDiscoveryResources(ctx)
|
||||
|
|
|
@ -15,13 +15,13 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/hashutil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/grpc"
|
||||
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/pomerium/pkg/grpcutil"
|
||||
"github.com/pomerium/pomerium/pkg/health"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
googlegrpc "google.golang.org/grpc"
|
||||
|
|
|
@ -17,11 +17,11 @@ import (
|
|||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/registry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||
"github.com/pomerium/pomerium/pkg/storage"
|
||||
"github.com/pomerium/pomerium/pkg/storage/inmemory"
|
||||
"github.com/pomerium/pomerium/pkg/storage/postgres"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@ const (
|
|||
// can be used in place of the standard authorization header if that header is being
|
||||
// used by upstream applications.
|
||||
HeaderPomeriumAuthorization = "x-pomerium-authorization"
|
||||
HeaderPomeriumIDPAccessToken = "x-pomerium-idp-access-token" //nolint: gosec
|
||||
HeaderPomeriumIDPIdentityToken = "x-pomerium-idp-identity-token" //nolint: gosec
|
||||
// HeaderPomeriumResponse is set when pomerium itself creates a response,
|
||||
// as opposed to the upstream application and can be used to distinguish
|
||||
// between an application error, and a pomerium related error when debugging.
|
||||
|
|
|
@ -8,6 +8,9 @@ var (
|
|||
// ErrNoSessionFound is the error for when no session is found.
|
||||
ErrNoSessionFound = errors.New("internal/sessions: session is not found")
|
||||
|
||||
// ErrInvalidSession is the error for when a session is invalid.
|
||||
ErrInvalidSession = errors.New("internal/sessions: invalid session")
|
||||
|
||||
// ErrMalformed is the error for when a session is found but is malformed.
|
||||
ErrMalformed = errors.New("internal/sessions: session is malformed")
|
||||
|
||||
|
|
115
internal/telemetry/metrics/bench_test.go
Normal file
115
internal/telemetry/metrics/bench_test.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package metrics_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
||||
"github.com/pomerium/pomerium/internal/testenv/upstreams"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestScrapeMetricsEndpoint(t *testing.T) {
|
||||
t.Skip("this test is for profiling purposes only")
|
||||
|
||||
env := testenv.New(t, testenv.WithTraceDebugFlags(testenv.StandardTraceDebugFlags))
|
||||
upstream := upstreams.HTTP(nil)
|
||||
upstream.Handle("/test", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
|
||||
routes := []testenv.Route{}
|
||||
for i := range 10 {
|
||||
routes = append(routes, upstream.Route().
|
||||
From(env.SubdomainURL(fmt.Sprintf("test-%d", i))).
|
||||
Policy(func(p *config.Policy) { p.AllowPublicUnauthenticatedAccess = true }))
|
||||
}
|
||||
env.AddUpstream(upstream)
|
||||
env.Start()
|
||||
snippets.WaitStartupComplete(env)
|
||||
|
||||
for _, r := range routes {
|
||||
resp, err := upstream.Get(r, upstreams.Path("/test"))
|
||||
assert.NoError(t, err)
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
resp.Body.Close()
|
||||
assert.Equal(t, "OK", string(data))
|
||||
}
|
||||
|
||||
metricsURL := fmt.Sprintf("http://localhost:%d/metrics", env.Ports().Metrics.Value())
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
var durations []time.Duration
|
||||
var totalBytes int64
|
||||
var errors int
|
||||
|
||||
pct := 0
|
||||
niter := 200
|
||||
for i := 0; i < niter; i++ {
|
||||
pct = i * 100 / niter
|
||||
if pct%10 == 0 {
|
||||
t.Log(pct, "%")
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
resp, err := client.Get(metricsURL)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
t.Logf("Request %d failed: %v", i, err)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
|
||||
nb, err := io.Copy(io.Discard, resp.Body)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
durations = append(durations, elapsed)
|
||||
totalBytes += nb
|
||||
}
|
||||
|
||||
if len(durations) > 0 {
|
||||
sort.Slice(durations, func(i, j int) bool {
|
||||
return durations[i] < durations[j]
|
||||
})
|
||||
|
||||
var total time.Duration
|
||||
for _, d := range durations {
|
||||
total += d
|
||||
}
|
||||
|
||||
t.Logf("Metrics scraping statistics:")
|
||||
t.Logf(" Successful requests: %d", len(durations))
|
||||
t.Logf(" Failed requests: %d", errors)
|
||||
t.Logf(" Total bytes: %d", totalBytes)
|
||||
t.Logf(" Avg bytes per request: %.2f", float64(totalBytes)/float64(len(durations)))
|
||||
t.Logf(" Min: %v", durations[0])
|
||||
t.Logf(" Max: %v", durations[len(durations)-1])
|
||||
t.Logf(" Avg: %v", total/time.Duration(len(durations)))
|
||||
t.Logf(" p50: %v", durations[len(durations)*50/100])
|
||||
t.Logf(" p90: %v", durations[len(durations)*90/100])
|
||||
t.Logf(" p95: %v", durations[len(durations)*95/100])
|
||||
t.Logf(" p99: %v", durations[len(durations)*99/100])
|
||||
} else {
|
||||
t.Logf("No successful requests made")
|
||||
}
|
||||
|
||||
t.Logf("metrics endpoint: %s", metricsURL)
|
||||
|
||||
env.Stop()
|
||||
}
|
|
@ -240,11 +240,11 @@ var (
|
|||
Measure: identityManagerLastSessionRefreshSuccess,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
// IdentityManagerLastSessionRefreshErrorView contains user refresh errors counter
|
||||
// IdentityManagerLastSessionRefreshErrorView contains session refresh errors counter
|
||||
IdentityManagerLastSessionRefreshErrorView = &view.View{
|
||||
Name: identityManagerLastUserRefreshError.Name(),
|
||||
Description: identityManagerLastUserRefreshError.Description(),
|
||||
Measure: identityManagerLastUserRefreshError,
|
||||
Name: identityManagerLastSessionRefreshError.Name(),
|
||||
Description: identityManagerLastSessionRefreshError.Description(),
|
||||
Measure: identityManagerLastSessionRefreshError,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
// IdentityManagerLastSessionRefreshSuccessTimestampView contains successful session refresh counter
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -22,7 +21,6 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/prometheus"
|
||||
"github.com/pomerium/pomerium/pkg/metrics"
|
||||
)
|
||||
|
||||
// EnvoyMetricsPath is the path on the metrics listener that retrieves envoy metrics.
|
||||
|
@ -44,7 +42,7 @@ func (e *ScrapeEndpoint) String() string {
|
|||
|
||||
// PrometheusHandler creates an exporter that exports stats to Prometheus
|
||||
// and returns a handler suitable for exporting metrics.
|
||||
func PrometheusHandler(endpoints []ScrapeEndpoint, installationID string, timeout time.Duration) (http.Handler, error) {
|
||||
func PrometheusHandler(endpoints []ScrapeEndpoint, timeout time.Duration, labels map[string]string) (http.Handler, error) {
|
||||
exporter, err := getGlobalExporter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -52,7 +50,7 @@ func PrometheusHandler(endpoints []ScrapeEndpoint, installationID string, timeou
|
|||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/metrics", newProxyMetricsHandler(exporter, endpoints, installationID, timeout))
|
||||
mux.Handle("/metrics", newProxyMetricsHandler(exporter, endpoints, timeout, labels))
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
|
@ -96,12 +94,16 @@ func registerDefaultViews() error {
|
|||
|
||||
// newProxyMetricsHandler creates a subrequest to the envoy control plane for metrics and
|
||||
// combines them with internal envoy-provided
|
||||
func newProxyMetricsHandler(exporter *ocprom.Exporter, endpoints []ScrapeEndpoint, installationID string, timeout time.Duration) http.HandlerFunc {
|
||||
func newProxyMetricsHandler(
|
||||
exporter *ocprom.Exporter,
|
||||
endpoints []ScrapeEndpoint,
|
||||
timeout time.Duration,
|
||||
labels map[string]string,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), timeout)
|
||||
defer cancel()
|
||||
|
||||
labels := getCommonLabels(installationID)
|
||||
if err := writeMetricsMux(ctx, w, append(
|
||||
scrapeEndpoints(endpoints, labels),
|
||||
ocExport("pomerium", exporter, r, labels)),
|
||||
|
@ -156,7 +158,7 @@ func writeMetricsResult(w io.Writer, res promProducerResult) error {
|
|||
return fmt.Errorf("fetch: %w", res.err)
|
||||
}
|
||||
return errors.Join(
|
||||
prometheus.Export(w, prometheus.AddLabels(prometheus.NewMetricFamilyStream(res.src), res.labels)),
|
||||
prometheus.RelabelTextStream(w, res.src, res.labels),
|
||||
res.src.Close(),
|
||||
)
|
||||
}
|
||||
|
@ -229,17 +231,3 @@ func scrapeEndpoint(endpoint ScrapeEndpoint, extra map[string]string) promProduc
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getCommonLabels(installationID string) map[string]string {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
hostname = "__none__"
|
||||
}
|
||||
m := map[string]string{
|
||||
metrics.HostnameLabel: hostname,
|
||||
}
|
||||
if installationID != "" {
|
||||
m[metrics.InstallationIDLabel] = installationID
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ envoy_server_initialization_time_ms_bucket{le="1000"} 1
|
|||
}
|
||||
|
||||
func getMetrics(t *testing.T, envoyURL *url.URL, header http.Header) []byte {
|
||||
h, err := PrometheusHandler([]ScrapeEndpoint{{Name: "envoy", URL: *envoyURL}}, "test_installation_id", time.Second*20)
|
||||
h, err := PrometheusHandler([]ScrapeEndpoint{{Name: "envoy", URL: *envoyURL}}, time.Second*20, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
103
internal/telemetry/prometheus/relabel_text_stream.go
Normal file
103
internal/telemetry/prometheus/relabel_text_stream.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func writeMulti(dst io.Writer, b ...[]byte) error {
|
||||
for _, buf := range b {
|
||||
if _, err := dst.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RelabelTextStream relabels a prometheus text stream by adding additional labels to each metric.
|
||||
func RelabelTextStream(dst io.Writer, src io.Reader, addLabels map[string]string) error {
|
||||
if len(addLabels) == 0 {
|
||||
_, err := io.Copy(dst, src)
|
||||
return err
|
||||
}
|
||||
|
||||
var labelsBuilder strings.Builder
|
||||
for _, k := range slices.Sorted(maps.Keys(addLabels)) {
|
||||
v := addLabels[k]
|
||||
if labelsBuilder.Len() > 0 {
|
||||
labelsBuilder.WriteByte(',')
|
||||
}
|
||||
labelsBuilder.WriteString(k)
|
||||
labelsBuilder.WriteString("=\"")
|
||||
labelsBuilder.WriteString(v)
|
||||
labelsBuilder.WriteString("\"")
|
||||
}
|
||||
addedLabels := []byte(labelsBuilder.String())
|
||||
|
||||
r := bufio.NewReader(src)
|
||||
|
||||
for {
|
||||
line, err := r.ReadSlice('\n')
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
if _, err := dst.Write(line); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
spaceIdx := bytes.IndexByte(line, ' ')
|
||||
if spaceIdx == -1 {
|
||||
if _, err := dst.Write(line); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
metricWithLabels := line[:spaceIdx]
|
||||
value := line[spaceIdx:]
|
||||
|
||||
openBraceIdx := bytes.IndexByte(metricWithLabels, '{')
|
||||
if openBraceIdx == -1 { // no labels
|
||||
if err := writeMulti(dst, metricWithLabels, []byte("{"), addedLabels, []byte("}"), value); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
metricName := metricWithLabels[:openBraceIdx]
|
||||
|
||||
closeBraceIdx := bytes.LastIndexByte(metricWithLabels, '}')
|
||||
if closeBraceIdx == -1 || closeBraceIdx <= openBraceIdx {
|
||||
if _, err := dst.Write(line); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
existingLabels := metricWithLabels[openBraceIdx+1 : closeBraceIdx]
|
||||
|
||||
if len(existingLabels) > 0 {
|
||||
if err := writeMulti(dst, metricName, []byte("{"), existingLabels, []byte(","), addedLabels, []byte("}"), value); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := writeMulti(dst, metricName, []byte("{"), addedLabels, []byte("}"), value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
141
internal/telemetry/prometheus/relabel_text_stream_test.go
Normal file
141
internal/telemetry/prometheus/relabel_text_stream_test.go
Normal file
|
@ -0,0 +1,141 @@
|
|||
package prometheus_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// RepeatingReader repeats reading from the beginning after EOF for a specified number of times
|
||||
type RepeatingReader struct {
|
||||
reader *bytes.Reader
|
||||
resets int
|
||||
maxResets int
|
||||
}
|
||||
|
||||
// NewRepeatingReader creates a new reader that will reset up to maxResets times
|
||||
func NewRepeatingReader(data []byte, maxResets int) *RepeatingReader {
|
||||
return &RepeatingReader{
|
||||
reader: bytes.NewReader(data),
|
||||
resets: 0,
|
||||
maxResets: maxResets,
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements io.Reader
|
||||
func (r *RepeatingReader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.reader.Read(p)
|
||||
if err == io.EOF && r.resets < r.maxResets {
|
||||
r.reader.Seek(0, io.SeekStart)
|
||||
r.resets++
|
||||
return r.Read(p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func BenchmarkRelabelTestStream(b *testing.B) {
|
||||
addLabels := map[string]string{"instance": "localhost:9090", "installation_id": "12345-67890-12345-67890"}
|
||||
src := []byte(`
|
||||
# TYPE envoy_cluster_upstream_cx_total counter
|
||||
envoy_cluster_upstream_cx_total{service="pomerium-proxy",envoy_cluster_name="route-1",installation_id="aecd6525-9eaa-448d-93d9-6363c04b1ccb",hostname="pomerium-proxy-55589cc5f-fjhsb"} 2
|
||||
envoy_cluster_upstream_cx_total{service="pomerium-proxy",envoy_cluster_name="route-2",installation_id="aecd6525-9eaa-448d-93d9-6363c04b1ccb",hostname="pomerium-proxy-55589cc5f-fjhsb"} 3
|
||||
`)
|
||||
|
||||
b.Run("RelabelTextStream", func(b *testing.B) {
|
||||
inputReader := NewRepeatingReader(src, b.N)
|
||||
err := prometheus.RelabelTextStream(io.Discard, inputReader, addLabels)
|
||||
require.NoError(b, err)
|
||||
})
|
||||
b.Run("Previous", func(b *testing.B) {
|
||||
inputReader := NewRepeatingReader(src, b.N)
|
||||
err := prometheus.Export(io.Discard, prometheus.AddLabels(prometheus.NewMetricFamilyStream(inputReader), addLabels))
|
||||
require.NoError(b, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRelabelTextStream(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
addLabels map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "empty input",
|
||||
input: "",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "no labels to add",
|
||||
input: "metric 42\n",
|
||||
addLabels: map[string]string{},
|
||||
expected: "metric 42\n",
|
||||
},
|
||||
{
|
||||
name: "comment lines",
|
||||
input: "# HELP metric_name Help text\n# TYPE metric_name counter\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "# HELP metric_name Help text\n# TYPE metric_name counter\n",
|
||||
},
|
||||
{
|
||||
name: "metric without labels",
|
||||
input: "http_requests_total 42\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "http_requests_total{instance=\"localhost:9090\"} 42\n",
|
||||
},
|
||||
{
|
||||
name: "metric with existing labels",
|
||||
input: "http_requests_total{method=\"GET\"} 42\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "http_requests_total{method=\"GET\",instance=\"localhost:9090\"} 42\n",
|
||||
},
|
||||
{
|
||||
name: "multiple labels to add",
|
||||
input: "http_requests_total 42\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090", "job": "prometheus"},
|
||||
expected: "http_requests_total{instance=\"localhost:9090\",job=\"prometheus\"} 42\n",
|
||||
},
|
||||
{
|
||||
name: "malformed metric (no space)",
|
||||
input: "invalid_metric\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "invalid_metric\n",
|
||||
},
|
||||
{
|
||||
name: "malformed metric (no closing brace)",
|
||||
input: "invalid_metric{label=\"value\" 42\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "invalid_metric{label=\"value\" 42\n",
|
||||
},
|
||||
{
|
||||
name: "empty labels",
|
||||
input: "http_requests_total{} 42\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "http_requests_total{instance=\"localhost:9090\"} 42\n",
|
||||
},
|
||||
{
|
||||
name: "multiple metrics",
|
||||
input: "metric1 10\nmetric2{label=\"value\"} 20\n# COMMENT\nmetric3 30\n",
|
||||
addLabels: map[string]string{"instance": "localhost:9090"},
|
||||
expected: "metric1{instance=\"localhost:9090\"} 10\nmetric2{label=\"value\",instance=\"localhost:9090\"} 20\n# COMMENT\nmetric3{instance=\"localhost:9090\"} 30\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
inputReader := strings.NewReader(tc.input)
|
||||
outputBuffer := &bytes.Buffer{}
|
||||
|
||||
err := prometheus.RelabelTextStream(outputBuffer, inputReader, tc.addLabels)
|
||||
require.NoError(t, err)
|
||||
|
||||
actual := outputBuffer.String()
|
||||
require.Equal(t, tc.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import (
|
|||
"github.com/pomerium/pomerium/config/envoyconfig/filemgr"
|
||||
databroker_service "github.com/pomerium/pomerium/databroker"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv/envutil"
|
||||
"github.com/pomerium/pomerium/internal/testenv/values"
|
||||
"github.com/pomerium/pomerium/pkg/cmd/pomerium"
|
||||
|
@ -47,6 +46,7 @@ import (
|
|||
"github.com/pomerium/pomerium/pkg/identity/manager"
|
||||
"github.com/pomerium/pomerium/pkg/netutil"
|
||||
"github.com/pomerium/pomerium/pkg/slices"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
@ -21,12 +21,12 @@ import (
|
|||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/internal/testenv/scenarios"
|
||||
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
||||
"github.com/pomerium/pomerium/internal/testenv/upstreams"
|
||||
. "github.com/pomerium/pomerium/internal/testutil/tracetest" //nolint:revive
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
var allServices = []string{
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/pkg/grpcutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
|
|
@ -6,10 +6,10 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
||||
"github.com/pomerium/pomerium/internal/testenv/values"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
|
|
|
@ -21,10 +21,10 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/pomerium/pomerium/integration/forms"
|
||||
"github.com/pomerium/pomerium/internal/retry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
||||
"github.com/pomerium/pomerium/internal/testenv/values"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"unique"
|
||||
|
||||
gocmp "github.com/google/go-cmp/cmp"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
|
|
@ -48,6 +48,7 @@ func New(
|
|||
func (c *client) getGRPCConn(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
opts := append(
|
||||
c.config.GetDialOptions(),
|
||||
grpc.WithAuthority(c.config.GetAuthority()),
|
||||
grpc.WithPerRPCCredentials(c),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.UseCompressor("gzip"),
|
||||
|
@ -60,7 +61,7 @@ func (c *client) getGRPCConn(ctx context.Context) (*grpc.ClientConn, error) {
|
|||
),
|
||||
)
|
||||
|
||||
conn, err := grpc.DialContext(ctx, c.config.GetConnectionURI(), opts...)
|
||||
conn, err := grpc.NewClient(c.config.GetConnectionURI(), opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error dialing grpc server: %w", err)
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ func (c *client) logConnectionState(ctx context.Context, conn *grpc.ClientConn)
|
|||
_ = conn.WaitForStateChange(ctx, state)
|
||||
state = conn.GetState()
|
||||
log.Ctx(ctx).Debug().
|
||||
Str("endpoint", c.config.connectionURI).
|
||||
Str("endpoint", c.config.GetConnectionURI()).
|
||||
Str("state", state.String()).
|
||||
Msg("grpc connection state")
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ import (
|
|||
|
||||
// config is the configuration for the gRPC client
|
||||
type config struct {
|
||||
connectionURI string
|
||||
// authority is a host:port string that will be used as the :authority pseudo-header
|
||||
authority string
|
||||
// requireTLS is whether TLS should be used or cleartext
|
||||
requireTLS bool
|
||||
// opts are additional options to pass to the gRPC client
|
||||
|
@ -41,9 +42,14 @@ func getConfig(
|
|||
return c, nil
|
||||
}
|
||||
|
||||
// GetAuthority returns the authority to use in the :authority pseudo-header
|
||||
func (c *config) GetAuthority() string {
|
||||
return c.authority
|
||||
}
|
||||
|
||||
// GetConnectionURI returns connection string conforming to https://github.com/grpc/grpc/blob/master/doc/naming.md
|
||||
func (c *config) GetConnectionURI() string {
|
||||
return c.connectionURI
|
||||
return "dns:" + c.authority
|
||||
}
|
||||
|
||||
// GetDialTimeout returns the timeout for the dial operation
|
||||
|
@ -101,7 +107,7 @@ func (c *config) parseEndpoint(endpoint string) error {
|
|||
return fmt.Errorf("unsupported url scheme: %s", u.Scheme)
|
||||
}
|
||||
|
||||
c.connectionURI = fmt.Sprintf("dns:%s:%s", host, port)
|
||||
c.authority = host + ":" + port
|
||||
c.requireTLS = requireTLS
|
||||
|
||||
return nil
|
||||
|
|
|
@ -23,11 +23,11 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/events"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/registry"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
derivecert_config "github.com/pomerium/pomerium/pkg/derivecert/config"
|
||||
"github.com/pomerium/pomerium/pkg/envoy"
|
||||
"github.com/pomerium/pomerium/pkg/envoy/files"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/proxy"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
|
|
@ -713,7 +713,7 @@ func TestSharedResourceMonitor(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBootstrapConfig(t *testing.T) {
|
||||
b := envoyconfig.New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil)
|
||||
b := envoyconfig.New("localhost:1111", "localhost:2222", "localhost:3333", filemgr.NewManager(), nil, true)
|
||||
testEnvoyPid := 99
|
||||
tempDir := t.TempDir()
|
||||
monitor, err := NewSharedResourceMonitor(context.Background(), config.NewStaticSource(nil), tempDir, WithCgroupDriver(&cgroupV2Driver{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -123,7 +123,7 @@ message Route {
|
|||
string kubernetes_service_account_token = 26;
|
||||
string kubernetes_service_account_token_file = 64;
|
||||
bool enable_google_cloud_serverless_authentication = 42;
|
||||
IssuerFormat jwt_issuer_format = 65;
|
||||
optional IssuerFormat jwt_issuer_format = 65;
|
||||
repeated string jwt_groups_filter = 66;
|
||||
optional BearerTokenFormat bearer_token_format = 70;
|
||||
|
||||
|
@ -160,7 +160,7 @@ message Policy {
|
|||
string remediation = 9;
|
||||
}
|
||||
|
||||
// Next ID: 139.
|
||||
// Next ID: 140.
|
||||
message Settings {
|
||||
message Certificate {
|
||||
bytes cert_bytes = 3;
|
||||
|
@ -214,6 +214,7 @@ message Settings {
|
|||
map<string, string> set_response_headers = 69;
|
||||
// repeated string jwt_claims_headers = 37;
|
||||
map<string, string> jwt_claims_headers = 63;
|
||||
optional IssuerFormat jwt_issuer_format = 139;
|
||||
repeated string jwt_groups_filter = 119;
|
||||
optional BearerTokenFormat bearer_token_format = 138;
|
||||
optional google.protobuf.Duration default_upstream_timeout = 39;
|
||||
|
|
|
@ -16,11 +16,11 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
"github.com/pomerium/pomerium/pkg/identity/identity"
|
||||
"github.com/pomerium/pomerium/pkg/identity/oauth"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// Name identifies the generic OpenID Connect provider.
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -13,13 +13,13 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/testenv"
|
||||
"github.com/pomerium/pomerium/internal/testenv/scenarios"
|
||||
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
||||
. "github.com/pomerium/pomerium/internal/testutil/tracetest" //nolint:revive
|
||||
"github.com/pomerium/pomerium/internal/testutil/tracetest/mock_otlptrace"
|
||||
"github.com/pomerium/pomerium/internal/version"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel"
|
|
@ -9,8 +9,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
. "github.com/pomerium/pomerium/internal/testutil/tracetest" //nolint:revive
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
|
@ -4,7 +4,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
|
@ -9,7 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/pomerium/datasource/pkg/directory"
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/databroker"
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/sessions"
|
||||
"github.com/pomerium/pomerium/internal/testutil"
|
||||
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
||||
|
@ -47,7 +46,7 @@ func Test_getUserInfoData(t *testing.T) {
|
|||
proxy.state.Load().dataBrokerClient = client
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/.pomerium/", nil)
|
||||
r.Header.Set(httputil.HeaderPomeriumIDPAccessToken, "ACCESS_TOKEN")
|
||||
r.Header.Set("Authorization", "Bearer ACCESS_TOKEN")
|
||||
data := proxy.getUserInfoData(r)
|
||||
assert.NotNil(t, data.Session)
|
||||
assert.NotNil(t, data.User)
|
||||
|
|
|
@ -15,8 +15,8 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/handlers"
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/middleware"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
)
|
||||
|
||||
// registerDashboardHandlers returns the proxy service's ServeMux
|
||||
|
|
|
@ -19,8 +19,8 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/proxy/portal"
|
||||
)
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ func testOptions(t *testing.T) *config.Options {
|
|||
opts.Services = config.ServiceAll
|
||||
opts.SharedKey = "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ="
|
||||
opts.CookieSecret = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw="
|
||||
bearerTokenFormatIDPAccessToken := config.BearerTokenFormatIDPAccessToken
|
||||
opts.BearerTokenFormat = &bearerTokenFormatIDPAccessToken
|
||||
|
||||
hpkePrivateKey, err := opts.GetHPKEPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
|
Loading…
Add table
Reference in a new issue