github.com/zhyoulun/cilium@v1.6.12/test/k8sT/KafkaPolicies.go (about)

     1  // Copyright 2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package k8sTest
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/cilium/cilium/api/v1/models"
    23  	. "github.com/cilium/cilium/test/ginkgo-ext"
    24  	"github.com/cilium/cilium/test/helpers"
    25  
    26  	. "github.com/onsi/gomega"
    27  )
    28  
    29  var _ = Describe("K8sKafkaPolicyTest", func() {
    30  
    31  	var (
    32  		kubectl             *helpers.Kubectl
    33  		microscopeErr       error
    34  		microscopeCancel                       = func() error { return nil }
    35  		backgroundCancel    context.CancelFunc = func() { return }
    36  		backgroundError     error
    37  		l7Policy            = helpers.ManifestGet("kafka-sw-security-policy.yaml")
    38  		demoPath            = helpers.ManifestGet("kafka-sw-app.yaml")
    39  		kafkaApp            = "kafka"
    40  		backupApp           = "empire-backup"
    41  		empireHqApp         = "empire-hq"
    42  		outpostApp          = "empire-outpost"
    43  		apps                = []string{kafkaApp, backupApp, empireHqApp, outpostApp}
    44  		appPods             = map[string]string{}
    45  		topicEmpireAnnounce = "empire-announce"
    46  		topicDeathstarPlans = "deathstar-plans"
    47  		topicTest           = "test-topic"
    48  
    49  		prodHqAnnounce    = `sh -c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
    50  		conOutpostAnnoune = `sh -c "./kafka-consume.sh --topic empire-announce --from-beginning --max-messages 1"`
    51  		prodHqDeathStar   = `sh -c "echo 'deathstar reactor design v3' | ./kafka-produce.sh --topic deathstar-plans"`
    52  		conOutDeathStar   = `sh -c "./kafka-consume.sh --topic deathstar-plans --from-beginning --max-messages 1"`
    53  		prodBackAnnounce  = `sh -c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
    54  		prodOutAnnounce   = `sh -c "echo 'Vader Booed at Empire Karaoke Party' | ./kafka-produce.sh --topic empire-announce"`
    55  	)
    56  
    57  	AfterFailed(func() {
    58  		kubectl.CiliumReport(helpers.KubeSystemNamespace,
    59  			"cilium service list",
    60  			"cilium endpoint list")
    61  	})
    62  
    63  	AfterAll(func() {
    64  		kubectl.CloseSSHClient()
    65  	})
    66  
    67  	Context("Kafka Policy Tests", func() {
    68  		createTopicCmd := func(topic string) string {
    69  			return fmt.Sprintf("/opt/kafka_2.11-0.10.1.0/bin/kafka-topics.sh --create "+
    70  				"--zookeeper localhost:2181 --replication-factor 1 "+
    71  				"--partitions 1 --topic %s", topic)
    72  		}
    73  
    74  		createTopic := func(topic string, pod string) error {
    75  			return kubectl.ExecKafkaPodCmd(helpers.DefaultNamespace, pod, createTopicCmd(topic))
    76  		}
    77  
    78  		// WaitKafkaBroker waits for the broker to be ready, by executing
    79  		// a command repeatedly until it succeeds, or a timeout occurs
    80  		waitForKafkaBroker := func(pod string, cmd string) error {
    81  			body := func() bool {
    82  				err := kubectl.ExecKafkaPodCmd(helpers.DefaultNamespace, pod, cmd)
    83  				if err != nil {
    84  					return false
    85  				}
    86  				return true
    87  			}
    88  			err := helpers.WithTimeout(body, "Kafka Broker not ready", &helpers.TimeoutConfig{Timeout: helpers.HelperTimeout})
    89  			return err
    90  		}
    91  
    92  		waitForDNSResolution := func(pod, service string) error {
    93  			body := func() bool {
    94  				dnsLookupCmd := fmt.Sprintf("nslookup %s", service)
    95  				res := kubectl.ExecPodCmd(helpers.DefaultNamespace, pod, dnsLookupCmd)
    96  
    97  				if !res.WasSuccessful() {
    98  					return false
    99  				}
   100  				return true
   101  			}
   102  			err := helpers.WithTimeout(body, fmt.Sprintf("unable to resolve DNS for service %s in pod %s", service, pod), &helpers.TimeoutConfig{Timeout: 30 * time.Second})
   103  			return err
   104  		}
   105  
   106  		JustBeforeEach(func() {
   107  			microscopeErr, microscopeCancel = kubectl.MicroscopeStart()
   108  			Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")
   109  
   110  			backgroundCancel, backgroundError = kubectl.BackgroundReport("uptime")
   111  			Expect(backgroundError).To(BeNil(), "Cannot start background report process")
   112  		})
   113  
   114  		JustAfterEach(func() {
   115  			kubectl.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration)
   116  			Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")
   117  			backgroundCancel()
   118  		})
   119  
   120  		AfterEach(func() {
   121  			// On aftereach don't make assertions to delete all.
   122  			_ = kubectl.Delete(demoPath)
   123  			_ = kubectl.Delete(l7Policy)
   124  
   125  			ExpectAllPodsTerminated(kubectl)
   126  		})
   127  
   128  		BeforeAll(func() {
   129  			kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)
   130  			DeployCiliumAndDNS(kubectl)
   131  
   132  			kubectl.ApplyDefault(demoPath)
   133  			err := kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=kafkaTestApp", helpers.HelperTimeout)
   134  			Expect(err).Should(BeNil(), "Kafka Pods are not ready after timeout")
   135  
   136  			err = kubectl.WaitForKubeDNSEntry("kafka-service", helpers.DefaultNamespace)
   137  			Expect(err).To(BeNil(), "DNS entry of kafka-service is not ready after timeout")
   138  
   139  			err = kubectl.CiliumEndpointWaitReady()
   140  			Expect(err).To(BeNil(), "Endpoints are not ready after timeout")
   141  
   142  			appPods = helpers.GetAppPods(apps, helpers.DefaultNamespace, kubectl, "app")
   143  
   144  			By("Wait for Kafka broker to be up")
   145  			err = waitForKafkaBroker(appPods[kafkaApp], createTopicCmd(topicTest))
   146  			Expect(err).To(BeNil(), "Timeout: Kafka cluster failed to come up correctly")
   147  		})
   148  
   149  		It("KafkaPolicies", func() {
   150  			By("Creating new kafka topic %s", topicEmpireAnnounce)
   151  			err := createTopic(topicEmpireAnnounce, appPods[kafkaApp])
   152  			Expect(err).Should(BeNil(), "Failed to create topic empire-announce")
   153  
   154  			By("Creating new kafka topic %s", topicDeathstarPlans)
   155  			err = createTopic(topicDeathstarPlans, appPods[kafkaApp])
   156  			Expect(err).Should(BeNil(), "Failed to create topic deathstar-plans")
   157  
   158  			By("Waiting for DNS to resolve within pods for kafka-service")
   159  			err = waitForDNSResolution(appPods[empireHqApp], "kafka-service")
   160  			Expect(err).Should(BeNil(), "Failed to resolve kafka-service DNS entry in pod %s", appPods[empireHqApp])
   161  			err = waitForDNSResolution(appPods[outpostApp], "kafka-service")
   162  			Expect(err).Should(BeNil(), "Failed to resolve kafka-service DNS entry in pod %s", appPods[outpostApp])
   163  
   164  			By("Testing basic Kafka Produce and Consume")
   165  			// We need to produce first, since consumer script waits for
   166  			// some messages to be already there by the producer.
   167  
   168  			err = kubectl.ExecKafkaPodCmd(
   169  				helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
   170  			Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")
   171  
   172  			err = kubectl.ExecKafkaPodCmd(
   173  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
   174  			Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")
   175  
   176  			err = kubectl.ExecKafkaPodCmd(
   177  				helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
   178  			Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic deathstar-plans")
   179  
   180  			err = kubectl.ExecKafkaPodCmd(
   181  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
   182  			Expect(err).Should(BeNil(), "Failed to consume from outpost on topic deathstar-plans")
   183  
   184  			err = kubectl.ExecKafkaPodCmd(
   185  				helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
   186  			Expect(err).Should(BeNil(), "Failed to produce to backup on topic empire-announce")
   187  
   188  			err = kubectl.ExecKafkaPodCmd(
   189  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
   190  			Expect(err).Should(BeNil(), "Failed to produce to outpost on topic empire-announce")
   191  
   192  			By("Apply L7 kafka policy and wait")
   193  
   194  			_, err = kubectl.CiliumPolicyAction(
   195  				helpers.DefaultNamespace, l7Policy,
   196  				helpers.KubectlApply, helpers.HelperTimeout)
   197  			Expect(err).To(BeNil(), "L7 policy cannot be imported correctly")
   198  
   199  			By("validate that CEP is updated with correct enforcement mode")
   200  
   201  			desiredPolicyStatus := map[string]models.EndpointPolicyEnabled{
   202  				backupApp:   models.EndpointPolicyEnabledNone,
   203  				empireHqApp: models.EndpointPolicyEnabledNone,
   204  				kafkaApp:    models.EndpointPolicyEnabledBoth,
   205  				outpostApp:  models.EndpointPolicyEnabledNone,
   206  			}
   207  
   208  			body := func() bool {
   209  				for app, policy := range desiredPolicyStatus {
   210  					cep := kubectl.CepGet(helpers.DefaultNamespace, appPods[app])
   211  					if cep == nil {
   212  						return false
   213  					}
   214  					state := models.EndpointPolicyEnabledNone
   215  					switch {
   216  					case cep.Policy.Egress.Enforcing && cep.Policy.Ingress.Enforcing:
   217  						state = models.EndpointPolicyEnabledBoth
   218  					case cep.Policy.Egress.Enforcing:
   219  						state = models.EndpointPolicyEnabledIngress
   220  					case cep.Policy.Ingress.Enforcing:
   221  						state = models.EndpointPolicyEnabledEgress
   222  					}
   223  
   224  					if state != policy {
   225  						return false
   226  					}
   227  				}
   228  				return true
   229  			}
   230  			err = helpers.WithTimeout(body, "CEP policy enforcement", &helpers.TimeoutConfig{Timeout: helpers.HelperTimeout})
   231  			Expect(err).To(BeNil(), "CEP not updated with correct policy enforcement")
   232  
   233  			By("Testing Kafka L7 policy enforcement status")
   234  			err = kubectl.ExecKafkaPodCmd(
   235  				helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
   236  			Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")
   237  
   238  			err = kubectl.ExecKafkaPodCmd(
   239  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
   240  			Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")
   241  
   242  			err = kubectl.ExecKafkaPodCmd(
   243  				helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
   244  			Expect(err).Should(BeNil(), "Failed to produce from empire-hq on topic deathstar-plans")
   245  
   246  			err = kubectl.ExecKafkaPodCmd(
   247  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
   248  			Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")
   249  
   250  			err = kubectl.ExecKafkaPodCmd(
   251  				helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
   252  			Expect(err).Should(HaveOccurred(), " Produce to backup on topic empire-announce should have been denied")
   253  
   254  			err = kubectl.ExecKafkaPodCmd(
   255  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
   256  			Expect(err).Should(HaveOccurred(), " Consume from outpost on topic deathstar-plans should have been denied")
   257  
   258  			err = kubectl.ExecKafkaPodCmd(
   259  				helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
   260  			Expect(err).Should(HaveOccurred(), "Produce to outpost on topic empire-announce should have been denied")
   261  		})
   262  	})
   263  })