dynsec_helper.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. package mq
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "time"
  7. mqtt "github.com/eclipse/paho.mqtt.golang"
  8. "github.com/gravitl/netmaker/servercfg"
  9. )
  10. const (
  11. // constant for admin role
  12. adminRole = "admin"
  13. // constant for server role
  14. serverRole = "server"
  15. // constant for exporter role
  16. exporterRole = "exporter"
  17. // const for dynamic security file
  18. dynamicSecurityFile = "dynamic-security.json"
  19. )
  20. var (
  21. // default configuration of dynamic security
  22. dynConfig = dynJSON{
  23. Clients: []client{
  24. {
  25. Username: mqAdminUserName,
  26. TextName: "netmaker admin user",
  27. Password: "",
  28. Salt: "",
  29. Iterations: 0,
  30. Roles: []clientRole{
  31. {
  32. Rolename: adminRole,
  33. },
  34. },
  35. },
  36. {
  37. Username: mqNetmakerServerUserName,
  38. TextName: "netmaker server user",
  39. Password: "",
  40. Salt: "",
  41. Iterations: 0,
  42. Roles: []clientRole{
  43. {
  44. Rolename: serverRole,
  45. },
  46. },
  47. },
  48. },
  49. Roles: []role{
  50. {
  51. Rolename: adminRole,
  52. Acls: []Acl{
  53. {
  54. AclType: "publishClientSend",
  55. Topic: "$CONTROL/dynamic-security/#",
  56. Priority: -1,
  57. Allow: true,
  58. },
  59. {
  60. AclType: "publishClientReceive",
  61. Topic: "$CONTROL/dynamic-security/#",
  62. Priority: -1,
  63. Allow: true,
  64. },
  65. {
  66. AclType: "subscribePattern",
  67. Topic: "$CONTROL/dynamic-security/#",
  68. Priority: -1,
  69. Allow: true,
  70. },
  71. {
  72. AclType: "publishClientReceive",
  73. Topic: "$SYS/#",
  74. Priority: -1,
  75. Allow: true,
  76. },
  77. {
  78. AclType: "subscribePattern",
  79. Topic: "$SYS/#",
  80. Priority: -1,
  81. Allow: true,
  82. },
  83. {
  84. AclType: "publishClientReceive",
  85. Topic: "#",
  86. Priority: -1,
  87. Allow: true,
  88. },
  89. {
  90. AclType: "subscribePattern",
  91. Topic: "#",
  92. Priority: -1,
  93. Allow: true,
  94. },
  95. {
  96. AclType: "unsubscribePattern",
  97. Topic: "#",
  98. Priority: -1,
  99. Allow: true,
  100. },
  101. {
  102. AclType: "publishClientSend",
  103. Topic: "#",
  104. Priority: -1,
  105. Allow: true,
  106. },
  107. },
  108. },
  109. {
  110. Rolename: serverRole,
  111. Acls: []Acl{
  112. {
  113. AclType: "publishClientSend",
  114. Topic: "peers/#",
  115. Priority: -1,
  116. Allow: true,
  117. },
  118. {
  119. AclType: "publishClientSend",
  120. Topic: "update/#",
  121. Priority: -1,
  122. Allow: true,
  123. },
  124. {
  125. AclType: "publishClientSend",
  126. Topic: "metrics_exporter",
  127. Priority: -1,
  128. Allow: true,
  129. },
  130. {
  131. AclType: "publishClientReceive",
  132. Topic: "ping/#",
  133. Priority: -1,
  134. Allow: true,
  135. },
  136. {
  137. AclType: "publishClientReceive",
  138. Topic: "update/#",
  139. Priority: -1,
  140. Allow: true,
  141. },
  142. {
  143. AclType: "publishClientReceive",
  144. Topic: "signal/#",
  145. Priority: -1,
  146. Allow: true,
  147. },
  148. {
  149. AclType: "publishClientReceive",
  150. Topic: "metrics/#",
  151. Priority: -1,
  152. Allow: true,
  153. },
  154. },
  155. },
  156. },
  157. DefaultAcl: defaultAccessAcl{
  158. PublishClientSend: false,
  159. PublishClientReceive: true,
  160. Subscribe: false,
  161. Unsubscribe: true,
  162. },
  163. }
  164. exporterMQClient = client{
  165. Username: mqExporterUserName,
  166. TextName: "netmaker metrics exporter",
  167. Password: "",
  168. Salt: "",
  169. Iterations: 101,
  170. Roles: []clientRole{
  171. {
  172. Rolename: exporterRole,
  173. },
  174. },
  175. }
  176. exporterMQRole = role{
  177. Rolename: exporterRole,
  178. Acls: []Acl{
  179. {
  180. AclType: "publishClientReceive",
  181. Topic: "metrics_exporter",
  182. Allow: true,
  183. Priority: -1,
  184. },
  185. },
  186. }
  187. )
  188. // DynListCLientsCmdResp - struct for list clients response from MQ
  189. type DynListCLientsCmdResp struct {
  190. Responses []struct {
  191. Command string `json:"command"`
  192. Error string `json:"error"`
  193. Data ListClientsData `json:"data"`
  194. } `json:"responses"`
  195. }
  196. // ListClientsData - struct for list clients data
  197. type ListClientsData struct {
  198. Clients []string `json:"clients"`
  199. TotalCount int `json:"totalCount"`
  200. }
  201. // GetAdminClient - fetches admin client of the MQ
  202. func GetAdminClient() (mqtt.Client, error) {
  203. opts := mqtt.NewClientOptions()
  204. setMqOptions(mqAdminUserName, servercfg.GetMqAdminPassword(), opts)
  205. mqclient := mqtt.NewClient(opts)
  206. var connecterr error
  207. if token := mqclient.Connect(); !token.WaitTimeout(MQ_TIMEOUT*time.Second) || token.Error() != nil {
  208. if token.Error() == nil {
  209. connecterr = errors.New("connect timeout")
  210. } else {
  211. connecterr = token.Error()
  212. }
  213. }
  214. return mqclient, connecterr
  215. }
  216. // ListClients - to list all clients in the MQ
  217. func ListClients(client mqtt.Client) (ListClientsData, error) {
  218. respChan := make(chan mqtt.Message, 10)
  219. defer close(respChan)
  220. command := "listClients"
  221. resp := ListClientsData{}
  222. msg := MqDynsecPayload{
  223. Commands: []MqDynSecCmd{
  224. {
  225. Command: command,
  226. },
  227. },
  228. }
  229. client.Subscribe("$CONTROL/dynamic-security/v1/response", 2, mqtt.MessageHandler(func(c mqtt.Client, m mqtt.Message) {
  230. respChan <- m
  231. }))
  232. defer client.Unsubscribe()
  233. d, _ := json.Marshal(msg)
  234. token := client.Publish("$CONTROL/dynamic-security/v1", 2, true, d)
  235. if !token.WaitTimeout(30) || token.Error() != nil {
  236. var err error
  237. if token.Error() == nil {
  238. err = errors.New("connection timeout")
  239. } else {
  240. err = token.Error()
  241. }
  242. return resp, err
  243. }
  244. for m := range respChan {
  245. msg := DynListCLientsCmdResp{}
  246. json.Unmarshal(m.Payload(), &msg)
  247. for _, mI := range msg.Responses {
  248. if mI.Command == command {
  249. return mI.Data, nil
  250. }
  251. }
  252. }
  253. return resp, errors.New("resp not found")
  254. }
  255. // FetchNetworkAcls - fetches network acls
  256. func FetchNetworkAcls(network string) []Acl {
  257. return []Acl{
  258. {
  259. AclType: "publishClientReceive",
  260. Topic: fmt.Sprintf("update/%s/#", network),
  261. Allow: true,
  262. },
  263. {
  264. AclType: "publishClientReceive",
  265. Topic: fmt.Sprintf("peers/%s/#", network),
  266. Allow: true,
  267. },
  268. }
  269. }
  270. // FetchNodeAcls -fetches node acls
  271. func FetchNodeAcls(nodeID string) []Acl {
  272. return []Acl{
  273. {
  274. AclType: "publishClientSend",
  275. Topic: fmt.Sprintf("signal/%s", nodeID),
  276. Allow: true,
  277. },
  278. {
  279. AclType: "publishClientSend",
  280. Topic: fmt.Sprintf("update/%s", nodeID),
  281. Allow: true,
  282. },
  283. {
  284. AclType: "publishClientSend",
  285. Topic: fmt.Sprintf("ping/%s", nodeID),
  286. Allow: true,
  287. },
  288. {
  289. AclType: "publishClientSend",
  290. Topic: fmt.Sprintf("metrics/%s", nodeID),
  291. Allow: true,
  292. },
  293. }
  294. }