Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: TokenFile with DerivedState #160

Merged
merged 12 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -217,7 +217,7 @@ func (idCfg *IdentityConfig) loadFromFlag(program string, args []string) error {
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
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func DefaultIdentityConfig() *IdentityConfig {
roleCertNamingFormat: "",
roleCertKeyNamingFormat: "",
RoleAuthHeader: DEFAULT_ROLE_AUTH_HEADER,
tokenDir: "",
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
TokenType: "accesstoken",
TokenRefresh: DEFAULT_TOKEN_REFRESH,
TokenExpiry: DEFAULT_TOKEN_EXPIRY,
Expand All @@ -106,7 +107,6 @@ func DefaultIdentityConfig() *IdentityConfig {
TokenServerTLSCAPath: "",
TokenServerTLSCertPath: "",
TokenServerTLSKeyPath: "",
TokenDir: "",
MetricsServerAddr: "",
HealthCheckAddr: "",
HealthCheckEndpoint: "",
Expand Down
29 changes: 0 additions & 29 deletions pkg/config/derived-access-token.go

This file was deleted.

3 changes: 1 addition & 2 deletions pkg/config/derived-target-domain-roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,9 @@ func (idCfg *IdentityConfig) derivedTargetDomainRoles() error {
})
}

idCfg.TokenTargetDomainRoles = tokenDomainRoles // TODO: Delete me and refactor by using the type DerivedTargetDomainRoles below:
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
idCfg.targetDomainRoles = DerivedTargetDomainRoles{
roleCerts: roleCertDomainRoles,
// tokens: tokenDomainRoles,
// tokens: tokenDomainRoles,
}

return nil
Expand Down
79 changes: 79 additions & 0 deletions pkg/config/derived-token-file.go
Original file line number Diff line number Diff line change
@@ -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
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
// TODO: Add Format
// Format string
Delimiter string
}

type DerivedTokenFile struct {
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
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{
y-myajima marked this conversation as resolved.
Show resolved Hide resolved
AccessToken: TokenFileConfig{
Use: false,
Dir: "",
// Format: "",
Delimiter: "",
},
RoleToken: TokenFileConfig{
Use: false,
Dir: "",
// Format: "",
Delimiter: "",
},
}

if idCfg.tokenDir == "" {
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
return nil // disable
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
}

// 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.",
}
}
mlajkim marked this conversation as resolved.
Show resolved Hide resolved

return nil
}
10 changes: 7 additions & 3 deletions pkg/config/dervied.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,18 @@ func (idCfg *IdentityConfig) loadDerivedConfig() error {
// TODO:
// depends on the following:
// - derivedTargetDomainRoles()
// if err := idCfg.derivedAccessTokenConfig(); err != nil {
// if err := idCfg.derivedTokenCacheConfig(); err != nil {
// return err
// }

// depends on the following:
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
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
// }

Expand Down
5 changes: 4 additions & 1 deletion pkg/config/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type IdentityConfig struct {
roleCertNamingFormat string
roleCertKeyNamingFormat string
//
// Token Cache Derived State and its related fields:
TokenCache DerivedTokenFile
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
tokenDir string
//
RoleAuthHeader string
TokenType string
TokenRefresh time.Duration
Expand All @@ -69,7 +73,6 @@ type IdentityConfig struct {
TokenServerTLSCAPath string
TokenServerTLSCertPath string
TokenServerTLSKeyPath string
TokenDir string
MetricsServerAddr string
HealthCheckAddr string
HealthCheckEndpoint string
Expand Down
16 changes: 9 additions & 7 deletions pkg/token/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ 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 != ""
// TODO: move to derived token file
enableWriteFiles := idCfg.TokenCache.AccessToken.Use || idCfg.TokenCache.RoleToken.Use
if !enableWriteFiles {
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
log.Debugf("Skipping to write token files to directory with empty TOKEN_DIR [%s]", idCfg.TokenDir)
// 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)
mlajkim marked this conversation as resolved.
Show resolved Hide resolved
}

// initialize token cache with placeholder
Expand All @@ -80,11 +82,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: enableWriteFiles}, &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: tokenExpiryInSecond, WriteFileRequired: enableWriteFiles}, &RoleToken{})
roleTokenCache.Store(CacheKey{Domain: domain, Role: role, MinExpiry: tokenExpiryInSecond, WriteFileRequired: idCfg.TokenCache.RoleToken.Use}, &RoleToken{})
}
}

Expand Down Expand Up @@ -123,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())
Expand Down Expand Up @@ -394,7 +396,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 {
Expand All @@ -405,7 +407,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 {
Expand Down
Loading