From 0a41ea55a08619a0423e65d92f972ce6eb227355 Mon Sep 17 00:00:00 2001 From: Henry Avetisyan Date: Fri, 13 Sep 2024 12:52:49 -0700 Subject: [PATCH] do not exit when token refresh fails while pod is running (#2724) extend cmd line support to accept multiple arguments Signed-off-by: Henry Avetisyan --- libs/go/sia/agent/agent.go | 81 ++++--- libs/go/sia/agent/agent_test.go | 2 +- libs/go/sia/aws/agent/agent.go | 81 ++++--- libs/go/sia/aws/agent/agent_test.go | 2 +- libs/go/sia/aws/options/options.go | 310 +++++++++++++----------- libs/go/sia/aws/options/options_test.go | 8 + libs/go/sia/options/options.go | 246 ++++++++++--------- libs/go/sia/options/options_test.go | 8 + libs/go/sia/util/util.go | 9 +- libs/go/sia/util/util_test.go | 4 +- pom.xml | 1 + provider/gcp/sia-run/pom.xml | 2 +- 12 files changed, 430 insertions(+), 324 deletions(-) diff --git a/libs/go/sia/agent/agent.go b/libs/go/sia/agent/agent.go index 2b4c8342c6d..5485443713e 100644 --- a/libs/go/sia/agent/agent.go +++ b/libs/go/sia/agent/agent.go @@ -85,10 +85,10 @@ func RoleKey(rotateKey bool, roleKey, svcKey string) (*rsa.PrivateKey, error) { } } -func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { +func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, []string) { //initialize our return state to success - failures := 0 + failures := make([]string, 0) for _, role := range opts.Roles { var roleRequest = new(zts.RoleCertificateRequest) @@ -99,7 +99,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { client, err := util.ZtsClient(ztsUrl, opts.ZTSServerName, svcKeyFile, svcCertFile, opts.ZTSCACertFile) if err != nil { log.Printf("unable to initialize ZTS Client with url %s for role %s, err: %v\n", ztsUrl, role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } client.AddCredentials("User-Agent", opts.Version) @@ -112,7 +112,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { } if err != nil { log.Printf("unable to read private key role %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } @@ -134,7 +134,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { csr, err := util.GenerateRoleCertCSR(key, roleCertReqOptions) if err != nil { log.Printf("unable to generate CSR for %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } roleRequest.Csr = csr @@ -155,18 +155,18 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { roleCert, err := client.PostRoleCertificateRequestExt(roleRequest) if err != nil { log.Printf("PostRoleCertificateRequest failed for %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } roleKeyBytes := util.PrivatePem(key) err = util.SaveRoleCertKey([]byte(roleKeyBytes), []byte(roleCert.X509Certificate), role.RoleKeyFilename, role.RoleCertFilename, svcKeyFile, role.Name, role.Uid, role.Gid, role.FileMode, opts.GenerateRoleKey, opts.RotateKey, opts.BackupDir, opts.FileDirectUpdate) if err != nil { log.Printf("Unable to save role cert key for role %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } } - log.Printf("SIA processed %d (failures %d) role certificate requests\n", len(opts.Roles), failures) + log.Printf("SIA processed %d (failures %d) role certificate requests\n", len(opts.Roles), len(failures)) return len(opts.Roles), failures } @@ -601,7 +601,14 @@ func SetupAgent(opts *options.Options, siaMainDir, siaLinkDir string) { } } -func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { +func RunAgent(siaCmds, ztsUrl string, opts *options.Options) { + cmds := strings.Split(siaCmds, ",") + for _, cmd := range cmds { + runAgentCommand(cmd, ztsUrl, opts) + } +} + +func runAgentCommand(siaCmd, ztsUrl string, opts *options.Options) { //make sure the meta endpoint is configured by the caller if opts.MetaEndPoint == "" { @@ -626,19 +633,25 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { switch cmd { case "rolecert": count, failures := GetRoleCertificates(ztsUrl, opts) - if failures != 0 && !skipErrors { - log.Fatalf("unable to fetch %d out of %d requested role certificates\n", failures, count) + if len(failures) != 0 { + util.ExecuteScript(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + if !skipErrors { + log.Fatalf("unable to fetch %d out of %d requested role certificates\n", len(failures), count) + } } if count != 0 { - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) } case "token": if tokenOpts != nil { err := fetchAccessToken(tokenOpts) - if err != nil && !skipErrors { - log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + if err != nil { + util.ExecuteScript(opts.RunAfterTokensErrParts, err.Error(), false) + if !skipErrors { + log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + } } - util.ExecuteScript(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } else { log.Print("unable to fetch access tokens, invalid or missing configuration") } @@ -647,14 +660,14 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { if err != nil { log.Fatalf("Unable to register identity, err: %v\n", err) } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) log.Printf("identity registered for services: %s\n", svcs) case "rotate", "refresh": err = RefreshInstance(ztsUrl, opts) if err != nil { log.Fatalf("Refresh identity failed, err: %v\n", err) } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) log.Printf("Identity successfully refreshed for services: %s\n", svcs) case "init": err := RegisterInstance(ztsUrl, opts, false) @@ -663,16 +676,22 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { } log.Printf("identity registered for services: %s\n", svcs) count, failures := GetRoleCertificates(ztsUrl, opts) - if failures != 0 && !skipErrors { - log.Fatalf("unable to fetch %d out of %d requested role certificates\n", failures, count) + if len(failures) != 0 { + util.ExecuteScript(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + if !skipErrors { + log.Fatalf("unable to fetch %d out of %d requested role certificates\n", len(failures), count) + } } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) if tokenOpts != nil { err := fetchAccessToken(tokenOpts) - if err != nil && !skipErrors { - log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + if err != nil { + util.ExecuteScript(opts.RunAfterTokensErrParts, err.Error(), false) + if !skipErrors { + log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + } } - util.ExecuteScript(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } default: // we're going to iterate through our configured services. @@ -729,6 +748,7 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { errors <- fmt.Errorf("refresh identity failed: %v\n", err) return } else { + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsErrParts, svcs, false) log.Printf("refresh identity failed for svcs %s, error: %v\n", svcs, err) log.Printf("refresh will be retried in %d minutes, failure %d of %d\n", opts.RefreshInterval, failedRefreshCount, opts.FailCountForExit) } @@ -741,15 +761,18 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { if tokenOpts != nil { err := accessTokenRequest(tokenOpts) if err != nil { - errors <- fmt.Errorf("Unable to fetch access tokens after identity refresh, err: %v\n", err) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensErrParts, err.Error(), false) } else { - util.ExecuteScriptWithoutBlock(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } } else { log.Print("token config does not exist - do not refresh tokens") } - GetRoleCertificates(ztsUrl, opts) - util.ExecuteScriptWithoutBlock(opts.RunAfterParts, opts.RunAfterFailExit) + _, failures := GetRoleCertificates(ztsUrl, opts) + if len(failures) != 0 { + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + } + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) util.NotifySystemdReadyForCommand(cmd, "systemd-notify-all") if opts.SDSUdsPath != "" { @@ -799,9 +822,9 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { log.Printf("refreshing access-token..") err := accessTokenRequest(tokenOpts) if err != nil { - errors <- fmt.Errorf("refresh access-token task got error: %v\n", err) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensErrParts, err.Error(), false) } else { - util.ExecuteScriptWithoutBlock(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } case <-stop: errors <- nil diff --git a/libs/go/sia/agent/agent_test.go b/libs/go/sia/agent/agent_test.go index c83f8a3013b..2eb6143d8d9 100644 --- a/libs/go/sia/agent/agent_test.go +++ b/libs/go/sia/agent/agent_test.go @@ -372,7 +372,7 @@ func TestRoleCertificateRequest(test *testing.T) { } _, failures := GetRoleCertificates("http://127.0.0.1:5084/zts/v1", opts) - if failures != 0 { + if len(failures) != 0 { test.Errorf("Unable to get role certificate: %v", err) return } diff --git a/libs/go/sia/aws/agent/agent.go b/libs/go/sia/aws/agent/agent.go index 83731476629..5a7175e4721 100644 --- a/libs/go/sia/aws/agent/agent.go +++ b/libs/go/sia/aws/agent/agent.go @@ -87,10 +87,10 @@ func RoleKey(rotateKey bool, roleKey, svcKey string) (*rsa.PrivateKey, error) { } } -func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { +func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, []string) { //initialize our return state to success - failures := 0 + failures := make([]string, 0) for _, role := range opts.Roles { var roleRequest = new(zts.RoleCertificateRequest) @@ -101,7 +101,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { client, err := util.ZtsClient(ztsUrl, opts.ZTSServerName, svcKeyFile, svcCertFile, opts.ZTSCACertFile) if err != nil { log.Printf("unable to initialize ZTS Client with url %s for role %s, err: %v\n", ztsUrl, role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } client.AddCredentials("User-Agent", opts.Version) @@ -114,7 +114,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { } if err != nil { log.Printf("unable to read private key role %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } @@ -136,7 +136,7 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { csr, err := util.GenerateRoleCertCSR(key, roleCertReqOptions) if err != nil { log.Printf("unable to generate CSR for %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } roleRequest.Csr = csr @@ -157,18 +157,18 @@ func GetRoleCertificates(ztsUrl string, opts *options.Options) (int, int) { roleCert, err := client.PostRoleCertificateRequestExt(roleRequest) if err != nil { log.Printf("PostRoleCertificateRequest failed for %s, err: %v\n", role.Name, err) - failures += 1 + failures = append(failures, role.Name) continue } roleKeyBytes := util.PrivatePem(key) err = util.SaveRoleCertKey([]byte(roleKeyBytes), []byte(roleCert.X509Certificate), role.RoleKeyFilename, role.RoleCertFilename, svcKeyFile, role.Name, role.Uid, role.Gid, role.FileMode, opts.GenerateRoleKey, opts.RotateKey, opts.BackupDir, opts.FileDirectUpdate) if err != nil { - failures += 1 + failures = append(failures, role.Name) continue } } - log.Printf("SIA processed %d (failures %d) role certificate requests\n", len(opts.Roles), failures) + log.Printf("SIA processed %d (failures %d) role certificate requests\n", len(opts.Roles), len(failures)) return len(opts.Roles), failures } @@ -597,7 +597,14 @@ func SetupAgent(opts *options.Options, siaMainDir, siaLinkDir string) { } } -func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { +func RunAgent(siaCmds, ztsUrl string, opts *options.Options) { + cmds := strings.Split(siaCmds, ",") + for _, cmd := range cmds { + runAgentCommand(cmd, ztsUrl, opts) + } +} + +func runAgentCommand(siaCmd, ztsUrl string, opts *options.Options) { //make sure the meta endpoint is configured by the caller if opts.MetaEndPoint == "" { @@ -622,19 +629,25 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { switch cmd { case "rolecert": count, failures := GetRoleCertificates(ztsUrl, opts) - if failures != 0 && !skipErrors { - log.Fatalf("unable to fetch %d out of %d requested role certificates\n", failures, count) + if len(failures) != 0 { + util.ExecuteScript(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + if !skipErrors { + log.Fatalf("unable to fetch %d out of %d requested role certificates\n", len(failures), count) + } } if count != 0 { - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) } case "token": if tokenOpts != nil { err := fetchAccessToken(tokenOpts) - if err != nil && !skipErrors { - log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + if err != nil { + util.ExecuteScript(opts.RunAfterTokensErrParts, err.Error(), false) + if !skipErrors { + log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + } } - util.ExecuteScript(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } else { log.Print("unable to fetch access tokens, invalid or missing configuration") } @@ -643,14 +656,14 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { if err != nil { log.Fatalf("Unable to register identity, err: %v\n", err) } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) log.Printf("identity registered for services: %s\n", svcs) case "rotate", "refresh": err = RefreshInstance(data, ztsUrl, opts) if err != nil { log.Fatalf("Refresh identity failed, err: %v\n", err) } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) log.Printf("Identity successfully refreshed for services: %s\n", svcs) case "init": err := RegisterInstance(data, ztsUrl, opts, false) @@ -659,16 +672,22 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { } log.Printf("identity registered for services: %s\n", svcs) count, failures := GetRoleCertificates(ztsUrl, opts) - if failures != 0 && !skipErrors { - log.Fatalf("unable to fetch %d out of %d requested role certificates\n", failures, count) + if len(failures) != 0 { + util.ExecuteScript(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + if !skipErrors { + log.Fatalf("unable to fetch %d out of %d requested role certificates\n", len(failures), count) + } } - util.ExecuteScript(opts.RunAfterParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) if tokenOpts != nil { err := fetchAccessToken(tokenOpts) - if err != nil && !skipErrors { - log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + if err != nil { + util.ExecuteScript(opts.RunAfterTokensErrParts, err.Error(), false) + if !skipErrors { + log.Fatalf("Unable to fetch access tokens, err: %v\n", err) + } } - util.ExecuteScript(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScript(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } default: // we're going to iterate through our configured services. @@ -730,6 +749,7 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { errors <- fmt.Errorf("refresh identity failed: %v\n", err) return } else { + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsErrParts, svcs, false) log.Printf("refresh identity failed for svcs %s, error: %v\n", svcs, err) log.Printf("refresh will be retried in %d minutes, failure %d of %d\n", opts.RefreshInterval, failedRefreshCount, opts.FailCountForExit) } @@ -742,15 +762,18 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { if tokenOpts != nil { err := accessTokenRequest(tokenOpts) if err != nil { - errors <- fmt.Errorf("Unable to fetch access token after identity refresh, err: %v\n", err) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensErrParts, err.Error(), false) } else { - util.ExecuteScriptWithoutBlock(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } } else { log.Print("token config does not exist - do not refresh token") } - GetRoleCertificates(ztsUrl, opts) - util.ExecuteScriptWithoutBlock(opts.RunAfterParts, opts.RunAfterFailExit) + _, failures := GetRoleCertificates(ztsUrl, opts) + if len(failures) != 0 { + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsErrParts, strings.Join(failures, ","), false) + } + util.ExecuteScriptWithoutBlock(opts.RunAfterCertsOkParts, "", opts.RunAfterFailExit) util.NotifySystemdReadyForCommand(cmd, "systemd-notify-all") if opts.SDSUdsPath != "" { @@ -800,9 +823,9 @@ func RunAgent(siaCmd, ztsUrl string, opts *options.Options) { log.Printf("refreshing access-token..") err := accessTokenRequest(tokenOpts) if err != nil { - errors <- fmt.Errorf("refresh access-token task got error: %v\n", err) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensErrParts, err.Error(), false) } else { - util.ExecuteScriptWithoutBlock(opts.RunAfterTokensParts, opts.RunAfterFailExit) + util.ExecuteScriptWithoutBlock(opts.RunAfterTokensOkParts, "", opts.RunAfterFailExit) } case <-stop: errors <- nil diff --git a/libs/go/sia/aws/agent/agent_test.go b/libs/go/sia/aws/agent/agent_test.go index c29be7728e0..dfe64c87a1a 100644 --- a/libs/go/sia/aws/agent/agent_test.go +++ b/libs/go/sia/aws/agent/agent_test.go @@ -388,7 +388,7 @@ func TestRoleCertificateRequest(test *testing.T) { } _, failures := GetRoleCertificates("http://127.0.0.1:5084/zts/v1", opts) - if failures != 0 { + if len(failures) != 0 { test.Errorf("Unable to get role certificate: %v", err) return } diff --git a/libs/go/sia/aws/options/options.go b/libs/go/sia/aws/options/options.go index 8c0c65d4d6d..8fff4d8f6cf 100644 --- a/libs/go/sia/aws/options/options.go +++ b/libs/go/sia/aws/options/options.go @@ -79,41 +79,43 @@ type ConfigAccount struct { // Config represents entire sia_config file type Config struct { - Version string `json:"version,omitempty"` //name of the provider - Service string `json:"service,omitempty"` //name of the service for the identity - Services map[string]ConfigService `json:"services,omitempty"` //names of the multiple services for the identity - Ssh *bool `json:"ssh,omitempty"` //ssh certificate support - SshHostKeyType hostkey.KeyType `json:"ssh_host_key_type,omitempty"` //ssh host key type - rsa, ecdsa, etc - SshPrincipals string `json:"ssh_principals,omitempty"` //ssh additional principals - SanDnsWildcard bool `json:"sandns_wildcard,omitempty"` //san dns wildcard support - SanDnsHostname bool `json:"sandns_hostname,omitempty"` //san dns hostname support - SanDnsX509Cnames string `json:"sandns_x509_cnames,omitempty"` //additional san dns entries to be added to the CSR - UseRegionalSTS bool `json:"regionalsts,omitempty"` //whether to use a regional STS endpoint (default is false) - Accounts []ConfigAccount `json:"accounts,omitempty"` //array of configured accounts - GenerateRoleKey bool `json:"generate_role_key,omitempty"` //private key to be generated for role certificate - RotateKey bool `json:"rotate_key,omitempty"` //rotate private key support - User string `json:"user,omitempty"` //the username to chown the cert/key dirs to. If absent, then root - Group string `json:"group,omitempty"` //the group name to chown the cert/key dirs to. If absent, then athenz - SDSUdsPath string `json:"sds_uds_path,omitempty"` //uds path if the agent should support uds connections - SDSUdsUid int `json:"sds_uds_uid,omitempty"` //uds connections must be from the given user uid - ExpiryTime int `json:"expiry_time,omitempty"` //service and role certificate expiry in minutes - RefreshInterval int `json:"refresh_interval,omitempty"` //specifies refresh interval in minutes - ZTSRegion string `json:"zts_region,omitempty"` //specifies zts region for the requests - DropPrivileges bool `json:"drop_privileges,omitempty"` //drop privileges to configured user instead of running as root - AccessTokens map[string]ac.Role `json:"access_tokens,omitempty"` //map of role name to token attributes - FileDirectUpdate bool `json:"file_direct_update,omitempty"` //update key/cert files directly instead of using rename - SiaKeyDir string `json:"sia_key_dir,omitempty"` //sia keys directory to override /var/lib/sia/keys - SiaCertDir string `json:"sia_cert_dir,omitempty"` //sia certs directory to override /var/lib/sia/certs - SiaTokenDir string `json:"sia_token_dir,omitempty"` //sia tokens directory to override /var/lib/sia/tokens - SiaBackupDir string `json:"sia_backup_dir,omitempty"` //sia backup directory to override /var/lib/sia/backup - HostnameSuffix string `json:"hostname_suffix,omitempty"` //hostname suffix in case we need to auto-generate hostname - AccessManagement bool `json:"access_management,omitempty"` //access management support - FailCountForExit int `json:"fail_count_for_exit,omitempty"` //number of failed counts before exiting program - RunAfter string `json:"run_after,omitempty"` //execute the command mentioned after certs are created - RunAfterTokens string `json:"run_after_tokens,omitempty"` //execute the command mentioned after tokens are created - SpiffeTrustDomain string `json:"spiffe_trust_domain,omitempty"` //spiffe trust domain - if configured used full spiffe uri with namespace - StoreTokenOption *int `json:"store_token_option,omitempty"` //store access token option - RunAfterFailExit bool `json:"run_after_fail_exit,omitempty"` //exit process if run_after script fails + Version string `json:"version,omitempty"` //name of the provider + Service string `json:"service,omitempty"` //name of the service for the identity + Services map[string]ConfigService `json:"services,omitempty"` //names of the multiple services for the identity + Ssh *bool `json:"ssh,omitempty"` //ssh certificate support + SshHostKeyType hostkey.KeyType `json:"ssh_host_key_type,omitempty"` //ssh host key type - rsa, ecdsa, etc + SshPrincipals string `json:"ssh_principals,omitempty"` //ssh additional principals + SanDnsWildcard bool `json:"sandns_wildcard,omitempty"` //san dns wildcard support + SanDnsHostname bool `json:"sandns_hostname,omitempty"` //san dns hostname support + SanDnsX509Cnames string `json:"sandns_x509_cnames,omitempty"` //additional san dns entries to be added to the CSR + UseRegionalSTS bool `json:"regionalsts,omitempty"` //whether to use a regional STS endpoint (default is false) + Accounts []ConfigAccount `json:"accounts,omitempty"` //array of configured accounts + GenerateRoleKey bool `json:"generate_role_key,omitempty"` //private key to be generated for role certificate + RotateKey bool `json:"rotate_key,omitempty"` //rotate private key support + User string `json:"user,omitempty"` //the username to chown the cert/key dirs to. If absent, then root + Group string `json:"group,omitempty"` //the group name to chown the cert/key dirs to. If absent, then athenz + SDSUdsPath string `json:"sds_uds_path,omitempty"` //uds path if the agent should support uds connections + SDSUdsUid int `json:"sds_uds_uid,omitempty"` //uds connections must be from the given user uid + ExpiryTime int `json:"expiry_time,omitempty"` //service and role certificate expiry in minutes + RefreshInterval int `json:"refresh_interval,omitempty"` //specifies refresh interval in minutes + ZTSRegion string `json:"zts_region,omitempty"` //specifies zts region for the requests + DropPrivileges bool `json:"drop_privileges,omitempty"` //drop privileges to configured user instead of running as root + AccessTokens map[string]ac.Role `json:"access_tokens,omitempty"` //map of role name to token attributes + FileDirectUpdate bool `json:"file_direct_update,omitempty"` //update key/cert files directly instead of using rename + SiaKeyDir string `json:"sia_key_dir,omitempty"` //sia keys directory to override /var/lib/sia/keys + SiaCertDir string `json:"sia_cert_dir,omitempty"` //sia certs directory to override /var/lib/sia/certs + SiaTokenDir string `json:"sia_token_dir,omitempty"` //sia tokens directory to override /var/lib/sia/tokens + SiaBackupDir string `json:"sia_backup_dir,omitempty"` //sia backup directory to override /var/lib/sia/backup + HostnameSuffix string `json:"hostname_suffix,omitempty"` //hostname suffix in case we need to auto-generate hostname + AccessManagement bool `json:"access_management,omitempty"` //access management support + FailCountForExit int `json:"fail_count_for_exit,omitempty"` //number of failed counts before exiting program + RunAfterCerts string `json:"run_after,omitempty"` //execute the command mentioned after certs are created + RunAfterCertsErr string `json:"run_after_certs_err,omitempty"` //execute the command mentioned after role certs fail to refresh + RunAfterTokens string `json:"run_after_tokens,omitempty"` //execute the command mentioned after tokens are created + RunAfterTokensErr string `json:"run_after_tokens_err,omitempty"` //execute the command mentioned after tokens fail to refresh + SpiffeTrustDomain string `json:"spiffe_trust_domain,omitempty"` //spiffe trust domain - if configured used full spiffe uri with namespace + StoreTokenOption *int `json:"store_token_option,omitempty"` //store access token option + RunAfterFailExit bool `json:"run_after_fail_exit,omitempty"` //exit process if run_after script fails } type AccessProfileConfig struct { @@ -156,70 +158,72 @@ type Service struct { // Options represents settings that are derived from config file and application defaults type Options struct { - Provider provider.Provider //provider instance - MetaEndPoint string //meta data service endpoint - Name string //name of the service identity - User string //the username to chown the cert/key dirs to. If absent, then root - Group string //the group name to chown the cert/key dirs to. If absent, then athenz - Domain string //name of the domain for the identity - Account string //name of the account - Service string //name of the service for the identity - Zts string //the ZTS to contact - InstanceId string //instance id if ec2, task id if running within eks/ecs - Roles []Role //map of roles to retrieve certificates for - Region string //region name - SanDnsWildcard bool //san dns wildcard support - SanDnsHostname bool //san dns hostname support - Version string //sia version number - ZTSDomains []string //zts domain prefixes - Services []Service //array of configured services - Ssh bool //ssh certificate support - UseRegionalSTS bool //use regional sts endpoint - KeyDir string //private key directory path - CertDir string //x.509 certificate directory path - AthenzCACertFile string //filename to store Athenz CA certs - ZTSCACertFile string //filename for CA certs when communicating with ZTS - ZTSServerName string //ZTS server name, if necessary for tls - ZTSAWSDomains []string //list of domain prefixes for sanDNS entries - GenerateRoleKey bool //option to generate a separate key for role certificates - RotateKey bool //rotate the private key when refreshing certificates - BackupDir string //backup directory for key/cert rotation - CertCountryName string //generated x.509 certificate country name - CertOrgName string //generated x.509 certificate organization name - SshPubKeyFile string //ssh host public key file path - SshCertFile string //ssh host certificate file path - SshConfigFile string //sshd config file path - SshHostKeyType hostkey.KeyType //ssh host key type - rsa or ecdsa - PrivateIp string //instance private ip - EC2Document string //EC2 instance identity document - EC2Signature string //EC2 instance identity document pkcs7 signature - EC2StartTime *time.Time //EC2 instance start time - InstanceIdSanDNS bool //include instance id in a san dns entry (backward compatible option) - RolePrincipalEmail bool //include role principal in a san email field (backward compatible option) - SDSUdsPath string //UDS path if the agent should support uds connections - SDSUdsUid int //UDS connections must be from the given user uid - RefreshInterval int //refresh interval for certificates - default 24 hours - ZTSRegion string //ZTS region in case the client needs this information - DropPrivileges bool //Drop privileges to configured user instead of running as root - TokenDir string //Access tokens directory - AccessTokens []ac.AccessToken //Access tokens object - Profile string //Access profile name - ProfileRestrictTo string //Tag associated with access profile roles - Threshold float64 //threshold in number of days for cert expiry checks - SshThreshold float64 //threshold in number of days for ssh cert expiry checks - FileDirectUpdate bool //update key/cert files directly instead of using rename - HostnameSuffix string //hostname suffix in case we need to auto-generate hostname - SshPrincipals string //ssh additional principals - AccessManagement bool //access management support - AddlSanDNSEntries []string //additional san dns entries to be added to the CSR - FailCountForExit int //number of failed counts before exiting program - RunAfterParts []string //run after parsed parts - RunAfterTokensParts []string //run after token parsed parts - SpiffeTrustDomain string //spiffe uri trust domain - SpiffeNamespace string //spiffe uri namespace - OmitDomain bool //attestation role only includes service name - StoreTokenOption *int //store access token option - RunAfterFailExit bool //exit process if run_after script fails + Provider provider.Provider //provider instance + MetaEndPoint string //meta data service endpoint + Name string //name of the service identity + User string //the username to chown the cert/key dirs to. If absent, then root + Group string //the group name to chown the cert/key dirs to. If absent, then athenz + Domain string //name of the domain for the identity + Account string //name of the account + Service string //name of the service for the identity + Zts string //the ZTS to contact + InstanceId string //instance id if ec2, task id if running within eks/ecs + Roles []Role //map of roles to retrieve certificates for + Region string //region name + SanDnsWildcard bool //san dns wildcard support + SanDnsHostname bool //san dns hostname support + Version string //sia version number + ZTSDomains []string //zts domain prefixes + Services []Service //array of configured services + Ssh bool //ssh certificate support + UseRegionalSTS bool //use regional sts endpoint + KeyDir string //private key directory path + CertDir string //x.509 certificate directory path + AthenzCACertFile string //filename to store Athenz CA certs + ZTSCACertFile string //filename for CA certs when communicating with ZTS + ZTSServerName string //ZTS server name, if necessary for tls + ZTSAWSDomains []string //list of domain prefixes for sanDNS entries + GenerateRoleKey bool //option to generate a separate key for role certificates + RotateKey bool //rotate the private key when refreshing certificates + BackupDir string //backup directory for key/cert rotation + CertCountryName string //generated x.509 certificate country name + CertOrgName string //generated x.509 certificate organization name + SshPubKeyFile string //ssh host public key file path + SshCertFile string //ssh host certificate file path + SshConfigFile string //sshd config file path + SshHostKeyType hostkey.KeyType //ssh host key type - rsa or ecdsa + PrivateIp string //instance private ip + EC2Document string //EC2 instance identity document + EC2Signature string //EC2 instance identity document pkcs7 signature + EC2StartTime *time.Time //EC2 instance start time + InstanceIdSanDNS bool //include instance id in a san dns entry (backward compatible option) + RolePrincipalEmail bool //include role principal in a san email field (backward compatible option) + SDSUdsPath string //UDS path if the agent should support uds connections + SDSUdsUid int //UDS connections must be from the given user uid + RefreshInterval int //refresh interval for certificates - default 24 hours + ZTSRegion string //ZTS region in case the client needs this information + DropPrivileges bool //Drop privileges to configured user instead of running as root + TokenDir string //Access tokens directory + AccessTokens []ac.AccessToken //Access tokens object + Profile string //Access profile name + ProfileRestrictTo string //Tag associated with access profile roles + Threshold float64 //threshold in number of days for cert expiry checks + SshThreshold float64 //threshold in number of days for ssh cert expiry checks + FileDirectUpdate bool //update key/cert files directly instead of using rename + HostnameSuffix string //hostname suffix in case we need to auto-generate hostname + SshPrincipals string //ssh additional principals + AccessManagement bool //access management support + AddlSanDNSEntries []string //additional san dns entries to be added to the CSR + FailCountForExit int //number of failed counts before exiting program + RunAfterCertsOkParts []string //run after certificate parsed parts for success + RunAfterCertsErrParts []string //run after certificate parsed parts for errors + RunAfterTokensOkParts []string //run after token parsed parts for success + RunAfterTokensErrParts []string //run after token parsed parts for errors + SpiffeTrustDomain string //spiffe uri trust domain + SpiffeNamespace string //spiffe uri namespace + OmitDomain bool //attestation role only includes service name + StoreTokenOption *int //store access token option + RunAfterFailExit bool //exit process if run_after script fails } const ( @@ -442,12 +446,18 @@ func InitEnvConfig(config *Config) (*Config, *ConfigAccount, error) { if config.SshPrincipals == "" { config.SshPrincipals = os.Getenv("ATHENZ_SIA_SSH_PRINCIPALS") } - if config.RunAfter == "" { - config.RunAfter = os.Getenv("ATHENZ_SIA_RUN_AFTER") + if config.RunAfterCerts == "" { + config.RunAfterCerts = os.Getenv("ATHENZ_SIA_RUN_AFTER") } if config.RunAfterTokens == "" { config.RunAfterTokens = os.Getenv("ATHENZ_SIA_RUN_AFTER_TOKENS") } + if config.RunAfterCertsErr == "" { + config.RunAfterCertsErr = os.Getenv("ATHENZ_SIA_RUN_AFTER_CERTS_ERROR") + } + if config.RunAfterTokensErr == "" { + config.RunAfterTokensErr = os.Getenv("ATHENZ_SIA_RUN_AFTER_TOKENS_ERROR") + } if config.SpiffeTrustDomain == "" { config.SpiffeTrustDomain = os.Getenv("ATHENZ_SIA_SPIFFE_TRUST_DOMAIN") } @@ -552,8 +562,10 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro sshPrincipals := "" accessManagement := false failCountForExit := 2 - runAfter := "" + runAfterCerts := "" + runAfterCertsErr := "" runAfterTokens := "" + runAfterTokensErr := "" spiffeTrustDomain := "" addlSanDNSEntries := make([]string, 0) runAfterFailExit := false @@ -603,12 +615,18 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro if config.SshPrincipals != "" { sshPrincipals = config.SshPrincipals } - if config.RunAfter != "" { - runAfter = config.RunAfter + if config.RunAfterCerts != "" { + runAfterCerts = config.RunAfterCerts } if config.RunAfterTokens != "" { runAfterTokens = config.RunAfterTokens } + if config.RunAfterCertsErr != "" { + runAfterCertsErr = config.RunAfterCertsErr + } + if config.RunAfterTokensErr != "" { + runAfterTokensErr = config.RunAfterTokensErr + } if config.FailCountForExit > 0 { failCountForExit = config.FailCountForExit } @@ -750,47 +768,49 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro } return &Options{ - Name: account.Name, - User: account.User, - Group: account.Group, - Domain: account.Domain, - Account: account.Account, - Zts: account.Zts, - Version: fmt.Sprintf("SIA-AWS %s", version), - UseRegionalSTS: useRegionalSTS, - SanDnsWildcard: sanDnsWildcard, - SanDnsHostname: sanDnsHostname, - HostnameSuffix: hostnameSuffix, - Services: services, - Roles: roles, - TokenDir: tokenDir, - CertDir: certDir, - KeyDir: keyDir, - AthenzCACertFile: fmt.Sprintf("%s/ca.cert.pem", certDir), - GenerateRoleKey: generateRoleKey, - RotateKey: rotateKey, - BackupDir: backupDir, - SDSUdsPath: sdsUdsPath, - RefreshInterval: refreshInterval, - ZTSRegion: ztsRegion, - DropPrivileges: dropPrivileges, - AccessTokens: accessTokens, - Profile: profile, - ProfileRestrictTo: profileRestrictTo, - Threshold: account.Threshold, - SshThreshold: account.SshThreshold, - FileDirectUpdate: fileDirectUpdate, - SshHostKeyType: sshHostKeyType, - SshPrincipals: sshPrincipals, - AccessManagement: accessManagement, - FailCountForExit: failCountForExit, - RunAfterParts: util.ParseScriptArguments(runAfter), - RunAfterTokensParts: util.ParseScriptArguments(runAfterTokens), - SpiffeTrustDomain: spiffeTrustDomain, - OmitDomain: account.OmitDomain, - StoreTokenOption: storeTokenOption, - AddlSanDNSEntries: addlSanDNSEntries, - RunAfterFailExit: runAfterFailExit, + Name: account.Name, + User: account.User, + Group: account.Group, + Domain: account.Domain, + Account: account.Account, + Zts: account.Zts, + Version: fmt.Sprintf("SIA-AWS %s", version), + UseRegionalSTS: useRegionalSTS, + SanDnsWildcard: sanDnsWildcard, + SanDnsHostname: sanDnsHostname, + HostnameSuffix: hostnameSuffix, + Services: services, + Roles: roles, + TokenDir: tokenDir, + CertDir: certDir, + KeyDir: keyDir, + AthenzCACertFile: fmt.Sprintf("%s/ca.cert.pem", certDir), + GenerateRoleKey: generateRoleKey, + RotateKey: rotateKey, + BackupDir: backupDir, + SDSUdsPath: sdsUdsPath, + RefreshInterval: refreshInterval, + ZTSRegion: ztsRegion, + DropPrivileges: dropPrivileges, + AccessTokens: accessTokens, + Profile: profile, + ProfileRestrictTo: profileRestrictTo, + Threshold: account.Threshold, + SshThreshold: account.SshThreshold, + FileDirectUpdate: fileDirectUpdate, + SshHostKeyType: sshHostKeyType, + SshPrincipals: sshPrincipals, + AccessManagement: accessManagement, + FailCountForExit: failCountForExit, + RunAfterCertsOkParts: util.ParseScriptArguments(runAfterCerts), + RunAfterCertsErrParts: util.ParseScriptArguments(runAfterCertsErr), + RunAfterTokensOkParts: util.ParseScriptArguments(runAfterTokens), + RunAfterTokensErrParts: util.ParseScriptArguments(runAfterTokensErr), + SpiffeTrustDomain: spiffeTrustDomain, + OmitDomain: account.OmitDomain, + StoreTokenOption: storeTokenOption, + AddlSanDNSEntries: addlSanDNSEntries, + RunAfterFailExit: runAfterFailExit, }, nil } diff --git a/libs/go/sia/aws/options/options_test.go b/libs/go/sia/aws/options/options_test.go index e154354e0da..a6a1407132e 100644 --- a/libs/go/sia/aws/options/options_test.go +++ b/libs/go/sia/aws/options/options_test.go @@ -759,6 +759,10 @@ func TestInitEnvConfig(t *testing.T) { os.Setenv("ATHENZ_SIA_STORE_TOKEN_OPTION", "2") os.Setenv("ATHENZ_SIA_OMIT_DOMAIN", "true") os.Setenv("ATHENZ_SIA_SANDNS_X509_CNAMES", "svc1.athenz.io,svc2.athenz.io") + os.Setenv("ATHENZ_SIA_RUN_AFTER", "/run-after.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_CERTS_ERROR", "/run-after-error.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_TOKENS", "/run-after-tokens.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_TOKENS_ERROR", "/run-after-tokens-error.sh") cfg, cfgAccount, err := InitEnvConfig(nil) require.Nilf(t, err, "error should be empty, error: %v", err) @@ -798,6 +802,10 @@ func TestInitEnvConfig(t *testing.T) { assert.Equal(t, 10, cfg.FailCountForExit) assert.Equal(t, 2, *cfg.StoreTokenOption) assert.True(t, cfgAccount.OmitDomain) + assert.Equal(t, "/run-after.sh", cfg.RunAfterCerts) + assert.Equal(t, "/run-after-error.sh", cfg.RunAfterCertsErr) + assert.Equal(t, "/run-after-tokens.sh", cfg.RunAfterTokens) + assert.Equal(t, "/run-after-tokens-error.sh", cfg.RunAfterTokensErr) os.Clearenv() } diff --git a/libs/go/sia/options/options.go b/libs/go/sia/options/options.go index 8926a32571e..04b6f05de5b 100644 --- a/libs/go/sia/options/options.go +++ b/libs/go/sia/options/options.go @@ -116,8 +116,10 @@ type Config struct { SshThreshold float64 `json:"sshcert_threshold_to_check,omitempty"` //threshold to verify for ssh certs AccessManagement bool `json:"access_management,omitempty"` //access management support FailCountForExit int `json:"fail_count_for_exit,omitempty"` //number of failed counts before exiting program - RunAfter string `json:"run_after,omitempty"` //execute the command mentioned after certs are created + RunAfterCerts string `json:"run_after,omitempty"` //execute the command mentioned after certs are created + RunAfterCertsErr string `json:"run_after_certs_err,omitempty"` //execute the command mentioned after role certs fail to refresh RunAfterTokens string `json:"run_after_tokens,omitempty"` //execute the command mentioned after tokens are created + RunAfterTokensErr string `json:"run_after_tokens_err,omitempty"` //execute the command mentioned after tokens fail to refresh SpiffeTrustDomain string `json:"spiffe_trust_domain,omitempty"` //spiffe trust domain - if configured generate full spiffe uri with namespace StoreTokenOption *int `json:"store_token_option,omitempty"` //store access token option RunAfterFailExit bool `json:"run_after_fail_exit,omitempty"` //exit process if run_after script fails @@ -163,72 +165,74 @@ type Service struct { // Options represents settings that are derived from config file and application defaults type Options struct { - Provider provider.Provider //provider instance - MetaEndPoint string //meta data service endpoint - Name string //name of the service identity - User string //the username to chown the cert/key dirs to. If absent, then root - Group string //the group name to chown the cert/key dirs to. If absent, then athenz - Domain string //name of the domain for the identity - Account string //name of the account - Service string //name of the service for the identity - Zts string //the ZTS to contact - InstanceId string //instance id if ec2/vm, task id if running within eks/ecs/gke - InstanceName string //instance name if ec2/vm - Roles []Role //map of roles to retrieve certificates for - Region string //region name - SanDnsWildcard bool //san dns wildcard support - SanDnsHostname bool //san dns hostname support - Version string //sia version number - ZTSDomains []string //zts domain prefixes - Services []Service //array of configured services - Ssh bool //ssh certificate support - UseRegionalSTS bool //use regional sts endpoint - KeyDir string //private key directory path - CertDir string //x.509 certificate directory path - AthenzCACertFile string //filename to store Athenz CA certs - ZTSCACertFile string //filename for CA certs when communicating with ZTS - ZTSServerName string //ZTS server name, if necessary for tls - ZTSAWSDomains []string //list of domain prefixes for sanDNS entries - GenerateRoleKey bool //option to generate a separate key for role certificates - RotateKey bool //rotate the private key when refreshing certificates - BackupDir string //backup directory for key/cert rotation - CertCountryName string //generated x.509 certificate country name - CertOrgName string //generated x.509 certificate organization name - SshPubKeyFile string //ssh host public key file path - SshCertFile string //ssh host certificate file path - SshConfigFile string //sshd config file path - SshHostKeyType hostkey.KeyType //ssh host key type - rsa or ecdsa - PrivateIp string //instance private ip - EC2Document string //EC2 instance identity document - EC2Signature string //EC2 instance identity document pkcs7 signature - EC2StartTime *time.Time //EC2 instance start time - InstanceIdSanDNS bool //include instance id in a san dns entry (backward compatible option) - RolePrincipalEmail bool //include role principal in a san email field (backward compatible option) - SDSUdsPath string //UDS path if the agent should support uds connections - SDSUdsUid int //UDS connections must be from the given user uid - RefreshInterval int //refresh interval for certificates - default 24 hours - ZTSRegion string //ZTS region in case the client needs this information - DropPrivileges bool //Drop privileges to configured user instead of running as root - TokenDir string //Access tokens directory - AccessTokens []ac.AccessToken //Access tokens object - Profile string //Access profile name - ProfileRestrictTo string //Tag associated with access profile roles - Threshold float64 //threshold in number of days for cert expiry checks - SshThreshold float64 //threshold in number of days for ssh cert expiry checks - FileDirectUpdate bool //update key/cert files directly instead of using rename - HostnameSuffix string //hostname suffix in case we need to auto-generate hostname - SshPrincipals string //ssh additional principals - AccessManagement bool //access management support - ZTSCloudDomains []string //list of domain prefixes for sanDNS entries - AddlSanDNSEntries []string //additional san dns entries to be added to the CSR - FailCountForExit int //number of failed counts before exiting program - RunAfterParts []string //run after parsed parts - RunAfterTokensParts []string //run after token parsed parts - SpiffeTrustDomain string //spiffe uri trust domain - SpiffeNamespace string //spiffe uri namespace - OmitDomain bool //attestation role only includes service name - StoreTokenOption *int //store access token option - RunAfterFailExit bool //exit process if run_after script fails + Provider provider.Provider //provider instance + MetaEndPoint string //meta data service endpoint + Name string //name of the service identity + User string //the username to chown the cert/key dirs to. If absent, then root + Group string //the group name to chown the cert/key dirs to. If absent, then athenz + Domain string //name of the domain for the identity + Account string //name of the account + Service string //name of the service for the identity + Zts string //the ZTS to contact + InstanceId string //instance id if ec2/vm, task id if running within eks/ecs/gke + InstanceName string //instance name if ec2/vm + Roles []Role //map of roles to retrieve certificates for + Region string //region name + SanDnsWildcard bool //san dns wildcard support + SanDnsHostname bool //san dns hostname support + Version string //sia version number + ZTSDomains []string //zts domain prefixes + Services []Service //array of configured services + Ssh bool //ssh certificate support + UseRegionalSTS bool //use regional sts endpoint + KeyDir string //private key directory path + CertDir string //x.509 certificate directory path + AthenzCACertFile string //filename to store Athenz CA certs + ZTSCACertFile string //filename for CA certs when communicating with ZTS + ZTSServerName string //ZTS server name, if necessary for tls + ZTSAWSDomains []string //list of domain prefixes for sanDNS entries + GenerateRoleKey bool //option to generate a separate key for role certificates + RotateKey bool //rotate the private key when refreshing certificates + BackupDir string //backup directory for key/cert rotation + CertCountryName string //generated x.509 certificate country name + CertOrgName string //generated x.509 certificate organization name + SshPubKeyFile string //ssh host public key file path + SshCertFile string //ssh host certificate file path + SshConfigFile string //sshd config file path + SshHostKeyType hostkey.KeyType //ssh host key type - rsa or ecdsa + PrivateIp string //instance private ip + EC2Document string //EC2 instance identity document + EC2Signature string //EC2 instance identity document pkcs7 signature + EC2StartTime *time.Time //EC2 instance start time + InstanceIdSanDNS bool //include instance id in a san dns entry (backward compatible option) + RolePrincipalEmail bool //include role principal in a san email field (backward compatible option) + SDSUdsPath string //UDS path if the agent should support uds connections + SDSUdsUid int //UDS connections must be from the given user uid + RefreshInterval int //refresh interval for certificates - default 24 hours + ZTSRegion string //ZTS region in case the client needs this information + DropPrivileges bool //Drop privileges to configured user instead of running as root + TokenDir string //Access tokens directory + AccessTokens []ac.AccessToken //Access tokens object + Profile string //Access profile name + ProfileRestrictTo string //Tag associated with access profile roles + Threshold float64 //threshold in number of days for cert expiry checks + SshThreshold float64 //threshold in number of days for ssh cert expiry checks + FileDirectUpdate bool //update key/cert files directly instead of using rename + HostnameSuffix string //hostname suffix in case we need to auto-generate hostname + SshPrincipals string //ssh additional principals + AccessManagement bool //access management support + ZTSCloudDomains []string //list of domain prefixes for sanDNS entries + AddlSanDNSEntries []string //additional san dns entries to be added to the CSR + FailCountForExit int //number of failed counts before exiting program + RunAfterCertsOkParts []string //run after certificate parsed parts for success + RunAfterCertsErrParts []string //run after certificate parsed parts for errors + RunAfterTokensOkParts []string //run after token parsed parts for success + RunAfterTokensErrParts []string //run after token parsed parts for errors + SpiffeTrustDomain string //spiffe uri trust domain + SpiffeNamespace string //spiffe uri namespace + OmitDomain bool //attestation role only includes service name + StoreTokenOption *int //store access token option + RunAfterFailExit bool //exit process if run_after script fails } const ( @@ -489,12 +493,18 @@ func InitEnvConfig(config *Config, provider provider.Provider) (*Config, *Config if config.SshPrincipals == "" { config.SshPrincipals = os.Getenv("ATHENZ_SIA_SSH_PRINCIPALS") } - if config.RunAfter == "" { - config.RunAfter = os.Getenv("ATHENZ_SIA_RUN_AFTER") + if config.RunAfterCerts == "" { + config.RunAfterCerts = os.Getenv("ATHENZ_SIA_RUN_AFTER") } if config.RunAfterTokens == "" { config.RunAfterTokens = os.Getenv("ATHENZ_SIA_RUN_AFTER_TOKENS") } + if config.RunAfterCertsErr == "" { + config.RunAfterCertsErr = os.Getenv("ATHENZ_SIA_RUN_AFTER_CERTS_ERROR") + } + if config.RunAfterTokensErr == "" { + config.RunAfterTokensErr = os.Getenv("ATHENZ_SIA_RUN_AFTER_TOKENS_ERROR") + } if config.SpiffeTrustDomain == "" { config.SpiffeTrustDomain = os.Getenv("ATHENZ_SIA_SPIFFE_TRUST_DOMAIN") } @@ -625,8 +635,10 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro sshPrincipals := "" accessManagement := false failCountForExit := 2 - runAfter := "" + runAfterCerts := "" + runAfterCertsErr := "" runAfterTokens := "" + runAfterTokensErr := "" spiffeTrustDomain := "" addlSanDNSEntries := make([]string, 0) runAfterFailExit := false @@ -677,12 +689,18 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro if config.SshPrincipals != "" { sshPrincipals = config.SshPrincipals } - if config.RunAfter != "" { - runAfter = config.RunAfter + if config.RunAfterCerts != "" { + runAfterCerts = config.RunAfterCerts } if config.RunAfterTokens != "" { runAfterTokens = config.RunAfterTokens } + if config.RunAfterCertsErr != "" { + runAfterCertsErr = config.RunAfterCertsErr + } + if config.RunAfterTokensErr != "" { + runAfterTokensErr = config.RunAfterTokensErr + } if config.FailCountForExit > 0 { failCountForExit = config.FailCountForExit } @@ -831,47 +849,49 @@ func setOptions(config *Config, account *ConfigAccount, profileConfig *AccessPro } return &Options{ - Name: account.Name, - User: account.User, - Group: account.Group, - Domain: account.Domain, - Account: account.Account, - Zts: account.Zts, - Version: fmt.Sprintf("SIA %s", version), - UseRegionalSTS: useRegionalSTS, - SanDnsWildcard: sanDnsWildcard, - SanDnsHostname: sanDnsHostname, - HostnameSuffix: hostnameSuffix, - Services: services, - Roles: roles, - TokenDir: tokenDir, - CertDir: certDir, - KeyDir: keyDir, - AthenzCACertFile: fmt.Sprintf("%s/ca.cert.pem", certDir), - GenerateRoleKey: generateRoleKey, - RotateKey: rotateKey, - BackupDir: backupDir, - SDSUdsPath: sdsUdsPath, - RefreshInterval: refreshInterval, - ZTSRegion: ztsRegion, - DropPrivileges: dropPrivileges, - AccessTokens: accessTokens, - Profile: profile, - ProfileRestrictTo: profileRestrictTo, - Threshold: account.Threshold, - SshThreshold: account.SshThreshold, - FileDirectUpdate: fileDirectUpdate, - SshHostKeyType: sshHostKeyType, - SshPrincipals: sshPrincipals, - AccessManagement: accessManagement, - FailCountForExit: failCountForExit, - RunAfterParts: util.ParseScriptArguments(runAfter), - RunAfterTokensParts: util.ParseScriptArguments(runAfterTokens), - SpiffeTrustDomain: spiffeTrustDomain, - OmitDomain: account.OmitDomain, - StoreTokenOption: storeTokenOption, - AddlSanDNSEntries: addlSanDNSEntries, - RunAfterFailExit: runAfterFailExit, + Name: account.Name, + User: account.User, + Group: account.Group, + Domain: account.Domain, + Account: account.Account, + Zts: account.Zts, + Version: fmt.Sprintf("SIA %s", version), + UseRegionalSTS: useRegionalSTS, + SanDnsWildcard: sanDnsWildcard, + SanDnsHostname: sanDnsHostname, + HostnameSuffix: hostnameSuffix, + Services: services, + Roles: roles, + TokenDir: tokenDir, + CertDir: certDir, + KeyDir: keyDir, + AthenzCACertFile: fmt.Sprintf("%s/ca.cert.pem", certDir), + GenerateRoleKey: generateRoleKey, + RotateKey: rotateKey, + BackupDir: backupDir, + SDSUdsPath: sdsUdsPath, + RefreshInterval: refreshInterval, + ZTSRegion: ztsRegion, + DropPrivileges: dropPrivileges, + AccessTokens: accessTokens, + Profile: profile, + ProfileRestrictTo: profileRestrictTo, + Threshold: account.Threshold, + SshThreshold: account.SshThreshold, + FileDirectUpdate: fileDirectUpdate, + SshHostKeyType: sshHostKeyType, + SshPrincipals: sshPrincipals, + AccessManagement: accessManagement, + FailCountForExit: failCountForExit, + RunAfterCertsOkParts: util.ParseScriptArguments(runAfterCerts), + RunAfterCertsErrParts: util.ParseScriptArguments(runAfterCertsErr), + RunAfterTokensOkParts: util.ParseScriptArguments(runAfterTokens), + RunAfterTokensErrParts: util.ParseScriptArguments(runAfterTokensErr), + SpiffeTrustDomain: spiffeTrustDomain, + OmitDomain: account.OmitDomain, + StoreTokenOption: storeTokenOption, + AddlSanDNSEntries: addlSanDNSEntries, + RunAfterFailExit: runAfterFailExit, }, nil } diff --git a/libs/go/sia/options/options_test.go b/libs/go/sia/options/options_test.go index de9e2a26c20..3f35d856f85 100644 --- a/libs/go/sia/options/options_test.go +++ b/libs/go/sia/options/options_test.go @@ -735,6 +735,10 @@ func TestInitEnvConfigAwsProvider(t *testing.T) { os.Setenv("ATHENZ_SIA_STORE_TOKEN_OPTION", "2") os.Setenv("ATHENZ_SIA_OMIT_DOMAIN", "true") os.Setenv("ATHENZ_SIA_SANDNS_X509_CNAMES", "svc1.athenz.io,svc2.athenz.io") + os.Setenv("ATHENZ_SIA_RUN_AFTER", "/run-after.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_CERTS_ERROR", "/run-after-error.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_TOKENS", "/run-after-tokens.sh") + os.Setenv("ATHENZ_SIA_RUN_AFTER_TOKENS_ERROR", "/run-after-tokens-error.sh") provider := MockAWSProvider{ Name: fmt.Sprintf("athenz.aws.us-west-2"), @@ -778,6 +782,10 @@ func TestInitEnvConfigAwsProvider(t *testing.T) { assert.Equal(t, 10, cfg.FailCountForExit) assert.Equal(t, 2, *cfg.StoreTokenOption) assert.True(t, cfgAccount.OmitDomain) + assert.Equal(t, "/run-after.sh", cfg.RunAfterCerts) + assert.Equal(t, "/run-after-error.sh", cfg.RunAfterCertsErr) + assert.Equal(t, "/run-after-tokens.sh", cfg.RunAfterTokens) + assert.Equal(t, "/run-after-tokens-error.sh", cfg.RunAfterTokensErr) os.Clearenv() } diff --git a/libs/go/sia/util/util.go b/libs/go/sia/util/util.go index 3f4e6d9e3c7..9dbc79fc088 100644 --- a/libs/go/sia/util/util.go +++ b/libs/go/sia/util/util.go @@ -1317,11 +1317,14 @@ func ParseScriptArguments(script string) []string { // ExecuteScript executes a script along with the provided // arguments while blocking the agent -func ExecuteScript(script []string, runAfterFailExit bool) error { +func ExecuteScript(script []string, addlDetail string, runAfterFailExit bool) error { // execute run after script (if provided) if len(script) == 0 { return nil } + if addlDetail != "" { + script = append(script, addlDetail) + } log.Printf("executing run after hook for: %v", script) err := exec.Command(script[0], script[1:]...).Run() if err != nil { @@ -1335,9 +1338,9 @@ func ExecuteScript(script []string, runAfterFailExit bool) error { // ExecuteScriptWithoutBlock executes a script along with the provided // arguments in a go subroutine without blocking the agent -func ExecuteScriptWithoutBlock(script []string, runAfterFailExit bool) { +func ExecuteScriptWithoutBlock(script []string, addlDetail string, runAfterFailExit bool) { go func() { - ExecuteScript(script, runAfterFailExit) + ExecuteScript(script, addlDetail, runAfterFailExit) }() } diff --git a/libs/go/sia/util/util_test.go b/libs/go/sia/util/util_test.go index 3c7202789d1..63c4264e639 100644 --- a/libs/go/sia/util/util_test.go +++ b/libs/go/sia/util/util_test.go @@ -1756,13 +1756,13 @@ func TestParseSiaCmd(test *testing.T) { func TestExecuteScript(test *testing.T) { // non-existent script - err := ExecuteScript([]string{"unknown-script"}, false) + err := ExecuteScript([]string{"unknown-script"}, "", false) assert.NotNil(test, err) // remove our test file if it exists os.Remove("/tmp/test-after-script") // valid script - err = ExecuteScript([]string{"data/test_after_script.sh"}, true) + err = ExecuteScript([]string{"data/test_after_script.sh"}, "", true) assert.Nil(test, err) // verify our test file was created _, err = os.Stat("/tmp/test-after-script") diff --git a/pom.xml b/pom.xml index 3c9682660f8..9b6e38425a8 100644 --- a/pom.xml +++ b/pom.xml @@ -178,6 +178,7 @@ provider/buildkite/sia-buildkite provider/gcp/sia-gce provider/gcp/sia-gke + provider/gcp/sia-run provider/github/sia-actions utils/zms-cli utils/athenz-conf diff --git a/provider/gcp/sia-run/pom.xml b/provider/gcp/sia-run/pom.xml index b311f1714f8..16cf8d46d21 100644 --- a/provider/gcp/sia-run/pom.xml +++ b/provider/gcp/sia-run/pom.xml @@ -19,7 +19,7 @@ com.yahoo.athenz athenz - 1.11.64-SNAPSHOT + 1.11.66-SNAPSHOT ../../../pom.xml