mirror of https://github.com/status-im/consul.git
Create HCP management token in HCP manager (#19830)
* Create HCP management token in HCP manager * Change InitializeManagementToken to ManagementTokenUpserter * Implement and use management token upsert function * Fix race condition in test * Add idea for improvement as comment * Return early in upsertManagementToken if token exists
This commit is contained in:
parent
98c9702ba3
commit
37a5fddffa
|
@ -586,6 +586,55 @@ func (s *Server) initializeManagementToken(name, secretID string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) upsertManagementToken(name, secretID string) error {
|
||||||
|
state := s.fsm.State()
|
||||||
|
if _, err := uuid.ParseUUID(secretID); err != nil {
|
||||||
|
s.logger.Warn("Configuring a non-UUID management token is deprecated")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, token, err := state.ACLTokenGetBySecret(nil, secretID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get %s: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if token != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor, err := lib.GenerateUUID(s.checkTokenUUID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate the accessor ID for %s: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken := structs.ACLToken{
|
||||||
|
AccessorID: accessor,
|
||||||
|
SecretID: secretID,
|
||||||
|
Description: name,
|
||||||
|
Policies: []structs.ACLTokenPolicyLink{
|
||||||
|
{
|
||||||
|
ID: structs.ACLPolicyGlobalManagementID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
Local: false,
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken.SetHash(true)
|
||||||
|
|
||||||
|
req := structs.ACLTokenBatchSetRequest{
|
||||||
|
Tokens: structs.ACLTokens{&newToken},
|
||||||
|
CAS: false,
|
||||||
|
}
|
||||||
|
if _, err := s.raftApply(structs.ACLTokenSetRequestType, &req); err != nil {
|
||||||
|
return fmt.Errorf("failed to create %s: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Created ACL token", "description", name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) insertAnonymousToken() error {
|
func (s *Server) insertAnonymousToken() error {
|
||||||
state := s.fsm.State()
|
state := s.fsm.State()
|
||||||
_, token, err := state.ACLTokenGetBySecret(nil, anonymousToken, nil)
|
_, token, err := state.ACLTokenGetBySecret(nil, anonymousToken, nil)
|
||||||
|
|
|
@ -588,6 +588,15 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
|
||||||
Logger: logger.Named("hcp_manager"),
|
Logger: logger.Named("hcp_manager"),
|
||||||
SCADAProvider: flat.HCP.Provider,
|
SCADAProvider: flat.HCP.Provider,
|
||||||
TelemetryProvider: flat.HCP.TelemetryProvider,
|
TelemetryProvider: flat.HCP.TelemetryProvider,
|
||||||
|
ManagementTokenUpserterFn: func(name, secretId string) error {
|
||||||
|
if s.IsLeader() {
|
||||||
|
// Idea for improvement: Upsert a token with a well-known accessorId here instead
|
||||||
|
// of a randomly generated one. This would prevent any possible insertion collision between
|
||||||
|
// this and the insertion that happens during the ACL initialization process (initializeACLs function)
|
||||||
|
return s.upsertManagementToken(name, secretId)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
var recorder *middleware.RequestRecorder
|
var recorder *middleware.RequestRecorder
|
||||||
|
|
|
@ -26,9 +26,12 @@ type ManagerConfig struct {
|
||||||
SCADAProvider scada.Provider
|
SCADAProvider scada.Provider
|
||||||
TelemetryProvider *hcpProviderImpl
|
TelemetryProvider *hcpProviderImpl
|
||||||
|
|
||||||
StatusFn StatusCallback
|
StatusFn StatusCallback
|
||||||
MinInterval time.Duration
|
// Idempotent function to upsert the HCP management token. This will be called periodically in
|
||||||
MaxInterval time.Duration
|
// the manager's main loop.
|
||||||
|
ManagementTokenUpserterFn ManagementTokenUpserter
|
||||||
|
MinInterval time.Duration
|
||||||
|
MaxInterval time.Duration
|
||||||
|
|
||||||
Logger hclog.Logger
|
Logger hclog.Logger
|
||||||
}
|
}
|
||||||
|
@ -54,6 +57,7 @@ func (cfg *ManagerConfig) nextHeartbeat() time.Duration {
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusCallback func(context.Context) (hcpclient.ServerStatus, error)
|
type StatusCallback func(context.Context) (hcpclient.ServerStatus, error)
|
||||||
|
type ManagementTokenUpserter func(name, secretId string) error
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
logger hclog.Logger
|
logger hclog.Logger
|
||||||
|
@ -111,6 +115,14 @@ func (m *Manager) Run(ctx context.Context) error {
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
for {
|
for {
|
||||||
|
// Check for configured management token from HCP and upsert it if found
|
||||||
|
if hcpManagement := m.cfg.CloudConfig.ManagementToken; len(hcpManagement) > 0 {
|
||||||
|
upsertTokenErr := m.cfg.ManagementTokenUpserterFn("HCP Management Token", hcpManagement)
|
||||||
|
if upsertTokenErr != nil {
|
||||||
|
m.logger.Error("failed to upsert HCP management token", "err", upsertTokenErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m.cfgMu.RLock()
|
m.cfgMu.RLock()
|
||||||
cfg := m.cfg
|
cfg := m.cfg
|
||||||
m.cfgMu.RUnlock()
|
m.cfgMu.RUnlock()
|
||||||
|
|
|
@ -22,12 +22,18 @@ func TestManager_Run(t *testing.T) {
|
||||||
statusF := func(ctx context.Context) (hcpclient.ServerStatus, error) {
|
statusF := func(ctx context.Context) (hcpclient.ServerStatus, error) {
|
||||||
return hcpclient.ServerStatus{ID: t.Name()}, nil
|
return hcpclient.ServerStatus{ID: t.Name()}, nil
|
||||||
}
|
}
|
||||||
|
upsertManagementTokenCalled := make(chan struct{}, 1)
|
||||||
|
upsertManagementTokenF := func(name, secretID string) error {
|
||||||
|
upsertManagementTokenCalled <- struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
updateCh := make(chan struct{}, 1)
|
updateCh := make(chan struct{}, 1)
|
||||||
client.EXPECT().PushServerStatus(mock.Anything, &hcpclient.ServerStatus{ID: t.Name()}).Return(nil).Once()
|
client.EXPECT().PushServerStatus(mock.Anything, &hcpclient.ServerStatus{ID: t.Name()}).Return(nil).Once()
|
||||||
|
|
||||||
cloudCfg := config.CloudConfig{
|
cloudCfg := config.CloudConfig{
|
||||||
ResourceID: "organization/85702e73-8a3d-47dc-291c-379b783c5804/project/8c0547c0-10e8-1ea2-dffe-384bee8da634/hashicorp.consul.global-network-manager.cluster/test",
|
ResourceID: "organization/85702e73-8a3d-47dc-291c-379b783c5804/project/8c0547c0-10e8-1ea2-dffe-384bee8da634/hashicorp.consul.global-network-manager.cluster/test",
|
||||||
NodeID: "node-1",
|
NodeID: "node-1",
|
||||||
|
ManagementToken: "fake-token",
|
||||||
}
|
}
|
||||||
scadaM := scada.NewMockProvider(t)
|
scadaM := scada.NewMockProvider(t)
|
||||||
scadaM.EXPECT().UpdateHCPConfig(cloudCfg).Return(nil)
|
scadaM.EXPECT().UpdateHCPConfig(cloudCfg).Return(nil)
|
||||||
|
@ -52,12 +58,13 @@ func TestManager_Run(t *testing.T) {
|
||||||
mockTelemetryCfg, nil).Maybe()
|
mockTelemetryCfg, nil).Maybe()
|
||||||
|
|
||||||
mgr := NewManager(ManagerConfig{
|
mgr := NewManager(ManagerConfig{
|
||||||
Client: client,
|
Client: client,
|
||||||
Logger: hclog.New(&hclog.LoggerOptions{Output: io.Discard}),
|
Logger: hclog.New(&hclog.LoggerOptions{Output: io.Discard}),
|
||||||
StatusFn: statusF,
|
StatusFn: statusF,
|
||||||
CloudConfig: cloudCfg,
|
ManagementTokenUpserterFn: upsertManagementTokenF,
|
||||||
SCADAProvider: scadaM,
|
CloudConfig: cloudCfg,
|
||||||
TelemetryProvider: telemetryProvider,
|
SCADAProvider: scadaM,
|
||||||
|
TelemetryProvider: telemetryProvider,
|
||||||
})
|
})
|
||||||
mgr.testUpdateSent = updateCh
|
mgr.testUpdateSent = updateCh
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
@ -76,6 +83,7 @@ func TestManager_Run(t *testing.T) {
|
||||||
require.Equal(t, client, telemetryProvider.hcpClient)
|
require.Equal(t, client, telemetryProvider.hcpClient)
|
||||||
require.NotNil(t, telemetryProvider.GetHeader())
|
require.NotNil(t, telemetryProvider.GetHeader())
|
||||||
require.NotNil(t, telemetryProvider.GetHTTPClient())
|
require.NotNil(t, telemetryProvider.GetHTTPClient())
|
||||||
|
require.NotEmpty(t, upsertManagementTokenCalled, "upsert management token function not called")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManager_SendUpdate(t *testing.T) {
|
func TestManager_SendUpdate(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue