oss: do a proper check-and-set on the CA roots/config fsm operation

This commit is contained in:
Kyle Havlovitz 2018-11-06 22:46:06 -08:00
parent 003dacb340
commit 70accbb2e0
3 changed files with 32 additions and 5 deletions

View file

@ -78,10 +78,12 @@ func (s *ConnectCA) ConfigurationSet(
// Exit early if it's a no-op change
state := s.srv.fsm.State()
_, config, err := state.CAConfig()
confIdx, config, err := state.CAConfig()
if err != nil {
return err
}
// Don't allow users to change the ClusterID.
args.Config.ClusterID = config.ClusterID
if args.Config.Provider == config.Provider && reflect.DeepEqual(args.Config.Config, config.Config) {
return nil
@ -195,6 +197,7 @@ func (s *ConnectCA) ConfigurationSet(
args.Op = structs.CAOpSetRootsAndConfig
args.Index = idx
args.Config.ModifyIndex = confIdx
args.Roots = newRoots
resp, err := s.srv.raftApply(structs.ConnectCARequestType, args)
if err != nil {
@ -203,6 +206,9 @@ func (s *ConnectCA) ConfigurationSet(
if respErr, ok := resp.(error); ok {
return respErr
}
if respOk, ok := resp.(bool); ok && !respOk {
return fmt.Errorf("could not atomically update roots and config")
}
// If the config has been committed, update the local provider instance
// and call teardown on the old provider
@ -375,6 +381,20 @@ func (s *ConnectCA) Sign(
pem = strings.TrimSpace(pem) + "\n" + p
}
// Append our local CA's intermediate if there is one.
inter, err := provider.ActiveIntermediate()
if err != nil {
return err
}
root, err := provider.ActiveRoot()
if err != nil {
return err
}
if inter != root {
pem = strings.TrimSpace(pem) + "\n" + inter
}
// TODO(banks): when we implement IssuedCerts table we can use the insert to
// that as the raft index to return in response. Right now we can rely on only
// the built-in provider being supported and the implementation detail that we

View file

@ -339,11 +339,14 @@ func (c *FSM) applyConnectCAOperation(buf []byte, index uint64) interface{} {
if err != nil {
return err
}
if err := c.state.CASetConfig(index+1, req.Config); err != nil {
return err
if !act {
return act
}
act, err = c.state.CACheckAndSetConfig(index+1, req.Config.ModifyIndex, req.Config)
if err != nil {
return err
}
return act
default:
c.logger.Printf("[WARN] consul.fsm: Invalid CA operation '%s'", req.Op)

View file

@ -172,7 +172,11 @@ func (s *Store) caSetConfigTxn(idx uint64, tx *memdb.Txn, config *structs.CAConf
if prev != nil {
existing := prev.(*structs.CAConfiguration)
config.CreateIndex = existing.CreateIndex
config.ClusterID = existing.ClusterID
// Allow the ClusterID to change if it's provided by an internal operation, such
// as a primary datacenter being switched to secondary mode.
if config.ClusterID == "" {
config.ClusterID = existing.ClusterID
}
} else {
config.CreateIndex = idx
}