ElastAlert2는 Yelp에서 만든 ElastAlert을 기반으로 발전한 오픈소스입니다. 더 이상 ElastAlert은 관리되지 않기에 ElastAlert2를 사용해야 합니다. 이와 관련하여 ElastAlert 공식 Github에서도 다음과 같이 기재해두었습니다.
ElastAlert is no longer maintained. Please use ElastAlert2 instead.
ElastAlert2는 도커를 통해서도 설치가 가능한데, 여기서는 Python Package
를 이용하여 설치하는 방법으로 진행하겠습니다. 다른 설치 방법은 공식 문서를 참고해주세요.
- CentOS 7.9
- Python 3.11
- OpenSSL 1.1.1
- ElastAlert2 2.13.2
ElastAlert2를 사용하기 위해서는 Python 3.11
이상의 버전이 필요합니다.
현재 설치된 버전을 아래 명령어로 확인해주세요.
python3 --version
# or
python3 -V
만약 설치가 되어있지 않거나 Python 3.11
보다 낮은 버전인 경우, python을 설치해야 합니다. 여기서는 설치하는 과정을 진행하도록 하겠습니다.
먼저 CentOS를 업데이트 합니다.
sudo yum -y update
업데이트를 완료하면 서버를 재부팅해주세요.
sudo systemctl reboot
재부팅이 되면 Python 3.11
을 설치하기 위한 패키지를 설치합니다. CentOS 7 / RHEL 7
의 경우 Python 3.11
을 공식적으로 지원하지 않아 소스 코드를 직접 설치해야 하는데 이 때 아래의 패키지가 필요하기 때문입니다. 이미 설치가 되어 있다면 Noting to do
라는 문구가 화면에 표출됩니다.
sudo yum -y install epel-release
sudo yum install -y wget make cmake gcc bzip2-devel libffi-devel zlib-devel
그 다음으로 Python 3.11
을 빌드하기 위해 필요한 OpenSSL 1.1.1
를 설치하도록 하겠습니다. 참고로, OpenSSL 1.1.1
이상의 버전이면 어떤 버전이든 괜찮습니다.
설치 전 먼저 현재 openssl
이 존재하는지 확인해주세요.
openssl version
현재 설치된 버전이 OpenSSL 1.1.1
이상의 버전이 아니라면 제거합니다.
sudo yum -y remove openssl openssl-devel
그 다음 OpenSSL 설치에 필요한 패키지를 추가로 설치합니다.
sudo yum install -y gcc-c++ pcre-devel perl
패키지 설치가 완료되면, 아래 명령어를 통해 압축 파일을 다운로드 받거나 공식 문서에서 직접 다운로드 받아 서버로 업로드 합니다.
wget https://www.openssl.org/source/openssl-1.1.1v.tar.gz
다운로드가 완료되면 압축을 해제합니다.
tar xvf openssl-1.1.1v.tar.gz
그 다음 생성된 디렉터리로 이동(cd openssl-1.1.1v
) 후 OpenSSL
을 설정합니다.
./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl
설정이 완료되면 아래 명령어를 통해 OpenSSL 1.1.1
버전을 빌드합니다.
make -j $(nproc)
이제 OpenSSL 1.1.1
을 설치할 수 있습니다. 아래 명령어를 통해 설치해 주세요.
sudo make install
설치가 완료되면 공유 라이브러리 캐시를 업데이트 합니다.
sudo ldconfig
그 다음 시스템 전체 OpenSSL 설정을 업데이트 합니다.
sudo tee /etc/profile.d/openssl.sh<<EOF
export PATH=/usr/local/openssl/bin:\$PATH
export LD_LIBRARY_PATH=/usr/local/openssl/lib:\$LD_LIBRARY_PATH
EOF
업데이트가 완료되면 쉘 환경을 리로드합니다.
source /etc/profile.d/openssl.sh
서버를 logout
했다가 다시 접속하여 OpenSSL
버전을 확인하면, 1.1.1
로 설정된 것을 확인할 수 있습니다.
openssl version
# 아래와 같이 화면에 표출됨
# OpenSSL 1.1.1v 1 Aug 2023
이제 Python 3.11
설치를 위한 준비가 끝났습니다. 아래 명령어를 이용해서 Python 3.11
설치용 압축 파일을 다운로드 받거나 공식 문서에서 직접 다운로드 받아 서버로 업로드 합니다.
wget https://www.python.org/ftp/python/3.11.4/Python-3.11.4.tgz
다운로드가 완료되면 압축을 해제합니다.
tar xvf Python-3.11.4.tgz
그 다음 생성된 디렉터리로 이동(cd Python-3.11.4
) 후 아래 명령어를 통해 설정합니다.
LDFLAGS="${LDFLAGS} -Wl,-rpath=/usr/local/openssl/lib" ./configure --with-openssl=/usr/local/openssl
설정이 완료되면 빌드해주세요. 빌드하는 데 조금 걸릴 수 있습니다.
make
빌드가 완료되었다면, 이제 Python 3.11
을 설치할 수 있습니다. 아래 명령어를 통해 설치해 주세요.
sudo make altinstall
설치가 완료되면 다음 명령어를 통해 버전이 뜨는지 확인해주세요.
python3.11 --version
# or
python3.11 -V
그리고 설치 과정에서 pip
도 함께 설치됩니다. pip
도 python
과 마찬가지로 --version
또는 -V
를 통해 버전 확인이 가능합니다.
pip3.11 --version
# or
pip3.11 -V
ElastAlert2를 설치하기 전, Python 모듈을 업데이트 합니다.
pip3.11 install "setuptools>=11.3"
pip 업그레이드도 진행해주세요.
pip3.11 install --upgrade pip
그 다음 공식 Github에서 필요한 버전을 다운로드 받습니다. 저는 $HOME
에 elastalert2
디렉터리를 생성하고 그 안에 다운로드 받았습니다. 참고로, git clone
을 통해 받으시는 방법도 있습니다.
다운로드가 완료되면 압축을 해제합니다.
tar xvf elastalert2-2.13.2.tar.gz
압축 해제가 완료되면, 생성된 디렉터리(elastalert2-2.13.2
)로 이동합니다.
그리고 ElastAlert을 설치하기 위해 필요한 모듈을 먼저 설치합니다.
pip3.11 install -r requirements.txt
그 다음 setup.py
의 install_requires
내에 있는 모듈 설정을 모두 주석 처리합니다. 이렇게 하는 이유는 install_requires
의 모듈은 기본적으로 pip
를 통해 설치되기 때문입니다. 그러나 여기서는 pip3.11
로 실행해야 하기 때문에 이러한 과정이 필요합니다. 이러한 과정이 싫다면 pip 실행 시 pip3.11이 실행되도록 변경하면 됩니다.
import os
from setuptools import find_packages
from setuptools import setup
base_dir = os.path.dirname(__file__)
setup(
# 내용 생략
install_requires=[
# 'apscheduler>=3.9.1.post1,<4.0',
# 'aws-requests-auth>=0.4.3',
# 'boto3>=1.26.30',
# 'cffi>=1.15.1',
# 'croniter>=1.3.8',
# 'elasticsearch==7.10.1',
# 'envparse>=0.2.0',
# 'exotel==0.1.5',
# 'Jinja2>=3.1.2',
# 'jira>=3.4.1',
# 'jsonpointer>=2.3',
# 'jsonschema>=4.17.3',
# 'prison>=0.2.1',
# 'prometheus_client>=0.15.0',
# 'python-dateutil>=2.8.2',
# 'PyYAML>=6.0',
# 'py-zabbix>=1.1.7',
# 'requests>=2.8.2',
# 'sortedcontainers>=2.4.0',
# 'statsd-tags==3.2.1.post1',
# 'stomp.py>=8.1.0',
# 'tencentcloud-sdk-python>=3.0.795',
# 'texttable>=1.6.7',
# 'twilio>=7.16.0',
# 'tzlocal==2.1'
]
)
만약 이렇게 하지 않고 setup.py
를 설치하면 다음과 같은 에러가 발생하게 됩니다.
Download error on https://pypi.org/simple/: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1002) -- Some packages may not be found!
모듈 설치가 완료되면, 아래 명령어를 사용하여 ElastAlert2
를 설치합니다.
sudo python3.11 setup.py install
그 다음 ElastAlert이 동작하는데 필요한 Elasticsearch 인덱스를 생성하면 설치가 끝납니다. 만약 여러 대의 Elastsearch Cluster를 바라보고 있는 ElastAlert 서버가 여러 대라면, ElastAlert 한 대에서만 진행해주세요.
elastalert-create-index
그리고 Elastsearch 1대에 대한 host, port 정보와 username, password 정보를 입력합니다. 만약 index
이름을 따로 설정하고 싶다면 원하는 대로 입력해주세요. 여기서는 elastalert
으로 설정했습니다. 설정하지 않으면 elastalert_status
라고 저장됩니다.
생성이 완료되었는지는 Kibana DevTools에서 확인해보겠습니다.
GET _cat/indices/elastalert*?v&s=index:desc
Kibana DevTools에 위와 같이 입력하고 실행하면, 다음과 같은 내용을 확인할 수 있습니다.
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open elastalert_status rnVmB4KzSOuORgnZn5v9Vg 1 1 0 0 416b 208b
green open elastalert_silence wQ5tzi49TKG0EFtrae_ESQ 1 1 0 0 416b 208b
green open elastalert_past JCYlZdA2SCmcIeY_sPdHJQ 1 1 0 0 416b 208b
green open elastalert_error KH8xpGLDSdWnME13limEQQ 1 1 0 0 416b 208b
green open elastalert PlfHTmXrRuOX3bDtSuvKAA 1 1 0 0 416b 208b
ElastAlert 설치가 완료되었으므로, 이제 실행을 위한 설정을 진행하도록 하겠습니다. 먼저, 설정 파일인 config.yml
과 규칙을 저장할 rules
디렉터리를 생성합니다. 여기서는 elastalert2
디렉터리 위치에 생성했으며, 구조는 다음과 같습니다.
elastalert2
├── config.yaml
├── elastalert2-2.13.2
└── rules
그 다음 config.yaml
을 아래와 같이 작성합니다.
rules_folder: rules
run_every:
seconds: 10
buffer_time:
minutes: 15
use_ssl : True
ca_certs: <ElasticSearch CA 파일 경로>
es_host: 10.0.0.1
es_port: 9200
es_username: <Elasticsearch user name>
es_password: <Elasticsearch 패스워드>
es_hosts:
- 10.0.0.1:9200
- 10.0.0.2:9200
- 10.0.0.3:9200
- 10.0.0.4:9200
- 10.0.0.5:9200
writeback_index: elastalert
query_key: "env"
rules_folder
: 규칙 파일이 위치한 디렉터리 경로run_every
: 규칙을 리로드하는 시간 간격 (defaultminutes: 5
)buffer_time
: 지정한 시간 범위 내에서 이벤트나 패턴을 역추적하고 알림을 생성하기 위해 사용되는 설정use_ssl
: SSL 사용 여부 설정ca_certs
: ElasticSearch CA 파일 경로 설정es_hosts
: ElastSearch 목록es_host
: Elasticsearch IPes_port
: Elasticsearch Portes_username
: Elasticsearch 사용자 이름es_password
: Elasticsearch 사용자 비밀번호es_hosts
: Elasticsearch 클러스터 목록writeback_index
: ElastAlert2가 데이터를 저장할 인덱스 이름query_key
: 인덱스 내 알림 그룹 기준
rule을 생성하기 전, ElastAlert의 rule type에 대해 간단히 알아보겠습니다.
any
: 모든 필드blacklist
: 특정 필드가 블랙 리스트에 포함되어 있을 때whitelist
: 특정 필드가 화이트 리스트에 포함되어 있지 않을 때change
: 특정 필드의 값이 변경된 경우frequency
: 주어진 시간 내에 특정 수의 이벤트가 있을 때spike
: 두 슬라이딩 윈도우 내의 이벤트 수 비교하여spike_height
이전 기간보다 몇 배 더 크거나 작은 경우flatline
: 일정 기간 동안 발생한 총 이벤트 수가 주어진 값보다 적을 때new_term
: 필드에 이전에 볼 수 없었던 새로운 값이 나타날 때cardinality
: 특정 시간 동안 특정 필드에 대한 고유 값의 총 개수가 임계값보다 높거나 낮을 때metric_aggregation
:calculation window
의 메트릭 값이 임계값보다 높거나 낮을 때spike_aggregation
:calculation window
의 메트릭 값이spike_height
이전 기간보다 몇 배 더 크거나 작은 경우percentage_match
:calculation window
내match bucket
에 있는 문서의 백분율이 임계값보다 높거나 낮은 경우
각 rule type에 따라 설정하는 옵션이 다르며, 상세한 설명이나 사용 가능한 옵션은 공식 문서를 참고하시길 바랍니다.
rule을 생성하기 전, 먼저 조건에 맞는 인덱스와 도큐먼트를 생성합니다. 이 때, 도큐먼트에 date
타입을 가지는 필드를 가지고 있어야 ElastAlert에서 날짜에 대해 구분할 수 있습니다.
ElastAlert에서는 기본적으로 @timestamp
필드를 기준으로 알림을 보냅니다. 알림을 보내는 필드 기준을 변경하기 위해 date
타입을 두 개 생성해보았습니다.
# 인덱스 생성
PUT testalertindex
{
"mappings": {
"properties": {
"@timestamp": {"type": "date"},
"datetime": {"type": "date"},
"name": {"type": "text"},
"env": {"type": "keyword"}
}
}
}
# 도큐먼트 생성
PUT testalertindex/_doc/1
{
"@timestamp": "2023-10-23T00:00+09:00",
"datetime": "2023-10-22T15:00:00+09:00",
"name": "kim1",
"env": "prod"
}
그 다음, any
타입으로 rule을 생성해보도록 하겠습니다. 알림은 Teams
를 통해 받도록 설정하였습니다.
name: "test any"
type: any
index: testalertindex
filter:
- query:
query_string:
query: "name: kim*"
alert:
- "ms_teams"
ms_teams_webhook_url: "MS Teams Webhook URL"
rule이 정상 동작하는지 테스트를 진행합니다.
elastalert-test-rule --config config.yaml rules/test_any.yaml
테스트를 진행하면 현재 시간 기분으로 24시간 전부터 15분마다 쿼리에 맞는 도큐먼트가 있는지 검색합니다. 그러면 다음과 유사하게 @timestamp
시간대에 알림이 하나 있는 것을 발견합니다.
# ...
INFO:elastalert:Queried rule test any from 2023-10-22 14:58 KST to 2023-10-22 15:13 KST: 0 / 0 hits
# ...
INFO:elastalert:Queried rule test any from 2023-10-22 23:58 KST to 2023-10-23 00:13 KST: 1 / 1 hits
이번에는 datetime
필드를 기준으로 알림을 보내도록 설정해보겠습니다. config.yml
또는 직접 생성한 rule 파일에 다음 내용을 추가하면 됩니다.
timestamp_field: "datetime"
그 다음 테스트를 해보면, 알림이 datetime
필드를 기준으로 발생한 것을 확인할 수 있습니다.
#...
INFO:elastalert:Queried rule test any from 2023-10-22 14:59 KST to 2023-10-22 15:14 KST: 1 / 1 hits
#...
INFO:elastalert:Queried rule test any from 2023-10-22 23:59 KST to 2023-10-23 00:14 KST: 0 / 0 hits
이제 실제로 적용하기 위해 ElastAlert을 실행합니다.
python3.11 -m elastalert.elastalert --verbose --config config.yaml
그리고 알림에 해당하는 새로운 도큐먼트를 추가합니다. 여기서 @timestamp
를 생략한 이유는 알림 기준이 datetime
이므로 추가하지 않아도 괜찮기 때문입니다.
PUT testalertindex/_doc/2
{
"datetime": "2023-10-23T10:25:00+09:00",
"name": "kim2",
"env": "prod"
}
도큐먼트를 추가하고 나면 Teams에서 다음과 같이 알림이 정상적으로 오는 것을 확인할 수 있습니다.
ElastAlert에서는 알림 비활성화 기능을 제공합니다. 알림을 받지 않길 원하는 elastalert rule 파일에 다음 내용을 추가하면 됩니다.
is_enabled: false
그 다음 ElastAlert을 실행해보면 아래와 같은 로그를 확인할 수 있습니다.
INFO:elastalert:Disabled rules are: ['test any']
is_enabled
는 default 값을 true
로 가지기 때문에, 비활성화하는 경우가 아니라면 입력하지 않아도 괜찮습니다.
만약 rule을 완전히 없애고 싶다면, rule 파일을 삭제하면 됩니다.
ElastAlert 알림 메시지에는 Kibana URL을 설정할 수 있습니다. rule 파일 또는 config.yml에 다음과 같은 내용을 추가합니다. 이 때, 설정하려는 인덱스에 대한 인덱스 패턴을 생성한 상태여야 합니다. 참고로, 전체 rule에 공통으로 적용하고 싶다면 config.yml, 특정 rule에 대해서만 적용하고 싶다면 rule 파일에 추가하면 되고, config.yml보다 rule 파일에 쓰인 내용의 우선 순위가 더 높습니다.
generate_kibana_discover_url: True
kibana_discover_app_url: "<Kibana URL>/app/discover#/"
kibana_discover_index_pattern_id: "<인덱스 패턴 ID>"
kibana_discover_version: "7.10"
설정을 한 다음 ElastAlert을 추가하고 다음과 같이 인덱스를 추가합니다.
PUT testalertindex/_doc/3
{
"datetime": "2023-10-23T15:15:00+09:00",
"name": "kim3",
"env": "prod"
}
그 다음 전송된 알림의 Kibana URL에 접속하면 아래와 같이 설정한 쿼리와 그룹을 통해 구분된 알림을 표출하는 것을 확인할 수 있습니다.
이번에는 알림 메시지 내용을 변경해보겠습니다. alert_text_type
을 alert_text_jinja
로 설정하여 추가하였습니다. 다른 alert_text_type
설정 방법은 공식 문서를 참고해주세요.
generate_kibana_discover_url: True
kibana_discover_app_url: "<Kibana URL>/app/discover#/"
kibana_discover_index_pattern_id: "<인덱스 패턴 ID>"
kibana_discover_version: "7.10"
ms_teams_attach_kibana_discover_url: True
ms_teams_kibana_discover_title: "Discover in Kibana"
alert_text_type: alert_text_jinja
alert_text: |
Time: {{datetime}}
Name: {{name}}
ms_teams_attach_kibana_discover_url
및 ms_teams_kibana_discover_title
는 kibana url 전체를 보지 않고 입력 버튼으로 제공하기 위해 추가한 설정입니다.
alert_text
내용을 작성할 때는 {{ }}
내에 필드명을 입력하면, 해당 알림에 대한 필드 값을 제공합니다. 그리고 줄바꿈을 하고 싶다면 중간에 한 줄 비워두면 됩니다.
적용 후 실행하고 다음 도큐먼트를 추가해봅시다.
PUT testalertindex/_doc/4
{
"datetime": "2023-10-23T17:42:00+09:00",
"name": "kim4",
"env": "stg"
}
ElastAlert을 백그라운드로 실행할 수 있도록 설정해보겠습니다. 다양한 방법이 있지만 그 중 systemctl
을 사용하려고 합니다.
먼저 elastalert.service
파일을 생성합니다.
sudo vi /etc/systemd/system/elastalert.service
그리고 파일 내용을 아래와 같이 입력한 다음, 저장합니다.
[Unit]
Description=elastalert2
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/monitoring/elastalert2
ExecStart=/usr/local/bin/python3.11 -m elastalert.elastalert --verbose --config config.yaml
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
그 다음 아래 명령어를 통해 서비스를 새로 불러옵니다.
sudo systemctl daemon-reload
이제 모든 설정이 완료 되었으므로, systemctl
을 통해 실행해봅시다.
sudo systemctl start elastalert
실행 상태는 다음 명령어를 통해 상세하게 확인할 수 잇습니다.
sudo systemctl status elastalert -l
이제 실제로 알림이 오는지 확인해보겠습니다.
PUT testalertindex/_doc/5
{
"datetime": "2023-10-24T22:58:00+09:00",
"name": "kim5",
"env": "prod"
}
새로운 도큐먼트를 추가하면 다음과 같이 알림이 정상적으로 오는 것을 확인할 수 있습니다.
정상 동작을 확인했으므로, 부팅 시 자동으로 시작되도록 설정해줍니다.
sudo systemctl enable elastalert
- https://github.com/Yelp/elastalert
- https://github.com/jertel/elastalert2
- https://elastalert2.readthedocs.io/en/latest/running_elastalert.html#as-a-python-package
- https://computingforgeeks.com/install-python-3-on-centos-rhel-7/
- https://computingforgeeks.com/how-to-install-openssl-1-1-on-centos-rhel-7/#google_vignette
- https://freewings.tistory.com/81
- https://www.unh4ck.com/building-an-open-siem-from-scratch/3.-installing-elastalert
- Yelp/elastalert#1566