|
@@ -1,214 +0,0 @@
|
|
|
-package mq
|
|
|
-
|
|
|
-import (
|
|
|
- "crypto/sha512"
|
|
|
- "encoding/base64"
|
|
|
- "encoding/json"
|
|
|
- "errors"
|
|
|
- "fmt"
|
|
|
- "os"
|
|
|
- "time"
|
|
|
-
|
|
|
- mqtt "github.com/eclipse/paho.mqtt.golang"
|
|
|
- "github.com/gravitl/netmaker/functions"
|
|
|
- "github.com/gravitl/netmaker/logger"
|
|
|
- "github.com/gravitl/netmaker/logic"
|
|
|
- "github.com/gravitl/netmaker/netclient/ncutils"
|
|
|
- "github.com/gravitl/netmaker/servercfg"
|
|
|
- "golang.org/x/crypto/pbkdf2"
|
|
|
-)
|
|
|
-
|
|
|
-// mq client for admin
|
|
|
-var mqAdminClient mqtt.Client
|
|
|
-
|
|
|
-const (
|
|
|
- // constant for client command
|
|
|
- CreateClientCmd = "createClient"
|
|
|
- // constant for disable command
|
|
|
- DisableClientCmd = "disableClient"
|
|
|
- // constant for delete client command
|
|
|
- DeleteClientCmd = "deleteClient"
|
|
|
- // constant for modify client command
|
|
|
- ModifyClientCmd = "modifyClient"
|
|
|
-
|
|
|
- // constant for create role command
|
|
|
- CreateRoleCmd = "createRole"
|
|
|
- // constant for delete role command
|
|
|
- DeleteRoleCmd = "deleteRole"
|
|
|
-
|
|
|
- // constant for admin user name
|
|
|
- mqAdminUserName = "Netmaker-Admin"
|
|
|
- // constant for server user name
|
|
|
- mqNetmakerServerUserName = "Netmaker-Server"
|
|
|
- // constant for exporter user name
|
|
|
- mqExporterUserName = "Netmaker-Exporter"
|
|
|
-
|
|
|
- // DynamicSecSubTopic - constant for dynamic security subscription topic
|
|
|
- dynamicSecSubTopic = "$CONTROL/dynamic-security/#"
|
|
|
- // DynamicSecPubTopic - constant for dynamic security subscription topic
|
|
|
- dynamicSecPubTopic = "$CONTROL/dynamic-security/v1"
|
|
|
-)
|
|
|
-
|
|
|
-// struct for dynamic security file
|
|
|
-type dynJSON struct {
|
|
|
- Clients []client `json:"clients"`
|
|
|
- Roles []role `json:"roles"`
|
|
|
- DefaultAcl defaultAccessAcl `json:"defaultACLAccess"`
|
|
|
-}
|
|
|
-
|
|
|
-// struct for client role
|
|
|
-type clientRole struct {
|
|
|
- Rolename string `json:"rolename"`
|
|
|
-}
|
|
|
-
|
|
|
-// struct for MQ client
|
|
|
-type client struct {
|
|
|
- Username string `json:"username"`
|
|
|
- TextName string `json:"textName"`
|
|
|
- Password string `json:"password"`
|
|
|
- Salt string `json:"salt"`
|
|
|
- Iterations int `json:"iterations"`
|
|
|
- Roles []clientRole `json:"roles"`
|
|
|
-}
|
|
|
-
|
|
|
-// struct for MQ role
|
|
|
-type role struct {
|
|
|
- Rolename string `json:"rolename"`
|
|
|
- Acls []Acl `json:"acls"`
|
|
|
-}
|
|
|
-
|
|
|
-// struct for default acls
|
|
|
-type defaultAccessAcl struct {
|
|
|
- PublishClientSend bool `json:"publishClientSend"`
|
|
|
- PublishClientReceive bool `json:"publishClientReceive"`
|
|
|
- Subscribe bool `json:"subscribe"`
|
|
|
- Unsubscribe bool `json:"unsubscribe"`
|
|
|
-}
|
|
|
-
|
|
|
-// MqDynSecGroup - struct for MQ client group
|
|
|
-type MqDynSecGroup struct {
|
|
|
- Groupname string `json:"groupname"`
|
|
|
- Priority int `json:"priority"`
|
|
|
-}
|
|
|
-
|
|
|
-// MqDynSecRole - struct for MQ client role
|
|
|
-type MqDynSecRole struct {
|
|
|
- Rolename string `json:"rolename"`
|
|
|
- Priority int `json:"priority"`
|
|
|
-}
|
|
|
-
|
|
|
-// Acl - struct for MQ acls
|
|
|
-type Acl struct {
|
|
|
- AclType string `json:"acltype"`
|
|
|
- Topic string `json:"topic"`
|
|
|
- Priority int `json:"priority,omitempty"`
|
|
|
- Allow bool `json:"allow"`
|
|
|
-}
|
|
|
-
|
|
|
-// MqDynSecCmd - struct for MQ dynamic security command
|
|
|
-type MqDynSecCmd struct {
|
|
|
- Command string `json:"command"`
|
|
|
- Username string `json:"username"`
|
|
|
- Password string `json:"password"`
|
|
|
- RoleName string `json:"rolename,omitempty"`
|
|
|
- Acls []Acl `json:"acls,omitempty"`
|
|
|
- Clientid string `json:"clientid"`
|
|
|
- Textname string `json:"textname"`
|
|
|
- Textdescription string `json:"textdescription"`
|
|
|
- Groups []MqDynSecGroup `json:"groups"`
|
|
|
- Roles []MqDynSecRole `json:"roles"`
|
|
|
-}
|
|
|
-
|
|
|
-// MqDynsecPayload - struct for dynamic security command payload
|
|
|
-type MqDynsecPayload struct {
|
|
|
- Commands []MqDynSecCmd `json:"commands"`
|
|
|
-}
|
|
|
-
|
|
|
-// encodePasswordToPBKDF2 - encodes the given password with PBKDF2 hashing for MQ
|
|
|
-func encodePasswordToPBKDF2(password string, salt string, iterations int, keyLength int) string {
|
|
|
- binaryEncoded := pbkdf2.Key([]byte(password), []byte(salt), iterations, keyLength, sha512.New)
|
|
|
- return base64.StdEncoding.EncodeToString(binaryEncoded)
|
|
|
-}
|
|
|
-
|
|
|
-// Configure - configures the dynamic initial configuration for MQ
|
|
|
-func Configure() error {
|
|
|
-
|
|
|
- logger.Log(0, "Configuring MQ...")
|
|
|
- dynConfig := dynConfigInI
|
|
|
- path := functions.GetNetmakerPath() + ncutils.GetSeparator() + dynamicSecurityFile
|
|
|
-
|
|
|
- password := servercfg.GetMqAdminPassword()
|
|
|
- if password == "" {
|
|
|
- return errors.New("MQ admin password not provided")
|
|
|
- }
|
|
|
- if logic.CheckIfFileExists(path) {
|
|
|
- data, err := os.ReadFile(path)
|
|
|
- if err == nil {
|
|
|
- var cfg dynJSON
|
|
|
- err = json.Unmarshal(data, &cfg)
|
|
|
- if err == nil {
|
|
|
- logger.Log(0, "MQ config exists already, So Updating Existing Config...")
|
|
|
- dynConfig = cfg
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- exporter := false
|
|
|
- for i, cI := range dynConfig.Clients {
|
|
|
- if cI.Username == mqAdminUserName || cI.Username == mqNetmakerServerUserName {
|
|
|
- salt := logic.RandomString(12)
|
|
|
- hashed := encodePasswordToPBKDF2(password, salt, 101, 64)
|
|
|
- cI.Password = hashed
|
|
|
- cI.Iterations = 101
|
|
|
- cI.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
|
|
|
- dynConfig.Clients[i] = cI
|
|
|
- } else if servercfg.Is_EE && cI.Username == mqExporterUserName {
|
|
|
- exporter = true
|
|
|
- exporterPassword := servercfg.GetLicenseKey()
|
|
|
- salt := logic.RandomString(12)
|
|
|
- hashed := encodePasswordToPBKDF2(exporterPassword, salt, 101, 64)
|
|
|
- cI.Password = hashed
|
|
|
- cI.Iterations = 101
|
|
|
- cI.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
|
|
|
- dynConfig.Clients[i] = cI
|
|
|
- }
|
|
|
- }
|
|
|
- if servercfg.Is_EE && !exporter {
|
|
|
- exporterPassword := servercfg.GetLicenseKey()
|
|
|
- salt := logic.RandomString(12)
|
|
|
- hashed := encodePasswordToPBKDF2(exporterPassword, salt, 101, 64)
|
|
|
- exporterMQClient.Password = hashed
|
|
|
- exporterMQClient.Iterations = 101
|
|
|
- exporterMQClient.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
|
|
|
- dynConfig.Clients = append(dynConfig.Clients, exporterMQClient)
|
|
|
- }
|
|
|
- data, err := json.MarshalIndent(dynConfig, "", " ")
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- return os.WriteFile(path, data, 0755)
|
|
|
-}
|
|
|
-
|
|
|
-// publishes the message to dynamic security topic
|
|
|
-func publishEventToDynSecTopic(payload MqDynsecPayload) error {
|
|
|
-
|
|
|
- d, err := json.Marshal(payload)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- var connecterr error
|
|
|
- if token := mqAdminClient.Publish(dynamicSecPubTopic, 2, false, d); !token.WaitTimeout(MQ_TIMEOUT*time.Second) || token.Error() != nil {
|
|
|
- if token.Error() == nil {
|
|
|
- connecterr = errors.New("connect timeout")
|
|
|
- } else {
|
|
|
- connecterr = token.Error()
|
|
|
- }
|
|
|
- }
|
|
|
- return connecterr
|
|
|
-}
|
|
|
-
|
|
|
-// watchDynSecTopic - message handler for dynamic security responses
|
|
|
-func watchDynSecTopic(client mqtt.Client, msg mqtt.Message) {
|
|
|
-
|
|
|
- logger.Log(1, fmt.Sprintf("----->WatchDynSecTopic Message: %+v", string(msg.Payload())))
|
|
|
-
|
|
|
-}
|