Buenas a todo@s. En este post vamos a hacer que nuestro graylog, reciba los logs de apache montado en docker y bajo un web proxy que será traefik. A primera vista parece sencillo, pero hay que hacer un par de cosillas para que toda la info llegue correcta y podamos manipularla.
Pasos previos
Graylog
Antes que nada, tenemos que tener montado nuestro graylog. Este irá sobre docker y con traefik y lo desplegaremos con docker-compose.
mkdir graylog && cd graylog
vim docker-compose.yml
version: '3' services: mongodb: container_name: graylog_mongodb image: mongo:3 volumes: - mongodb:/data/db:Z networks: - backend labels: - "traefik.enable=false" elasticsearch: container_name: graylog_elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:5.6.10 volumes: - elasticsearch:/usr/share/elasticsearch/data:Z environment: - http.host=0.0.0.0 - xpack.security.enabled=false - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - cluster.name=graylog - TZ=Europe/Madrid ulimits: memlock: soft: -1 hard: -1 networks: - backend labels: - "traefik.enable=false" graylog: container_name: graylog_server image: graylog/graylog:2.4 environment: GRAYLOG_PASSWORD_SECRET: pc5segCzHPNlVn5eTIU0mrQtSiueSQTXIq0XOe0ZSarEqJ3yw6VY58INFNrATDnaUzVdquh6ugY0HHHHCqstARbr8gV3zyrI GRAYLOG_ROOT_PASSWORD_SHA2:faddf971d18f29934eeec767f66c1026bb3ad6a927501d9783ed009c7829abe5GRAYLOG_WEB_ENDPOINT_URI: 'https://graylog.example.com/api' GRAYLOG_ELASTICSEARCH_HOSTS: 'http://elasticsearch:9200' GRAYLOG_ROOT_TIMEZONE: 'Europe/Madrid' GRAYLOG_SERVER_JAVA_OPTS: '-Xms512m -Xmx512m -XX:NewRatio=1 -XX:MaxMetaspaceSize=128m -server -XX:+ResizeTLAB -XX:+UseConcMarkSweepGC -XX:+CMSConcurrentMTEnabled -XX:+CMSClassUnloadingEnabled -XX:+UseParNewGC -XX:-OmitStackTraceInFastThrow' ES_MEMORY: 1g TZ: 'Europe/Madrid' volumes: - conf:/usr/share/graylog:Z - journal:/usr/share/graylog/data/journal:Z - ./confs/GeoLite2-City.mmdb:/etc/graylog/server/GeoLite2-City.mmdb depends_on: - mongodb - elasticsearch links: - mongodb:mongo ports: - 1514:1514/tcp - 1514:1514/udp networks: - backend - traefik labels: - "traefik.backend=graylog" - "traefik.frontend.rule=Host:graylog.example.com" - "traefik.docker.network=traefik" - "traefik.port=9000" volumes: mongodb: elasticsearch: conf: journal: networks: backend: traefik: external: name: traefik
Ahora añadiremos la base de datos de geolite2
mkdir confs && cd confs
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz && tar -zxvf GeoLite2-City.tar.gz GeoLite2-City_20180911/GeoLite2-City.mmdb && mv GeoLite2-City_*/GeoLite2-City.mmdb . && rm -fr GeoLite2-City.tar.gz GeoLite2-City_*
Una vez con esto levantar el stack
docker-compose up -d
Traefik
Ahora tenemos que hacer que Traefik pase la IP del host que accede a apache. Esto se hace con el parámetro forwardedHeaers , de lo contrario, en los logs de apache solo se verán peticiones desde la IP de traefik.
vim traefik.toml
[entryPoints] [entryPoints.http] address = ":80" [entryPoints.http.forwardedHeaders] trustedIPs = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"] [entryPoints.https] address = ":443" [entryPoints.https.forwardedHeaders] trustedIPs = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
Apache
Y por último, queda configurar apache para que en los logs interprete bien la IP externa. Para ello, hay que habilitar un módulo y configurar los logs.
Habilitar el módulo:
a2enmod remoteip
Editar el apache.conf o httpd.conf y des-comentar:
LoadModule remoteip_module modules/mod_remoteip.so
Y cambiar el formato el log. Hay que cambiar el %h por el %a
#LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
Y reiniciar apache
Configuración
Apache
Hay que configurar apache para mandar los logs a graylog. Si se ha montado con docker. Basta con añadir en el docker-compose en la sección de apache lo siguiente:
logging: driver: syslog options: syslog-address: "udp://graylog.example.com:1514" tag: "apache"
Si no es así, hay que mirar cual es la opción que mas nos conviene. Graylog tiene una herramienta que es el sidecar para enviar logs.
Graylog
En graylog, hay que hacer unas primeras configuraciones para que funcione la geolocalización
Ir a configuración y habilitar la geo-location
Y poner en orden correcto el Message Processors Configuration. Lo importante es que el GeoIP Resolver esté al final
Ahora toca crear el input para recibir los logs. Para esto ir a la sección de Inputs y crear uno. En nuestro caso va a ser del tipo Syslog UDP .
Ahora le añadiremos un extractor de Apache. Esto puede que haya que adaptarlo cada uno a sus logs
Importar el extractor
El que vamos a utilizar es este pero un poco cambiado. Solo hay que copiar y pegarlo
{ "extractors": [ { "title": "Apache Time", "extractor_type": "regex", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "apache_time", "extractor_config": { "regex_value": "\\:(\\d+\\:\\d+:\\d+)\\s" }, "condition_type": "none", "condition_value": "" }, { "title": "Apache user agent", "extractor_type": "split_and_index", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_client_UserAgent", "extractor_config": { "index": 6, "split_by": "\"" }, "condition_type": "none", "condition_value": "" }, { "title": "Apache_date", "extractor_type": "regex", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_date", "extractor_config": { "regex_value": "\\[(\\d+\\/\\w+\\/\\d+)" }, "condition_type": "none", "condition_value": "" }, { "title": "Apache Client IP", "extractor_type": "split_and_index", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_client_IP", "extractor_config": { "index": 2, "split_by": " " }, "condition_type": "regex", "condition_value": "(?<![0-9])(?:(?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[.](?:[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(?![0-9])" }, { "title": "Apache http request", "extractor_type": "split_and_index", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_http_request", "extractor_config": { "index": 2, "split_by": "\"" }, "condition_type": "none", "condition_value": "" }, { "title": "Apache referrer", "extractor_type": "split_and_index", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_referrer", "extractor_config": { "index": 4, "split_by": "\"" }, "condition_type": "none", "condition_value": "" }, { "title": "Whois", "extractor_type": "lookup_table", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "Apache_client_IP", "target_field": "Whois", "extractor_config": { "lookup_table_name": "whois" }, "condition_type": "none", "condition_value": "" }, { "title": "Apache http status code", "extractor_type": "regex", "converters": [], "order": 0, "cursor_strategy": "copy", "source_field": "message", "target_field": "Apache_http_status", "extractor_config": { "regex_value": "HTTP[^\"]*\" (200|301|302|304|404|500)" }, "condition_type": "none", "condition_value": "" } ], "version": "2.4.6" }
Y una vez hecho esto, los logs de apache ya empezarán a tener mas campos y podremos manipularlos de una manera mas fácil
Con esto, ya se podrá empezar a crear dashboards e ir añadiendo lo que nos interese.
Hola Isma!
Soy Quique, cuánto tiempo! ¿Sería muy complicado esto mismo aplicado a Nginx? Tenemos un compose con Nginx y Tomcat 8 y nos gustaría gestionar esos logs.
Una alegría leerte. Un abrazo,
Quique