diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile index 9ab821c273..f143bd87b9 100644 --- a/.clusterfuzzlite/Dockerfile +++ b/.clusterfuzzlite/Dockerfile @@ -1,4 +1,4 @@ -FROM gcr.io/oss-fuzz-base/base-builder-go@sha256:bab77046ede6fae6f9ab931ada4b17a5adaf71842ac93e32300d06d5b9829891 +FROM gcr.io/oss-fuzz-base/base-builder-go@sha256:9bf7fad8ca02443224c7518392d80c97a62b8cb0822f03aadf9193a7e27346f0 COPY . $SRC/skipper COPY ./.clusterfuzzlite/build.sh $SRC/ diff --git a/filters/auth/authclient.go b/filters/auth/authclient.go index ca5463eade..ccc71a1ef5 100644 --- a/filters/auth/authclient.go +++ b/filters/auth/authclient.go @@ -32,6 +32,7 @@ type authClient struct { type tokeninfoClient interface { getTokeninfo(token string, ctx filters.FilterContext) (map[string]any, error) + Close() } var _ tokeninfoClient = &authClient{} diff --git a/filters/auth/grant.go b/filters/auth/grant.go index a828caab78..9344082326 100644 --- a/filters/auth/grant.go +++ b/filters/auth/grant.go @@ -175,11 +175,7 @@ func (f *grantFilter) setupToken(token *oauth2.Token, tokeninfo map[string]inter // By piggy-backing on the OIDC token container, // we gain downstream compatibility with the oidcClaimsQuery filter. - ctx.StateBag()[oidcClaimsCacheKey] = tokenContainer{ - OAuth2Token: token, - Subject: subject, - Claims: tokeninfo, - } + SetOIDCClaims(ctx, tokeninfo) // Set the tokeninfo also in the tokeninfoCacheKey state bag, so we // can reuse e.g. the forwardToken() filter. diff --git a/filters/auth/grant_test.go b/filters/auth/grant_test.go index 70270e73ca..18818f96cb 100644 --- a/filters/auth/grant_test.go +++ b/filters/auth/grant_test.go @@ -210,6 +210,7 @@ func newAuthProxy(t *testing.T, config *auth.OAuthConfig, routes []*eskip.Route, fr.Register(config.NewGrantCallback()) fr.Register(config.NewGrantClaimsQuery()) fr.Register(config.NewGrantLogout()) + fr.Register(auth.NewOIDCQueryClaimsFilter()) pc := proxytest.Config{ RoutingOptions: routing.Options{ @@ -331,6 +332,7 @@ func TestGrantFlow(t *testing.T) { config := newGrantTestConfig(tokeninfo.URL, provider.URL) routes := eskip.MustParse(`* -> oauthGrant() + -> oidcClaimsQuery("/:sub") -> status(204) -> setResponseHeader("Backend-Request-Cookie", "${request.header.Cookie}") -> diff --git a/filters/auth/main_test.go b/filters/auth/main_test.go index 4da87fe2a4..3df902c5e3 100644 --- a/filters/auth/main_test.go +++ b/filters/auth/main_test.go @@ -18,11 +18,7 @@ func TestMain(m *testing.M) { func cleanupAuthClients() { for _, c := range tokeninfoAuthClient { - if ac, ok := c.(*authClient); ok { - ac.Close() - } else if cc, ok := c.(*tokeninfoCache); ok { - cc.client.(*authClient).Close() - } + c.Close() } for _, c := range issuerAuthClient { diff --git a/filters/auth/oidc_introspection.go b/filters/auth/oidc_introspection.go index a32752a7c0..8d21dc4ec1 100644 --- a/filters/auth/oidc_introspection.go +++ b/filters/auth/oidc_introspection.go @@ -42,6 +42,14 @@ func NewOIDCQueryClaimsFilter() filters.Spec { } } +// Sets OIDC claims in the state bag. +// Intended for use with the oidcClaimsQuery filter. +func SetOIDCClaims(ctx filters.FilterContext, claims map[string]interface{}) { + ctx.StateBag()[oidcClaimsCacheKey] = tokenContainer{ + Claims: claims, + } +} + func (spec *oidcIntrospectionSpec) Name() string { switch spec.typ { case checkOIDCQueryClaims: diff --git a/filters/auth/tokeninfo.go b/filters/auth/tokeninfo.go index 53323012cb..f12f24d868 100644 --- a/filters/auth/tokeninfo.go +++ b/filters/auth/tokeninfo.go @@ -12,6 +12,7 @@ import ( "github.com/opentracing/opentracing-go" "github.com/zalando/skipper/filters" "github.com/zalando/skipper/filters/annotate" + "github.com/zalando/skipper/metrics" ) const ( @@ -32,9 +33,10 @@ type TokeninfoOptions struct { Timeout time.Duration MaxIdleConns int Tracer opentracing.Tracer + Metrics metrics.Metrics // CacheSize configures the maximum number of cached tokens. - // The cache evicts least recently used items first. + // The cache periodically evicts random items when number of cached tokens exceeds CacheSize. // Zero value disables tokeninfo cache. CacheSize int @@ -100,7 +102,7 @@ func (o *TokeninfoOptions) newTokeninfoClient() (tokeninfoClient, error) { } if o.CacheSize > 0 { - c = newTokeninfoCache(c, o.CacheSize, o.CacheTTL) + c = newTokeninfoCache(c, o.Metrics, o.CacheSize, o.CacheTTL) } return c, nil } diff --git a/filters/auth/tokeninfocache.go b/filters/auth/tokeninfocache.go index c925ae5834..df31bc62f6 100644 --- a/filters/auth/tokeninfocache.go +++ b/filters/auth/tokeninfocache.go @@ -1,32 +1,32 @@ package auth import ( - "container/list" + "maps" "sync" + "sync/atomic" "time" "github.com/zalando/skipper/filters" + "github.com/zalando/skipper/metrics" ) type ( tokeninfoCache struct { - client tokeninfoClient - size int - ttl time.Duration - now func() time.Time - - mu sync.Mutex - cache map[string]*entry - // least recently used token at the end - history *list.List + client tokeninfoClient + metrics metrics.Metrics + size int + ttl time.Duration + now func() time.Time + + cache sync.Map // map[string]*entry + count atomic.Int64 // estimated number of cached entries, see https://github.com/golang/go/issues/20680 + quit chan struct{} } entry struct { - cachedAt time.Time - expiresAt time.Time - info map[string]any - // reference in the history - href *list.Element + expiresAt time.Time + info map[string]any + infoExpiresAt time.Time } ) @@ -34,15 +34,22 @@ var _ tokeninfoClient = &tokeninfoCache{} const expiresInField = "expires_in" -func newTokeninfoCache(client tokeninfoClient, size int, ttl time.Duration) *tokeninfoCache { - return &tokeninfoCache{ +func newTokeninfoCache(client tokeninfoClient, metrics metrics.Metrics, size int, ttl time.Duration) *tokeninfoCache { + c := &tokeninfoCache{ client: client, + metrics: metrics, size: size, ttl: ttl, now: time.Now, - cache: make(map[string]*entry, size), - history: list.New(), + quit: make(chan struct{}), } + go c.evictLoop() + return c +} + +func (c *tokeninfoCache) Close() { + c.client.Close() + close(c.quit) } func (c *tokeninfoCache) getTokeninfo(token string, ctx filters.FilterContext) (map[string]any, error) { @@ -58,35 +65,21 @@ func (c *tokeninfoCache) getTokeninfo(token string, ctx filters.FilterContext) ( } func (c *tokeninfoCache) cached(token string) map[string]any { - now := c.now() - - c.mu.Lock() - - if e, ok := c.cache[token]; ok { + if v, ok := c.cache.Load(token); ok { + now := c.now() + e := v.(*entry) if now.Before(e.expiresAt) { - c.history.MoveToFront(e.href) - cachedInfo := e.info - c.mu.Unlock() - // It might be ok to return cached value // without adjusting "expires_in" to avoid copy // if caller never modifies the result and // when "expires_in" did not change (same second) // or for small TTL values - info := shallowCopyOf(cachedInfo) + info := maps.Clone(e.info) - elapsed := now.Sub(e.cachedAt).Truncate(time.Second).Seconds() - info[expiresInField] = info[expiresInField].(float64) - elapsed + info[expiresInField] = e.infoExpiresAt.Sub(now).Truncate(time.Second).Seconds() return info - } else { - // remove expired - delete(c.cache, token) - c.history.Remove(e.href) } } - - c.mu.Unlock() - return nil } @@ -95,38 +88,62 @@ func (c *tokeninfoCache) tryCache(token string, info map[string]any) { if expiresIn <= 0 { return } - if c.ttl > 0 && expiresIn > c.ttl { - expiresIn = c.ttl - } now := c.now() - expiresAt := now.Add(expiresIn) + e := &entry{ + info: info, + infoExpiresAt: now.Add(expiresIn), + } + + if c.ttl > 0 && expiresIn > c.ttl { + e.expiresAt = now.Add(c.ttl) + } else { + e.expiresAt = e.infoExpiresAt + } - c.mu.Lock() - defer c.mu.Unlock() + if _, loaded := c.cache.Swap(token, e); !loaded { + c.count.Add(1) + } +} - if e, ok := c.cache[token]; ok { - // update - e.cachedAt = now - e.expiresAt = expiresAt - e.info = info - c.history.MoveToFront(e.href) - return +func (c *tokeninfoCache) evictLoop() { + ticker := time.NewTicker(time.Minute) + defer ticker.Stop() + for { + select { + case <-c.quit: + return + case <-ticker.C: + c.evict() + } } +} - // create - c.cache[token] = &entry{ - cachedAt: now, - expiresAt: expiresAt, - info: info, - href: c.history.PushFront(token), +func (c *tokeninfoCache) evict() { + now := c.now() + // Evict expired entries + c.cache.Range(func(key, value any) bool { + e := value.(*entry) + if now.After(e.expiresAt) { + if c.cache.CompareAndDelete(key, value) { + c.count.Add(-1) + } + } + return true + }) + + // Evict random entries until the cache size is within limits + if c.count.Load() > int64(c.size) { + c.cache.Range(func(key, value any) bool { + if c.cache.CompareAndDelete(key, value) { + c.count.Add(-1) + } + return c.count.Load() > int64(c.size) + }) } - // remove least used - if len(c.cache) > c.size { - leastUsed := c.history.Back() - delete(c.cache, leastUsed.Value.(string)) - c.history.Remove(leastUsed) + if c.metrics != nil { + c.metrics.UpdateGauge("tokeninfocache.count", float64(c.count.Load())) } } @@ -141,11 +158,3 @@ func expiresIn(info map[string]any) time.Duration { } return 0 } - -func shallowCopyOf(info map[string]any) map[string]any { - m := make(map[string]any, len(info)) - for k, v := range info { - m[k] = v - } - return m -} diff --git a/filters/auth/tokeninfocache_test.go b/filters/auth/tokeninfocache_test.go index a5cfbf4a0e..86162207ac 100644 --- a/filters/auth/tokeninfocache_test.go +++ b/filters/auth/tokeninfocache_test.go @@ -12,6 +12,7 @@ import ( "github.com/zalando/skipper/filters" "github.com/zalando/skipper/filters/filtertest" + "github.com/zalando/skipper/metrics/metricstest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,6 +23,7 @@ type tokeninfoClientFunc func(string, filters.FilterContext) (map[string]any, er func (f tokeninfoClientFunc) getTokeninfo(token string, ctx filters.FilterContext) (map[string]any, error) { return f(token, ctx) } +func (f tokeninfoClientFunc) Close() {} type testTokeninfoToken string @@ -58,6 +60,7 @@ func (c *testClock) now() time.Time { func TestTokeninfoCache(t *testing.T) { const ( TokenTTLSeconds = 600 + CacheSize = 1 CacheTTL = 300 * time.Second // less than TokenTTLSeconds ) @@ -79,15 +82,19 @@ func TestTokeninfoCache(t *testing.T) { })) defer authServer.Close() + m := &metricstest.MockMetrics{} + defer m.Close() + o := TokeninfoOptions{ URL: authServer.URL + "/oauth2/tokeninfo", - CacheSize: 1, + CacheSize: CacheSize, CacheTTL: CacheTTL, + Metrics: m, } c, err := o.newTokeninfoClient() require.NoError(t, err) - defer c.(*tokeninfoCache).client.(*authClient).Close() + defer c.Close() c.(*tokeninfoCache).now = clock.now ctx := &filtertest.Context{FRequest: &http.Request{}} @@ -111,7 +118,7 @@ func TestTokeninfoCache(t *testing.T) { assert.Equal(t, int32(1), authRequests, "expected no request to auth sever") assert.Equal(t, token, info["uid"]) - assert.Equal(t, float64(595), info["expires_in"], "expected TokenTTLSeconds - truncate(delay)") + assert.Equal(t, float64(594), info["expires_in"], "expected truncate(TokenTTLSeconds - delay)") // Third request after "sleeping" longer than cache TTL clock.add(CacheTTL) @@ -123,7 +130,7 @@ func TestTokeninfoCache(t *testing.T) { assert.Equal(t, token, info["uid"]) assert.Equal(t, float64(294), info["expires_in"], "expected truncate(TokenTTLSeconds - CacheTTL - delay)") - // Fourth request with a new token evicts cached value + // Fourth request with a new token token = newTestTokeninfoToken(clock.now()).String() info, err = c.getTokeninfo(token, ctx) @@ -132,6 +139,19 @@ func TestTokeninfoCache(t *testing.T) { assert.Equal(t, int32(3), authRequests, "expected new request to auth sever") assert.Equal(t, token, info["uid"]) assert.Equal(t, float64(600), info["expires_in"], "expected TokenTTLSeconds") + + // Force eviction and verify cache size is within limits + c.(*tokeninfoCache).evict() + m.WithGauges(func(g map[string]float64) { + assert.Equal(t, float64(CacheSize), g["tokeninfocache.count"]) + }) + + // Force eviction after all entries expired and verify cache is empty + clock.add(CacheTTL + time.Second) + c.(*tokeninfoCache).evict() + m.WithGauges(func(g map[string]float64) { + assert.Equal(t, float64(0), g["tokeninfocache.count"]) + }) } // Tests race between reading and writing cache for the same token @@ -152,7 +172,8 @@ func TestTokeninfoCacheUpdateRace(t *testing.T) { return map[string]any{"requestNumber": requestNumber, "uid": token, "expires_in": float64(600)}, nil }) - c := newTokeninfoCache(mc, 1, time.Hour) + c := newTokeninfoCache(mc, nil, 1, time.Hour) + defer c.Close() const token = "atoken" @@ -234,7 +255,8 @@ func BenchmarkTokeninfoCache(b *testing.B) { return tokenValues[token], nil }) - c := newTokeninfoCache(mc, bi.cacheSize, time.Hour) + c := newTokeninfoCache(mc, nil, bi.cacheSize, time.Hour) + defer c.Close() var tokens []string for i := 0; i < bi.tokens; i++ { diff --git a/filters/openpolicyagent/opaauthorizerequest/opaauthorizerequest_test.go b/filters/openpolicyagent/opaauthorizerequest/opaauthorizerequest_test.go index 45c4087ffc..51f4a493ad 100644 --- a/filters/openpolicyagent/opaauthorizerequest/opaauthorizerequest_test.go +++ b/filters/openpolicyagent/opaauthorizerequest/opaauthorizerequest_test.go @@ -63,7 +63,7 @@ func TestAuthorizeRequestFilter(t *testing.T) { msg: "Allow Requests with spaces in path", filterName: "opaAuthorizeRequest", bundleName: "somebundle.tar.gz", - regoQuery: "envoy/authz/allow", + regoQuery: "envoy/authz/allow_with_space_in_path", requestPath: "/my%20path", requestMethod: "GET", contextExtensions: "", @@ -106,7 +106,7 @@ func TestAuthorizeRequestFilter(t *testing.T) { msg: "Allow Requests with query parameters", filterName: "opaAuthorizeRequest", bundleName: "somebundle.tar.gz", - regoQuery: "envoy/authz/allow", + regoQuery: "envoy/authz/allow_with_query", requestPath: "/allow-with-query?pass=yes&id=1&id=2&msg=help%20me", requestMethod: "GET", contextExtensions: "", @@ -173,8 +173,8 @@ func TestAuthorizeRequestFilter(t *testing.T) { msg: "Simple Forbidden with Query Parameters", filterName: "opaAuthorizeRequest", bundleName: "somebundle.tar.gz", - regoQuery: "envoy/authz/allow", - requestPath: "/allow-with-query?tofail=true", + regoQuery: "envoy/authz/deny_with_query", + requestPath: "/allow-me?tofail=true", requestMethod: "GET", contextExtensions: "", expectedStatus: http.StatusForbidden, @@ -384,6 +384,20 @@ func TestAuthorizeRequestFilter(t *testing.T) { backendHeaders: make(http.Header), removeHeaders: make(http.Header), }, + { + msg: "Allow Requests ignoring fragment", + filterName: "opaAuthorizeRequest", + bundleName: "somebundle.tar.gz", + regoQuery: "envoy/authz/allow_with_path_having_fragment", + requestPath: "/path-with-empty-query#fragment?", + requestMethod: "GET", + contextExtensions: "", + expectedStatus: http.StatusOK, + expectedBody: "Welcome!", + expectedHeaders: make(http.Header), + backendHeaders: make(http.Header), + removeHeaders: make(http.Header), + }, } { t.Run(ti.msg, func(t *testing.T) { t.Logf("Running test for %v", ti) @@ -405,33 +419,44 @@ func TestAuthorizeRequestFilter(t *testing.T) { "main.rego": ` package envoy.authz - default allow = false + default allow := false + default deny_with_query := false allow { - input.parsed_path = [ "allow" ] - input.parsed_query = {} + input.parsed_path == [ "allow" ] + input.parsed_query == {} } allow_with_http_path { input.attributes.request.http.path == "/some/api/path?q1=v1&msg=help%20me" } - allow { - input.parsed_path = [ "my path" ] + allow_with_space_in_path { + input.parsed_path == [ "my path" ] } allow_with_path_having_empty_query { - input.parsed_path = [ "path-with-empty-query" ] - input.parsed_query = {} + input.parsed_path == [ "path-with-empty-query" ] + input.parsed_query == {} } - allow { - input.parsed_path = [ "allow-with-query" ] + allow_with_query { + input.parsed_path == [ "allow-with-query" ] input.parsed_query.pass == ["yes"] input.parsed_query.id == ["1", "2"] input.parsed_query.msg == ["help me"] } + deny_with_query { + input.attributes.request.http.path == "/allow-me?tofail=true" + not input.parsed_query.tofail == ["true"] + } + + allow_with_path_having_fragment { + input.parsed_path == [ "path-with-empty-query" ] + input.attributes.request.http.path == "/path-with-empty-query" + } + allow_context_extensions { input.attributes.contextExtensions["com.mycompany.myprop"] == "myvalue" } @@ -440,15 +465,15 @@ func TestAuthorizeRequestFilter(t *testing.T) { opa.runtime().config.labels.environment == "test" } - default allow_object = { + default allow_object := { "allowed": false, "headers": {"x-ext-auth-allow": "no"}, "body": "Unauthorized Request", "http_status": 401 } - allow_object = response { - input.parsed_path = [ "allow", "structured" ] + allow_object := response { + input.parsed_path == [ "allow", "structured" ] response := { "allowed": true, "headers": { @@ -477,7 +502,7 @@ func TestAuthorizeRequestFilter(t *testing.T) { "headers": "bogus string instead of object" } - default allow_body = false + default allow_body := false allow_body { input.parsed_body.target_id == "123456" @@ -485,7 +510,7 @@ func TestAuthorizeRequestFilter(t *testing.T) { decision_id := input.attributes.metadataContext.filterMetadata.open_policy_agent.decision_id - allow_object_decision_id_in_header = response { + allow_object_decision_id_in_header := response { input.parsed_path = ["allow", "structured"] decision_id response := { diff --git a/filters/openpolicyagent/opaserveresponse/opaserveresponse_test.go b/filters/openpolicyagent/opaserveresponse/opaserveresponse_test.go index 89c4e611d8..6809ceb9b3 100644 --- a/filters/openpolicyagent/opaserveresponse/opaserveresponse_test.go +++ b/filters/openpolicyagent/opaserveresponse/opaserveresponse_test.go @@ -77,7 +77,7 @@ func TestServerResponseFilter(t *testing.T) { regoQuery: "envoy/authz/allow_object", requestPath: "/allow/structured/with-empty-query-string?", expectedStatus: http.StatusOK, - expectedBody: "Welcome from policy!", + expectedBody: "Welcome from policy with empty query string!", expectedHeaders: map[string][]string{"X-Ext-Auth-Allow": {"yes"}}, }, { @@ -87,7 +87,7 @@ func TestServerResponseFilter(t *testing.T) { regoQuery: "envoy/authz/allow_object", requestPath: "/allow/structured/with-query?pass=yes", expectedStatus: http.StatusOK, - expectedBody: "Welcome from policy!", + expectedBody: "Welcome from policy with query params!", expectedHeaders: map[string][]string{"X-Ext-Auth-Allow": {"yes"}}, }, { @@ -172,21 +172,21 @@ func TestServerResponseFilter(t *testing.T) { "main.rego": ` package envoy.authz - default allow = false + default allow := false allow { - input.parsed_path = [ "allow" ] + input.parsed_path == [ "allow" ] } - default allow_object = { + default allow_object := { "allowed": false, "headers": {"x-ext-auth-allow": "no"}, "body": "Unauthorized Request", "http_status": 403 } - allow_object = response { - input.parsed_path = [ "allow", "structured" ] + allow_object := response { + input.parsed_path == [ "allow", "structured" ] response := { "allowed": true, "headers": {"x-ext-auth-allow": "yes"}, @@ -195,30 +195,30 @@ func TestServerResponseFilter(t *testing.T) { } } - allow_object = response { - input.parsed_path = [ "allow", "structured", "with-empty-query-string" ] + allow_object := response { + input.parsed_path == [ "allow", "structured", "with-empty-query-string" ] input.parsed_query == {} response := { "allowed": true, "headers": {"x-ext-auth-allow": "yes"}, - "body": "Welcome from policy!", + "body": "Welcome from policy with empty query string!", "http_status": 200 } } - allow_object = response { - input.parsed_path = [ "allow", "structured", "with-query" ] + allow_object := response { + input.parsed_path == [ "allow", "structured", "with-query" ] input.parsed_query.pass == ["yes"] response := { "allowed": true, "headers": {"x-ext-auth-allow": "yes"}, - "body": "Welcome from policy!", + "body": "Welcome from policy with query params!", "http_status": 200 } } - allow_object = response { - input.parsed_path = [ "allow", "production" ] + allow_object := response { + input.parsed_path == [ "allow", "production" ] opa.runtime().config.labels.environment == "production" response := { "allowed": true, @@ -228,8 +228,8 @@ func TestServerResponseFilter(t *testing.T) { } } - allow_object = response { - input.parsed_path = [ "allow", "test" ] + allow_object := response { + input.parsed_path == [ "allow", "test" ] opa.runtime().config.labels.environment == "test" response := { "allowed": true, @@ -239,8 +239,8 @@ func TestServerResponseFilter(t *testing.T) { } } - allow_object_structured_body = response { - input.parsed_path = [ "allow", "structured" ] + allow_object_structured_body := response { + input.parsed_path == [ "allow", "structured" ] response := { "allowed": true, "headers": {"x-ext-auth-allow": "yes"}, @@ -249,8 +249,8 @@ func TestServerResponseFilter(t *testing.T) { } } - allow_object_contextextensions = response { - input.parsed_path = [ "allow", "structured" ] + allow_object_contextextensions := response { + input.parsed_path == [ "allow", "structured" ] response := { "allowed": true, "headers": {"x-ext-auth-allow": "yes"}, @@ -259,7 +259,7 @@ func TestServerResponseFilter(t *testing.T) { } } - allow_object_req_body = response { + allow_object_req_body := response { response := { "allowed": true, "headers": {}, diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile index 1ff2bf3c2b..b86df9f9a5 100644 --- a/fuzz/Dockerfile +++ b/fuzz/Dockerfile @@ -1,4 +1,4 @@ -FROM amazonlinux:2023@sha256:5cb6ab1a1a13f33425b6c660a45f06298e204a22df1f9eeefe69cda3735d9757 +FROM amazonlinux:2023@sha256:1b091808a98a0a1b0570073421866f5a76adfa43e8d7a42b2f5dd0c60053a567 WORKDIR /workspace diff --git a/packaging/Dockerfile.arm64 b/packaging/Dockerfile.arm64 index 5248307777..d722f2f7e9 100644 --- a/packaging/Dockerfile.arm64 +++ b/packaging/Dockerfile.arm64 @@ -1,4 +1,4 @@ -FROM --platform=linux/arm64 alpine@sha256:21dc6063fd678b478f57c0e13f47560d0ea4eeba26dfc947b2a4f81f686b9f45 +FROM --platform=linux/arm64 alpine@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099 LABEL maintainer="Team Gateway&Proxy @ Zalando SE " RUN apk --no-cache add ca-certificates && update-ca-certificates ADD build/linux/arm64/skipper \ diff --git a/packaging/Dockerfile.armv7 b/packaging/Dockerfile.armv7 index 8fe85748e6..d2ec131224 100644 --- a/packaging/Dockerfile.armv7 +++ b/packaging/Dockerfile.armv7 @@ -1,4 +1,4 @@ -FROM --platform=linux/arm/v7 alpine@sha256:21dc6063fd678b478f57c0e13f47560d0ea4eeba26dfc947b2a4f81f686b9f45 +FROM --platform=linux/arm/v7 alpine@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099 LABEL maintainer="Team Gateway&Proxy @ Zalando SE " RUN apk --no-cache add ca-certificates && update-ca-certificates ADD build/linux/arm/v7/skipper \ diff --git a/skipper.go b/skipper.go index cea8901b8e..d9fd7f6e92 100644 --- a/skipper.go +++ b/skipper.go @@ -1630,6 +1630,7 @@ func run(o Options, sig chan os.Signal, idleConnsCH chan struct{}) error { Timeout: o.OAuthTokeninfoTimeout, MaxIdleConns: o.IdleConnectionsPerHost, Tracer: tracer, + Metrics: mtr, CacheSize: o.OAuthTokeninfoCacheSize, CacheTTL: o.OAuthTokeninfoCacheTTL, }