// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package taskrunner import ( "context" "fmt" "os" "path/filepath" "slices" "strings" log "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-multierror" "github.com/hashicorp/nomad/client/allocrunner/interfaces" cstructs "github.com/hashicorp/nomad/client/structs" "github.com/hashicorp/nomad/nomad/structs" ) const ( // consulTokenFilename is the name of the file holding the Consul SI token // inside the task's secret directory. consulTokenFilename = "consul_token" // consulTokenFilePerms is the level of file permissions granted on the file in // the secrets directory for the task consulTokenFilePerms = 0640 ) type consulHook struct { task *structs.Task tokenDir string hookResources *cstructs.AllocHookResources logger log.Logger } func newConsulHook(logger log.Logger, tr *TaskRunner) *consulHook { h := &consulHook{ task: tr.Task(), tokenDir: tr.taskDir.SecretsDir, hookResources: tr.allocHookResources, } h.logger = logger.Named(h.Name()) return h } func (*consulHook) Name() string { return "consul_task" } func (h *consulHook) Prestart(ctx context.Context, req *interfaces.TaskPrestartRequest, resp *interfaces.TaskPrestartResponse) error { mErr := multierror.Error{} tokens := h.hookResources.GetConsulTokens() // Write tokens to tasks' secret dirs for _, t := range tokens { for tokenName, token := range t { s := strings.SplitN(tokenName, "/", 2) if len(s) < 2 { continue } identity := s[0] taskName := s[1] // do not write tokens that do not belong to any of this task's // identities if taskName != h.task.Name || !slices.ContainsFunc( h.task.Identities, func(id *structs.WorkloadIdentity) bool { return id.Name == identity }) && identity != h.task.Identity.Name { continue } tokenPath := filepath.Join(h.tokenDir, consulTokenFilename) if err := os.WriteFile(tokenPath, []byte(token.SecretID), consulTokenFilePerms); err != nil { mErr.Errors = append(mErr.Errors, fmt.Errorf("failed to write Consul SI token: %w", err)) } env := map[string]string{ "CONSUL_TOKEN": token.SecretID, "CONSUL_HTTP_TOKEN": token.SecretID, } resp.Env = env } } return mErr.ErrorOrNil() }