diff --git a/k8s/netpol-allow-testcurl-for-testweb.yaml b/k8s/netpol-allow-testcurl-for-testweb.yaml new file mode 100644 index 00000000..c0a73f13 --- /dev/null +++ b/k8s/netpol-allow-testcurl-for-testweb.yaml @@ -0,0 +1,14 @@ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: allow-testcurl-for-testweb +spec: + podSelector: + matchLabels: + run: testweb + ingress: + - from: + - podSelector: + matchLabels: + run: testcurl + diff --git a/k8s/netpol-deny-all-for-testweb.yaml b/k8s/netpol-deny-all-for-testweb.yaml new file mode 100644 index 00000000..e975991c --- /dev/null +++ b/k8s/netpol-deny-all-for-testweb.yaml @@ -0,0 +1,10 @@ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: deny-all-for-testweb +spec: + podSelector: + matchLabels: + run: testweb + ingress: [] + diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index 98b0803b..173668d8 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -38,10 +38,11 @@ chapters: - - k8s/kubectlscale.md - k8s/daemonset.md - k8s/rollout.md - #- k8s/logs-cli.md - #- k8s/logs-centralized.md - #- k8s/helm.md - #- k8s/namespaces.md + - k8s/logs-cli.md + - k8s/logs-centralized.md + - k8s/helm.md + - k8s/namespaces.md + - k8s/netpol.md - k8s/whatsnext.md - k8s/links.md - shared/thankyou.md diff --git a/slides/kube-halfday.yml b/slides/kube-halfday.yml index 01b9dd86..9df37a3c 100644 --- a/slides/kube-halfday.yml +++ b/slides/kube-halfday.yml @@ -42,9 +42,11 @@ chapters: - k8s/rollout.md - - k8s/logs-cli.md # Bridget hasn't added EFK yet +<<<<<<< HEAD #- k8s/logs-centralized.md - k8s/helm.md - k8s/namespaces.md + #- k8s/netpol.md - k8s/whatsnext.md # - k8s/links.md # Bridget-specific diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index 190af30a..00f7f97f 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -41,6 +41,7 @@ chapters: - k8s/logs-centralized.md - k8s/helm.md - k8s/namespaces.md + - k8s/netpol.md - k8s/whatsnext.md - k8s/links.md - shared/thankyou.md diff --git a/slides/kube/netpol.md b/slides/kube/netpol.md new file mode 100644 index 00000000..a29739a6 --- /dev/null +++ b/slides/kube/netpol.md @@ -0,0 +1,235 @@ +# Network policies + +- Namespaces help us to *organize* resources + +- Namespaces do not provide isolation + +- By default, every pod can contact every other pod + +- By default, every service accepts traffic from anyone + +- If we want this to be different, we need *network policies* + +--- + +## What's a network policy? + +A network policy is defined by the following things. + +- A *pod selector* indicating which pods it applies to + + e.g.: "all pods in namespace `blue` with the label `zone=internal`" + +- A list of *ingress rules* indicating which inbound traffic is allowed + + e.g.: "TCP connections to ports 8000 and 8080 coming from pods with label `zone=dmz`, + and from the external subnet 4.42.6.0/24, except 4.42.6.5" + +- A list of *egress rules* indicating which outbound traffic is allowed + +A network policy can provide ingress rules, egress rules, or both. + +--- + +## How do network policies apply? + +- A pod can be "selected" by any number of network policies + +- If a pod isn't selected by any network policy, then its traffic is unrestricted + + (Except if it's traffic to/from another pod, which itself is selected and restricted) + +- If a pod is selected by at least one network policy, then all traffic is blocked ... + + ... unless it is explicitly allowed by one of these network policies + +Note: that logic applies separately to ingress and egress traffic. + +If a pod is selected by network policies that only specify ingress rules, +
then egress traffic for that pod is unrestricted. + +--- + +## The rationale for network policies + +- In network security, it is generally considered better to "deny all, then allow selectively" + + (The other approach, "allow all, then block selectively" makes it too easy to leave holes) + +- As soon as one network policy selects a pod, the pod enters this "deny all" logic + +- Further network policies can open additional access + +- Good network policies should be scoped as precisely as possible + +- In particular: make sure that the selector is not too broad + + (Otherwise, you end up affecting pods that were otherwise well secured) + +--- + +## Our first network policy + +This is our game plan: + +- run a web server in a pod + +- create a network policy to block all access to the web server + +- create another network policy to allow access only from specific pods + +--- + +## Running our test web server + +.exercise[ + +- Let's use the `nginx` image: + ```bash + kubectl run testweb --image=nginx + ``` + +- Find out the IP address of the pod with one of these two commands: + ```bash + kubectl get pods -o wide -l run=testweb + IP=$(kubectl get pods -l run=testweb -o json | jq -r .items[0].status.podIP) + ``` + +- Check that we can connect to the server: + ```bash + curl $IP + ``` +] + +The `curl` command should show us the "Welcome to nginx!" page. + +--- + +## Adding a very restrictive network policy + +- The policy will select pods with the label `run=testweb` + +- It will specify an empty list of ingress rules (matching nothing) + +.exercise[ + +- Apply the policy in this YAML file: + ```bash + kubectl apply -f ~/container.training/k8s/netpol-deny-all-for-testweb.yaml + ``` + +- Check if we can still access the server: + ```bash + curl $IP + ``` + +] + +The `curl` command should now time out. + +--- + +## Looking at the network policy + +This is the file that we applied: + +```yaml +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: deny-all-for-testweb +spec: + podSelector: + matchLabels: + run: testweb + ingress: [] +``` + +--- + +## Allowing connections only from specific pods + +- We want to allow traffic from pods with the label `run=testcurl` + +- Reminder: this label is automatically applied when we do `kubectl run testcurl ...` + +.exercise[ + +- Apply another policy: + ```bash + kubectl apply -f ~/container.training/netpol-allow-testcurl-for-testweb.yaml + ``` + +] + +--- + +## Looking at the network policy + +This is the second file that we applied: + +```yaml +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: allow-testcurl-for-testweb +spec: + podSelector: + matchLabels: + run: testweb + ingress: + - from: + - podSelector: + matchLabels: + run: testcurl +``` + +--- + +## Testing the network policy + +- Let's create pods with, and without, the required label + +.exercise[ + +- Try to connect to testweb from a pod with the `run=testcurl` label: + ```bash + kubectl run testcurl --rm -i --image=centos -- curl -m3 $IP + ``` + +- Try to connect to testweb with a different label: + ```bash + kubectl run testkurl --rm -i --image=centos -- curl -m3 $IP + ``` + +] + +The first command will work (and show the "Welcome to nginx!" page). + +The second command will fail and time out after 3 seconds. + +(The timeout is obtained with the `-m3` option.) + +--- + +## An important warning + +- Some network plugins only have partial support for network policies + +- For instance, Weave [doesn't support ipBlock (yet)](https://github.com/weaveworks/weave/issues/3168) + +- Weave added support for egress rules [in version 2.4](https://github.com/weaveworks/weave/pull/3313) (released in July 2018) + +- Unsupported features might be silently ignored + + (Making you believe that you are secure, when you're not) + +--- + +## Further resources + +- As always, the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/network-policies/) is a good starting point + +- [Ahmet Alp Balkan](https://ahmet.im/) delivered a [very good talk about network policies](https://www.youtube.com/watch?list=PLj6h78yzYM2P-3-xqvmWaZbbI1sW-ulZb&v=3gGpMmYeEO8) at KubeCon + +- He also compiled some [ready-to-use recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes) for network policies