搭建安全认证的ELK日志系统

2018-08-09 214173人围观 ,发现 8 个不明物体 安全管理

*本文原创作者:chuanwei,本文属FreeBuf原创奖励计划,未经许可禁止转载

前言

笔者使用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.zip4.解压到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

*本文原创作者:chuanwei,本文属FreeBuf原创奖励计划,未经许可禁止转载

发表评论

已有 8 条评论

取消
Loading...
css.php