cyclonus

module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2021 License: MIT

README

Cyclonus

Network policy explainer, prober, and test case generator

Parse, explain, and probe network policies to understand their implications and help design policies that suit your needs!

Quickstart

Grab the latest release to get started using Cyclonus.

Run as a kubernetes job

Take a look at the hack directory:

ls hack
antrea              calico              cilium              flannel             run-cyclonus-job.sh

Choose the right job for your CNI, then run:

cd hack/calico
./github-action.sh

This will:

  • create a namespace, service account, and cluster role binding for cyclonus
  • create a cyclonus job

Pull the logs from the job:

kubectl logs -f -n netpol cyclonus-abcde
Run from source

Assuming you have a kube cluster and your kubectl is configured to point to it, you can run:

cd cmd/cyclonus
go run main.go generate
Docker images

Images are available at mfenwick100/cyclonus:

docker pull docker.io/mfenwick100/cyclonus:latest

Integrations

krew plugin

Cyclonus is available as a krew/kubectl plugin:

  • Set up krew
  • install cyclonus through krew: kubectl krew install cyclonus
  • use cyclonus as a kubectl plugin: kubectl cyclonus -h.
Antrea testing

Cyclonus runs network policy tests for Antrea on a daily basis.

Cilium testing

Cyclonus runs network policy tests for Cilium on a daily basis.

Cyclonus functionality

Probe

Run a connectivity probe against a Kubernetes cluster.

cyclonus probe

Kube results for:
  policy y/allow-all-for-label:
  policy y/allow-by-ip:
  policy y/allow-label-to-label:
  policy y/deny-all:
  policy y/deny-all-for-label:
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|  -  | X/A | X/B | X/C | Y/A | Y/B | Y/C | Z/A | Z/B | Z/C |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| x/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| x/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| x/c | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/c | .   | .   | .   | .   | .   | X   | .   | .   | .   |
| z/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| z/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| z/c | .   | .   | .   | X   | .   | X   | .   | .   | .   |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

0 wrong, 0 no value, 81 correct, 0 ignored out of 81 total
Policy generator

For CNI conformance testing.

Generate network policy test scenarios, install the scenarios one at a time in kubernetes, and compare actual measured connectivity to expected connectivity using a truth table.

cyclonus generate \
  --mode simple-fragments \
  --include conflict,peer-ipblock \
  --ignore-loopback \
  --perturbation-wait-seconds 15

...
Tag results:
Tag Result
direction 10 / 20 = 50% ❌
- egress 5 / 11 = 45% ❌
- ingress 5 / 11 = 45% ❌
miscellaneous 10 / 16 = 62% ❌
- conflict 10 / 16 = 62% ❌
peer-ipblock 0 / 4 = 0% ❌
- IP-block-no-except 0 / 2 = 0% ❌
- IP-block-with-except 0 / 2 = 0% ❌
peer-pods 4 / 4 = 100% ✅
- all-namespaces 4 / 4 = 100% ✅
- all-pods 4 / 4 = 100% ✅
rule 6 / 8 = 75% ❌
- allow-all 2 / 4 = 50% ❌
- deny-all 6 / 8 = 75% ❌
Policy analysis
Explain policies

Groups policies by target, divides rules into egress and ingress, and gives a basic explanation of the combined policies. This clarifies the interactions between "denies" and "allows" from multiple policies.

cyclonus analyze \
  --mode explain \
  --policy-path ./networkpolicies/simple-example/

+---------+---------------+------------------------+---------------------+--------------------------+
|  TYPE   |    TARGET     |      SOURCE RULES      |        PEER         |      PORT/PROTOCOL       |
+---------+---------------+------------------------+---------------------+--------------------------+
| Ingress | namespace: y  | y/allow-label-to-label | no ips              | no ports, no protocols   |
|         | Match labels: | y/deny-all-for-label   |                     |                          |
|         |   pod: a      |                        |                     |                          |
+         +               +                        +---------------------+--------------------------+
|         |               |                        | namespace: y        | all ports, all protocols |
|         |               |                        | pods: Match labels: |                          |
|         |               |                        |   pod: c            |                          |
+         +---------------+------------------------+---------------------+                          +
|         | namespace: y  | y/allow-all-for-label  | all pods, all ips   |                          |
|         | Match labels: |                        |                     |                          |
|         |   pod: b      |                        |                     |                          |
+         +---------------+------------------------+---------------------+--------------------------+
|         | namespace: y  | y/allow-by-ip          | ports for all IPs   | no ports, no protocols   |
|         | Match labels: |                        |                     |                          |
|         |   pod: c      |                        |                     |                          |
+         +               +                        +---------------------+--------------------------+
|         |               |                        | 0.0.0.0/24          | all ports, all protocols |
|         |               |                        | except []           |                          |
|         |               |                        |                     |                          |
+         +               +                        +---------------------+--------------------------+
|         |               |                        | no pods             | no ports, no protocols   |
|         |               |                        |                     |                          |
|         |               |                        |                     |                          |
+         +---------------+------------------------+---------------------+                          +
|         | namespace: y  | y/deny-all             | no pods, no ips     |                          |
|         | all pods      |                        |                     |                          |
+---------+---------------+------------------------+---------------------+--------------------------+
Which policy rules apply to a pod?

This takes the previous command a step further: it combines the rules from all the targets that apply to a pod.

cyclonus analyze \
  --mode query-target \
  --policy-path ./networkpolicies/simple-example/ \
  --target-pod-path ./examples/targets.json

pod in ns y with labels map[pod:a]:
+---------+---------------+-----------------------------+---------------------+--------------------------+
|  TYPE   |    TARGET     |        SOURCE RULES         |        PEER         |      PORT/PROTOCOL       |
+---------+---------------+-----------------------------+---------------------+--------------------------+
| Ingress | namespace: y  | y/allow-label-to-label      | no ips              | no ports, no protocols   |
|         | Match labels: | y/deny-all-for-label        |                     |                          |
|         |   pod: a      | y/deny-all                  |                     |                          |
+         +               +                             +---------------------+--------------------------+
|         |               |                             | namespace: y        | all ports, all protocols |
|         |               |                             | pods: Match labels: |                          |
|         |               |                             |   pod: c            |                          |
+---------+---------------+-----------------------------+---------------------+--------------------------+
|         |               |                             |                     |                          |
+---------+---------------+-----------------------------+---------------------+--------------------------+
| Egress  | namespace: y  | y/deny-all-egress           | all pods, all ips   | all ports, all protocols |
|         | Match labels: | y/allow-all-egress-by-label |                     |                          |
|         |   pod: a      |                             |                     |                          |
+---------+---------------+-----------------------------+---------------------+--------------------------+
Will policies allow or block traffic?

Given arbitrary traffic examples (from a source to a destination, including labels, over a port and protocol), this command parses network policies and determines if the traffic is allowed or not.

cyclonus analyze \
  --mode query-traffic \
  --policy-path ./networkpolicies/simple-example/ \
  --traffic-path ./examples/traffic.json

Traffic:
+--------------------------+-------------+---------------+-----------+-----------+------------+
|      PORT/PROTOCOL       | SOURCE/DEST |    POD IP     | NAMESPACE | NS LABELS | POD LABELS |
+--------------------------+-------------+---------------+-----------+-----------+------------+
| 80 (serve-80-tcp) on TCP | source      | 192.168.1.99  | y         | ns: y     | app: c     |
+                          +-------------+---------------+           +           +------------+
|                          | destination | 192.168.1.100 |           |           | pod: b     |
+--------------------------+-------------+---------------+-----------+-----------+------------+

Is traffic allowed?
+-------------+--------+---------------+
|    TYPE     | ACTION |    TARGET     |
+-------------+--------+---------------+
| Ingress     | Allow  | namespace: y  |
|             |        | Match labels: |
|             |        |   pod: b      |
+             +--------+---------------+
|             | Deny   | namespace: y  |
|             |        | all pods      |
+-------------+--------+---------------+
|             |        |               |
+-------------+--------+---------------+
| Egress      | Deny   | namespace: y  |
|             |        | all pods      |
+-------------+--------+---------------+
| IS ALLOWED? | FALSE  |                
+-------------+--------+---------------+
Simulated probe

Runs a simulated connectivity probe against a set of network policies, without using a kubernetes cluster.

cyclonus analyze \
  --mode probe \
  --policy-path ./networkpolicies/simple-example/ \
  --probe-path ./examples/probe.json

Combined:
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|     | X/A | X/B | X/C | Y/A | Y/B | Y/C | Z/A | Z/B | Z/C |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| x/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| x/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| x/c | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| y/c | X   | X   | X   | X   | X   | X   | X   | X   | X   |
| z/a | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| z/b | .   | .   | .   | X   | .   | X   | .   | .   | .   |
| z/c | .   | .   | .   | X   | .   | X   | .   | .   | .   |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Linter

Checks network policies for common problems.

cyclonus analyze \
  --mode lint \
  --policy-path ./networkpolicies/simple-example

+-----------------+------------------------------+-------------------+-----------------------------+
| SOURCE/RESOLVED |             TYPE             |      TARGET       |       SOURCE POLICIES       |
+-----------------+------------------------------+-------------------+-----------------------------+
| Resolved        | CheckTargetAllEgressAllowed  | namespace: y      | y/allow-all-egress-by-label |
|                 |                              |                   |                             |
|                 |                              | pod selector:     |                             |
|                 |                              | matchExpressions: |                             |
|                 |                              | - key: pod        |                             |
|                 |                              |   operator: In    |                             |
|                 |                              |   values:         |                             |
|                 |                              |   - a             |                             |
|                 |                              |   - b             |                             |
|                 |                              |                   |                             |
+-----------------+------------------------------+-------------------+-----------------------------+
| Resolved        | CheckDNSBlockedOnTCP         | namespace: y      | y/deny-all-egress           |
|                 |                              |                   |                             |
|                 |                              | pod selector:     |                             |
|                 |                              | {}                |                             |
|                 |                              |                   |                             |
+-----------------+------------------------------+-------------------+-----------------------------+
| Resolved        | CheckDNSBlockedOnUDP         | namespace: y      | y/deny-all-egress           |
|                 |                              |                   |                             |
|                 |                              | pod selector:     |                             |
|                 |                              | {}                |                             |
|                 |                              |                   |                             |
+-----------------+------------------------------+-------------------+-----------------------------+

Developer guide

Setup
  • Get set up with golang 1.15

  • clone this repo

     git clone git@github.com:mattfenwick/cyclonus.git
     cd cyclonus
    
  • set up a KinD cluster with a CNI that supports network policies

     pushd kind/calico
     ./setup.sh
     popd
    
  • run cyclonus

     go run cmd/cyclonus/main.go generate --mode=example
    

How to Release Binaries

See goreleaser's requirements here.

Get a GitHub Personal Access Token and add the repo scope. Set GITHUB_TOKEN to this value:

export GITHUB_TOKEN=...

See here for more information on github tokens.

Choose a tag/release name, create and push a tag:

TAG=v0.0.1

git tag $TAG
git push origin $TAG

Cut a release:

goreleaser release --rm-dist

Make a test release:

goreleaser release --snapshot --rm-dist

Motivation and History

Testing network policies for CNI providers on Kubernetes has historically been very difficult, requiring a lot of boiler plate. This was recently improved upstream via truth table based tests (see KEP). Cyclonus is the next evolution of the truth table tests which are part of upstream Kubernetes. Cyclonus generates hundreds of network policies, their connectivity tables, and outputs results in the same, easy to read format.

Directories

Path Synopsis
cmd
pkg
cli

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL