インターネット上のリポジトリへ直接アクセス出来ない環境でVulsを使ってスキャンする方法

# はじめに
先日、「[Vuls構成デザインパターン](http://qiita.com/usiusi360/items/5a7125350ed57b327636)」の中で「[5．インターネットから隔離された環境での運用](http://qiita.com/usiusi360/items/5a7125350ed57b327636#5インターネットから隔離された環境での運用)」について簡単に構成を示しましたが、今回は実際に出来るかPoC(Proof Of Concept)を実施してみます。

# 構成図

AWS上にて以下のような環境を作りました。
スキャン対象サーバは外部へ直接アクセスできないようにセキュリティグループのOutboundで制限します。

OS: CentOS Linux release 7.2.1511 (Core)

<img width="100%" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/54952/d6e418fe-3d87-281e-6a37-ff630be2bebd.png">

インスタンスを作成したら、スキャン対象サーバから外部のサイトにアクセスできないことをcurlで確認しておきます。

# ローカルリポジトリを構築

参考URL
> [CentOS 7でyumサーバ(yumリポジトリミラーサーバ)を構築する](https://orebibou.com/2015/03/centos-7でyumサーバyumリポジトリミラーサーバを構築する/)
> [CentOS7 リポジトリサーバ クイックスタート](http://qiita.com/ezaqiita/items/294b7525fdb496d89bce)


- 上記URL先の内容を参考にしながらリポジトリを作成します。


### リポジトリサーバにパッケージインストール＆rsyncでパッケージダウンロード

```bash
$ sudo yum install httpd rsync createrepo
$ sudo mkdir -p /var/www/html/centos/7/{os,updates,extras}/
$ sudo rsync -rptvz --delete rsync://ftp.riken.jp/centos/7/os/ /var/www/html/centos/7/os/
$ sudo rsync -rptvz --delete rsync://ftp.riken.jp/centos/7/updates/ /var/www/html/centos/7/updates/
$ sudo rsync -rptvz --delete rsync://ftp.riken.jp/centos/7/extras/ /var/www/html/centos/7/extras/
```

```bash:rsync結果確認
$ tree -L 4 /var/www/html/centos/
/var/www/html/centos/
└── 7
    ├── extras
    │   └── x86_64
    │       ├── Packages
    │       ├── drpms
    │       └── repodata
    ├── os
    │   └── x86_64
    │       ├── CentOS_BuildTag
    │       ├── EFI
    │       ├── EULA
    │       ├── GPL
    │       ├── LiveOS
    │       ├── Packages
    │       ├── RPM-GPG-KEY-CentOS-7
    │       ├── RPM-GPG-KEY-CentOS-Testing-7
    │       ├── images
    │       ├── isolinux
    │       └── repodata
    └── updates
        └── x86_64
            ├── Packages
            ├── drpms
            └── repodata
```

### リポジトリサーバのapache設定

```
$ cd /etc/httpd/conf.d
$ sudo mkdir old
$ sudo mv * old
# echo '<directory "/var/www/html/centos">' >  /etc/httpd/conf.d/centos-mirror.conf
# echo '  options +indexes'                 >> /etc/httpd/conf.d/centos-mirror.conf
# echo '</directory>'                       >> /etc/httpd/conf.d/centos-mirror.conf
$ sudo systemctl restart  httpd
```

```html:curlで動作確認
$ curl -s http://localhost/centos/7/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /centos/7</title>
 </head>
 <body>
<h1>Index of /centos/7</h1>
<ul><li><a href="/centos/"> Parent Directory</a></li>
<li><a href="extras/"> extras/</a></li>
<li><a href="os/"> os/</a></li>
<li><a href="updates/"> updates/</a></li>
</ul>
</body></html>
```

### スキャン対象サーバ(yumクライアント)設定

```bash
$ sudo vi /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra #コメントアウトする
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
baseurl=http://<リポジトリサーバのアドレス>/centos/$releasever/os/$basearch/ #←追記
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates
[updates]
name=CentOS-$releasever - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra #コメントアウトする
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
baseurl=http://<リポジトリサーバのアドレス>/centos/$releasever/updates/$basearch/ #←追記
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra  #コメントアウトする
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
baseurl=http://<リポジトリサーバのアドレス>/centos/$releasever/extras/$basearch/ #←追記
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
```

### スキャン対象サーバ(yumクライアント)動作確認
リポジトリの「/var/log/httpd/access_log」をtailで見ながら、アクセスが来ているか確認します。

```bash
$ sudo yum clean all
$ sudo yum list all
```


# スキャン対象サーバに対してVulsでスキャンする

通常どおりscanを行います。

ただし構成図のようなVulsサーバ自身もインターネットにアクセスできない環境の場合、「go-cve-dictionary」だけインターネットに出られる環境で実施し、作成された「cve.sqlite3」をVulsサーバへコピーします。

```bash
$ vuls scan -cve-dictionary-dbpath=/opt/vuls/cve.sqlite3 -report-json
```

問題なく「vuls scan」は実行され結果も得られます。また当然ですが、**パブリックなリポジトリを直接参照する場合とローカルリポジトリを参照する場合とで検知結果に違いは発生しませんでした。**


# vuls scan時に必要なリポジトリのデータについて
スキャン対象サーバで「yum clean all」を行なったあとに「vuls scan」した場合のローカルリポジトリのアクセスログを確認したところ、以下のログのとおり「os/update/extra」の**各repodataの下しかアクセスしていません**。
試しにrepodataだけ残し、それ以外のデータを削除してvuls scanしてみましたが、問題なくチェックできます。vulsによるスキャンだけを目的とするのであれば、「repodata」フォルダだけrsyncし大量のrpmファイルがある**「Packages」フォルダを除外することで同期の時間を短くできそうです**。

```bash
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/os/x86_64/repodata/repomd.xml HTTP/1.1" 200 3735 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/extras/x86_64/repodata/repomd.xml HTTP/1.1" 200 3448 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/updates/x86_64/repodata/repomd.xml HTTP/1.1" 200 3470 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/os/x86_64/repodata/436345f4b666f0a461d479ccfabc2c22823d4f2173c2653e5250fea62f0afe98-c7-x86_64-comps.xml.gz HTTP/1.1" 200 158802 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/extras/x86_64/repodata/255224094a57c2de7e747fc25441b55e6f210ec0b026d434ebecf8b726e680af-primary.sqlite.bz2 HTTP/1.1" 200 170282 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/os/x86_64/repodata/c6411f1cc8a000ed2b651b49134631d279abba1ec1f78e5dcca79a52d8c1eada-primary.sqlite.bz2 HTTP/1.1" 200 5549298 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:35 +0000] "GET /centos/7/updates/x86_64/repodata/1e5e6f28f65cae495ae491aa28709234f7569c0f5d350d356ca8ffb8c18afde9-primary.sqlite.bz2 HTTP/1.1" 200 9490679 "-" "urlgrabber/3.10 yum/3.4.3"
10.0.0.29 - - [11/Dec/2016:14:10:41 +0000] "GET /centos/7/updates/x86_64/repodata/bae0e84dee59a756da73eb53de2ffdd9fab7b0f526bc937d3e32bf4b9011d2ff-other.sqlite.bz2 HTTP/1.1" 200 82702698 "-" "urlgrabber/3.10 yum/3.4.3"
```

# 外界から完全に分離されたシステムの場合
先日の「[Vuls構成デザインパターン](http://qiita.com/usiusi360/items/5a7125350ed57b327636#5インターネットから隔離された環境での運用)」でも示しましたが、オンプレ環境などでインターネットへの接続経路が全く無いシステムの場合、更新パッケージ取得用のPCをシステムの外に用意し、そこでパブリックリポジトリのデータと「go-cve-dictionary」の取得を行います。
そしてポータブルHDDやUSBメモリなどの媒体を介してローカルリポジトリやVulsサーバへ反映させる運用方法が考えられます。

<img width="100%" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/54952/60de735f-fa0a-598c-8d99-14ef9cc2c6d3.png">

# さいごに
今回は試していませんがソースを元にビルドする場合rpm化し、それをローカルリポジトリに登録することで(changelogをrpmに埋め込む必要はありますが)CPEベースのチェックではなく、yumによる一括管理を行うことができます。

またVuls自体、ビルド時に依存関係のあるパッケージを自動的にダウンロードするためインターネット接続が無いと辛いですが、ビルドされたバイナリはポータビリティに優れているためシステムの外でビルドされたものを使えば導入は比較的容易にできます。
今回の内容と合わせてオンプレ環境での導入の助けになればと思います。