I'm interested in using a singleuser pod NetworkPolicy to limit egress. The use-case I have in mind is providing a public but very locked-down jupyterhub deployment to give people a taster with minimal barriers, and to provide full access behind a second authenticated deployment.
I found a related discussion on https://github.com/jupyterhub/mybinder.org-deploy/issues/146 and can see pros and cons to including it in this chart:
If you think it's worthwhile here's a proposal:
singleuser:
networkPolicy:
ingress:
- List of ingress rules from https://kubernetes.io/docs/concepts/services-networking/network-policies/
egress:
- List of egress rules from https://kubernetes.io/docs/concepts/services-networking/network-policies/
applied to
podSelector:
matchLabels:
app: jupyterhub
component: singleuser-server
I 100% think we should apply network policies here.
The one thing I was bitten by in jupyterhub/mybinder.org-deploy#146 is that kubernetes doesn't check at all for using unsupported features, so you can happily load an egress network policy that is completely ignored without any warnings or errors. I haven't checked in a bit, but I assume gke-1.9 will have sufficiently recent calico (>= 2.6.1) to enable egress policies.
We should start by sketching out a network policy of who needs to talk to whom, and what the default should be. To get started:
ingress:
egress:
Figuring out the right labeling scheme / default policies for that would be great!
Thanks, I'll try and come up with something. A barrier I've already run into is that the DNS server is in the kube-system namespace so the obvious thing is to allow egress to port 53 in kube-system, however namespaceSelector only works on labels, and at least on my cluster namespaces are unlabelled. Best I've come up with is to allow UDP/53 egress to anywhere.
This is what I've come up with so far based on @minrk's outline: https://gist.github.com/manics/ccc96169e4ce22f4cf434c7c7f9b9630
I've been testing on openstack (deployed with kubespray, canal network plugin)
This is great, since I need something like this for a course starting in a month :D
I agree this belongs in z2jh. I think the only knob we should turn to begin with is 'who can single-user server talk to?', since you might have plenty of other in-cluster services that you might wanna expose to the singleuser server.
What you have sounds like a good start, @manics!
@manics awesome! Feel free to make a PR with what you have, and we can iron it out.
My only question based on your gist is about best practices in terms of how to organize the information: when giving pods access to the proxy, should we be putting those pods in the proxy's network policy explicitly, or should we be using a single label like 'proxy-api-access' in the network policy and applying that label to all of the pods that need access?
i.e. when granting a new pod access to the proxy, do I modify the pod's labels, or the proxy's network policy? It seems like the former makes the most sense for ingress. I'm not sure if egress is best treated the same or not.
I think ingress is fairly easy policy:
Egress is definitely going to be more complicated, so I suggest we tackle ingress first and then go from there?
Thanks for the feedback, I'll open a PR today/tomorrow.
@manics @minrk @yuvipanda awesome!!! I learned a lot by reading this thread!
@manics I think the pod will talk to the k8s-api through kube-proxy pods (one per node), so if we manage to target that we are good I think. Also I think they communicate with HTTP by default.
Name: kube-proxy-gke-jupyter-se-cpu1-core-pool-08ec0c9f-ps6x
Namespace: kube-system
Node: gke-jupyter-se-cpu1-core-pool-08ec0c9f-ps6x/10.156.0.2
Start Time: Tue, 03 Apr 2018 03:55:00 +0200
Labels: component=kube-proxy
tier=node
Annotations: kubernetes.io/config.hash=52dadc5e78a1031dc12599fa181e4548
kubernetes.io/config.mirror=52dadc5e78a1031dc12599fa181e4548
kubernetes.io/config.seen=2018-04-03T01:54:55.691951702Z
kubernetes.io/config.source=file
scheduler.alpha.kubernetes.io/critical-pod=
Status: Running
IP: 10.156.0.2
Containers:
kube-proxy:
Container ID: docker://f8c76cadebfa4c5a4bf588a4ea875624c80cce6b04dbab2fabd6a74f8e095e3c
Image: gcr.io/google_containers/kube-proxy:v1.9.4-gke.1
Image ID: docker://sha256:6c8f7ef27e17f23e30691157b7b713d4032acc6bc04a8657082a26979559995b
Port: <none>
Command:
/bin/sh
-c
exec kube-proxy --master=https://35.198.66.16 --kubeconfig=/var/lib/kube-proxy/kubeconfig --cluster-cidr=10.16.0.0/14 --resource-container="" --oom-score-adj=-998 --v=2 --feature-gates=ExperimentalCriticalPodAnnotation=true --iptables-sync-period=1m --iptables-min-sync-period=10s --ipvs-sync-period=1m --ipvs-min-sync-period=10s 1>>/var/log/kube-proxy.log 2>&1