2022-02-09 10:15:00 +00:00
package steward
2022-02-09 13:59:40 +00:00
2022-04-05 08:35:59 +00:00
import (
2022-04-07 12:18:28 +00:00
"bytes"
2022-04-05 08:35:59 +00:00
"fmt"
"log"
"os"
"path/filepath"
"sync"
bolt "go.etcd.io/bbolt"
)
2022-04-04 08:29:14 +00:00
2022-04-20 04:26:01 +00:00
// centralAuth holds the logic related to handling public keys and auth maps.
2022-02-09 13:59:40 +00:00
type centralAuth struct {
2022-04-07 12:18:28 +00:00
// schema map[Node]map[argsString]signatureBase32
2022-05-11 07:55:27 +00:00
authorization * authorization
2022-05-12 07:25:10 +00:00
pki * pki
2022-05-11 07:55:27 +00:00
}
// newCentralAuth will return a new and prepared *centralAuth
func newCentralAuth ( configuration * Configuration , errorKernel * errorKernel ) * centralAuth {
c := centralAuth {
authorization : newAuthorization ( ) ,
2022-05-12 07:25:10 +00:00
pki : newPKI ( configuration , errorKernel ) ,
2022-05-11 07:55:27 +00:00
}
return & c
}
2022-05-12 07:25:10 +00:00
type pki struct {
nodeKeysAndHash * nodeKeysAndHash
2022-04-20 16:33:52 +00:00
nodeNotAckedPublicKeys * nodeNotAckedPublicKeys
configuration * Configuration
db * bolt . DB
bucketNamePublicKeys string
errorKernel * errorKernel
2022-04-05 08:35:59 +00:00
}
2022-05-11 07:55:27 +00:00
// newKeys will return a prepared *keys with input values set.
2022-05-12 07:25:10 +00:00
func newPKI ( configuration * Configuration , errorKernel * errorKernel ) * pki {
p := pki {
2022-04-07 12:18:28 +00:00
// schema: make(map[Node]map[argsString]signatureBase32),
2022-05-12 07:25:10 +00:00
nodeKeysAndHash : newNodeKeysAndHash ( configuration ) ,
2022-04-20 16:33:52 +00:00
nodeNotAckedPublicKeys : newNodeNotAckedPublicKeys ( configuration ) ,
configuration : configuration ,
bucketNamePublicKeys : "publicKeys" ,
errorKernel : errorKernel ,
2022-04-05 08:35:59 +00: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 )
}
2022-05-12 07:25:10 +00:00
p . db = db
2022-04-05 08:35:59 +00:00
2022-04-05 10:02:45 +00:00
// Get public keys from db storage.
2022-05-12 07:25:10 +00:00
keys , err := p . dbDumpPublicKey ( )
2022-04-05 08:35:59 +00:00
if err != nil {
2022-04-05 10:02:45 +00:00
log . Printf ( "debug: dbPublicKeyDump failed, probably empty db: %v\n" , err )
2022-04-05 08:35:59 +00:00
}
2022-04-05 10:02:45 +00:00
// Only assign from storage to in memory map if the storage contained any values.
if keys != nil {
2022-05-12 07:25:10 +00:00
p . nodeKeysAndHash . KeyMap = keys
2022-04-05 10:02:45 +00:00
for k , v := range keys {
log . Printf ( "info: public keys db contains: %v, %v\n" , k , [ ] byte ( v ) )
}
}
2022-04-05 08:35:59 +00:00
2022-05-12 07:25:10 +00:00
return & p
2022-02-09 13:59:40 +00:00
}
2022-04-05 08:35:59 +00:00
// addPublicKey to the db if the node do not exist, or if it is a new value.
2022-05-12 07:25:10 +00:00
func ( p * pki ) addPublicKey ( proc process , msg Message ) {
2022-04-05 08:35:59 +00:00
2022-04-20 06:41:57 +00: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 08:35:59 +00:00
// Check if a key for the current node already exists in the map.
2022-05-12 07:25:10 +00:00
p . nodeKeysAndHash . mu . Lock ( )
existingKey , ok := p . nodeKeysAndHash . KeyMap [ msg . FromNode ]
p . nodeKeysAndHash . mu . Unlock ( )
2022-04-05 08:35:59 +00:00
2022-04-07 12:18:28 +00:00
if ok && bytes . Equal ( existingKey , msg . Data ) {
2022-04-20 16:33:52 +00:00
fmt . Printf ( " * \nkey value for REGISTERED node %v is the same, doing nothing\n\n" , msg . FromNode )
2022-04-05 08:35:59 +00:00
return
}
2022-05-12 07:25:10 +00:00
p . nodeNotAckedPublicKeys . mu . Lock ( )
existingNotAckedKey , ok := p . nodeNotAckedPublicKeys . KeyMap [ msg . FromNode ]
2022-04-20 16:33:52 +00:00
// 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 )
2022-05-12 07:25:10 +00:00
p . nodeNotAckedPublicKeys . mu . Unlock ( )
2022-04-20 16:33:52 +00:00
return
2022-04-05 08:35:59 +00:00
}
2022-05-12 07:25:10 +00:00
p . nodeNotAckedPublicKeys . KeyMap [ msg . FromNode ] = msg . Data
p . nodeNotAckedPublicKeys . mu . Unlock ( )
2022-04-20 16:33:52 +00:00
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 )
2022-05-12 07:25:10 +00:00
p . errorKernel . infoSend ( proc , msg , er )
2022-04-05 08:35:59 +00:00
}
2022-05-06 05:47:12 +00: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 08:35:59 +00:00
//dbUpdatePublicKey will update the public key for a node in the db.
2022-05-12 07:25:10 +00:00
func ( p * pki ) dbUpdatePublicKey ( node string , value [ ] byte ) error {
err := p . db . Update ( func ( tx * bolt . Tx ) error {
2022-04-05 08:35:59 +00:00
//Create a bucket
2022-05-12 07:25:10 +00:00
bu , err := tx . CreateBucketIfNotExists ( [ ] byte ( p . bucketNamePublicKeys ) )
2022-04-05 08:35:59 +00: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 05:47:12 +00: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 08:35:59 +00:00
// dumpBucket will dump out all they keys and values in the
// specified bucket, and return a sorted []samDBValue
2022-05-12 07:25:10 +00:00
func ( p * pki ) dbDumpPublicKey ( ) ( map [ Node ] [ ] byte , error ) {
2022-04-07 12:18:28 +00:00
m := make ( map [ Node ] [ ] byte )
2022-04-05 08:35:59 +00:00
2022-05-12 07:25:10 +00:00
err := p . db . View ( func ( tx * bolt . Tx ) error {
bu := tx . Bucket ( [ ] byte ( p . bucketNamePublicKeys ) )
2022-04-05 08:35:59 +00: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 12:18:28 +00:00
m [ Node ( k ) ] = v
2022-04-05 08:35:59 +00:00
return nil
} )
return nil
} )
if err != nil {
return nil , err
2022-02-09 13:59:40 +00:00
}
2022-04-05 08:35:59 +00:00
return m , nil
2022-02-09 13:59:40 +00:00
}
2022-04-04 08:29:14 +00:00
2022-05-12 07:25:10 +00:00
// nodeKeysAndHash holds all the gathered public keys of nodes in the system.
2022-04-05 08:35:59 +00:00
// The keys will be written to a k/v store for persistence.
2022-05-12 07:25:10 +00:00
type nodeKeysAndHash struct {
2022-04-09 04:46:47 +00:00
mu sync . RWMutex
2022-04-07 12:18:28 +00:00
KeyMap map [ Node ] [ ] byte
2022-05-12 04:22:11 +00:00
// TODO TOMOROW: implement sorting of KeyMap,
// Hash it and store the result into hash,
// marshal and send the whole nodePublicKeys to the end node.
// We should update the hash when a node is added with the allow key method.
Hash [ 32 ] byte
2022-04-04 08:29:14 +00:00
}
2022-05-12 07:25:10 +00:00
// newNnodeKeysAndHash will return a prepared type of nodeKeysAndHash.
func newNodeKeysAndHash ( configuration * Configuration ) * nodeKeysAndHash {
n := nodeKeysAndHash {
2022-04-07 12:18:28 +00:00
KeyMap : make ( map [ Node ] [ ] byte ) ,
2022-04-04 08:29:14 +00:00
}
return & n
}
2022-04-20 16:33:52 +00: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
}