lørdag den 28. januar 2017

Log management med ELK - part 1

Log management - der er ingen undskyldning

Har du et overblik over hvem, der besøger dine services, hvilken klient de bruger til det og hvad de er interesseret i?

Det overblik har jeg:


Jeg er medejer at et lille startup (http://compark.dk), hvor vi har flere services (webservices, web løsninger, hjemmesider mm.) og vi interesserer os meget for at holde styr på vores butik; til dette bruger vi Elasticsearch, Logstash og Kibana - populært kaldet ELK.

Jeg har tidligere beskrevet hvordan man bruger nginx og jeg vil nu vise, hvordan man kan trække logs ind i Elasticsearch for en sådan service. I eksemplet benyttes docker.

nginx logs -> ELK i docker

Først skriver vi en konfiguration til Logstash, som kan læse access loggen fra nginx. Opret logstash.conf og giv den følgende indhold:

input {
  file {
    path => "/var/log/nginx.access.log"
    type => "nginx"
  }
}

output {
  elasticsearch { hosts => ['elasticsearch'] }
}

filter {
  if [type] == "nginx" {
   grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
   }
  }
}

I input definerer vi, at vi tager fra filen med den pågældende sti. Her er det også muligt at sætte start_from => "beginning", hvis man ønsker at indlæse alt fra filen helt forfra. Default er at starte fra "end".

I output kan vi skrive til flere forskellige kilder. Jeg nøjes med at skrive til elasticsearch hostnamet på default porten 9200.

Filter bruges til at definere, hvordan linjerne skal tolkes af logstash. COMBINEDAPACHELOG er formatet nginx spytter ud.

Inden vi kan starte de nyere versioner af Elasticsearch, er vi nødt til at fortælle vores host system, at vm'ere skal have lov at bruge lidt mere memory. Følgende linje skal derfor ind i /etc/sysctl.conf

  vm.max_map_count=262144

Da dette først træder i kraft ved næste genstart, kan denne kommando bruges til at sætte værdien her og nu:
  >  sysctl -w vm.max_map_count=262144

Nu er vi klar til at starte vores ELK stak op.

Først starter vi Elasticsearch 5.1.1 med docker:
  > docker run -d --name elasticsearch elasticsearch:5.1.1

Så starter vi logstash, så der kan komme noget data ind i elasticsearch:
  > docker run -d --name logstash -v /var/log/nginx.access.log:/var/log/nginx.access.log -v /path/to/logstash.conf:/logstash.conf --link elasticsearch:elasticsearch logstash:5.1.1 logstash -f /logstash.conf

Containeren har fået to datavolumes med fra hosten: logstash.conf og nginx.access.log. Containeren er også linket til elasticsearch, så den kan sende data dertil via hostnamet "elasticsearch".

Nu skal vi blot starte kibana:
 > docker run -d --name kibana -p 5601:5601 --link elasticsearch:elasticsearch kibana:5.1.1

Start en browser og bevæg dig til localhost:5601, hvor kibana nu udstiller de data, der kommer ind i elasticsearch fra logstash.

Reverseproxy med nginx - part 2

Reverseproxy med nginx - part 2 - SSL og static content

I første del af denne guide, beskrev jeg, hvordan man sætter nginx op til at agere reverseproxy, hvis man har flere subdomæner, man ønsker at udstille. Nu vil jeg beskrive hvordan man får nginx til at servere https trafik og hvordan man lader sine applikationer servere dynamisk indhold, mens nginx tager sig af alt det statiske.

Vi starter med et eksempel på en konfiguration, der udstiller en service på port 443 (https), men som også tager mod forespørgsler på port 80 (http) og dirigerer dem til samme service på port 443.

server {
 listen 443 ssl;
 ssl_certificate /etc/letsencrypt/live/test.sysprog.dk/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/test.sysprog.dk/privkey.pem;
 server_name test.sysprog.dk;
 access_log /var/log/nginx.access.log;
 error_log /var/log/nginx_error.log debug;
 location / {
        include conf.d/proxy.conf;
        proxy_pass http://localhost:1337;
 }
}

server {
 listen 80;
 server_name test.sysprog.dk;
 return 301 https://$host$request_uri;
}

besøger man http://test.sysprog.dk, vil man få en http 301 og ryge videre til https://test.sysprog.dk, som er en proxy til en service, der kører lokalt på port 1337 på serveren. Http servicen på port 1337 udstilles altså via https takket være nginx og certifikat-servicen letsencrypt: https://letsencrypt.org/

Static content

Lad os antage, at servicen på test.sysprog.dk er en Spring boot applikation, som også har noget statisk indhold, jeg ikke behøver belemre applikationen med at levere. Når jeg alligevel har sat en nginx op foran, kan jeg jo lade den klare sådan en opgave.

server {
 listen 443 ssl;
 ssl_certificate /etc/letsencrypt/live/test.sysprog.dk/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/test.sysprog.dk/privkey.pem;
 server_name test.sysprog.dk;
 access_log /var/log/nginx.access.log;
 error_log /var/log/nginx_error.log debug;
 location / {
        include conf.d/proxy.conf;
        proxy_pass https://localhost:8443;
 }
 location /assets {
     root /path/to/application/target/classes/static;
 }
}

server {
 listen 80;
 server_name test.sysprog.dk;
 return 301 https://$host$request_uri;
}


På denne måde vil alle requests til /assets/.... blive håndteret af nginx, som finder det statiske inhold i /path/to/application/target/classes/static

fredag den 13. januar 2017

Reverseproxy med nginx - part 1

Reverseproxy med nginx - part 1

Dette forudsætter at nginx er installeret på systemet. Guiden henvender sig til Debian baserede systemer, men vil også kunne anvendes på andre systemer; det er da ikke givet at stierne til konfigurationsfiler er ens.

Opret /etc/nginx/conf.d/proxy.conf med følgende indhold

proxy_redirect 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;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;

Denne fil kan nu inkluderes i andre konfigurationer, så man får sat headers på alle forwards fremover.

Opret /etc/nginx/conf.d/sub.domain.dk.conf (kald filen hvad du har lyst til) med følgende indhold:

server {
 listen 80;
 server_name sub.domain.dk;
 access_log /var/log/nginx.access.log;
 error_log /var/log/nginx_error.log debug;
 location / {
  include conf.d/proxy.conf;
  proxy_pass http://localhost:3000;
 }
}

Linje for linje, betyder det, at vi lytter på port 80.
server_name beskriver at reglen skal gælde, når sub.domain.dk rammes.
Access og error log beskrives.
Definer en regel for location /
Her inkluderer jeg de generelle konfigurationer, der blev sat i proxy.conf
Derefter beskrives, hvor requests skal sendes hen

I de tilfælde, hvor man ønsker et login, før der redirected til en side, tilføjer man disse to linjer på en location:
  auth_basic "Restricted"; #For Basic Auth
  auth_basic_user_file /etc/nginx/.htpasswd;

Dette giver kun basic auth. Der er også ldap plugins og meget andet.
Opret en bruger i /etc/nginx/.htpasswd med htpasswd som kan findes i pakken "apache2-utils"

Eks:
  sudo htpasswd -c /etc/nginx/.htpasswd bruger1
  sudo htpasswd /etc/nginx/.htpasswd bruger2

På en location er der også mulighed for at sætte andre begrænsninger, som eks. antallet af samtidige forbindelser pr. IP, limit på bandwidth mm.

Nu har du oprettet et subdomæne, som forwardes til port 3000 på localhost. Man kan oprette flere ved at placere endnu en fil i conf.d mappen:

Opret /etc/nginx/conf.d/sub2.domain.dk.conf (kald filen hvad du har lyst til) med følgende indhold:

server {
 listen 80;
 server_name sub2.domain.dk;
 access_log /var/log/nginx.access.log;
 error_log /var/log/nginx_error.log debug;
 location / {
  include conf.d/proxy.conf;
  auth_basic "Restricted";

  auth_basic_user_file /etc/nginx/.htpasswd;
  proxy_pass http://localhost:3001;
 }
}

Nu har du oprettet endnu et subdomæne, som forwardes til port 3001 på localhost. Dette subdomæne kører med basic auth.