Skip to content

Commit

Permalink
Feat/token naming format (#163)
Browse files Browse the repository at this point in the history
* add token naming format

Signed-off-by: myajima <myajima@lycorp.co.jp>

* fix comment

Signed-off-by: myajima <myajima@lycorp.co.jp>

---------

Signed-off-by: myajima <myajima@lycorp.co.jp>
  • Loading branch information
y-myajima authored Sep 19, 2024
1 parent 1cbb25e commit bbb7bdd
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 20 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ endif
ifneq ($(ATHENZ_SIA_DEFAULT_INTERMEDIATE_CERT_BUNDLE),)
LDFLAGS_ARGS += -X 'github.com/AthenZ/k8s-athenz-sia/v3/pkg/config.DEFAULT_INTERMEDIATE_CERT_BUNDLE=$(ATHENZ_SIA_DEFAULT_INTERMEDIATE_CERT_BUNDLE)'
endif
ifneq ($(ATHENZ_SIA_DEFAULT_ACCESS_TOKEN_FILENAME_DELIMITER),)
LDFLAGS_ARGS += -X 'github.com/AthenZ/k8s-athenz-sia/v3/pkg/config.DEFAULT_ACCESS_TOKEN_FILENAME_DELIMITER=$(ATHENZ_SIA_DEFAULT_ACCESS_TOKEN_FILENAME_DELIMITER)'
endif
ifneq ($(ATHENZ_SIA_DEFAULT_ROLE_TOKEN_FILENAME_DELIMITER),)
LDFLAGS_ARGS += -X 'github.com/AthenZ/k8s-athenz-sia/v3/pkg/config.DEFAULT_ROLE_TOKEN_FILENAME_DELIMITER=$(ATHENZ_SIA_DEFAULT_ROLE_TOKEN_FILENAME_DELIMITER)'
endif

ifneq ($(LDFLAGS_ARGS),)
LDFLAGS += -ldflags "$(LDFLAGS_ARGS) -linkmode=external"
Expand Down
15 changes: 15 additions & 0 deletions athenz-sia.env
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,21 @@ TOKEN_SERVER_TLS_KEY_PATH=
#
TOKEN_DIR=
#
# Naming format for the file that outputs the AccessToken(e.g. /var/run/athenz/accesstokens/{{domain}}{{delimiter}}{{role}}.accesstoken)
#
ACCESS_TOKEN_NAMING_FORMAT=
#
# File name delimiter for Athenz AccessToken files
#
ACCESS_TOKEN_FILENAME_DELIMITER=:role.
#
# Naming format for the file that outputs the RoleToken(e.g. /var/run/athenz/roletokens/{{domain}}{{delimiter}}{{role}}.roletoken)
#
ROLE_TOKEN_NAMING_FORMAT=
#
# File name delimiter for Athenz RoleToken files
ROLE_TOKEN_FILENAME_DELIMITER=:role.
#
# Server address to listen as metrics exporter sidecar (e.g. :9999)
#
METRICS_SERVER_ADDR=
Expand Down
8 changes: 8 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ func (idCfg *IdentityConfig) loadFromENV() error {
loadEnv("TOKEN_SERVER_TLS_CERT_PATH", &idCfg.tokenServerTLSCertPath)
loadEnv("TOKEN_SERVER_TLS_KEY_PATH", &idCfg.tokenServerTLSKeyPath)
loadEnv("TOKEN_DIR", &idCfg.tokenDir)
loadEnv("ACCESS_TOKEN_NAMING_FORMAT", &idCfg.accessTokenNamingFormat)
loadEnv("ACCESS_TOKEN_FILENAME_DELIMITER", &idCfg.accessTokenFilenameDelimiter)
loadEnv("ROLE_TOKEN_NAMING_FORMAT", &idCfg.roleTokenNamingFormat)
loadEnv("ROLE_TOKEN_FILENAME_DELIMITER", &idCfg.roleTokenFilenameDelimiter)
loadEnv("METRICS_SERVER_ADDR", &idCfg.MetricsServerAddr)
loadEnv("DELETE_INSTANCE_ID", &idCfg.rawDeleteInstanceID)
loadEnv("USE_TOKEN_SERVER", &idCfg.rawUseTokenServer)
Expand Down Expand Up @@ -218,6 +222,10 @@ func (idCfg *IdentityConfig) loadFromFlag(program string, args []string) error {
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.accessTokenNamingFormat, "access-token-naming-format", idCfg.accessTokenNamingFormat, "The file name format when outputting the access token to a file")
f.StringVar(&idCfg.accessTokenFilenameDelimiter, "access-token-filename-delimiter", idCfg.accessTokenFilenameDelimiter, "The delimiter that separates the domain name and role name when outputting the access token to a file")
f.StringVar(&idCfg.roleTokenNamingFormat, "role-token-naming-format", idCfg.roleTokenNamingFormat, "The file name format when outputting the role token to a file")
f.StringVar(&idCfg.roleTokenFilenameDelimiter, "role-token-filename-delimiter", idCfg.roleTokenFilenameDelimiter, "The delimiter that separates the domain name and role name when outputting the role token to a file")
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
12 changes: 7 additions & 5 deletions pkg/config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ var (
DEFAULT_ROLE_CERT_EXPIRY_TIME_BUFFER_MINUTES_RAW = "5"
DEFAULT_ROLE_CERT_EXPIRY_TIME_BUFFER_MINUTES = 5

DEFAULT_ENDPOINT string
DEFAULT_ROLE_AUTH_HEADER = "Athenz-Role-Auth"
DEFAULT_DNS_SUFFIX = "athenz.cloud"
DEFAULT_ROLE_CERT_FILENAME_DELIMITER = ":role."
DEFAULT_INTERMEDIATE_CERT_BUNDLE string
DEFAULT_ENDPOINT string
DEFAULT_ROLE_AUTH_HEADER = "Athenz-Role-Auth"
DEFAULT_DNS_SUFFIX = "athenz.cloud"
DEFAULT_ROLE_CERT_FILENAME_DELIMITER = ":role."
DEFAULT_ACCESS_TOKEN_FILENAME_DELIMITER = ":role."
DEFAULT_ROLE_TOKEN_FILENAME_DELIMITER = ":role."
DEFAULT_INTERMEDIATE_CERT_BUNDLE string

// default values for graceful shutdown
DEFAULT_SHUTDOWN_TIMEOUT = 5 * time.Second
Expand Down
33 changes: 27 additions & 6 deletions pkg/config/derived-token-file.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package config

import (
"fmt"
"path/filepath"
"strings"
)
Expand All @@ -27,7 +28,6 @@ type TokenFileConfig struct {
}

type DerivedTokenFile struct {
Dir string // TODO: This might be deleted later
AccessToken TokenFileConfig
RoleToken TokenFileConfig
}
Expand All @@ -36,7 +36,6 @@ type DerivedTokenFile struct {
func (idCfg *IdentityConfig) derivedTokenFileConfig() error {
// default:
idCfg.TokenFile = DerivedTokenFile{
Dir: "",
AccessToken: TokenFileConfig{
Use: false,
Format: "",
Expand All @@ -51,13 +50,21 @@ func (idCfg *IdentityConfig) derivedTokenFileConfig() error {

// TODO: Apply the following instead?:
// if idCfg.TokenDir == "" || idCfg.TokenType == "" {
if idCfg.tokenDir == "" {
if idCfg.tokenDir == "" && idCfg.accessTokenNamingFormat == "" && idCfg.roleTokenNamingFormat == "" {
return nil // disabled
}

// If both the TokenDir settings and the NamingFormat settings are configured redundantly, an error will be returned.
if idCfg.tokenDir != "" && idCfg.accessTokenNamingFormat != "" {
return fmt.Errorf("Both TOKEN_DIR[%s] and ACCESS_TOKEN_NAMING_FORMAT[%s] are set. Please ensure only one of these is specified to avoid conflicts.", idCfg.tokenDir, idCfg.accessTokenNamingFormat)
}
if idCfg.tokenDir != "" && idCfg.roleTokenNamingFormat != "" {
return fmt.Errorf("Both TOKEN_DIR[%s] and ROLE_TOKEN_NAMING_FORMAT[%s] are set. Please ensure only one of these is specified to avoid conflicts.", idCfg.tokenDir, idCfg.roleTokenNamingFormat)

}

// Enable from now on:
idCfg.TokenFile = DerivedTokenFile{
Dir: idCfg.tokenDir,
AccessToken: func() TokenFileConfig {
// disabled
if !strings.Contains(idCfg.TokenType, "accesstoken") {
Expand All @@ -67,10 +74,17 @@ func (idCfg *IdentityConfig) derivedTokenFileConfig() error {
Delimiter: "",
}
}
if idCfg.accessTokenNamingFormat != "" {
return TokenFileConfig{
Use: true,
Format: idCfg.accessTokenNamingFormat,
Delimiter: idCfg.accessTokenFilenameDelimiter,
}
}
return TokenFileConfig{
Use: true,
Format: filepath.Join(idCfg.tokenDir, "{{domain}}{{delimiter}}{{role}}.accesstoken"),
Delimiter: ":role.",
Delimiter: idCfg.accessTokenFilenameDelimiter,
}

}(),
Expand All @@ -83,10 +97,17 @@ func (idCfg *IdentityConfig) derivedTokenFileConfig() error {
Delimiter: "",
}
}
if idCfg.roleTokenNamingFormat != "" {
return TokenFileConfig{
Use: true,
Format: idCfg.roleTokenNamingFormat,
Delimiter: idCfg.roleTokenFilenameDelimiter,
}
}
return TokenFileConfig{
Use: true,
Format: filepath.Join(idCfg.tokenDir, "{{domain}}{{delimiter}}{{role}}.roletoken"),
Delimiter: ":role.",
Delimiter: idCfg.roleTokenFilenameDelimiter,
}
}(),
}
Expand Down
8 changes: 6 additions & 2 deletions pkg/config/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ type IdentityConfig struct {
roleCertKeyNamingFormat string
//
// Token Cache Derived State and its related fields:
TokenFile DerivedTokenFile
tokenDir string
TokenFile DerivedTokenFile
tokenDir string
accessTokenFilenameDelimiter string
accessTokenNamingFormat string
roleTokenFilenameDelimiter string
roleTokenNamingFormat string
//
// Token Server Derived State and its related fields:
TokenServer DerivedTokenServer
Expand Down
20 changes: 13 additions & 7 deletions pkg/token/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ func New(ctx context.Context, idCfg *config.IdentityConfig) (daemon.Daemon, erro
log.Info("Skipped token provider initiation")
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
// TODO: Maybe if !idCfg.TokenFile.Use()
if !idCfg.TokenFile.AccessToken.Use && !idCfg.TokenFile.RoleToken.Use {
if !idCfg.TokenFile.AccessToken.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)
log.Debugf("Skipping to write access token files to directory with empty filename format[%s]", idCfg.TokenFile.AccessToken.Format)
}
if !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 role token files to directory with empty filename format[%s]", idCfg.TokenFile.RoleToken.Format)
}

// initialize token cache with placeholder
Expand Down Expand Up @@ -401,6 +403,9 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error {
// File output processing
domain, role := key.Domain, key.Role
token := d.accessTokenCache.Load(key)
if token == nil {
return fmt.Errorf("failed to load access token from cache: %s", key.String())
}
outPath, err := extutil.GeneratePath(d.idCfg.TokenFile.AccessToken.Format, domain, role, d.idCfg.TokenFile.AccessToken.Delimiter)
if err != nil {
return fmt.Errorf("failed to generate path for access token with format [%s], domain [%s], role [%s], delimiter [%s]: %w", d.idCfg.TokenFile.AccessToken.Format, domain, role, d.idCfg.TokenFile.AccessToken.Delimiter, err)
Expand All @@ -415,6 +420,9 @@ func (d *tokenService) updateAndWriteFileToken(key CacheKey, tt mode) error {
// File output processing
domain, role := key.Domain, key.Role
token := d.roleTokenCache.Load(key)
if token == nil {
return fmt.Errorf("failed to load role token from cache: %s", key.String())
}
outPath, err := extutil.GeneratePath(d.idCfg.TokenFile.RoleToken.Format, domain, role, d.idCfg.TokenFile.RoleToken.Delimiter)
if err != nil {
return fmt.Errorf("failed to generate path for role token with format [%s], domain [%s], role [%s], delimiter [%s]: %w", d.idCfg.TokenFile.RoleToken.Format, domain, role, d.idCfg.TokenFile.RoleToken.Delimiter, err)
Expand Down Expand Up @@ -445,8 +453,6 @@ func (d *tokenService) writeFile(token Token, outPath string, tt mode) error {
return fmt.Errorf("invalid token type: %d", tt)
}

domain := token.Domain()
role := token.Role()
rawToken := token.Raw()
if rawToken == "" {
// skip placeholder token added during daemon creation
Expand All @@ -458,7 +464,7 @@ func (d *tokenService) writeFile(token Token, outPath string, tt mode) error {
return fmt.Errorf("unable to create directory for token: %w", err)
}
// Unlike the delimiter used for file names, the log output will use the Athenz standard delimiter ":role.":
log.Infof("[New %s Token] Subject: %s:role.%s [%d bytes] in %s", tokenType, domain, role, len(rawToken), outPath)
log.Infof("[New %s Token] Subject: %s:role.%s [%d bytes] in %s", tokenType, token.Domain(), token.Role(), len(rawToken), outPath)
if err := w.AddBytes(outPath, 0644, []byte(rawToken)); err != nil {
return fmt.Errorf("unable to save %s Token: %w", tokenType, err)
}
Expand Down

0 comments on commit bbb7bdd

Please sign in to comment.