validation_test.go 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  279. Spec: networking.NetworkPolicySpec{
  280. PodSelector: metav1.LabelSelector{
  281. MatchLabels: map[string]string{"a": "b"},
  282. },
  283. Egress: []networking.NetworkPolicyEgressRule{
  284. {
  285. To: []networking.NetworkPolicyPeer{
  286. {
  287. NamespaceSelector: &metav1.LabelSelector{
  288. MatchLabels: map[string]string{"c": "d"},
  289. },
  290. },
  291. },
  292. },
  293. },
  294. Ingress: []networking.NetworkPolicyIngressRule{
  295. {
  296. From: []networking.NetworkPolicyPeer{
  297. {
  298. IPBlock: &networking.IPBlock{
  299. CIDR: "fd00:192:168::/48",
  300. Except: []string{"fd00:192:168:3::/64", "fd00:192:168:4::/64"},
  301. },
  302. },
  303. },
  304. },
  305. },
  306. },
  307. },
  308. {
  309. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  310. Spec: networking.NetworkPolicySpec{
  311. PodSelector: metav1.LabelSelector{
  312. MatchLabels: map[string]string{"a": "b"},
  313. },
  314. Ingress: []networking.NetworkPolicyIngressRule{
  315. {
  316. From: []networking.NetworkPolicyPeer{
  317. {
  318. IPBlock: &networking.IPBlock{
  319. CIDR: "fd00:192:168::/48",
  320. Except: []string{"fd00:192:168:3::/64", "fd00:192:168:4::/64"},
  321. },
  322. },
  323. },
  324. },
  325. },
  326. },
  327. },
  328. {
  329. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  330. Spec: networking.NetworkPolicySpec{
  331. PodSelector: metav1.LabelSelector{
  332. MatchLabels: map[string]string{"a": "b"},
  333. },
  334. Egress: []networking.NetworkPolicyEgressRule{
  335. {
  336. To: []networking.NetworkPolicyPeer{
  337. {
  338. IPBlock: &networking.IPBlock{
  339. CIDR: "fd00:192:168::/48",
  340. Except: []string{"fd00:192:168:3::/64", "fd00:192:168:4::/64"},
  341. },
  342. },
  343. },
  344. },
  345. },
  346. PolicyTypes: []networking.PolicyType{networking.PolicyTypeEgress},
  347. },
  348. },
  349. {
  350. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  351. Spec: networking.NetworkPolicySpec{
  352. PodSelector: metav1.LabelSelector{
  353. MatchLabels: map[string]string{"a": "b"},
  354. },
  355. Egress: []networking.NetworkPolicyEgressRule{
  356. {
  357. To: []networking.NetworkPolicyPeer{
  358. {
  359. IPBlock: &networking.IPBlock{
  360. CIDR: "fd00:192:168::/48",
  361. Except: []string{"fd00:192:168:3::/64", "fd00:192:168:4::/64"},
  362. },
  363. },
  364. },
  365. },
  366. },
  367. PolicyTypes: []networking.PolicyType{networking.PolicyTypeIngress, networking.PolicyTypeEgress},
  368. },
  369. },
  370. }
  371. // Success cases are expected to pass validation.
  372. for k, v := range successCases {
  373. if errs := ValidateNetworkPolicy(&v); len(errs) != 0 {
  374. t.Errorf("Expected success for %d, got %v", k, errs)
  375. }
  376. }
  377. invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
  378. errorCases := map[string]networking.NetworkPolicy{
  379. "namespaceSelector and ipBlock": {
  380. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  381. Spec: networking.NetworkPolicySpec{
  382. PodSelector: metav1.LabelSelector{
  383. MatchLabels: map[string]string{"a": "b"},
  384. },
  385. Ingress: []networking.NetworkPolicyIngressRule{
  386. {
  387. From: []networking.NetworkPolicyPeer{
  388. {
  389. NamespaceSelector: &metav1.LabelSelector{
  390. MatchLabels: map[string]string{"c": "d"},
  391. },
  392. IPBlock: &networking.IPBlock{
  393. CIDR: "192.168.0.0/16",
  394. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  395. },
  396. },
  397. },
  398. },
  399. },
  400. },
  401. },
  402. "podSelector and ipBlock": {
  403. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  404. Spec: networking.NetworkPolicySpec{
  405. PodSelector: metav1.LabelSelector{
  406. MatchLabels: map[string]string{"a": "b"},
  407. },
  408. Egress: []networking.NetworkPolicyEgressRule{
  409. {
  410. To: []networking.NetworkPolicyPeer{
  411. {
  412. PodSelector: &metav1.LabelSelector{
  413. MatchLabels: map[string]string{"c": "d"},
  414. },
  415. IPBlock: &networking.IPBlock{
  416. CIDR: "192.168.0.0/16",
  417. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  418. },
  419. },
  420. },
  421. },
  422. },
  423. },
  424. },
  425. "missing from and to type": {
  426. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  427. Spec: networking.NetworkPolicySpec{
  428. PodSelector: metav1.LabelSelector{
  429. MatchLabels: map[string]string{"a": "b"},
  430. },
  431. Ingress: []networking.NetworkPolicyIngressRule{
  432. {
  433. From: []networking.NetworkPolicyPeer{{}},
  434. },
  435. },
  436. Egress: []networking.NetworkPolicyEgressRule{
  437. {
  438. To: []networking.NetworkPolicyPeer{{}},
  439. },
  440. },
  441. },
  442. },
  443. "invalid spec.podSelector": {
  444. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  445. Spec: networking.NetworkPolicySpec{
  446. PodSelector: metav1.LabelSelector{
  447. MatchLabels: invalidSelector,
  448. },
  449. Ingress: []networking.NetworkPolicyIngressRule{
  450. {
  451. From: []networking.NetworkPolicyPeer{
  452. {
  453. NamespaceSelector: &metav1.LabelSelector{
  454. MatchLabels: map[string]string{"c": "d"},
  455. },
  456. },
  457. },
  458. },
  459. },
  460. },
  461. },
  462. "invalid ingress.ports.protocol": {
  463. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  464. Spec: networking.NetworkPolicySpec{
  465. PodSelector: metav1.LabelSelector{},
  466. Ingress: []networking.NetworkPolicyIngressRule{
  467. {
  468. Ports: []networking.NetworkPolicyPort{
  469. {
  470. Protocol: &protocolICMP,
  471. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  472. },
  473. },
  474. },
  475. },
  476. },
  477. },
  478. "invalid ingress.ports.port (int)": {
  479. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  480. Spec: networking.NetworkPolicySpec{
  481. PodSelector: metav1.LabelSelector{},
  482. Ingress: []networking.NetworkPolicyIngressRule{
  483. {
  484. Ports: []networking.NetworkPolicyPort{
  485. {
  486. Protocol: &protocolTCP,
  487. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 123456789},
  488. },
  489. },
  490. },
  491. },
  492. },
  493. },
  494. "invalid ingress.ports.port (str)": {
  495. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  496. Spec: networking.NetworkPolicySpec{
  497. PodSelector: metav1.LabelSelector{},
  498. Ingress: []networking.NetworkPolicyIngressRule{
  499. {
  500. Ports: []networking.NetworkPolicyPort{
  501. {
  502. Protocol: &protocolTCP,
  503. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "!@#$"},
  504. },
  505. },
  506. },
  507. },
  508. },
  509. },
  510. "invalid ingress.from.podSelector": {
  511. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  512. Spec: networking.NetworkPolicySpec{
  513. PodSelector: metav1.LabelSelector{},
  514. Ingress: []networking.NetworkPolicyIngressRule{
  515. {
  516. From: []networking.NetworkPolicyPeer{
  517. {
  518. PodSelector: &metav1.LabelSelector{
  519. MatchLabels: invalidSelector,
  520. },
  521. },
  522. },
  523. },
  524. },
  525. },
  526. },
  527. "invalid egress.to.podSelector": {
  528. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  529. Spec: networking.NetworkPolicySpec{
  530. PodSelector: metav1.LabelSelector{},
  531. Egress: []networking.NetworkPolicyEgressRule{
  532. {
  533. To: []networking.NetworkPolicyPeer{
  534. {
  535. PodSelector: &metav1.LabelSelector{
  536. MatchLabels: invalidSelector,
  537. },
  538. },
  539. },
  540. },
  541. },
  542. },
  543. },
  544. "invalid egress.ports.protocol": {
  545. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  546. Spec: networking.NetworkPolicySpec{
  547. PodSelector: metav1.LabelSelector{},
  548. Egress: []networking.NetworkPolicyEgressRule{
  549. {
  550. Ports: []networking.NetworkPolicyPort{
  551. {
  552. Protocol: &protocolICMP,
  553. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  554. },
  555. },
  556. },
  557. },
  558. },
  559. },
  560. "invalid egress.ports.port (int)": {
  561. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  562. Spec: networking.NetworkPolicySpec{
  563. PodSelector: metav1.LabelSelector{},
  564. Egress: []networking.NetworkPolicyEgressRule{
  565. {
  566. Ports: []networking.NetworkPolicyPort{
  567. {
  568. Protocol: &protocolTCP,
  569. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 123456789},
  570. },
  571. },
  572. },
  573. },
  574. },
  575. },
  576. "invalid egress.ports.port (str)": {
  577. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  578. Spec: networking.NetworkPolicySpec{
  579. PodSelector: metav1.LabelSelector{},
  580. Egress: []networking.NetworkPolicyEgressRule{
  581. {
  582. Ports: []networking.NetworkPolicyPort{
  583. {
  584. Protocol: &protocolTCP,
  585. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "!@#$"},
  586. },
  587. },
  588. },
  589. },
  590. },
  591. },
  592. "invalid ingress.from.namespaceSelector": {
  593. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  594. Spec: networking.NetworkPolicySpec{
  595. PodSelector: metav1.LabelSelector{},
  596. Ingress: []networking.NetworkPolicyIngressRule{
  597. {
  598. From: []networking.NetworkPolicyPeer{
  599. {
  600. NamespaceSelector: &metav1.LabelSelector{
  601. MatchLabels: invalidSelector,
  602. },
  603. },
  604. },
  605. },
  606. },
  607. },
  608. },
  609. "missing cidr field": {
  610. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  611. Spec: networking.NetworkPolicySpec{
  612. PodSelector: metav1.LabelSelector{},
  613. Ingress: []networking.NetworkPolicyIngressRule{
  614. {
  615. From: []networking.NetworkPolicyPeer{
  616. {
  617. IPBlock: &networking.IPBlock{
  618. Except: []string{"192.168.8.0/24", "192.168.9.0/24"},
  619. },
  620. },
  621. },
  622. },
  623. },
  624. },
  625. },
  626. "invalid cidr format": {
  627. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  628. Spec: networking.NetworkPolicySpec{
  629. PodSelector: metav1.LabelSelector{
  630. MatchLabels: map[string]string{"a": "b"},
  631. },
  632. Ingress: []networking.NetworkPolicyIngressRule{
  633. {
  634. From: []networking.NetworkPolicyPeer{
  635. {
  636. IPBlock: &networking.IPBlock{
  637. CIDR: "192.168.5.6",
  638. Except: []string{"192.168.1.0/24", "192.168.2.0/24"},
  639. },
  640. },
  641. },
  642. },
  643. },
  644. },
  645. },
  646. "invalid ipv6 cidr format": {
  647. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  648. Spec: networking.NetworkPolicySpec{
  649. PodSelector: metav1.LabelSelector{
  650. MatchLabels: map[string]string{"a": "b"},
  651. },
  652. Ingress: []networking.NetworkPolicyIngressRule{
  653. {
  654. From: []networking.NetworkPolicyPeer{
  655. {
  656. IPBlock: &networking.IPBlock{
  657. CIDR: "fd00:192:168::",
  658. Except: []string{"fd00:192:168:3::/64", "fd00:192:168:4::/64"},
  659. },
  660. },
  661. },
  662. },
  663. },
  664. },
  665. },
  666. "except field is an empty string": {
  667. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  668. Spec: networking.NetworkPolicySpec{
  669. PodSelector: metav1.LabelSelector{
  670. MatchLabels: map[string]string{"a": "b"},
  671. },
  672. Ingress: []networking.NetworkPolicyIngressRule{
  673. {
  674. From: []networking.NetworkPolicyPeer{
  675. {
  676. IPBlock: &networking.IPBlock{
  677. CIDR: "192.168.8.0/24",
  678. Except: []string{"", " "},
  679. },
  680. },
  681. },
  682. },
  683. },
  684. },
  685. },
  686. "except IP is outside of CIDR range": {
  687. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  688. Spec: networking.NetworkPolicySpec{
  689. PodSelector: metav1.LabelSelector{
  690. MatchLabels: map[string]string{"a": "b"},
  691. },
  692. Ingress: []networking.NetworkPolicyIngressRule{
  693. {
  694. From: []networking.NetworkPolicyPeer{
  695. {
  696. IPBlock: &networking.IPBlock{
  697. CIDR: "192.168.8.0/24",
  698. Except: []string{"192.168.9.1/24"},
  699. },
  700. },
  701. },
  702. },
  703. },
  704. },
  705. },
  706. "except IP is not strictly within CIDR range": {
  707. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  708. Spec: networking.NetworkPolicySpec{
  709. PodSelector: metav1.LabelSelector{
  710. MatchLabels: map[string]string{"a": "b"},
  711. },
  712. Ingress: []networking.NetworkPolicyIngressRule{
  713. {
  714. From: []networking.NetworkPolicyPeer{
  715. {
  716. IPBlock: &networking.IPBlock{
  717. CIDR: "192.168.0.0/24",
  718. Except: []string{"192.168.0.0/24"},
  719. },
  720. },
  721. },
  722. },
  723. },
  724. },
  725. },
  726. "except IPv6 is outside of CIDR range": {
  727. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  728. Spec: networking.NetworkPolicySpec{
  729. PodSelector: metav1.LabelSelector{
  730. MatchLabels: map[string]string{"a": "b"},
  731. },
  732. Ingress: []networking.NetworkPolicyIngressRule{
  733. {
  734. From: []networking.NetworkPolicyPeer{
  735. {
  736. IPBlock: &networking.IPBlock{
  737. CIDR: "fd00:192:168:1::/64",
  738. Except: []string{"fd00:192:168:2::/64"},
  739. },
  740. },
  741. },
  742. },
  743. },
  744. },
  745. },
  746. "invalid policyTypes": {
  747. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  748. Spec: networking.NetworkPolicySpec{
  749. PodSelector: metav1.LabelSelector{
  750. MatchLabels: map[string]string{"a": "b"},
  751. },
  752. Egress: []networking.NetworkPolicyEgressRule{
  753. {
  754. To: []networking.NetworkPolicyPeer{
  755. {
  756. IPBlock: &networking.IPBlock{
  757. CIDR: "192.168.0.0/16",
  758. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  759. },
  760. },
  761. },
  762. },
  763. },
  764. PolicyTypes: []networking.PolicyType{"foo", "bar"},
  765. },
  766. },
  767. "too many policyTypes": {
  768. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  769. Spec: networking.NetworkPolicySpec{
  770. PodSelector: metav1.LabelSelector{
  771. MatchLabels: map[string]string{"a": "b"},
  772. },
  773. Egress: []networking.NetworkPolicyEgressRule{
  774. {
  775. To: []networking.NetworkPolicyPeer{
  776. {
  777. IPBlock: &networking.IPBlock{
  778. CIDR: "192.168.0.0/16",
  779. Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
  780. },
  781. },
  782. },
  783. },
  784. },
  785. PolicyTypes: []networking.PolicyType{"foo", "bar", "baz"},
  786. },
  787. },
  788. }
  789. // Error cases are not expected to pass validation.
  790. for testName, networkPolicy := range errorCases {
  791. if errs := ValidateNetworkPolicy(&networkPolicy); len(errs) == 0 {
  792. t.Errorf("Expected failure for test: %s", testName)
  793. }
  794. }
  795. }
  796. func TestValidateNetworkPolicyUpdate(t *testing.T) {
  797. type npUpdateTest struct {
  798. old networking.NetworkPolicy
  799. update networking.NetworkPolicy
  800. }
  801. successCases := map[string]npUpdateTest{
  802. "no change": {
  803. old: networking.NetworkPolicy{
  804. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  805. Spec: networking.NetworkPolicySpec{
  806. PodSelector: metav1.LabelSelector{
  807. MatchLabels: map[string]string{"a": "b"},
  808. },
  809. Ingress: []networking.NetworkPolicyIngressRule{},
  810. },
  811. },
  812. update: networking.NetworkPolicy{
  813. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  814. Spec: networking.NetworkPolicySpec{
  815. PodSelector: metav1.LabelSelector{
  816. MatchLabels: map[string]string{"a": "b"},
  817. },
  818. Ingress: []networking.NetworkPolicyIngressRule{},
  819. },
  820. },
  821. },
  822. "change spec": {
  823. old: networking.NetworkPolicy{
  824. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  825. Spec: networking.NetworkPolicySpec{
  826. PodSelector: metav1.LabelSelector{},
  827. Ingress: []networking.NetworkPolicyIngressRule{},
  828. },
  829. },
  830. update: networking.NetworkPolicy{
  831. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  832. Spec: networking.NetworkPolicySpec{
  833. PodSelector: metav1.LabelSelector{
  834. MatchLabels: map[string]string{"a": "b"},
  835. },
  836. Ingress: []networking.NetworkPolicyIngressRule{},
  837. },
  838. },
  839. },
  840. }
  841. for testName, successCase := range successCases {
  842. successCase.old.ObjectMeta.ResourceVersion = "1"
  843. successCase.update.ObjectMeta.ResourceVersion = "1"
  844. if errs := ValidateNetworkPolicyUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
  845. t.Errorf("expected success (%s): %v", testName, errs)
  846. }
  847. }
  848. errorCases := map[string]npUpdateTest{
  849. "change name": {
  850. old: networking.NetworkPolicy{
  851. ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
  852. Spec: networking.NetworkPolicySpec{
  853. PodSelector: metav1.LabelSelector{},
  854. Ingress: []networking.NetworkPolicyIngressRule{},
  855. },
  856. },
  857. update: networking.NetworkPolicy{
  858. ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "bar"},
  859. Spec: networking.NetworkPolicySpec{
  860. PodSelector: metav1.LabelSelector{},
  861. Ingress: []networking.NetworkPolicyIngressRule{},
  862. },
  863. },
  864. },
  865. }
  866. for testName, errorCase := range errorCases {
  867. errorCase.old.ObjectMeta.ResourceVersion = "1"
  868. errorCase.update.ObjectMeta.ResourceVersion = "1"
  869. if errs := ValidateNetworkPolicyUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
  870. t.Errorf("expected failure: %s", testName)
  871. }
  872. }
  873. }
  874. func TestValidateIngress(t *testing.T) {
  875. defaultBackend := networking.IngressBackend{
  876. ServiceName: "default-backend",
  877. ServicePort: intstr.FromInt(80),
  878. }
  879. newValid := func() networking.Ingress {
  880. return networking.Ingress{
  881. ObjectMeta: metav1.ObjectMeta{
  882. Name: "foo",
  883. Namespace: metav1.NamespaceDefault,
  884. },
  885. Spec: networking.IngressSpec{
  886. Backend: &networking.IngressBackend{
  887. ServiceName: "default-backend",
  888. ServicePort: intstr.FromInt(80),
  889. },
  890. Rules: []networking.IngressRule{
  891. {
  892. Host: "foo.bar.com",
  893. IngressRuleValue: networking.IngressRuleValue{
  894. HTTP: &networking.HTTPIngressRuleValue{
  895. Paths: []networking.HTTPIngressPath{
  896. {
  897. Path: "/foo",
  898. Backend: defaultBackend,
  899. },
  900. },
  901. },
  902. },
  903. },
  904. },
  905. },
  906. Status: networking.IngressStatus{
  907. LoadBalancer: api.LoadBalancerStatus{
  908. Ingress: []api.LoadBalancerIngress{
  909. {IP: "127.0.0.1"},
  910. },
  911. },
  912. },
  913. }
  914. }
  915. servicelessBackend := newValid()
  916. servicelessBackend.Spec.Backend.ServiceName = ""
  917. invalidNameBackend := newValid()
  918. invalidNameBackend.Spec.Backend.ServiceName = "defaultBackend"
  919. noPortBackend := newValid()
  920. noPortBackend.Spec.Backend = &networking.IngressBackend{ServiceName: defaultBackend.ServiceName}
  921. noForwardSlashPath := newValid()
  922. noForwardSlashPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{
  923. {
  924. Path: "invalid",
  925. Backend: defaultBackend,
  926. },
  927. }
  928. noPaths := newValid()
  929. noPaths.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{}
  930. badHost := newValid()
  931. badHost.Spec.Rules[0].Host = "foobar:80"
  932. badRegexPath := newValid()
  933. badPathExpr := "/invalid["
  934. badRegexPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{
  935. {
  936. Path: badPathExpr,
  937. Backend: defaultBackend,
  938. },
  939. }
  940. badPathErr := fmt.Sprintf("spec.rules[0].http.paths[0].path: Invalid value: '%v'", badPathExpr)
  941. hostIP := "127.0.0.1"
  942. badHostIP := newValid()
  943. badHostIP.Spec.Rules[0].Host = hostIP
  944. badHostIPErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", hostIP)
  945. errorCases := map[string]networking.Ingress{
  946. "spec.backend.serviceName: Required value": servicelessBackend,
  947. "spec.backend.serviceName: Invalid value": invalidNameBackend,
  948. "spec.backend.servicePort: Invalid value": noPortBackend,
  949. "spec.rules[0].host: Invalid value": badHost,
  950. "spec.rules[0].http.paths: Required value": noPaths,
  951. "spec.rules[0].http.paths[0].path: Invalid value": noForwardSlashPath,
  952. }
  953. errorCases[badPathErr] = badRegexPath
  954. errorCases[badHostIPErr] = badHostIP
  955. wildcardHost := "foo.*.bar.com"
  956. badWildcard := newValid()
  957. badWildcard.Spec.Rules[0].Host = wildcardHost
  958. badWildcardErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", wildcardHost)
  959. errorCases[badWildcardErr] = badWildcard
  960. for k, v := range errorCases {
  961. errs := ValidateIngress(&v)
  962. if len(errs) == 0 {
  963. t.Errorf("expected failure for %q", 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. }
  973. func TestValidateIngressTLS(t *testing.T) {
  974. defaultBackend := networking.IngressBackend{
  975. ServiceName: "default-backend",
  976. ServicePort: intstr.FromInt(80),
  977. }
  978. newValid := func() networking.Ingress {
  979. return networking.Ingress{
  980. ObjectMeta: metav1.ObjectMeta{
  981. Name: "foo",
  982. Namespace: metav1.NamespaceDefault,
  983. },
  984. Spec: networking.IngressSpec{
  985. Backend: &networking.IngressBackend{
  986. ServiceName: "default-backend",
  987. ServicePort: intstr.FromInt(80),
  988. },
  989. Rules: []networking.IngressRule{
  990. {
  991. Host: "foo.bar.com",
  992. IngressRuleValue: networking.IngressRuleValue{
  993. HTTP: &networking.HTTPIngressRuleValue{
  994. Paths: []networking.HTTPIngressPath{
  995. {
  996. Path: "/foo",
  997. Backend: defaultBackend,
  998. },
  999. },
  1000. },
  1001. },
  1002. },
  1003. },
  1004. },
  1005. Status: networking.IngressStatus{
  1006. LoadBalancer: api.LoadBalancerStatus{
  1007. Ingress: []api.LoadBalancerIngress{
  1008. {IP: "127.0.0.1"},
  1009. },
  1010. },
  1011. },
  1012. }
  1013. }
  1014. errorCases := map[string]networking.Ingress{}
  1015. wildcardHost := "foo.*.bar.com"
  1016. badWildcardTLS := newValid()
  1017. badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
  1018. badWildcardTLS.Spec.TLS = []networking.IngressTLS{
  1019. {
  1020. Hosts: []string{wildcardHost},
  1021. },
  1022. }
  1023. badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts: Invalid value: '%v'", wildcardHost)
  1024. errorCases[badWildcardTLSErr] = badWildcardTLS
  1025. for k, v := range errorCases {
  1026. errs := ValidateIngress(&v)
  1027. if len(errs) == 0 {
  1028. t.Errorf("expected failure for %q", k)
  1029. } else {
  1030. s := strings.Split(k, ":")
  1031. err := errs[0]
  1032. if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
  1033. t.Errorf("unexpected error: %q, expected: %q", err, k)
  1034. }
  1035. }
  1036. }
  1037. }
  1038. func TestValidateIngressStatusUpdate(t *testing.T) {
  1039. defaultBackend := networking.IngressBackend{
  1040. ServiceName: "default-backend",
  1041. ServicePort: intstr.FromInt(80),
  1042. }
  1043. newValid := func() networking.Ingress {
  1044. return networking.Ingress{
  1045. ObjectMeta: metav1.ObjectMeta{
  1046. Name: "foo",
  1047. Namespace: metav1.NamespaceDefault,
  1048. ResourceVersion: "9",
  1049. },
  1050. Spec: networking.IngressSpec{
  1051. Backend: &networking.IngressBackend{
  1052. ServiceName: "default-backend",
  1053. ServicePort: intstr.FromInt(80),
  1054. },
  1055. Rules: []networking.IngressRule{
  1056. {
  1057. Host: "foo.bar.com",
  1058. IngressRuleValue: networking.IngressRuleValue{
  1059. HTTP: &networking.HTTPIngressRuleValue{
  1060. Paths: []networking.HTTPIngressPath{
  1061. {
  1062. Path: "/foo",
  1063. Backend: defaultBackend,
  1064. },
  1065. },
  1066. },
  1067. },
  1068. },
  1069. },
  1070. },
  1071. Status: networking.IngressStatus{
  1072. LoadBalancer: api.LoadBalancerStatus{
  1073. Ingress: []api.LoadBalancerIngress{
  1074. {IP: "127.0.0.1", Hostname: "foo.bar.com"},
  1075. },
  1076. },
  1077. },
  1078. }
  1079. }
  1080. oldValue := newValid()
  1081. newValue := newValid()
  1082. newValue.Status = networking.IngressStatus{
  1083. LoadBalancer: api.LoadBalancerStatus{
  1084. Ingress: []api.LoadBalancerIngress{
  1085. {IP: "127.0.0.2", Hostname: "foo.com"},
  1086. },
  1087. },
  1088. }
  1089. invalidIP := newValid()
  1090. invalidIP.Status = networking.IngressStatus{
  1091. LoadBalancer: api.LoadBalancerStatus{
  1092. Ingress: []api.LoadBalancerIngress{
  1093. {IP: "abcd", Hostname: "foo.com"},
  1094. },
  1095. },
  1096. }
  1097. invalidHostname := newValid()
  1098. invalidHostname.Status = networking.IngressStatus{
  1099. LoadBalancer: api.LoadBalancerStatus{
  1100. Ingress: []api.LoadBalancerIngress{
  1101. {IP: "127.0.0.1", Hostname: "127.0.0.1"},
  1102. },
  1103. },
  1104. }
  1105. errs := ValidateIngressStatusUpdate(&newValue, &oldValue)
  1106. if len(errs) != 0 {
  1107. t.Errorf("Unexpected error %v", errs)
  1108. }
  1109. errorCases := map[string]networking.Ingress{
  1110. "status.loadBalancer.ingress[0].ip: Invalid value": invalidIP,
  1111. "status.loadBalancer.ingress[0].hostname: Invalid value": invalidHostname,
  1112. }
  1113. for k, v := range errorCases {
  1114. errs := ValidateIngressStatusUpdate(&v, &oldValue)
  1115. if len(errs) == 0 {
  1116. t.Errorf("expected failure for %s", k)
  1117. } else {
  1118. s := strings.Split(k, ":")
  1119. err := errs[0]
  1120. if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
  1121. t.Errorf("unexpected error: %q, expected: %q", err, k)
  1122. }
  1123. }
  1124. }
  1125. }