network_policy.go 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747
  1. /*
  2. Copyright 2016 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 network
  14. import (
  15. "context"
  16. "encoding/json"
  17. v1 "k8s.io/api/core/v1"
  18. networkingv1 "k8s.io/api/networking/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. "k8s.io/apimachinery/pkg/types"
  21. "k8s.io/apimachinery/pkg/util/intstr"
  22. "k8s.io/kubernetes/test/e2e/framework"
  23. e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
  24. e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
  25. imageutils "k8s.io/kubernetes/test/utils/image"
  26. "fmt"
  27. "github.com/onsi/ginkgo"
  28. )
  29. /*
  30. The following Network Policy tests verify that policy object definitions
  31. are correctly enforced by a networking plugin. It accomplishes this by launching
  32. a simple netcat server, and two clients with different
  33. attributes. Each test case creates a network policy which should only allow
  34. connections from one of the clients. The test then asserts that the clients
  35. failed or successfully connected as expected.
  36. */
  37. var _ = SIGDescribe("NetworkPolicy [LinuxOnly]", func() {
  38. var service *v1.Service
  39. var podServer *v1.Pod
  40. var podServerLabelSelector string
  41. f := framework.NewDefaultFramework("network-policy")
  42. ginkgo.BeforeEach(func() {
  43. // Windows does not support network policies.
  44. e2eskipper.SkipIfNodeOSDistroIs("windows")
  45. })
  46. ginkgo.Context("NetworkPolicy between server and client", func() {
  47. ginkgo.BeforeEach(func() {
  48. ginkgo.By("Creating a simple server that serves on port 80 and 81.")
  49. podServer, service = createServerPodAndService(f, f.Namespace, "server", []int{80, 81})
  50. ginkgo.By("Waiting for pod ready", func() {
  51. err := f.WaitForPodReady(podServer.Name)
  52. framework.ExpectNoError(err)
  53. })
  54. // podServerLabelSelector holds the value for the podServer's label "pod-name".
  55. podServerLabelSelector = podServer.ObjectMeta.Labels["pod-name"]
  56. // Create pods, which should be able to communicate with the server on port 80 and 81.
  57. ginkgo.By("Testing pods can connect to both ports when no policy is present.")
  58. testCanConnect(f, f.Namespace, "client-can-connect-80", service, 80)
  59. testCanConnect(f, f.Namespace, "client-can-connect-81", service, 81)
  60. })
  61. ginkgo.AfterEach(func() {
  62. cleanupServerPodAndService(f, podServer, service)
  63. })
  64. ginkgo.It("should support a 'default-deny' policy [Feature:NetworkPolicy]", func() {
  65. policy := &networkingv1.NetworkPolicy{
  66. ObjectMeta: metav1.ObjectMeta{
  67. Name: "deny-all",
  68. },
  69. Spec: networkingv1.NetworkPolicySpec{
  70. PodSelector: metav1.LabelSelector{},
  71. Ingress: []networkingv1.NetworkPolicyIngressRule{},
  72. },
  73. }
  74. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  75. framework.ExpectNoError(err)
  76. defer cleanupNetworkPolicy(f, policy)
  77. // Create a pod with name 'client-cannot-connect', which will attempt to communicate with the server,
  78. // but should not be able to now that isolation is on.
  79. testCannotConnect(f, f.Namespace, "client-cannot-connect", service, 80)
  80. })
  81. ginkgo.It("should enforce policy to allow traffic from pods within server namespace based on PodSelector [Feature:NetworkPolicy]", func() {
  82. nsA := f.Namespace
  83. nsBName := f.BaseName + "-b"
  84. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  85. "ns-name": nsBName,
  86. })
  87. framework.ExpectNoError(err, "Error occurred while creating namespace-b.")
  88. // All communication should be possible before applying the policy.
  89. ginkgo.By("Creating client-a, in server's namespace, which should be able to contact the server.", func() {
  90. testCanConnect(f, nsA, "client-a", service, 80)
  91. })
  92. ginkgo.By("Creating client-b, in server's namespace, which should be able to contact the server.", func() {
  93. testCanConnect(f, nsA, "client-b", service, 80)
  94. })
  95. ginkgo.By("Creating client-a, not in server's namespace, which should be able to contact the server.", func() {
  96. testCanConnect(f, nsB, "client-a", service, 80)
  97. })
  98. ginkgo.By("Creating a network policy for the server which allows traffic from the pod 'client-a' in same namespace.")
  99. policy := &networkingv1.NetworkPolicy{
  100. ObjectMeta: metav1.ObjectMeta{
  101. Name: "allow-client-a-via-pod-selector",
  102. },
  103. Spec: networkingv1.NetworkPolicySpec{
  104. // Apply this policy to the Server
  105. PodSelector: metav1.LabelSelector{
  106. MatchLabels: map[string]string{
  107. "pod-name": podServerLabelSelector,
  108. },
  109. },
  110. // Allow traffic only from client-a
  111. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  112. From: []networkingv1.NetworkPolicyPeer{{
  113. PodSelector: &metav1.LabelSelector{
  114. MatchLabels: map[string]string{
  115. "pod-name": "client-a",
  116. },
  117. },
  118. }},
  119. }},
  120. },
  121. }
  122. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  123. framework.ExpectNoError(err)
  124. defer cleanupNetworkPolicy(f, policy)
  125. ginkgo.By("Creating client-a, in server's namespace, which should be able to contact the server.", func() {
  126. testCanConnect(f, nsA, "client-a", service, 80)
  127. })
  128. ginkgo.By("Creating client-b, in server's namespace, which should not be able to contact the server.", func() {
  129. testCannotConnect(f, nsA, "client-b", service, 80)
  130. })
  131. ginkgo.By("Creating client-a, not in server's namespace, which should not be able to contact the server.", func() {
  132. testCannotConnect(f, nsB, "client-a", service, 80)
  133. })
  134. })
  135. ginkgo.It("should enforce policy to allow traffic only from a different namespace, based on NamespaceSelector [Feature:NetworkPolicy]", func() {
  136. nsA := f.Namespace
  137. nsBName := f.BaseName + "-b"
  138. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  139. "ns-name": nsBName,
  140. })
  141. framework.ExpectNoError(err)
  142. // Create Server with Service in NS-B
  143. framework.Logf("Waiting for server to come up.")
  144. err = e2epod.WaitForPodRunningInNamespace(f.ClientSet, podServer)
  145. framework.ExpectNoError(err)
  146. // Create Policy for that service that allows traffic only via namespace B
  147. ginkgo.By("Creating a network policy for the server which allows traffic from namespace-b.")
  148. policy := &networkingv1.NetworkPolicy{
  149. ObjectMeta: metav1.ObjectMeta{
  150. Name: "allow-ns-b-via-namespace-selector",
  151. },
  152. Spec: networkingv1.NetworkPolicySpec{
  153. // Apply to server
  154. PodSelector: metav1.LabelSelector{
  155. MatchLabels: map[string]string{
  156. "pod-name": podServerLabelSelector,
  157. },
  158. },
  159. // Allow traffic only from NS-B
  160. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  161. From: []networkingv1.NetworkPolicyPeer{{
  162. NamespaceSelector: &metav1.LabelSelector{
  163. MatchLabels: map[string]string{
  164. "ns-name": nsBName,
  165. },
  166. },
  167. }},
  168. }},
  169. },
  170. }
  171. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(nsA.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  172. framework.ExpectNoError(err)
  173. defer cleanupNetworkPolicy(f, policy)
  174. testCannotConnect(f, nsA, "client-a", service, 80)
  175. testCanConnect(f, nsB, "client-b", service, 80)
  176. })
  177. ginkgo.It("should enforce policy based on PodSelector with MatchExpressions[Feature:NetworkPolicy]", func() {
  178. ginkgo.By("Creating a network policy for the server which allows traffic from the pod 'client-a'.")
  179. policy := &networkingv1.NetworkPolicy{
  180. ObjectMeta: metav1.ObjectMeta{
  181. Name: "allow-client-a-via-pod-selector-with-match-expressions",
  182. },
  183. Spec: networkingv1.NetworkPolicySpec{
  184. PodSelector: metav1.LabelSelector{
  185. MatchLabels: map[string]string{
  186. "pod-name": podServerLabelSelector,
  187. },
  188. },
  189. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  190. From: []networkingv1.NetworkPolicyPeer{{
  191. PodSelector: &metav1.LabelSelector{
  192. MatchExpressions: []metav1.LabelSelectorRequirement{{
  193. Key: "pod-name",
  194. Operator: metav1.LabelSelectorOpIn,
  195. Values: []string{"client-a"},
  196. }},
  197. },
  198. }},
  199. }},
  200. },
  201. }
  202. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  203. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  204. defer cleanupNetworkPolicy(f, policy)
  205. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  206. testCanConnect(f, f.Namespace, "client-a", service, 80)
  207. })
  208. ginkgo.By("Creating client-b which should not be able to contact the server.", func() {
  209. testCannotConnect(f, f.Namespace, "client-b", service, 80)
  210. })
  211. })
  212. ginkgo.It("should enforce policy based on NamespaceSelector with MatchExpressions[Feature:NetworkPolicy]", func() {
  213. nsA := f.Namespace
  214. nsBName := f.BaseName + "-b"
  215. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  216. "ns-name": nsBName,
  217. })
  218. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsBName, err)
  219. nsCName := f.BaseName + "-c"
  220. nsC, err := f.CreateNamespace(nsCName, map[string]string{
  221. "ns-name": nsCName,
  222. })
  223. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsCName, err)
  224. // Create Policy for the server that allows traffic from namespace different than namespace-a
  225. ginkgo.By("Creating a network policy for the server which allows traffic from ns different than namespace-a.")
  226. policy := &networkingv1.NetworkPolicy{
  227. ObjectMeta: metav1.ObjectMeta{
  228. Name: "allow-any-ns-different-than-ns-a-via-ns-selector-with-match-expressions",
  229. },
  230. Spec: networkingv1.NetworkPolicySpec{
  231. PodSelector: metav1.LabelSelector{
  232. MatchLabels: map[string]string{
  233. "pod-name": podServerLabelSelector,
  234. },
  235. },
  236. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  237. From: []networkingv1.NetworkPolicyPeer{{
  238. NamespaceSelector: &metav1.LabelSelector{
  239. MatchExpressions: []metav1.LabelSelectorRequirement{{
  240. Key: "ns-name",
  241. Operator: metav1.LabelSelectorOpNotIn,
  242. Values: []string{nsCName},
  243. }},
  244. },
  245. }},
  246. }},
  247. },
  248. }
  249. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(nsA.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  250. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  251. defer cleanupNetworkPolicy(f, policy)
  252. testCannotConnect(f, nsC, "client-a", service, 80)
  253. testCanConnect(f, nsB, "client-a", service, 80)
  254. })
  255. ginkgo.It("should enforce policy based on PodSelector or NamespaceSelector [Feature:NetworkPolicy]", func() {
  256. nsA := f.Namespace
  257. nsBName := f.BaseName + "-b"
  258. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  259. "ns-name": nsBName,
  260. })
  261. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsBName, err)
  262. // Create Policy for the server that allows traffic only via client B or namespace B
  263. ginkgo.By("Creating a network policy for the server which allows traffic from client-b or namespace-b.")
  264. policy := &networkingv1.NetworkPolicy{
  265. ObjectMeta: metav1.ObjectMeta{
  266. Name: "allow-ns-b-via-namespace-selector-or-client-b-via-pod-selector",
  267. },
  268. Spec: networkingv1.NetworkPolicySpec{
  269. PodSelector: metav1.LabelSelector{
  270. MatchLabels: map[string]string{
  271. "pod-name": podServerLabelSelector,
  272. },
  273. },
  274. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  275. From: []networkingv1.NetworkPolicyPeer{{
  276. PodSelector: &metav1.LabelSelector{
  277. MatchLabels: map[string]string{
  278. "pod-name": "client-b",
  279. },
  280. },
  281. }, {
  282. NamespaceSelector: &metav1.LabelSelector{
  283. MatchLabels: map[string]string{
  284. "ns-name": nsBName,
  285. },
  286. },
  287. }},
  288. }},
  289. },
  290. }
  291. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(nsA.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  292. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  293. defer cleanupNetworkPolicy(f, policy)
  294. testCanConnect(f, nsB, "client-a", service, 80)
  295. testCanConnect(f, nsA, "client-b", service, 80)
  296. testCannotConnect(f, nsA, "client-c", service, 80)
  297. })
  298. ginkgo.It("should enforce policy based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
  299. nsA := f.Namespace
  300. nsBName := f.BaseName + "-b"
  301. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  302. "ns-name": nsBName,
  303. })
  304. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsBName, err)
  305. // Create Policy for the server that allows traffic only via client-b in namespace B
  306. ginkgo.By("Creating a network policy for the server which allows traffic from client-b in namespace-b.")
  307. policy := &networkingv1.NetworkPolicy{
  308. ObjectMeta: metav1.ObjectMeta{
  309. Name: "allow-client-b-in-ns-b-via-ns-selector-and-pod-selector",
  310. },
  311. Spec: networkingv1.NetworkPolicySpec{
  312. PodSelector: metav1.LabelSelector{
  313. MatchLabels: map[string]string{
  314. "pod-name": podServerLabelSelector,
  315. },
  316. },
  317. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  318. From: []networkingv1.NetworkPolicyPeer{{
  319. PodSelector: &metav1.LabelSelector{
  320. MatchLabels: map[string]string{
  321. "pod-name": "client-b",
  322. },
  323. },
  324. NamespaceSelector: &metav1.LabelSelector{
  325. MatchLabels: map[string]string{
  326. "ns-name": nsBName,
  327. },
  328. },
  329. }},
  330. }},
  331. },
  332. }
  333. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(nsA.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  334. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  335. defer cleanupNetworkPolicy(f, policy)
  336. testCannotConnect(f, nsB, "client-a", service, 80)
  337. testCannotConnect(f, nsA, "client-b", service, 80)
  338. testCanConnect(f, nsB, "client-b", service, 80)
  339. })
  340. ginkgo.It("should enforce policy to allow traffic only from a pod in a different namespace based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
  341. nsA := f.Namespace
  342. nsBName := f.BaseName + "-b"
  343. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  344. "ns-name": nsBName,
  345. })
  346. framework.ExpectNoError(err, "Error occurred while creating namespace-b.")
  347. // Wait for Server in namespaces-a to be ready
  348. framework.Logf("Waiting for server to come up.")
  349. err = e2epod.WaitForPodRunningInNamespace(f.ClientSet, podServer)
  350. framework.ExpectNoError(err, "Error occurred while waiting for pod status in namespace: Running.")
  351. // Before application of the policy, all communication should be successful.
  352. ginkgo.By("Creating client-a, in server's namespace, which should be able to contact the server.", func() {
  353. testCanConnect(f, nsA, "client-a", service, 80)
  354. })
  355. ginkgo.By("Creating client-b, in server's namespace, which should be able to contact the server.", func() {
  356. testCanConnect(f, nsA, "client-b", service, 80)
  357. })
  358. ginkgo.By("Creating client-a, not in server's namespace, which should be able to contact the server.", func() {
  359. testCanConnect(f, nsB, "client-a", service, 80)
  360. })
  361. ginkgo.By("Creating client-b, not in server's namespace, which should be able to contact the server.", func() {
  362. testCanConnect(f, nsB, "client-b", service, 80)
  363. })
  364. ginkgo.By("Creating a network policy for the server which allows traffic only from client-a in namespace-b.")
  365. policy := &networkingv1.NetworkPolicy{
  366. ObjectMeta: metav1.ObjectMeta{
  367. Namespace: nsA.Name,
  368. Name: "allow-ns-b-client-a-via-namespace-pod-selector",
  369. },
  370. Spec: networkingv1.NetworkPolicySpec{
  371. // Apply this policy to the Server
  372. PodSelector: metav1.LabelSelector{
  373. MatchLabels: map[string]string{
  374. "pod-name": podServerLabelSelector,
  375. },
  376. },
  377. // Allow traffic only from client-a in namespace-b
  378. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  379. From: []networkingv1.NetworkPolicyPeer{{
  380. NamespaceSelector: &metav1.LabelSelector{
  381. MatchLabels: map[string]string{
  382. "ns-name": nsBName,
  383. },
  384. },
  385. PodSelector: &metav1.LabelSelector{
  386. MatchLabels: map[string]string{
  387. "pod-name": "client-a",
  388. },
  389. },
  390. }},
  391. }},
  392. },
  393. }
  394. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  395. framework.ExpectNoError(err, "Error occurred while creating policy: policy.")
  396. defer cleanupNetworkPolicy(f, policy)
  397. ginkgo.By("Creating client-a, in server's namespace, which should not be able to contact the server.", func() {
  398. testCannotConnect(f, nsA, "client-a", service, 80)
  399. })
  400. ginkgo.By("Creating client-b, in server's namespace, which should not be able to contact the server.", func() {
  401. testCannotConnect(f, nsA, "client-b", service, 80)
  402. })
  403. ginkgo.By("Creating client-a, not in server's namespace, which should be able to contact the server.", func() {
  404. testCanConnect(f, nsB, "client-a", service, 80)
  405. })
  406. ginkgo.By("Creating client-b, not in server's namespace, which should not be able to contact the server.", func() {
  407. testCannotConnect(f, nsB, "client-b", service, 80)
  408. })
  409. })
  410. ginkgo.It("should enforce policy based on Ports [Feature:NetworkPolicy]", func() {
  411. ginkgo.By("Creating a network policy for the Service which allows traffic only to one port.")
  412. policy := &networkingv1.NetworkPolicy{
  413. ObjectMeta: metav1.ObjectMeta{
  414. Name: "allow-ingress-on-port-81",
  415. },
  416. Spec: networkingv1.NetworkPolicySpec{
  417. // Apply to server
  418. PodSelector: metav1.LabelSelector{
  419. MatchLabels: map[string]string{
  420. "pod-name": podServerLabelSelector,
  421. },
  422. },
  423. // Allow traffic only to one port.
  424. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  425. Ports: []networkingv1.NetworkPolicyPort{{
  426. Port: &intstr.IntOrString{IntVal: 81},
  427. }},
  428. }},
  429. },
  430. }
  431. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  432. framework.ExpectNoError(err)
  433. defer cleanupNetworkPolicy(f, policy)
  434. ginkgo.By("Testing pods can connect only to the port allowed by the policy.")
  435. testCannotConnect(f, f.Namespace, "client-a", service, 80)
  436. testCanConnect(f, f.Namespace, "client-b", service, 81)
  437. })
  438. ginkgo.It("should enforce multiple, stacked policies with overlapping podSelectors [Feature:NetworkPolicy]", func() {
  439. ginkgo.By("Creating a network policy for the Service which allows traffic only to one port.")
  440. policy := &networkingv1.NetworkPolicy{
  441. ObjectMeta: metav1.ObjectMeta{
  442. Name: "allow-ingress-on-port-80",
  443. },
  444. Spec: networkingv1.NetworkPolicySpec{
  445. // Apply to server
  446. PodSelector: metav1.LabelSelector{
  447. MatchLabels: map[string]string{
  448. "pod-name": podServerLabelSelector,
  449. },
  450. },
  451. // Allow traffic only to one port.
  452. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  453. Ports: []networkingv1.NetworkPolicyPort{{
  454. Port: &intstr.IntOrString{IntVal: 80},
  455. }},
  456. }},
  457. },
  458. }
  459. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  460. framework.ExpectNoError(err)
  461. defer cleanupNetworkPolicy(f, policy)
  462. ginkgo.By("Creating a network policy for the Service which allows traffic only to another port.")
  463. policy2 := &networkingv1.NetworkPolicy{
  464. ObjectMeta: metav1.ObjectMeta{
  465. Name: "allow-ingress-on-port-81",
  466. },
  467. Spec: networkingv1.NetworkPolicySpec{
  468. // Apply to server
  469. PodSelector: metav1.LabelSelector{
  470. MatchLabels: map[string]string{
  471. "pod-name": podServerLabelSelector,
  472. },
  473. },
  474. // Allow traffic only to one port.
  475. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  476. Ports: []networkingv1.NetworkPolicyPort{{
  477. Port: &intstr.IntOrString{IntVal: 81},
  478. }},
  479. }},
  480. },
  481. }
  482. policy2, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy2, metav1.CreateOptions{})
  483. framework.ExpectNoError(err)
  484. defer cleanupNetworkPolicy(f, policy2)
  485. ginkgo.By("Testing pods can connect to both ports when both policies are present.")
  486. testCanConnect(f, f.Namespace, "client-a", service, 80)
  487. testCanConnect(f, f.Namespace, "client-b", service, 81)
  488. })
  489. ginkgo.It("should support allow-all policy [Feature:NetworkPolicy]", func() {
  490. ginkgo.By("Creating a network policy which allows all traffic.")
  491. policy := &networkingv1.NetworkPolicy{
  492. ObjectMeta: metav1.ObjectMeta{
  493. Name: "allow-all",
  494. },
  495. Spec: networkingv1.NetworkPolicySpec{
  496. // Allow all traffic
  497. PodSelector: metav1.LabelSelector{
  498. MatchLabels: map[string]string{},
  499. },
  500. Ingress: []networkingv1.NetworkPolicyIngressRule{{}},
  501. },
  502. }
  503. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  504. framework.ExpectNoError(err)
  505. defer cleanupNetworkPolicy(f, policy)
  506. ginkgo.By("Testing pods can connect to both ports when an 'allow-all' policy is present.")
  507. testCanConnect(f, f.Namespace, "client-a", service, 80)
  508. testCanConnect(f, f.Namespace, "client-b", service, 81)
  509. })
  510. ginkgo.It("should allow ingress access on one named port [Feature:NetworkPolicy]", func() {
  511. policy := &networkingv1.NetworkPolicy{
  512. ObjectMeta: metav1.ObjectMeta{
  513. Name: "allow-client-a-via-named-port-ingress-rule",
  514. },
  515. Spec: networkingv1.NetworkPolicySpec{
  516. // Apply this policy to the Server
  517. PodSelector: metav1.LabelSelector{
  518. MatchLabels: map[string]string{
  519. "pod-name": podServerLabelSelector,
  520. },
  521. },
  522. // Allow traffic to only one named port: "serve-80".
  523. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  524. Ports: []networkingv1.NetworkPolicyPort{{
  525. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80"},
  526. }},
  527. }},
  528. },
  529. }
  530. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  531. framework.ExpectNoError(err)
  532. defer cleanupNetworkPolicy(f, policy)
  533. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  534. testCanConnect(f, f.Namespace, "client-a", service, 80)
  535. })
  536. ginkgo.By("Creating client-b which should not be able to contact the server on port 81.", func() {
  537. testCannotConnect(f, f.Namespace, "client-b", service, 81)
  538. })
  539. })
  540. ginkgo.It("should allow ingress access from namespace on one named port [Feature:NetworkPolicy]", func() {
  541. nsBName := f.BaseName + "-b"
  542. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  543. "ns-name": nsBName,
  544. })
  545. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsBName, err)
  546. const allowedPort = 80
  547. policy := &networkingv1.NetworkPolicy{
  548. ObjectMeta: metav1.ObjectMeta{
  549. Name: "allow-client-in-ns-b-via-named-port-ingress-rule",
  550. },
  551. Spec: networkingv1.NetworkPolicySpec{
  552. // Apply this policy to the Server
  553. PodSelector: metav1.LabelSelector{
  554. MatchLabels: map[string]string{
  555. "pod-name": podServerLabelSelector,
  556. },
  557. },
  558. // Allow traffic to only one named port: "serve-80" from namespace-b.
  559. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  560. From: []networkingv1.NetworkPolicyPeer{{
  561. NamespaceSelector: &metav1.LabelSelector{
  562. MatchLabels: map[string]string{
  563. "ns-name": nsBName,
  564. },
  565. },
  566. }},
  567. Ports: []networkingv1.NetworkPolicyPort{{
  568. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80"},
  569. }},
  570. }},
  571. },
  572. }
  573. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  574. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  575. defer cleanupNetworkPolicy(f, policy)
  576. testCannotConnect(f, f.Namespace, "client-a", service, allowedPort)
  577. testCanConnect(f, nsB, "client-b", service, allowedPort)
  578. })
  579. ginkgo.It("should allow egress access on one named port [Feature:NetworkPolicy]", func() {
  580. clientPodName := "client-a"
  581. protocolUDP := v1.ProtocolUDP
  582. policy := &networkingv1.NetworkPolicy{
  583. ObjectMeta: metav1.ObjectMeta{
  584. Name: "allow-client-a-via-named-port-egress-rule",
  585. },
  586. Spec: networkingv1.NetworkPolicySpec{
  587. // Apply this policy to client-a
  588. PodSelector: metav1.LabelSelector{
  589. MatchLabels: map[string]string{
  590. "pod-name": clientPodName,
  591. },
  592. },
  593. // Allow traffic to only one named port: "serve-80".
  594. Egress: []networkingv1.NetworkPolicyEgressRule{{
  595. Ports: []networkingv1.NetworkPolicyPort{
  596. {
  597. Port: &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80"},
  598. },
  599. // Allow DNS look-ups
  600. {
  601. Protocol: &protocolUDP,
  602. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  603. },
  604. },
  605. }},
  606. },
  607. }
  608. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  609. framework.ExpectNoError(err)
  610. defer cleanupNetworkPolicy(f, policy)
  611. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  612. testCanConnect(f, f.Namespace, clientPodName, service, 80)
  613. })
  614. ginkgo.By("Creating client-a which should not be able to contact the server on port 81.", func() {
  615. testCannotConnect(f, f.Namespace, clientPodName, service, 81)
  616. })
  617. })
  618. ginkgo.It("should enforce updated policy [Feature:NetworkPolicy]", func() {
  619. const (
  620. clientAAllowedPort = 80
  621. clientANotAllowedPort = 81
  622. )
  623. ginkgo.By("Creating a network policy for the Service which allows traffic from pod at a port")
  624. policy := &networkingv1.NetworkPolicy{
  625. ObjectMeta: metav1.ObjectMeta{
  626. Name: "allow-ingress",
  627. },
  628. Spec: networkingv1.NetworkPolicySpec{
  629. // Apply to server
  630. PodSelector: metav1.LabelSelector{
  631. MatchLabels: map[string]string{
  632. "pod-name": podServerLabelSelector,
  633. },
  634. },
  635. // Allow traffic only to one port.
  636. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  637. From: []networkingv1.NetworkPolicyPeer{{
  638. PodSelector: &metav1.LabelSelector{
  639. MatchLabels: map[string]string{
  640. "pod-name": "client-a",
  641. },
  642. },
  643. }},
  644. Ports: []networkingv1.NetworkPolicyPort{{
  645. Port: &intstr.IntOrString{IntVal: clientAAllowedPort},
  646. }},
  647. }},
  648. },
  649. }
  650. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  651. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  652. testCanConnect(f, f.Namespace, "client-a", service, clientAAllowedPort)
  653. err = f.WaitForPodNotFound("client-a", framework.PodDeleteTimeout)
  654. framework.ExpectNoError(err, "Expected pod to be not found.")
  655. testCannotConnect(f, f.Namespace, "client-b", service, clientAAllowedPort)
  656. err = f.WaitForPodNotFound("client-b", framework.PodDeleteTimeout)
  657. framework.ExpectNoError(err, "Expected pod to be not found.")
  658. testCannotConnect(f, f.Namespace, "client-a", service, clientANotAllowedPort)
  659. err = f.WaitForPodNotFound("client-a", framework.PodDeleteTimeout)
  660. framework.ExpectNoError(err, "Expected pod to be not found.")
  661. const (
  662. clientBAllowedPort = 81
  663. clientBNotAllowedPort = 80
  664. )
  665. ginkgo.By("Updating a network policy for the Service which allows traffic from another pod at another port.")
  666. policy = &networkingv1.NetworkPolicy{
  667. ObjectMeta: metav1.ObjectMeta{
  668. Name: "allow-ingress",
  669. },
  670. Spec: networkingv1.NetworkPolicySpec{
  671. // Apply to server
  672. PodSelector: metav1.LabelSelector{
  673. MatchLabels: map[string]string{
  674. "pod-name": podServerLabelSelector,
  675. },
  676. },
  677. // Allow traffic only to one port.
  678. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  679. From: []networkingv1.NetworkPolicyPeer{{
  680. PodSelector: &metav1.LabelSelector{
  681. MatchLabels: map[string]string{
  682. "pod-name": "client-b",
  683. },
  684. },
  685. }},
  686. Ports: []networkingv1.NetworkPolicyPort{{
  687. Port: &intstr.IntOrString{IntVal: clientBAllowedPort},
  688. }},
  689. }},
  690. },
  691. }
  692. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Update(context.TODO(), policy, metav1.UpdateOptions{})
  693. framework.ExpectNoError(err, "Error updating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  694. defer cleanupNetworkPolicy(f, policy)
  695. testCannotConnect(f, f.Namespace, "client-b", service, clientBNotAllowedPort)
  696. err = f.WaitForPodNotFound("client-b", framework.PodDeleteTimeout)
  697. framework.ExpectNoError(err, "Expected pod to be not found.")
  698. testCannotConnect(f, f.Namespace, "client-a", service, clientBNotAllowedPort)
  699. testCanConnect(f, f.Namespace, "client-b", service, clientBAllowedPort)
  700. })
  701. ginkgo.It("should allow ingress access from updated namespace [Feature:NetworkPolicy]", func() {
  702. nsA := f.Namespace
  703. nsBName := f.BaseName + "-b"
  704. newNsBName := nsBName + "-updated"
  705. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  706. "ns-name": nsBName,
  707. })
  708. framework.ExpectNoError(err, "Error creating namespace %v: %v", nsBName, err)
  709. const allowedPort = 80
  710. // Create Policy for that service that allows traffic only via namespace B
  711. ginkgo.By("Creating a network policy for the server which allows traffic from namespace-b.")
  712. policy := &networkingv1.NetworkPolicy{
  713. ObjectMeta: metav1.ObjectMeta{
  714. Name: "allow-ns-b-via-namespace-selector",
  715. },
  716. Spec: networkingv1.NetworkPolicySpec{
  717. PodSelector: metav1.LabelSelector{
  718. MatchLabels: map[string]string{
  719. "pod-name": podServerLabelSelector,
  720. },
  721. },
  722. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  723. From: []networkingv1.NetworkPolicyPeer{{
  724. NamespaceSelector: &metav1.LabelSelector{
  725. MatchLabels: map[string]string{
  726. "ns-name": newNsBName,
  727. },
  728. },
  729. }},
  730. }},
  731. },
  732. }
  733. policy, err = f.ClientSet.NetworkingV1().NetworkPolicies(nsA.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  734. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  735. defer cleanupNetworkPolicy(f, policy)
  736. testCannotConnect(f, nsB, "client-a", service, allowedPort)
  737. nsB, err = f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), nsB.Name, metav1.GetOptions{})
  738. framework.ExpectNoError(err, "Error getting Namespace %v: %v", nsB.ObjectMeta.Name, err)
  739. nsB.ObjectMeta.Labels["ns-name"] = newNsBName
  740. nsB, err = f.ClientSet.CoreV1().Namespaces().Update(context.TODO(), nsB, metav1.UpdateOptions{})
  741. framework.ExpectNoError(err, "Error updating Namespace %v: %v", nsB.ObjectMeta.Name, err)
  742. testCanConnect(f, nsB, "client-b", service, allowedPort)
  743. })
  744. ginkgo.It("should allow ingress access from updated pod [Feature:NetworkPolicy]", func() {
  745. const allowedPort = 80
  746. ginkgo.By("Creating a network policy for the server which allows traffic from client-a-updated.")
  747. policy := &networkingv1.NetworkPolicy{
  748. ObjectMeta: metav1.ObjectMeta{
  749. Name: "allow-pod-b-via-pod-selector",
  750. },
  751. Spec: networkingv1.NetworkPolicySpec{
  752. PodSelector: metav1.LabelSelector{
  753. MatchLabels: map[string]string{
  754. "pod-name": podServerLabelSelector,
  755. },
  756. },
  757. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  758. From: []networkingv1.NetworkPolicyPeer{{
  759. PodSelector: &metav1.LabelSelector{
  760. MatchExpressions: []metav1.LabelSelectorRequirement{{
  761. Key: "pod-name",
  762. Operator: metav1.LabelSelectorOpDoesNotExist,
  763. }},
  764. },
  765. }},
  766. }},
  767. },
  768. }
  769. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  770. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  771. defer cleanupNetworkPolicy(f, policy)
  772. ginkgo.By(fmt.Sprintf("Creating client pod %s that should not be able to connect to %s.", "client-a", service.Name))
  773. // Specify RestartPolicy to OnFailure so we can check the client pod fails in the beginning and succeeds
  774. // after updating its label, otherwise it would not restart after the first failure.
  775. podClient := createNetworkClientPodWithRestartPolicy(f, f.Namespace, "client-a", service, allowedPort, v1.RestartPolicyOnFailure)
  776. defer func() {
  777. ginkgo.By(fmt.Sprintf("Cleaning up the pod %s", podClient.Name))
  778. if err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(context.TODO(), podClient.Name, nil); err != nil {
  779. framework.Failf("unable to cleanup pod %v: %v", podClient.Name, err)
  780. }
  781. }()
  782. // Check Container exit code as restartable Pod's Phase will be Running even when container fails.
  783. checkNoConnectivityByExitCode(f, f.Namespace, podClient, service)
  784. ginkgo.By(fmt.Sprintf("Updating client pod %s that should successfully connect to %s.", podClient.Name, service.Name))
  785. podClient = updatePodLabel(f, f.Namespace, podClient.Name, "replace", "/metadata/labels", map[string]string{})
  786. checkConnectivity(f, f.Namespace, podClient, service)
  787. })
  788. ginkgo.It("should deny ingress access to updated pod [Feature:NetworkPolicy]", func() {
  789. const allowedPort = 80
  790. ginkgo.By("Creating a network policy for the server which denies all traffic.")
  791. policy := &networkingv1.NetworkPolicy{
  792. ObjectMeta: metav1.ObjectMeta{
  793. Name: "deny-ingress-via-isolated-label-selector",
  794. },
  795. Spec: networkingv1.NetworkPolicySpec{
  796. PodSelector: metav1.LabelSelector{
  797. MatchLabels: map[string]string{
  798. "pod-name": podServerLabelSelector,
  799. },
  800. MatchExpressions: []metav1.LabelSelectorRequirement{{
  801. Key: "isolated",
  802. Operator: metav1.LabelSelectorOpExists,
  803. }},
  804. },
  805. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  806. Ingress: []networkingv1.NetworkPolicyIngressRule{},
  807. },
  808. }
  809. policy, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policy, metav1.CreateOptions{})
  810. framework.ExpectNoError(err, "Error creating Network Policy %v: %v", policy.ObjectMeta.Name, err)
  811. defer cleanupNetworkPolicy(f, policy)
  812. // Client can connect to service when the network policy doesn't apply to the server pod.
  813. testCanConnect(f, f.Namespace, "client-a", service, allowedPort)
  814. // Client cannot connect to service after updating the server pod's labels to match the network policy's selector.
  815. ginkgo.By(fmt.Sprintf("Updating server pod %s to be selected by network policy %s.", podServer.Name, policy.Name))
  816. updatePodLabel(f, f.Namespace, podServer.Name, "add", "/metadata/labels/isolated", nil)
  817. testCannotConnect(f, f.Namespace, "client-a", service, allowedPort)
  818. })
  819. ginkgo.It("should enforce egress policy allowing traffic to a server in a different namespace based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
  820. var nsBserviceA, nsBserviceB *v1.Service
  821. var nsBpodServerA, nsBpodServerB *v1.Pod
  822. nsA := f.Namespace
  823. nsBName := f.BaseName + "-b"
  824. nsB, err := f.CreateNamespace(nsBName, map[string]string{
  825. "ns-name": nsBName,
  826. })
  827. framework.ExpectNoError(err, "Error occurred while creating namespace-b.")
  828. // Creating pods and services in namespace-b
  829. nsBpodServerA, nsBserviceA = createServerPodAndService(f, nsB, "ns-b-server-a", []int{80})
  830. defer cleanupServerPodAndService(f, nsBpodServerA, nsBserviceA)
  831. nsBpodServerB, nsBserviceB = createServerPodAndService(f, nsB, "ns-b-server-b", []int{80})
  832. defer cleanupServerPodAndService(f, nsBpodServerB, nsBserviceB)
  833. // Wait for Server with Service in NS-A to be ready
  834. framework.Logf("Waiting for servers to be ready.")
  835. err = e2epod.WaitTimeoutForPodReadyInNamespace(f.ClientSet, podServer.Name, podServer.Namespace, framework.PodStartTimeout)
  836. framework.ExpectNoError(err, "Error occurred while waiting for pod status in namespace: Ready.")
  837. // Wait for Servers with Services in NS-B to be ready
  838. err = e2epod.WaitTimeoutForPodReadyInNamespace(f.ClientSet, nsBpodServerA.Name, nsBpodServerA.Namespace, framework.PodStartTimeout)
  839. framework.ExpectNoError(err, "Error occurred while waiting for pod status in namespace: Ready.")
  840. err = e2epod.WaitTimeoutForPodReadyInNamespace(f.ClientSet, nsBpodServerB.Name, nsBpodServerB.Namespace, framework.PodStartTimeout)
  841. framework.ExpectNoError(err, "Error occurred while waiting for pod status in namespace: Ready.")
  842. ginkgo.By("Creating a network policy for the server which allows traffic only to a server in different namespace.")
  843. protocolUDP := v1.ProtocolUDP
  844. policyAllowToServerInNSB := &networkingv1.NetworkPolicy{
  845. ObjectMeta: metav1.ObjectMeta{
  846. Namespace: nsA.Name,
  847. Name: "allow-to-ns-b-server-a-via-namespace-selector",
  848. },
  849. Spec: networkingv1.NetworkPolicySpec{
  850. // Apply this policy to the client
  851. PodSelector: metav1.LabelSelector{
  852. MatchLabels: map[string]string{
  853. "pod-name": "client-a",
  854. },
  855. },
  856. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  857. // Allow traffic only to server-a in namespace-b
  858. Egress: []networkingv1.NetworkPolicyEgressRule{
  859. {
  860. Ports: []networkingv1.NetworkPolicyPort{
  861. // Allow DNS look-ups
  862. {
  863. Protocol: &protocolUDP,
  864. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  865. },
  866. },
  867. },
  868. {
  869. To: []networkingv1.NetworkPolicyPeer{
  870. {
  871. NamespaceSelector: &metav1.LabelSelector{
  872. MatchLabels: map[string]string{
  873. "ns-name": nsBName,
  874. },
  875. },
  876. PodSelector: &metav1.LabelSelector{
  877. MatchLabels: map[string]string{
  878. "pod-name": nsBpodServerA.ObjectMeta.Labels["pod-name"],
  879. },
  880. },
  881. },
  882. },
  883. },
  884. },
  885. },
  886. }
  887. policyAllowToServerInNSB, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowToServerInNSB, metav1.CreateOptions{})
  888. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowToServerInNSB.")
  889. defer cleanupNetworkPolicy(f, policyAllowToServerInNSB)
  890. ginkgo.By("Creating client-a, in 'namespace-a', which should be able to contact the server-a in namespace-b.", func() {
  891. testCanConnect(f, nsA, "client-a", nsBserviceA, 80)
  892. })
  893. ginkgo.By("Creating client-a, in 'namespace-a', which should not be able to contact the server-b in namespace-b.", func() {
  894. testCannotConnect(f, nsA, "client-a", nsBserviceB, 80)
  895. })
  896. ginkgo.By("Creating client-a, in 'namespace-a', which should not be able to contact the server in namespace-a.", func() {
  897. testCannotConnect(f, nsA, "client-a", service, 80)
  898. })
  899. })
  900. ginkgo.It("should enforce multiple ingress policies with ingress allow-all policy taking precedence [Feature:NetworkPolicy]", func() {
  901. ginkgo.By("Creating a network policy for the server which allows traffic only from client-b.")
  902. policyAllowOnlyFromClientB := &networkingv1.NetworkPolicy{
  903. ObjectMeta: metav1.ObjectMeta{
  904. Namespace: f.Namespace.Name,
  905. Name: "allow-from-client-b-pod-selector",
  906. },
  907. Spec: networkingv1.NetworkPolicySpec{
  908. // Apply this policy to the Server
  909. PodSelector: metav1.LabelSelector{
  910. MatchLabels: map[string]string{
  911. "pod-name": podServerLabelSelector,
  912. },
  913. },
  914. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  915. // Allow traffic only from "client-b"
  916. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  917. From: []networkingv1.NetworkPolicyPeer{{
  918. PodSelector: &metav1.LabelSelector{
  919. MatchLabels: map[string]string{
  920. "pod-name": "client-b",
  921. },
  922. },
  923. }},
  924. }},
  925. },
  926. }
  927. policyAllowOnlyFromClientB, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowOnlyFromClientB, metav1.CreateOptions{})
  928. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowOnlyFromClientB.")
  929. defer cleanupNetworkPolicy(f, policyAllowOnlyFromClientB)
  930. ginkgo.By("Creating client-a which should not be able to contact the server.", func() {
  931. testCannotConnect(f, f.Namespace, "client-a", service, 80)
  932. })
  933. ginkgo.By("Creating client-b which should be able to contact the server.", func() {
  934. testCanConnect(f, f.Namespace, "client-b", service, 80)
  935. })
  936. ginkgo.By("Creating a network policy for the server which allows traffic from all clients.")
  937. policyIngressAllowAll := &networkingv1.NetworkPolicy{
  938. ObjectMeta: metav1.ObjectMeta{
  939. //Namespace: f.Namespace.Name,
  940. Name: "allow-all",
  941. },
  942. Spec: networkingv1.NetworkPolicySpec{
  943. // Apply this policy to all pods
  944. PodSelector: metav1.LabelSelector{
  945. MatchLabels: map[string]string{},
  946. },
  947. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  948. Ingress: []networkingv1.NetworkPolicyIngressRule{{}},
  949. },
  950. }
  951. policyIngressAllowAll, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyIngressAllowAll, metav1.CreateOptions{})
  952. framework.ExpectNoError(err, "Error occurred while creating policy: policyIngressAllowAll.")
  953. defer cleanupNetworkPolicy(f, policyIngressAllowAll)
  954. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  955. testCanConnect(f, f.Namespace, "client-a", service, 80)
  956. })
  957. ginkgo.By("Creating client-b which should be able to contact the server.", func() {
  958. testCanConnect(f, f.Namespace, "client-b", service, 80)
  959. })
  960. })
  961. ginkgo.It("should enforce multiple egress policies with egress allow-all policy taking precedence [Feature:NetworkPolicy]", func() {
  962. podServerB, serviceB := createServerPodAndService(f, f.Namespace, "server-b", []int{80})
  963. defer cleanupServerPodAndService(f, podServerB, serviceB)
  964. ginkgo.By("Waiting for pod ready", func() {
  965. err := f.WaitForPodReady(podServerB.Name)
  966. framework.ExpectNoError(err, "Error occurred while waiting for pod type: Ready.")
  967. })
  968. protocolUDP := v1.ProtocolUDP
  969. ginkgo.By("Creating client-a which should be able to contact the server before applying policy.", func() {
  970. testCanConnect(f, f.Namespace, "client-a", serviceB, 80)
  971. })
  972. ginkgo.By("Creating a network policy for the server which allows traffic only to server-a.")
  973. policyAllowOnlyToServerA := &networkingv1.NetworkPolicy{
  974. ObjectMeta: metav1.ObjectMeta{
  975. Namespace: f.Namespace.Name,
  976. Name: "allow-to-server-a-pod-selector",
  977. },
  978. Spec: networkingv1.NetworkPolicySpec{
  979. // Apply this policy to the "client-a"
  980. PodSelector: metav1.LabelSelector{
  981. MatchLabels: map[string]string{
  982. "pod-name": "client-a",
  983. },
  984. },
  985. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  986. // Allow traffic only to "server-a"
  987. Egress: []networkingv1.NetworkPolicyEgressRule{
  988. {
  989. Ports: []networkingv1.NetworkPolicyPort{
  990. // Allow DNS look-ups
  991. {
  992. Protocol: &protocolUDP,
  993. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  994. },
  995. },
  996. },
  997. {
  998. To: []networkingv1.NetworkPolicyPeer{
  999. {
  1000. PodSelector: &metav1.LabelSelector{
  1001. MatchLabels: map[string]string{
  1002. "pod-name": podServerLabelSelector,
  1003. },
  1004. },
  1005. },
  1006. },
  1007. },
  1008. },
  1009. },
  1010. }
  1011. policyAllowOnlyToServerA, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowOnlyToServerA, metav1.CreateOptions{})
  1012. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowOnlyToServerA.")
  1013. defer cleanupNetworkPolicy(f, policyAllowOnlyToServerA)
  1014. ginkgo.By("Creating client-a which should not be able to contact the server-b.", func() {
  1015. testCannotConnect(f, f.Namespace, "client-a", serviceB, 80)
  1016. })
  1017. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  1018. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1019. })
  1020. ginkgo.By("Creating a network policy which allows traffic to all pods.")
  1021. policyEgressAllowAll := &networkingv1.NetworkPolicy{
  1022. ObjectMeta: metav1.ObjectMeta{
  1023. Name: "allow-all",
  1024. },
  1025. Spec: networkingv1.NetworkPolicySpec{
  1026. // Apply this policy to all pods
  1027. PodSelector: metav1.LabelSelector{
  1028. MatchLabels: map[string]string{},
  1029. },
  1030. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  1031. Egress: []networkingv1.NetworkPolicyEgressRule{{}},
  1032. },
  1033. }
  1034. policyEgressAllowAll, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyEgressAllowAll, metav1.CreateOptions{})
  1035. framework.ExpectNoError(err, "Error occurred while creating policy: policyEgressAllowAll.")
  1036. defer cleanupNetworkPolicy(f, policyEgressAllowAll)
  1037. ginkgo.By("Creating client-a which should be able to contact the server-b.", func() {
  1038. testCanConnect(f, f.Namespace, "client-a", serviceB, 80)
  1039. })
  1040. ginkgo.By("Creating client-a which should be able to contact the server-a.", func() {
  1041. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1042. })
  1043. })
  1044. ginkgo.It("should stop enforcing policies after they are deleted [Feature:NetworkPolicy]", func() {
  1045. ginkgo.By("Creating a network policy for the server which denies all traffic.")
  1046. policyDenyAll := &networkingv1.NetworkPolicy{
  1047. ObjectMeta: metav1.ObjectMeta{
  1048. Namespace: f.Namespace.Name,
  1049. Name: "deny-all",
  1050. },
  1051. Spec: networkingv1.NetworkPolicySpec{
  1052. // Deny all traffic
  1053. PodSelector: metav1.LabelSelector{},
  1054. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  1055. Ingress: []networkingv1.NetworkPolicyIngressRule{},
  1056. },
  1057. }
  1058. policyDenyAll, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyDenyAll, metav1.CreateOptions{})
  1059. framework.ExpectNoError(err, "Error occurred while creating policy: policyDenyAll.")
  1060. ginkgo.By("Creating client-a which should not be able to contact the server.", func() {
  1061. testCannotConnect(f, f.Namespace, "client-a", service, 80)
  1062. })
  1063. ginkgo.By("Creating a network policy for the server which allows traffic only from client-a.")
  1064. policyAllowFromClientA := &networkingv1.NetworkPolicy{
  1065. ObjectMeta: metav1.ObjectMeta{
  1066. Namespace: f.Namespace.Name,
  1067. Name: "allow-from-client-a-pod-selector",
  1068. },
  1069. Spec: networkingv1.NetworkPolicySpec{
  1070. // Apply this policy to the Server
  1071. PodSelector: metav1.LabelSelector{
  1072. MatchLabels: map[string]string{
  1073. "pod-name": podServerLabelSelector,
  1074. },
  1075. },
  1076. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  1077. // Allow traffic from "client-a"
  1078. Ingress: []networkingv1.NetworkPolicyIngressRule{{
  1079. From: []networkingv1.NetworkPolicyPeer{{
  1080. PodSelector: &metav1.LabelSelector{
  1081. MatchLabels: map[string]string{
  1082. "pod-name": "client-a",
  1083. },
  1084. },
  1085. }},
  1086. }},
  1087. },
  1088. }
  1089. policyAllowFromClientA, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowFromClientA, metav1.CreateOptions{})
  1090. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowFromClientA.")
  1091. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  1092. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1093. })
  1094. ginkgo.By("Deleting the network policy allowing traffic from client-a")
  1095. cleanupNetworkPolicy(f, policyAllowFromClientA)
  1096. ginkgo.By("Creating client-a which should not be able to contact the server.", func() {
  1097. testCannotConnect(f, f.Namespace, "client-a", service, 80)
  1098. })
  1099. ginkgo.By("Deleting the network policy denying all traffic.")
  1100. cleanupNetworkPolicy(f, policyDenyAll)
  1101. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  1102. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1103. })
  1104. })
  1105. ginkgo.It("should allow egress access to server in CIDR block [Feature:NetworkPolicy]", func() {
  1106. var serviceB *v1.Service
  1107. var podServerB *v1.Pod
  1108. protocolUDP := v1.ProtocolUDP
  1109. // Getting podServer's status to get podServer's IP, to create the CIDR
  1110. podServerStatus, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(context.TODO(), podServer.Name, metav1.GetOptions{})
  1111. if err != nil {
  1112. framework.ExpectNoError(err, "Error occurred while getting pod status.")
  1113. }
  1114. podServerCIDR := fmt.Sprintf("%s/32", podServerStatus.Status.PodIP)
  1115. // Creating pod-b and service-b
  1116. podServerB, serviceB = createServerPodAndService(f, f.Namespace, "pod-b", []int{80})
  1117. ginkgo.By("Waiting for pod-b to be ready", func() {
  1118. err = f.WaitForPodReady(podServerB.Name)
  1119. framework.ExpectNoError(err, "Error occurred while waiting for pod type: Ready.")
  1120. })
  1121. defer cleanupServerPodAndService(f, podServerB, serviceB)
  1122. // Wait for podServerB with serviceB to be ready
  1123. err = e2epod.WaitForPodRunningInNamespace(f.ClientSet, podServerB)
  1124. framework.ExpectNoError(err, "Error occurred while waiting for pod status in namespace: Running.")
  1125. ginkgo.By("Creating client-a which should be able to contact the server-b.", func() {
  1126. testCanConnect(f, f.Namespace, "client-a", serviceB, 80)
  1127. })
  1128. policyAllowCIDR := &networkingv1.NetworkPolicy{
  1129. ObjectMeta: metav1.ObjectMeta{
  1130. Namespace: f.Namespace.Name,
  1131. Name: "allow-client-a-via-cidr-egress-rule",
  1132. },
  1133. Spec: networkingv1.NetworkPolicySpec{
  1134. // Apply this policy to the Server
  1135. PodSelector: metav1.LabelSelector{
  1136. MatchLabels: map[string]string{
  1137. "pod-name": "client-a",
  1138. },
  1139. },
  1140. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  1141. // Allow traffic to only one CIDR block.
  1142. Egress: []networkingv1.NetworkPolicyEgressRule{
  1143. {
  1144. Ports: []networkingv1.NetworkPolicyPort{
  1145. // Allow DNS look-ups
  1146. {
  1147. Protocol: &protocolUDP,
  1148. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  1149. },
  1150. },
  1151. },
  1152. {
  1153. To: []networkingv1.NetworkPolicyPeer{
  1154. {
  1155. IPBlock: &networkingv1.IPBlock{
  1156. CIDR: podServerCIDR,
  1157. },
  1158. },
  1159. },
  1160. },
  1161. },
  1162. },
  1163. }
  1164. policyAllowCIDR, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowCIDR, metav1.CreateOptions{})
  1165. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowCIDR.")
  1166. defer cleanupNetworkPolicy(f, policyAllowCIDR)
  1167. ginkgo.By("Creating client-a which should not be able to contact the server-b.", func() {
  1168. testCannotConnect(f, f.Namespace, "client-a", serviceB, 80)
  1169. })
  1170. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  1171. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1172. })
  1173. })
  1174. ginkgo.It("should enforce except clause while egress access to server in CIDR block [Feature:NetworkPolicy]", func() {
  1175. protocolUDP := v1.ProtocolUDP
  1176. // Getting podServer's status to get podServer's IP, to create the CIDR with except clause
  1177. podServerStatus, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(context.TODO(), podServer.Name, metav1.GetOptions{})
  1178. if err != nil {
  1179. framework.ExpectNoError(err, "Error occurred while getting pod status.")
  1180. }
  1181. podServerAllowCIDR := fmt.Sprintf("%s/24", podServerStatus.Status.PodIP)
  1182. // Exclude podServer's IP with an Except clause
  1183. podServerExceptList := []string{fmt.Sprintf("%s/32", podServerStatus.Status.PodIP)}
  1184. // client-a can connect to server prior to applying the NetworkPolicy
  1185. ginkgo.By("Creating client-a which should be able to contact the server.", func() {
  1186. testCanConnect(f, f.Namespace, "client-a", service, 80)
  1187. })
  1188. policyAllowCIDRWithExcept := &networkingv1.NetworkPolicy{
  1189. ObjectMeta: metav1.ObjectMeta{
  1190. Namespace: f.Namespace.Name,
  1191. Name: "deny-client-a-via-except-cidr-egress-rule",
  1192. },
  1193. Spec: networkingv1.NetworkPolicySpec{
  1194. // Apply this policy to the client.
  1195. PodSelector: metav1.LabelSelector{
  1196. MatchLabels: map[string]string{
  1197. "pod-name": "client-a",
  1198. },
  1199. },
  1200. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  1201. // Allow traffic to only one CIDR block except subnet which includes Server.
  1202. Egress: []networkingv1.NetworkPolicyEgressRule{
  1203. {
  1204. Ports: []networkingv1.NetworkPolicyPort{
  1205. // Allow DNS look-ups
  1206. {
  1207. Protocol: &protocolUDP,
  1208. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  1209. },
  1210. },
  1211. },
  1212. {
  1213. To: []networkingv1.NetworkPolicyPeer{
  1214. {
  1215. IPBlock: &networkingv1.IPBlock{
  1216. CIDR: podServerAllowCIDR,
  1217. Except: podServerExceptList,
  1218. },
  1219. },
  1220. },
  1221. },
  1222. },
  1223. },
  1224. }
  1225. policyAllowCIDRWithExcept, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowCIDRWithExcept, metav1.CreateOptions{})
  1226. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowCIDRWithExcept.")
  1227. defer cleanupNetworkPolicy(f, policyAllowCIDRWithExcept)
  1228. ginkgo.By("Creating client-a which should no longer be able to contact the server.", func() {
  1229. testCannotConnect(f, f.Namespace, "client-a", service, 80)
  1230. })
  1231. })
  1232. ginkgo.It("should enforce policies to check ingress and egress policies can be controlled independently based on PodSelector [Feature:NetworkPolicy]", func() {
  1233. var serviceA, serviceB *v1.Service
  1234. var podA, podB *v1.Pod
  1235. var err error
  1236. protocolUDP := v1.ProtocolUDP
  1237. // Before applying policy, communication should be successful between pod-a and pod-b
  1238. podA, serviceA = createServerPodAndService(f, f.Namespace, "pod-a", []int{80})
  1239. ginkgo.By("Waiting for pod-a to be ready", func() {
  1240. err = f.WaitForPodReady(podA.Name)
  1241. framework.ExpectNoError(err, "Error occurred while waiting for pod type: Ready.")
  1242. })
  1243. ginkgo.By("Creating client pod-b which should be able to contact the server pod-a.", func() {
  1244. testCanConnect(f, f.Namespace, "pod-b", serviceA, 80)
  1245. })
  1246. cleanupServerPodAndService(f, podA, serviceA)
  1247. podB, serviceB = createServerPodAndService(f, f.Namespace, "pod-b", []int{80})
  1248. ginkgo.By("Waiting for pod-b to be ready", func() {
  1249. err = f.WaitForPodReady(podB.Name)
  1250. framework.ExpectNoError(err, "Error occurred while waiting for pod type: Ready.")
  1251. })
  1252. ginkgo.By("Creating client pod-a which should be able to contact the server pod-b.", func() {
  1253. testCanConnect(f, f.Namespace, "pod-a", serviceB, 80)
  1254. })
  1255. ginkgo.By("Creating a network policy for pod-a which allows Egress traffic to pod-b.")
  1256. policyAllowToPodB := &networkingv1.NetworkPolicy{
  1257. ObjectMeta: metav1.ObjectMeta{
  1258. Namespace: f.Namespace.Name,
  1259. Name: "allow-pod-a-to-pod-b-using-pod-selector",
  1260. },
  1261. Spec: networkingv1.NetworkPolicySpec{
  1262. // Apply this policy on pod-a
  1263. PodSelector: metav1.LabelSelector{
  1264. MatchLabels: map[string]string{
  1265. "pod-name": "pod-a",
  1266. },
  1267. },
  1268. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
  1269. // Allow traffic to server on pod-b
  1270. Egress: []networkingv1.NetworkPolicyEgressRule{
  1271. {
  1272. Ports: []networkingv1.NetworkPolicyPort{
  1273. // Allow DNS look-ups
  1274. {
  1275. Protocol: &protocolUDP,
  1276. Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
  1277. },
  1278. },
  1279. },
  1280. {
  1281. To: []networkingv1.NetworkPolicyPeer{
  1282. {
  1283. PodSelector: &metav1.LabelSelector{
  1284. MatchLabels: map[string]string{
  1285. "pod-name": "pod-b",
  1286. },
  1287. },
  1288. },
  1289. },
  1290. },
  1291. },
  1292. },
  1293. }
  1294. policyAllowToPodB, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowToPodB, metav1.CreateOptions{})
  1295. framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowToPodB.")
  1296. defer cleanupNetworkPolicy(f, policyAllowToPodB)
  1297. ginkgo.By("Creating a network policy for pod-a that denies traffic from pod-b.")
  1298. policyDenyFromPodB := &networkingv1.NetworkPolicy{
  1299. ObjectMeta: metav1.ObjectMeta{
  1300. Namespace: f.Namespace.Name,
  1301. Name: "deny-pod-b-to-pod-a-pod-selector",
  1302. },
  1303. Spec: networkingv1.NetworkPolicySpec{
  1304. // Apply this policy on the server on pod-a
  1305. PodSelector: metav1.LabelSelector{
  1306. MatchLabels: map[string]string{
  1307. "pod-name": "pod-a",
  1308. },
  1309. },
  1310. PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
  1311. // Deny traffic from all pods, including pod-b
  1312. Ingress: []networkingv1.NetworkPolicyIngressRule{},
  1313. },
  1314. }
  1315. policyDenyFromPodB, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyDenyFromPodB, metav1.CreateOptions{})
  1316. framework.ExpectNoError(err, "Error occurred while creating policy: policyDenyFromPodB.")
  1317. defer cleanupNetworkPolicy(f, policyDenyFromPodB)
  1318. ginkgo.By("Creating client pod-a which should be able to contact the server pod-b.", func() {
  1319. testCanConnect(f, f.Namespace, "pod-a", serviceB, 80)
  1320. })
  1321. cleanupServerPodAndService(f, podB, serviceB)
  1322. // Creating server pod with label "pod-name": "pod-a" to deny traffic from client pod with label "pod-name": "pod-b"
  1323. podA, serviceA = createServerPodAndService(f, f.Namespace, "pod-a", []int{80})
  1324. ginkgo.By("Waiting for pod-a to be ready", func() {
  1325. err = f.WaitForPodReady(podA.Name)
  1326. framework.ExpectNoError(err, "Error occurred while waiting for pod type: Ready.")
  1327. })
  1328. ginkgo.By("Creating client pod-b which should be able to contact the server pod-a.", func() {
  1329. testCannotConnect(f, f.Namespace, "pod-b", serviceA, 80)
  1330. })
  1331. cleanupServerPodAndService(f, podA, serviceA)
  1332. })
  1333. })
  1334. })
  1335. func testCanConnect(f *framework.Framework, ns *v1.Namespace, podName string, service *v1.Service, targetPort int) {
  1336. ginkgo.By(fmt.Sprintf("Creating client pod %s that should successfully connect to %s.", podName, service.Name))
  1337. podClient := createNetworkClientPod(f, ns, podName, service, targetPort)
  1338. defer func() {
  1339. ginkgo.By(fmt.Sprintf("Cleaning up the pod %s", podClient.Name))
  1340. if err := f.ClientSet.CoreV1().Pods(ns.Name).Delete(context.TODO(), podClient.Name, nil); err != nil {
  1341. framework.Failf("unable to cleanup pod %v: %v", podClient.Name, err)
  1342. }
  1343. }()
  1344. checkConnectivity(f, ns, podClient, service)
  1345. }
  1346. func testCannotConnect(f *framework.Framework, ns *v1.Namespace, podName string, service *v1.Service, targetPort int) {
  1347. ginkgo.By(fmt.Sprintf("Creating client pod %s that should not be able to connect to %s.", podName, service.Name))
  1348. podClient := createNetworkClientPod(f, ns, podName, service, targetPort)
  1349. defer func() {
  1350. ginkgo.By(fmt.Sprintf("Cleaning up the pod %s", podClient.Name))
  1351. if err := f.ClientSet.CoreV1().Pods(ns.Name).Delete(context.TODO(), podClient.Name, nil); err != nil {
  1352. framework.Failf("unable to cleanup pod %v: %v", podClient.Name, err)
  1353. }
  1354. }()
  1355. checkNoConnectivity(f, ns, podClient, service)
  1356. }
  1357. func checkConnectivity(f *framework.Framework, ns *v1.Namespace, podClient *v1.Pod, service *v1.Service) {
  1358. framework.Logf("Waiting for %s to complete.", podClient.Name)
  1359. err := e2epod.WaitForPodNoLongerRunningInNamespace(f.ClientSet, podClient.Name, ns.Name)
  1360. framework.ExpectNoError(err, "Pod did not finish as expected.")
  1361. framework.Logf("Waiting for %s to complete.", podClient.Name)
  1362. err = e2epod.WaitForPodSuccessInNamespace(f.ClientSet, podClient.Name, ns.Name)
  1363. if err != nil {
  1364. pods, policies, logs := collectPodsAndNetworkPolicies(f, podClient)
  1365. framework.Failf("Pod %s should be able to connect to service %s, but was not able to connect.\nPod logs:\n%s\n\n Current NetworkPolicies:\n\t%v\n\n Pods:\n\t%v\n\n", podClient.Name, service.Name, logs, policies.Items, pods)
  1366. // Dump debug information for the test namespace.
  1367. framework.DumpDebugInfo(f.ClientSet, f.Namespace.Name)
  1368. }
  1369. }
  1370. func checkNoConnectivity(f *framework.Framework, ns *v1.Namespace, podClient *v1.Pod, service *v1.Service) {
  1371. framework.Logf("Waiting for %s to complete.", podClient.Name)
  1372. err := e2epod.WaitForPodSuccessInNamespace(f.ClientSet, podClient.Name, ns.Name)
  1373. // We expect an error here since it's a cannot connect test.
  1374. // Dump debug information if the error was nil.
  1375. if err == nil {
  1376. pods, policies, logs := collectPodsAndNetworkPolicies(f, podClient)
  1377. framework.Failf("Pod %s should not be able to connect to service %s, but was able to connect.\nPod logs:\n%s\n\n Current NetworkPolicies:\n\t%v\n\n Pods:\n\t %v\n\n", podClient.Name, service.Name, logs, policies.Items, pods)
  1378. // Dump debug information for the test namespace.
  1379. framework.DumpDebugInfo(f.ClientSet, f.Namespace.Name)
  1380. }
  1381. }
  1382. func checkNoConnectivityByExitCode(f *framework.Framework, ns *v1.Namespace, podClient *v1.Pod, service *v1.Service) {
  1383. err := e2epod.WaitForPodCondition(f.ClientSet, ns.Name, podClient.Name, "terminated", framework.PodStartTimeout, func(pod *v1.Pod) (bool, error) {
  1384. statuses := pod.Status.ContainerStatuses
  1385. if len(statuses) == 0 || statuses[0].State.Terminated == nil {
  1386. return false, nil
  1387. }
  1388. if statuses[0].State.Terminated.ExitCode != 0 {
  1389. return true, fmt.Errorf("pod %q container exited with code: %d", podClient.Name, statuses[0].State.Terminated.ExitCode)
  1390. }
  1391. return true, nil
  1392. })
  1393. // We expect an error here since it's a cannot connect test.
  1394. // Dump debug information if the error was nil.
  1395. if err == nil {
  1396. pods, policies, logs := collectPodsAndNetworkPolicies(f, podClient)
  1397. framework.Failf("Pod %s should not be able to connect to service %s, but was able to connect.\nPod logs:\n%s\n\n Current NetworkPolicies:\n\t%v\n\n Pods:\n\t%v\n\n", podClient.Name, service.Name, logs, policies.Items, pods)
  1398. // Dump debug information for the test namespace.
  1399. framework.DumpDebugInfo(f.ClientSet, f.Namespace.Name)
  1400. }
  1401. }
  1402. func collectPodsAndNetworkPolicies(f *framework.Framework, podClient *v1.Pod) ([]string, *networkingv1.NetworkPolicyList, string) {
  1403. // Collect pod logs when we see a failure.
  1404. logs, logErr := e2epod.GetPodLogs(f.ClientSet, f.Namespace.Name, podClient.Name, "client")
  1405. if logErr != nil {
  1406. framework.Failf("Error getting container logs: %s", logErr)
  1407. }
  1408. // Collect current NetworkPolicies applied in the test namespace.
  1409. policies, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  1410. if err != nil {
  1411. framework.Logf("error getting current NetworkPolicies for %s namespace: %s", f.Namespace.Name, err)
  1412. }
  1413. // Collect the list of pods running in the test namespace.
  1414. podsInNS, err := e2epod.GetPodsInNamespace(f.ClientSet, f.Namespace.Name, map[string]string{})
  1415. if err != nil {
  1416. framework.Logf("error getting pods for %s namespace: %s", f.Namespace.Name, err)
  1417. }
  1418. pods := []string{}
  1419. for _, p := range podsInNS {
  1420. pods = append(pods, fmt.Sprintf("Pod: %s, Status: %s\n", p.Name, p.Status.String()))
  1421. }
  1422. return pods, policies, logs
  1423. }
  1424. // Create a server pod with a listening container for each port in ports[].
  1425. // Will also assign a pod label with key: "pod-name" and label set to the given podName for later use by the network
  1426. // policy.
  1427. func createServerPodAndService(f *framework.Framework, namespace *v1.Namespace, podName string, ports []int) (*v1.Pod, *v1.Service) {
  1428. // Because we have a variable amount of ports, we'll first loop through and generate our Containers for our pod,
  1429. // and ServicePorts.for our Service.
  1430. containers := []v1.Container{}
  1431. servicePorts := []v1.ServicePort{}
  1432. for _, port := range ports {
  1433. // Build the containers for the server pod.
  1434. containers = append(containers, v1.Container{
  1435. Name: fmt.Sprintf("%s-container-%d", podName, port),
  1436. Image: imageutils.GetE2EImage(imageutils.Agnhost),
  1437. Args: []string{"porter"},
  1438. Env: []v1.EnvVar{
  1439. {
  1440. Name: fmt.Sprintf("SERVE_PORT_%d", port),
  1441. Value: "foo",
  1442. },
  1443. },
  1444. Ports: []v1.ContainerPort{
  1445. {
  1446. ContainerPort: int32(port),
  1447. Name: fmt.Sprintf("serve-%d", port),
  1448. },
  1449. },
  1450. ReadinessProbe: &v1.Probe{
  1451. Handler: v1.Handler{
  1452. HTTPGet: &v1.HTTPGetAction{
  1453. Path: "/",
  1454. Port: intstr.IntOrString{
  1455. IntVal: int32(port),
  1456. },
  1457. Scheme: v1.URISchemeHTTP,
  1458. },
  1459. },
  1460. },
  1461. })
  1462. // Build the Service Ports for the service.
  1463. servicePorts = append(servicePorts, v1.ServicePort{
  1464. Name: fmt.Sprintf("%s-%d", podName, port),
  1465. Port: int32(port),
  1466. TargetPort: intstr.FromInt(port),
  1467. })
  1468. }
  1469. ginkgo.By(fmt.Sprintf("Creating a server pod %s in namespace %s", podName, namespace.Name))
  1470. pod, err := f.ClientSet.CoreV1().Pods(namespace.Name).Create(context.TODO(), &v1.Pod{
  1471. ObjectMeta: metav1.ObjectMeta{
  1472. GenerateName: podName + "-",
  1473. Labels: map[string]string{
  1474. "pod-name": podName,
  1475. },
  1476. },
  1477. Spec: v1.PodSpec{
  1478. Containers: containers,
  1479. RestartPolicy: v1.RestartPolicyNever,
  1480. },
  1481. }, metav1.CreateOptions{})
  1482. framework.ExpectNoError(err)
  1483. framework.Logf("Created pod %v", pod.ObjectMeta.Name)
  1484. svcName := fmt.Sprintf("svc-%s", podName)
  1485. ginkgo.By(fmt.Sprintf("Creating a service %s for pod %s in namespace %s", svcName, podName, namespace.Name))
  1486. svc, err := f.ClientSet.CoreV1().Services(namespace.Name).Create(context.TODO(), &v1.Service{
  1487. ObjectMeta: metav1.ObjectMeta{
  1488. Name: svcName,
  1489. },
  1490. Spec: v1.ServiceSpec{
  1491. Ports: servicePorts,
  1492. Selector: map[string]string{
  1493. "pod-name": podName,
  1494. },
  1495. },
  1496. }, metav1.CreateOptions{})
  1497. framework.ExpectNoError(err)
  1498. framework.Logf("Created service %s", svc.Name)
  1499. return pod, svc
  1500. }
  1501. func cleanupServerPodAndService(f *framework.Framework, pod *v1.Pod, service *v1.Service) {
  1502. ginkgo.By("Cleaning up the server.")
  1503. if err := f.ClientSet.CoreV1().Pods(pod.Namespace).Delete(context.TODO(), pod.Name, nil); err != nil {
  1504. framework.Failf("unable to cleanup pod %v: %v", pod.Name, err)
  1505. }
  1506. ginkgo.By("Cleaning up the server's service.")
  1507. if err := f.ClientSet.CoreV1().Services(service.Namespace).Delete(context.TODO(), service.Name, nil); err != nil {
  1508. framework.Failf("unable to cleanup svc %v: %v", service.Name, err)
  1509. }
  1510. }
  1511. // Create a client pod which will attempt a netcat to the provided service, on the specified port.
  1512. // This client will attempt a one-shot connection, then die, without restarting the pod.
  1513. // Test can then be asserted based on whether the pod quit with an error or not.
  1514. func createNetworkClientPod(f *framework.Framework, namespace *v1.Namespace, podName string, targetService *v1.Service, targetPort int) *v1.Pod {
  1515. return createNetworkClientPodWithRestartPolicy(f, namespace, podName, targetService, targetPort, v1.RestartPolicyNever)
  1516. }
  1517. // Create a client pod which will attempt a netcat to the provided service, on the specified port.
  1518. // It is similar to createNetworkClientPod but supports specifying RestartPolicy.
  1519. func createNetworkClientPodWithRestartPolicy(f *framework.Framework, namespace *v1.Namespace, podName string, targetService *v1.Service, targetPort int, restartPolicy v1.RestartPolicy) *v1.Pod {
  1520. pod, err := f.ClientSet.CoreV1().Pods(namespace.Name).Create(context.TODO(), &v1.Pod{
  1521. ObjectMeta: metav1.ObjectMeta{
  1522. GenerateName: podName + "-",
  1523. Labels: map[string]string{
  1524. "pod-name": podName,
  1525. },
  1526. },
  1527. Spec: v1.PodSpec{
  1528. RestartPolicy: restartPolicy,
  1529. Containers: []v1.Container{
  1530. {
  1531. Name: "client",
  1532. Image: imageutils.GetE2EImage(imageutils.BusyBox),
  1533. Args: []string{
  1534. "/bin/sh",
  1535. "-c",
  1536. fmt.Sprintf("for i in $(seq 1 5); do nc -vz -w 8 %s.%s %d && exit 0 || sleep 1; done; exit 1",
  1537. targetService.Name, targetService.Namespace, targetPort),
  1538. },
  1539. },
  1540. },
  1541. },
  1542. }, metav1.CreateOptions{})
  1543. framework.ExpectNoError(err)
  1544. return pod
  1545. }
  1546. // Patch pod with a map value
  1547. func updatePodLabel(f *framework.Framework, namespace *v1.Namespace, podName string, patchOperation string, patchPath string, patchValue map[string]string) *v1.Pod {
  1548. type patchMapValue struct {
  1549. Op string `json:"op"`
  1550. Path string `json:"path"`
  1551. Value map[string]string `json:"value,omitempty"`
  1552. }
  1553. payload := []patchMapValue{{
  1554. Op: patchOperation,
  1555. Path: patchPath,
  1556. Value: patchValue,
  1557. }}
  1558. payloadBytes, err := json.Marshal(payload)
  1559. framework.ExpectNoError(err)
  1560. pod, err := f.ClientSet.CoreV1().Pods(namespace.Name).Patch(context.TODO(), podName, types.JSONPatchType, payloadBytes, metav1.PatchOptions{})
  1561. framework.ExpectNoError(err)
  1562. return pod
  1563. }
  1564. func cleanupNetworkPolicy(f *framework.Framework, policy *networkingv1.NetworkPolicy) {
  1565. ginkgo.By("Cleaning up the policy.")
  1566. if err := f.ClientSet.NetworkingV1().NetworkPolicies(policy.Namespace).Delete(context.TODO(), policy.Name, nil); err != nil {
  1567. framework.Failf("unable to cleanup policy %v: %v", policy.Name, err)
  1568. }
  1569. }