linkerd / linkerd2

Ultralight, security-first service mesh for Kubernetes. Main repo for Linkerd 2.x.
https://linkerd.io
Apache License 2.0
10.61k stars 1.27k forks source link

External/egress policy and support for enforcing network security policies and compliance #6234

Open AaronFriel opened 3 years ago

AaronFriel commented 3 years ago

Feature Request

Enable Linkerd policies to fully specify the external resources a cluster can access, a la egress gateways from Istio.

What problem are you trying to solve?

In high compliance environments, it's useful to be able to use the service mesh as part of the network security of a cluster.

Suppose I wish to have some pods interact with the GitHub API. We'll call this application our github-agent. Without using any third party tooling, those pods need port 443 outbound to be open. However, if a supply chain attack injects code into my cluster, they could phone home to any command and control (C2) node on port 443 to perform malicious acts.

A default deny policy in a namespace ensures that outbound network traffic must be authorized, but K8s network policies are layer 3 (IP address and protocol) based, and cannot enforce HTTPS or mitigate supply chain attacks such as Magecart.

A layer 7 proxy solution is needed to ensure our github-agent application can only access https://api.github.com with a valid certificate.

How should the problem be solved?

Either of the two methods seems sound to me:

  1. Client-side egress filtering

    Client-side profiles have an allowlist mode which acts as an additional layer of filtering that cannot be circumvented by application code (perhaps via the CNI Plugin and iptables rules?).

    Pros: the compute and networking overhead here is already paid for by existing sidecar containers.

    Cons: the NetworkPolicy that targets those pods will likely still need to allow port 443 egress to 0.0.0.0/0. (Is there an alternative?).

  2. Namespace or cluster-wide egress gateway

    A cluster-wide egress gateway is deployed by Linkerd which proxies requests to external services.

    Pros: Only that egress gateway needs port 443 egress.

    Cons: contrary to some of the goals of Linkerd, this creates an additional network hop and centralizes network traffic in the egress gateway(s)

Any alternatives you've considered?

In clusters I manage, I use a default deny to block all applications in the cluster from making external network requests. Then, I deploy:

This is fairly high overhead, requiring deploying 3 Kubernetes resources and modifying application code. The latter especially isn't always possible. If github-agent were a third party application, it may hardcode requests and not be configurable to use a proxy.

How would users interact with this feature?

Knobs/controls I would expect on this resource for each desired hostname:

My opinions on defaults:

The defaults therefore would result in Linkerd acting as a MITM for external resources and collecting telemetry, dropping trace headers on outbound requests.

For users with compliance needs, setting the allowlist flag would cause the sidecar to close connections to non-matching hostnames and protocols by default.

adleong commented 3 years ago

FYI some related work: https://github.com/grampelberg/k8s-egress

AaronFriel commented 3 years ago

@adleong excellent, that repo is very similar to what I'm doing.

I would rank the allowlist component of the feature (aka "block supply chain attacks" button) substantially higher than the ability to handle third party applications, but I do think this feature should be designed with a future in mind that supports adding that functionality down the road. There is one thing I forgot to mention, which is that many enterprise applications (the third party applications I mentioned above) do typically support HTTP_PROXY or HTTPS_PROXY env variables.

It looks like the Rust proxy may already work with the CONNECT method.

mogul commented 2 years ago

Other related work: Monzo's egress-operator

jume-dev commented 2 years ago

@AaronFriel Sry, for hijacking this issue, but I am interested in your solution for this:

I use a default deny to block all applications in the cluster from making external network requests

I don't have any pod that needs to talk to the internet so I want to restrict all external network requests. Can I do this with LinkerD?

limoges commented 1 year ago

@jume-dev It's been over a year since you wrote, but in the interest of readers: You cant limit all external network requests with LinkerD.

In the current state, you'd have to limit at the cluster networking layer (e.g. no routes to the outside).

btrepp commented 3 months ago

@jume-dev It's been over a year since you wrote, but in the interest of readers: You cant limit all external network requests with LinkerD.

In the current state, you'd have to limit at the cluster networking layer (e.g. no routes to the outside).

Is there any documentation on doing this?. I suspect it would be with network policy, but then you would still need linkerd to talk to it's components.

I think building your own egress pods makes sense, but at the moment I've struggled to find exactly what policies would work. You can trial and error it, but that might be kinda of tedious