backend_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. // Copyright 2021 the Kilo authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package k8s
  15. import (
  16. "net"
  17. "testing"
  18. "time"
  19. "github.com/kylelemons/godebug/pretty"
  20. "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
  21. v1 "k8s.io/api/core/v1"
  22. "github.com/squat/kilo/pkg/k8s/apis/kilo/v1alpha1"
  23. "github.com/squat/kilo/pkg/mesh"
  24. "github.com/squat/kilo/pkg/wireguard"
  25. )
  26. func mustKey() (k wgtypes.Key) {
  27. var err error
  28. if k, err = wgtypes.GeneratePrivateKey(); err != nil {
  29. panic(err.Error())
  30. }
  31. return
  32. }
  33. func mustPSKKey() (key *wgtypes.Key) {
  34. if k, err := wgtypes.GenerateKey(); err != nil {
  35. panic(err.Error())
  36. } else {
  37. key = &k
  38. }
  39. return
  40. }
  41. var (
  42. fooKey = mustKey()
  43. pskKey = mustPSKKey()
  44. second = time.Second
  45. zero = time.Duration(0)
  46. )
  47. func TestTranslateNode(t *testing.T) {
  48. for _, tc := range []struct {
  49. name string
  50. annotations map[string]string
  51. labels map[string]string
  52. out *mesh.Node
  53. subnet string
  54. }{
  55. {
  56. name: "empty",
  57. annotations: nil,
  58. out: &mesh.Node{},
  59. },
  60. {
  61. name: "invalid ips",
  62. annotations: map[string]string{
  63. endpointAnnotationKey: "10.0.0.1",
  64. internalIPAnnotationKey: "foo",
  65. },
  66. out: &mesh.Node{},
  67. },
  68. {
  69. name: "valid ips",
  70. annotations: map[string]string{
  71. endpointAnnotationKey: "10.0.0.1:51820",
  72. internalIPAnnotationKey: "10.0.0.2/32",
  73. },
  74. out: &mesh.Node{
  75. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.1").To4(), mesh.DefaultKiloPort),
  76. InternalIP: &net.IPNet{IP: net.ParseIP("10.0.0.2").To4(), Mask: net.CIDRMask(32, 32)},
  77. },
  78. },
  79. {
  80. name: "valid ips with ipv6",
  81. annotations: map[string]string{
  82. endpointAnnotationKey: "[ff10::10]:51820",
  83. internalIPAnnotationKey: "ff60::10/64",
  84. },
  85. out: &mesh.Node{
  86. Endpoint: wireguard.NewEndpoint(net.ParseIP("ff10::10").To16(), mesh.DefaultKiloPort),
  87. InternalIP: &net.IPNet{IP: net.ParseIP("ff60::10").To16(), Mask: net.CIDRMask(64, 128)},
  88. },
  89. },
  90. {
  91. name: "invalid subnet",
  92. annotations: map[string]string{},
  93. out: &mesh.Node{},
  94. subnet: "foo",
  95. },
  96. {
  97. name: "normalize subnet",
  98. annotations: map[string]string{},
  99. out: &mesh.Node{
  100. Subnet: &net.IPNet{IP: net.ParseIP("10.2.0.0").To4(), Mask: net.CIDRMask(24, 32)},
  101. },
  102. subnet: "10.2.0.1/24",
  103. },
  104. {
  105. name: "valid subnet",
  106. annotations: map[string]string{},
  107. out: &mesh.Node{
  108. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0").To4(), Mask: net.CIDRMask(24, 32)},
  109. },
  110. subnet: "10.2.1.0/24",
  111. },
  112. {
  113. name: "region",
  114. labels: map[string]string{
  115. RegionLabelKey: "a",
  116. },
  117. out: &mesh.Node{
  118. Location: "a",
  119. },
  120. },
  121. {
  122. name: "region override",
  123. annotations: map[string]string{
  124. locationAnnotationKey: "b",
  125. },
  126. labels: map[string]string{
  127. RegionLabelKey: "a",
  128. },
  129. out: &mesh.Node{
  130. Location: "b",
  131. },
  132. },
  133. {
  134. name: "invalid endpoint override",
  135. annotations: map[string]string{
  136. endpointAnnotationKey: "10.0.0.1:51820",
  137. forceEndpointAnnotationKey: "-10.0.0.2:51821",
  138. },
  139. out: &mesh.Node{
  140. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.1").To4(), mesh.DefaultKiloPort),
  141. },
  142. },
  143. {
  144. name: "endpoint override",
  145. annotations: map[string]string{
  146. endpointAnnotationKey: "10.0.0.1:51820",
  147. forceEndpointAnnotationKey: "10.0.0.2:51821",
  148. },
  149. out: &mesh.Node{
  150. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.2").To4(), 51821),
  151. },
  152. },
  153. {
  154. name: "wireguard persistent keepalive override",
  155. annotations: map[string]string{
  156. persistentKeepaliveKey: "25",
  157. },
  158. out: &mesh.Node{
  159. PersistentKeepalive: 25 * time.Second,
  160. },
  161. },
  162. {
  163. name: "invalid internal IP override",
  164. annotations: map[string]string{
  165. internalIPAnnotationKey: "10.1.0.1/24",
  166. forceInternalIPAnnotationKey: "-10.1.0.2/24",
  167. },
  168. out: &mesh.Node{
  169. InternalIP: &net.IPNet{IP: net.ParseIP("10.1.0.1").To4(), Mask: net.CIDRMask(24, 32)},
  170. NoInternalIP: false,
  171. },
  172. },
  173. {
  174. name: "internal IP override",
  175. annotations: map[string]string{
  176. internalIPAnnotationKey: "10.1.0.1/24",
  177. forceInternalIPAnnotationKey: "10.1.0.2/24",
  178. },
  179. out: &mesh.Node{
  180. InternalIP: &net.IPNet{IP: net.ParseIP("10.1.0.2").To4(), Mask: net.CIDRMask(24, 32)},
  181. NoInternalIP: false,
  182. },
  183. },
  184. {
  185. name: "invalid time",
  186. annotations: map[string]string{
  187. lastSeenAnnotationKey: "foo",
  188. },
  189. out: &mesh.Node{},
  190. },
  191. {
  192. name: "complete",
  193. annotations: map[string]string{
  194. endpointAnnotationKey: "10.0.0.1:51820",
  195. forceEndpointAnnotationKey: "10.0.0.2:51821",
  196. forceInternalIPAnnotationKey: "10.1.0.2/32",
  197. internalIPAnnotationKey: "10.1.0.1/32",
  198. keyAnnotationKey: fooKey.String(),
  199. lastSeenAnnotationKey: "1000000000",
  200. leaderAnnotationKey: "",
  201. locationAnnotationKey: "b",
  202. persistentKeepaliveKey: "25",
  203. wireGuardIPAnnotationKey: "10.4.0.1/16",
  204. },
  205. labels: map[string]string{
  206. RegionLabelKey: "a",
  207. },
  208. out: &mesh.Node{
  209. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.2").To4(), 51821),
  210. NoInternalIP: false,
  211. InternalIP: &net.IPNet{IP: net.ParseIP("10.1.0.2").To4(), Mask: net.CIDRMask(32, 32)},
  212. Key: fooKey,
  213. LastSeen: 1000000000,
  214. Leader: true,
  215. Location: "b",
  216. PersistentKeepalive: 25 * time.Second,
  217. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0").To4(), Mask: net.CIDRMask(24, 32)},
  218. WireGuardIP: &net.IPNet{IP: net.ParseIP("10.4.0.1").To4(), Mask: net.CIDRMask(16, 32)},
  219. },
  220. subnet: "10.2.1.0/24",
  221. },
  222. {
  223. name: "complete with ipv6",
  224. annotations: map[string]string{
  225. endpointAnnotationKey: "10.0.0.1:51820",
  226. forceEndpointAnnotationKey: "[1100::10]:51821",
  227. forceInternalIPAnnotationKey: "10.1.0.2/32",
  228. internalIPAnnotationKey: "10.1.0.1/32",
  229. keyAnnotationKey: fooKey.String(),
  230. lastSeenAnnotationKey: "1000000000",
  231. leaderAnnotationKey: "",
  232. locationAnnotationKey: "b",
  233. persistentKeepaliveKey: "25",
  234. wireGuardIPAnnotationKey: "10.4.0.1/16",
  235. },
  236. labels: map[string]string{
  237. RegionLabelKey: "a",
  238. },
  239. out: &mesh.Node{
  240. Endpoint: wireguard.NewEndpoint(net.ParseIP("1100::10"), 51821),
  241. NoInternalIP: false,
  242. InternalIP: &net.IPNet{IP: net.ParseIP("10.1.0.2"), Mask: net.CIDRMask(32, 32)},
  243. Key: fooKey,
  244. LastSeen: 1000000000,
  245. Leader: true,
  246. Location: "b",
  247. PersistentKeepalive: 25 * time.Second,
  248. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0"), Mask: net.CIDRMask(24, 32)},
  249. WireGuardIP: &net.IPNet{IP: net.ParseIP("10.4.0.1"), Mask: net.CIDRMask(16, 32)},
  250. },
  251. subnet: "10.2.1.0/24",
  252. },
  253. {
  254. name: "no InternalIP",
  255. annotations: map[string]string{
  256. endpointAnnotationKey: "10.0.0.1:51820",
  257. internalIPAnnotationKey: "",
  258. keyAnnotationKey: fooKey.String(),
  259. lastSeenAnnotationKey: "1000000000",
  260. locationAnnotationKey: "b",
  261. persistentKeepaliveKey: "25",
  262. wireGuardIPAnnotationKey: "10.4.0.1/16",
  263. },
  264. labels: map[string]string{
  265. RegionLabelKey: "a",
  266. },
  267. out: &mesh.Node{
  268. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.1"), 51820),
  269. InternalIP: nil,
  270. Key: fooKey,
  271. LastSeen: 1000000000,
  272. Leader: false,
  273. Location: "b",
  274. PersistentKeepalive: 25 * time.Second,
  275. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0"), Mask: net.CIDRMask(24, 32)},
  276. WireGuardIP: &net.IPNet{IP: net.ParseIP("10.4.0.1"), Mask: net.CIDRMask(16, 32)},
  277. },
  278. subnet: "10.2.1.0/24",
  279. },
  280. {
  281. name: "Force no internal IP",
  282. annotations: map[string]string{
  283. endpointAnnotationKey: "10.0.0.1:51820",
  284. internalIPAnnotationKey: "10.1.0.1/32",
  285. forceInternalIPAnnotationKey: "",
  286. keyAnnotationKey: fooKey.String(),
  287. lastSeenAnnotationKey: "1000000000",
  288. locationAnnotationKey: "b",
  289. persistentKeepaliveKey: "25",
  290. wireGuardIPAnnotationKey: "10.4.0.1/16",
  291. },
  292. labels: map[string]string{
  293. RegionLabelKey: "a",
  294. },
  295. out: &mesh.Node{
  296. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.1"), 51820),
  297. NoInternalIP: true,
  298. InternalIP: nil,
  299. Key: fooKey,
  300. LastSeen: 1000000000,
  301. Leader: false,
  302. Location: "b",
  303. PersistentKeepalive: 25 * time.Second,
  304. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0"), Mask: net.CIDRMask(24, 32)},
  305. WireGuardIP: &net.IPNet{IP: net.ParseIP("10.4.0.1"), Mask: net.CIDRMask(16, 32)},
  306. },
  307. subnet: "10.2.1.0/24",
  308. },
  309. } {
  310. n := &v1.Node{}
  311. n.Annotations = tc.annotations
  312. n.Labels = tc.labels
  313. n.Spec.PodCIDR = tc.subnet
  314. node := translateNode(n, RegionLabelKey)
  315. if diff := pretty.Compare(node, tc.out); diff != "" {
  316. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  317. }
  318. }
  319. }
  320. func TestTranslatePeer(t *testing.T) {
  321. for _, tc := range []struct {
  322. name string
  323. out *mesh.Peer
  324. spec v1alpha1.PeerSpec
  325. }{
  326. {
  327. name: "empty",
  328. out: &mesh.Peer{
  329. Peer: wireguard.Peer{
  330. PeerConfig: wgtypes.PeerConfig{
  331. PersistentKeepaliveInterval: &zero,
  332. },
  333. },
  334. },
  335. },
  336. {
  337. name: "invalid ips",
  338. spec: v1alpha1.PeerSpec{
  339. AllowedIPs: []string{
  340. "10.0.0.1",
  341. "foo",
  342. },
  343. },
  344. out: &mesh.Peer{
  345. Peer: wireguard.Peer{
  346. PeerConfig: wgtypes.PeerConfig{
  347. PersistentKeepaliveInterval: &zero,
  348. },
  349. },
  350. },
  351. },
  352. {
  353. name: "valid ips",
  354. spec: v1alpha1.PeerSpec{
  355. AllowedIPs: []string{
  356. "10.0.0.1/24",
  357. "10.0.0.2/32",
  358. },
  359. },
  360. out: &mesh.Peer{
  361. Peer: wireguard.Peer{
  362. PeerConfig: wgtypes.PeerConfig{
  363. AllowedIPs: []net.IPNet{
  364. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  365. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(32, 32)},
  366. },
  367. PersistentKeepaliveInterval: &zero,
  368. },
  369. },
  370. },
  371. },
  372. {
  373. name: "invalid endpoint ip",
  374. spec: v1alpha1.PeerSpec{
  375. Endpoint: &v1alpha1.PeerEndpoint{
  376. DNSOrIP: v1alpha1.DNSOrIP{
  377. IP: "foo",
  378. },
  379. Port: mesh.DefaultKiloPort,
  380. },
  381. },
  382. out: &mesh.Peer{
  383. Peer: wireguard.Peer{
  384. PeerConfig: wgtypes.PeerConfig{
  385. PersistentKeepaliveInterval: &zero,
  386. },
  387. },
  388. },
  389. },
  390. {
  391. name: "only endpoint port",
  392. spec: v1alpha1.PeerSpec{
  393. Endpoint: &v1alpha1.PeerEndpoint{
  394. Port: mesh.DefaultKiloPort,
  395. },
  396. },
  397. out: &mesh.Peer{
  398. Peer: wireguard.Peer{
  399. PeerConfig: wgtypes.PeerConfig{
  400. PersistentKeepaliveInterval: &zero,
  401. },
  402. },
  403. },
  404. },
  405. {
  406. name: "valid endpoint ip",
  407. spec: v1alpha1.PeerSpec{
  408. Endpoint: &v1alpha1.PeerEndpoint{
  409. DNSOrIP: v1alpha1.DNSOrIP{
  410. IP: "10.0.0.1",
  411. },
  412. Port: mesh.DefaultKiloPort,
  413. },
  414. },
  415. out: &mesh.Peer{
  416. Peer: wireguard.Peer{
  417. PeerConfig: wgtypes.PeerConfig{
  418. PersistentKeepaliveInterval: &zero,
  419. },
  420. Endpoint: wireguard.NewEndpoint(net.ParseIP("10.0.0.1").To4(), mesh.DefaultKiloPort),
  421. },
  422. },
  423. },
  424. {
  425. name: "valid endpoint ipv6",
  426. spec: v1alpha1.PeerSpec{
  427. Endpoint: &v1alpha1.PeerEndpoint{
  428. DNSOrIP: v1alpha1.DNSOrIP{
  429. IP: "ff60::2",
  430. },
  431. Port: mesh.DefaultKiloPort,
  432. },
  433. },
  434. out: &mesh.Peer{
  435. Peer: wireguard.Peer{
  436. PeerConfig: wgtypes.PeerConfig{
  437. PersistentKeepaliveInterval: &zero,
  438. },
  439. Endpoint: wireguard.NewEndpoint(net.ParseIP("ff60::2").To16(), mesh.DefaultKiloPort),
  440. },
  441. },
  442. },
  443. {
  444. name: "valid endpoint DNS",
  445. spec: v1alpha1.PeerSpec{
  446. Endpoint: &v1alpha1.PeerEndpoint{
  447. DNSOrIP: v1alpha1.DNSOrIP{
  448. DNS: "example.com",
  449. },
  450. Port: mesh.DefaultKiloPort,
  451. },
  452. },
  453. out: &mesh.Peer{
  454. Peer: wireguard.Peer{
  455. Endpoint: wireguard.ParseEndpoint("example.com:51820"),
  456. PeerConfig: wgtypes.PeerConfig{
  457. PersistentKeepaliveInterval: &zero,
  458. },
  459. },
  460. },
  461. },
  462. {
  463. name: "empty key",
  464. spec: v1alpha1.PeerSpec{
  465. PublicKey: "",
  466. },
  467. out: &mesh.Peer{
  468. Peer: wireguard.Peer{
  469. PeerConfig: wgtypes.PeerConfig{
  470. PersistentKeepaliveInterval: &zero,
  471. },
  472. },
  473. },
  474. },
  475. {
  476. name: "valid key",
  477. spec: v1alpha1.PeerSpec{
  478. PublicKey: fooKey.String(),
  479. },
  480. out: &mesh.Peer{
  481. Peer: wireguard.Peer{
  482. PeerConfig: wgtypes.PeerConfig{
  483. PublicKey: fooKey,
  484. PersistentKeepaliveInterval: &zero,
  485. },
  486. },
  487. },
  488. },
  489. {
  490. name: "invalid keepalive",
  491. spec: v1alpha1.PeerSpec{
  492. PersistentKeepalive: -1,
  493. },
  494. out: &mesh.Peer{
  495. Peer: wireguard.Peer{
  496. PeerConfig: wgtypes.PeerConfig{
  497. PersistentKeepaliveInterval: &zero,
  498. },
  499. },
  500. },
  501. },
  502. {
  503. name: "valid keepalive",
  504. spec: v1alpha1.PeerSpec{
  505. PersistentKeepalive: 1,
  506. },
  507. out: &mesh.Peer{
  508. Peer: wireguard.Peer{
  509. PeerConfig: wgtypes.PeerConfig{
  510. PersistentKeepaliveInterval: &second,
  511. },
  512. },
  513. },
  514. },
  515. {
  516. name: "valid preshared key",
  517. spec: v1alpha1.PeerSpec{
  518. PresharedKey: pskKey.String(),
  519. },
  520. out: &mesh.Peer{
  521. Peer: wireguard.Peer{
  522. PeerConfig: wgtypes.PeerConfig{
  523. PersistentKeepaliveInterval: &zero,
  524. PresharedKey: pskKey,
  525. },
  526. },
  527. },
  528. },
  529. } {
  530. p := &v1alpha1.Peer{}
  531. p.Spec = tc.spec
  532. peer := translatePeer(p)
  533. if diff := pretty.Compare(peer, tc.out); diff != "" {
  534. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  535. }
  536. }
  537. }