Gitlab clone over http fails to authenticate from external network - http

I have Gitlab 5.2 + Nginx installed on a local machine in my university. Clone over http works for machines that are within the internal network, but trying to clone from a machine on an external network results in an "fatal: Authentication failed" message, even though the exact same credentials are supplied. (I use the same credentials as the ones I use to log in to Gitlab via the web interface)
The Gitlab web interface is accessible from external networks. It is only the clone over http that fails (clone over ssh is not possible because port 22 is blocked)
Here are some lines from the relevant configuration files:
from config/gitlab.yml
host: mydomain
port: 80
https: false
Here are the relevant lines from the ngnix config file
server {
listen *:80 default_server; # In most cases *:80 is a good idea
server_name mydomain; # e.g., server_name source.example.com;
root /home/git/gitlab/public;
# individual nginx logs for this gitlab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
location / {
# serve static files from defined root folder;.
# #gitlab is a named location for the upstream fallback, see below
try_files $uri $uri/index.html $uri.html #gitlab;
}
# if a file, which is not found in the root folder is requested,
# then the proxy pass the request to the upsteam (gitlab unicorn)
location #gitlab {
proxy_read_timeout 2000; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_connect_timeout 2000; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://gitlab;
}
}
Note: I have added this line to /etc/hosts: 127.0.0.1 mydomain but it doesn't really help. (based on https://github.com/gitlabhq/gitlabhq/issues/3483#issuecomment-15783597)
Any ideas on what the issue might be/how I might debug this?

I believe this is fixed in 5.3, so try updating. See:
https://github.com/gitlabhq/gitlabhq/blob/master/CHANGELOG#L41
https://github.com/gitlabhq/gitlabhq/blob/master/config/gitlab.yml.example#L151

Related

How to setup NGINX proxy for Jenkins?

I have the current jenkins configuration:
server {
listen 80;
listen [::]:80;
server_name server_name mysubdomain.maindomain.com;
# This is the jenkins web root directory (mentioned in the /etc/default/jenkins file)
root /var/run/jenkins/war/;
access_log /var/log/nginx/jenkins/access.log;
error_log /var/log/nginx/jenkins/error.log;
#pass through headers from Jenkins which are considered invalid by Nginx server.
ignore_invalid_headers off;
location ~ "^/static/[0-9a-fA-F]{8}\/(.*)$" {
# rewrite all static files into requests to the root
# e.g /static/12345678/css/something.css will become /css/something.css
rewrite "^/static/[0-9a-fA-F]{8}\/(.*)" /$1 last;
}
location /userContent {
#have nginx handle all the static requests to the userContent folder files
#note : This is the $JENKINS_HOME dir
root /var/lib/jenkins/;
if (!-f $request_filename){
#this file does not exist, might be a directory or a /**view** url
rewrite (.*) /$1 last;
break;
}
sendfile on;
}
location #jenkins {
sendfile off;
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 X-Forwarded-Proto $scheme;
# Required for new HTTP-based CLI
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_pass http://127.0.0.1:2021;
}
location / {
# try_files $uri $uri/ =404;
try_files $uri #jenkins;
}
}
which is essentially a copy of this jenkins configuration and my current /etc/default/jenkins file:
NAME=jenkins
# location of java
JAVA=/usr/bin/java
JAVA_ARGS="-Djava.awt.headless=true"
# make jenkins listen on IPv4 address
JAVA_ARGS="-Djava.net.preferIPv4Stack=true"
PIDFILE=/var/run/$NAME/$NAME.pid
JENKINS_USER=$NAME
JENKINS_GROUP=$NAME
JENKINS_WAR=/usr/share/$NAME/$NAME.war
JENKINS_HOME=/var/lib/$NAME
RUN_STANDALONE=true
JENKINS_LOG=/var/log/$NAME/$NAME.log
MAXOPENFILES=8192
HTTP_PORT=2021
HTTP_HOST=127.0.0.1
# servlet context, important if you want to use apache proxying
PREFIX=/$NAME
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --prefix=$PREFIX --httpListenAddress=$HTTP_HOST --httpPort=$HTTP_PORT"
a simple curl requests shows a response of Jenkins running:
$ curl http://localhost:2021/jenkins/
<html><head><meta http-equiv='refresh' content='1;url=/jenkins/login?from=%2Fjenkins%2F'/><script>window.location.replace('/jenkins/login?from=%2Fjenkins%2F');</script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
You are authenticated as: anonymous
Groups that you are in:
Permission you need to have (but didn't): hudson.model.Hudson.Administer
-->
</body></html>
However I am unable to acess the Web UI from the browser. whenever I try to I get a 404. The following are the reevant versions of installed 'wares:
Nginx - 1.13.6
Jenkins - 2.73.2 (using java -jar path-to-warfile --version)
OS - ubuntu 16.04
JDK - openjdk version "1.8.0_131"
An inspection of sudo nginx -T revealed that my site config wasn't being loaded. After correcting the error in my nginx.conf (spelling error in the include directive for the directory), this resolved the issue.
Thanks to SmokedCheese on IRC for his/her help with this issue.

How do I get Nginx to return 444 if the request doesn't match a path?

Short version:
I want to use NGINX as a reverse proxy so that a client accessing the public facing URL gets served API data from the internal Gunicorn server sitting behind the proxy:
external path (proxy) => internal app
<static IP>/ABC/data => 127.0.0.1:8001/data
I'm not getting the location mapping correct.
Long version:
I am setting up NGINX for the first time and am attempting to use it as a reverse proxy for a rest api served by Gunicorn. The api is served at 127.0.0.1:8001 and I can access it from the server and get the appropriate responses, so that piece I believe is working correctly. It's running persistently using Supervisord.
I'd like to access one of the API endpoints externally at <static IP>/ABC/data. On the Gunicorn server, this endpoint available at localhost:8001/data. Eventually I'd like to serve other web apps through NGINX with roots like <static IP>/foo, <static IP>/bar, etc. Each of these web apps would be from an independent Python app. But currently, when I try to access the endpoint externally, I get a 444 error code, so I think I am not configuring NGINX correctly.
I put together my first attempt at an NGINX config from the config posted on the Guincorn site. Instead of a single config, I've split it into a global config and a site specific one. My global config at etc/nginx/nginx.conf looks like:
user ops;
worker_processes 1;
pid /run/nginx.pid;
error_log /tmp/nginx.error.log;
events {
worker_connections 1024; # increase if you have lots of clients
accept_mutex off; # set to 'on' if nginx worker_processes > 1
use epoll;
# 'use epoll;' to enable for Linux 2.6+
# 'use kqueue;' to enable for FreeBSD, OSX
}
http {
include mime.types;
# fallback in case we can't determine a type
default_type application/octet-stream;
access_log /tmp/nginx.access.log combined;
sendfile on;
server_tokens off;
server {
# if no Host match, close the connection to prevent host spoofing
listen 80 default_server;
return 444;
}
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Then my site specific configuration that is in /etc/nginx/sites-available (and is symlinked in /etc/nginx/sites-enabled) is:
upstream app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
# for UNIX domain socket setups
# server unix:/tmp/gunicorn_abc_api.sock fail_timeout=0;
# for a TCP configuration
server 127.0.0.1:8001 fail_timeout=0;
}
server {
# use 'listen 80 deferred;' for Linux
# use 'listen 80 accept_filter=httpready;' for FreeBSD
listen 80 deferred;
client_max_body_size 4G;
# set the correct host(s) for your site
server_name _;
keepalive_timeout 100;
# path for static files
#root /path/to/app/current/public;
location /ABC {
# checks for static file, if not found proxy to app
try_files $uri #proxy_to_app;
}
location #proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if and only if you use HTTPS
# proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
}
# error_page 500 502 503 504 /500.html;
# location = /500.html {
# root /path/to/app/current/public;
# }
}
The configs pass service nginx checkconfig, but I end up seeing the following in my access log:
XXX.XXX.X.XXX - - [09/Sep/2016:01:03:18 +0000] "GET /ABC/data HTTP/1.1" 444 0 "-" "python-requests/2.10.0"
I think I've somehow not configured the routes properly. Any suggestions would be appreciated.
UPDATE:
I have it working now with a few changes. I commented out the following block:
server {
# if no Host match, close the connection to prevent host spoofing
listen 80 default_server;
return 444;
}
I can't figure out how to get the behavior of returning 444 unless there is a valid route. I'd like to, but I'm still stuck on this part. This block seems to eat all incoming requests. I've also changed the app config to:
upstream app_server {
server 127.0.0.1:8001 fail_timeout=0;
}
server {
# use 'listen 80 deferred;' for Linux
# use 'listen 80 accept_filter=httpready;' for FreeBSD
listen 80 deferred;
client_max_body_size 100M;
# set the correct host(s) for your site
server_name $hostname;
keepalive_timeout 100;
location /ABC {
# checks for static file, if not found proxy to app
try_files $uri #proxy_to_app;
}
location #proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if and only if you use HTTPS
# proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
rewrite ^/ABC/(.*) /$1 break;
proxy_pass http://app_server;
}
}
Basically I seem to have had to explicity set server_name and also use rewrite to get the correct mapping to the app server.
This works fine for me, returns 444 (hangs up connection) only if no other server name is matched:
server {
listen 80;
server_name "";
return 444;
}

How to create Kubernetes cluster serving its own container with SSL and NGINX

I'm trying to build a Kubernetes cluster with following services inside:
Docker-registry (which will contain my django Docker image)
Nginx listenning both on port 80 and 443
PostgreSQL
Several django applications served with gunicorn
letsencrypt container to generate and automatically renew signed SSL certificates
My problem is a chicken and egg problem that occurs during the creation of the cluster:
My SSL certificates are stored in a secret volume that is generated by the letsencrypt container. To be able to generate the certificate, we need to show we are owner of the domain name and this is done by validating a file is accessible from the server name (basically this consist of Nginx being able to serve a staticfile over port 80)
So here occurs my first problem: To serve the static file needed by letsencrypt, I need to have nginx started. The SSL part of nginx can't be started if the secret hasn't been mounted and the secret is generated only when let's encrypt succeed...
So, a simple solution could be to have 2 Nginx containers: One listening only on port 80 that will be started first, then letsencrypt then we start a second Nginx container listening on port 443
-> This kind of look like a waste of resources in my opinion, but why not.
Now assuming I have 2 nginx containers, I want my Docker Registry to be accessible over https.
So in my nginx configuration, I'll have a docker-registry.conf file looking like:
upstream docker-registry {
server registry:5000;
}
server {
listen 443;
server_name docker.thedivernetwork.net;
# SSL
ssl on;
ssl_certificate /etc/nginx/conf.d/cacert.pem;
ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
location /v2/ {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
# To add basic authentication to v2 use auth_basic setting plus add_header
auth_basic "registry.localhost";
auth_basic_user_file /etc/nginx/conf.d/registry.password;
add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;
proxy_pass http://docker-registry;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
The important part is the proxy_pass that redirect toward the registry container.
The problem I'm facing is that my Django Gunicorn server also has its configuration file in the same folder django.conf:
upstream django {
server django:5000;
}
server {
listen 443 ssl;
server_name example.com;
charset utf-8;
ssl on;
ssl_certificate /etc/nginx/conf.d/cacert.pem;
ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 20M;
location / {
# checks for static file, if not found proxy to app
try_files $uri #proxy_to_django;
}
location #proxy_to_django {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
#proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 65;
proxy_read_timeout 65;
proxy_pass http://django;
}
}
So nginx will successfully start only under 3 conditions:
secret is mounted (this could be addressed by splitting Nginx into 2 separate containers)
registry service is started
django service is started
The problem is that django image is pulling its image from the registry service, so we are in a dead-lock situation again.
I didn't mention it but both registry and django have different ServerName so nginx is able to both serve them
The solution I though about it (but it's quite dirty!) would be to reload nginx several time with more and more configurations:
I start docker registry service
I start Nginx with only the registry.conf
I create my django rc and service
I reload nginx with both registry.conf and django.conf
If there was a way to make nginx start ignoring failing configuration, that would probably solve my issues as well.
How can I cleanly achieve this setup?
Thanks for your help
Thibault
Are you using Kubernetes Services for your applications?
With a Service to each of your Pods, you have a proxy for the Pods. Even if the pod is not started, as long as the Service is started nginx will find it when looking it up as the Service has an IP assigned.
So you start the Services, then start nginx and whatever Pod you want in the order you want.

Why is Nginx routing all traffic to one subdomain?

I am new to nginx. I am trying to install GitLabs alongside an existing php project which is currently being served by Apache on port 80. My plan is to get them both working side by side on port 90 and then turn off Apache, switching both projects to Nginx on port 80.
Okay. The problem is that both subdomains are being captured by the server for my php project which should only be served to requests for db.mydomain.com. For the php project I have a file called: ccdb symlinked into /etc/nginx/sites-enabled. It contains:
server {
server_name db.mydomain.com;
listen 90; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6
root /var/www/ccdb;
index index.html index.htm index.php;
}
However, for some reason, traffic to git.mydomain.com is being serverd from /var/www/ccdb even though I have another file symlinked alongside that one called gitlab with this content:
# GITLAB
# Maintainer: #randx
# App Version: 5.0
upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
}
server {
listen 90; # e.g., listen 192.168.1.1:80; In most cases *:80 is a good idea
server_name git.mydomain.com; # e.g., server_name source.example.com;
server_tokens off; # don't show the version number, a security best practice
root /home/git/gitlab/public;
# individual nginx logs for this gitlab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
location / {
# serve static files from defined root folder;.
# #gitlab is a named location for the upstream fallback, see below
try_files $uri $uri/index.html $uri.html #gitlab;
}
# if a file, which is not found in the root folder is requested,
# then the proxy pass the request to the upsteam (gitlab unicorn)
location #gitlab {
proxy_read_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_connect_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://gitlab;
}
}
NOTE: I am accessing the two domains from an OSX machine on the same local network which has entries in it's /etc/hosts file like so:
192.168.1.100 db.mydomain.com
192.168.1.100 git.mydomain.com
Try to use:
server_name git.mydomain.com:90;
... and:
server_name db.mydomain.com:90;

Using GitLab behind nginx enabled basic_auth?

I've successfully installed GitLab for management of private repositories (it's quite awesome!).
The problem I am having is by default, Gitlab login is presented when anyone hits my subdomain. I would like to protect the entire area with a basic_auth layer before the user gets the GitLab login screen. Unfortunately, this breaks my ability to push/pull from GitLab when it's enabled.
my nginx config to enable basic_auth:
auth_basic "Restricted";
auth_basic_user_file htpasswd;
Any ideas on how I can enable basic_auth without breaking git / gitlab functionality?
Add this to /etc/gitlab/gitlab.rb:
nginx['custom_gitlab_server_config'] = "auth_basic 'Restricted';\n auth_basic_user_file htpasswd;\n"
And run gitlab-ctl reconfigure
Kind of a hack at the moment but give this is a shot.
Edit your nginx site configuration to add / modify the following locations
location ^~ /api/v3/internal/allowed {
proxy_read_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_connect_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://gitlab;}
location / {
auth_basic "Gitlab Restricted Access";
auth_basic_user_file /home/git/gitlab/htpasswd.users;
# serve static files from defined root folder;.
# #gitlab is a named location for the upstream fallback, see below
try_files $uri $uri/index.html $uri.html #gitlab;
}
Leaving your #gitlab location block as is.
The trick is you let /api/v3/internal/allowd bypass the authentication. If you look at the logs when you do an git pull / push a request is made to the server whether or not to allow it. And on the standard nginx config with htpasswd that request would be blocked because the server has no idea about the authentication required.
Anyway not sure if there's a better alternative (couldn't find any) but this seems to work for me.
Your issue is that you want set a password restriction for public access to GitLab, but let Gitlab-Shell access the local GitLab instance without restriction.
You can have 2 nginx configurations depending on the IP interface. Change the line listen 0.0.0.0:80 default_server to listen 127.0.0.1:80 default_server.
https://github.com/gitlabhq/gitlabhq/blob/v7.7.2/lib/support/nginx/gitlab#L37-38

Resources