dynsec_helper.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. // constant for node role
  18. NodeRole = "node"
  19. // HostGenericRole constant for host role
  20. HostGenericRole = "host"
  21. // const for dynamic security file
  22. dynamicSecurityFile = "dynamic-security.json"
  23. )
  24. var (
  25. // default configuration of dynamic security
  26. dynConfigInI = dynJSON{
  27. Clients: []client{
  28. {
  29. Username: mqAdminUserName,
  30. TextName: "netmaker admin user",
  31. Password: "",
  32. Salt: "",
  33. Iterations: 0,
  34. Roles: []clientRole{
  35. {
  36. Rolename: adminRole,
  37. },
  38. },
  39. },
  40. {
  41. Username: mqNetmakerServerUserName,
  42. TextName: "netmaker server user",
  43. Password: "",
  44. Salt: "",
  45. Iterations: 0,
  46. Roles: []clientRole{
  47. {
  48. Rolename: serverRole,
  49. },
  50. },
  51. },
  52. exporterMQClient,
  53. },
  54. Roles: []role{
  55. {
  56. Rolename: adminRole,
  57. Acls: fetchAdminAcls(),
  58. },
  59. {
  60. Rolename: serverRole,
  61. Acls: fetchServerAcls(),
  62. },
  63. {
  64. Rolename: HostGenericRole,
  65. Acls: fetchNodeAcls(),
  66. },
  67. exporterMQRole,
  68. },
  69. DefaultAcl: defaultAccessAcl{
  70. PublishClientSend: false,
  71. PublishClientReceive: true,
  72. Subscribe: false,
  73. Unsubscribe: true,
  74. },
  75. }
  76. exporterMQClient = client{
  77. Username: mqExporterUserName,
  78. TextName: "netmaker metrics exporter",
  79. Password: "",
  80. Salt: "",
  81. Iterations: 101,
  82. Roles: []clientRole{
  83. {
  84. Rolename: exporterRole,
  85. },
  86. },
  87. }
  88. exporterMQRole = role{
  89. Rolename: exporterRole,
  90. Acls: fetchExporterAcls(),
  91. }
  92. )
  93. // DynListCLientsCmdResp - struct for list clients response from MQ
  94. type DynListCLientsCmdResp struct {
  95. Responses []struct {
  96. Command string `json:"command"`
  97. Error string `json:"error"`
  98. Data ListClientsData `json:"data"`
  99. } `json:"responses"`
  100. }
  101. // ListClientsData - struct for list clients data
  102. type ListClientsData struct {
  103. Clients []string `json:"clients"`
  104. TotalCount int `json:"totalCount"`
  105. }
  106. // GetAdminClient - fetches admin client of the MQ
  107. func GetAdminClient() (mqtt.Client, error) {
  108. opts := mqtt.NewClientOptions()
  109. setMqOptions(mqAdminUserName, servercfg.GetMqAdminPassword(), opts)
  110. mqclient := mqtt.NewClient(opts)
  111. var connecterr error
  112. if token := mqclient.Connect(); !token.WaitTimeout(MQ_TIMEOUT*time.Second) || token.Error() != nil {
  113. if token.Error() == nil {
  114. connecterr = errors.New("connect timeout")
  115. } else {
  116. connecterr = token.Error()
  117. }
  118. }
  119. return mqclient, connecterr
  120. }
  121. // ListClients - to list all clients in the MQ
  122. func ListClients(client mqtt.Client) (ListClientsData, error) {
  123. respChan := make(chan mqtt.Message, 10)
  124. defer close(respChan)
  125. command := "listClients"
  126. resp := ListClientsData{}
  127. msg := MqDynsecPayload{
  128. Commands: []MqDynSecCmd{
  129. {
  130. Command: command,
  131. },
  132. },
  133. }
  134. client.Subscribe("$CONTROL/dynamic-security/v1/response", 2, mqtt.MessageHandler(func(c mqtt.Client, m mqtt.Message) {
  135. respChan <- m
  136. }))
  137. defer client.Unsubscribe()
  138. d, _ := json.Marshal(msg)
  139. token := client.Publish("$CONTROL/dynamic-security/v1", 2, true, d)
  140. if !token.WaitTimeout(30) || token.Error() != nil {
  141. var err error
  142. if token.Error() == nil {
  143. err = errors.New("connection timeout")
  144. } else {
  145. err = token.Error()
  146. }
  147. return resp, err
  148. }
  149. for m := range respChan {
  150. msg := DynListCLientsCmdResp{}
  151. json.Unmarshal(m.Payload(), &msg)
  152. for _, mI := range msg.Responses {
  153. if mI.Command == command {
  154. return mI.Data, nil
  155. }
  156. }
  157. }
  158. return resp, errors.New("resp not found")
  159. }
  160. // fetches host related acls
  161. func fetchHostAcls(hostID string) []Acl {
  162. return []Acl{
  163. {
  164. AclType: "publishClientReceive",
  165. Topic: fmt.Sprintf("peers/host/%s/#", hostID),
  166. Priority: -1,
  167. Allow: true,
  168. },
  169. }
  170. }
  171. // FetchNetworkAcls - fetches network acls
  172. func FetchNetworkAcls(network string) []Acl {
  173. return []Acl{
  174. {
  175. AclType: "publishClientReceive",
  176. Topic: fmt.Sprintf("update/%s/#", network),
  177. Priority: -1,
  178. Allow: true,
  179. },
  180. {
  181. AclType: "publishClientReceive",
  182. Topic: fmt.Sprintf("peers/%s/#", network),
  183. Priority: -1,
  184. Allow: true,
  185. },
  186. {
  187. AclType: "publishClientReceive",
  188. Topic: fmt.Sprintf("proxy/%s/#", network),
  189. Priority: -1,
  190. Allow: true,
  191. },
  192. {
  193. AclType: "subscribePattern",
  194. Topic: "#",
  195. Priority: -1,
  196. Allow: true,
  197. },
  198. {
  199. AclType: "unsubscribePattern",
  200. Topic: "#",
  201. Priority: -1,
  202. Allow: true,
  203. },
  204. }
  205. }
  206. // DeleteNetworkRole - deletes a network role from DynSec system
  207. func DeleteNetworkRole(network string) error {
  208. // Deletes the network role from MQ
  209. event := MqDynsecPayload{
  210. Commands: []MqDynSecCmd{
  211. {
  212. Command: DeleteRoleCmd,
  213. RoleName: network,
  214. },
  215. },
  216. }
  217. return publishEventToDynSecTopic(event)
  218. }
  219. func deleteHostRole(hostID string) error {
  220. // Deletes the hostID role from MQ
  221. event := MqDynsecPayload{
  222. Commands: []MqDynSecCmd{
  223. {
  224. Command: DeleteRoleCmd,
  225. RoleName: getHostRoleName(hostID),
  226. },
  227. },
  228. }
  229. return publishEventToDynSecTopic(event)
  230. }
  231. // CreateNetworkRole - createss a network role from DynSec system
  232. func CreateNetworkRole(network string) error {
  233. // Create Role with acls for the network
  234. event := MqDynsecPayload{
  235. Commands: []MqDynSecCmd{
  236. {
  237. Command: CreateRoleCmd,
  238. RoleName: network,
  239. Textname: "Network wide role with Acls for nodes",
  240. Acls: FetchNetworkAcls(network),
  241. },
  242. },
  243. }
  244. return publishEventToDynSecTopic(event)
  245. }
  246. // creates role for the host with ID.
  247. func createHostRole(hostID string) error {
  248. // Create Role with acls for the host
  249. event := MqDynsecPayload{
  250. Commands: []MqDynSecCmd{
  251. {
  252. Command: CreateRoleCmd,
  253. RoleName: getHostRoleName(hostID),
  254. Textname: "host role with Acls for hosts",
  255. Acls: fetchHostAcls(hostID),
  256. },
  257. },
  258. }
  259. return publishEventToDynSecTopic(event)
  260. }
  261. func getHostRoleName(hostID string) string {
  262. return fmt.Sprintf("host-%s", hostID)
  263. }
  264. // serverAcls - fetches server role related acls
  265. func fetchServerAcls() []Acl {
  266. return []Acl{
  267. {
  268. AclType: "publishClientSend",
  269. Topic: "peers/#",
  270. Priority: -1,
  271. Allow: true,
  272. },
  273. {
  274. AclType: "publishClientSend",
  275. Topic: "proxy/#",
  276. Priority: -1,
  277. Allow: true,
  278. },
  279. {
  280. AclType: "publishClientSend",
  281. Topic: "peers/host/#",
  282. Priority: -1,
  283. Allow: true,
  284. },
  285. {
  286. AclType: "publishClientSend",
  287. Topic: "update/#",
  288. Priority: -1,
  289. Allow: true,
  290. },
  291. {
  292. AclType: "publishClientSend",
  293. Topic: "metrics_exporter",
  294. Priority: -1,
  295. Allow: true,
  296. },
  297. {
  298. AclType: "publishClientReceive",
  299. Topic: "ping/#",
  300. Priority: -1,
  301. Allow: true,
  302. },
  303. {
  304. AclType: "publishClientReceive",
  305. Topic: "update/#",
  306. Priority: -1,
  307. Allow: true,
  308. },
  309. {
  310. AclType: "publishClientReceive",
  311. Topic: "signal/#",
  312. Priority: -1,
  313. Allow: true,
  314. },
  315. {
  316. AclType: "publishClientReceive",
  317. Topic: "metrics/#",
  318. Priority: -1,
  319. Allow: true,
  320. },
  321. {
  322. AclType: "subscribePattern",
  323. Topic: "#",
  324. Priority: -1,
  325. Allow: true,
  326. },
  327. {
  328. AclType: "unsubscribePattern",
  329. Topic: "#",
  330. Priority: -1,
  331. Allow: true,
  332. },
  333. }
  334. }
  335. // fetchNodeAcls - fetches node related acls
  336. func fetchNodeAcls() []Acl {
  337. // keeping node acls generic as of now.
  338. return []Acl{
  339. {
  340. AclType: "publishClientSend",
  341. Topic: "signal/#",
  342. Priority: -1,
  343. Allow: true,
  344. },
  345. {
  346. AclType: "publishClientSend",
  347. Topic: "update/#",
  348. Priority: -1,
  349. Allow: true,
  350. },
  351. {
  352. AclType: "publishClientSend",
  353. Topic: "ping/#",
  354. Priority: -1,
  355. Allow: true,
  356. },
  357. {
  358. AclType: "publishClientSend",
  359. Topic: "metrics/#",
  360. Priority: -1,
  361. Allow: true,
  362. },
  363. {
  364. AclType: "subscribePattern",
  365. Topic: "#",
  366. Priority: -1,
  367. Allow: true,
  368. },
  369. {
  370. AclType: "unsubscribePattern",
  371. Topic: "#",
  372. Priority: -1,
  373. Allow: true,
  374. },
  375. }
  376. }
  377. // fetchExporterAcls - fetch exporter role related acls
  378. func fetchExporterAcls() []Acl {
  379. return []Acl{
  380. {
  381. AclType: "publishClientReceive",
  382. Topic: "metrics_exporter",
  383. Allow: true,
  384. Priority: -1,
  385. },
  386. {
  387. AclType: "subscribePattern",
  388. Topic: "#",
  389. Priority: -1,
  390. Allow: true,
  391. },
  392. {
  393. AclType: "unsubscribePattern",
  394. Topic: "#",
  395. Priority: -1,
  396. Allow: true,
  397. },
  398. }
  399. }
  400. // fetchAdminAcls - fetches admin role related acls
  401. func fetchAdminAcls() []Acl {
  402. return []Acl{
  403. {
  404. AclType: "publishClientSend",
  405. Topic: "$CONTROL/dynamic-security/#",
  406. Priority: -1,
  407. Allow: true,
  408. },
  409. {
  410. AclType: "publishClientReceive",
  411. Topic: "$CONTROL/dynamic-security/#",
  412. Priority: -1,
  413. Allow: true,
  414. },
  415. {
  416. AclType: "subscribePattern",
  417. Topic: "$CONTROL/dynamic-security/#",
  418. Priority: -1,
  419. Allow: true,
  420. },
  421. {
  422. AclType: "publishClientReceive",
  423. Topic: "$SYS/#",
  424. Priority: -1,
  425. Allow: true,
  426. },
  427. {
  428. AclType: "subscribePattern",
  429. Topic: "$SYS/#",
  430. Priority: -1,
  431. Allow: true,
  432. },
  433. {
  434. AclType: "publishClientReceive",
  435. Topic: "#",
  436. Priority: -1,
  437. Allow: true,
  438. },
  439. {
  440. AclType: "subscribePattern",
  441. Topic: "#",
  442. Priority: -1,
  443. Allow: true,
  444. },
  445. {
  446. AclType: "unsubscribePattern",
  447. Topic: "#",
  448. Priority: -1,
  449. Allow: true,
  450. },
  451. {
  452. AclType: "publishClientSend",
  453. Topic: "#",
  454. Priority: -1,
  455. Allow: true,
  456. },
  457. }
  458. }