Skip to content

Commit d304feb

Browse files
committed
auth: refactor jwks cache to support dynamic issuer registration
Signed-off-by: Aaron Wilson <aawilson@nvidia.com>
1 parent 4e2fb00 commit d304feb

File tree

6 files changed

+327
-230
lines changed

6 files changed

+327
-230
lines changed

ais/proxy.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,6 +3086,7 @@ func (p *proxy) Stop(err error) {
30863086
xreg.AbortAll(errors.New("p-stop"))
30873087

30883088
p.htrun.stop(&sync.WaitGroup{}, !isPrimary && smap.isValid() && !isEnu /*rmFromSmap*/)
3089+
p.authn.stop()
30893090
}
30903091

30913092
// on a best-effort basis, ignoring errors and bodyclose

ais/prxauth.go

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ type (
3434
tokenMap *shardedTokenMap
3535
// provides thread-safe access to an underlying map of tokens
3636
revokedTokens *RevokedTokensMap
37+
// for canceling internal long-lived context
38+
cancelCtx context.CancelFunc
3739
}
3840

3941
RevokedTokensMap struct {
@@ -64,46 +66,76 @@ const (
6466
TokenParserInitTimeout = 10 * time.Second
6567
)
6668

69+
// Client defaults for issuer requests
70+
// Used for JWKS URL discovery and fetching
71+
// See cmn/client.go
72+
const (
73+
// KeyCacheDialTimeout and KeyCacheTimeout are set for faster proxy startup in case of an unresponsive issuer service
74+
KeyCacheDialTimeout = 5 * time.Second
75+
KeyCacheTimeout = 10 * time.Second
76+
77+
// KeyCacheIdleConnsPerHost overrides AIS client settings to match http.Transport.DefaultMaxIdleConnsPerHost
78+
// Because of cached key sets, we don't expect to need idle connections to the same issuer host
79+
KeyCacheIdleConnsPerHost = 2
80+
// KeyCacheMaxIdleConnsLimit caps the maximum idle conns based on number of allowed issuers
81+
KeyCacheMaxIdleConnsLimit = 16
82+
)
83+
6784
/////////////////
6885
// authManager //
6986
/////////////////
7087

7188
func newAuthManager(config *cmn.Config) *authManager {
72-
parser := tok.NewTokenParser(&config.Auth, getJWKSClientConf(config), nil)
73-
cancelCtx, cancel := context.WithTimeout(context.Background(), TokenParserInitTimeout)
89+
rootCtx, rootCancel := context.WithCancel(context.Background())
90+
keyCacheClient := newKeyCacheClient(config)
91+
keyCacheManager := tok.NewKeyCacheManager(config.Auth.OIDC, keyCacheClient, nil)
92+
keyCacheManager.Init(rootCtx)
93+
timeoutCtx, cancel := context.WithTimeout(context.Background(), TokenParserInitTimeout)
7494
defer cancel()
75-
if err := parser.InitKeyCache(cancelCtx); err != nil {
76-
// TODO: Add dynamic cache registration so we can proceed from this init failure and resolve later
77-
cos.ExitLogf("Auth manager error: %v", err)
95+
if err := keyCacheManager.PopulateJWKSCache(timeoutCtx); err != nil {
96+
nlog.Errorf("Errors occurred while pre-populating JWKS key cache: %v", err)
7897
}
7998
return &authManager{
80-
tokenParser: parser,
99+
tokenParser: tok.NewTokenParser(&config.Auth, keyCacheManager),
81100
tokenMap: newShardedTokenMap(TokenMapShardExponent),
82101
revokedTokens: newRevokedTokensMap(),
102+
cancelCtx: rootCancel,
83103
}
84104
}
85105

86-
// Define the config for JWKS client used by the token parser
87-
func getJWKSClientConf(config *cmn.Config) (jwksConf *tok.JWKSClientConf) {
106+
// Define the client used by the key cache manager for contacting token issuers
107+
func newKeyCacheClient(config *cmn.Config) *http.Client {
108+
var tls cmn.TLSArgs
88109
// Set our own certificate, key, and verification settings from AIS network config
89-
var tlsArgs cmn.TLSArgs
90110
if config.Net.HTTP.UseHTTPS {
91-
tlsArgs = config.Net.HTTP.ToTLS()
111+
tls = config.Net.HTTP.ToTLS()
92112
} else {
93-
tlsArgs = cmn.TLSArgs{
113+
tls = cmn.TLSArgs{
94114
SkipVerify: false,
95115
}
96116
}
97-
if config.Auth.OIDC != nil {
98-
// Define the trusted CA for issuers
99-
tlsArgs.ClientCA = config.Auth.OIDC.IssuerCA
117+
// Override the trusted CA for issuers if location provided
118+
if config.Auth.OIDC != nil && config.Auth.OIDC.IssuerCA != "" {
119+
tls.ClientCA = config.Auth.OIDC.IssuerCA
120+
}
121+
// Key cache client should never need more idle connections than configured issuers
122+
// Set MaxIdleConns to limit the idle connections kept to issuers when we don't expect any subsequent requests
123+
maxIdleConns := KeyCacheIdleConnsPerHost
124+
if config.Auth.OIDC != nil && len(config.Auth.OIDC.AllowedIssuers) > maxIdleConns {
125+
maxIdleConns = min(len(config.Auth.OIDC.AllowedIssuers), KeyCacheMaxIdleConnsLimit)
100126
}
101127

102-
// Leave transport args empty for default config
103-
clientConf := &tok.JWKSClientConf{
104-
TLSArgs: &tlsArgs,
128+
transport := cmn.TransportArgs{
129+
DialTimeout: KeyCacheDialTimeout,
130+
Timeout: KeyCacheTimeout,
131+
IdleConnsPerHost: KeyCacheIdleConnsPerHost,
132+
MaxIdleConns: maxIdleConns,
105133
}
106-
return clientConf
134+
return cmn.NewClientTLS(transport, tls, false)
135+
}
136+
137+
func (a *authManager) stop() {
138+
a.cancelCtx()
107139
}
108140

109141
// Add tokens to the list of invalid ones and clean up the list from expired tokens.

cmd/authn/mgr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func newMgr(driver kvdb.Driver) (m *mgr, code int, err error) {
6161
// Create a limited token parser that only validates against a symmetric key with no issuer lookup
6262
// TODO: Support RSA keys in authN and issuer lookup with cert verification
6363
sigConf := &cmn.AuthSignatureConf{Key: Conf.Secret(), Method: cmn.SigMethodHMAC}
64-
m.tkParser = tok.NewTokenParser(&cmn.AuthConf{Signature: sigConf}, nil, nil)
64+
m.tkParser = tok.NewTokenParser(&cmn.AuthConf{Signature: sigConf}, nil)
6565
return
6666
}
6767

0 commit comments

Comments
 (0)