mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
consul: include admin partition in JWT login requests (#22226)
When logging into a JWT auth method, we need to explicitly supply the Consul admin partition if the local Consul agent is in a partition. We can't derive this from agent configuration because the Consul agent's configuration is canonical, so instead we get the partition from the fingerprint (if available). This changeset updates the Consul client constructor so that we close over the partition from the fingerprint. Ref: https://hashicorp.atlassian.net/browse/NET-9451
This commit is contained in:
3
.changelog/22226.txt
Normal file
3
.changelog/22226.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
consul: Fixed a bug where Consul admin partition was not used to login via Consul JWT auth method
|
||||
```
|
||||
@@ -130,7 +130,7 @@ func (ar *allocRunner) initRunnerHooks(config *clientconfig.Config) error {
|
||||
allocdir: ar.allocDir,
|
||||
widmgr: ar.widmgr,
|
||||
consulConfigs: ar.clientConfig.GetConsulConfigs(hookLogger),
|
||||
consulClientConstructor: consul.NewConsulClient,
|
||||
consulClientConstructor: consul.NewConsulClientFactory(config.Node),
|
||||
hookResources: ar.hookResources,
|
||||
envBuilder: newEnvBuilder,
|
||||
logger: hookLogger,
|
||||
|
||||
@@ -23,7 +23,7 @@ type consulHook struct {
|
||||
allocdir allocdir.Interface
|
||||
widmgr widmgr.IdentityManager
|
||||
consulConfigs map[string]*structsc.ConsulConfig
|
||||
consulClientConstructor func(*structsc.ConsulConfig, log.Logger) (consul.Client, error)
|
||||
consulClientConstructor consul.ConsulClientFunc
|
||||
hookResources *cstructs.AllocHookResources
|
||||
envBuilder *taskenv.Builder
|
||||
|
||||
@@ -39,7 +39,7 @@ type consulHookConfig struct {
|
||||
consulConfigs map[string]*structsc.ConsulConfig
|
||||
// consulClientConstructor injects the function that will return a consul
|
||||
// client (eases testing)
|
||||
consulClientConstructor func(*structsc.ConsulConfig, log.Logger) (consul.Client, error)
|
||||
consulClientConstructor consul.ConsulClientFunc
|
||||
|
||||
// hookResources is used for storing and retrieving Consul tokens
|
||||
hookResources *cstructs.AllocHookResources
|
||||
|
||||
@@ -63,43 +63,56 @@ type consulClient struct {
|
||||
// client is the API client to interact with consul
|
||||
client *consulapi.Client
|
||||
|
||||
// partition is the Consul partition for the local agent
|
||||
partition string
|
||||
|
||||
// config is the configuration to connect to consul
|
||||
config *config.ConsulConfig
|
||||
|
||||
logger hclog.Logger
|
||||
}
|
||||
|
||||
// NewConsulClient creates a new Consul client
|
||||
func NewConsulClient(config *config.ConsulConfig, logger hclog.Logger) (Client, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("nil consul config")
|
||||
// ConsulClientFunc creates a new Consul client for the specific Consul config
|
||||
type ConsulClientFunc func(config *config.ConsulConfig, logger hclog.Logger) (Client, error)
|
||||
|
||||
// NewConsulClientFactory returns a ConsulClientFunc that closes over the
|
||||
// partition
|
||||
func NewConsulClientFactory(node *structs.Node) ConsulClientFunc {
|
||||
partition := node.Attributes["consul.partition"]
|
||||
|
||||
return func(config *config.ConsulConfig, logger hclog.Logger) (Client, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("nil consul config")
|
||||
}
|
||||
|
||||
logger = logger.Named("consul").With("name", config.Name)
|
||||
|
||||
c := &consulClient{
|
||||
config: config,
|
||||
logger: logger,
|
||||
partition: partition,
|
||||
}
|
||||
|
||||
// Get the Consul API configuration
|
||||
apiConf, err := config.ApiConfig()
|
||||
if err != nil {
|
||||
logger.Error("error creating default Consul API config", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the API client
|
||||
client, err := consulapi.NewClient(apiConf)
|
||||
if err != nil {
|
||||
logger.Error("error creating Consul client", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
useragent.SetHeaders(client)
|
||||
c.client = client
|
||||
|
||||
return c, nil
|
||||
|
||||
}
|
||||
|
||||
logger = logger.Named("consul").With("name", config.Name)
|
||||
|
||||
c := &consulClient{
|
||||
config: config,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
// Get the Consul API configuration
|
||||
apiConf, err := config.ApiConfig()
|
||||
if err != nil {
|
||||
logger.Error("error creating default Consul API config", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the API client
|
||||
client, err := consulapi.NewClient(apiConf)
|
||||
if err != nil {
|
||||
logger.Error("error creating Consul client", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
useragent.SetHeaders(client)
|
||||
c.client = client
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// DeriveTokenWithJWT takes a JWT from request and returns a consul token.
|
||||
@@ -108,7 +121,10 @@ func (c *consulClient) DeriveTokenWithJWT(req JWTLoginRequest) (*consulapi.ACLTo
|
||||
AuthMethod: req.AuthMethodName,
|
||||
BearerToken: req.JWT,
|
||||
Meta: req.Meta,
|
||||
}, nil)
|
||||
}, &consulapi.WriteOptions{
|
||||
Partition: c.partition,
|
||||
})
|
||||
|
||||
return t, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user