mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
When available, we provide an environment variable `CONSUL_TOKEN` to tasks, but this isn't the environment variable expected by the Consul CLI. Job specifications like deploying an API Gateway become noticeably nicer if we can instead provide the expected env var.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
// 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 = 0440
|
|
)
|
|
|
|
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()
|
|
}
|