mirror of
https://github.com/openziti/zrok.git
synced 2025-06-26 12:42:18 +02:00
start of the secrets cache (based on sturdyc) (#987)
This commit is contained in:
parent
a993ddabda
commit
4c5f3e77e3
@ -3,6 +3,7 @@ package publicProxy
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"time"
|
||||
|
||||
"github.com/michaelquigley/cf"
|
||||
"github.com/openziti/zrok/endpoints"
|
||||
@ -22,6 +23,7 @@ type Config struct {
|
||||
Interstitial *InterstitialConfig
|
||||
Oauth *OauthConfig
|
||||
SecretsAccess *SecretsAccessConfig
|
||||
SecretsCache *SecretsCacheConfig
|
||||
Tls *endpoints.TlsConfig
|
||||
}
|
||||
|
||||
@ -57,6 +59,13 @@ type SecretsAccessConfig struct {
|
||||
ServiceName string
|
||||
}
|
||||
|
||||
type SecretsCacheConfig struct {
|
||||
Capacity int
|
||||
Shards int
|
||||
TTL time.Duration
|
||||
EvictionPercentage int
|
||||
}
|
||||
|
||||
func (p *OauthProviderConfig) GetEndpoint() oauth2.Endpoint {
|
||||
return oauth2.Endpoint{
|
||||
AuthURL: p.AuthURL,
|
||||
@ -68,6 +77,12 @@ func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Identity: "public",
|
||||
Address: "0.0.0.0:8080",
|
||||
SecretsCache: &SecretsCacheConfig{
|
||||
Capacity: 10000,
|
||||
Shards: 10,
|
||||
TTL: 2 * time.Hour,
|
||||
EvictionPercentage: 10,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,18 +153,18 @@ func hostTargetReverseProxy(cfg *Config, ctx ziti.Context) *httputil.ReverseProx
|
||||
return &httputil.ReverseProxy{Director: director}
|
||||
}
|
||||
|
||||
func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Context) http.HandlerFunc {
|
||||
func shareHandler(handler http.Handler, cfg *Config, key []byte, ctx ziti.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
shrToken := resolveService(pcfg.HostMatch, r.Host)
|
||||
shrToken := resolveService(cfg.HostMatch, r.Host)
|
||||
if shrToken != "" {
|
||||
if svc, found := endpoints.GetRefreshedService(shrToken, ctx); found {
|
||||
if cfg, found := svc.Config[sdk.ZrokProxyConfig]; found {
|
||||
if r.Method != http.MethodOptions && (pcfg.Interstitial != nil && pcfg.Interstitial.Enabled) {
|
||||
if proxyConfig, found := svc.Config[sdk.ZrokProxyConfig]; found {
|
||||
if r.Method != http.MethodOptions && (cfg.Interstitial != nil && cfg.Interstitial.Enabled) {
|
||||
sendInterstitial := true
|
||||
if len(pcfg.Interstitial.UserAgentPrefixes) > 0 {
|
||||
if len(cfg.Interstitial.UserAgentPrefixes) > 0 {
|
||||
ua := r.Header.Get("User-Agent")
|
||||
matched := false
|
||||
for _, prefix := range pcfg.Interstitial.UserAgentPrefixes {
|
||||
for _, prefix := range cfg.Interstitial.UserAgentPrefixes {
|
||||
if strings.HasPrefix(ua, prefix) {
|
||||
matched = true
|
||||
break
|
||||
@ -175,13 +175,13 @@ func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Conte
|
||||
}
|
||||
}
|
||||
if sendInterstitial {
|
||||
if v, istlFound := cfg["interstitial"]; istlFound {
|
||||
if v, istlFound := proxyConfig["interstitial"]; istlFound {
|
||||
if istlEnabled, ok := v.(bool); ok && istlEnabled {
|
||||
skip := r.Header.Get("skip_zrok_interstitial")
|
||||
_, zrokOkErr := r.Cookie("zrok_interstitial")
|
||||
if skip == "" && zrokOkErr != nil {
|
||||
logrus.Debugf("forcing interstitial for '%v'", r.URL)
|
||||
interstitialUi.WriteInterstitialAnnounce(w, pcfg.Interstitial.HtmlPath)
|
||||
interstitialUi.WriteInterstitialAnnounce(w, cfg.Interstitial.HtmlPath)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -189,7 +189,7 @@ func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Conte
|
||||
}
|
||||
}
|
||||
|
||||
if scheme, found := cfg["auth_scheme"]; found {
|
||||
if scheme, found := proxyConfig["auth_scheme"]; found {
|
||||
switch scheme {
|
||||
case string(sdk.None):
|
||||
logrus.Debugf("auth scheme none '%v'", shrToken)
|
||||
@ -206,7 +206,7 @@ func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Conte
|
||||
return
|
||||
}
|
||||
authed := false
|
||||
if v, found := cfg["basic_auth"]; found {
|
||||
if v, found := proxyConfig["basic_auth"]; found {
|
||||
if basicAuth, ok := v.(map[string]interface{}); ok {
|
||||
if v, found := basicAuth["users"]; found {
|
||||
if arr, ok := v.([]interface{}); ok {
|
||||
@ -247,7 +247,7 @@ func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Conte
|
||||
case string(sdk.Oauth):
|
||||
logrus.Debugf("auth scheme oauth '%v'", shrToken)
|
||||
|
||||
if oauthCfg, found := cfg["oauth"]; found {
|
||||
if oauthCfg, found := proxyConfig["oauth"]; found {
|
||||
if provider, found := oauthCfg.(map[string]interface{})["provider"]; found {
|
||||
var authCheckInterval time.Duration
|
||||
if checkInterval, found := oauthCfg.(map[string]interface{})["authorization_check_interval"]; !found {
|
||||
@ -268,34 +268,34 @@ func shareHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Conte
|
||||
cookie, err := r.Cookie("zrok-access")
|
||||
if err != nil {
|
||||
logrus.Errorf("unable to get 'zrok-access' cookie: %v", err)
|
||||
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
oauthLoginRequired(w, r, cfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
return
|
||||
}
|
||||
tkn, err := jwt.ParseWithClaims(cookie.Value, &ZrokClaims{}, func(t *jwt.Token) (interface{}, error) {
|
||||
if pcfg.Oauth == nil {
|
||||
if cfg.Oauth == nil {
|
||||
return nil, fmt.Errorf("missing oauth configuration for access point; unable to parse jwt")
|
||||
}
|
||||
return key, nil
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Errorf("unable to parse jwt: %v", err)
|
||||
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
oauthLoginRequired(w, r, cfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
return
|
||||
}
|
||||
claims := tkn.Claims.(*ZrokClaims)
|
||||
if claims.Provider != provider {
|
||||
logrus.Error("provider mismatch; restarting auth flow")
|
||||
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
oauthLoginRequired(w, r, cfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
return
|
||||
}
|
||||
if claims.AuthorizationCheckInterval != authCheckInterval {
|
||||
logrus.Error("authorization check interval mismatch; restarting auth flow")
|
||||
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
oauthLoginRequired(w, r, cfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
return
|
||||
}
|
||||
if claims.Audience != r.Host {
|
||||
logrus.Errorf("audience claim '%s' does not match requested host '%s'; restarting auth flow", claims.Audience, r.Host)
|
||||
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
oauthLoginRequired(w, r, cfg.Oauth, provider.(string), target, authCheckInterval)
|
||||
return
|
||||
}
|
||||
|
||||
|
60
endpoints/publicProxy/secretsAccess.go
Normal file
60
endpoints/publicProxy/secretsAccess.go
Normal file
@ -0,0 +1,60 @@
|
||||
package publicProxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/openziti/sdk-golang/ziti"
|
||||
"github.com/openziti/zrok/controller/secretsGrpc"
|
||||
"github.com/viccon/sturdyc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
type Secret struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func GetSecrets(shareToken string, cfg *Config) ([]Secret, error) {
|
||||
cacheClient := sturdyc.New[[]Secret](cfg.SecretsCache.Capacity, cfg.SecretsCache.Shards, cfg.SecretsCache.TTL, cfg.SecretsCache.EvictionPercentage)
|
||||
fetch := func(ctx context.Context) ([]Secret, error) {
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
zcfg, err := ziti.NewConfigFromFile(cfg.SecretsAccess.IdentityPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zctx, err := ziti.NewContext(zcfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := zctx.DialWithOptions(addr, &ziti.DialOptions{ConnectTimeout: 30 * time.Second})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
}
|
||||
resolver.SetDefaultScheme("passthrough")
|
||||
conn, err := grpc.NewClient(cfg.SecretsAccess.ServiceName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
client := secretsGrpc.NewSecretsClient(conn)
|
||||
resp, err := client.FetchSecrets(ctx, &secretsGrpc.SecretsRequest{ShareToken: shareToken})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var secrets []Secret
|
||||
for _, secret := range resp.GetSecrets() {
|
||||
secrets = append(secrets, Secret{Key: secret.Key, Value: secret.Value})
|
||||
}
|
||||
return secrets, nil
|
||||
}
|
||||
return cacheClient.GetOrFetch(context.Background(), shareToken, fetch)
|
||||
}
|
1
go.mod
1
go.mod
@ -55,6 +55,7 @@ require (
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/viccon/sturdyc v1.1.5
|
||||
github.com/wneessen/go-mail v0.2.7
|
||||
github.com/zitadel/oidc/v3 v3.39.0
|
||||
go.uber.org/zap v1.27.0
|
||||
|
2
go.sum
2
go.sum
@ -940,6 +940,8 @@ github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOH
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/viccon/sturdyc v1.1.5 h1:GLQDnsyKt3L/tpdWCIARIRefn+5DAyvqu+0irBwt+vk=
|
||||
github.com/viccon/sturdyc v1.1.5/go.mod h1:OCBEgG/i48uugKQ498UQlfMHmf5j8MYY8a4BApfVnMo=
|
||||
github.com/wneessen/go-mail v0.2.7 h1:4gj1flZjm05htmVj8AS6TbYXLQBYabzuQMmu8pZc/Js=
|
||||
github.com/wneessen/go-mail v0.2.7/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
|
Loading…
x
Reference in New Issue
Block a user