Proposal for a formal solution to embedding kibana without double authentication

The problem

You have a corporate site where you want to embed your kibana dashboard. Your users log in to your corporate website with user and password and when they go to see the dashboard, the iframe requires them to log in again, even though they both validate against the same identity provider.
Update: I coded the whole thing, see https://gitlab.com/francomartin3/kibana-sso. It works!

The partial solution I found

There are many solutions going around that are either old or dont work. Here is one that does work, at least partially.

Reverse proxying

Your dashboard doesnt contain any sensitive data so just make it public right? Just setup an nginx server with the following server block:

server {
     listen       8080 ;
     server_name  default_server;
     location / {
         proxy_set_header  Host $host;
         proxy_set_header  X-Real-IP $remote_addr;
         proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header  Authorization "Basic YOURENCODEDCREDS";
         proxy_pass  https://kibana.domain/; # actual kibana URL
      }

Some gotchas with this

Tech saavy people

Anyone with access to the iframe will be able to see the url and access it separately so make sure you have a separate tenant for public access. If you fail to do this, any tech saavy person will inspect your iframe, see the src="kbproxy.noauth.domain" and access it directly, getting access to all the dashboards.
If you create a separate tenant and create a service account with read only access to that tenant, you should be set.

Public only information

Like I mentioned before, you can only expose public information using this approach.

Other comments

Since kibana's dashboards are embedded in iframes, and are usually in other domains, CORS will not let you do javascript dark magic and kibana is not supporting the good'ol cors:'*' option.
When you login into kibana, the backend sends you two cookies that your browser sends with your requests. Dont have those cookies? too bad, go to the login site and get new ones. Cookies are set at the domain level so chrome will start bitching in the console if an iframe tries to access a main site cookie and youll get a clear session button in the iframe and youll see your hopes and dreams fall apart

The proposed solution

I tried this and it seems to work, Ill be implementing this during the week but I did a POC and it seems to work.
We will be delegating RBAC to elasticsearch by sending the same credentials the user logged in with to kibana and storing cookies in redis. Then sending them to the client when required.

The TLWR

You need a reverse proxy, a really simple backend and some form of storage. When your backend gets creds, send them to kibana too and save the cookies that come as headers in some form of storage.
Point the iframe to a backend that expects the user token. The backend will fetch the cookies using the token you provided and redirect to the dashboard. Now the iframe has cookies and is going to load the dashboard. Profit.

Now lets go down the rabbit hole

Requirements

  • You need to manage the login backend.
  • A reverse proxy
  • Patience

The steps

  • When the user sends the authentication header to the backend, send them to the authentication provider. In my case its AD. If they are valid, send them to kibana.domain/api/v1/auth/login. We are replicating what the client does when logging in through the web, see the web request for more information on what headers to send.
  • Kibana will answer with two cookie headers: security_authentication and security_storage. By now you have a user token that you generated and will be sending to the client. You probably are storing that token in redis along with other user information, probably in a hashset. Add both cookies to that hashset.
  • You will create two locations in the reverse proxy. "/" will be pointing to kibana and "/backend" will be pointing to a custom backend.
server {
     listen       8080 ; 
     server_name  default_server;
     location / {
         proxy_set_header  Host $host;
         proxy_set_header  X-Real-IP $remote_addr;
         proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_pass  http://kibana.domain/;
     }
    location /backend {
         proxy_pass  http://custombackend.domain/;
     }
 }
  • Create the iframe tag with the src pointing to the custom backend path and use a query parameter to add the token. Use javascript for this. The src should be in the form "reverseproxy.domain/backend/?token=1234".
  • The backend will get that token parameter, go to redis and fetch the security cookies. The response of the backend will be a redirection to the reverse proxied kibana dashboard url "reverseproxy.domain/thedashid" and will have two set cookie headers with all the kibana security stuff.

Feel free to try this and tell me in the comments if you do. I've tried this as a POC without redis and answering hardcoded headers but it seems to work. Ill be implementing this during the week or weekend if I get bored.
Update: I coded the whole thing, see https://gitlab.com/francomartin3/kibana-sso. It works!

2 Likes

Hi @franco-martin,

thanks for this proposal, I am sure it will help a lot of kibana users!

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.