As we corporate from Windows ran away

It so happened that in our company C # was chosen as the main language for backend development. By the way, we were always satisfied with this choice, and when MS started developing the .net Core platform, it became even more interesting, since C # is good, but C # under Linux is even better.


I will not describe the transition path to cross-platform development, since many people have already passed the transition path from the Framework to the Core.


I will focus on one moment. In addition, Docker pushed us towards hosting our applications for Linux, because we really wanted to join the youth stream of containerization of everything that was possible.


Since we are developing an enterprise, together with us we had to escape under linux and pass-through windows authentication. Actually, this was the driving force behind writing an article. Since the information was very difficult, in separate chunks, and communication with many people, the idea of ​​collecting everything you need in one place and describing the working version seemed good.


As a solution, a variant with reverse proxy for nginx with kerberos authentication was selected. And so that the solution could be used by comrades from different projects, it was decided to file the docker image, which would solve the basic problem, and from which others could be inherited, or use it as it is.


In order to make kerberos work, it was necessary to build nginx with additional modules.
The result was about this team. Everything is molded in two calls to create smaller layers.


Let's sort our Dockerfile. We will be based on a very compact image with alpine


FROM alpine:3.7

Next, tighten the necessary packages, the source code of nginx and the required module spnego-http-auth-nginx-module. The result is something like this.


ENV NGINX_VERSION 1.15.1
RUN set -ex \  && apk add --no-cache \    git \    krb5 \    krb5-dev \    ca-certificates \    libressl \    pcre \    zlib \  && apk add --no-cache --virtual .build-deps \    build-base \    linux-headers \    libressl-dev \    pcre-dev \    wget \    zlib-dev \  && cd /tmp \  && wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \  && tar xzf nginx-${NGINX_VERSION}.tar.gz \  && git clone https://github.com/stnoonan/spnego-http-auth-nginx-module.git nginx-${NGINX_VERSION}/spnego-http-auth-nginx-module

This block was selected separately so that when reassembling this layer could be taken from the cache, since it is the longest in time.


The next set of commands will collect nginx and tidy up for themselves, so that the image does not swell in vain


RUN cd /tmp/nginx-${NGINX_VERSION} \  && ./configure \\    --prefix=/etc/nginx \    --sbin-path=/usr/sbin/nginx \    --conf-path=/etc/nginx/nginx.conf \    --error-log-path=/var/log/nginx/error.log \    --pid-path=/var/run/nginx.pid \    --lock-path=/var/run/nginx.lock \    --user=nginx \    --group=nginx \    --with-threads \    --with-file-aio \    --with-http_ssl_module \    --with-http_v2_module \    --with-http_realip_module \    --with-http_addition_module \    --with-http_sub_module \    --with-http_dav_module \    --with-http_flv_module \    --with-http_mp4_module \    --with-http_gunzip_module \    --with-http_gzip_static_module \    --with-http_auth_request_module \    --with-http_random_index_module \    --with-http_secure_link_module \    --with-http_slice_module \    --with-http_stub_status_module \    --http-log-path=/var/log/nginx/access.log \    --http-client-body-temp-path=/var/cache/nginx/client_temp \    --http-proxy-temp-path=/var/cache/nginx/proxy_temp \    --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \    --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \    --http-scgi-temp-path=/var/cache/nginx/scgi_temp \    --with-mail \    --with-mail_ssl_module \    --with-stream \    --with-stream_ssl_module \    --with-stream_realip_module \    --add-module=spnego-http-auth-nginx-module \  && make -j$(getconf _NPROCESSORS_ONLN) \  && make install \  && sed -i -e 's/#access_log  logs\/access.log  main;/access_log \/dev\/stdout;/' -e 's/#error_log  logs\/error.log  notice;/error_log stderr notice;/' /etc/nginx/nginx.conf \  && adduser -D nginx \  && mkdir -p /var/cache/nginx \  && apk del .build-deps \  && rm -rf /tmp/*

And to make it all make sense, raise nginx


CMD ["nginx", "-g", "daemon off;"]

We can assume that the image is ready, now we proceed to ensure that our server has the ability to authorize users.


To do this, you need to find a domain administrator, I was extremely lucky with him - the guy was responsive and did what he was asked for very quickly. And you need to do the following.
Suppose the hostname of the host machine is "host-linux", and your domain is "DOMAIN.LOCAL".
In the domain, you need to start a machine with the name "host-linux" and create an account to which we will tie it, for example, "host-linux-user". Next, you need to create an SPN and generate a keytab file, which we will need when lifting the container.


We have a team like this


C:\Windows\system32>ktpass -princ HTTP/HOST-LINUX.domain.local@DOMAIN.LOCAL -mapuser host-linux-user@DOMAIN.LOCAL -pass yourpassword -cryptoAll -ptype KRB5_NT_PRINCIPAL -out C:\Temp\web.keytab

After I got the file, you could go experimenting. As a result, I got the following nginx.conf


http {
    #Whatever is there by defaultserver {
        listen80;
        server_name  localhost;
        #Here kerberos stuff startsauth_gsson;
        auth_gss_realm DOMAIN.LOCAL;
        #Keytab file from the mounted folderauth_gss_keytab /home/spnego/config/web.keytab;
        auth_gss_service_name HTTP/HOST-LINUX.domain.local;
        auth_gss_allow_basic_fallbackoff;
        #Here kerberos stuff endslocation / {
            root   html;
            index  index.html index.htm;
        }
#bla-bla-bla

Now, in order to start everything up, when lifting the container, you need to throw the current nginx.conf to it and feed the received web.keytab. To do this, use the magic docker-compose


version: "2"
services:
    nginx-spnego:
        image: fclmman/alpine-nginx-spnego
#опишем проброс портов. Например такой
        ports:
            - 80:80
            - 5010:5010
            - 443:443
            - 8001:8001#примонтируем раздел с web.keytab, и закинем в контейнер наш конфиг
        volumes:
            - ./config:/home/spnego/config
            - ./config/nginx.conf:/etc/nginx/nginx.conf

We follow in the directory where we have docker-compose.yml. In our case, there should be a directory ./config with the files nginx.conf and web.keytab in the same folder. Execute the command


docker-compose -f ./docker-compose.yml  up -d

The container rose and did not die. It gives hope for success.


Open the browser on the blast machine.


In one tab, open chrome: // net-internals / and write down the requests that we go. In another tab, open http: // host-linux: 80 / . Let's go back to chrome: // net-internals / and see the results.


#Видим что сервер потребовал negotiate
t= 3 [st= 3]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                    --> HTTP/1.1 401 UnauthorizedServer: nginx/1.15.1Date: Fri, 10 Aug 201814:15:54 GMT
                        Content-Type: text/html
                        Content-Length: 597Connection: keep-alive
                        WWW-Authenticate: Negotiate
t= 4 [st= 4]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                    --> GET / HTTP/1.1
                        Host: host-linux
                        Connection: keep-alive
                        Pragma: no-cacheCache-Control: no-cache
                        Authorization: Negotiate #очень длинный набор букв
                        Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
                        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
                        Accept-Encoding: gzip, deflate
                        Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
t= 4 [st= 4]     -HTTP_TRANSACTION_SEND_REQUEST
t= 4 [st= 4]     +HTTP_TRANSACTION_READ_HEADERS  [dt=47]
t= 4 [st= 4]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=47]
t=51 [st=51]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                    --> HTTP/1.1 200 OK
                        Server: nginx/1.15.1
                        Date: Fri, 10 Aug 2018 14:15:54 GMT
                        Content-Type: text/html
                        Content-Length: 612
                        Last-Modified: Fri, 10 Aug 2018 12:21:36 GMT
                        Connection: keep-alive
                        WWW-Authenticate: Negotiate #Набор букв покороче
                        ETag: "5b6d8350-264"
                        Accept-Ranges: bytes

As a result, we see that the operation was successful and we see the nginx welcome screen.
It is worth making one clarification, everything will work only according to the hostname, but as far as I understand it correctly, because we tied kerberos to it.


Thank you for your attention, if you have read this far, and I really hope that the article will be useful.


Also popular now: