Write it down while it’s hot for your future self

0 – preface

Recently in the development process, there was a business requirement to embed an online editor (such as vscode, jupyterlab, etc.) in our platform web pages.

An online editor is easier to fix, and there are open source components available online.

Embedding an online editor in a Web page, using iframe to load links to the online editor, is also possible without much problem.

However, a further requirement is that the online editor is only accessible through the Web pages of our platform, and not when accessed from another browser or from another computer via the online editor link.

This need is reasonable and necessary. From the point of view of security, if the link of the online editor can be accessed anywhere, once the link is leaked, all the people who get the link can directly access the online editor and operate the content inside, which will cause serious problems such as data leakage and malicious tampering of files.

1 – plan

The authentication of third-party applications embedded through iframe can be generally divided into two directions:

  1. Use the authentication system provided by the third-party application, for example, use the account password or token to log in.
  2. Integrate third-party applications into existing platform authentication systems.

The first is the easiest to think of and implement. You only need to use the customized configuration files of third-party applications to complete the authentication function. However, this scheme has certain disadvantages:

  1. Poor compatibility: Different third-party applications have different authentication methods. Some use the user name and password to log in (such as FileBrowser), some use the password only (such as VScode), and some use the token to log in (such as JupyterLab). For different third-party applications, the configuration is different and takes time.
  2. No authentication: If some third-party applications do not have their own authentication, the first solution will not work.
  3. Poor user experience: When accessing third-party applications on the Web side of the platform, you need to enter the password again. The password is too many and is easy to forget.
  4. Potential security issues: Once third-party applications have vulnerabilities and their authentication is breached, it will directly affect our platform (see log4j).

In view of the inappropriateness of the first scheme, the second authentication scheme is needed. So how do you do that?

Let’s look at the system architecture:

As you can see, third-party applications are load balancing services in the form of pods, using the Ingress configuration file (in this case, Nginx Ingress) to internally forward external traffic at the Ingress Controller layer.

In the nginx Ingress configuration file, traffic is mainly forwarded to external requests by configuring the regular expression of path to the corresponding service layer. Nginx Ingress annotations are also available for additional functionality, as shown in the link.

Using nginx. Ingress. Kubernetes. IO/auth – url can realize external authentication, to forward the external request to the specified authentication interface: authentication through after, and then forwarded to the corresponding service layer; Authentication failed, then forwarded to the nginx. Ingress. Kubernetes. IO/auth – signin to log in.

The above black part is the theoretical basis for the implementation of this scheme. However, to implement this feature, you need to solve:

  1. An authentication interface is developed to filter authentication requests from third-party applications.
  2. How do I transmit authentication information to an authentication interface

To address the first problem, you can open a new authentication service in the Kubernetes cluster to provide an authentication interface. The second problem is that the access URL of third-party applications is the same as the URL of the platform and the cookie is shared. Therefore, authentication information can be transmitted to the authentication interface through cookies.

2 – to achieve

Here is a simple demo implementation.

First, configure the ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-signin: http://open.domain.com/login
    nginx.ingress.kubernetes.io/auth-url: http://{auth_service}.{namespace}.svc.cluster.local/api/v1/auth
  namespace: openmmlab
spec:
  rules:
  - host: open.domain.com
    http:
      paths:
      - backend:
          service:
            name: {auth_serivce}
            port:
              number: {service_port}
        path: /{path}/vscode(/|$)(.*)
        pathType: Prefix
Copy the code

Then, write the authentication interface (SpringBoot):

@GetMapping ( "/api/v1/auth" ) public void auth ( HttpServletRequest request, HttpServletResponse response ) { Cookie [] cookies = request.getCookies() ; log.info ( "nginx called auth api! , cookies:{}", cookies ) ; if ( cookies == null ) { response.setStatus (401); return; } for ( Cookie cookie : Cookies) {// Write specific authentication logic, here is simply to determine whether the cookie carries the token field, if there is, then directly return HTTP response 200, If (cookie.getName().equals("token")) {response.setStatus (200); return; } } response.setStatus (401); }Copy the code

When http:// {auth_service}. {namespace}. SVC. Cluster. The local/API/v1 / auth interface returns the HTTP status code is 401, Automatically call nginx. Ingress. Kubernetes. IO/auth – signin address, namely http://open.domain.com/login to login authentication.

In this way, third-party applications can be incorporated into the authentication system of the existing platform without resorting to the authentication function of third-party applications.

The above.