[dashboard] Verify JWT token
## What this PR does When OIDC is disabled, the dashboard's token-proxy now properly validates bearer tokens against the k8s API's JWKS url. ### Release note ```release-note [dashboard] Verify bearer tokens against the issuer's JWKS url. ``` Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
This commit is contained in:
parent
4fa7eed058
commit
23e399bd9a
5 changed files with 258 additions and 49 deletions
|
|
@ -3,6 +3,21 @@ module token-proxy
|
|||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/gorilla/securecookie v1.1.2
|
||||
github.com/lestrrat-go/httprc/v3 v3.0.2
|
||||
github.com/lestrrat-go/jwx/v3 v3.0.13
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||
github.com/lestrrat-go/dsig v1.0.0 // indirect
|
||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
|
||||
github.com/segmentio/asm v1.2.1 // indirect
|
||||
github.com/valyala/fastjson v1.6.7 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,43 @@
|
|||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
|
||||
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
|
||||
github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38=
|
||||
github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo=
|
||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY=
|
||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
|
||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/httprc/v3 v3.0.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0=
|
||||
github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
|
||||
github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk=
|
||||
github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU=
|
||||
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
|
||||
github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM=
|
||||
github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
|
|
@ -13,10 +16,13 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/lestrrat-go/httprc/v3"
|
||||
"github.com/lestrrat-go/jwx/v3/jwk"
|
||||
"github.com/lestrrat-go/jwx/v3/jwt"
|
||||
)
|
||||
|
||||
/* ----------------------------- flags ------------------------------------ */
|
||||
|
|
@ -26,7 +32,9 @@ var (
|
|||
cookieName, cookieSecretB64 string
|
||||
cookieSecure bool
|
||||
cookieRefresh time.Duration
|
||||
tokenCheckURL string
|
||||
jwksURL string
|
||||
saTokenPath string
|
||||
saCACertPath string
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -38,7 +46,70 @@ func init() {
|
|||
flag.StringVar(&cookieSecretB64, "cookie-secret", "", "Base64-encoded cookie secret")
|
||||
flag.BoolVar(&cookieSecure, "cookie-secure", false, "Set Secure flag on cookie")
|
||||
flag.DurationVar(&cookieRefresh, "cookie-refresh", 0, "Cookie refresh interval (e.g. 1h)")
|
||||
flag.StringVar(&tokenCheckURL, "token-check-url", "", "URL for external token validation")
|
||||
flag.StringVar(&jwksURL, "jwks-url", "https://kubernetes.default.svc/openid/v1/jwks", "JWKS URL for token verification")
|
||||
flag.StringVar(&saTokenPath, "sa-token-path", "/var/run/secrets/kubernetes.io/serviceaccount/token", "Path to service account token")
|
||||
flag.StringVar(&saCACertPath, "sa-ca-cert-path", "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", "Path to service account CA certificate")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// Initialize jwkCache
|
||||
ctx := context.Background()
|
||||
// Load CA certificate
|
||||
caCert, err := os.ReadFile(saCACertPath)
|
||||
if err != nil {
|
||||
jwkCacheErr := fmt.Errorf("failed to read CA cert: %w", err)
|
||||
panic(jwkCacheErr)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||
jwkCacheErr := fmt.Errorf("failed to parse CA cert")
|
||||
panic(jwkCacheErr)
|
||||
}
|
||||
|
||||
// Create transport with SA token injection
|
||||
transport := &saTokenTransport{
|
||||
base: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
},
|
||||
},
|
||||
tokenPath: saTokenPath,
|
||||
}
|
||||
transport.startRefresh(ctx, 5*time.Minute)
|
||||
|
||||
httpClient := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Create httprc client with custom HTTP client
|
||||
httprcClient := httprc.NewClient(
|
||||
httprc.WithHTTPClient(httpClient),
|
||||
)
|
||||
|
||||
// Create JWK cache
|
||||
jwkCache, err = jwk.NewCache(ctx, httprcClient)
|
||||
if err != nil {
|
||||
jwkCacheErr := fmt.Errorf("failed to create JWK cache: %w", err)
|
||||
panic(jwkCacheErr)
|
||||
}
|
||||
|
||||
// Register the JWKS URL with refresh settings
|
||||
if err := jwkCache.Register(ctx, jwksURL,
|
||||
jwk.WithMinInterval(5*time.Minute),
|
||||
jwk.WithMaxInterval(15*time.Minute),
|
||||
); err != nil {
|
||||
jwkCacheErr := fmt.Errorf("failed to register JWKS URL: %w", err)
|
||||
panic(jwkCacheErr)
|
||||
}
|
||||
|
||||
// Perform initial fetch to ensure the JWKS is available
|
||||
if _, err := jwkCache.Refresh(ctx, jwksURL); err != nil {
|
||||
jwkCacheErr := fmt.Errorf("failed to fetch initial JWKS: %w", err)
|
||||
panic(jwkCacheErr)
|
||||
}
|
||||
|
||||
log.Printf("JWK cache initialized with JWKS URL: %s", jwksURL)
|
||||
}
|
||||
|
||||
/* ----------------------------- templates -------------------------------- */
|
||||
|
|
@ -117,42 +188,94 @@ var loginTmpl = template.Must(template.New("login").Parse(`
|
|||
</body>
|
||||
</html>`))
|
||||
|
||||
/* ----------------------------- helpers ---------------------------------- */
|
||||
/* ----------------------------- JWK cache -------------------------------- */
|
||||
|
||||
func decodeJWT(raw string) jwt.MapClaims {
|
||||
if raw == "" {
|
||||
return jwt.MapClaims{}
|
||||
}
|
||||
tkn, _, err := new(jwt.Parser).ParseUnverified(raw, jwt.MapClaims{})
|
||||
if err != nil || tkn == nil {
|
||||
return jwt.MapClaims{}
|
||||
}
|
||||
if c, ok := tkn.Claims.(jwt.MapClaims); ok {
|
||||
return c
|
||||
}
|
||||
return jwt.MapClaims{}
|
||||
var (
|
||||
jwkCache *jwk.Cache
|
||||
)
|
||||
|
||||
// saTokenTransport adds the service account token to requests and refreshes it periodically.
|
||||
type saTokenTransport struct {
|
||||
base http.RoundTripper
|
||||
tokenPath string
|
||||
mu sync.RWMutex
|
||||
token string
|
||||
}
|
||||
|
||||
func externalTokenCheck(raw string) error {
|
||||
if tokenCheckURL == "" {
|
||||
func (t *saTokenTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
t.mu.RLock()
|
||||
token := t.token
|
||||
t.mu.RUnlock()
|
||||
|
||||
if token != "" {
|
||||
req = req.Clone(req.Context())
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
return t.base.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (t *saTokenTransport) refreshToken() {
|
||||
data, err := os.ReadFile(t.tokenPath)
|
||||
if err != nil {
|
||||
log.Printf("warning: failed to read SA token: %v", err)
|
||||
return
|
||||
}
|
||||
t.mu.Lock()
|
||||
t.token = string(data)
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
func (t *saTokenTransport) startRefresh(ctx context.Context, interval time.Duration) {
|
||||
t.refreshToken()
|
||||
go func() {
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
t.refreshToken()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
/* ----------------------------- helpers ---------------------------------- */
|
||||
|
||||
// verifyAndParseJWT verifies the token signature and returns the parsed token.
|
||||
func verifyAndParseJWT(ctx context.Context, raw string) (jwt.Token, error) {
|
||||
if raw == "" {
|
||||
return nil, fmt.Errorf("empty token")
|
||||
}
|
||||
|
||||
keySet, err := jwkCache.Lookup(ctx, jwksURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get JWKS: %w", err)
|
||||
}
|
||||
|
||||
token, err := jwt.Parse([]byte(raw), jwt.WithKeySet(keySet))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify token: %w", err)
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// getClaim extracts a claim value from a verified token.
|
||||
func getClaim(token jwt.Token, key string) any {
|
||||
if token == nil {
|
||||
return nil
|
||||
}
|
||||
req, _ := http.NewRequest(http.MethodGet, tokenCheckURL, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+raw)
|
||||
cli := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := cli.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
var val any
|
||||
if err := token.Get(key, &val); err != nil {
|
||||
return nil
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("status %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
return val
|
||||
}
|
||||
|
||||
func encodeSession(sc *securecookie.SecureCookie, token string, exp, issued int64) (string, error) {
|
||||
v := map[string]interface{}{
|
||||
v := map[string]any{
|
||||
"access_token": token,
|
||||
"expires": exp,
|
||||
"issued": issued,
|
||||
|
|
@ -166,7 +289,6 @@ func encodeSession(sc *securecookie.SecureCookie, token string, exp, issued int6
|
|||
/* ----------------------------- main ------------------------------------- */
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if upstream == "" {
|
||||
log.Fatal("--upstream is required")
|
||||
}
|
||||
|
|
@ -214,7 +336,11 @@ func main() {
|
|||
}{Action: signIn, Err: "Token required"})
|
||||
return
|
||||
}
|
||||
if err := externalTokenCheck(token); err != nil {
|
||||
|
||||
// Verify token signature using JWKS
|
||||
verifiedToken, err := verifyAndParseJWT(r.Context(), token)
|
||||
if err != nil {
|
||||
log.Printf("token verification failed: %v", err)
|
||||
_ = loginTmpl.Execute(w, struct {
|
||||
Action string
|
||||
Err string
|
||||
|
|
@ -223,9 +349,8 @@ func main() {
|
|||
}
|
||||
|
||||
exp := time.Now().Add(24 * time.Hour).Unix()
|
||||
claims := decodeJWT(token)
|
||||
if v, ok := claims["exp"].(float64); ok {
|
||||
exp = int64(v)
|
||||
if expTime, ok := verifiedToken.Expiration(); ok && !expTime.IsZero() {
|
||||
exp = expTime.Unix()
|
||||
}
|
||||
session, _ := encodeSession(sc, token, exp, time.Now().Unix())
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
|
|
@ -264,7 +389,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
var token string
|
||||
var sess map[string]interface{}
|
||||
var sess map[string]any
|
||||
if sc != nil {
|
||||
if err := sc.Decode(cookieName, c.Value, &sess); err != nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
|
|
@ -273,19 +398,25 @@ func main() {
|
|||
token, _ = sess["access_token"].(string)
|
||||
} else {
|
||||
token = c.Value
|
||||
sess = map[string]interface{}{
|
||||
sess = map[string]any{
|
||||
"expires": time.Now().Add(24 * time.Hour).Unix(),
|
||||
"issued": time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
claims := decodeJWT(token)
|
||||
|
||||
out := map[string]interface{}{
|
||||
// Re-verify the token to ensure it's still valid
|
||||
verifiedToken, err := verifyAndParseJWT(r.Context(), token)
|
||||
if err != nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
out := map[string]any{
|
||||
"token": token,
|
||||
"sub": claims["sub"],
|
||||
"email": claims["email"],
|
||||
"preferred_username": claims["preferred_username"],
|
||||
"groups": claims["groups"],
|
||||
"sub": getClaim(verifiedToken, "sub"),
|
||||
"email": getClaim(verifiedToken, "email"),
|
||||
"preferred_username": getClaim(verifiedToken, "preferred_username"),
|
||||
"groups": getClaim(verifiedToken, "groups"),
|
||||
"expires": sess["expires"],
|
||||
"issued": sess["issued"],
|
||||
"cookie_refresh_enable": cookieRefresh > 0,
|
||||
|
|
@ -303,7 +434,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
var token string
|
||||
var sess map[string]interface{}
|
||||
var sess map[string]any
|
||||
if sc != nil {
|
||||
if err := sc.Decode(cookieName, c.Value, &sess); err != nil {
|
||||
http.Redirect(w, r, signIn, http.StatusFound)
|
||||
|
|
@ -312,7 +443,7 @@ func main() {
|
|||
token, _ = sess["access_token"].(string)
|
||||
} else {
|
||||
token = c.Value
|
||||
sess = map[string]interface{}{
|
||||
sess = map[string]any{
|
||||
"expires": time.Now().Add(24 * time.Hour).Unix(),
|
||||
"issued": time.Now().Unix(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,30 @@ apiVersion: v1
|
|||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: incloud-web-gatekeeper
|
||||
{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }}
|
||||
{{- if ne $oidcEnabled "true" }}
|
||||
---
|
||||
# ClusterRole to allow token-proxy to fetch JWKS for JWT verification
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: incloud-web-gatekeeper-jwks
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /openid/v1/jwks
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: incloud-web-gatekeeper-jwks
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: incloud-web-gatekeeper-jwks
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: incloud-web-gatekeeper
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ spec:
|
|||
- --cookie-name=kc-access
|
||||
- --cookie-secure=true
|
||||
- --cookie-secret=$(TOKEN_PROXY_COOKIE_SECRET)
|
||||
- --token-check-url=http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080/api/clusters/default/k8s/apis/core.cozystack.io/v1alpha1/tenantnamespaces
|
||||
env:
|
||||
- name: TOKEN_PROXY_COOKIE_SECRET
|
||||
valueFrom:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue