Nginx 로그를 위한 Logstash Pipeline 설정하기
Logstash 를 이용해 로그를 프로세싱 해보자. Logstash 에 대한 기초적인 설정은 다음글에서 확인 가능하다.
또, 이 글은 Elastic 홈페이지에 내용을 기반으로 한다.
filebeat 설정 및 기동
먼저 파일 filebeat 설정을 다음과 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 도 추가 하였다. 다음과 같이 시작 한다.
1 |
]$ ./filebeat -e -c filebeat.yml -d "publish" |
logstash Nginx pipeline 설정
먼저 filebeat 으로부터 메시지가 잘 들어오는지 디버깅을 먼저 해보자. 다음과 같이 간단하게 설정을 해본다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
input { beats { port => "5044" } } #filter { # #} output { stdout { codec => rubydebug } } |
INPUT 에는 filebeat 으로부터 전송을 받기 위한 port 를 지정해준다. OUTPUT 에는 디버깅을 위한 화면출력을 설정해 준다.
테스트
filebeat 의 로그 파일에 한 줄 넣어준다.
1 |
]# head -1 linux.systemv.pe.kr.access.log > /var/log/nginx/linux.systemv.pe.kr.access.log |
이렇게 하고 난 후에 logstash 의 출력 로그를 보면 다음과 같이 나온다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
{ "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 에 기록되어 있다.
1 2 3 |
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 을 이용한다. 메시지를 가공처리하는데 미리 정의된 형식도 지원한다. 다음과 같이 해보자.
1 2 3 4 5 |
filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} } } |
filebeat 는 한번 읽은 로그는 다시 읽지 않는다. filebeat 는 중지 시키고, 데이터 디렉토리에 registry 디렉토리를 삭제 한다.
1 2 3 |
]# cd data ]# rm -rf registry ]# filebeat -e -c filebeat.yml -d "publish" |
이렇게 하면 파일을 다시 읽는다. 하지만 결과는 필드로 구분되지 않았다. 이것은 미리 정의된 FILTER 가 적용되지 않았음을 의미 한다.
FILTER 의 적용은 grok 을 사용하는데, 이것을 매번 해보는건 힘들다. 그래서 온라인으로 테스트를 할 수 있도록 도와주는 사이트가 있다.
여기에서 샘플데이터를 넣은 후에 패턴을 grok 패턴으로 적용하면 결과를 보여준다. 이 패턴을 이용하면 된다.
grok 의 사용법은 %{SYNTAX:SEMANTIC} 형식인데, SYNTAX 는 패턴이다. SEMANTIC 는 그 패턴을 담는 변수라고 보면 된다. 그런데, 이 패턴은 미리 정의되어 있는데, 다음에서 확인 가능하다.
Nginx 형식에 맞는 grok 패턴을 다음과 같이 입력 해줬다.
1 2 3 4 5 |
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}\"" } } } |
이렇게 한 후에 로그를 전송하면 다음과 같이 잘 파싱된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
{ "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 필터에서 사용해야 한다.
1 2 |
]# 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 파일을 작성한다.
1 2 3 4 5 6 7 8 9 |
{ "cluster": ["manage_index_templates", "monitor", "manage_ilm"], "indices": [ { "names": [ "nginx-access-*" ], "privileges": ["write","create","create_index","manage","manage_ilm"] } ] } |
그리고 이제 다음과 같이 curl 명령어를 작성해 실행하면 된다.
1 2 3 |
]$ 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 형식으로 생성이 가능하다.
1 2 3 4 5 6 |
POST _security/user/logstash_internal { "password" : "x-pack-test-password", "roles" : [ "logstash_writer"], "full_name" : "Internal Logstash User" } |
logstash OUTPUT 파이프라인 설정
이제 Logstash 의 OUTPUT 파이프라인을 설정해야 한다. 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 |
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-날짜 로 인덱스가 생성되면서 데이터가 적재된다.