github.com/imran-kn/cilium-fork@v1.6.9/Documentation/gettingstarted/kafka.rst (about)

     1  .. only:: not (epub or latex or html)
     2  
     3      WARNING: You are looking at unreleased Cilium documentation.
     4      Please use the official rendered version released here:
     5      http://docs.cilium.io
     6  
     7  .. _gs_kafka:
     8  
     9  ************************
    10  Securing a Kafka cluster
    11  ************************
    12  
    13  This document serves as an introduction to using Cilium to enforce Kafka-aware
    14  security policies.  It is a detailed walk-through of getting a single-node
    15  Cilium environment running on your machine. It is designed to take 15-30
    16  minutes.
    17  
    18  .. include:: gsg_requirements.rst
    19  
    20  Deploy the Demo Application
    21  ===========================
    22  
    23  Now that we have Cilium deployed and ``kube-dns`` operating correctly we can
    24  deploy our demo Kafka application.  Since our first demo of Cilium + HTTP-aware security
    25  policies was Star Wars-themed we decided to do the same for Kafka.  While the
    26  `HTTP-aware Cilium  Star Wars demo <https://www.cilium.io/blog/2017/5/4/demo-may-the-force-be-with-you>`_
    27  showed how the Galactic Empire used HTTP-aware security policies to protect the Death Star from the
    28  Rebel Alliance, this Kafka demo shows how the lack of Kafka-aware security policies allowed the
    29  Rebels to steal the Death Star plans in the first place.
    30  
    31  Kafka is a powerful platform for passing datastreams between different components of an application.
    32  A cluster of "Kafka brokers" connect nodes that "produce" data into a data stream, or "consume" data
    33  from a datastream.   Kafka refers to each datastream as a "topic".
    34  Because scalable and highly-available Kafka clusters are non-trivial to run, the same cluster of
    35  Kafka brokers often handles many different topics at once (read this `Introduction to Kafka
    36  <https://kafka.apache.org/intro>`_ for more background).
    37  
    38  In our simple example, the Empire uses a Kafka cluster to handle two different topics:
    39  
    40  - *empire-announce* : Used to broadcast announcements to sites spread across the galaxy
    41  - *deathstar-plans* : Used by a small group of sites coordinating on building the ultimate battlestation.
    42  
    43  To keep the setup small, we will just launch a small number of pods to represent this setup:
    44  
    45  - *kafka-broker* : A single pod running Kafka and Zookeeper representing the Kafka cluster
    46    (label app=kafka).
    47  - *empire-hq* : A pod representing the Empire's Headquarters, which is the only pod that should
    48    produce messages to *empire-announce* or *deathstar-plans* (label app=empire-hq).
    49  - *empire-backup* : A secure backup facility located in `Scarif <http://starwars.wikia.com/wiki/Scarif_vault>`_ ,
    50    which is allowed to "consume" from the secret *deathstar-plans* topic (label app=empire-backup).
    51  - *empire-outpost-8888* : A random outpost in the empire.  It needs to "consume" messages from
    52    the *empire-announce* topic (label app=empire-outpost).
    53  - *empire-outpost-9999* : Another random outpost in the empire that "consumes" messages from
    54    the *empire-announce* topic (label app=empire-outpost).
    55  
    56  All pods other than *kafka-broker* are Kafka clients, which need access to the *kafka-broker*
    57  container on TCP port 9092 in order to send Kafka protocol messages.
    58  
    59  .. image:: images/cilium_kafka_gsg_topology.png
    60  
    61  The file ``kafka-sw-app.yaml`` contains a Kubernetes Deployment for each of the pods described
    62  above, as well as a Kubernetes Service for both Kafka and Zookeeper.
    63  
    64  .. parsed-literal::
    65  
    66      $ kubectl create -f \ |SCM_WEB|\/examples/kubernetes-kafka/kafka-sw-app.yaml
    67      deployment "kafka-broker" created
    68      deployment "zookeeper" created
    69      service "zook" created
    70      service "kafka-service" created
    71      deployment "empire-hq" created
    72      deployment "empire-outpost-8888" created
    73      deployment "empire-outpost-9999" created
    74      deployment "empire-backup" created
    75  
    76  Kubernetes will deploy the pods and service  in the background.
    77  Running ``kubectl get svc,pods`` will inform you about the progress of the operation.
    78  Each pod will go through several states until it reaches ``Running`` at which
    79  point the setup is ready.
    80  
    81  ::
    82  
    83      $ kubectl get svc,pods
    84      NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    85      kafka-service   ClusterIP   None            <none>        9092/TCP   2m
    86      kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP    10m
    87      zook            ClusterIP   10.97.250.131   <none>        2181/TCP   2m
    88  
    89      NAME                                   READY     STATUS    RESTARTS   AGE
    90      empire-backup-6f4567d5fd-gcrvg         1/1       Running   0          2m
    91      empire-hq-59475b4b64-mrdww             1/1       Running   0          2m
    92      empire-outpost-8888-78dffd49fb-tnnhf   1/1       Running   0          2m
    93      empire-outpost-9999-7dd9fc5f5b-xp6jw   1/1       Running   0          2m
    94      kafka-broker-b874c78fd-jdwqf           1/1       Running   0          2m
    95      zookeeper-85f64b8cd4-nprck             1/1       Running   0          2m
    96  
    97  Setup Client Terminals
    98  ======================
    99  
   100  First we will open a set of windows to represent the different Kafka clients discussed above.
   101  For consistency, we recommend opening them in the pattern shown in the image below, but this is optional.
   102  
   103  .. image:: images/cilium_kafka_gsg_terminal_layout.png
   104  
   105  In each window, use copy-paste to have each terminal provide a shell inside each pod.
   106  
   107  empire-hq terminal:
   108  ::
   109  
   110     $ HQ_POD=$(kubectl get pods -l app=empire-hq -o jsonpath='{.items[0].metadata.name}') && kubectl exec -it $HQ_POD -- sh -c "PS1=\"empire-hq $\" /bin/bash"
   111  
   112  empire-backup terminal:
   113  ::
   114  
   115     $ BACKUP_POD=$(kubectl get pods -l app=empire-backup -o jsonpath='{.items[0].metadata.name}') && kubectl exec -it $BACKUP_POD -- sh -c "PS1=\"empire-backup $\" /bin/bash"
   116  
   117  outpost-8888 terminal:
   118  ::
   119  
   120     $ OUTPOST_8888_POD=$(kubectl get pods -l outpostid=8888 -o jsonpath='{.items[0].metadata.name}') && kubectl exec -it $OUTPOST_8888_POD -- sh -c "PS1=\"outpost-8888 $\" /bin/bash"
   121  
   122  outpost-9999 terminal:
   123  ::
   124  
   125     $ OUTPOST_9999_POD=$(kubectl get pods -l outpostid=9999 -o jsonpath='{.items[0].metadata.name}') && kubectl exec -it $OUTPOST_9999_POD -- sh -c "PS1=\"outpost-9999 $\" /bin/bash"
   126  
   127  
   128  Test Basic Kafka Produce & Consume
   129  ==================================
   130  
   131  First, let's start the consumer clients listening to their respective Kafka topics.  All of the consumer
   132  commands below will hang intentionally, waiting to print data they consume from the Kafka topic:
   133  
   134  In the *empire-backup* window, start listening on the top-secret *deathstar-plans* topic:
   135  
   136  ::
   137  
   138      $ ./kafka-consume.sh --topic deathstar-plans
   139  
   140  In the *outpost-8888* window, start listening to *empire-announcement*:
   141  
   142  ::
   143  
   144      $ ./kafka-consume.sh --topic empire-announce
   145  
   146  Do the same in the *outpost-9999* window:
   147  
   148  ::
   149  
   150      $ ./kafka-consume.sh --topic empire-announce
   151  
   152  Now from the *empire-hq*, first produce a message to the *empire-announce* topic:
   153  
   154  ::
   155  
   156     $ echo "Happy 40th Birthday to General Tagge" | ./kafka-produce.sh --topic empire-announce
   157  
   158  This message will be posted to the *empire-announce* topic, and shows up in both the *outpost-8888* and
   159  *outpost-9999* windows who consume that topic.   It will not show up in *empire-backup*.
   160  
   161  *empire-hq* can also post a version of the top-secret deathstar plans to the *deathstar-plans* topic:
   162  
   163  ::
   164  
   165     $ echo "deathstar reactor design v3" | ./kafka-produce.sh --topic deathstar-plans
   166  
   167  This message shows up in the *empire-backup* window, but not for the outposts.
   168  
   169  Congratulations, Kafka is working as expected :)
   170  
   171  The Danger of a Compromised Kafka Client
   172  ========================================
   173  
   174  But what if a rebel spy gains access to any of the remote outposts that act as Kafka clients?
   175  Since every client has access to the Kafka broker on port 9092, it can do some bad stuff.
   176  For starters, the outpost container can actually switch roles from a consumer to a producer,
   177  sending "malicious" data to all other consumers on the topic.
   178  
   179  To prove this, kill the existing ``kafka-consume.sh`` command in the outpost-9999 window
   180  by typing control-C and instead run:
   181  
   182  ::
   183  
   184    $ echo "Vader Booed at Empire Karaoke Party" | ./kafka-produce.sh --topic empire-announce
   185  
   186  Uh oh!  Outpost-8888 and all of the other outposts in the empire have now received this fake announcement.
   187  
   188  But even more nasty from a security perspective is that the outpost container can access any topic
   189  on the kafka-broker.
   190  
   191  In the outpost-9999 container, run:
   192  
   193  ::
   194  
   195    $ ./kafka-consume.sh --topic deathstar-plans
   196    "deathstar reactor design v3"
   197  
   198  We see that any outpost can actually access the secret deathstar plans.  Now we know how the rebels got
   199  access to them!
   200  
   201  Securing Access to Kafka with Cilium
   202  ====================================
   203  
   204  Obviously, it would be much more secure to limit each pod's access to the Kafka broker to be
   205  least privilege (i.e., only what is needed for the app to operate correctly and nothing more).
   206  
   207  We can do that with the following Cilium security policy.   As with Cilium HTTP policies, we can write
   208  policies that identify pods by labels, and then limit the traffic in/out of this pod.  In
   209  this case, we'll create a policy that identifies the exact traffic that should be allowed to reach the
   210  Kafka broker, and deny the rest.
   211  
   212  As an example, a policy could limit containers with label *app=empire-outpost* to only be able to consume
   213  topic *empire-announce*, but would block any attempt by a compromised container (e.g., empire-outpost-9999)
   214  from producing to *empire-announce* or consuming from *deathstar-plans*.
   215  
   216  .. image:: images/cilium_kafka_gsg_attack.png
   217  
   218  Here is the *CiliumNetworkPolicy* rule that limits access of pods with label *app=empire-outpost* to
   219  only consume on topic *empire-announce*:
   220  
   221  .. literalinclude:: ../../examples/policies/getting-started/kafka.yaml
   222  
   223  A *CiliumNetworkPolicy* contains a list of rules that define allowed requests, meaning that requests
   224  that do not match any rules are denied as invalid.
   225  
   226  The above rule applies to inbound (i.e., "ingress") connections to kafka-broker pods (as
   227  indicated by "app: kafka"
   228  in the "endpointSelector" section).  The rule will apply to connections from pods with label
   229  "app: empire-outpost" as indicated by the "fromEndpoints" section.   The rule explicitly matches
   230  Kafka connections destined to TCP 9092, and allows consume/produce actions on various topics of interest.
   231  For example we are allowing *consume* from topic *empire-announce* in this case.
   232  
   233  The full policy adds two additional rules that permit the legitimate "produce"
   234  (topic *empire-announce* and topic *deathstar-plans*) from *empire-hq* and the
   235  legitimate consume  (topic = "deathstar-plans") from *empire-backup*.  The full policy
   236  can be reviewed by opening the URL in the command below in a browser.
   237  
   238  Apply this Kafka-aware network security policy using ``kubectl`` in the main window:
   239  
   240  .. parsed-literal::
   241  
   242      $ kubectl create -f \ |SCM_WEB|\/examples/kubernetes-kafka/kafka-sw-security-policy.yaml
   243  
   244  If we then again try to produce a message from outpost-9999 to *empire-annnounce*, it is denied.
   245  Type control-c and then run:
   246  
   247  ::
   248  
   249    $ echo "Vader Trips on His Own Cape" | ./kafka-produce.sh --topic empire-announce
   250    >>[2018-04-10 23:50:34,638] ERROR Error when sending message to topic empire-announce with key: null, value: 27 bytes with error: (org.apache.kafka.clients.producer.internals.ErrorLoggingCallback)
   251    org.apache.kafka.common.errors.TopicAuthorizationException: Not authorized to access topics: [empire-announce]
   252  
   253  This is because the policy does not allow messages with role = "produce" for topic "empire-announce" from
   254  containers with label app = empire-outpost.  Its worth noting that we don't simply drop the message (which
   255  could easily be confused with a network error), but rather we respond with the Kafka access denied error
   256  (similar to how HTTP would return an error code of 403 unauthorized).
   257  
   258  Likewise, if the outpost container ever tries to consume from topic *deathstar-plans*, it is denied, as
   259  role = consume is only allowed for topic *empire-announce*.
   260  
   261  To test, from the outpost-9999 terminal, run:
   262  
   263  ::
   264  
   265    $./kafka-consume.sh --topic deathstar-plans
   266    [2018-04-10 23:51:12,956] WARN Error while fetching metadata with correlation id 2 : {deathstar-plans=TOPIC_AUTHORIZATION_FAILED} (org.apache.kafka.clients.NetworkClient)
   267  
   268  This is blocked as well, thanks to the Cilium network policy. Imagine how different things would have been if the empire had been using
   269  Cilium from the beginning!
   270  
   271  Clean Up
   272  ========
   273  
   274  You have now installed Cilium, deployed a demo app, and tested both
   275  L7 Kafka-aware network security policies.  To clean up, run:
   276  
   277  ::
   278  
   279      $ minikube delete
   280  
   281  After this, you can re-run the tutorial from Step 1.