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-05-16 05:15:38 +00:00
// acl and authorization level related data and methods.
2022-05-11 07:55:27 +00:00
authorization * authorization
2022-05-16 05:15:38 +00:00
// public key distribution related data and methods.
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-16 05:15:38 +00:00
// nodesAcked is the structure that holds all the keys that we have
// acknowledged, and that are allowed to be distributed within the
// system. It also contains a hash of all those keys.
type nodesAcked struct {
mu sync . Mutex
keysAndHash * keysAndHash
}
// newNodesAcked will return a prepared *nodesAcked structure.
func newNodesAcked ( ) * nodesAcked {
n := nodesAcked {
keysAndHash : newKeysAndHash ( ) ,
}
return & n
}
// pki holds the data and method relevant to key handling and distribution.
2022-05-12 07:25:10 +00:00
type pki struct {
2022-05-16 05:15:38 +00:00
nodesAcked * nodesAcked
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-16 05:15:38 +00:00
nodesAcked : newNodesAcked ( ) ,
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-16 05:15:38 +00:00
p . nodesAcked . keysAndHash . Keys = 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-16 05:15:38 +00:00
// Get the current hash from db if one exists.
hash , err := p . dbViewHash ( )
if err != nil {
log . Printf ( "debug: dbViewHash failed: %v\n" , err )
}
if hash != nil {
var h [ 32 ] byte
copy ( h [ : ] , hash )
p . nodesAcked . keysAndHash . Hash = h
}
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-16 05:15:38 +00:00
p . nodesAcked . mu . Lock ( )
existingKey , ok := p . nodesAcked . keysAndHash . Keys [ msg . FromNode ]
p . nodesAcked . 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-05-16 05:15:38 +00:00
fmt . Printf ( " \n * public key 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-16 05:15:38 +00:00
//dbUpdateHash will update the public key for a node in the db.
func ( p * pki ) dbUpdateHash ( hash [ ] byte ) error {
err := p . db . Update ( func ( tx * bolt . Tx ) error {
//Create a bucket
bu , err := tx . CreateBucketIfNotExists ( [ ] byte ( "hash" ) )
if err != nil {
return fmt . Errorf ( "error: CreateBuckerIfNotExists failed: %v" , err )
}
//Put a value into the bucket.
if err := bu . Put ( [ ] byte ( "hash" ) , [ ] byte ( hash ) ) ; 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
}
// dbViewHash will look up and return a specific value if it exists for a key in a bucket in a DB.
func ( p * pki ) dbViewHash ( ) ( [ ] byte , error ) {
var value [ ] byte
// View is a help function to get values out of the database.
err := p . db . View ( func ( tx * bolt . Tx ) error {
//Open a bucket to get key's and values from.
bu := tx . Bucket ( [ ] byte ( "hash" ) )
if bu == nil {
log . Printf ( "info: no db hash bucket exist\n" )
return nil
}
v := bu . Get ( [ ] byte ( "hash" ) )
if len ( v ) == 0 {
log . Printf ( "info: view: hash key not found\n" )
return nil
}
value = v
return nil
} )
return value , 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-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
}