前言
笔者使用 ELK 日志系统搭建了日志系统, 由于 ELK 日志系统默认是没有认证功能, 日志存储安全无法保证, ELK 自身的漏洞也可能增加风险. 本文中笔者采用 nginx 进行代理认证, 写此文希望用自己的实验成果能帮到需要的人, 提高安全管理人员安全意识.
1. 背景
由于网络安全法要求信息系统运营单位的网络日志保留时间不低于 6 个月, 在信息安全等级保护中也有相应要求, 日志记录的保存也是执法检查部门近年的关注的重点, 原因即是为了安全事件的事后追查, 因此信息系统产生的各种日志必须进行安全的保存, 规避违法违规风险, 尽到作为信息系统运营单位安全保护责任.
因笔者在某政府单位驻场安全运维, 该单位没有日志系统, 因此决定使用著名的 ELK 日志系统搭建了日志系统, 用于收集全网日志, 包括网络设备 syslog, 操作系统 syslog,apahce,tomcat,iis,was,weblogic 等. 由于 ELK 日志系统默认是没有认证功能, 日志存储安全无法保证, ELK 自身的漏洞也可能增加风险, 很多人忽略了这一点, 网上也没有文章强调认证. 本文中我采用了 nginx 进行代理认证, 写此文希望用自己的实验成果能帮到需要的人, 提高安全管理人员安全意识.
2. 运行环境
windows 2008 R2 两台作为日志系统服务端, 安装 Elasticsearch 5.6.9,Logstash 5.6.9,Nginx1.14.0,JDK1.8+.
centos 6.9 一台作为日志系统客户端, 安装 filebeat 5.6.9
3. 方案
filebeat: 作为客户端采集网站 A 网站 B.... 的 apache,tomcat,nginx 等中间件 log 文件, 并配置 tags(用于区分日志类型)和 fields:service(用于区分日志来源网站建立不同索引)参数, 不使用 logstash 作为客户端的原因是 logstash 太占用资源了, 还需要 java 环境. filebeat 接收 syslog 和 filebeat 发来的日志在 filter 中根据 tags 类型格式化, 在 output 中根据 fields:service 配置索引输出到 Elasticsearch 不同网站建立不同索引. 客户端不会直接请求 Elasticsearch 的 9200 端口, 确保安全.
Elasticsearch: 安装到 windows 服务器, 作日志存储处理, 所在服务器开启防火墙:
策略 1: 允许集群节点之间 tcp9200,tcp9300 端口, ping 通信.
策略 2: 允许 filebeat 客户端访问服务器 tcp54320 和 udp514 端口(logstash 中定义). 策略 3: 允许管理员 ip 访问经过 nginx 代理认证后的 head 插件端口 tcp19100(nginx 中自定义),Elasticsearch 的 tcp19200 端口和 kibana 的 tcp15601 端口, 方便管理员远程管理. 所有策略配置好后客户端无法直接访问 Elasticsearch 的 9100,9200,9300 端口和 kibana 的 5601 端口, 仅管理员可访问代理后的 19100,19200,15601 端口, 对应 9100,9200,5601 端口.
Kibana: 安装到 windows 服务器, 作为日志展示和查询.
Elasticsearch-head: Elasticsearch 的图形管理插件.
Nginx: 安装到主 windows 服务器节点, 因为 Elasticsearch 默认是无认证的, 日志可被恶意删除, 无论在内网还是公网都是非常危险的, 因此有必要采用 nginx 进行反向代理认证.
Nssm: 将免安装的 logstah,kibana,nginx 安装为服务, 配置为自动启动.
* 对于性能有需求的可考虑使用 redis, 非本文关注重点, 不再介绍了.
4. 下载必要软件和版本选择
*ELK5.6.9 支持到 windows server 2008 操作系统, 更高版本需要 windows server 2012 操作系统. 资源下载地址:
- Elasticsearch 5.6.9: https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.9.zip
- Logstash 5.6.9: https://artifacts.elastic.co/downloads/logstash/logstash-5.6.9.zip
- filebeat 5.6.9 Linux: https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.6.9-x86_64.rpm
- filebeat 5.6.9 Windows: https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.3.2-windows-x86_64.zip
- Kibana 5.6.9: https://artifacts.elastic.co/downloads/kibana/kibana-5.6.9-windows-x86.zip
- JDK(1.8 以上): http://download.oracle.com/otn-pub/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-windows-x64.exe
- elasticsearch-head: https://github.com/mobz/elasticsearch-head#running-with-built-in-server
- nginx 1.14.0: http://nginx.org/download/nginx-1.14.0.zip
- nssm: http://www.nssm.cc/release/nssm-2.24.zip
5. 安装 ELK
5.1 Elasticsearch 安装配置
解压修改配置文件即可运行.
请注意有一个坑: elasticsearch 必须是两个组成集群, 不然会出现错误, 也可在同一台服务器运行两个 elasticsearch, 如果启动报错, 是因为复制两个 elasticsearch 时 data 目录已有数据, 造成冲突, 清空 data 里面的数据即可启动两个 elasticsearch. 本文采用两台服务器搭建, 配置如下:
主节点配置文件 elasticsearch.yml
- # 禁用虚拟内存, 提高性能
- bootstrap.memory_lock: true
- # 节点名称自定义:
- cluster.name: elasticsearch
- # 数据通信端口:
- http.port: 9200
- # 监听网卡 ip
- network.host: 192.168.1.1
- # 是否是数据节点:
- node.data: true
- # 关闭即可:
- node.ingest: true
- # 是否是主节点, 不定义的话先启动的是主节点:
- node.master: true
- # 最大存储节点:
- node.max_local_storage_nodes: 1
- # 节点名字自定义:
- node.name: Win-Master-1
- # 数据文件路径
- path.data: D:\elk\elasticsearch\data
- path.logs: D:\elk\elasticsearch\logs
- # 节点间通信端口:
- transport.tcp.port: 9300
- # 节点 ip, 节点之间要允许 ping 和 9300 端口通信
- discovery.zen.ping.unicast.hosts: ["192.168.1.1", "192.168.1.2"]
- #head 插件相关:
- http.cors.enabled: true
- http.cors.allow-origin: "*"
备节点配置文件 elasticsearch.yml
- # 禁用虚拟内存, 提高性能
- bootstrap.memory_lock: true
- # 节点名称自定义:
- cluster.name: elasticsearch
- # 数据通信端口:
- http.port: 9200
- # 监听网卡 ip
- network.host: 192.168.1.2
- # 是否是数据节点:
- node.data: true
- # 关闭即可:
- node.ingest: true
- # 是否是主节点, 不定义的话先启动的是主节点:
- node.master: false
- # 最大存储节点:
- node.max_local_storage_nodes: 1
- # 节点名字自定义:
- node.name: Win-salve-1
- # 数据文件路径
- path.data: D:\elk\elasticsearch\data
- path.logs: D:\elk\elasticsearch\logs
- # 节点间通信端口:
- transport.tcp.port: 9300
- # 节点 ip, 节点之间要允许 ping 和 9300 端口通信
- discovery.zen.ping.unicast.hosts: ["192.168.1.1", "192.168.1.2"]
- #head 插件相关:
- http.cors.enabled: true
- http.cors.allow-origin: "*"
安装服务
进入 bin 目录在 cmd 中运行:
- elasticsearch-service.bat install
- # 图形服务管理工具或 windows 服务中启动服务
- elasticsearch-service-mgr.exe
安装 head 插件
1. 下载安装 node.js , 网址: https://nodejs.org/en/ 2.nodejs 安装目录下运行:
npm install -g grunt-cli
3. 下载 head 插件, 网址: https://github.com/mobz/elasticsearch-head/archive/master.zip 4. 解压到 elasticsearch 下, 自定义目录名称 head, 修改以下源码:
- head/Gruntfile.js
- connect: {
- server: {
- options: {
- port: 9100,
- hostname: '*',
- base: '.',
- keepalive: true
- }
- }
- }
- head/_site/app.js
- this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://192.168.1.1:19100/elasticsearch/";
- # 这里的地址和第六章 nginx 代理配置对应.
5.2 logstash 安装配置
解压修改配置文件即可.
新建配置文件 logstash.conf
- input{
- stdin{
- }
- #配置端口, 接收 syslog 日志:
- syslog {
- type => syslog
- port => 514
- }
- #配置端口, 接收 filebeat 发来的日志.
- beats {
- port => 54320
- }
- #logstash 做客户端时的配置举例, 本方案不采用, 故注释掉.
- #file {
- # path => "D:/log/apache/access-*.log"
- # type => "apache_access"
- # start_position => "beginning"
- # ignore_older => 0 #读取已有的日志文件
- #}
- }
- filter {
- #logstash 做客户端时的配置举例, 本方案不采用, 故注释掉.
- #if [type] == "apache_access" {
- # grok {
- # match => {"message" => "%{COMBINEDAPACHELOG}" }
- # }
- #}
- #filebeat 做客户端时的配置
- #filter 其实也可以不配置, 但不利于根据字段搜索和分析日志.
- if "apache_access" in [tags] {
- grok {
- match => {"message" => "%{COMBINEDAPACHELOG}" }
- }
- #%{COMBINEDAPACHELOG}内置的 apcahe 日志匹配规则.
- }
- if "nginx_access" in [tags] {
- grok {
- match => {"message" => "%{COMBINEDAPACHELOG} %{QS:x_forwarded_for} %{HOSTNAME:server_name}" }
- }
- #为了便于搜索多二级域名的网站, 这里修改 nginx 默认日志字段后, 添加了 {HOSTNAME:server_name} 规则, nginx 比 apahce 增加了一个 {QS:x_forwarded_for} 这里也加上了.
- }
- if "tomcat_access" in [tags] {
- grok {
- match => {"message" => "%{COMBINEDAPACHELOG}" }
- }
- #%{COMBINEDAPACHELOG}内置的日志匹配规则, 可自定义.
- }
- }
- output{
- #logstash 做客户端时的配置, 输出到 elasticsearch,, 本方案不采用, 故注释掉.
- #if [type] == "apache_access" {
- # elasticsearch{
- # hosts => ["10.0.21.194:9200"]
- # index => "apache-%{ YYYY.MM.dd}"
- # }
- #}
- #syslog 到 elasticsearch
- if [type] == "syslog" {
- elasticsearch{
- hosts => ["192.168.1.1:9200"]
- index => "syslog-%{ YYYY.MM.dd}"
- }
- }
- #根据 filebeat 中 service 不同域名建立不同索引, 输出到 elasticsearch
- if [fields][service] == "www.a.com" {
- elasticsearch{
- hosts => ["192.168.1.1:9200"]
- index => "www.a.com-%{ YYYY.MM.dd}"
- }
- }
- #根据 filebeat 中 service 不同域名建立不同索引, 输出到 elasticsearch
- if [fields][service] == "www.b.com" {
- elasticsearch{
- hosts => ["192.168.1.1:9200"]
- index => "www.c.com-%{ YYYY.MM.dd}"
- }
- }
- #其他日志
- elasticsearch{
- hosts => ["192.168.1.1:9200"]
- index => "other-%{ YYYY.MM.dd}"
- }
- #输出到屏幕
- stdout{
- codec=>rubydebug
- }
- }
- # 提示: 如果你想在业务服务器上使用 logstash 做客户端, 但服务器是低版本 java,logstash 又需要以 JDk1.8 以上运行, 可在 logstash/startup.option 配置文件中的 set 参数指定高版本 JAVACMD 路径, 亲测可用.
安装服务
在 bin 目录新建一个 logstash-start.bat 文件写入:
logstash.bat logstash.conf
在 cmd 中使用 nssm 安装服务, 选择 logstash-start.bat 路径, 并配置启动依赖于 "elasticsearch-service" 服务(确保开启自启动正常):
nssm install logstash
关于 filter 的 grok 正则处理, 单独说一下:
1.apahce 日志 Logstash 默认自带了 apache 标准日志的 grok 正则:
- COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{NOTSPACE:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-)
- COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}
nginx 标准日志的 grok 正则定义是:
MAINNGINXLOG %{COMBINEDAPACHELOG}
2. 对于 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"';
nginx 比 Apache 多了一个 $http_x_forwarded_for 变量, 所以 nginx 标准日志的 grok 正则定义是:
MAINNGINXLOG %{COMBINEDAPACHELOG} %{QS:x_forwarded_for}
3. 为了便于搜索日志, 在可日志中加一个 server name 字段, 也即网站的域名, 适用于网站群的情况, 便于区分不同网站日志.
- log_format main '$remote_addr - $remote_user [$time_local]"$request" '
- '$status $body_bytes_sent"$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for" $server_name';
添加 server_name 后的 grok 正则定义:
MAINNGINXLOG %{COMBINEDAPACHELOG} %{QS:x_forwarded_for} %{HOSTNAME:server_name}
对于默认正则的修改可以这样在默认正则后面追加, 前提是 x_forwarded_for,server_name 的正则在默认正则中是存在的:
match => {"message" => "%{COMBINEDAPACHELOG} %{QS:x_forwarded_for} %{HOSTNAME:server_name}" }
4. 如何自定义规则.
默认的 grok 正则定义文件在下面路径: logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-0.3.0/patterns 下. 如果要自定义新的, 在 logstah.conf 中指定规则文件路径即可, 自定义规则优先级大于默认规则, 举例如下:
- grok {
- patterns_dir => "/usr/local/logstash/patterns" // 设置自定义正则路径
- match => {
- "message" => "%{NGINXACCESS}"
- }
- }
5.3 kibana 安装配置
解压修改配置文件即可.
修改配置文件 config/kibana.yml
因为采用了 nginx 进行本地代理, 只允许 localhost 本地访问即可.
- server.port: 5601
- server.host: "localhost"
- elasticsearch.url: "http://192.168.1.1:9200"
安装服务
在 bin 目录新建一个 kibana-start.bat 文件写入:
kibana.bat
在 cmd 中使用 nssm 安装服务, 选择 kibana.bat 路径, 并配置启动依赖于 "logstash" 服务(确保开机自启动正常):
nssm install kibana
6. filebeat 安装配置
6.1 filebeat 安装
仅介绍 linux 下安装, windows 同理.
rpm -ivh filebeat-5.6.9-x86_64.rpm
6.2 修改配置文件 filebeat.yml
- filebeat.prospectors:
- - input_type: log
- paths:
- - /usr/local/nginx/logs/*.log
- tags: ["nginx_access"]
- fields:
- service : www.a.com
- output.logstash:
- hosts: ["192.168.1.1:54320"]
- # 参数说明:
- #tages 是标记日志类型, 便于 logstah 进行 filter 格式化, 对应 logstah 配置.
- #service 是为了在 logstash 中根据不同网站发来的日志建立不同的 Elasticsearch 索引, 方便日志查询, 建议填写系统域名或别名, 对应 logstah 配置.
- #yml 格式是根据缩进判断参数, 相同缩进为一类参数, 注意缩进.
6.3 自启动
systemctl enable filebeat 或 chkconfig filebeat on
6.4 logrotate 配置
由于我们将日志远程存储, 本地日志就没有必要一直保留, 占用存储空间, apahce 自带日志分割功能, 不再写具体方法了, 默认情况下 nginx,tomcat 等产生的日志一直保存, 我们可以使用 logrotate 分割日志, logrotate 的配置文件在 / etc/logrotate.conf.
举例配置如下:/usr/local/nginx/logs/*.log 位置是新添加的, 前面的可注释掉.
- # see "man logrotate" for details
- # rotate log files weekly
- weekly
- # keep 4 weeks worth of backlogs
- rotate 4
- # create new (empty) log files after rotating old ones
- create
- # use date as a suffix of the rotated file
- dateext
- # uncomment this if you want your log files compressed
- compress
- # RPM packages drop log rotation information into this directory
- include /etc/logrotate.d
- # no packages own wtmp and btmp -- we'll rotate them here
- #/var/log/wtmp {
- # monthly
- # create 0664 root utmp
- # minsize 1M
- # rotate 1
- #}
- #/var/log/btmp {
- # missingok
- # monthly
- # create 0600 root utmp
- # rotate 1
- #}
- /usr/local/nginx/logs/*.log{
- daily
- rotate 90
- missingok
- notifempty
- dateext
- compress
- delaycompress
- create 600 root root
- sharedscripts
- postrotate
- if [ -f /usr/local/nginx/logs/nginx.pid ]; then
- kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
- fi
- endscript
- }
- # system-specific logs may be also be configured here.
logrotate 主要参数如下表:
参数 功能
compress 通过 gzip 压缩转储以后的日志
nocompress 不需要压缩时, 用这个参数
copytruncate 用于还在打开中的日志文件, 把当前日志备份并截断
nocopytruncate 备份日志文件但是不截断
create mode owner group 转储文件, 使用指定的文件模式创建新的日志文件
nocreate 不建立新的日志文件
delaycompress 和 compress 一起使用时, 转储的日志文件到下一次转储时才压缩
nodelaycompress 覆盖 delaycompress 选项, 转储同时压缩.
errors address 专储时的错误信息发送到指定的 Email 地址
ifempty 即使是空文件也转储, 这个是 logrotate 的缺省选项.
notifempty 如果是空文件的话, 不转储
mail address 把转储的日志文件发送到指定的 E-mail 地址
nomail 转储时不发送日志文件
olddir directory 转储后的日志文件放入指定的目录, 必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript 在转储以前需要执行的命令可以放入这个对, 这两个关键字必须单独成行
postrotate/endscript 在转储以后需要执行的命令可以放入这个对, 这两个关键字必须单独成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate count 指定日志文件删除之前转储的次数, 0 指没有备份, 5 指保留 5 个备份
tabootext [+] list 让 logrotate 不转储指定扩展名的文件, 缺省的扩展名是:.rpm-orig, .rpmsave, v, 和 ~
size size 当日志文件到达指定的大小时才转储, Size 可以指定 bytes (缺省)以及 KB (sizek)或者 MB (sizem).
7. 配置 nginx 反向代理及认证
7.1 修改配置文件 nginx.conf
- upstream kibana {
- server 127.0.0.1:5601;
- }
- upstream head {
- server 127.0.0.1:9100;
- }
- upstream elasticsearch {
- server 192.168.1.1:9200;
- }
- server {
- listen 15601;
- server_name 192.168.1.1;
- location / {
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- #配置帐号密码, 在 linux 上使用命令, 生成一个密码文件 #命令: htpasswd -bc ./password admin 123456
- #复制到 windows 上 D:\elk\head-nginx\conf\password
- auth_basic "login";# 提示信息
- auth_basic_user_file D:\elk\head-nginx\conf\password; #密码文件(写绝对路径, 注意 \ n 转义)
- autoindex on;
- proxy_pass http://kibana;
- }
- error_log logs/kinaba._route_error.log;
- access_log logs/kinaba._route_access.log main;
- }
- server {
- listen 19100;
- server_name 192.168.1.1 localhost;
- #配置帐号密码, 同上
- auth_basic "login";# 提示信息
- auth_basic_user_file D:\elk\head-nginx\conf\password; #密码文件(写绝对路径, 别相对路径, 注意转义)
- autoindex on;
- location / {
- proxy_pass http://head/;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- #这里使用 http://192.168.1.1:19100/elasticsearch / 请求 9200 服务, 因此在 head 插件中配置 elasticsearch 服务路径是 http://192.168.1.1:19100/elasticsearch/.
- location /elasticsearch/ {
- proxy_pass http://elasticsearch/;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- error_log logs/kinaba._route_error.log;
- access_log logs/kinaba._route_access.log main;
- }
7.2 安装服务
在根目录新建一个 nginx-start.bat 文件写入:
nginx.exe
在 cmd 中使用 nssm 安装服务, 选择 nginx.exe 路径:
nssm install nginx
参考连接:
- https://blog.csdn.net/yx1214442120/article/details/55102298
- https://blog.csdn.net/pilihaotian/article/details/52452010
来源: http://www.tuicool.com/articles/JnAfArU