系统安全监控DIY:动手做Osquery Agent

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

系统安全的主动监控和被动监控

如何写agent的文章有太多,做系统安全监控的文章也有很多,有些出色的开源安全工具和一些安全服务,其中ossec在众多的企业运用广泛,但复杂的配置和复杂的规则特性很难做到快速部署,对于安全来说时间就是”金钱”,今天我们的主角是facebook开源的osquery,通过集成osquery来实现快速监控系统安全,通过编写简单的agent来做到分布式服务器监控。

Osquary 简介:

• osquery是一个SQL驱动操作系统检测和分析工具。

• 项目主页:http://osquery.io/

• 代码托管地址:https://github.com/facebook/osquer 

Osquery   CentOS 7 安装:

在CentOS 7上安装只要 yum install osquery 就可以了,是不是很简单?

Osquery 缺陷:

But, osquery 有一个很大的缺陷,就是他不能通过远程操作, 至少笔者是没有看到任何远程操作的方案,只有通过定制log日志或者上服务器运行命令才行,这样对我们我们N台服务器的管理和部署就显得及其不方便了,经过一番github上的搜索找到了osqeury的python库,既然能用python来控制他,那就可以做成分布式来agent来管理它。

踩坑:

有方案就会有踩坑,在开发之初,笔者采用的是celery这款分布式列队神器来对各个系统进行管理,但最后发现下发任务只能被执行一次,多个节点没办法做到同事计算,所以对管理大量的服务器来说,它不能胜任,所以还是决定自己动手来实现agent的管理,任务的下发和服务器的监控。

下面我们来看下他的架构:

系统安全监控DIY:动手做Osquery Agent

我们通过生产者消费者模型来出发相关任务,通过让消息队列发送任务,让Client接受到任务(包括定时任务和非定时任务),通过任务的操作,把结果写入到mysql数据库中,并且服务器中的Agent会上报状态给redis,告知服务器的ip和服务器现在的状态等。

代码分服务端和客户端,服务端来发送任务,客户端来执行任务,非常简单,我们来解读下代码:

#主函数
def main(config):
    r = RedisConn(db=6)
     #获得本级IP
    local_ip = getLocalIp()
    #无限循环
    while True:
        #读取redis中的任务,这里的任务是通过ip获取的
        key, data = r.breadpop("tasks" + local_ip)
        #通过dill模块来实现任务执行,这样我们就可以让客户端来执行不同的任务,做到动态执行任务
        d_fun , d_agrs = dill.loads(data)
        d_fun(*d_agrs)

整个客户端就是获取任务,执行任务的过程都是动态的,也就是任务可以进行自定义。

#一个任务,也就是我们执行osquery的方法

def run_task(rules):

    #一样,我们需要获取本机IP

    local_ip = getLocalIp()

    #获得当前时间

    times = time.strftime("%Y-%m-%d %H:%M", time.localtime())

    #连接数据库

    sqlhelp = MySQLHelper(host=“127.0.0.1”, db="Safe_DB", user="root", passwd=“root")

    print("times:",times)

    print(“rules:",str(rules['rules']))

    #osquery接口

    instance = osquery.SpawnInstance()

    instance.open()

    #获得规则

    rules = rules[‘rules']

    for rule in rules:

        #获得规则名

        rule_name = str(rule)#,encoding = “utf-8”)

        #获得规则

        rule = str(rules[rule])#,encoding = "utf-8")

        res_s = []

        try:

            #执行规则

            q = instance.client.query(rule)

            status = q.status.message

            

            if status != "OK":

                print("status:",status)

                continue;

            res_s = q.response

        except Exception as e:

            print("error:",str(e))

            continue;

       #循环查询出的结果

        for res_dict in res_s:

            for res in res_dict:

                pass

                name = res

                data = res_dict[name]

                #print(name)

                #把结果存储数据库

                sql = "insert into osquery_sql(ip_address,rule_name,name,data,time) values('{}','{}','{}','{}','{}')"

                sql = sql.format(local_ip,rule_name,name,data,times)

                print(sql)

                try:

                    sqlhelp.curd(sql)

                except:

                    continue;

是不是非常简单?这样我们就能不断的提供给它规则,让它去执行就可以了,其实在这之前,我们还需要获得agent的相关信息,我给它定义了一个方法叫uploadAgentInfo,我们来看下

#上传agent信息

def uploadAgentInfo():

    #获取本机ip

    local_ip = getLocalIp()

    r = RedisConn(db=7)

    #获取当前时间

    times = time.strftime("%Y-%m-%d %H:%M", time.localtime())

    #判断是否有本机信息

    config = r.hash_get("agent_ip", local_ip)

    if config == None:

        config = {}

        config['sleep'] = 10

        config['run_time'] = times

        #把ip存入redis

        r.hash_set("agent_ip",local_ip,config)

    return config

其实在这个方法中,我们可以看出,它上传了此agent的ip到redis,这样,我们的服务器就能获取到有多少agent和它相关的信息。当然config字典我们可以更加丰富它,并且我们可以,并且也可以做到实时的数据上传。

说完agent,我们来看看服务端,其实服务端非常简单,下面就是服务端的工作,你没看错,就几行代码

if name == "main":

    #消息缓存

    r = RedisConn(db=6)

    #规则缓存(需要手动或者使用脚本在redis中建立规则,redis中的规则用hash存储)

    rule_r = RedisConn(db=9)

    rules = rule_r.hash_get_all("rule")

    param = {"rules": rules}

    #agent端信息

    ip_r = RedisConn(db=7)

    ip_r = ip_r.hash_get_all("agent_ip")

    try:

        #把任务传到redis缓存中

        data = dill.dumps((run_task,[param]))

        for ip in ip_r:

            r.lpush("tasks" + ip,data)

    except Exception as e:

        print("error:" + str(e))

这里需要注意的是,不管在服务端还是在客户端,这套代码是要相同部署的,我们可以用gitlab进行代码更新,用Jenkins来做到自动部署,是不是非常方便?至此,osquery的agent已经全部做完,目前也只是做到数据的采集,对规则和对数据的分析还未开始做,等以后有时间了,还会分享关于osquery的监控规则和对数据的分析,请期待。

完整代码:链接:https://share.weiyun.com/3e60e0ac3b4f007c60f44b534ce61c4c (密码:vRETgT)

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

发表评论