集中式日志分析平台 - ELK Stack - 开源安全套件 SearchGuard 的整合 - 1

前言

在之前的一篇 集中式日志分析平台 - ELK Stack - 安全解决方案 X-Pack 里讲解了官方收费安全套件,官方套件很强大啊,但是完全收费。业界比较有名的一款开源产品 SearchGuard 却是部分收费,专注于 ES 的安全加固以及顺带做做 ELK 栈的 security,功能包括:

认证授权有关的:

  • 支持基础 Http 认证;
  • 支持 LDAP 和 AD,可以用于认证和授权的用户角色信息元数据集中式存储;(收费)
  • 支持 Kerberos 双边认证;(收费)
  • 支持 JWT;(收费)
  • 支持代理认证,可以很方便的实现 SSO 系统对接;

ES 行(document)和列(field)级别的安全访问控制;

日志审计功能;(收费)

ELK 栈其他组件有关的:

  • 和 Kibana 完美整合,包括添加了 x-pack 插件的情况下,支持 Kerberos 认证、代理认证、JWT、用户名/密码登录认证、Https 加密、对 ES 访问的 ACL 等,并且可以自定义登录首页样式;
  • 支持 Kibana 的 visualization、dashboard 的多租户模式;(收费)
  • 和 logstash 完美整合,支持 logstash 可以通过 Https 访问 ES;
  • 和 x-pack monitoring 整合;
  • 支持 Tribe nodes 模式,也就是说支持多个 ES 集群的级联查询;
  • 支持 indices 的快照和恢复操作,默认只有 admin 用户具备权限;
  • 可以和开源 ES 报警组件 ElastAlert 整合;

本文描述的是如何把关键性的几个免费功能整合到我们的 ELK 栈里去,涵盖了

  • 如何以脚本的形式 quickstart 整合 search guard 至 elasticsearch (Https & indices 粒度 ACL);
  • 如何让 kibana 访问安全 elasticsearch 集群;
  • 如何让 logstash 访问安全 elasticsearch 集群;
  • 一个简单的链路调试例子;

Integration with ES(Https & indices 粒度 ACL)

假设我们已经有一个 ELK 集群(部署方式请参考我之前的文章),它的节点分布是这样的(版本统一为 5.2.1):

IP Role
172.16.134.34 ES/Logstash/Kibana
172.16.134.37 ES/Logstash/Zookeeper/Kafka/Filebeat

服务的安装路径统一为 /home/admin/server/${SERVICE_NAME} ,日志的统一路径为 /home/admin/logs/${SERVICE_NAME}

互联网联通情况下的安装:

/home/admin/server/elasticsearch-current/bin/elasticsearch-plugin install -b com.floragunn:search-guard-5:5.2.1-12

请按照您自己的 es 版本进行版本选择:https://github.com/floragunncom/search-guard/wiki

离线环境下的安装:

在可以访问互联网的机器上下载 https://oss.sonatype.org/content/repositories/releases/com/floragunn/search-guard-5/5.2.1-12/search-guard-5-5.2.1-12.zip,然后上传至内网环境。

/home/admin/server/elasticsearch-current/bin/elasticsearch-plugin install -b file:///home/admin/soft/search-guard-5-5.2.1-12.zip

运行命令进行脚本式初始化:

cd /home/admin/server/elasticsearch-current/plugins/search-guard-5/tools
chmod +x install_demo_configuration.sh
./install_demo_configuration.sh

完成后会在 config 目录下生成测试用的 3 个 jks 文件:

  • truststore.jks—根 CA;
  • keystore.jks—节点证书;
  • kirk.jks—运行 sgadmin 必备的管理员证书;

完成后也会自动设置一些默认配置至 elasticsearch.yml 中:

######## Start Search Guard Demo Configuration ########
searchguard.ssl.transport.keystore_filepath: keystore.jks
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.http.enabled: true
searchguard.ssl.http.keystore_filepath: keystore.jks
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.authcz.admin_dn:
  - CN=kirk,OU=client,O=client,L=test, C=de
cluster.name: searchguard_demo
network.host: 0.0.0.0

但是如果现在重新启动 es 可能会报错,因为原先的配置里涵盖了 cluster.name network.host 等配置,报错可能如下:

Exception in thread "main" ElasticsearchParseException[duplicate settings key [cluster.name] found at line number [21], column number [15], previous value [lw-daily], current value [search
guard_demo]]

这里 lw-daily 是我们默认的集群名称。

我们需要删除相应报错配置项,然后重启 es:

######## Start Search Guard Demo Configuration ########
searchguard.ssl.transport.keystore_filepath: keystore.jks
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.http.enabled: true
searchguard.ssl.http.keystore_filepath: keystore.jks
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.authcz.admin_dn:
  - CN=kirk,OU=client,O=client,L=test, C=de
network.host: 0.0.0.0

如果重启过程中还遇到如下报错说明 openssl 运行缺少 jar:

[2017-07-12T12:56:23,987][INFO ][c.f.s.s.DefaultSearchGuardKeyStore] Open SSL not available (this is not an error, we simply fallback to built-in JDK SSL) because of java.lang.ClassNotFoundException: org.apache.tomcat.jni.SSL

该情况需要去官方下载对应版本的 jar 包(https://github.com/floragunncom/search-guard-docs/blob/master/tls_openssl.md),比如我们的版本对应的是 http://repo1.maven.org/maven2/io/netty/netty-tcnative/1.1.33.Fork25,然后放置到 plugins/search-guard-5/

mv netty-tcnative-1.1.33.Fork25-linux-x86_64.jar /home/admin/server/elasticsearch-current/plugin/search-gurad-5/

修改 tools/sgadmin_demo.sh ,使其中一行匹配我们默认的集群名称:

/home/admin/server/elasticsearch-current/plugins/search-guard-5/tools/sgadmin.sh -cd /home/admin/server/elasticsearch-current/plugins/search-guard-5/sgconfig -cn lw-daily -ks /home/admin/server/elasticsearch-current/config/kirk.jks -ts /home/admin/server/elasticsearch-current/config/truststore.jks -nhnv

我们把 -cn 参数修改为了 lw-daily。

然后我们执行脚本:

./sgadmin_demo.sh

执行脚本之后会根据 plugins/search-guard-5-5.2.1-12/sgconfig 的配置初始化 search guard index,初始化的包括内部用户、角色、用户和角色的映射、权限组等等。

到这一步之后安装就算完成了,我们可以通过接口观察是否配置正确:

https://172.16.134.34:9200/_searchguard/authinfo

这里默认的用户名和密码可以选择 adminadmin,如果通过认证,那么就会返回如下结果:

{
    user: "User [name=admin, roles=[]]",
    user_name: "admin",
    user_requested_tenant: null,
    remote_address: "172.16.129.61:50317",
    sg_roles: [
        "sg_all_access",
        "sg_own_index",
        "sg_public"
    ],
    sg_tenants: {
        test_tenant_ro: true,
        admin: true,
        adm_tenant: true
    },
    principal: null,
    peer_certificates: "0"
}

Integration with Kibana

ES 做了加固,原先的普通访问方式就歇菜了,首先是 Https 然后是 ACL,那么就会没通过认证和得到相应的权限访问资源。我们需要对 Kibana 做相应的配置:

下载 plugin:

https://github.com/floragunncom/search-guard-kibana-plugin/releases/download/v5.2.1-3/searchguard-kibana-5.2.1-3.zip

安装 plugin:

/home/admin/server/kibana-current/bin/kibana-plugin install file:///home/admin/soft/searchguard-kibana-5.2.1-3.zip

修改 kibana.yml

elasticsearch.url: "https://v134034.yn1.lwsite.net:9200"
server.host: "v134034.yn1.lwsite.net"

searchguard.basicauth.enabled: true
searchguard.cookie.secure: false
searchguard.cookie.name: 'searchguard_authentication'
searchguard.cookie.password: 'searchguard_cookie_default_password'
searchguard.cookie.ttl: 3600000
searchguard.session.ttl: 3600000
searchguard.session.keepalive: true

elasticsearch.username: "kibanaserver"
elasticsearch.password: "kibanaserver"

elasticsearch.ssl.verify: false

console.proxyConfig:
  - match:
      protocol: "https"
    ssl:
      verify: false

重启 kibana:

sudo kill -9 $(sudo lsof -i:5601 | awk '{print$2}' | tail -1 )
/home/admin/server/kibana-current/bin/kibana >> /home/admin/logs/kibana/kibana.log 2>&1 &

使用 kibanaserver 查看是否可以登录,密码默认为 kibanaserver。(该用户是在整合 searchguard 至 es 之后在运行 demo 脚本中生成的,同样的 logstash 用户也是)

Integration with Logstash

同样,我们需要修改 logstash ,以使其可以访问 es。以下是一个简单的示例配置,数据来自 kafka 的 stdin_test:

input {
  kafka {
    bootstrap_servers => 'v134037.yn1.lwsite.net:9092'
    consumer_threads => 1
    topics => ["stdin_test"]
    type => "stdin_test"
    codec => "json"
  }
}

output {
  elasticsearch {
    hosts => ["v134034.yn1.lwsite.net:9200","v134037.yn1.lwsite.net:9200"]
    manage_template => false
    index => "stdin_test-%{+YYYY.MM.dd}"
    document_type => "stdin_test"
    ssl => true
    ssl_certificate_verification => false
    truststore => "/home/admin/server/elasticsearch-current/config/truststore.jks"
    truststore_password => changeit
    user => logstash
    password => logstash
  }
}

其中,/home/admin/server/elasticsearch-current/config/truststore.jks 也是由之前的 demo 脚本生成的。

重启 logstash 之后可以正确访问。

即使 ssl_certificate_verification 设置为 false,也必须配置 truststore ,否则会报错:

logstash unable to find valid certification path to requested target,参考 issue 链接:https://github.com/logstash-plugins/logstash-output-http/issues/21,我们必须保证 truststore 文件存在可读。

一个简单的例子

上一节我们介绍了如何整合 logstash 至 searchguard,现在我们要在 stdin_test 这个 topic 里面造些数据进行集成测试,我们当然用 filebeat 推送数据至 kafka,filebeat 部署在 172.16.134.37,配置如下:

首先是主配置文件 /home/admin/server/filebeat-current/filebeat.yml

filebeat:
  config_dir: /home/admin/server/filebeat-current/conf.d

output.kafka:
  hosts: ["v134037.yn1.lwsite.net:9092"]
  topic: '%{[type]}'
  partition.round_robin:
    reachable_only: false
  required_acks: 1
  compression: gzip
  max_message_bytes: 10485760

然后是对应的采集 stdin_test 的配置文件 /home/admin/server/filebeat-current/conf.d/stdin_test.yml

filebeat.prospectors:
- input_type: log
  paths:
  - /tmp/stdin_test.log
  document_type: stdin_test

OK,接下来我们灌简单数据至文件:

echo "1" >> /tmp/stdin_test.log

在 Kibana 添加 index 的时候发现无法获取,排查了一下可以得知 Kafka 是有 topic 新建并且有数据的:

/home/admin/server/kafka-current/bin/kafka-topics.sh --list --zookeeper 172.16.134.37:2181
/home/admin/server/kafka-current/bin/kafka-console-consumer.sh --zookeeper 127.0.0.1:2181 --topic stdin_test --from-beginning

然后排查下 logstash DEBUG 日志:

[2017-07-13T15:06:14,376][WARN ][logstash.outputs.elasticsearch] Failed action. {:status=>403, :action=>["index", {:_id=>nil, :_index=>"stdin_test-2017.07.13", :_type=>"stdin_test", :_routing=>nil}, 2017-07-13T07:06:14.280Z %{host} {
"@timestamp":"2017-07-13T07:06:13.054Z","beat":{"hostname":"v134037.yn1","name":"v134037.yn1","version":"5.2.1"},"input_type":"log","message":"1","offset":6,"source":"/tmp/stdin_test.log","type":"stdin_test"}], :response=>{"index"=>{
"_index"=>"stdin_test-2017.07.13", "_type"=>"stdin_test", "_id"=>nil, "status"=>403, "error"=>{"type"=>"security_exception", "reason"=>"no permissions for indices:admin/create"}}}}

注意最后的报错 no permissions for indices:admin/create,可以得知 logstash 没有对应权限进行 indices 新建。按照官方的建议,对 searchguard 的配置文件进行修改 /home/admin/server/elasticsearch-5.2.1/plugins/search-guard-5/sgconfig/sg_roles.yml,注意只修改 sg_logstash 这个角色的配置:

...
sg_logstash:
  cluster:
    - indices:admin/template/get
    - indices:admin/template/put
    - CLUSTER_MONITOR
    - CLUSTER_COMPOSITE_OPS
  indices:
    'logstash-*':
      '*':
        - CRUD
        - CREATE_INDEX
    'stdin_test-*': # 修改这里,添加对应权限
      '*':
        - CRUD
        - CREATE_INDEX
    '*beat*':
      '*':
        - CRUD
        - CREATE_INDEX
...

发现修改后重启没有卵用,看到了官方的建议说需要用脚本刷下配置:

/home/admin/server/elasticsearch-current/plugins/search-guard-5/tools/sgadmin.sh -cd /home/admin/server/elasticsearch-current/plugins/search-guard-5/sgconfig -cn lw-daily -ks /home/admin/server/elasticsearch-current/config/kirk.jks -ts /home/admin/server/elasticsearch-current/config/truststore.jks -nhnv

官方说只要一个节点刷就可以全局生效,但是我发现不行,所以我是全局所有节点都进行了这个操作的。重启试下是否数据可以被 Kibana 识别,发现还是不行,这个时候看了下 Kibana 的日志发现如下报错:

[2017-07-13T15:49:28,591][INFO ][c.f.s.c.PrivilegesEvaluator] No index-level perm match for User [name=kibanaserver, roles=[]] [IndexType [index=stdin_test-2017.07.13, type=*]] [Action [indices:admin/mappings/fields/get]] [RolesCheck
ed [sg_kibana_server, sg_own_index, sg_public]]
[2017-07-13T15:49:28,591][INFO ][c.f.s.c.PrivilegesEvaluator] No permissions for {sg_public=[IndexType [index=stdin_test-2017.07.13, type=*]], sg_own_index=[IndexType [index=stdin_test-2017.07.13, type=*]], sg_kibana_server=[IndexTyp
e [index=stdin_test-2017.07.13, type=*]]}

也是权限的问题,按照和之前一样的方式修改权限:

...
sg_kibana:
  cluster:
    - CLUSTER_COMPOSITE_OPS_RO
  indices:
    '*':
      '*':
        - READ
        - indices:admin/mappings/fields/get*
    '?kibana':
      '*':
        - ALL
...

并且刷新后,重启 Kibana,以 kibanaro 角色登录(默认密码 kibanaro),再灌入测试数据至日志文件后,就可以正确获取 indices 数据。

小结

本文介绍了如何使用 searchguard 对 ES 进行 https 和 indices 粒度 ACL 的安全赋能,以及一个短小的例子。下一篇我将写一下如何整合 Kerberos 双边认证进行进一步加固,以及如何使用 restful API 对 ES 进行访问。

参考文献

  • http://floragunncom.github.io/search-guard-docs/installation.html
  • http://floragunncom.github.io/search-guard-docs/quickstart.html
  • http://floragunncom.github.io/search-guard-docs/kibana.html
  • http://floragunncom.github.io/search-guard-docs/logstash.html
  • http://floragunncom.github.io/search-guard-docs/sgadmin.html

你可能感兴趣的:(集中式日志分析平台 - ELK Stack - 开源安全套件 SearchGuard 的整合 - 1)