容器安全之静态扫描
2019-10-29 10:20:00 Author: www.4hou.com(查看原文) 阅读量:108 收藏

导语:容器技术在google推广之下,目前已经在得到广泛的应用,越来越多的企业借助云计算为企业提质增效,实现产业升级,随着应用程序在云中大规模部署,导致云环境的复杂性不断增加,越来越多的互联网应用在云上遇到挑战,企业需要更高效的应用管理和更弹性的计算架构。

0x00、业务需求

容器技术在google推广之下,目前已经在得到广泛的应用,越来越多的企业借助云计算为企业提质增效,实现产业升级,随着应用程序在云中大规模部署,导致云环境的复杂性不断增加,越来越多的互联网应用在云上遇到挑战,企业需要更高效的应用管理和更弹性的计算架构。以 Kubernetes 为代表的云原生技术让“云原生”从一个模糊的概念,强势成长为通用技术。灵雀云、linkcloud等第三方厂商也不断涌出,同时,云原生的容器云也在各大公有云厂商中快速部署、实践、产品化。

在这种大背景下,很多使用场景都涌现出来:

1、DevOps场景

2、IoT Egde边缘计算端

3、公有云容器集群

4、私有化平台集成

5、…

在这种的大背景下,容器安全是一个必须考虑的一个问题,今天就和大家讨论一下,其中一项docker镜像扫描。

0x01、容器漏洞扫描原理

软件漏洞是软件或操作系统中存在缺陷或弱点,容器漏洞扫描系统需要具备:针对操作系统软件包(RedHat、CentOS,Debian,Ubuntu),应用程序依赖项(nodejs,php,npm,yarn,python等)进行扫描,同时方便集成devops(例如:Jenkins、镜像仓库等)。精确度高(特别是Alpine Linux和RHEL /CentOS)

漏洞扫描最重要是拥有一个强大的漏洞库,

可以收集:https://github.com/aquasecurity/vuln-list/tree/master/alpine

{
  "IssueID": 0,
  "VulnerabilityID": "CVE-2019-5736",
  "Release": "3.9",
  "Package": "runc",
  "Repository": "community",
  "FixedVersion": "1.0.0_rc6-r1",
  "Subject": "",
  "Description": ""
}
其中VulnerabilityID、Package、FixedVersion,组成了版本比对数据库。当然可以通过CNVD关联的CVE号补充Subject、Description。漏洞总数超过1万+
扫描器检查部分代码(以ubuntu为例):
第三方库支持:bundler、cargo、composer、npm、pipenv、poetry、yarn、node、python
获取原始版本:
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]vulnerability.DetectedVulnerability, error) {
 log.Logger.Info("Detecting Ubuntu vulnerabilities...")
 log.Logger.Debugf("ubuntu: os version: %s", osVer)
 log.Logger.Debugf("ubuntu: the number of packages: %d", len(pkgs))

 var vulns []vulnerability.DetectedVulnerability
 for _, pkg := range pkgs {
  advisories, err := ubuntu.Get(osVer, pkg.SrcName)
  if err != nil {
   return nil, xerrors.Errorf("failed to get Ubuntu advisories: %w", err)
  }

  installed := utils.FormatSrcVersion(pkg)
  installedVersion, err := version.NewVersion(installed)
  if err != nil {
   log.Logger.Debugf("failed to parse Ubuntu installed package version: %w", err)
   continue
  }

  for _, adv := range advisories {
   vuln := vulnerability.DetectedVulnerability{
    VulnerabilityID:  adv.VulnerabilityID,
    PkgName:          pkg.Name,
    InstalledVersion: installed,
    FixedVersion:     adv.FixedVersion,
   }

   if adv.FixedVersion == "" {
    vulns = append(vulns, vuln)
    continue
   }

   fixedVersion, err := version.NewVersion(adv.FixedVersion)
   if err != nil {
    log.Logger.Debugf("failed to parse Ubuntu package version: %w", err)
    continue
   }

   if installedVersion.LessThan(fixedVersion) {
    vulns = append(vulns, vuln)
   }
  }
 }
 return vulns, nil
}
func Get(release string, pkgName string) ([]vulnerability.Advisory, error) {
 bucket := fmt.Sprintf(platformFormat, release)
 advisories, err := db.Config{}.ForEach(bucket, pkgName)
 if err != nil {
  return nil, xerrors.Errorf("error in Ubuntu foreach: %w", err)
 }
 if len(advisories) == 0 {
  return nil, nil
 }

 var results []vulnerability.Advisory
 for _, v := range advisories {
  var advisory vulnerability.Advisory
  if err = json.Unmarshal(v, &advisory); err != nil {
   return nil, xerrors.Errorf("failed to unmarshal Ubuntu JSON: %w", err)
  }
  results = append(results, advisory)
 }
 return results, nil
}
输出检查结果:
func (tw TableWriter) write(result Result) {
 table := tablewriter.NewWriter(tw.Output)
 table.SetHeader([]string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version", "Title"})

 severityCount := map[string]int{}
 for _, v := range result.Vulnerabilities {
  severityCount[v.Severity]++

  title := v.Title
  if title == "" {
   title = v.Description
  }
  splittedTitle := strings.Split(title, " ")
  if len(splittedTitle) >= 12 {
   title = strings.Join(splittedTitle[:12], " ") + "..."
  }
  if tw.Output == os.Stdout {
   table.Append([]string{v.PkgName, v.VulnerabilityID, vulnerability.ColorizeSeverity(v.Severity),
    v.InstalledVersion, v.FixedVersion, title})
  } else {
   table.Append([]string{v.PkgName, v.VulnerabilityID, v.Severity, v.InstalledVersion, v.FixedVersion, title})
  }
 }

 var results []string
 for _, severity := range vulnerability.SeverityNames {
  r := fmt.Sprintf("%s: %d", severity, severityCount[severity])
  results = append(results, r)
 }

 fmt.Printf("\n%s\n", result.FileName)
 fmt.Println(strings.Repeat("=", len(result.FileName)))
 fmt.Printf("Total: %d (%s)\n\n", len(result.Vulnerabilities), strings.Join(results, ", "))

 if len(result.Vulnerabilities) == 0 {
  return
 }

 table.SetAutoMergeCells(true)
 table.SetRowLine(true)
 table.Render()
 return
}

0x02、容器漏洞扫描产品化

主要是让用户提升安全运营效率,快速查找定位,评估容器漏洞危害性,决定是否修复。

屏幕快照 2019-10-27 上午10.44.24.png


文章来源: https://www.4hou.com/system/21191.html
如有侵权请联系:admin#unsafe.sh