Table of Contents
Logstash 를 이용해 로그를 프로세싱 해보자. Logstash 에 대한 기초적인 설정은 다음글에서 확인 가능하다.
또, 이 글은 Elastic 홈페이지에 내용을 기반으로 한다.
filebeat 설정 및 기동
먼저 파일 filebeat 설정을 다음과 한다.
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/linux.systemv.pe.kr.access.log
tags: ["nginx_access_log"]
fields:
server_name: linux.systemv.pe.kr
log_type: nginx-log
nginx: true
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
output.logstash:
hosts: ["192.168.97.32:5044"]
Elastic 홈페이지에는 간단하게 설정하도록 나오지만 여기서는 몇가지 설정을 추가 하였다. tags 를 설정하였고 fields 도 추가 하였다. 다음과 같이 시작 한다.
]$ ./filebeat -e -c filebeat.yml -d "publish"
logstash Nginx pipeline 설정
먼저 filebeat 으로부터 메시지가 잘 들어오는지 디버깅을 먼저 해보자. 다음과 같이 간단하게 설정을 해본다.
input {
beats {
port => "5044"
}
}
#filter {
#
#}
output {
stdout {
codec => rubydebug
}
}
INPUT 에는 filebeat 으로부터 전송을 받기 위한 port 를 지정해준다. OUTPUT 에는 디버깅을 위한 화면출력을 설정해 준다.
테스트
filebeat 의 로그 파일에 한 줄 넣어준다.
]# head -1 linux.systemv.pe.kr.access.log > /var/log/nginx/linux.systemv.pe.kr.access.log
이렇게 하고 난 후에 logstash 의 출력 로그를 보면 다음과 같이 나온다.
{
"tags" => [
[0] "nginx_access_log",
[1] "beats_input_codec_plain_applied"
],
"agent" => {
"version" => "8.1.1",
"ephemeral_id" => "55b51681-f855-46ae-8abc-f6fb7d78ebaa",
"name" => "venus8.systemv.local",
"type" => "filebeat",
"id" => "dd5018a6-31ef-4e42-95f9-2bf7b63b50f9"
},
"fields" => {
"log_type" => "nginx-log",
"nginx" => true,
"server_name" => "linux.systemv.pe.kr"
},
"input" => {
"type" => "log"
},
"host" => {
"name" => "venus8.systemv.local"
},
"message" => "112.171.18.83 - - [16/May/2021:21:01:46 +0900] \"GET /wp-admin/ HTTP/2.0\" 200 34391 \"https://linux.systemv.pe.kr/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36\" \"-\"",
"log" => {
"file" => {
"path" => "/var/log/nginx/linux.systemv.pe.kr.access.log"
},
"offset" => 0
},
"event" => {
"original" => "112.171.18.83 - - [16/May/2021:21:01:46 +0900] \"GET /wp-admin/ HTTP/2.0\" 200 34391 \"https://linux.systemv.pe.kr/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36\" \"-\""
},
"@version" => "1",
"@timestamp" => 2022-03-24T08:22:42.515Z,
"ecs" => {
"version" => "8.0.0"
}
}
여기서 보아야 할 것은 filebeat 에서 설정한 tags 와 field 다. 이것이 logstash 로 전송될때에 그대로 전송이 된다. message 에는 log 파일에 내용을 담고 있는데 이것을, 이제 필드별로 구별을 해야 한다. 이를 위해서는 로그의 형식을 알아야 한다.
Nginx 로그 형식
Nginx 의 로그 형식은 nginx 설정 파일에 log_format 에 기록되어 있다.
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
이 형식은 필요에 따라서 변경 될 수 있다. 이 형식을 알아야 한다.
Logstash FILTER pipeline 설정
이제 Nginx Pipeline 에 FILTER 를 설정해야 한다. 일 FILTER 는 들어오는 메시지를 가공처리해주는데, grok 을 이용한다. 메시지를 가공처리하는데 미리 정의된 형식도 지원한다. 다음과 같이 해보자.
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}"}
}
}
filebeat 는 한번 읽은 로그는 다시 읽지 않는다. filebeat 는 중지 시키고, 데이터 디렉토리에 registry 디렉토리를 삭제 한다.
]# cd data ]# rm -rf registry ]# filebeat -e -c filebeat.yml -d "publish"
이렇게 하면 파일을 다시 읽는다. 하지만 결과는 필드로 구분되지 않았다. 이것은 미리 정의된 FILTER 가 적용되지 않았음을 의미 한다.
FILTER 의 적용은 grok 을 사용하는데, 이것을 매번 해보는건 힘들다. 그래서 온라인으로 테스트를 할 수 있도록 도와주는 사이트가 있다.
여기에서 샘플데이터를 넣은 후에 패턴을 grok 패턴으로 적용하면 결과를 보여준다. 이 패턴을 이용하면 된다.
grok 의 사용법은 %{SYNTAX:SEMANTIC} 형식인데, SYNTAX 는 패턴이다. SEMANTIC 는 그 패턴을 담는 변수라고 보면 된다. 그런데, 이 패턴은 미리 정의되어 있는데, 다음에서 확인 가능하다.
Nginx 형식에 맞는 grok 패턴을 다음과 같이 입력 해줬다.
filter {
grok {
match => { "message" => "%{IPORHOST:remote_addr} - %{USER:remote_user} \[%{HTTPDATE:time_local}\] \"(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:status} (?:%{NUMBER:body_bytes_sent}|-) \"%{GREEDYDATA:referrer}\" \"%{GREEDYDATA:http_user_agent}\" \"%{DATA:forwarder}\"" }
}
}
이렇게 한 후에 로그를 전송하면 다음과 같이 잘 파싱된다.
{
"log" => {
"offset" => 0,
"file" => {
"path" => "/var/log/nginx/linux.systemv.pe.kr.access.log"
}
},
"host" => {
"name" => "venus8.systemv.local"
},
"remote_addr" => "112.171.18.83",
"body_bytes_sent" => "34391",
"forwarder" => "-",
"remote_user" => "-",
"http_user_agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"agent" => {
"version" => "8.1.1",
"id" => "41c16096-d133-441c-8f28-ac6182518441",
"name" => "venus8.systemv.local",
"type" => "filebeat",
"ephemeral_id" => "a6ce3e3a-a00b-427a-b7fb-8ee54c9f12d4"
},
"httpversion" => "2.0",
"ecs" => {
"version" => "8.0.0"
},
"verb" => "GET",
"status" => "200",
"input" => {
"type" => "log"
},
"tags" => [
[0] "nginx_access_log",
[1] "beats_input_codec_plain_applied"
],
"time_local" => "16/May/2021:21:01:46 +0900",
"fields" => {
"nginx" => true,
"log_type" => "nginx-log",
"server_name" => "linux.systemv.pe.kr"
},
"message" => "112.171.18.83 - - [16/May/2021:21:01:46 +0900] \"GET /wp-admin/ HTTP/2.0\" 200 34391 \"https://linux.systemv.pe.kr/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36\" \"-\"",
"referrer" => "https://linux.systemv.pe.kr/",
"@version" => "1",
"event" => {
"original" => "112.171.18.83 - - [16/May/2021:21:01:46 +0900] \"GET /wp-admin/ HTTP/2.0\" 200 34391 \"https://linux.systemv.pe.kr/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36\" \"-\""
},
"request" => "/wp-admin/",
"@timestamp" => 2022-03-24T09:35:43.924Z
}
Elasticsearch 보안
Elasticsearch 가 버전이 높아지면서 보안이 강화 됐다. 더군다나 Security 플러그인을 활성화할 경우에 각종 Rules와 Roles 들이 생성된다. 뭔가를 하기 위해서는 인증을 거쳐야 한다는 뜻이다.
Logstash 는 최종적으로 Elasticsearch 로 데이터를 보내야 한다. 이에 대한 보안 설정이 필요한데, 이에 대한 자세한 설명은 다음에 잘 나와 있다.
CA 인증서 설정
Elasticsearch 8.1 을 설치할때에 CA 인증서가 config/certs 디렉토리에 생성 되었다. RPM 으로 설치하였을 경우에 /etc/elasticsearch/certs 디렉토리인데, 여기에 http_ca.crt 파일로 존재 한다. 이것을 Logstash 에 OUTPUT 필터에서 사용해야 한다.
]# mkdir ${LOGSTASH_HOME}/config/certs
]# cp /etc/elasticsearch/certs/http_ca.crt ${LOGSTASH_HOME}/config/certs/
Logstash 를 위한 자격증명 만들기
자격증명을 만들기 위해서는 권한을 부여한 역할(Role) 를 만들어야 한다. Kibana 를 설치했다면 Management > Roles 에서 생성할 수 있다. 다음과 같이 만든다.
- Role 이름: logstash_writer
- Cluster Privileges: manage_index_templates, monitor, manage_ilm
- Indices Name: nginx-access-*
- Indices Privileges: write, create, create_index, manage, manage_ilm
이것은 다음과 같이 curl 을 이용할 수도 있다. 먼저 Role 을 위한 JSON 파일을 작성한다.
{
"cluster": ["manage_index_templates", "monitor", "manage_ilm"],
"indices": [
{
"names": [ "nginx-access-*" ],
"privileges": ["write","create","create_index","manage","manage_ilm"]
}
]
}
그리고 이제 다음과 같이 curl 명령어를 작성해 실행하면 된다.
]$ curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic:1H=APM9Dxdatua43TtRj -X POST -H "Content-Type: application/json" https://192.168.97.32:9200/_security/role/logstash_writer -d @logstash_role.json
{"role":{"created":true}}
]$
이제 사용자를 만들어야 한다. 사용자를 만들때에는 패스워드도 함께 생성하고 앞에서 만든 logstash_writer 롤을 할당해 준다.
역시 이것도 다음과 같이 JSON 형식으로 생성이 가능하다.
POST _security/user/logstash_internal
{
"password" : "x-pack-test-password",
"roles" : [ "logstash_writer"],
"full_name" : "Internal Logstash User"
}
logstash OUTPUT 파이프라인 설정
이제 Logstash 의 OUTPUT 파이프라인을 설정해야 한다. 다음과 같다.
output {
if "nginx_access_log" in [tags] {
elasticsearch {
hosts => ["https://192.168.97.32:9200"]
cacert => '/opt/logstash/config/certs/http_ca.crt'
ssl => true
user => "logstash_internal"
password => "154321"
index => "%{[fields][log_type]}-%{+YYYY.MM.dd}"
}
}
}
결론
logstash OUTPUT 파이프라인 설정이 되면 logstash 와 filebeat 을 재시작 하고 nginx 로그를 넣게 되면 이제 Elasticsearch 에 nginx-access-날짜 로 인덱스가 생성되면서 데이터가 적재된다.

