dynsec_helper.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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. AclType: "publishClientReceive",
  171. Topic: fmt.Sprintf("host/update/%s/#", hostID),
  172. Priority: -1,
  173. Allow: true,
  174. },
  175. }
  176. }
  177. // FetchNetworkAcls - fetches network acls
  178. func FetchNetworkAcls(network string) []Acl {
  179. return []Acl{
  180. {
  181. AclType: "publishClientReceive",
  182. Topic: fmt.Sprintf("update/%s/#", network),
  183. Priority: -1,
  184. Allow: true,
  185. },
  186. {
  187. AclType: "publishClientReceive",
  188. Topic: fmt.Sprintf("peers/%s/#", network),
  189. Priority: -1,
  190. Allow: true,
  191. },
  192. {
  193. AclType: "publishClientReceive",
  194. Topic: fmt.Sprintf("proxy/%s/#", network),
  195. Priority: -1,
  196. Allow: true,
  197. },
  198. {
  199. AclType: "subscribePattern",
  200. Topic: "#",
  201. Priority: -1,
  202. Allow: true,
  203. },
  204. {
  205. AclType: "unsubscribePattern",
  206. Topic: "#",
  207. Priority: -1,
  208. Allow: true,
  209. },
  210. }
  211. }
  212. // DeleteNetworkRole - deletes a network role from DynSec system
  213. func DeleteNetworkRole(network string) error {
  214. // Deletes the network role from MQ
  215. event := MqDynsecPayload{
  216. Commands: []MqDynSecCmd{
  217. {
  218. Command: DeleteRoleCmd,
  219. RoleName: network,
  220. },
  221. },
  222. }
  223. return publishEventToDynSecTopic(event)
  224. }
  225. func deleteHostRole(hostID string) error {
  226. // Deletes the hostID role from MQ
  227. event := MqDynsecPayload{
  228. Commands: []MqDynSecCmd{
  229. {
  230. Command: DeleteRoleCmd,
  231. RoleName: getHostRoleName(hostID),
  232. },
  233. },
  234. }
  235. return publishEventToDynSecTopic(event)
  236. }
  237. // CreateNetworkRole - createss a network role from DynSec system
  238. func CreateNetworkRole(network string) error {
  239. // Create Role with acls for the network
  240. event := MqDynsecPayload{
  241. Commands: []MqDynSecCmd{
  242. {
  243. Command: CreateRoleCmd,
  244. RoleName: network,
  245. Textname: "Network wide role with Acls for nodes",
  246. Acls: FetchNetworkAcls(network),
  247. },
  248. },
  249. }
  250. return publishEventToDynSecTopic(event)
  251. }
  252. // creates role for the host with ID.
  253. func createHostRole(hostID string) error {
  254. // Create Role with acls for the host
  255. event := MqDynsecPayload{
  256. Commands: []MqDynSecCmd{
  257. {
  258. Command: CreateRoleCmd,
  259. RoleName: getHostRoleName(hostID),
  260. Textname: "host role with Acls for hosts",
  261. Acls: fetchHostAcls(hostID),
  262. },
  263. },
  264. }
  265. return publishEventToDynSecTopic(event)
  266. }
  267. func getHostRoleName(hostID string) string {
  268. return fmt.Sprintf("host-%s", hostID)
  269. }
  270. // serverAcls - fetches server role related acls
  271. func fetchServerAcls() []Acl {
  272. return []Acl{
  273. {
  274. AclType: "publishClientSend",
  275. Topic: "peers/#",
  276. Priority: -1,
  277. Allow: true,
  278. },
  279. {
  280. AclType: "publishClientSend",
  281. Topic: "proxy/#",
  282. Priority: -1,
  283. Allow: true,
  284. },
  285. {
  286. AclType: "publishClientSend",
  287. Topic: "peers/host/#",
  288. Priority: -1,
  289. Allow: true,
  290. },
  291. {
  292. AclType: "publishClientSend",
  293. Topic: "update/#",
  294. Priority: -1,
  295. Allow: true,
  296. },
  297. {
  298. AclType: "publishClientSend",
  299. Topic: "metrics_exporter",
  300. Priority: -1,
  301. Allow: true,
  302. },
  303. {
  304. AclType: "publishClientReceive",
  305. Topic: "ping/#",
  306. Priority: -1,
  307. Allow: true,
  308. },
  309. {
  310. AclType: "publishClientReceive",
  311. Topic: "update/#",
  312. Priority: -1,
  313. Allow: true,
  314. },
  315. {
  316. AclType: "publishClientReceive",
  317. Topic: "signal/#",
  318. Priority: -1,
  319. Allow: true,
  320. },
  321. {
  322. AclType: "publishClientReceive",
  323. Topic: "metrics/#",
  324. Priority: -1,
  325. Allow: true,
  326. },
  327. {
  328. AclType: "subscribePattern",
  329. Topic: "#",
  330. Priority: -1,
  331. Allow: true,
  332. },
  333. {
  334. AclType: "unsubscribePattern",
  335. Topic: "#",
  336. Priority: -1,
  337. Allow: true,
  338. },
  339. {
  340. AclType: "publishClientReceive",
  341. Topic: "host/update/#",
  342. Priority: -1,
  343. Allow: true,
  344. },
  345. }
  346. }
  347. // fetchNodeAcls - fetches node related acls
  348. func fetchNodeAcls() []Acl {
  349. // keeping node acls generic as of now.
  350. return []Acl{
  351. {
  352. AclType: "publishClientSend",
  353. Topic: "signal/#",
  354. Priority: -1,
  355. Allow: true,
  356. },
  357. {
  358. AclType: "publishClientSend",
  359. Topic: "update/#",
  360. Priority: -1,
  361. Allow: true,
  362. },
  363. {
  364. AclType: "publishClientSend",
  365. Topic: "ping/#",
  366. Priority: -1,
  367. Allow: true,
  368. },
  369. {
  370. AclType: "publishClientSend",
  371. Topic: "metrics/#",
  372. Priority: -1,
  373. Allow: true,
  374. },
  375. {
  376. AclType: "subscribePattern",
  377. Topic: "#",
  378. Priority: -1,
  379. Allow: true,
  380. },
  381. {
  382. AclType: "unsubscribePattern",
  383. Topic: "#",
  384. Priority: -1,
  385. Allow: true,
  386. },
  387. }
  388. }
  389. // fetchExporterAcls - fetch exporter role related acls
  390. func fetchExporterAcls() []Acl {
  391. return []Acl{
  392. {
  393. AclType: "publishClientReceive",
  394. Topic: "metrics_exporter",
  395. Allow: true,
  396. Priority: -1,
  397. },
  398. {
  399. AclType: "subscribePattern",
  400. Topic: "#",
  401. Priority: -1,
  402. Allow: true,
  403. },
  404. {
  405. AclType: "unsubscribePattern",
  406. Topic: "#",
  407. Priority: -1,
  408. Allow: true,
  409. },
  410. }
  411. }
  412. // fetchAdminAcls - fetches admin role related acls
  413. func fetchAdminAcls() []Acl {
  414. return []Acl{
  415. {
  416. AclType: "publishClientSend",
  417. Topic: "$CONTROL/dynamic-security/#",
  418. Priority: -1,
  419. Allow: true,
  420. },
  421. {
  422. AclType: "publishClientReceive",
  423. Topic: "$CONTROL/dynamic-security/#",
  424. Priority: -1,
  425. Allow: true,
  426. },
  427. {
  428. AclType: "subscribePattern",
  429. Topic: "$CONTROL/dynamic-security/#",
  430. Priority: -1,
  431. Allow: true,
  432. },
  433. {
  434. AclType: "publishClientReceive",
  435. Topic: "$SYS/#",
  436. Priority: -1,
  437. Allow: true,
  438. },
  439. {
  440. AclType: "subscribePattern",
  441. Topic: "$SYS/#",
  442. Priority: -1,
  443. Allow: true,
  444. },
  445. {
  446. AclType: "publishClientReceive",
  447. Topic: "#",
  448. Priority: -1,
  449. Allow: true,
  450. },
  451. {
  452. AclType: "subscribePattern",
  453. Topic: "#",
  454. Priority: -1,
  455. Allow: true,
  456. },
  457. {
  458. AclType: "unsubscribePattern",
  459. Topic: "#",
  460. Priority: -1,
  461. Allow: true,
  462. },
  463. {
  464. AclType: "publishClientSend",
  465. Topic: "#",
  466. Priority: -1,
  467. Allow: true,
  468. },
  469. }
  470. }