From 7ea3e6668f3e1316f01543bb6e72167ba80eb519 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:19:28 +0900 Subject: [PATCH 01/12] derived token cache Signed-off-by: myajima --- pkg/config/config.go | 16 ++++---- pkg/config/default.go | 7 ++-- pkg/config/derived-access-token.go | 29 -------------- pkg/config/derived-target-domain-roles.go | 5 +-- pkg/config/dervied.go | 7 ++-- pkg/config/model.go | 10 +++-- pkg/token/server.go | 10 ++--- pkg/token/service.go | 47 +++++++++++------------ 8 files changed, 50 insertions(+), 81 deletions(-) delete mode 100644 pkg/config/derived-access-token.go diff --git a/pkg/config/config.go b/pkg/config/config.go index 773f9154..f1a83e99 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -108,7 +108,7 @@ func (idCfg *IdentityConfig) loadFromENV() error { loadEnv("TOKEN_SERVER_TLS_CA_PATH", &idCfg.TokenServerTLSCAPath) loadEnv("TOKEN_SERVER_TLS_CERT_PATH", &idCfg.TokenServerTLSCertPath) loadEnv("TOKEN_SERVER_TLS_KEY_PATH", &idCfg.TokenServerTLSKeyPath) - loadEnv("TOKEN_DIR", &idCfg.TokenDir) + loadEnv("TOKEN_DIR", &idCfg.tokenDir) loadEnv("METRICS_SERVER_ADDR", &idCfg.MetricsServerAddr) loadEnv("DELETE_INSTANCE_ID", &idCfg.rawDeleteInstanceID) loadEnv("USE_TOKEN_SERVER", &idCfg.rawUseTokenServer) @@ -142,11 +142,11 @@ func (idCfg *IdentityConfig) loadFromENV() error { if err != nil { return fmt.Errorf("Invalid ROLE_CERT_OUTPUT_KEY_FILE [%q], %w", idCfg.rawRoleCertKeyFileOutput, err) } - idCfg.TokenRefresh, err = time.ParseDuration(idCfg.rawTokenRefresh) + idCfg.tokenRefresh, err = time.ParseDuration(idCfg.rawTokenRefresh) if err != nil { return fmt.Errorf("Invalid TOKEN_REFRESH_INTERVAL [%q], %w", idCfg.rawTokenRefresh, err) } - idCfg.TokenExpiry, err = time.ParseDuration(idCfg.rawTokenExpiry) + idCfg.tokenExpiry, err = time.ParseDuration(idCfg.rawTokenExpiry) if err != nil { return fmt.Errorf("Invalid TOKEN_EXPIRY [%q], %w", idCfg.rawTokenExpiry, err) } @@ -209,15 +209,15 @@ func (idCfg *IdentityConfig) loadFromFlag(program string, args []string) error { f.StringVar(&idCfg.roleCertKeyNamingFormat, "role-cert-key-naming-format", idCfg.roleCertKeyNamingFormat, "The file name format when outputting the role cert key to a file") // RoleAuthHeader f.StringVar(&idCfg.TokenType, "token-type", idCfg.TokenType, "type of the role token to request (\"roletoken\", \"accesstoken\" or \"roletoken+accesstoken\")") - f.DurationVar(&idCfg.TokenRefresh, "token-refresh-interval", idCfg.TokenRefresh, "token refresh interval") - f.DurationVar(&idCfg.TokenExpiry, "token-expiry", idCfg.TokenExpiry, "token expiry duration (0 to use Athenz server's default expiry)") + f.DurationVar(&idCfg.tokenRefresh, "token-refresh-interval", idCfg.tokenRefresh, "token refresh interval") + f.DurationVar(&idCfg.tokenExpiry, "token-expiry", idCfg.tokenExpiry, "token expiry duration (0 to use Athenz server's default expiry)") f.StringVar(&idCfg.TokenServerAddr, "token-server-addr", idCfg.TokenServerAddr, "HTTP server address to provide tokens (required for token provisioning)") f.BoolVar(&idCfg.TokenServerRESTAPI, "token-server-rest-api", idCfg.TokenServerRESTAPI, "enable token server RESTful API (true/false)") f.DurationVar(&idCfg.TokenServerTimeout, "token-server-timeout", idCfg.TokenServerTimeout, "token server timeout (default 3s)") f.StringVar(&idCfg.TokenServerTLSCAPath, "token-server-tls-ca-path", idCfg.TokenServerTLSCAPath, "token server TLS CA path (if set, enable TLS Client Authentication)") f.StringVar(&idCfg.TokenServerTLSCertPath, "token-server-tls-cert-path", idCfg.TokenServerTLSCertPath, "token server TLS certificate path (if empty, disable TLS)") f.StringVar(&idCfg.TokenServerTLSKeyPath, "token-server-tls-key-path", idCfg.TokenServerTLSKeyPath, "token server TLS certificate key path (if empty, disable TLS)") - f.StringVar(&idCfg.TokenDir, "token-dir", idCfg.TokenDir, "directory to write token files") + f.StringVar(&idCfg.tokenDir, "token-dir", idCfg.tokenDir, "directory to write token files") f.StringVar(&idCfg.MetricsServerAddr, "metrics-server-addr", idCfg.MetricsServerAddr, "HTTP server address to provide metrics") f.BoolVar(&idCfg.DeleteInstanceID, "delete-instance-id", idCfg.DeleteInstanceID, "delete x509 certificate record from identity provider on shutdown (true/false)") // Token Server @@ -249,8 +249,8 @@ func (idCfg *IdentityConfig) parseRawValues() (err error) { func (idCfg *IdentityConfig) validateAndInit() (err error) { - if idCfg.TokenExpiry != 0 && idCfg.TokenRefresh >= idCfg.TokenExpiry { - return fmt.Errorf("Invalid TokenRefresh[%s] >= TokenExpiry[%s]", idCfg.TokenRefresh.String(), idCfg.TokenExpiry.String()) + if idCfg.tokenExpiry != 0 && idCfg.tokenRefresh >= idCfg.tokenExpiry { + return fmt.Errorf("Invalid TokenRefresh[%s] >= TokenExpiry[%s]", idCfg.tokenRefresh.String(), idCfg.tokenExpiry.String()) } // TODO: clarify unused logic diff --git a/pkg/config/default.go b/pkg/config/default.go index 36ab0d6d..7b9c47a9 100644 --- a/pkg/config/default.go +++ b/pkg/config/default.go @@ -90,7 +90,6 @@ func DefaultIdentityConfig() *IdentityConfig { PodName: "", Reloader: nil, ServerCACert: "", - TokenTargetDomainRoles: []DomainRole{}, roleCertDir: "", roleCertFilenameDelimiter: DEFAULT_ROLE_CERT_FILENAME_DELIMITER, roleCertKeyFileOutput: false, @@ -98,15 +97,15 @@ func DefaultIdentityConfig() *IdentityConfig { roleCertKeyNamingFormat: "", RoleAuthHeader: DEFAULT_ROLE_AUTH_HEADER, TokenType: "accesstoken", - TokenRefresh: DEFAULT_TOKEN_REFRESH, - TokenExpiry: DEFAULT_TOKEN_EXPIRY, + tokenDir: "", + tokenRefresh: DEFAULT_TOKEN_REFRESH, + tokenExpiry: DEFAULT_TOKEN_EXPIRY, TokenServerAddr: "", TokenServerRESTAPI: false, TokenServerTimeout: DEFAULT_TOKEN_SERVER_TIMEOUT, TokenServerTLSCAPath: "", TokenServerTLSCertPath: "", TokenServerTLSKeyPath: "", - TokenDir: "", MetricsServerAddr: "", HealthCheckAddr: "", HealthCheckEndpoint: "", diff --git a/pkg/config/derived-access-token.go b/pkg/config/derived-access-token.go deleted file mode 100644 index c6e4f190..00000000 --- a/pkg/config/derived-access-token.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2023 LY Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package config defines all the configuration parameters. It reads configuration from environment variables and command-line arguments. -package config - -// type DerivedAccessToken struct { -// Use bool // if fetching access token as files is enabled (de facto standard) -// Dir string // directory to store access token. Usually one, but can be multiple -// TargetDomainRoles []DomainRole // domain roles to fetch access tokens -// Delimiter string -// } - -// // derivedAccessToken ... TODO: Comment -// func (idCfg *IdentityConfig) derivedAccessToken() error { -// // TODO: Write -// return nil -// } diff --git a/pkg/config/derived-target-domain-roles.go b/pkg/config/derived-target-domain-roles.go index 4be54e42..10b28844 100644 --- a/pkg/config/derived-target-domain-roles.go +++ b/pkg/config/derived-target-domain-roles.go @@ -24,7 +24,7 @@ import ( type DerivedTargetDomainRoles struct { roleCerts []DomainRole // private as the derived state is used only within the config package - // tokens []DomainRole // private as the derived state is used only within the config package + tokens []DomainRole // private as the derived state is used only within the config package } // derivedTargetDomainRoles sets the DerivedTargetDomainRoles with the given rawTargetDomainRoles. @@ -63,10 +63,9 @@ func (idCfg *IdentityConfig) derivedTargetDomainRoles() error { }) } - idCfg.TokenTargetDomainRoles = tokenDomainRoles // TODO: Delete me and refactor by using the type DerivedTargetDomainRoles below: idCfg.targetDomainRoles = DerivedTargetDomainRoles{ roleCerts: roleCertDomainRoles, - // tokens: tokenDomainRoles, + tokens: tokenDomainRoles, } return nil diff --git a/pkg/config/dervied.go b/pkg/config/dervied.go index a7893a2b..4e8f0eae 100644 --- a/pkg/config/dervied.go +++ b/pkg/config/dervied.go @@ -39,12 +39,11 @@ func (idCfg *IdentityConfig) loadDerivedConfig() error { return err } - // TODO: // depends on the following: // - derivedTargetDomainRoles() - // if err := idCfg.derivedAccessTokenConfig(); err != nil { - // return err - // } + if err := idCfg.derivedTokenChacheConfig(); err != nil { + return err + } // TODO: // depends on the following: diff --git a/pkg/config/model.go b/pkg/config/model.go index 674b6035..156dfba2 100644 --- a/pkg/config/model.go +++ b/pkg/config/model.go @@ -49,7 +49,6 @@ type IdentityConfig struct { ServerCACert string K8sSecretBackup DerivedK8sSecretBackup ServiceCert DerivedServiceCert - TokenTargetDomainRoles []DomainRole // TODO: Will be migrated into DerivedTargetDomainRoles targetDomainRoles DerivedTargetDomainRoles // private as the derived state is used only within the config package // RoleCerts Derived State and its related fields: RoleCert DerivedRoleCert @@ -59,17 +58,20 @@ type IdentityConfig struct { roleCertNamingFormat string roleCertKeyNamingFormat string // + // Token Cache Derived State and its related fields: + TokenCache DerivedTokenCache + tokenDir string + tokenRefresh time.Duration + tokenExpiry time.Duration + // RoleAuthHeader string TokenType string - TokenRefresh time.Duration - TokenExpiry time.Duration TokenServerAddr string TokenServerRESTAPI bool TokenServerTimeout time.Duration TokenServerTLSCAPath string TokenServerTLSCertPath string TokenServerTLSKeyPath string - TokenDir string MetricsServerAddr string HealthCheckAddr string HealthCheckEndpoint string diff --git a/pkg/token/server.go b/pkg/token/server.go index 49dfa625..b589495d 100644 --- a/pkg/token/server.go +++ b/pkg/token/server.go @@ -90,8 +90,8 @@ func postRoleToken(ts *tokenService, w http.ResponseWriter, r *http.Request) { // if rtRequest.MaxExpiry != nil && *rtRequest.MaxExpiry > 0{ // k.MaxExpiry = *rtRequest.MaxExpiry // } - if k.MinExpiry == 0 && ts.tokenExpiryInSecond > 0 { - k.MinExpiry = ts.tokenExpiryInSecond + if k.MinExpiry == 0 && ts.idCfg.TokenCache.ExpirySeconds > 0 { + k.MinExpiry = ts.idCfg.TokenCache.ExpirySeconds } // cache lookup (token TTL must >= 1 minute) @@ -173,8 +173,8 @@ func postAccessToken(ts *tokenService, w http.ResponseWriter, r *http.Request) { if atRequest.Expiry != nil && *atRequest.Expiry > 0 { k.MaxExpiry = *atRequest.Expiry } - if k.MaxExpiry == 0 && ts.tokenExpiryInSecond > 0 { - k.MaxExpiry = ts.tokenExpiryInSecond + if k.MaxExpiry == 0 && ts.idCfg.TokenCache.ExpirySeconds > 0 { + k.MaxExpiry = ts.idCfg.TokenCache.ExpirySeconds } // cache lookup (token TTL must >= 1 minute) @@ -259,7 +259,7 @@ func newHandlerFunc(ts *tokenService, timeout time.Duration) http.Handler { } else { // TODO: Since the specifications are not yet decided, the value of WriteFileRequired is undetermined. // TODO: Maybe we need to separate the cache keys for RT and AT? - k := CacheKey{Domain: domain, Role: role, MinExpiry: ts.tokenExpiryInSecond} + k := CacheKey{Domain: domain, Role: role, MinExpiry: ts.idCfg.TokenCache.ExpirySeconds} if ts.tokenType&mACCESS_TOKEN != 0 { k, aToken = ts.accessTokenCache.Search(k) if aToken == nil { diff --git a/pkg/token/service.go b/pkg/token/service.go index 009a3f8e..2d2c8602 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -51,10 +51,8 @@ type tokenService struct { ztsClient *zts.ZTSClient saService string - idCfg *config.IdentityConfig - // TODO: move to derived token - tokenExpiryInSecond int - tokenType mode + idCfg *config.IdentityConfig + tokenType mode tokenServer *http.Server tokenServerRunning bool @@ -66,25 +64,27 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro return nil, nil } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. - enableWriteFiles := idCfg.TokenDir != "" + enableAccessToken := idCfg.TokenCache.AccessToken.Use + enableRoleToken := idCfg.TokenCache.RoleToken.Use + enableWriteFiles := enableAccessToken || enableRoleToken if !enableWriteFiles { - log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenDir) + // The Dir settings for the access token and role token are the same. + log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenCache.AccessToken.Dir) } // initialize token cache with placeholder tt := newType(idCfg.TokenType) - tokenExpiryInSecond := int(idCfg.TokenExpiry.Seconds()) accessTokenCache := NewLockedTokenCache("accesstoken", idCfg.Namespace, idCfg.PodName) roleTokenCache := NewLockedTokenCache("roletoken", idCfg.Namespace, idCfg.PodName) - for _, dr := range idCfg.TokenTargetDomainRoles { + for _, dr := range idCfg.TokenCache.TargetDomainRoles { domain, role := dr.Domain, dr.Role // TODO: Rewrite the following if statement as "if tt.isAccessTokenEnabled()..." if tt&mACCESS_TOKEN != 0 { - accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: tokenExpiryInSecond, WriteFileRequired: enableWriteFiles}, &AccessToken{}) + accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: enableWriteFiles}, &AccessToken{}) } // TODO: Rewrite the following if statement as "if tt.isRoleTokenEnabled()..." if tt&mROLE_TOKEN != 0 { - roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: tokenExpiryInSecond, WriteFileRequired: enableWriteFiles}, &RoleToken{}) + roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: enableWriteFiles}, &RoleToken{}) } } @@ -110,14 +110,13 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // setup token service ts := &tokenService{ - shutdownChan: make(chan struct{}, 1), - accessTokenCache: accessTokenCache, - roleTokenCache: roleTokenCache, - ztsClient: ztsClient, - saService: saService, - idCfg: idCfg, - tokenType: tt, - tokenExpiryInSecond: tokenExpiryInSecond, + shutdownChan: make(chan struct{}, 1), + accessTokenCache: accessTokenCache, + roleTokenCache: roleTokenCache, + ztsClient: ztsClient, + saService: saService, + idCfg: idCfg, + tokenType: tt, } // write tokens as files only if it is non-init mode OR TOKEN_DIR is set @@ -189,15 +188,15 @@ func (ts *tokenService) Start(ctx context.Context) error { } // refreshes tokens periodically - if ts.idCfg.TokenRefresh > 0 { - t := time.NewTicker(ts.idCfg.TokenRefresh) + if ts.idCfg.TokenCache.Refresh > 0 { + t := time.NewTicker(ts.idCfg.TokenCache.Refresh) ts.shutdownWg.Add(1) go func() { defer t.Stop() defer ts.shutdownWg.Done() for { - log.Infof("Will refresh cached tokens within %s", ts.idCfg.TokenRefresh.String()) + log.Infof("Will refresh cached tokens within %s", ts.idCfg.TokenCache.Refresh.String()) select { case <-ts.shutdownChan: @@ -211,7 +210,7 @@ func (ts *tokenService) Start(ctx context.Context) error { } // backoff retry until TOKEN_REFRESH_INTERVAL / 4 OR context is done - for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, ts.idCfg.TokenRefresh/4) { + for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, ts.idCfg.TokenCache.Refresh/4) { log.Errorf("Failed to refresh tokens after multiple retries: %s", err.Error()) } } @@ -394,7 +393,7 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error { // File output processing domain, role := key.Domain, key.Role token := d.accessTokenCache.Load(key) - outPath := filepath.Join(d.idCfg.TokenDir, domain+":role."+role+".accesstoken") + outPath := filepath.Join(d.idCfg.TokenCache.AccessToken.Dir, domain+d.idCfg.TokenCache.AccessToken.Delimiter+role+".accesstoken") return d.writeFile(token, outPath, mACCESS_TOKEN) } updateAndWriteFileRoleToken := func(key CacheKey) error { @@ -405,7 +404,7 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error { // File output processing domain, role := key.Domain, key.Role token := d.roleTokenCache.Load(key) - outPath := filepath.Join(d.idCfg.TokenDir, domain+":role."+role+".roletoken") + outPath := filepath.Join(d.idCfg.TokenCache.RoleToken.Dir, domain+d.idCfg.TokenCache.RoleToken.Delimiter+role+".roletoken") return d.writeFile(token, outPath, mROLE_TOKEN) } switch tt { From 999552ba8a8626a31009b23ded59f108db3fe142 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:21:21 +0900 Subject: [PATCH 02/12] fix Signed-off-by: myajima --- pkg/config/derived-token-cache.go | 82 +++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 pkg/config/derived-token-cache.go diff --git a/pkg/config/derived-token-cache.go b/pkg/config/derived-token-cache.go new file mode 100644 index 00000000..717c2238 --- /dev/null +++ b/pkg/config/derived-token-cache.go @@ -0,0 +1,82 @@ +// Copyright 2023 LY Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package config defines all the configuration parameters. It reads configuration from environment variables and command-line arguments. +package config + +import ( + "strings" + "time" +) + +type WriteFileConfig struct { + Use bool + Dir string + // TODO: Add Format + // Format string + Delimiter string +} + +type DerivedTokenCache struct { + // Use bool // if fetching access token as files is enabled (de facto standard) + TargetDomainRoles []DomainRole // domain roles to fetch tokens + Refresh time.Duration // refresh interval + ExpirySeconds int + AccessToken WriteFileConfig + RoleToken WriteFileConfig +} + +// // derivedAccessToken ... TODO: Comment +func (idCfg *IdentityConfig) derivedTokenChacheConfig() error { + // default: + idCfg.TokenCache = DerivedTokenCache{ + TargetDomainRoles: idCfg.targetDomainRoles.tokens, + Refresh: idCfg.tokenRefresh, + ExpirySeconds: int(idCfg.tokenExpiry.Seconds()), + AccessToken: WriteFileConfig{ + Use: false, + Dir: "", + // Format: "", + Delimiter: "", + }, + RoleToken: WriteFileConfig{ + Use: false, + Dir: "", + // Format: "", + Delimiter: "", + }, + } + + // access token: + if strings.Contains(idCfg.TokenType, "accesstoken") { + idCfg.TokenCache.AccessToken = WriteFileConfig{ + Use: true, + Dir: idCfg.tokenDir, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"), + Delimiter: ":role.", + } + } + + // role token: + if strings.Contains(idCfg.TokenType, "roletoken") { + idCfg.TokenCache.RoleToken = WriteFileConfig{ + Use: true, + Dir: idCfg.tokenDir, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"), + Delimiter: ":role.", + } + } + + return nil +} From 492d4a4fc20487cc5e1147a08ae76424457a02f0 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:22:04 +0900 Subject: [PATCH 03/12] remove use Signed-off-by: myajima --- pkg/config/derived-token-cache.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/config/derived-token-cache.go b/pkg/config/derived-token-cache.go index 717c2238..0bedd59e 100644 --- a/pkg/config/derived-token-cache.go +++ b/pkg/config/derived-token-cache.go @@ -29,7 +29,6 @@ type WriteFileConfig struct { } type DerivedTokenCache struct { - // Use bool // if fetching access token as files is enabled (de facto standard) TargetDomainRoles []DomainRole // domain roles to fetch tokens Refresh time.Duration // refresh interval ExpirySeconds int From ed575c0ce3edc56d11b837959ee20e44138ccf8e Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:23:31 +0900 Subject: [PATCH 04/12] fix comment Signed-off-by: myajima --- pkg/config/derived-token-cache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/derived-token-cache.go b/pkg/config/derived-token-cache.go index 0bedd59e..c4745906 100644 --- a/pkg/config/derived-token-cache.go +++ b/pkg/config/derived-token-cache.go @@ -36,7 +36,7 @@ type DerivedTokenCache struct { RoleToken WriteFileConfig } -// // derivedAccessToken ... TODO: Comment +// derivedTokenChacheConfig reads given configuration and sets the derived state of updating token cache related configuration. func (idCfg *IdentityConfig) derivedTokenChacheConfig() error { // default: idCfg.TokenCache = DerivedTokenCache{ From 28e4df369ad82bfa3c963cc5eda8916767a53b64 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:31:14 +0900 Subject: [PATCH 05/12] fix comment Signed-off-by: myajima --- pkg/token/service.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/token/service.go b/pkg/token/service.go index 2d2c8602..91e74d46 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -64,11 +64,9 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro return nil, nil } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. - enableAccessToken := idCfg.TokenCache.AccessToken.Use - enableRoleToken := idCfg.TokenCache.RoleToken.Use - enableWriteFiles := enableAccessToken || enableRoleToken + enableWriteFiles := idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use if !enableWriteFiles { - // The Dir settings for the access token and role token are the same. + // When file output is disabled, the Dir settings for the access token and role token will all be empty strings. log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenCache.AccessToken.Dir) } @@ -80,11 +78,11 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro domain, role := dr.Domain, dr.Role // TODO: Rewrite the following if statement as "if tt.isAccessTokenEnabled()..." if tt&mACCESS_TOKEN != 0 { - accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: enableWriteFiles}, &AccessToken{}) + accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: idCfg.TokenCache.AccessToken.Use}, &AccessToken{}) } // TODO: Rewrite the following if statement as "if tt.isRoleTokenEnabled()..." if tt&mROLE_TOKEN != 0 { - roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: enableWriteFiles}, &RoleToken{}) + roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: idCfg.TokenCache.RoleToken.Use}, &RoleToken{}) } } From ce420ba3fffcb42d962e320eb7cd593653986a90 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:58:31 +0900 Subject: [PATCH 06/12] token file Signed-off-by: myajima --- pkg/config/config.go | 12 ++--- pkg/config/default.go | 7 +-- pkg/config/derived-token-cache.go | 81 ------------------------------- pkg/config/dervied.go | 11 +++-- pkg/config/model.go | 9 ++-- pkg/token/server.go | 10 ++-- pkg/token/service.go | 36 ++++++++------ 7 files changed, 48 insertions(+), 118 deletions(-) delete mode 100644 pkg/config/derived-token-cache.go diff --git a/pkg/config/config.go b/pkg/config/config.go index f1a83e99..b3a0ea11 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -142,11 +142,11 @@ func (idCfg *IdentityConfig) loadFromENV() error { if err != nil { return fmt.Errorf("Invalid ROLE_CERT_OUTPUT_KEY_FILE [%q], %w", idCfg.rawRoleCertKeyFileOutput, err) } - idCfg.tokenRefresh, err = time.ParseDuration(idCfg.rawTokenRefresh) + idCfg.TokenRefresh, err = time.ParseDuration(idCfg.rawTokenRefresh) if err != nil { return fmt.Errorf("Invalid TOKEN_REFRESH_INTERVAL [%q], %w", idCfg.rawTokenRefresh, err) } - idCfg.tokenExpiry, err = time.ParseDuration(idCfg.rawTokenExpiry) + idCfg.TokenExpiry, err = time.ParseDuration(idCfg.rawTokenExpiry) if err != nil { return fmt.Errorf("Invalid TOKEN_EXPIRY [%q], %w", idCfg.rawTokenExpiry, err) } @@ -209,8 +209,8 @@ func (idCfg *IdentityConfig) loadFromFlag(program string, args []string) error { f.StringVar(&idCfg.roleCertKeyNamingFormat, "role-cert-key-naming-format", idCfg.roleCertKeyNamingFormat, "The file name format when outputting the role cert key to a file") // RoleAuthHeader f.StringVar(&idCfg.TokenType, "token-type", idCfg.TokenType, "type of the role token to request (\"roletoken\", \"accesstoken\" or \"roletoken+accesstoken\")") - f.DurationVar(&idCfg.tokenRefresh, "token-refresh-interval", idCfg.tokenRefresh, "token refresh interval") - f.DurationVar(&idCfg.tokenExpiry, "token-expiry", idCfg.tokenExpiry, "token expiry duration (0 to use Athenz server's default expiry)") + f.DurationVar(&idCfg.TokenRefresh, "token-refresh-interval", idCfg.TokenRefresh, "token refresh interval") + f.DurationVar(&idCfg.TokenExpiry, "token-expiry", idCfg.TokenExpiry, "token expiry duration (0 to use Athenz server's default expiry)") f.StringVar(&idCfg.TokenServerAddr, "token-server-addr", idCfg.TokenServerAddr, "HTTP server address to provide tokens (required for token provisioning)") f.BoolVar(&idCfg.TokenServerRESTAPI, "token-server-rest-api", idCfg.TokenServerRESTAPI, "enable token server RESTful API (true/false)") f.DurationVar(&idCfg.TokenServerTimeout, "token-server-timeout", idCfg.TokenServerTimeout, "token server timeout (default 3s)") @@ -249,8 +249,8 @@ func (idCfg *IdentityConfig) parseRawValues() (err error) { func (idCfg *IdentityConfig) validateAndInit() (err error) { - if idCfg.tokenExpiry != 0 && idCfg.tokenRefresh >= idCfg.tokenExpiry { - return fmt.Errorf("Invalid TokenRefresh[%s] >= TokenExpiry[%s]", idCfg.tokenRefresh.String(), idCfg.tokenExpiry.String()) + if idCfg.TokenExpiry != 0 && idCfg.TokenRefresh >= idCfg.TokenExpiry { + return fmt.Errorf("Invalid TokenRefresh[%s] >= TokenExpiry[%s]", idCfg.TokenRefresh.String(), idCfg.TokenExpiry.String()) } // TODO: clarify unused logic diff --git a/pkg/config/default.go b/pkg/config/default.go index 7b9c47a9..4de67e44 100644 --- a/pkg/config/default.go +++ b/pkg/config/default.go @@ -90,16 +90,17 @@ func DefaultIdentityConfig() *IdentityConfig { PodName: "", Reloader: nil, ServerCACert: "", + TokenTargetDomainRoles: []DomainRole{}, roleCertDir: "", roleCertFilenameDelimiter: DEFAULT_ROLE_CERT_FILENAME_DELIMITER, roleCertKeyFileOutput: false, roleCertNamingFormat: "", roleCertKeyNamingFormat: "", RoleAuthHeader: DEFAULT_ROLE_AUTH_HEADER, - TokenType: "accesstoken", tokenDir: "", - tokenRefresh: DEFAULT_TOKEN_REFRESH, - tokenExpiry: DEFAULT_TOKEN_EXPIRY, + TokenType: "accesstoken", + TokenRefresh: DEFAULT_TOKEN_REFRESH, + TokenExpiry: DEFAULT_TOKEN_EXPIRY, TokenServerAddr: "", TokenServerRESTAPI: false, TokenServerTimeout: DEFAULT_TOKEN_SERVER_TIMEOUT, diff --git a/pkg/config/derived-token-cache.go b/pkg/config/derived-token-cache.go deleted file mode 100644 index c4745906..00000000 --- a/pkg/config/derived-token-cache.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2023 LY Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package config defines all the configuration parameters. It reads configuration from environment variables and command-line arguments. -package config - -import ( - "strings" - "time" -) - -type WriteFileConfig struct { - Use bool - Dir string - // TODO: Add Format - // Format string - Delimiter string -} - -type DerivedTokenCache struct { - TargetDomainRoles []DomainRole // domain roles to fetch tokens - Refresh time.Duration // refresh interval - ExpirySeconds int - AccessToken WriteFileConfig - RoleToken WriteFileConfig -} - -// derivedTokenChacheConfig reads given configuration and sets the derived state of updating token cache related configuration. -func (idCfg *IdentityConfig) derivedTokenChacheConfig() error { - // default: - idCfg.TokenCache = DerivedTokenCache{ - TargetDomainRoles: idCfg.targetDomainRoles.tokens, - Refresh: idCfg.tokenRefresh, - ExpirySeconds: int(idCfg.tokenExpiry.Seconds()), - AccessToken: WriteFileConfig{ - Use: false, - Dir: "", - // Format: "", - Delimiter: "", - }, - RoleToken: WriteFileConfig{ - Use: false, - Dir: "", - // Format: "", - Delimiter: "", - }, - } - - // access token: - if strings.Contains(idCfg.TokenType, "accesstoken") { - idCfg.TokenCache.AccessToken = WriteFileConfig{ - Use: true, - Dir: idCfg.tokenDir, - // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"), - Delimiter: ":role.", - } - } - - // role token: - if strings.Contains(idCfg.TokenType, "roletoken") { - idCfg.TokenCache.RoleToken = WriteFileConfig{ - Use: true, - Dir: idCfg.tokenDir, - // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"), - Delimiter: ":role.", - } - } - - return nil -} diff --git a/pkg/config/dervied.go b/pkg/config/dervied.go index 4e8f0eae..f60deb8c 100644 --- a/pkg/config/dervied.go +++ b/pkg/config/dervied.go @@ -39,16 +39,21 @@ func (idCfg *IdentityConfig) loadDerivedConfig() error { return err } + // TODO: // depends on the following: // - derivedTargetDomainRoles() - if err := idCfg.derivedTokenChacheConfig(); err != nil { + // if err := idCfg.derivedTokenCacheConfig(); err != nil { + // return err + // } + + // depends on the following: + if err := idCfg.derivedTokenFileConfig(); err != nil { return err } // TODO: // depends on the following: - // - derivedTargetDomainRoles() - // if err := idCfg.derivedRoleTokenConfig(); err != nil { + // if err := idCfg.derivedTokenServerConfig(); err != nil { // return err // } diff --git a/pkg/config/model.go b/pkg/config/model.go index 156dfba2..0a9bcdc1 100644 --- a/pkg/config/model.go +++ b/pkg/config/model.go @@ -49,6 +49,7 @@ type IdentityConfig struct { ServerCACert string K8sSecretBackup DerivedK8sSecretBackup ServiceCert DerivedServiceCert + TokenTargetDomainRoles []DomainRole // TODO: Will be migrated into DerivedTargetDomainRoles targetDomainRoles DerivedTargetDomainRoles // private as the derived state is used only within the config package // RoleCerts Derived State and its related fields: RoleCert DerivedRoleCert @@ -59,13 +60,13 @@ type IdentityConfig struct { roleCertKeyNamingFormat string // // Token Cache Derived State and its related fields: - TokenCache DerivedTokenCache - tokenDir string - tokenRefresh time.Duration - tokenExpiry time.Duration + TokenCache DerivedTokenFile + tokenDir string // RoleAuthHeader string TokenType string + TokenRefresh time.Duration + TokenExpiry time.Duration TokenServerAddr string TokenServerRESTAPI bool TokenServerTimeout time.Duration diff --git a/pkg/token/server.go b/pkg/token/server.go index b589495d..49dfa625 100644 --- a/pkg/token/server.go +++ b/pkg/token/server.go @@ -90,8 +90,8 @@ func postRoleToken(ts *tokenService, w http.ResponseWriter, r *http.Request) { // if rtRequest.MaxExpiry != nil && *rtRequest.MaxExpiry > 0{ // k.MaxExpiry = *rtRequest.MaxExpiry // } - if k.MinExpiry == 0 && ts.idCfg.TokenCache.ExpirySeconds > 0 { - k.MinExpiry = ts.idCfg.TokenCache.ExpirySeconds + if k.MinExpiry == 0 && ts.tokenExpiryInSecond > 0 { + k.MinExpiry = ts.tokenExpiryInSecond } // cache lookup (token TTL must >= 1 minute) @@ -173,8 +173,8 @@ func postAccessToken(ts *tokenService, w http.ResponseWriter, r *http.Request) { if atRequest.Expiry != nil && *atRequest.Expiry > 0 { k.MaxExpiry = *atRequest.Expiry } - if k.MaxExpiry == 0 && ts.idCfg.TokenCache.ExpirySeconds > 0 { - k.MaxExpiry = ts.idCfg.TokenCache.ExpirySeconds + if k.MaxExpiry == 0 && ts.tokenExpiryInSecond > 0 { + k.MaxExpiry = ts.tokenExpiryInSecond } // cache lookup (token TTL must >= 1 minute) @@ -259,7 +259,7 @@ func newHandlerFunc(ts *tokenService, timeout time.Duration) http.Handler { } else { // TODO: Since the specifications are not yet decided, the value of WriteFileRequired is undetermined. // TODO: Maybe we need to separate the cache keys for RT and AT? - k := CacheKey{Domain: domain, Role: role, MinExpiry: ts.idCfg.TokenCache.ExpirySeconds} + k := CacheKey{Domain: domain, Role: role, MinExpiry: ts.tokenExpiryInSecond} if ts.tokenType&mACCESS_TOKEN != 0 { k, aToken = ts.accessTokenCache.Search(k) if aToken == nil { diff --git a/pkg/token/service.go b/pkg/token/service.go index 91e74d46..40d4eeb3 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -51,8 +51,10 @@ type tokenService struct { ztsClient *zts.ZTSClient saService string - idCfg *config.IdentityConfig - tokenType mode + idCfg *config.IdentityConfig + // TODO: move to derived token + tokenExpiryInSecond int + tokenType mode tokenServer *http.Server tokenServerRunning bool @@ -72,17 +74,18 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // initialize token cache with placeholder tt := newType(idCfg.TokenType) + tokenExpiryInSecond := int(idCfg.TokenExpiry.Seconds()) accessTokenCache := NewLockedTokenCache("accesstoken", idCfg.Namespace, idCfg.PodName) roleTokenCache := NewLockedTokenCache("roletoken", idCfg.Namespace, idCfg.PodName) - for _, dr := range idCfg.TokenCache.TargetDomainRoles { + for _, dr := range idCfg.TokenTargetDomainRoles { domain, role := dr.Domain, dr.Role // TODO: Rewrite the following if statement as "if tt.isAccessTokenEnabled()..." if tt&mACCESS_TOKEN != 0 { - accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: idCfg.TokenCache.AccessToken.Use}, &AccessToken{}) + accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenCache.AccessToken.Use}, &AccessToken{}) } // TODO: Rewrite the following if statement as "if tt.isRoleTokenEnabled()..." if tt&mROLE_TOKEN != 0 { - roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: idCfg.TokenCache.ExpirySeconds, WriteFileRequired: idCfg.TokenCache.RoleToken.Use}, &RoleToken{}) + roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenCache.RoleToken.Use}, &RoleToken{}) } } @@ -108,13 +111,14 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // setup token service ts := &tokenService{ - shutdownChan: make(chan struct{}, 1), - accessTokenCache: accessTokenCache, - roleTokenCache: roleTokenCache, - ztsClient: ztsClient, - saService: saService, - idCfg: idCfg, - tokenType: tt, + shutdownChan: make(chan struct{}, 1), + accessTokenCache: accessTokenCache, + roleTokenCache: roleTokenCache, + ztsClient: ztsClient, + saService: saService, + idCfg: idCfg, + tokenType: tt, + tokenExpiryInSecond: tokenExpiryInSecond, } // write tokens as files only if it is non-init mode OR TOKEN_DIR is set @@ -186,15 +190,15 @@ func (ts *tokenService) Start(ctx context.Context) error { } // refreshes tokens periodically - if ts.idCfg.TokenCache.Refresh > 0 { - t := time.NewTicker(ts.idCfg.TokenCache.Refresh) + if ts.idCfg.TokenRefresh > 0 { + t := time.NewTicker(ts.idCfg.TokenRefresh) ts.shutdownWg.Add(1) go func() { defer t.Stop() defer ts.shutdownWg.Done() for { - log.Infof("Will refresh cached tokens within %s", ts.idCfg.TokenCache.Refresh.String()) + log.Infof("Will refresh cached tokens within %s", ts.idCfg.TokenRefresh.String()) select { case <-ts.shutdownChan: @@ -208,7 +212,7 @@ func (ts *tokenService) Start(ctx context.Context) error { } // backoff retry until TOKEN_REFRESH_INTERVAL / 4 OR context is done - for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, ts.idCfg.TokenCache.Refresh/4) { + for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, ts.idCfg.TokenRefresh/4) { log.Errorf("Failed to refresh tokens after multiple retries: %s", err.Error()) } } From 2e7ceabadbfa5ccbc580c3a23edb4f4ba64085d0 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 11:58:43 +0900 Subject: [PATCH 07/12] fix Signed-off-by: myajima --- pkg/config/derived-token-file.go | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 pkg/config/derived-token-file.go diff --git a/pkg/config/derived-token-file.go b/pkg/config/derived-token-file.go new file mode 100644 index 00000000..239cad0a --- /dev/null +++ b/pkg/config/derived-token-file.go @@ -0,0 +1,79 @@ +// Copyright 2023 LY Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package config defines all the configuration parameters. It reads configuration from environment variables and command-line arguments. +package config + +import ( + "strings" +) + +type TokenFileConfig struct { + Use bool + Dir string + // TODO: Add Format + // Format string + Delimiter string +} + +type DerivedTokenFile struct { + AccessToken TokenFileConfig + RoleToken TokenFileConfig +} + +// derivedTokenFileConfig reads given configuration and sets the derived state of outputting token file related configuration. +func (idCfg *IdentityConfig) derivedTokenFileConfig() error { + // default: + idCfg.TokenCache = DerivedTokenFile{ + AccessToken: TokenFileConfig{ + Use: false, + Dir: "", + // Format: "", + Delimiter: "", + }, + RoleToken: TokenFileConfig{ + Use: false, + Dir: "", + // Format: "", + Delimiter: "", + }, + } + + if idCfg.tokenDir == "" { + return nil // disable + } + + // Enable from now on: + // access token: + if strings.Contains(idCfg.TokenType, "accesstoken") { + idCfg.TokenCache.AccessToken = TokenFileConfig{ + Use: true, + Dir: idCfg.tokenDir, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"), + Delimiter: ":role.", + } + } + + // role token: + if strings.Contains(idCfg.TokenType, "roletoken") { + idCfg.TokenCache.RoleToken = TokenFileConfig{ + Use: true, + Dir: idCfg.tokenDir, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"), + Delimiter: ":role.", + } + } + + return nil +} From 3c0590da5d80764ea877f6878998c9c9b1663085 Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 12:02:18 +0900 Subject: [PATCH 08/12] disable derived token target domain roles Signed-off-by: myajima --- pkg/config/derived-target-domain-roles.go | 4 ++-- pkg/token/service.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/config/derived-target-domain-roles.go b/pkg/config/derived-target-domain-roles.go index 10b28844..dc8ab5ff 100644 --- a/pkg/config/derived-target-domain-roles.go +++ b/pkg/config/derived-target-domain-roles.go @@ -24,7 +24,7 @@ import ( type DerivedTargetDomainRoles struct { roleCerts []DomainRole // private as the derived state is used only within the config package - tokens []DomainRole // private as the derived state is used only within the config package + // tokens []DomainRole // private as the derived state is used only within the config package } // derivedTargetDomainRoles sets the DerivedTargetDomainRoles with the given rawTargetDomainRoles. @@ -65,7 +65,7 @@ func (idCfg *IdentityConfig) derivedTargetDomainRoles() error { idCfg.targetDomainRoles = DerivedTargetDomainRoles{ roleCerts: roleCertDomainRoles, - tokens: tokenDomainRoles, + // tokens: tokenDomainRoles, } return nil diff --git a/pkg/token/service.go b/pkg/token/service.go index 40d4eeb3..d1f05a1c 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -66,6 +66,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro return nil, nil } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. + // TODO: move to derived token file enableWriteFiles := idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use if !enableWriteFiles { // When file output is disabled, the Dir settings for the access token and role token will all be empty strings. @@ -124,7 +125,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // write tokens as files only if it is non-init mode OR TOKEN_DIR is set // If it is in refresh mode, when requesting tokens using the REST API for the domains and roles specified in TARGET_DOMAIN_ROLES, // the cache is updated to ensure a cache hit from the first request. - if !idCfg.Init || enableWriteFiles { + if !idCfg.Init || idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use { // TODO: if cap(errs) == len(errs), implies all token updates failed, should be fatal for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, config.DEFAULT_MAX_ELAPSED_TIME_ON_INIT) { log.Errorf("Failed to refresh tokens after multiple retries: %s", err.Error()) From 2ed60f479688128b8c4bc13bf42b2ba268595d0d Mon Sep 17 00:00:00 2001 From: myajima Date: Wed, 18 Sep 2024 12:33:40 +0900 Subject: [PATCH 09/12] rename Signed-off-by: myajima --- pkg/config/default.go | 2 +- pkg/config/derived-target-domain-roles.go | 1 + pkg/config/derived-token-file.go | 60 ++++++++++++++--------- pkg/config/dervied.go | 1 - pkg/config/model.go | 4 +- pkg/token/service.go | 15 +++--- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/pkg/config/default.go b/pkg/config/default.go index 4de67e44..09ab1224 100644 --- a/pkg/config/default.go +++ b/pkg/config/default.go @@ -97,7 +97,6 @@ func DefaultIdentityConfig() *IdentityConfig { roleCertNamingFormat: "", roleCertKeyNamingFormat: "", RoleAuthHeader: DEFAULT_ROLE_AUTH_HEADER, - tokenDir: "", TokenType: "accesstoken", TokenRefresh: DEFAULT_TOKEN_REFRESH, TokenExpiry: DEFAULT_TOKEN_EXPIRY, @@ -107,6 +106,7 @@ func DefaultIdentityConfig() *IdentityConfig { TokenServerTLSCAPath: "", TokenServerTLSCertPath: "", TokenServerTLSKeyPath: "", + tokenDir: "", MetricsServerAddr: "", HealthCheckAddr: "", HealthCheckEndpoint: "", diff --git a/pkg/config/derived-target-domain-roles.go b/pkg/config/derived-target-domain-roles.go index dc8ab5ff..90fa2543 100644 --- a/pkg/config/derived-target-domain-roles.go +++ b/pkg/config/derived-target-domain-roles.go @@ -63,6 +63,7 @@ func (idCfg *IdentityConfig) derivedTargetDomainRoles() error { }) } + idCfg.TokenTargetDomainRoles = tokenDomainRoles // TODO: Delete me and refactor by using the type DerivedTargetDomainRoles below: idCfg.targetDomainRoles = DerivedTargetDomainRoles{ roleCerts: roleCertDomainRoles, // tokens: tokenDomainRoles, diff --git a/pkg/config/derived-token-file.go b/pkg/config/derived-token-file.go index 239cad0a..58205edf 100644 --- a/pkg/config/derived-token-file.go +++ b/pkg/config/derived-token-file.go @@ -21,13 +21,13 @@ import ( type TokenFileConfig struct { Use bool - Dir string // TODO: Add Format // Format string Delimiter string } type DerivedTokenFile struct { + Dir string AccessToken TokenFileConfig RoleToken TokenFileConfig } @@ -35,45 +35,61 @@ type DerivedTokenFile struct { // derivedTokenFileConfig reads given configuration and sets the derived state of outputting token file related configuration. func (idCfg *IdentityConfig) derivedTokenFileConfig() error { // default: - idCfg.TokenCache = DerivedTokenFile{ + idCfg.TokenFile = DerivedTokenFile{ + Dir: "", AccessToken: TokenFileConfig{ Use: false, - Dir: "", // Format: "", Delimiter: "", }, RoleToken: TokenFileConfig{ Use: false, - Dir: "", // Format: "", Delimiter: "", }, } + // TODO: Apply the following instead?: + // if idCfg.TokenDir == "" || idCfg.TokenType == "" { if idCfg.tokenDir == "" { - return nil // disable + return nil // disabled } // Enable from now on: // access token: - if strings.Contains(idCfg.TokenType, "accesstoken") { - idCfg.TokenCache.AccessToken = TokenFileConfig{ - Use: true, - Dir: idCfg.tokenDir, - // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"), - Delimiter: ":role.", - } - } + idCfg.TokenFile = DerivedTokenFile{ + Dir: idCfg.tokenDir, + AccessToken: func() TokenFileConfig { + // disabled + if !strings.Contains(idCfg.TokenType, "accesstoken") { + return TokenFileConfig{ + Use: false, + // Format: "", + Delimiter: "", + } + } + return TokenFileConfig{ + Use: true, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"), + Delimiter: ":role.", + } - // role token: - if strings.Contains(idCfg.TokenType, "roletoken") { - idCfg.TokenCache.RoleToken = TokenFileConfig{ - Use: true, - Dir: idCfg.tokenDir, - // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"), - Delimiter: ":role.", - } + }(), + RoleToken: func() TokenFileConfig { + // disabled + if !strings.Contains(idCfg.TokenType, "roletoken") { + return TokenFileConfig{ + Use: false, + // Format: "", + Delimiter: "", + } + } + return TokenFileConfig{ + Use: true, + // Format: filepath.Join(idCfg.TokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"), + Delimiter: ":role.", + } + }(), } - return nil } diff --git a/pkg/config/dervied.go b/pkg/config/dervied.go index f60deb8c..4656d263 100644 --- a/pkg/config/dervied.go +++ b/pkg/config/dervied.go @@ -46,7 +46,6 @@ func (idCfg *IdentityConfig) loadDerivedConfig() error { // return err // } - // depends on the following: if err := idCfg.derivedTokenFileConfig(); err != nil { return err } diff --git a/pkg/config/model.go b/pkg/config/model.go index 0a9bcdc1..11fe9ff4 100644 --- a/pkg/config/model.go +++ b/pkg/config/model.go @@ -60,8 +60,8 @@ type IdentityConfig struct { roleCertKeyNamingFormat string // // Token Cache Derived State and its related fields: - TokenCache DerivedTokenFile - tokenDir string + TokenFile DerivedTokenFile + tokenDir string // RoleAuthHeader string TokenType string diff --git a/pkg/token/service.go b/pkg/token/service.go index d1f05a1c..c3379d1b 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -67,10 +67,9 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. // TODO: move to derived token file - enableWriteFiles := idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use - if !enableWriteFiles { + if !idCfg.TokenFile.AccessToken.Use && !idCfg.TokenFile.RoleToken.Use { // When file output is disabled, the Dir settings for the access token and role token will all be empty strings. - log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenCache.AccessToken.Dir) + log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenFile.Dir) } // initialize token cache with placeholder @@ -82,11 +81,11 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro domain, role := dr.Domain, dr.Role // TODO: Rewrite the following if statement as "if tt.isAccessTokenEnabled()..." if tt&mACCESS_TOKEN != 0 { - accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenCache.AccessToken.Use}, &AccessToken{}) + accessTokenCache.Store(CacheKey{Domain: domain, Role: role, MaxExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenFile.AccessToken.Use}, &AccessToken{}) } // TODO: Rewrite the following if statement as "if tt.isRoleTokenEnabled()..." if tt&mROLE_TOKEN != 0 { - roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenCache.RoleToken.Use}, &RoleToken{}) + roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenFile.RoleToken.Use}, &RoleToken{}) } } @@ -125,7 +124,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // write tokens as files only if it is non-init mode OR TOKEN_DIR is set // If it is in refresh mode, when requesting tokens using the REST API for the domains and roles specified in TARGET_DOMAIN_ROLES, // the cache is updated to ensure a cache hit from the first request. - if !idCfg.Init || idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use { + if !idCfg.Init || idCfg.TokenFile.AccessToken.Use || idCfg.TokenFile.RoleToken.Use { // TODO: if cap(errs) == len(errs), implies all token updates failed, should be fatal for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, config.DEFAULT_MAX_ELAPSED_TIME_ON_INIT) { log.Errorf("Failed to refresh tokens after multiple retries: %s", err.Error()) @@ -396,7 +395,7 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error { // File output processing domain, role := key.Domain, key.Role token := d.accessTokenCache.Load(key) - outPath := filepath.Join(d.idCfg.TokenCache.AccessToken.Dir, domain+d.idCfg.TokenCache.AccessToken.Delimiter+role+".accesstoken") + outPath := filepath.Join(d.idCfg.TokenFile.Dir, domain+d.idCfg.TokenFile.AccessToken.Delimiter+role+".accesstoken") return d.writeFile(token, outPath, mACCESS_TOKEN) } updateAndWriteFileRoleToken := func(key CacheKey) error { @@ -407,7 +406,7 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error { // File output processing domain, role := key.Domain, key.Role token := d.roleTokenCache.Load(key) - outPath := filepath.Join(d.idCfg.TokenCache.RoleToken.Dir, domain+d.idCfg.TokenCache.RoleToken.Delimiter+role+".roletoken") + outPath := filepath.Join(d.idCfg.TokenFile.Dir, domain+d.idCfg.TokenFile.RoleToken.Delimiter+role+".roletoken") return d.writeFile(token, outPath, mROLE_TOKEN) } switch tt { From aea0280b3c02b46fbc234a1c41c47309ffc0acc3 Mon Sep 17 00:00:00 2001 From: Jeongwoo Kim - jekim Date: Wed, 18 Sep 2024 13:36:26 +0900 Subject: [PATCH 10/12] comment: removed as not required --- pkg/config/derived-token-file.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/config/derived-token-file.go b/pkg/config/derived-token-file.go index 58205edf..201727cc 100644 --- a/pkg/config/derived-token-file.go +++ b/pkg/config/derived-token-file.go @@ -56,7 +56,6 @@ func (idCfg *IdentityConfig) derivedTokenFileConfig() error { } // Enable from now on: - // access token: idCfg.TokenFile = DerivedTokenFile{ Dir: idCfg.tokenDir, AccessToken: func() TokenFileConfig { From 19a5c71a4bc1e1ed0f9c26404da388eb5c9de07d Mon Sep 17 00:00:00 2001 From: Jeongwoo Kim - jekim Date: Wed, 18 Sep 2024 13:40:28 +0900 Subject: [PATCH 11/12] comment: todos --- pkg/token/service.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/token/service.go b/pkg/token/service.go index c3379d1b..2de5ff10 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -67,6 +67,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. // TODO: move to derived token file + // TODO: Maybe idCfg.TokenFile.Use() if !idCfg.TokenFile.AccessToken.Use && !idCfg.TokenFile.RoleToken.Use { // When file output is disabled, the Dir settings for the access token and role token will all be empty strings. log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenFile.Dir) @@ -124,6 +125,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro // write tokens as files only if it is non-init mode OR TOKEN_DIR is set // If it is in refresh mode, when requesting tokens using the REST API for the domains and roles specified in TARGET_DOMAIN_ROLES, // the cache is updated to ensure a cache hit from the first request. + // TODO: Maybe !idCfg.Init || idCfg.TokenFile.Use() if !idCfg.Init || idCfg.TokenFile.AccessToken.Use || idCfg.TokenFile.RoleToken.Use { // TODO: if cap(errs) == len(errs), implies all token updates failed, should be fatal for _, err := range ts.updateTokenCachesAndWriteFiles(ctx, config.DEFAULT_MAX_ELAPSED_TIME_ON_INIT) { From bb551928686565b682796029c8ad9093ba504d93 Mon Sep 17 00:00:00 2001 From: Jeongwoo Kim - jekim Date: Wed, 18 Sep 2024 13:41:45 +0900 Subject: [PATCH 12/12] comment: fixed logic for comment --- pkg/token/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/token/service.go b/pkg/token/service.go index 2de5ff10..5d6c61ea 100644 --- a/pkg/token/service.go +++ b/pkg/token/service.go @@ -67,7 +67,7 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro } // TODO: In the next PR, the determination will be made on a per Access Token and Role Token basis. // TODO: move to derived token file - // TODO: Maybe idCfg.TokenFile.Use() + // TODO: Maybe if !idCfg.TokenFile.Use() if !idCfg.TokenFile.AccessToken.Use && !idCfg.TokenFile.RoleToken.Use { // When file output is disabled, the Dir settings for the access token and role token will all be empty strings. log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenFile.Dir)