restic / rest-server

Rest Server is a high performance HTTP server that implements restic's REST backend API.
BSD 2-Clause "Simplified" License
978 stars 143 forks source link

Don't ignore `--private-repos` when `--no-auth` is used #174

Open zroug opened 2 years ago

zroug commented 2 years ago

Output of rest-server --version

rest-server 0.10.0 compiled with go1.15.2 on linux/amd64

What should rest-server do differently?

It should still check whether username and path match, when flags --no-auth and --private-repos are used simultaneously. I think that essentially means omitting !s.NoAuth here: https://github.com/restic/rest-server/blob/421da62900ced37c3ef7098e1ca94250a12742ec/handlers.go#L70

What are you trying to do? What is your use case?

This change would allow me to use a reverse proxy for authentication and still use --private-repos. I could use this to work around issues like #70, #73 or #111 more easily.

Did rest-server help you today? Did it make you happy in any way?

Yes, I especially like the append only mode and the stateless simplicity.

wojas commented 2 years ago

It would require a bit more work to support this. We currently have no username to compare to when auth is disabled, username will always be an empty string (see checkAuth). I guess we could just read the username part of the Basic auth, but not check the password.

Would the Basic auth header be set by the check on your reverse proxy?

zroug commented 2 years ago

You are right, my reverse proxy sets an additional header with the user name. I didn't realize that this header is not part of the basic auth header. I probably could get the proxy to send a fake Authorization header but I think it would be much cleaner to specify a header to trust the username from. That makes it a bit more complicated, but maybe --no-auth could have an optional argument to specify a trusted header that contains the user name?

rawtaz commented 2 years ago

What reverse proxy are you using, how is the authentication between your restic client and the proxy performed, and what is the normal way for the proxy to signal to the backend that the user is authenticated?

zroug commented 2 years ago

I'm using Traefik​ as a reverse proxy. Right now Traefik is not authenticating the the clients, this is done by restic rest server at the moment. I would like to instead use Traefik to authenticate the users using ForwardAuth (https://doc.traefik.io/traefik/v2.0/middlewares/forwardauth/), so that we can have a single user database. The backend would not receive any not authenticated requests. A header that contains the user name would be added to authenticated requests.

wojas commented 2 years ago

I have seen similar things before. I agree that adding something like --trusted-username-header would be the best solution.

MichaelEischer commented 2 years ago

Wouldn't it be easier to just let the reverse proxy check that the username and path prefix match? Since #112 all --private-repos does is verify that the first part of the pathname matches the username. The option is no longer necessary to provide subrepositories.

wojas commented 2 years ago

Wouldn't it be easier to just let the reverse proxy check that the username and path prefix match? Since #112 all --private-repos does is verify that the first part of the pathname matches the username. The option is no longer necessary to provide subrepositories.

Maybe, but #117 shows the risks of having two different components try to interpret the request path.

140 also allows giving specific users additional permissions, which would not work in combination with a check on the proxy level.

GeorgFoc commented 2 years ago

I stumbeled over this problem as well (I use nginx). What I would expect would be something like this:

Internet --https-->proxy/lb --http-->rest-server

So normal TLS Termination. I found, that the current SSL Ciphers are week, and I cannot change them.

For TLS Termination working correctly, the Rest-Server should Respect the X-Forwarded-Proto Header, to know, that the client talks https, but the requests comes through http. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto

This would be enough for me. Basic Auth would still work, because the Authorization Header could also be proxied, as far as I understand.

Also nice would be a health endpoint like /healthz with only response with http 200 if the Rest-Server is healthy.

MichaelEischer commented 2 years ago

@GeorgFoc Basic-Auth at rest-server also works without enabling TLS. So, I don't understand what you need the X-Forwarded-Proto header for.

GeorgFoc commented 2 years ago

@MichaelEischer Yes you are right. I'm sorry. I touched to many systems yesterday and was unconcentrated. TLS Terminations works just finde.