traefik-library-image icon indicating copy to clipboard operation
traefik-library-image copied to clipboard

Allow traefik to bind to service ports when not running as root

Open jochenseeber opened this issue 1 year ago • 5 comments

Description

This pull request allows Traefik to bind to service ports (< port number 1024) by setting cap_net_bind_service on the Traefik binary.

This allows to start Traefik as non-root user in Kubernetes and drop all capabilities except NET_BIND_SERVICE, e.g. using the following securityContext:

      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        runAsNonRoot: true
        capabilities:
          drop: [ALL]
          add: [NET_BIND_SERVICE]

This feature has been requested multiple times, e.g.:

and would allow us to run Traefik in a more secure way

Background

There has been some discussion that adding NET_BIND_SERVICE is enough to achieve this, and the image need not be changed. However, this is not sufficient. In order to work correctly, the capability has to be added to the Pod in Kubernetes and also be set on the binary with setcap.

jochenseeber avatar Jan 22 '24 14:01 jochenseeber

Default kubernetes install with chart is already non-root and secured on pod level with

        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true

and on deployment level with:

      securityContext:
        runAsGroup: 65532
        runAsNonRoot: true
        runAsUser: 65532

=> @jochenseeber It's already read-only, non-root and drop all capabilities. Would you please detail your use case ?

mloiseleur avatar Jun 19 '24 15:06 mloiseleur

=> @jochenseeber It's already read-only, non-root and drop all capabilities. Would you please detail your use case ?

Yes, and when running it and trying to bind to a service port (<1024) it fails. Setting capability NET_BIND_SERVICE on the traefik binary in the image allows the non-root traefik to successfully bind to e.g. port 80 or 443.

jochenseeber avatar Jun 21 '24 13:06 jochenseeber

Yes, and when running it and trying to bind to a service port (<1024) it fails.

:thinking: Mmmh ... :thinking: I'm not sure I follow. Default install with the Chart listen on tcp/80 and tcp/443 using a (LoadBalancer) Service with ports (<1024) on this Service. On the pod level, ports are > 1024, allowing to drop all capabilities by default.

I understand why it fails but I do not understand how it can be more secure by adding a capability requirement when it can run without any.

mloiseleur avatar Jun 21 '24 15:06 mloiseleur

Our use case is to run Traefik as DaemonSet and have the pod bind directly to ports 80 & 443. Binding directly simplifies our network setup -- no need to do DNAT & very simple to create stateless firewall rules.

Giving NET_BIND_SERVICE to the pod is an additional capability, but imo a negligible risk. If the pod is running behind a service it most likely only has access to an internal network interface. It probably does not matter to which port it binds on that.

To sum it up, it would enable our use case, provide a feature that has been requested by multiple other users, and imo not introduce a security risk.

jochenseeber avatar Jun 21 '24 16:06 jochenseeber

That's a very specific and un-common use case. setcap can be quite unreliable. Did you try to set with sysctl net.ipv4.ip_unprivileged_port_start to 0 ? AFAIK, it's working and far more reliable.

mloiseleur avatar Jun 24 '24 07:06 mloiseleur

Hey @jochenseeber, Thanks for your contribution. After discussing with the team, we think it's not a common practice and we don't want to enforce capabilities at the dockerfile level. Therefore, we are closing this PR.

emilevauge avatar Oct 10 '24 13:10 emilevauge