The magic of 2 lines in Lua or how to bring the original HTTP Authorization header-authorization headers to the web service

The article will be useful to those:

  • who needs to use several types of authorization in one request to the server;
  • who wants to open the services of the Kubernetes / Docker world to the general Internet, without thinking about how to protect a particular service;
  • thinks that everything has already been done by someone, and would like to make the world a little more convenient and safer.


Services made available through Kubernetes have a rich set of authorization methods. One of the more fashionable is the Authorization header: Bearer Is, for example: JWT authorization (JSON Web Token) with the transfer of a set of keys, and hence values, in one header. There are also Basic authorizations, for example for the Registry (Docker image repository). This authorization does not use cookies and is automatically added by the browser (except for Safari – there are nuances that we have not yet decided) to all requests to the server.

Problem 1:

I can’t log in through Firefox & Safari in the Storage OS interface, the Loader appears, and that’s it.

Mini hypothesis:

Proxying problem. A quick check showed the result: if authorization without using proxying (universal secure access using a certificate), then everything works. So what’s the deal?

After analyzing the network stack, we realized that the Authorization header is being used, however, earlier, during the configuration of the proxying of Rancher services, it was found that this header is passed to the proxied service and contains the authorization data for the certificate, so it was decided to simply delete it after the authorization process is complete (FakeBasicAuth ).

Problem 2:

In many web servers, authorization with a personal certificate is implemented through emulation of Basic authorization (in fact, interfering with a user request), probably in order to reduce changes in the main code of the web server. This method is called FakeBasicAuth. After setting such a header, the web server overwrites the Authorization header that comes from the user.


1. The scope of the FakeBasicAuth header lends itself to even more restriction, so that the original header is restored for transfer to the proxied resource in such a way that only the original header, if any, will be transferred.

2. The scope of the Authorization header can be designed so that the header will be saved before activating the FakeBasicAuth mechanism and restored after.

Visible State – Target:

Storage OS authorizes, you can configure this service while maintaining a unified approach to opening the availability of services to the external Internet.

Additional purpose:

Unified, fast and secure http access while preserving the functionality of all possible http services (for example, REST API for a mobile application or Registry Docker).

How to check?

  • docker login – using keys and login / password.
  • – using the login and password from the secret configs p-qj9qm / secrets / kube-system: init-secr… (does not work in Safari).
  • – using a browser and login / password from Registry. For those who read carefully, the trick: you can use this interface instead of the standard docker login – there is built-in proxying to the Registry.

Hypothesis testing:

1. Based on previous experience, let’s try to find a way on the Internet for such requests: apache authentification external basic via cert.
There was a more or less adequate article about ldap

like this:

RewriteEngine on
RewriteCond %{IS_SUBREQ} ^false$
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set REMOTE_USER %{RU}e

And then pass the title in additional headers through the construction

RequestHeader add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"

But, unfortunately, this construction does not imply the creation of an identical header, the header of the user’s request, and env is formed incorrectly.
Therefore, the method based on the standard rewrite turned out to be useless and complicated.

2. If we cannot standardly, then we need to turn to lua, we have previously seen that there are blocks for processing requests that are executed before processing certificates, again look at the block diagram from the article lua_load_resty_core and instructions module_lua_writinghooks with early design.

It turns out that we can use the same script (How we made friends Apple Safari and client certificates with websockets at ZeroTech) to save the Authorization header before replacing it with FakeBasicAuth.

LuaHookAccessChecker /usr/local/etc/apache24/sslincludes/websocket_token.lua handler early

In Lua, it now looks like this:

require 'apache2'

function handler(r)
        local fmt="%Y%m%d%H%M%S"
        local timeout = 3600 -- 1 hour
        local auth = r.headers_in['Authorization']

        r.notes['zt-cert-timeout'] = timeout
        r.notes['zt-cert-date-next'] =,os.time()+timeout)
        r.notes['zt-cert-date-halfnext'] =,os.time()+ (timeout/2))
        r.notes['zt-cert-date-now'] =,os.time())

        if auth ~= nil then
                r.notes['zt-auth-before'] = auth

        return apache2.OK


New designs are marked in bold. And since we know that the env obtained from Lua is only available for expr expressions, we add a construction next to the encryption of the zt-cert token:

# outgoing cookie to user

Header set Set-Cookie "expr=zt-cert=%{sha1:...

# pass headers to the proxied service

RequestHeader add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"

The availability of data for transfer to the service was checked by transferring data back to the user to the browser:

Header add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"

The most interesting thing here is a way to check for the presence of data, so as not to transmit the header to the proxied service if it did not come from outside the user’s browser. The second part of the construction is responsible for this:

"expr=%{env:zt-auth-before} =~/.{1,}/"


There are no ready-made solutions on the Internet at the moment, about three hours were spent searching and trying to test variations, because I didn’t want to “reinvent the wheel”.

Added 5 lines, 3 of which can be safely removed.
What do you think? – Write your options for answers in the comments to the article.

I did not want to write about this experience, since in fact it is only 2 lines and the Authorization header will reach the addressee, but I decided to share information anyway, since it uses a good store of knowledge from previous research on certificates (we are talking about this article habr. com / ru / company / zerotech / blog / 509130). In addition, there are hardly any daredevils to write something of their own and so simple in an unknown language.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *