Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traefik uses weak security settings by default #2841

Open
jameswilliams1 opened this issue Sep 19, 2020 · 8 comments · May be fixed by #2854
Open

Traefik uses weak security settings by default #2841

jameswilliams1 opened this issue Sep 19, 2020 · 8 comments · May be fixed by #2854
Labels

Comments

@jameswilliams1
Copy link
Contributor

jameswilliams1 commented Sep 19, 2020

tl;dr

Traefik is configured using its default settings leaving it more open to attacks - a few tweaks could bring it up to production standard and lower the attack surface. See this report of a site made using cookiecutter-django.

Security Issues

  • There is support for legacy tls versions that use weak security
  • The full range of ciphers are used, including older and weaker ones that have been broken already
  • There is no cipher preference: ideally websites should prefer ciphers in order of strength to ensure the weaker ones are used as an absolute last resort (or just not support them entirely)
  • There are server name indication (SNI) issues with the site - browsers that don't support SNI are served the TRAEFIK_DEFAULT_CERT which is not trusted as it is self-signed
  • Forward secrecy is not enabled properly - this means an attacker who breaks through any tls ciphers can also decode previous messages made to the site
  • The 'server' HTTP header from the site reveals the exact version of gunicorn being used, the same issue is present with Tornado on the Flower UI
  • The current security settings are not used in the Flower UI as they are set using Django, not Traefik

Fixes needed

  • Remove support for TLS <1.2 (this affects only very, very old browsers which probably arent supported by bootstrap/other libs anyway)
  • Reduce the range of ciphers used to only the strongest ones
  • Set server preference for the strongest ciphers
  • Require SNI for browsers that access the site (this works in all modern browsers, and even quite old ones)
  • Ensure forward secrecy is used always, or at a minimum ensure ciphers that dont gurantee forward secrecy are only used if there is no better option in the client browser
  • Obfuscate the server software displayed in the 'server' header
  • Move HSTS settings to Traefik so they are also used by both Django and Flower

Also slightly related, not big enough for its own issue: copying the traefik.yaml as part of the docker build is not really ideal as it prevents hot-reloading the config (a nice feature of traefik) - you need to completely rebuild to update config. Simply mounting the file read-only in production.yml would fix this.

I can make a PR if someone seconds these changes.

@browniebroke
Copy link
Member

Thanks for raising this issue. We're open to pull request(s) to fix these security issues. Some are definitely non-obvious and less experienced people would benefit a lot from someone experienced with Traefik tuning these.

While you're on the subject of tuning Traefik, you might also be interested in #1992. A fix was started in #2217 but it somewhat stalled now, and it would be great to fix it.

@jameswilliams1
Copy link
Contributor Author

@browniebroke I have an updated config for this that gets an A+ on ssllabs now, I will make a PR shortly. Worth also mentioning a major improvement to security would be to add a Content-Security-Policy header, basically only allowing scripts/styles/ajax calls from certain domains (majorly reduces the risk of XSS attacks, more details here.

Ideally you would block everything and whitelist the bare minimum, but for cookicutter this would be far too restrictive for end users as we don't know what code/libraries they will add. I was thinking what could be good: a fairly permissive policy that works with Bootstrap/jQuery/other cookicutter tools out of the box and allows everything by default from the current site. It's not the optimal security settings, but as a default its as good as we can get it, and more than enough for most websites, thoughts?

@jameswilliams1
Copy link
Contributor Author

I'll look into the traefik non-root as well as that's something that's been bothering me for a while.

@browniebroke
Copy link
Member

Oh yes, CSP would be very nice, although it's a separate issue.

I was thinking what could be good: a fairly permissive policy that works with Bootstrap/jQuery/other cookicutter tools out of the box and allows everything by default from the current site. It's not the optimal security settings, but as a default its as good as we can get it, and more than enough for most websites.

If we could provide a basic setup, it would be a massive improvement, yes. I like the approach you suggest, I think it's important to not trip people unfamiliar with it too quickly while providing a basic level of security. Feel free to submit a PR directly (or open a separate issue if you think it'll take you longer to implement).

@jameswilliams1
Copy link
Contributor Author

Will do, I'll look at adapting the one I have for my site and making it a little more permissive (as its tuned specifically for my site ATM). Probably best I add a small section to the readme for users - essentially if you want to use a script from a different CDN you would also have to add the domain to the CSP header in traefik.yml to enable it to execute.

@manast1
Copy link

manast1 commented Mar 24, 2021

I'll look into the traefik non-root as well as that's something that's been bothering me for a while.

Sorry if im bothering or this is the wrong place - this is my first Github post.
@jameswilliams1 I cant find a bind mount of the dockersocket to the traefik container in your pulls or files. How can traefik work without binding docker.sock?
As traefik usually is the entrypoint to everything else, I want to drop root privileges entirely if possible.

  • chaged to non privileged ports
  • set socketbind to read only
  • started traefik with unprivileged user (through Dockerfile or docker-compose)
    Once in non-root mode, traefik is unable to use the socket (permission denied).
    Can you give me a hint what I'm overseeing?

@jameswilliams1
Copy link
Contributor Author

jameswilliams1 commented Mar 24, 2021

I'll look into the traefik non-root as well as that's something that's been bothering me for a while.

Sorry if im bothering or this is the wrong place - this is my first Github post.
@jameswilliams1 I cant find a bind mount of the dockersocket to the traefik container in your pulls or files. How can traefik work without binding docker.sock?
As traefik usually is the entrypoint to everything else, I want to drop root privileges entirely if possible.

* chaged to non privileged ports

* set socketbind to read only

* started traefik with unprivileged user (through Dockerfile or docker-compose)
  Once in non-root mode, traefik is unable to use the socket (permission denied).
  Can you give me a hint what I'm overseeing?

I'd avoid mounting the sock for a prod deployment, it gives root access to the host. You don't need to use a sock with Traefik unless you have multiple containers for each service that need to be resolved dynamically (really more useful for K8s than docker-compose) but if needed go with a proxy like this so Traefiks access is read only. Whether the docker user is root or not doesn't matter if you have sock access as you could just create a new container and chroot it to / on the host/any other container anyway.

In answer to the last question, sockets require write access to do anything. If you're trying to prevent malicious creation/deletion of containers you need a proxy as above.

@manast1
Copy link

manast1 commented Mar 25, 2021

Tanks alot @jameswilliams1 - didn't expect that fast response :)
Ok got it & nice illustration of madness (chroot to / ). Docker and Traefik docs confused me for the same reason you stated (doesn't protect socket from captured container root or non-root).
I'll try the proxy aproach and hope it supports my docker-api version 1.41 (newest).
I love the idea of services describing themself and their routing. Most docker/traefik tutorials use dynamic configuration. I don't have any scaling/k8s/swam yet, but I hope the dynamic configuration helps me later on once I build something useful / decide to learn more /switch to swarm.
edit/feedback: traefik now runs rootless with the proxy solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants