云资源安全合规基线自动化检查与配置

Posted by int32bit on January 14, 2020
本文阅读量:

1 云资源安全合规基线需求和问题

云平台通过自服务接口提供了快速的资源供给方式,用户通过云平台console或者云管平台可以灵活按需快速构建云资源,甚至可以在几分钟构建自己的虚拟数据中心,资源的快速构建已不是什么难事,真正的难事在于如何有效治理好云资源,安全合规治理、标签治理、配置与安全基线检查等都不是什么容易的事。

如果前面有云管则可以挡一道,做一些配置限制、基线检查以及自动调整,但同时也失去了部分灵活性,并且也难以做到覆盖所有规范点。部分企业采用保姆式,云基础资源的申请均由云部门统一管理,包括创建和更新,通过一系列流程完成云资源最终交付,业务部门只需要能够通过堡垒机访问即可,这样其实工作都压在了云部门,交付也失去了敏捷性。

无论采用哪种方式,管理员都避免不了对云资源进行审计和基线检查,云基础资源管理员往往需要花费大量的时间去检查资源是否满足安全合规性、是否符合监管要求、是否遵循安全配置基线,常做的工作如检查资源的标签是否完备并且符合规范、安全组是否开放了高危端口、虚拟机是否使用了满足要求的黄金AMI、业务有没有考虑跨多AZ、磁盘是否加密、虚拟机是否直接挂弹性IP等等,虚拟机资源甚至还需要类似主机IDS工具做进一步OS级别的基线检查。

通常我们有如下几种方法来完成如上工作:

  • 人肉检查。最土的办法,登录每个业务账号一个一个检查,这种方式费力不讨好,效率低下。
  • 脚本轮询检查。通过调用云平台API检查资源是否合规及满足配置基线。这种方法在资源规模不大的情况下效率还可以,但很考验工程师的脚本能力,脚本维护起来也比较难。
  • 云平台托管服务。这是比较推荐的方法,很多云平台都提供了资源的合规性检查服务,比如OpenStack的Congress服务AWS Config服务等。

第一种方法没什么可说的,一两个账户可以这么玩,几十上百个账户基本不可行。第二种方法最大的问题是脚本开发和维护比较难,除非自己实现一套规则引擎框架,否则一个规则一个脚本,根本无法维护。

因此我们主要讨论第三种方案,以AWS为例简要介绍如何利用AWS托管服务做基线自动检查与配置。

2 安全基线自动化检查与配置相关服务简介

2.1 操作记录审计服务

安全基线自动化配置和检查从用户操作的时间点就已经开始了,云平台每一次在处理API调用时都会记录谁在什么时候执行了什么操作,每一次操作都会产生一个事件,事件中还会包含API调用的请求参数、创建的资源对象等信息。

这个功能不仅是监管以及安全审计要求,也是真正实现基于事件驱动的基线检查持续性和实时性的基础。

CloudTrail是AWS的审计服务,记录了所有通过AWS管理控制台、AWS开发工具包、命令行工具和其他AWS服务执行的任何操作。

cloudtrail

2.2 事件与性能监控服务

光产生了操作记录事件还不行,要实现基线自动化配置和检查,还需要把这些事件监控起来,因此需要监控服务。监控服务不仅仅包括监控其他服务的性能指标,还包括监控所有的事件和日志。由于监控指标和事件往往都会很多,因此监控服务还需要支持根据一定的条件进行数据过滤,传统的监控服务如Zabbix、Prometheus都支持。

Cloudwatch是AWS的监控服务,支持根据规则过滤和监视各种事件。

cloudwatch

2.3 Serverless计算

事件产生了并且也监控起来了,剩下最后一步就是真正的action。当然你可以订阅这些事件或者轮询发生的事件,然后自己起一个虚拟机部署handler服务来处理消费这些事件。但我认为最适合用来做action的是serverless计算,又称函数计算。

这是因为:

  • 依次处理的事件通常都是独立无状态的,因此不需要后台服务和存储介质专门保存这些状态。
  • 我们处理的事件产生通常是无时间规律的,这种场景不适合起一个专门的服务轮询监视,不仅不能保证处理的即时性,还可能由于无事件产生出现服务器资源闲置,浪费计算资源。而基于事件触发的函数计算能最小粒度的实现按需按量计算、收费,省时省钱。

AWS Lambda服务是AWS的函数计算服务,支持各种事件触发,其中就包括Cloudwatch。

aws lambda

3 安全基线自动化检查与配置实现方案

3.1 手动拼积木

有了前面的基础,充分利用和集成云平台已有的托管服务,很容易就可以实现安全基线自动化配置与检查工作了。

以AWS安全组规则为例,只需要开启Cloudtrail功能,并在Cloudwatch中配置规则Rule监听AuthorizeSecurityGroupIngress事件,然后Target配置触发Lambda函数,Lambda函数拿到事件,找到安全组规则对应的资源对象,检查是否满足要求,不满足要求则进行通知告警,通过lambda能做权限范围以内的任何事。

另外以一个AWS上常见的问题为例,我们知道AWS的EC2、EBS等资源是不记录创建用户的,如果一个账户有多个用户,在EC2列表中根本查不到这个虚拟机到底是谁创建的,只能通过cloudtrail在海量日志中慢慢去找了。

解决的办法其实也很简单,通过cloudwatch监听cloudtrail的RunInstances事件并触发lambda函数调用,这个lambda函数负责把event取出来,根据event的记录的用户名把标签CreatorName打到EC2实例上即可。

我们发现这种方案的工作量主要集中在Lambda函数的代码开发。

3.2 使用云平台托管服务

很多云平台都提供了专门的配置基线检查托管服务,比如OpenStack Congress服务、AWS的Config服务,使用这些托管的服务,利用其内置的规则能够省去写lambda代码。

以AWS Config为例,目前国内AWS已经支持83条托管规则,包括:

  • 检查EC2实例的AMI是否符合规范;
  • 检查Tag是否完备和规范;
  • 检查安全组是否开放了指定端口的0.0.0.0/0访问;

aws config

但是AWS Config服务只能做合规性配置基线检查,不能做任何操作。另外如果托管的规则不能满足需求,Config还支持触发自定义Lambda函数。

3.3 使用Policy As Service服务

前面介绍的方法配置都不是什么难事,难就难在需要自己写lambda函数,规则多了工作量还是挺大的,并且规则多了代码维护起来也特别麻烦。

如果能把规则逻辑从代码中抽象出来,用户只需要声明或者定义规则,不需要每个规则都要自己写lambda函数告诉平台怎么一步步处理,而只需要复用一套通用规则引擎,则显然无论工作量还是管理难度都会大大减少。

这就是我们将要介绍的Policy as Service服务,我们只需要根据规则声明Policy,无需关心具体怎么实现的,只要关心最终状态是否满足我们声明的规则即可。声明式编程在其他地方也被广泛使用,比如Kubernetes通过YAML文件声明资源,Docker Compose也是,Terraform也是如此。

Congress是针对OpenStack基于Policy声明的安全合规配置基线检查工具。CapitalOne开源的cloud custodian(简称c7n)也是基于policy声明的云资源配置基线检查工具,目前支持AWS、Azure以及GCP,未来可能还会支持Kubernetes。

本文接下来简单介绍下cloud custodian项目。

4 cloud custodian项目简介

相比前面的介绍的方法需要自己写lambda函数或者脚本,c7n是声明式的,这很符合现代的使用模式。

c7n policy包含3个主要部分:

  • resource: 声明资源类型,比如aws.ec2。
  • filters: 资源的匹配条件,即声明满足这条policy的条件是什么。
  • actions: 行为,即声明满足policy条件后做什么,比如对虚拟机关机、删除虚拟机、打标签等都是action。

4.1 resource

c7n支持AWS 162种资源类型,通过custodian schema可以列出所有的resource类型:

# custodian schema
resources:
- aws.account
- aws.ami
- aws.ec2
- ...

不同的资源类型支持不同的filters以及actions。

4.2 filters

不同的resource支持不同的filter type,其中value type可以说是最朴素也是最通用的filter type了,直接读取resource的属性值进行匹配。

比如我们通常会制作自己的黄金AMI,我们要求业务必须使用黄金AMI启动虚拟机,通过如下filters可以找出所有不合规的虚拟机列表:

resource: aws.ec2
filters:
- type: value
  key: ImageId
  op: not-in
  value:
  - ami-1 # Invalid
  - ami-2 # Invalid
  - ...    

如果是单值匹配,可以简化写法,type可以省略。

比如过滤所有运行状态为running的AWS ec2虚拟机,filters可以简化为:

resource: aws.ec2
filters:
- "State.Name": running

基于标签过滤资源可能是最常用的方式了,因此使用标签也有简便的写法:

filters:
- "tag:Custodian": 'value'

如上过滤所有打了Custodian标签值为value的资源列表。

如果匹配所有没有打Custodian标签的资源列表可以写成"tag:Custodian": present,其中present是一个特殊的操作符,表示该属性值不存在,更多的操作符可以参考官方文档Generic Filters

除了value的filter type,针对特定的resource类型,还有许多非常有用的filter type,通过custodian schema aws.ec2.filters可以查看AWS ec2支持的所有filters type,比如instance-age type可以基于实例创建时长进行过滤:

filters:
- type: instance-age
  days: 60

如上会匹配所有超过2个月的虚拟机。

4.3 actions

和filters一样,不同的resource type支持不同的action,以ec2为例支持的actions包括但不限于如下:

  • 开关机、重启;
  • 修改安全组;
  • 打标签、修改标签;
  • 打快照;
  • 执行lambda函数、webhook;
  • 告警、邮件通知;

4.4 一个完整的例子

有了resource、filters、actions我们就可以确定针对哪种资源满足什么条件执行什么动作了。

还是以前面的黄金AMI为例,假设我们针对没有按照要求使用管理员规定的黄金AMI的不合规虚拟机执行关机操作,

- name: stop-invalid-ami-ec2
  resource: ec2
  comment: |
    Find all running EC2 instances that are using invalid AMIs and stop them
  filters:
    - "State.Name": running
    - type: value
      key: ImageId
      op: in
      value:
          - ami-1 # Invalid
          - ami-2
          - ...
  actions:
    - stop

在本地执行:

custodian run -s output stop-invalid-ami-ec2.yaml

4.5 mode

custodian是一次运行的Job任务,和Terraform一样运行完任务就结束了,没有运行任何后台服务。因此需要每次在虚拟机上敲命令行手动执行,当然聪明点的做法是写一个cron job,每隔一段时间自动跑一遍。

如果c7n只支持这种模式那就没啥用了,显然c7n不会做得这么低端。

其实c7n最强大的功能角色是充当粘合剂,把云平台的各种配置功能粘合在一起,集成云平台已有的工具。

以AWS为例,由于c7n是一次运行的无状态Job任务,那其实根本就不需要在虚拟机上本地运行浪费虚拟机浪费钱,现在都流行serverless了,lambda再合适不过了。

谁来触发lambda,当然event最合适,因此使用cloudwatch触发最合适。event谁来产生,cloudtrail会记录AWS的所有API调用event,因此cloudtrail最合适做event的记录和发布了。

AWS支持cloudwatch、cloudtail、config-rule等各种mode。

还是以AWS自动给资源打上User标签的问题为例,前面已经介绍了实现方案。现在的问题是如果有很多账户,每个账户都手动配置一遍显然非常繁琐且耗时间。当然可以把lambda函数提前放到S3上,然后通过Terraform配置lambda、cloudwatch、cloudtrail,不过这种方式单说lambda函数不说,光Terraform代码没有几百行肯定是搞不定的。

而使用c7n则只需要写一条policy,不到20行代码:

policies:
- name: ec2-auto-tag-user
  resource: ec2
  mode:
    type: cloudtrail
    role: arn:aws-cn:iam::***:role/***
    events:
      - RunInstances
  filters:
    - tag:CreatorName: absent
  actions:
    - type: auto-tag-user
      tag: CreatorName
      principal_id_tag: CreatorId

如上使用了cloudtrail mode,action使用了auto-tag-user,这个也是内置支持的行为,role为lambda函数执行使用的role,需要在IAM中配置有打tag的权限。

执行这个policy后会自动生成lambda函数,代码是自动生成的(其实就是c7n的源码):

c7n lambda

触发器为CloudWatch Events,可以查看其配置如下:

c7n cloudwatch

除了事件驱动,基于时间轮询也是没有问题的,对应c7n mode为periodic,实现方式则通过cloudwatch的Schedule方式触发lambda函数。

比如每小时检查下是否存在安全组暴露了高危端口到互联网:

policies:
- name: test-periodic
  mode:
    type: periodic
    schedule: "rate(1 hour)"
    role: arn:aws-cn:iam::***:role/***
  resource: ec2
  filters:
  - type: ingress
    IpProtocol: tcp
    Ports: [22, 3389]
    Cidr:
      value:
      - "0.0.0.0/0"
      - "::/0"
      op: in
   actions: ...

通过如上两个例子,我们发现c7n把AWS的lambda、cloudwatch、cloudtrail很好的联动起来了,相对自己写lambda函数以及cloudwatch规则,c7n确实省了不少事。

5 总结

本文首先介绍了云平台和资源的安全合规配置基线的需求和问题,然后介绍了如何集成云平台已有的托管服务实现云平台和资源的安全合规自动配置和检查,最后以custodian为例介绍基于Policy规则声明式配置和检查安全合规基线。