AWS/EC2

ELK(Elasticsearch + Logstash + Kibana + Filebeat)로그 모니터링 - 2

Rohin 2024. 3. 25. 12:34
반응형

# Logstash + Filebeat 설치

Logstash 설치

https://www.elastic.co/guide/en/logstash/current/installing-logstash.html

 

Installing Logstash | Logstash Reference [8.12] | Elastic

Use the echo method described above to add the Logstash repository. Do not use add-apt-repository as it will add a deb-src entry as well, but we do not provide a source package. If you have added the deb-src entry, you will see an error like the following:

www.elastic.co

GPG Key 가져오기

# rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

yum 저장소 등록

# vi /etc/yum.repos.d/logstash.repo

[logstash-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

설치

# yum install logstash

데이터 전송할때 사용할 역할 생성 (Kibana를 통해서 진행했다!)

ElasticSearch로 보내기위한 계정을 생성하고 역할을 생성한다.
(Logstash데이터를 받기위해 Elasticsearch에 계정생성하는 작업이다)

역할먼저 생성한 과정
특정 index에 대한 지정을 할때는 해당 인덱스만 영향을 받으므로 *로 처리해도 문제는 없다. (위와같이 할경우 index가 nginx*, logstash* 항목에 대해서만 작업이 가능)

데이터 전송할때 사용할 계정 생성

아까 만들었던 역할의 권한을 부여하여 계정 생성
이제 logstash 설정 부분을 수정하러 간다.

logstash.yml

# cat /etc/logstash/logstash.yml

path.data: /var/lib/logstash                       # Logstash 데이터 저장 경로
path.config: /etc/logstash/conf.d/*.conf           # 읽어들일 conf 파일들 지정
path.logs: /var/log/logstash                       # Logstash log 저장 경로

위 파일은 수정할건 없었다.
Logstash 데몬에 대한 설정

Config 파일 구조

Logstash 설정은 input, filter, output 3가지로 분류된다.
input - 데이터를 수집하는 역할
filter - 데이터를 변환하는 역할
output - 데이터를 내보내는 역할

모든 역할을 한파일로 관리해도되지만 여러개의 conf 파일로 저장하여 관리도 가능하다.
예시)

# ll /etc/logstash/conf.d/
-rw-r--r--. 1 root root 1281 Mar 21 11:54 filter_nginx.conf          # nginx 관련 filter 내용 정리
-rw-r--r--. 1 root root 2581 Mar 21 15:32 filter_syslog.conf         # syslog 관련 filter 내용 정리
-rw-r--r--. 1 root root   65 Mar 20 14:19 input_filebeat.conf        # filebeat으로 들어오는 input 관련 내용 정리
-rw-r--r--. 1 root root  543 Mar 20 14:35 output_nginx.conf          # nginx 관련 output 내용 정리
-rw-r--r--. 1 root root  516 Mar 20 15:46 output_syslog.conf         # syslog 관련 output 내용 정리

필자는 간단하게 설명하고자 하나의 파일로 담아서 설명 드립니다!

test.conf

# vi /etc/logstash/conf.d/test.conf


## 데이터를 받아오는곳에 대한 정의
input {
  beats {
    port => 5044                 ## input으로 받아올 포트 지정
    type => "filebeat"           ## type 설정 (위 input으로 들어오는 데이터는 필드값이 type : filebeat 으로 지정된다)
  }
}

## 데이터를 grok 언어를 통해 파싱하기.
## if문 사용 가능 (filebeat 설정의 tags 값에 harulife-nginx-server 가 들어있으면 진행)
## grok 언어에 대한 설명은 다음항목에서 설명진행. (grok, ruby등 다양한 언어사용가능)
## mutate 설정은 grok로 쪼개놓은 필드값을 묶어서 필드화 시키는 작업
## remove_field 설정은 쪼개놓은 필드값을 보여주지 않게 설정하는 작업

filter {
  grok {
    if "harulife-nginx-server" in [tags] {
      grok {
        match => {
          "message" => [
            "%{WORD:month} %{NUMBER:day} %{NUMBER:hour}:%{NUMBER:minute}:%{NUMBER:second} %{HOSTNAME:hostname} %{DATA:sys_service}\[%{NUMBER:PID}\]: %{GREEDYDATA:message}",
            "%{WORD:month} %{NUMBER:day} %{NUMBER:hour}:%{NUMBER:minute}:%{NUMBER:second} %{HOSTNAME:hostname} %{DATA:sys_service}: %{GREEDYDATA:message}"
            ]
        }
      }
      mutate {
        add_field => {
          "time" => "%{month} %{day} %{hour}:%{minute}:%{second}"
        }
        remove_field => ["month", "day", "hour", "minute", "second"]
      }
    }
  }
}

## 데이터를 보낼곳에 대한 정의
## hosts - 보낼곳에 대한 정의
## index - index는 어떤 index에 넣을지 지정 (없으면 생성함)
## cacert - https 통신임으로 통신할때 사용할 인증서 지정
## user - elasticsearch에 데이터를 쌓을수있는 권한을 가진 계정 설정
## password - 계정에 대한 패스워드

output {
  elasticsearch {
    hosts => ["https://localhost:9200"]
    index => "nginx-%{+YYYY.MM.dd}"
    cacert => "/etc/logstash/certs/http_ca.crt"
    user => "logstash_writer"
    password => "asdfqwer1234"
  }
}

Grok에 대한 설명

https://grokdebugger.com/ 를 통해 로그를 Debug 가능

      grok {
        match => {
          "message" => [
            "%{WORD:month} %{NUMBER:day} %{NUMBER:hour}:%{NUMBER:minute}:%{NUMBER:second} %{HOSTNAME:hostname} %{DATA:sys_service}\[%{NUMBER:PID}\]: %{GREEDYDATA} %{IPV4:remote_ip}%{GREEDYDATA} %{NUMBER:Port}%{GREEDYDATA}",
            "%{WORD:month} %{NUMBER:day} %{NUMBER:hour}:%{NUMBER:minute}:%{NUMBER:second} %{SYSLOGHOST:hostname} sshd\[%{NUMBER:pid}\]: error: kex_exchange_identification: client sent invalid protocol identifier \"%{GREEDYDATA:invalid_protocol_identifier}\""
          ]
        }
      }

- grok로 파싱할때 사용할 로그 형태

더보기

2024/03/18 19:37:56 [error] 26349#0: *568 open() "/usr/share/nginx/html/pftp" failed (2: No such file or directory), client: 79.110.62.195, server: _, request: "GET /pftp HTTP/1.1", host: "43.202.65.196" 2024/03/18 19:37:56 [error] 26349#0: *569 open() "/usr/share/nginx/html/sh" failed (2: No such file or directory), client: 79.110.62.195, server: _, request: "GET /sh HTTP/1.1", host: "43.202.65.196" 2024/03/18 19:37:57 [error] 26349#0: *570 open() "/usr/share/nginx/html/sshd" failed (2: No such file or directory), client: 79.110.62.195, server: _, request: "GET /sshd HTTP/1.1", host: "43.202.65.196" 2024/03/18 19:37:57 [error] 26349#0: *571 open() "/usr/share/nginx/html/tftp" failed (2: No such file or directory), client: 79.110.62.195, server: _, request: "GET /tftp HTTP/1.1", host: "43.202.65.196" 2024/03/18 20:20:55 [error] 26349#0: *573 open() "/usr/share/nginx/html/.env" failed (2: No such file or directory), client: 185.254.196.173, server: _, request: "GET /.env HTTP/1.1", host: "43.202.65.196" 2024/03/18 21:25:28 [error] 26349#0: *579 open() "/usr/share/nginx/html/.env" failed (2: No such file or directory), client: 177.54.158.94, server: _, request: "GET /.env HTTP/1.1", host: "43.202.65.196" 2024/03/18 22:02:43 [error] 26349#0: *583 open() "/usr/share/nginx/html/aaa9" failed (2: No such file or directory), client: 137.184.226.250, server: _, request: "GET /aaa9 HTTP/1.1", host: "43.202.65.196"

- grok로 파싱할때 grok 코드

더보기

%{YEAR:year}/%{MONTHNUM:month}/%{MONTHDAY:day} %{HOUR:hour}:%{MINUTE:minute}:%{SECOND:second} \[%{LOGLEVEL:level}\] %{NUMBER:pid}#%{NUMBER}: \*%{NUMBER} %{GREEDYDATA:message}, client: %{IPORHOST:client}, server: %{DATA:server}, request: "%{WORD:http_method} %{URIPATHPARAM:request} HTTP/%{NUMBER:http_version}\", host: \"%{IPORHOST:host}\"

- grok 코드로 파싱하고 난뒤 결과값

더보기

[ { "year": 2024, "month": 3, "day": 18, "hour": 19, "minute": 37, "second": 56, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/pftp\" failed (2: No such file or directory)", "client": "79.110.62.195", "server": "_", "http_method": "GET", "request": "/pftp", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 19, "minute": 37, "second": 56, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/sh\" failed (2: No such file or directory)", "client": "79.110.62.195", "server": "_", "http_method": "GET", "request": "/sh", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 19, "minute": 37, "second": 57, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/sshd\" failed (2: No such file or directory)", "client": "79.110.62.195", "server": "_", "http_method": "GET", "request": "/sshd", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 19, "minute": 37, "second": 57, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/tftp\" failed (2: No such file or directory)", "client": "79.110.62.195", "server": "_", "http_method": "GET", "request": "/tftp", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 20, "minute": 20, "second": 55, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/.env\" failed (2: No such file or directory)", "client": "185.254.196.173", "server": "_", "http_method": "GET", "request": "/.env", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 21, "minute": 25, "second": 28, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/.env\" failed (2: No such file or directory)", "client": "177.54.158.94", "server": "_", "http_method": "GET", "request": "/.env", "http_version": 1.1, "host": "43.202.65.196" }, { "year": 2024, "month": 3, "day": 18, "hour": 22, "minute": 2, "second": 43, "level": "error", "pid": 26349, "message": "open() \"/usr/share/nginx/html/aaa9\" failed (2: No such file or directory)", "client": "137.184.226.250", "server": "_", "http_method": "GET", "request": "/aaa9", "http_version": 1.1, "host": "43.202.65.196" } ]

Logstash에 대한 설명은 끝!

 

Filebeat 설치

https://www.elastic.co/guide/en/beats/filebeat/current/setup-repositories.html

 

Repositories for APT and YUM | Filebeat Reference [8.12] | Elastic

To add the Elastic repository, make sure that you use the echo method shown in the example. Do not use add-apt-repository because it will add a deb-src entry, but we do not provide a source package. If you have added the deb-src entry by mistake, you will

www.elastic.co

GPG Key 가져오기

# rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch

yum repo 저장소 추가

[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

filebeat 설치

# yum install filebeat

filebeat.yml

###### INPUT 설정 ######
filebeat.inputs:
###### nginx_access log 설정 ######
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
    fields:
      server_name: harulife_web
      log_name: nginx_access_log
    tags: ["harulife-nginx-server", "nginx_access_log"]
    scan_frequency: 5s  ## 해당 로그를 5초간격으로 스캔한다.

###### nginx_error log 설정 ######
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/error.log
    fields:
      server_name: harulife_web
      log_name: nginx_error_log
    tags: ["harulife-nginx-server", "nginx_error_log"]

###### message log 설정 ######
  - type: log
    enabled: true
    paths:
      - /var/log/messages
    fields:
      server_name: harulife_web
      log_name: message
    tags: ["harulife-nginx-server", "messages"]

###### secure log 설정 ######
  - type: log
    enabled: true
    paths:
      - /var/log/secure
    fields:
      server_name: harulife_web
      log_name: secure
    tags: ["harulife-nginx-server", "secure"]


###### modules를 사용 여부 설정 ######
## 기본적으로 제공되는 모듈이 있지만 모두다 본인이 파싱해서 사용하겠다면 false 한다.
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false

###### 사용할 shards 수 지정 ######
## 사용빈도가 많다면 해당 값을 늘려준다.
setup.template.settings:
  index.number_of_shards: 1



###### OUTPUT 설정 ######
output.logstash:
  hosts: ["172.31.28.41:5044"]


processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~


## 로컬에서 debug 설정
logging.level: debug
logging.to_files: true
logging.files:
  path: /var/log/filebeat
  name: filebeat
  keepfiles: 7
  permissions: 0640

세분화된 설명

  - type: log                             ## Type은 뭘로 할건지 설정
    enabled: true                         ## 실행 할건지 말건지 설정
    paths:                                ## 수집할 로그 paths 설정
      - /var/log/nginx/access.log         
    fields:                               ## 해당 로그에 대해 fields 설정
      server_name: harulife_web               ## fields.server_name 이라는 필드가 생성되며 해당 필드값은 harulife_web 이 된다.
      log_name: nginx_access_log.         
    tags: ["harulife-nginx-server", "nginx_access_log"]   ## tags가 달린채로 데이터를 넘긴다. (tags 필드도 생김)
    scan_frequency: 5s                    ## 해당 로그를 5초간격으로 스캔한다.

 

위와같이 설정후 이제 Kibana에서 확인하면된다!