Integrating Kerberos and SingleStore DB (MySQL protocol) authentication can be hard enough. However, this can be made even harder by trying to make this work when the cluster connection is coming from a web browser, going through to a SingleStore DB cluster via WebSockets.
My goal with this post is to briefly explain how we integrated them all in a very simple and neat way. I am not going to explain Kerberos and SingleStore DB in too much depth. There are plenty of resources explaining what these are.
SingleStore Studio is a stateless UI to manage and interact with a SingleStore DB cluster. Let's quickly review a few things:
It's stateless. The UI is simply a tool to interact with a cluster in a simple way. All the authentication logic and displayed information is powered by the SingleStore DB cluster.
SingleStore DB is MySQL wire protocol compatible, which allows us to use any existing MySQL driver to connect to a cluster.
Studio can run without any backend server and solely inside a browser. We do have a light web server to serve static resources (HTML/CSS/JS files), but it's not very important.
To communicate with the SingleStore DB cluster, we use a forked version of the mysqljs driver inside a Web Worker. We can say that Studio's "backend" runs inside the browser in this worker. You can read this blog post to learn more about this architecture.
All the cluster authentication logic is managed by the MySQL driver.
Kerberos is an authentication protocol that is widely used in the enterprise world. Its main goal is to provide a secure Single Sign-On mechanism to reuse the existing system's authenticated credentials:
A user logs in to their laptop.
The system generates a Kerberos service ticket.
Any application can integrate with Kerberos and automatically log the user in reusing the system's service ticket.
If you're using the mysql CLI to talk to a SingleStore DB cluster, you can follow the Kerberos + SingleStore DB documentation to get this exact flow running in your laptop. However, we wanted to make this work when using SingleStore Studio as well.
Why this was challenging
Looking at the existing MySQL drivers, the support for Kerberos authentication is very limited and its existence depends on system native libraries, which is impossible to achieve inside a browser context. To clarify, within the browser environment, it's not possible to access native libraries such as the filesystem ("fs") and others which are required to grab Kerberos tickets. Since we generate the MySQL protocol packets (which includes all the authentication logic) in the browser, things get complicated.
Our first approach was to implement this support inside our mysqljs fork and ship Studio as an desktop application with Electron. In order for that to work, we extended our mysqljs driver to support the GSSAPI, a standardized authentication API that supports Kerberos authentication. We got this to work but it had some limitations:
Kerberos authentication would only work for the desktop application, which is not ideal.
Shipping an application in a different target binary and adding new third party libraries has a huge maintenance cost that lasts forever. This cost shouldn't be taken lightly.
Our final solution
Browsers already provide a native Kerberos implementation for HTTP requests using the SPNEGO protocol, although that API is very limited.
The next question is: how do we integrate that with the MySQL protocol inside the browser? Here's what we came up with:
We extended the MySQL "Auth Switch Request Packet" so that when it receives the "auth_gssapi_client" auth request, it will do an HTTP get request to a custom API endpoint controlled by Studio's web server (described before in this article).
SingleStore DB is set up to send the "auth_gssapi_client" auth request whenever the user that is trying to sign is configured in the cluster as a GSSAPI user.
This new endpoint implements only the first part of the SPNEGO protocol. We don't want to have Kerberos service ticket validation logic in Studio, since that logic should be implemented by the SingleStore DB cluster.
This first part consists of:
If the HTTP header "Authorization Negotiate" is not present, it returns a 401 with the response header `WWW-Authenticate: Negotiate`. This will force the browser to initialize the SPNEGO protocol and contact the Kerberos KDC to authenticate the user. More information about how this works can be found in the Chrome documentation.
If the header is present, we assume that the browser has already authenticated the user, so we just return back the service ticket from the "Authorization Negotiate" header.
The frontend grabs the service ticket on the response and injects it inside the MySQL authentication packet.
The SingleStore DB cluster can now validate the service ticket and authenticate the user.
Here's a diagram of the full solution:
We're quite happy with this solution since we didn't have to add a desktop distribution to SingleStore Studio. It works everywhere, we have very few lines of code to maintain and we didn't have to add any third party dependencies.