2022-02-09 11:15:00 +01:00
package steward
2022-02-09 14:59:40 +01:00
2022-04-05 10:35:59 +02:00
import (
2022-04-07 14:18:28 +02:00
"bytes"
2022-04-05 10:35:59 +02:00
"fmt"
"log"
"os"
"path/filepath"
"sync"
bolt "go.etcd.io/bbolt"
)
2022-04-04 10:29:14 +02:00
2022-04-20 06:26:01 +02:00
// centralAuth holds the logic related to handling public keys and auth maps.
2022-02-09 14:59:40 +01:00
type centralAuth struct {
2022-04-07 14:18:28 +02:00
// schema map[Node]map[argsString]signatureBase32
2022-04-20 18:33:52 +02:00
nodePublicKeys * nodePublicKeys
nodeNotAckedPublicKeys * nodeNotAckedPublicKeys
configuration * Configuration
db * bolt . DB
bucketNamePublicKeys string
errorKernel * errorKernel
2022-04-05 10:35:59 +02:00
}
2022-04-20 06:26:01 +02:00
// newCentralAuth will return a prepared *centralAuth with input values set.
2022-04-05 10:35:59 +02:00
func newCentralAuth ( configuration * Configuration , errorKernel * errorKernel ) * centralAuth {
c := centralAuth {
2022-04-07 14:18:28 +02:00
// schema: make(map[Node]map[argsString]signatureBase32),
2022-04-20 18:33:52 +02:00
nodePublicKeys : newNodePublicKeys ( configuration ) ,
nodeNotAckedPublicKeys : newNodeNotAckedPublicKeys ( configuration ) ,
configuration : configuration ,
bucketNamePublicKeys : "publicKeys" ,
errorKernel : errorKernel ,
2022-04-05 10:35:59 +02:00
}
databaseFilepath := filepath . Join ( configuration . DatabaseFolder , "auth.db" )
// Open the database file for persistent storage of public keys.
db , err := bolt . Open ( databaseFilepath , 0600 , nil )
if err != nil {
log . Printf ( "error: failed to open db: %v\n" , err )
os . Exit ( 1 )
}
c . db = db
2022-04-05 12:02:45 +02:00
// Get public keys from db storage.
2022-04-05 10:35:59 +02:00
keys , err := c . dbDumpPublicKey ( )
if err != nil {
2022-04-05 12:02:45 +02:00
log . Printf ( "debug: dbPublicKeyDump failed, probably empty db: %v\n" , err )
2022-04-05 10:35:59 +02:00
}
2022-04-05 12:02:45 +02:00
// Only assign from storage to in memory map if the storage contained any values.
if keys != nil {
2022-04-07 09:34:06 +02:00
c . nodePublicKeys . KeyMap = keys
2022-04-05 12:02:45 +02:00
for k , v := range keys {
log . Printf ( "info: public keys db contains: %v, %v\n" , k , [ ] byte ( v ) )
}
}
2022-04-05 10:35:59 +02:00
return & c
2022-02-09 14:59:40 +01:00
}
2022-04-05 10:35:59 +02:00
// addPublicKey to the db if the node do not exist, or if it is a new value.
func ( c * centralAuth ) addPublicKey ( proc process , msg Message ) {
2022-04-20 08:41:57 +02:00
// TODO: When receiviving a new or different keys for a node we should
// have a service with it's own storage for these keys, and an operator
// should have to acknowledge the new keys.
// For this we need:
// - A service that keeps the state of all the new keys detected in the
// bytes.equal check below.
// - A Log message should be thrown so we know that there is a new key.
// - A Request method that can be used by operator to acknowledge a new
// key for a host.
2022-04-05 10:35:59 +02:00
// Check if a key for the current node already exists in the map.
2022-04-20 18:33:52 +02:00
c . nodePublicKeys . mu . Lock ( )
2022-04-07 09:34:06 +02:00
existingKey , ok := c . nodePublicKeys . KeyMap [ msg . FromNode ]
2022-04-20 18:33:52 +02:00
c . nodePublicKeys . mu . Unlock ( )
2022-04-05 10:35:59 +02:00
2022-04-07 14:18:28 +02:00
if ok && bytes . Equal ( existingKey , msg . Data ) {
2022-04-20 18:33:52 +02:00
fmt . Printf ( " * \nkey value for REGISTERED node %v is the same, doing nothing\n\n" , msg . FromNode )
2022-04-05 10:35:59 +02:00
return
}
2022-04-20 18:33:52 +02:00
c . nodeNotAckedPublicKeys . mu . Lock ( )
existingNotAckedKey , ok := c . nodeNotAckedPublicKeys . KeyMap [ msg . FromNode ]
// We only want to send one notification to the error kernel about new key detection,
// so we check if the values are the same as the one we already got before we continue
// with registering and logging for the the new key.
if ok && bytes . Equal ( existingNotAckedKey , msg . Data ) {
fmt . Printf ( " * \nkey value for NOT-REGISTERED node %v is the same, doing nothing\n\n" , msg . FromNode )
c . nodeNotAckedPublicKeys . mu . Unlock ( )
return
2022-04-05 10:35:59 +02:00
}
2022-04-20 18:33:52 +02:00
c . nodeNotAckedPublicKeys . KeyMap [ msg . FromNode ] = msg . Data
c . nodeNotAckedPublicKeys . mu . Unlock ( )
er := fmt . Errorf ( "info: detected new public key for node: %v. This key will need to be authorized by operator to be allowed into the system" , msg . FromNode )
fmt . Printf ( " * %v\n" , er )
c . errorKernel . infoSend ( proc , msg , er )
// TODO: The below commented code should put used within the REQ handler instead to
// store the real keys into the allowed public keys map.
// Here we should only add new keys to the NotAcked map.
// // New key
// c.nodePublicKeys.KeyMap[msg.FromNode] = msg.Data
// c.nodePublicKeys.mu.Unlock()
//
// // Add key to persistent storage.
// c.dbUpdatePublicKey(string(msg.FromNode), msg.Data)
//
// if ok {
// er := fmt.Errorf("info: updated with new public key for node: %v", msg.FromNode)
// fmt.Printf(" * %v\n", er)
// c.errorKernel.infoSend(proc, msg, er)
// }
// if !ok {
// er := fmt.Errorf("info: added public key for new node: %v", msg.FromNode)
// fmt.Printf(" * %v\n", er)
// c.errorKernel.infoSend(proc, msg, er)
// }
2022-04-05 10:35:59 +02:00
//c.dbDump(c.bucketPublicKeys)
}
2022-05-06 07:47:12 +02:00
// // dbGetPublicKey will look up and return a specific value if it exists for a key in a bucket in a DB.
// func (c *centralAuth) dbGetPublicKey(node string) ([]byte, error) {
// var value []byte
// // View is a help function to get values out of the database.
// err := c.db.View(func(tx *bolt.Tx) error {
// //Open a bucket to get key's and values from.
// bu := tx.Bucket([]byte(c.bucketNamePublicKeys))
// if bu == nil {
// log.Printf("info: no db bucket exist: %v\n", c.bucketNamePublicKeys)
// return nil
// }
//
// v := bu.Get([]byte(node))
// if len(v) == 0 {
// log.Printf("info: view: key not found\n")
// return nil
// }
//
// value = v
//
// return nil
// })
//
// return value, err
// }
2022-04-05 10:35:59 +02:00
//dbUpdatePublicKey will update the public key for a node in the db.
func ( c * centralAuth ) dbUpdatePublicKey ( node string , value [ ] byte ) error {
err := c . db . Update ( func ( tx * bolt . Tx ) error {
//Create a bucket
2022-04-07 14:18:28 +02:00
bu , err := tx . CreateBucketIfNotExists ( [ ] byte ( c . bucketNamePublicKeys ) )
2022-04-05 10:35:59 +02:00
if err != nil {
return fmt . Errorf ( "error: CreateBuckerIfNotExists failed: %v" , err )
}
//Put a value into the bucket.
if err := bu . Put ( [ ] byte ( node ) , [ ] byte ( value ) ) ; err != nil {
return err
}
//If all was ok, we should return a nil for a commit to happen. Any error
// returned will do a rollback.
return nil
} )
return err
}
2022-05-06 07:47:12 +02:00
// // deleteKeyFromBucket will delete the specified key from the specified
// // bucket if it exists.
// func (c *centralAuth) dbDeletePublicKey(key string) error {
// err := c.db.Update(func(tx *bolt.Tx) error {
// bu := tx.Bucket([]byte(c.bucketNamePublicKeys))
//
// err := bu.Delete([]byte(key))
// if err != nil {
// log.Printf("error: delete key in bucket %v failed: %v\n", c.bucketNamePublicKeys, err)
// }
//
// return nil
// })
//
// return err
// }
2022-04-05 10:35:59 +02:00
// dumpBucket will dump out all they keys and values in the
// specified bucket, and return a sorted []samDBValue
2022-04-07 14:18:28 +02:00
func ( c * centralAuth ) dbDumpPublicKey ( ) ( map [ Node ] [ ] byte , error ) {
m := make ( map [ Node ] [ ] byte )
2022-04-05 10:35:59 +02:00
err := c . db . View ( func ( tx * bolt . Tx ) error {
2022-04-07 14:18:28 +02:00
bu := tx . Bucket ( [ ] byte ( c . bucketNamePublicKeys ) )
2022-04-05 10:35:59 +02:00
if bu == nil {
return fmt . Errorf ( "error: dumpBucket: tx.bucket returned nil" )
}
// For each element found in the DB, print it.
bu . ForEach ( func ( k , v [ ] byte ) error {
2022-04-07 14:18:28 +02:00
m [ Node ( k ) ] = v
2022-04-05 10:35:59 +02:00
return nil
} )
return nil
} )
if err != nil {
return nil , err
2022-02-09 14:59:40 +01:00
}
2022-04-05 10:35:59 +02:00
return m , nil
2022-02-09 14:59:40 +01:00
}
2022-04-04 10:29:14 +02:00
2022-04-05 10:35:59 +02:00
// nodePublicKeys holds all the gathered public keys of nodes in the system.
// The keys will be written to a k/v store for persistence.
2022-04-04 10:29:14 +02:00
type nodePublicKeys struct {
2022-04-09 06:46:47 +02:00
mu sync . RWMutex
2022-04-07 14:18:28 +02:00
KeyMap map [ Node ] [ ] byte
2022-04-04 10:29:14 +02:00
}
2022-04-05 10:35:59 +02:00
// newNodePublicKeys will return a prepared type of nodePublicKeys.
func newNodePublicKeys ( configuration * Configuration ) * nodePublicKeys {
2022-04-04 10:29:14 +02:00
n := nodePublicKeys {
2022-04-07 14:18:28 +02:00
KeyMap : make ( map [ Node ] [ ] byte ) ,
2022-04-04 10:29:14 +02:00
}
return & n
}
2022-04-20 18:33:52 +02:00
// --- HERE
// nodeNotAckedPublicKeys holds all the gathered but not acknowledged public
// keys of nodes in the system.
type nodeNotAckedPublicKeys struct {
mu sync . RWMutex
KeyMap map [ Node ] [ ] byte
}
// newNodeNotAckedPublicKeys will return a prepared type of nodePublicKeys.
func newNodeNotAckedPublicKeys ( configuration * Configuration ) * nodeNotAckedPublicKeys {
n := nodeNotAckedPublicKeys {
KeyMap : make ( map [ Node ] [ ] byte ) ,
}
return & n
}