validation_test.go 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package validation
  14. import (
  15. "fmt"
  16. "strings"
  17. "testing"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. "k8s.io/apimachinery/pkg/util/intstr"
  20. utilfeature "k8s.io/apiserver/pkg/util/feature"
  21. featuregatetesting "k8s.io/component-base/featuregate/testing"
  22. api "k8s.io/kubernetes/pkg/apis/core"
  23. "k8s.io/kubernetes/pkg/apis/networking"
  24. "k8s.io/kubernetes/pkg/features"
  25. )
  26. func TestValidateNetworkPolicy(t *testing.T) {
  27. protocolTCP := api.ProtocolTCP
  28. protocolUDP := api.ProtocolUDP
  29. protocolICMP := api.Protocol("ICMP")
  30. protocolSCTP := api.ProtocolSCTP
  31. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SCTPSupport, true)()
  32. successCases := []networking.NetworkPolicy{
  33. {
  34. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  35. Spec: networking.NetworkPolicySpec{
  36. PodSelector: metav1.LabelSelector{
  37. MatchLabels: map[string]string{"a": "b"},
  38. },
  39. Ingress: []networking.NetworkPolicyIngressRule{},
  40. },
  41. },
  42. {
  43. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  44. Spec: networking.NetworkPolicySpec{
  45. PodSelector: metav1.LabelSelector{
  46. MatchLabels: map[string]string{"a": "b"},
  47. },
  48. Ingress: []networking.NetworkPolicyIngressRule{
  49. {
  50. From: []networking.NetworkPolicyPeer{},
  51. Ports: []networking.NetworkPolicyPort{},
  52. },
  53. },
  54. },
  55. },
  56. {
  57. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  58. Spec: networking.NetworkPolicySpec{
  59. PodSelector: metav1.LabelSelector{
  60. MatchLabels: map[string]string{"a": "b"},
  61. },
  62. Ingress: []networking.NetworkPolicyIngressRule{
  63. {
  64. Ports: []networking.NetworkPolicyPort{
  65. {
  66. Protocol: nil,
  67. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  68. },
  69. {
  70. Protocol: &protocolTCP,
  71. Port: nil,
  72. },
  73. {
  74. Protocol: &protocolTCP,
  75. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 443},
  76. },
  77. {
  78. Protocol: &protocolUDP,
  79. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
  80. },
  81. {
  82. Protocol: &protocolSCTP,
  83. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 7777},
  84. },
  85. },
  86. },
  87. },
  88. },
  89. },
  90. {
  91. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  92. Spec: networking.NetworkPolicySpec{
  93. PodSelector: metav1.LabelSelector{
  94. MatchLabels: map[string]string{"a": "b"},
  95. },
  96. Ingress: []networking.NetworkPolicyIngressRule{
  97. {
  98. From: []networking.NetworkPolicyPeer{
  99. {
  100. PodSelector: &metav1.LabelSelector{
  101. MatchLabels: map[string]string{"c": "d"},
  102. },
  103. },
  104. },
  105. },
  106. },
  107. },
  108. },
  109. {
  110. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  111. Spec: networking.NetworkPolicySpec{
  112. PodSelector: metav1.LabelSelector{
  113. MatchLabels: map[string]string{"a": "b"},
  114. },
  115. Ingress: []networking.NetworkPolicyIngressRule{
  116. {
  117. From: []networking.NetworkPolicyPeer{
  118. {
  119. NamespaceSelector: &metav1.LabelSelector{
  120. MatchLabels: map[string]string{"c": "d"},
  121. },
  122. },
  123. },
  124. },
  125. },
  126. },
  127. },
  128. {
  129. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  130. Spec: networking.NetworkPolicySpec{
  131. PodSelector: metav1.LabelSelector{
  132. MatchLabels: map[string]string{"a": "b"},
  133. },
  134. Ingress: []networking.NetworkPolicyIngressRule{
  135. {
  136. From: []networking.NetworkPolicyPeer{
  137. {
  138. NamespaceSelector: &metav1.LabelSelector{
  139. MatchLabels: map[string]string{"c": "d"},
  140. },
  141. PodSelector: &metav1.LabelSelector{
  142. MatchLabels: map[string]string{"e": "f"},
  143. },
  144. },
  145. },
  146. },
  147. },
  148. },
  149. },
  150. {
  151. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  152. Spec: networking.NetworkPolicySpec{
  153. PodSelector: metav1.LabelSelector{
  154. MatchLabels: map[string]string{"a": "b"},
  155. },
  156. Egress: []networking.NetworkPolicyEgressRule{
  157. {
  158. To: []networking.NetworkPolicyPeer{
  159. {
  160. NamespaceSelector: &metav1.LabelSelector{
  161. MatchLabels: map[string]string{"c": "d"},
  162. },
  163. },
  164. },
  165. },
  166. },
  167. Ingress: []networking.NetworkPolicyIngressRule{
  168. {
  169. From: []networking.NetworkPolicyPeer{
  170. {
  171. IPBlock: &networking.IPBlock{
  172. CIDR: "192.168.0.0/16",
  173. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  174. },
  175. },
  176. },
  177. },
  178. },
  179. },
  180. },
  181. {
  182. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  183. Spec: networking.NetworkPolicySpec{
  184. PodSelector: metav1.LabelSelector{
  185. MatchLabels: map[string]string{"a": "b"},
  186. },
  187. Ingress: []networking.NetworkPolicyIngressRule{
  188. {
  189. From: []networking.NetworkPolicyPeer{
  190. {
  191. IPBlock: &networking.IPBlock{
  192. CIDR: "192.168.0.0/16",
  193. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  194. },
  195. },
  196. },
  197. },
  198. },
  199. },
  200. },
  201. {
  202. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  203. Spec: networking.NetworkPolicySpec{
  204. PodSelector: metav1.LabelSelector{
  205. MatchLabels: map[string]string{"a": "b"},
  206. },
  207. Egress: []networking.NetworkPolicyEgressRule{
  208. {
  209. To: []networking.NetworkPolicyPeer{
  210. {
  211. IPBlock: &networking.IPBlock{
  212. CIDR: "192.168.0.0/16",
  213. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  214. },
  215. },
  216. },
  217. },
  218. },
  219. PolicyTypes: []networking.PolicyType{networking.PolicyTypeEgress},
  220. },
  221. },
  222. {
  223. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  224. Spec: networking.NetworkPolicySpec{
  225. PodSelector: metav1.LabelSelector{
  226. MatchLabels: map[string]string{"a": "b"},
  227. },
  228. Egress: []networking.NetworkPolicyEgressRule{
  229. {
  230. To: []networking.NetworkPolicyPeer{
  231. {
  232. IPBlock: &networking.IPBlock{
  233. CIDR: "192.168.0.0/16",
  234. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  235. },
  236. },
  237. },
  238. },
  239. },
  240. PolicyTypes: []networking.PolicyType{networking.PolicyTypeIngress, networking.PolicyTypeEgress},
  241. },
  242. },
  243. {
  244. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  245. Spec: networking.NetworkPolicySpec{
  246. PodSelector: metav1.LabelSelector{
  247. MatchLabels: map[string]string{"a": "b"},
  248. },
  249. Egress: []networking.NetworkPolicyEgressRule{
  250. {
  251. Ports: []networking.NetworkPolicyPort{
  252. {
  253. Protocol: nil,
  254. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  255. },
  256. {
  257. Protocol: &protocolTCP,
  258. Port: nil,
  259. },
  260. {
  261. Protocol: &protocolTCP,
  262. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 443},
  263. },
  264. {
  265. Protocol: &protocolUDP,
  266. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
  267. },
  268. {
  269. Protocol: &protocolSCTP,
  270. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 7777},
  271. },
  272. },
  273. },
  274. },
  275. },
  276. },
  277. }
  278. // Success cases are expected to pass validation.
  279. for k, v := range successCases {
  280. if errs := ValidateNetworkPolicy(&v); len(errs) != 0 {
  281. t.Errorf("Expected success for %d, got %v", k, errs)
  282. }
  283. }
  284. invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
  285. errorCases := map[string]networking.NetworkPolicy{
  286. "namespaceSelector and ipBlock": {
  287. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  288. Spec: networking.NetworkPolicySpec{
  289. PodSelector: metav1.LabelSelector{
  290. MatchLabels: map[string]string{"a": "b"},
  291. },
  292. Ingress: []networking.NetworkPolicyIngressRule{
  293. {
  294. From: []networking.NetworkPolicyPeer{
  295. {
  296. NamespaceSelector: &metav1.LabelSelector{
  297. MatchLabels: map[string]string{"c": "d"},
  298. },
  299. IPBlock: &networking.IPBlock{
  300. CIDR: "192.168.0.0/16",
  301. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  302. },
  303. },
  304. },
  305. },
  306. },
  307. },
  308. },
  309. "podSelector and ipBlock": {
  310. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  311. Spec: networking.NetworkPolicySpec{
  312. PodSelector: metav1.LabelSelector{
  313. MatchLabels: map[string]string{"a": "b"},
  314. },
  315. Egress: []networking.NetworkPolicyEgressRule{
  316. {
  317. To: []networking.NetworkPolicyPeer{
  318. {
  319. PodSelector: &metav1.LabelSelector{
  320. MatchLabels: map[string]string{"c": "d"},
  321. },
  322. IPBlock: &networking.IPBlock{
  323. CIDR: "192.168.0.0/16",
  324. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  325. },
  326. },
  327. },
  328. },
  329. },
  330. },
  331. },
  332. "missing from and to type": {
  333. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  334. Spec: networking.NetworkPolicySpec{
  335. PodSelector: metav1.LabelSelector{
  336. MatchLabels: map[string]string{"a": "b"},
  337. },
  338. Ingress: []networking.NetworkPolicyIngressRule{
  339. {
  340. From: []networking.NetworkPolicyPeer{{}},
  341. },
  342. },
  343. Egress: []networking.NetworkPolicyEgressRule{
  344. {
  345. To: []networking.NetworkPolicyPeer{{}},
  346. },
  347. },
  348. },
  349. },
  350. "invalid spec.podSelector": {
  351. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  352. Spec: networking.NetworkPolicySpec{
  353. PodSelector: metav1.LabelSelector{
  354. MatchLabels: invalidSelector,
  355. },
  356. Ingress: []networking.NetworkPolicyIngressRule{
  357. {
  358. From: []networking.NetworkPolicyPeer{
  359. {
  360. NamespaceSelector: &metav1.LabelSelector{
  361. MatchLabels: map[string]string{"c": "d"},
  362. },
  363. },
  364. },
  365. },
  366. },
  367. },
  368. },
  369. "invalid ingress.ports.protocol": {
  370. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  371. Spec: networking.NetworkPolicySpec{
  372. PodSelector: metav1.LabelSelector{},
  373. Ingress: []networking.NetworkPolicyIngressRule{
  374. {
  375. Ports: []networking.NetworkPolicyPort{
  376. {
  377. Protocol: &protocolICMP,
  378. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  379. },
  380. },
  381. },
  382. },
  383. },
  384. },
  385. "invalid ingress.ports.port (int)": {
  386. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  387. Spec: networking.NetworkPolicySpec{
  388. PodSelector: metav1.LabelSelector{},
  389. Ingress: []networking.NetworkPolicyIngressRule{
  390. {
  391. Ports: []networking.NetworkPolicyPort{
  392. {
  393. Protocol: &protocolTCP,
  394. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 123456789},
  395. },
  396. },
  397. },
  398. },
  399. },
  400. },
  401. "invalid ingress.ports.port (str)": {
  402. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  403. Spec: networking.NetworkPolicySpec{
  404. PodSelector: metav1.LabelSelector{},
  405. Ingress: []networking.NetworkPolicyIngressRule{
  406. {
  407. Ports: []networking.NetworkPolicyPort{
  408. {
  409. Protocol: &protocolTCP,
  410. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "!@#$"},
  411. },
  412. },
  413. },
  414. },
  415. },
  416. },
  417. "invalid ingress.from.podSelector": {
  418. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  419. Spec: networking.NetworkPolicySpec{
  420. PodSelector: metav1.LabelSelector{},
  421. Ingress: []networking.NetworkPolicyIngressRule{
  422. {
  423. From: []networking.NetworkPolicyPeer{
  424. {
  425. PodSelector: &metav1.LabelSelector{
  426. MatchLabels: invalidSelector,
  427. },
  428. },
  429. },
  430. },
  431. },
  432. },
  433. },
  434. "invalid egress.to.podSelector": {
  435. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  436. Spec: networking.NetworkPolicySpec{
  437. PodSelector: metav1.LabelSelector{},
  438. Egress: []networking.NetworkPolicyEgressRule{
  439. {
  440. To: []networking.NetworkPolicyPeer{
  441. {
  442. PodSelector: &metav1.LabelSelector{
  443. MatchLabels: invalidSelector,
  444. },
  445. },
  446. },
  447. },
  448. },
  449. },
  450. },
  451. "invalid egress.ports.protocol": {
  452. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  453. Spec: networking.NetworkPolicySpec{
  454. PodSelector: metav1.LabelSelector{},
  455. Egress: []networking.NetworkPolicyEgressRule{
  456. {
  457. Ports: []networking.NetworkPolicyPort{
  458. {
  459. Protocol: &protocolICMP,
  460. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  461. },
  462. },
  463. },
  464. },
  465. },
  466. },
  467. "invalid egress.ports.port (int)": {
  468. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  469. Spec: networking.NetworkPolicySpec{
  470. PodSelector: metav1.LabelSelector{},
  471. Egress: []networking.NetworkPolicyEgressRule{
  472. {
  473. Ports: []networking.NetworkPolicyPort{
  474. {
  475. Protocol: &protocolTCP,
  476. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 123456789},
  477. },
  478. },
  479. },
  480. },
  481. },
  482. },
  483. "invalid egress.ports.port (str)": {
  484. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  485. Spec: networking.NetworkPolicySpec{
  486. PodSelector: metav1.LabelSelector{},
  487. Egress: []networking.NetworkPolicyEgressRule{
  488. {
  489. Ports: []networking.NetworkPolicyPort{
  490. {
  491. Protocol: &protocolTCP,
  492. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "!@#$"},
  493. },
  494. },
  495. },
  496. },
  497. },
  498. },
  499. "invalid ingress.from.namespaceSelector": {
  500. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  501. Spec: networking.NetworkPolicySpec{
  502. PodSelector: metav1.LabelSelector{},
  503. Ingress: []networking.NetworkPolicyIngressRule{
  504. {
  505. From: []networking.NetworkPolicyPeer{
  506. {
  507. NamespaceSelector: &metav1.LabelSelector{
  508. MatchLabels: invalidSelector,
  509. },
  510. },
  511. },
  512. },
  513. },
  514. },
  515. },
  516. "missing cidr field": {
  517. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  518. Spec: networking.NetworkPolicySpec{
  519. PodSelector: metav1.LabelSelector{},
  520. Ingress: []networking.NetworkPolicyIngressRule{
  521. {
  522. From: []networking.NetworkPolicyPeer{
  523. {
  524. IPBlock: &networking.IPBlock{
  525. Except: []string{"192.168.8.0/24", "192.168.9.0/24"},
  526. },
  527. },
  528. },
  529. },
  530. },
  531. },
  532. },
  533. "invalid cidr format": {
  534. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  535. Spec: networking.NetworkPolicySpec{
  536. PodSelector: metav1.LabelSelector{
  537. MatchLabels: map[string]string{"a": "b"},
  538. },
  539. Ingress: []networking.NetworkPolicyIngressRule{
  540. {
  541. From: []networking.NetworkPolicyPeer{
  542. {
  543. IPBlock: &networking.IPBlock{
  544. CIDR: "192.168.5.6",
  545. Except: []string{"192.168.1.0/24", "192.168.2.0/24"},
  546. },
  547. },
  548. },
  549. },
  550. },
  551. },
  552. },
  553. "except field is an empty string": {
  554. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  555. Spec: networking.NetworkPolicySpec{
  556. PodSelector: metav1.LabelSelector{
  557. MatchLabels: map[string]string{"a": "b"},
  558. },
  559. Ingress: []networking.NetworkPolicyIngressRule{
  560. {
  561. From: []networking.NetworkPolicyPeer{
  562. {
  563. IPBlock: &networking.IPBlock{
  564. CIDR: "192.168.8.0/24",
  565. Except: []string{"", " "},
  566. },
  567. },
  568. },
  569. },
  570. },
  571. },
  572. },
  573. "except IP is outside of CIDR range": {
  574. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  575. Spec: networking.NetworkPolicySpec{
  576. PodSelector: metav1.LabelSelector{
  577. MatchLabels: map[string]string{"a": "b"},
  578. },
  579. Ingress: []networking.NetworkPolicyIngressRule{
  580. {
  581. From: []networking.NetworkPolicyPeer{
  582. {
  583. IPBlock: &networking.IPBlock{
  584. CIDR: "192.168.8.0/24",
  585. Except: []string{"192.168.9.1/24"},
  586. },
  587. },
  588. },
  589. },
  590. },
  591. },
  592. },
  593. "invalid policyTypes": {
  594. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  595. Spec: networking.NetworkPolicySpec{
  596. PodSelector: metav1.LabelSelector{
  597. MatchLabels: map[string]string{"a": "b"},
  598. },
  599. Egress: []networking.NetworkPolicyEgressRule{
  600. {
  601. To: []networking.NetworkPolicyPeer{
  602. {
  603. IPBlock: &networking.IPBlock{
  604. CIDR: "192.168.0.0/16",
  605. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  606. },
  607. },
  608. },
  609. },
  610. },
  611. PolicyTypes: []networking.PolicyType{"foo", "bar"},
  612. },
  613. },
  614. "too many policyTypes": {
  615. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  616. Spec: networking.NetworkPolicySpec{
  617. PodSelector: metav1.LabelSelector{
  618. MatchLabels: map[string]string{"a": "b"},
  619. },
  620. Egress: []networking.NetworkPolicyEgressRule{
  621. {
  622. To: []networking.NetworkPolicyPeer{
  623. {
  624. IPBlock: &networking.IPBlock{
  625. CIDR: "192.168.0.0/16",
  626. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  627. },
  628. },
  629. },
  630. },
  631. },
  632. PolicyTypes: []networking.PolicyType{"foo", "bar", "baz"},
  633. },
  634. },
  635. }
  636. // Error cases are not expected to pass validation.
  637. for testName, networkPolicy := range errorCases {
  638. if errs := ValidateNetworkPolicy(&networkPolicy); len(errs) == 0 {
  639. t.Errorf("Expected failure for test: %s", testName)
  640. }
  641. }
  642. }
  643. func TestValidateNetworkPolicyUpdate(t *testing.T) {
  644. type npUpdateTest struct {
  645. old networking.NetworkPolicy
  646. update networking.NetworkPolicy
  647. }
  648. successCases := map[string]npUpdateTest{
  649. "no change": {
  650. old: networking.NetworkPolicy{
  651. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  652. Spec: networking.NetworkPolicySpec{
  653. PodSelector: metav1.LabelSelector{
  654. MatchLabels: map[string]string{"a": "b"},
  655. },
  656. Ingress: []networking.NetworkPolicyIngressRule{},
  657. },
  658. },
  659. update: networking.NetworkPolicy{
  660. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  661. Spec: networking.NetworkPolicySpec{
  662. PodSelector: metav1.LabelSelector{
  663. MatchLabels: map[string]string{"a": "b"},
  664. },
  665. Ingress: []networking.NetworkPolicyIngressRule{},
  666. },
  667. },
  668. },
  669. "change spec": {
  670. old: networking.NetworkPolicy{
  671. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  672. Spec: networking.NetworkPolicySpec{
  673. PodSelector: metav1.LabelSelector{},
  674. Ingress: []networking.NetworkPolicyIngressRule{},
  675. },
  676. },
  677. update: networking.NetworkPolicy{
  678. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  679. Spec: networking.NetworkPolicySpec{
  680. PodSelector: metav1.LabelSelector{
  681. MatchLabels: map[string]string{"a": "b"},
  682. },
  683. Ingress: []networking.NetworkPolicyIngressRule{},
  684. },
  685. },
  686. },
  687. }
  688. for testName, successCase := range successCases {
  689. successCase.old.ObjectMeta.ResourceVersion = "1"
  690. successCase.update.ObjectMeta.ResourceVersion = "1"
  691. if errs := ValidateNetworkPolicyUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
  692. t.Errorf("expected success (%s): %v", testName, errs)
  693. }
  694. }
  695. errorCases := map[string]npUpdateTest{
  696. "change name": {
  697. old: networking.NetworkPolicy{
  698. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  699. Spec: networking.NetworkPolicySpec{
  700. PodSelector: metav1.LabelSelector{},
  701. Ingress: []networking.NetworkPolicyIngressRule{},
  702. },
  703. },
  704. update: networking.NetworkPolicy{
  705. ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "bar"},
  706. Spec: networking.NetworkPolicySpec{
  707. PodSelector: metav1.LabelSelector{},
  708. Ingress: []networking.NetworkPolicyIngressRule{},
  709. },
  710. },
  711. },
  712. }
  713. for testName, errorCase := range errorCases {
  714. errorCase.old.ObjectMeta.ResourceVersion = "1"
  715. errorCase.update.ObjectMeta.ResourceVersion = "1"
  716. if errs := ValidateNetworkPolicyUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
  717. t.Errorf("expected failure: %s", testName)
  718. }
  719. }
  720. }
  721. func TestValidateIngress(t *testing.T) {
  722. defaultBackend := networking.IngressBackend{
  723. ServiceName: "default-backend",
  724. ServicePort: intstr.FromInt(80),
  725. }
  726. newValid := func() networking.Ingress {
  727. return networking.Ingress{
  728. ObjectMeta: metav1.ObjectMeta{
  729. Name: "foo",
  730. Namespace: metav1.NamespaceDefault,
  731. },
  732. Spec: networking.IngressSpec{
  733. Backend: &networking.IngressBackend{
  734. ServiceName: "default-backend",
  735. ServicePort: intstr.FromInt(80),
  736. },
  737. Rules: []networking.IngressRule{
  738. {
  739. Host: "foo.bar.com",
  740. IngressRuleValue: networking.IngressRuleValue{
  741. HTTP: &networking.HTTPIngressRuleValue{
  742. Paths: []networking.HTTPIngressPath{
  743. {
  744. Path: "/foo",
  745. Backend: defaultBackend,
  746. },
  747. },
  748. },
  749. },
  750. },
  751. },
  752. },
  753. Status: networking.IngressStatus{
  754. LoadBalancer: api.LoadBalancerStatus{
  755. Ingress: []api.LoadBalancerIngress{
  756. {IP: "127.0.0.1"},
  757. },
  758. },
  759. },
  760. }
  761. }
  762. servicelessBackend := newValid()
  763. servicelessBackend.Spec.Backend.ServiceName = ""
  764. invalidNameBackend := newValid()
  765. invalidNameBackend.Spec.Backend.ServiceName = "defaultBackend"
  766. noPortBackend := newValid()
  767. noPortBackend.Spec.Backend = &networking.IngressBackend{ServiceName: defaultBackend.ServiceName}
  768. noForwardSlashPath := newValid()
  769. noForwardSlashPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{
  770. {
  771. Path: "invalid",
  772. Backend: defaultBackend,
  773. },
  774. }
  775. noPaths := newValid()
  776. noPaths.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{}
  777. badHost := newValid()
  778. badHost.Spec.Rules[0].Host = "foobar:80"
  779. badRegexPath := newValid()
  780. badPathExpr := "/invalid["
  781. badRegexPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{
  782. {
  783. Path: badPathExpr,
  784. Backend: defaultBackend,
  785. },
  786. }
  787. badPathErr := fmt.Sprintf("spec.rules[0].http.paths[0].path: Invalid value: '%v'", badPathExpr)
  788. hostIP := "127.0.0.1"
  789. badHostIP := newValid()
  790. badHostIP.Spec.Rules[0].Host = hostIP
  791. badHostIPErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", hostIP)
  792. errorCases := map[string]networking.Ingress{
  793. "spec.backend.serviceName: Required value": servicelessBackend,
  794. "spec.backend.serviceName: Invalid value": invalidNameBackend,
  795. "spec.backend.servicePort: Invalid value": noPortBackend,
  796. "spec.rules[0].host: Invalid value": badHost,
  797. "spec.rules[0].http.paths: Required value": noPaths,
  798. "spec.rules[0].http.paths[0].path: Invalid value": noForwardSlashPath,
  799. }
  800. errorCases[badPathErr] = badRegexPath
  801. errorCases[badHostIPErr] = badHostIP
  802. wildcardHost := "foo.*.bar.com"
  803. badWildcard := newValid()
  804. badWildcard.Spec.Rules[0].Host = wildcardHost
  805. badWildcardErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", wildcardHost)
  806. errorCases[badWildcardErr] = badWildcard
  807. for k, v := range errorCases {
  808. errs := ValidateIngress(&v)
  809. if len(errs) == 0 {
  810. t.Errorf("expected failure for %q", k)
  811. } else {
  812. s := strings.Split(k, ":")
  813. err := errs[0]
  814. if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
  815. t.Errorf("unexpected error: %q, expected: %q", err, k)
  816. }
  817. }
  818. }
  819. }
  820. func TestValidateIngressTLS(t *testing.T) {
  821. defaultBackend := networking.IngressBackend{
  822. ServiceName: "default-backend",
  823. ServicePort: intstr.FromInt(80),
  824. }
  825. newValid := func() networking.Ingress {
  826. return networking.Ingress{
  827. ObjectMeta: metav1.ObjectMeta{
  828. Name: "foo",
  829. Namespace: metav1.NamespaceDefault,
  830. },
  831. Spec: networking.IngressSpec{
  832. Backend: &networking.IngressBackend{
  833. ServiceName: "default-backend",
  834. ServicePort: intstr.FromInt(80),
  835. },
  836. Rules: []networking.IngressRule{
  837. {
  838. Host: "foo.bar.com",
  839. IngressRuleValue: networking.IngressRuleValue{
  840. HTTP: &networking.HTTPIngressRuleValue{
  841. Paths: []networking.HTTPIngressPath{
  842. {
  843. Path: "/foo",
  844. Backend: defaultBackend,
  845. },
  846. },
  847. },
  848. },
  849. },
  850. },
  851. },
  852. Status: networking.IngressStatus{
  853. LoadBalancer: api.LoadBalancerStatus{
  854. Ingress: []api.LoadBalancerIngress{
  855. {IP: "127.0.0.1"},
  856. },
  857. },
  858. },
  859. }
  860. }
  861. errorCases := map[string]networking.Ingress{}
  862. wildcardHost := "foo.*.bar.com"
  863. badWildcardTLS := newValid()
  864. badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
  865. badWildcardTLS.Spec.TLS = []networking.IngressTLS{
  866. {
  867. Hosts: []string{wildcardHost},
  868. },
  869. }
  870. badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts: Invalid value: '%v'", wildcardHost)
  871. errorCases[badWildcardTLSErr] = badWildcardTLS
  872. for k, v := range errorCases {
  873. errs := ValidateIngress(&v)
  874. if len(errs) == 0 {
  875. t.Errorf("expected failure for %q", k)
  876. } else {
  877. s := strings.Split(k, ":")
  878. err := errs[0]
  879. if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
  880. t.Errorf("unexpected error: %q, expected: %q", err, k)
  881. }
  882. }
  883. }
  884. }
  885. func TestValidateIngressStatusUpdate(t *testing.T) {
  886. defaultBackend := networking.IngressBackend{
  887. ServiceName: "default-backend",
  888. ServicePort: intstr.FromInt(80),
  889. }
  890. newValid := func() networking.Ingress {
  891. return networking.Ingress{
  892. ObjectMeta: metav1.ObjectMeta{
  893. Name: "foo",
  894. Namespace: metav1.NamespaceDefault,
  895. ResourceVersion: "9",
  896. },
  897. Spec: networking.IngressSpec{
  898. Backend: &networking.IngressBackend{
  899. ServiceName: "default-backend",
  900. ServicePort: intstr.FromInt(80),
  901. },
  902. Rules: []networking.IngressRule{
  903. {
  904. Host: "foo.bar.com",
  905. IngressRuleValue: networking.IngressRuleValue{
  906. HTTP: &networking.HTTPIngressRuleValue{
  907. Paths: []networking.HTTPIngressPath{
  908. {
  909. Path: "/foo",
  910. Backend: defaultBackend,
  911. },
  912. },
  913. },
  914. },
  915. },
  916. },
  917. },
  918. Status: networking.IngressStatus{
  919. LoadBalancer: api.LoadBalancerStatus{
  920. Ingress: []api.LoadBalancerIngress{
  921. {IP: "127.0.0.1", Hostname: "foo.bar.com"},
  922. },
  923. },
  924. },
  925. }
  926. }
  927. oldValue := newValid()
  928. newValue := newValid()
  929. newValue.Status = networking.IngressStatus{
  930. LoadBalancer: api.LoadBalancerStatus{
  931. Ingress: []api.LoadBalancerIngress{
  932. {IP: "127.0.0.2", Hostname: "foo.com"},
  933. },
  934. },
  935. }
  936. invalidIP := newValid()
  937. invalidIP.Status = networking.IngressStatus{
  938. LoadBalancer: api.LoadBalancerStatus{
  939. Ingress: []api.LoadBalancerIngress{
  940. {IP: "abcd", Hostname: "foo.com"},
  941. },
  942. },
  943. }
  944. invalidHostname := newValid()
  945. invalidHostname.Status = networking.IngressStatus{
  946. LoadBalancer: api.LoadBalancerStatus{
  947. Ingress: []api.LoadBalancerIngress{
  948. {IP: "127.0.0.1", Hostname: "127.0.0.1"},
  949. },
  950. },
  951. }
  952. errs := ValidateIngressStatusUpdate(&newValue, &oldValue)
  953. if len(errs) != 0 {
  954. t.Errorf("Unexpected error %v", errs)
  955. }
  956. errorCases := map[string]networking.Ingress{
  957. "status.loadBalancer.ingress[0].ip: Invalid value": invalidIP,
  958. "status.loadBalancer.ingress[0].hostname: Invalid value": invalidHostname,
  959. }
  960. for k, v := range errorCases {
  961. errs := ValidateIngressStatusUpdate(&v, &oldValue)
  962. if len(errs) == 0 {
  963. t.Errorf("expected failure for %s", k)
  964. } else {
  965. s := strings.Split(k, ":")
  966. err := errs[0]
  967. if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
  968. t.Errorf("unexpected error: %q, expected: %q", err, k)
  969. }
  970. }
  971. }
  972. }