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

How does access control work? #1713

Open
kentonv opened this issue Apr 21, 2024 · 7 comments · Fixed by #1714
Open

How does access control work? #1713

kentonv opened this issue Apr 21, 2024 · 7 comments · Fixed by #1714
Labels

Comments

@kentonv
Copy link

kentonv commented Apr 21, 2024

It's really easy to set up a build farm following the quick start guide. Hooray!

However, this guide configures buildfarm to listen for commands on a public IP port on all network interfaces. Anyone who is able to reach the machine over the network at all will be able to tell it to run arbitrary actions.

Digging around the docs and source code for a while, I was unable to figure out what I am supposed to do about this. I couldn't find any built-in authentication mechanism. There is an option to configure TLS, but it looks like this only authenticates the server to the client; the server will still accept commands from any client. Meanwhile, there does not appear to be any way to configure the server to bind only to localhost, which would then allow an authenticating proxy to be configured in front of the server.

Did I miss something? What is the recommended way to prevent untrusted clients from connecting to buildfarm?

@werkt werkt added the question label Apr 22, 2024
@werkt
Copy link
Member

werkt commented Apr 22, 2024

Glad you had success with the guide!

There is no limitation currently via authentication, all existing installations have made do with TLS distributed credentials via certs.

I've definitely wanted to stay out of a password retention/authentication scheme internal to buildfarm.
If you have a particular client that supports a third party authentication mechanism, I'd be happy to take a look at supporting it.

@kentonv
Copy link
Author

kentonv commented Apr 22, 2024

As far as I can tell, the existing TLS config doesn't solve this. It only lets you set a certificate for the server. I don't see an option to configure the server to check the client's certificate. So, it still allows anyone to connect. Is that correct?

My client is just Bazel. Bazel appears to implement a number of options here:

  • --remote_header permits passing an arbitrary header value. This could be used to pass Authorization: Bearer <secret-token>. The server could be configured to require this header matches one of the values on some authorized list.
  • Apparently, Bazel will use username/password found in .netrc (which I assume also results in an Authorization header being sent, using HTTP Basic Auth).
  • Bazel supports mTLS, that is, giving the client a private key and certificate. The server would presumably need to check that the client's certificate is signed by a particular CA cert.

Personally, of these, I would prefer the first option: Just check for a simple secret token in the header. It is the easiest to configure, and it lets people avoid the overhead of encryption if they trust their network (but don't trust all the devices on it). That said, I'd guess mTLS is the preferred approach for big installations.

Alternatively, if buildfarm merely supported the ability to bind sockets to localhost only, not to a port on the physical network, then it would be straightforward for me to use SSH port forwarding or some type of proxy of my own in front of buildfarm.

(FWIW, in my use case, I'm just trying to delegate builds from my laptop to a more-powerful server machine on my home network. But I don't necessarily trust every device connecting to my network...)

@werkt
Copy link
Member

werkt commented Apr 22, 2024

If the server is configured with a specific cert, and the clients do not have a corresponding cert to interact with it, I expect that it would result in an inability to access the transport stream. I have, for instance, seen nginx managed TLS that required keyed certs, representing a partition in the client communication capacity. Or maybe I'm deluding myself, I don't purport to be an expert in this.

If you're not concerned about replay subversion or key persistence, we can probably add the first mechanism succinctly.
I'm not sure if anything happens for gRPC (HTTP/2) communication with .netrc from bazel. I would have to experiment.
My eyes glaze over when mTLS is mentioned, but I believe this is what I was suggesting in terms of pairing a TLS endpoint that may or may not be buildfarm server itself, or some intervening proxy like nginx.

The bind option is interesting. I can pursue adding that config immediately.

@kentonv
Copy link
Author

kentonv commented Apr 22, 2024

If the server is configured with a specific cert, and the clients do not have a corresponding cert to interact with it, I expect that it would result in an inability to access the transport stream.

I don't think that's how TLS works (and I do have a fair amount of experience with it). The server will happily tell its certificate to any client that connects, it's not a secret. The reason you have to configure the client with the certificate is to tell the client that it should only trust a server with a matching certificate. But this only authenticates the server to the client; it doesn't authenticate the client to the server. The client could just as easily be configured to accept any certificate, and the server would allow it.

In order for the server to authenticate the client, the client must have its own private key and corresponding client certificate, which the server is configured to verify. This is known as mTLS (mutual TLS). It doesn't appear that buildfarm's current config provides any way for me to specify how to verify client certs, so I assume this is not implemented.

If you're not concerned about replay subversion or key persistence, we can probably add the first mechanism succinctly.

For my purposes I'd be totally fine with the secret token just being plaintext in the config file. I understand this doesn't protect against MITM and that configs are easy to leak.

The bind option is interesting. I can pursue adding that config immediately.

Yeah, in theory this should be easy to implement although I noticed that gRPC's ServerBuilder class in Java doesn't seem to have an obvious place to pass a bind address, which I find surprising. But I'm not familiar with this APIs, hopefully I'm missing something.

werkt added a commit to werkt/bazel-buildfarm that referenced this issue Apr 22, 2024
Use cases have been presented which limit server bind address
presentation.
Partially Fixes buildfarm#1713
werkt added a commit that referenced this issue Apr 22, 2024
Use cases have been presented which limit server bind address
presentation.
Partially Fixes #1713
@werkt
Copy link
Member

werkt commented Apr 22, 2024

bindAddress in server config is now on main, please give it a shot. Example in examples/config.yml

@kentonv
Copy link
Author

kentonv commented Apr 22, 2024

Thanks. Should workers support the same? Otherwise I guess workers, too, will accept requests from anyone on the network?

(I could probably make a PR for that following your example, if it makes sense.)

Separately, it looks like GitHub auto-closed this issue but I suppose it should stay open to track the more general problem?

@werkt werkt reopened this Apr 22, 2024
@werkt
Copy link
Member

werkt commented Apr 23, 2024

They certainly can support the same, would look forward to your PR. I've reopened the issue, and will leave it that way until we rule one way or another on access - adding code that is required to facilitate security is something I've wanted to avoid.

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.

2 participants