Como posso combinar dois comandos para ordenar dados de arquivos de log compactados e não compactados?

4

Estou executando este comando para obter uma contagem de tentativas de login malsucedidas do auth.log de um servidor e funciona bem:

sudo cat /var/log/auth.{log,log.1} | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

Mas o problema é que, como todos os servidores do mundo, eu tenho alguns arquivos GZipped criados por rotação de log que não serão analisados por esse comando:

-rw-r----- 1 syslog adm  7822722 Oct 31 13:44 /var/log/auth.log
-rw-r----- 1 syslog adm 12532511 Oct 25 06:59 /var/log/auth.log.1
-rw-r----- 1 syslog adm  2250939 Oct 18 06:55 /var/log/auth.log.2.gz
-rw-r----- 1 syslog adm  2139669 Oct 11 07:06 /var/log/auth.log.3.gz
-rw-r----- 1 syslog adm  2769919 Oct  4 06:54 /var/log/auth.log.4.gz

Para lidar com esses, eu tenho uma variante do comando que usa zcat em vez de cat , mas é um incômodo ter que executar dois comandos para obter esses dados. Existe alguma maneira de combinar os comandos cat e zcat em um comando para que eu possa obter resultados combinados? Eu sei que eu poderia escrever algum script Bash para filtrar através de arquivos compactados versus descompactados, mas eu uso este one-liner atual em vários servidores e eu quero ter um one-liner que eu possa consultar rapidamente e usar quando necessário.

Mais detalhes.

Eu tenho feito algumas auditorias de segurança e ajustes de firewall e tenho esse comando que executo que me dá uma boa contagem de tentativas de "Falha na senha" dos arquivos auth.log em uma máquina Ubuntu Linux:

sudo cat /var/log/auth.{log,log.1} | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

Funciona muito bem! A saída é algo como isto:

 5909 Oct 18
13444 Oct 19
  351 Oct 20
  162 Oct 21
  499 Oct 22
  377 Oct 23
  145 Oct 24
10897 Oct 25
   76 Oct 26
   54 Oct 27
  310 Oct 28
 1024 Oct 29
  208 Oct 30
   30 Oct 31

E, embora isso funcione bem para logs descompactados, como os logs são rotacionados e compactados, sempre há arquivos compactados do GZip que também podem ser incluídos. Então eu executo essa variante do comando acima que usa zcat :

sudo zcat -q /var/log/auth.log* | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

E a saída é algo assim:

gzip: /var/log/auth.log: not in gzip format

gzip: /var/log/auth.log.1: not in gzip format
  10413 Sep 27
  15977 Sep 28
  12297 Sep 29
  14438 Sep 30
  23394 Oct 1
  12912 Oct 2
  15844 Oct 3
  19697 Oct 4
  15350 Oct 5
  12358 Oct 6
  12692 Oct 7
   8377 Oct 8
  10875 Oct 9
    565 Oct 10
  16027 Oct 11
  10422 Oct 12
   6808 Oct 13
  26891 Oct 14
   9493 Oct 15
   5138 Oct 16
   9415 Oct 17
   2226 Oct 18

Como você pode ver, a saída funciona quando funciona, mas seria interessante se as variantes cat e zcat desse comando pudessem ser simplesmente combinadas em um comando. Como isso pode ser feito?

Pontos de bônus:

Estes problemas não são críticos, mas seria bom se, de alguma forma, eles pudessem ser abordados em uma solução:

  • Observe que na parte superior da saída zcat há dois erros de zcat tentando processar dois arquivos descompactados. Suprimir isso seria bom.
  • Observe também como os comandos cat e zcat mostram dados para 18 de outubro; um dia quando a rotação de log aconteceu. Haveria alguma maneira de somar esses dois valores no comando? Se não, eu estou bem em ter duas linhas de dados de 18 de outubro com valores diferentes que eu teria que somar manualmente.
por JakeGould 31.10.2015 / 18:55

2 respostas

6

Pode usar zgrep , que será descompactado se necessário e, portanto, funciona com texto simples e entrada compactada. Além disso, o grep / zgrep pode processar vários arquivos diretamente, o que é necessário neste caso, pois a entrada mista de texto e compactado para entrada padrão nem sempre funciona como planejado. Supressão de nomes de arquivos na saída do grep com -h ou --no-filename .

sudo zgrep -h 'Failed password' /var/log/auth.* | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

Página do manual:

ZGREP(1)                                                              ZGREP(1)

NAME
       zgrep - search possibly compressed files for a regular expression

SYNOPSIS
       zgrep [ grep_options ] [ -e ] pattern filename...

DESCRIPTION
       Zgrep  invokes grep on compressed or gzipped files.  All options specified
       are passed directly to grep.  If no file is specified, then  the  standard
       input  is  decompressed if necessary and fed to grep.  Otherwise the given
       files are uncompressed if necessary and fed to grep.

       If the GREP environment variable is set, zgrep uses it as the grep program
       to be invoked.

AUTHOR
       Charles Levert ([email protected])

SEE ALSO
       grep(1), gzexe(1), gzip(1), zdiff(1), zforce(1), zmore(1), znew(1)
    
por 01.11.2015 / 15:39
1

Embora seja feio digitar cada vez, você pode fazer algo como:

for log in /var/log/auth.log*; do if ! sudo zcat "$log" 2>/dev/null; then sudo cat "$log"; fi; done | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

Provavelmente seria melhor criar uma função para pelo menos a parte cat , algo como:

getLogs() {
    for log in /var/log/auth.log*; do
        if ! sudo zcat "$log" 2>&/dev/null; then
            sudo cat "$log"
        fi
    done
}

Então seu comando pode ser

getLogs | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c

ou você pode fazer a coisa toda ser uma função:

getSSHFailures() {
    for log in /var/log/auth.log*; do
        if ! sudo zcat "$log" 2>/dev/null; then
            sudo cat "$log"
        fi
    done | grep 'Failed password' | grep sshd | awk '{print $1,$2}' | sort -k 1,1M -k 2n | uniq -c
}

Então você acabou de ligar

getSSHFailures

Você poderia definir essa função no seu .bashrc e ter essa função disponível em cada shell que você iniciar

Além disso, isso também deve corrigir sua observação sobre o erro ao tentar zcat de arquivos não compactados (porque redirecionamos zcat erros para /dev/null ) e nos livramos da entrada duplicada, porque estamos imprimindo tudo os resultados juntos como um único fluxo antes de processá-los.

Finalmente, awk pode realmente fazer a correspondência de padrões para nós, então também podemos nos livrar dos 2 grep s como:

getSSHFailures() {
    for log in /var/log/auth.log*; do
        if ! sudo zcat "$log" 2>/dev/null; then
            sudo cat "$log"
        fi
    done | awk '/sshd.*Failed password/ {print $1,$2}' | sort -k 1,1M -k 2n | uniq -c
}
    
por 01.11.2015 / 13:16