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

[Bug]: Proxying using {{port}}-{{host}} does not work #6353

Closed
4 tasks done
varunchopra opened this issue Jul 25, 2023 · 17 comments
Closed
4 tasks done

[Bug]: Proxying using {{port}}-{{host}} does not work #6353

varunchopra opened this issue Jul 25, 2023 · 17 comments
Labels
bug Something isn't working

Comments

@varunchopra
Copy link

varunchopra commented Jul 25, 2023

Is there an existing issue for this?

  • I have searched the existing issues

OS/Web Information

  • Web Browser: Firefox
  • Local OS: MacOS
  • Remote OS: Ubuntu 22.04
  • Remote Architecture: amd64
  • code-server --version: 4.15.0 daac46b with Code 1.80.1

Steps to Reproduce

To avoid re-creating certs for different domains and sub-domains, I've tried to prepend the port to the URL instead of using it as a sub-domain.

  1. Using VSCODE_PROXY_URI=https://{{port}}-{{host}}, if code-server is running on code.example.com, then port 9000 should work on 9000-code.example.com. This is similar to how Gitpod does it.

  2. Setup nginx to read 9000-code.example.com and proxy_pass it to port 9000, NOT the port code-server is running on. If you proxy_pass it to the code_server port, it will just open code-server.

  3. Open python -m http.server 9000 inside code-server. You will see the popup with the proxy URL.

The proxy URL will work but it's only because of nginx, not because it's being proxied through code-server.

Expected

It should be proxied through code-server and require cookies and stuff, by proxying to the code-server port (and not port 9000 as seen above).

Actual

Proxying to the code-server port simply opens code-server again instead of the proxied request.

Proxying to the actual port creates a public URL which forwards the requests to the correct port but WITHOUT actually going through code-server. On the running Python server, I also see a 404 response from GET /_static/out/browser/serviceWorker.js but I don't know why this happens.

Logs

No response

Screenshot/Video

No response

Does this issue happen in VS Code or GitHub Codespaces?

  • I cannot reproduce this in VS Code.
  • I cannot reproduce this in GitHub Codespaces.

Are you accessing code-server over HTTPS?

  • I am using HTTPS.

Notes

While this currently works for my setup, it looks like a bug and I'm not sure if the "fix" is stable long term. My only goal is to use {{ port }}-{{ host }} instead of {{ port }}.{{ host }} so if anyone has suggestions, I'm open to them.

@varunchopra varunchopra added bug Something isn't working triage This issue needs to be triaged by a maintainer labels Jul 25, 2023
@varunchopra varunchopra changed the title [Bug]: [Bug]: Proxying using {{port}}-{{host}} does not work Jul 25, 2023
@smerschjohann
Copy link
Contributor

You aren't activating the internal reverse proxy functionality, therefore it does not work.

You can start code-server like this: ./code-server --proxy-domain {{port}}-{{host}}, then it should work as you expected.

@varunchopra
Copy link
Author

varunchopra commented Jul 27, 2023

OH! That's right, it worked! I was using --proxy-domain example.

Can you tell me how the two (setting VSCODE_PROXY_URI and passing --proxy-domain) are different? . I've tried reading the code but I don't work with Typescript. :/

In the docs I see the following example, perhaps this needs to be fixed?

You can either set up a wildcard DNS entry for *.<domain> if your
domain name registrar supports it, or you can create one for every port you want
to access (3000.<domain>, 8080.<domain>, etc).

Now from the above I assumed <domain> is example.com.

And then it says:

To set your domain, start code-server with the --proxy-domain flag:

code-server --proxy-domain <domain>

I hope this explains why I did what I did.

Additionally, I still see the following requests being made:

127.0.0.1 - - [27/Jul/2023 01:20:16] "GET /_static/out/browser/serviceWorker.js HTTP/1.1" 404 -

And these throw a 401 Unauthorized when I try to login at https://9000-example.com/login in incognito:

https://9000-example.com/_static/src/browser/pages/global.css
https://9000-example.com/_static/src/browser/pages/login.css
https://9000-exmaple.com/_static/src/browser/media/pwa-icon-512.png

What's the reason for this?

Thank you for your help! :-D

@code-asher
Copy link
Member

code-asher commented Jul 28, 2023 via email

@smerschjohann
Copy link
Contributor

Good question. My guess is we have a bug where those resources are being blocked through the domain proxy but we should let them through. Not sure about the 404 though.

At first glance, I think this is correct behavior. We are reverse proxying the target port, so these files are not available except the specific application also provides these files. But even then it would not work, because at that particular moment you are not authenticated (401).

I'm not sure if the path is generic enough to not collide with the forwarded application, so instead I think the password prompt page should either load the resources from the main domain or embed the required resources. And I think the serviceWorker is not required at all.

@code-asher
Copy link
Member

code-asher commented Jul 28, 2023 via email

@smerschjohann
Copy link
Contributor

Ah, I did not look at the code. Yes, you are right, as it is only served if unauthenticated and has etags it should be fine.

@varunchopra
Copy link
Author

varunchopra commented Jul 28, 2023

I think letting the request through would cause a bit of confusion. Wouldn't it be better to redirect unauthenticated requests to the main domain (without the port)? - 9000.code.example.com/* redirects to code.example.com/login.

Once logged in, the user can be allowed to access the proxied domains.

On a similar note, I believe we use a cookie called coder-session-cookie (I don't remember what it is exactly), but nginx doesn't play nice with cookies with hyphens in them. You have to pull the cookie from $http_cookie instead of being able to access it directly with $cookie_coder_session_cookie. Can we rename this to coder_session_cookie?

@smerschjohann
Copy link
Contributor

smerschjohann commented Jul 28, 2023

this would require a more complex flow, because of general cookie policies.

  1. 9000.code.example.com/[path]
  2. redirect to code.example.com/login
  3. user authenticates (or is already authenticated)
  4. redirect to 9000.code.example.com/code with an authorization code
  5. /code must validate that code and set a cookie accordingly
  6. redirect back to 9000.code.example.com/[path]

Benefit: For the user, the authentication process can be skipped in most cases as he is already authenticated on the coder-server editor. So no password input required. But I'm not sure if it's worth the effort.

@smerschjohann
Copy link
Contributor

On a similar note, I believe we use a cookie called coder-session-cookie (I don't remember what it is exactly), but nginx doesn't play nice with cookies with hyphens in them. You have to pull the cookie from $http_cookie instead of being able to access it directly with $cookie_coder_session_cookie. Can we rename this to coder_session_cookie?

why do you tamper with the cookies at all?

@varunchopra
Copy link
Author

varunchopra commented Jul 28, 2023

I'm not sure I understand the workflow you've pointed out.

  1. Why is there a /code endpoint on a proxied domain?
  2. Why does it redirect to 9000.code.example.com with an auth code? Why doesn't it just check the cookie set on the parent domain?

why do you tamper with the cookies at all?

To try what I suggested - if 9000.code.example.com doesn't have a auth cookie, redirect to code.example.com for it to be authenticated. Once the user's logged in, they can visit 9000.code.example.com again view the proxied data.

@smerschjohann
Copy link
Contributor

As I said, general cookie policies. You can only set cookies downwards: code.example.com can set cookies that are accessible from 9000.code.example.com. But e.g. 9000-code.example.com cannot access any cookie from code.example.com and code.example.com cannot set cookies for 9000-code.example.com.

@varunchopra
Copy link
Author

varunchopra commented Jul 28, 2023

This is fixable - if I use varunchopra.code.example.com, 9000-varunchopra.code.example.com, I can set the cookie on .code.example.com and it will work. We only need to specify what the cookie domain should be.

And like you said, it should already work for the child domains.

FWIW I think it's fine as it is - I'm all up for your initial suggestion.

@smerschjohann
Copy link
Contributor

Well multiple issues:

  1. The proxy domain can be completly different from the domain where the code-server runs. The Authentication should work in the same way everywhere.
  2. Normally, it is not good practice and a potential security risk to set "Site" cookies that can be accessed by ALL subdomains. Are you really in control of all subdomains all the time? (But it seems that it is currently done this way https://github.com/coder/code-server/blob/main/src/node/http.ts#L326) @code-asher Is there a reason why "domain" is set here?
  3. Especially if you think about code-{{port}}.example.com. What about code2-{{port}} etc. They will be able to capture your cookie.

@varunchopra
Copy link
Author

Yes, you're right. While I'm okay with having the same cookie - I suspect most people won't and we shouldn't add anything insecure by default.

@code-asher
Copy link
Member

You are right, that is exactly why the domain is set there, so the cookie can be accessed by all subdomains. If I recall correctly it takes the domain, finds the highest level --proxy-domain that matches, and uses that as the cookie domain value so I think we actually broke it since the proxy domain always contains {{port}} now and will never match. 😆

But you raise a really good point about it being a security risk, so I think it would be prudent to remove this or fix it and make it opt-in.

@code-asher
Copy link
Member

Another thought: we might need to think about logout logic now that it might not all be under the same domain.

@code-asher code-asher removed the triage This issue needs to be triaged by a maintainer label Jul 12, 2024
@code-asher
Copy link
Member

I think we solved the original issue so I will close this and open others for the various points that were raised here.

@code-asher code-asher closed this as not planned Won't fix, can't repro, duplicate, stale Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants