===== Obtener IP origen sin terminar conexión SSL =====
En este escenario:
* Edge router. Es el nginx que recibe la conexión del cliente, y expone a la DMZ los puertos TCP 443 y TCP 80. Si recibe la conexión al puerto TCP 443 lo redirige (capa 4) a "behind edge" usando proxy protocol para poder proporcionarle la IP origen
* Behind edge. Servidor que expone puertos TCP 443 y TCP 80 a 'edge router'. Cuando recibe la conexión TCP 443, por protocolo 'proxy protocol', termina la conexión SSL, y por tanto entrega los certificados (autorfirmados) SSL. Tanto por TCP 80 como por TCP 443 redirige las conexiones a 'php'
* Php. Pinta las cabeceras que recibe
Requisitos:
* Docker instalado
* Docker compose instalados
* El servidor tiene que tener una IP pública
* Nombre DNS (en este ejemplo "example.com") que apunte a la IP pública del servidor
1. Edge router
1.1. Crear directorio:
mkdir edge
1.2. Crear 'default.conf':
vim edge/default.conf
Con el siguiente contenido:
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $remote_addr;
# To avoid 404. Credits:
# https://serverfault.com/a/407983/570054
proxy_set_header Host $host:$server_port;
server {
listen 80;
location / {
proxy_pass http://behind_edge;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html/;
internal;
}
}
1.3. Crear 'nginx.conf':
vim edge/nginx.conf
Con el siguiente contenido:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
upstream behind_edge {
# Docker container named 'behind_edge' sharing same docker network
server behind_edge:80;
}
}
stream {
server {
listen 443;
proxy_pass behind_edge_ssl;
proxy_protocol on;
}
upstream behind_edge_ssl {
# Docker container named 'behind_edge' sharing same docker network
server behind_edge:443;
}
log_format basic '$remote_addr - [$time_local] '
'$status '
'';
access_log /var/log/nginx/access.log basic;
}
2. Behind edge
2.1. Crear directorio:
mkdir behind_edge
2.2. Crear 'default.conf':
vim behind_edge/default.conf
Con el siguiente contenido:
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $remote_addr;
# To avoid 404. Credits:
# https://serverfault.com/a/407983/570054
proxy_set_header Host $host:$server_port;
proxy_set_header X-Custom-IP $proxy_protocol_addr;
proxy_set_header X-Custom-Port $proxy_protocol_port;
server {
listen 80;
location / {
proxy_pass http://php;
}
}
server {
listen 443 ssl proxy_protocol;
location / {
proxy_pass https://php_ssl;
}
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
}
2.3. Crear 'nginx.conf':
vim behind_edge/nginx.conf
Con el siguiente contenido:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
upstream php {
# Docker container named 'php' sharing same docker network
server php:80;
}
upstream php_ssl {
# Docker container named 'php' sharing same docker network
server php:443;
}
}
2.4. Crear:
vim behind_edge/Dockerfile
Con el siguiente contenido:
FROM nginx
RUN apt-get update && apt-get install -y \
ssl-cert
3. Php
**NOTA**: de hecho la parte de SSL en el contenedor PHP ya no es necesaria, pero bueno...
3.1. Crear directorio:
mkdir php
3.2. Crear:
vim php/index.php
Con el siguiente contenido:
$value) {
echo "$name: $value
\n";
}
?>
3.3. Crear:
vim php/Dockerfile
Con el siguiente contenido:
FROM php:7-apache
RUN apt-get update && apt-get install -y \
ssl-cert
RUN a2enmod \
remoteip \
ssl
RUN a2ensite default-ssl.conf
COPY index.php /var/www/html/
4. Crear:
vim docker-compose.yml
Con el siguiente contenido:
services:
behind_edge:
build:
context: ./behind_edge
container_name: behind_edge
volumes:
- "/home/debian/behind_edge/nginx.conf:/etc/nginx/nginx.conf:ro"
- "/home/debian/behind_edge/default.conf:/etc/nginx/conf.d/default.conf:ro"
edge:
container_name: edge
image: nginx
ports:
- 80:80
- 443:443
volumes:
- "/home/debian/edge/nginx.conf:/etc/nginx/nginx.conf:ro"
- "/home/debian/edge/default.conf:/etc/nginx/conf.d/default.conf:ro"
php:
build:
context: ./php
container_name: php
version: "3.3"
Ajustar las rutas a los archivos, en este ejemplo "/home/debian". Resumen:
.
├── behind_edge
│ ├── default.conf
│ ├── Dockerfile
│ └── nginx.conf
├── docker-compose.yml
├── edge
│ ├── default.conf
│ └── nginx.conf
└── php
├── Dockerfile
└── index.php
5. Probar. Ejecutar:
curl -s -k https://example.com
Resultado esperado similar a:
X-Real-IP: 8.8.8.8
X-Forwarded-For: 172.25.0.3
Host: php_ssl
Connection: close
User-Agent: curl/7.74.0
Accept: */*
Vemos que la cabecera 'X-Real-IP' contiene la IP pública del cliente que ha enviado la petición, en este caso '8.8.8.8'