[alpine] CVE-2019-13638への対応


#!/bin/sh -eo pipefail
trivy --exit-code 1 --quiet --severity HIGH,CRITICAL --auto-refresh --ignore-unfixed -c --auto-refresh company-nginx
2019-08-14T05:34:12.729Z    INFO    Removing image caches...
2019-08-14T05:34:12.730Z    INFO    Updating vulnerability database...
2019-08-14T05:36:00.080Z    INFO    Updating nvd data...
2019-08-14T05:36:33.431Z    INFO    Updating alpine data...
2019-08-14T05:36:35.409Z    INFO    Updating redhat data...
2019-08-14T05:36:38.522Z    INFO    Updating debian data...
2019-08-14T05:36:42.107Z    INFO    Updating debian-oval data...
2019-08-14T05:36:46.868Z    INFO    Updating ubuntu data...
2019-08-14T05:36:53.949Z    INFO    Detecting Alpine vulnerabilities...

company-nginx (alpine 3.9.4)
============================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION |             TITLE              |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| patch   | CVE-2019-13638   | CRITICAL | 2.7.6-r4          | 2.7.6-r6      | patch: OS shell command        |
|         |                  |          |                   |               | injection when processing      |
|         |                  |          |                   |               | crafted patch files            |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
Exited with code 1

trivy実行時にalpineに脆弱性があるよと怒られました。
インフラ全然わからないマンの僕が色々調べながら対応したので、将来自分で見直すために、ログとして対応内容と調査した内容をまとめます。

前提

今回エラーが発生したのはnginx用のDockerfileでした。
以下、Dockerfileの抜粋です。

FROM nginx:1.17.1-alpine

RUN set -e && \
  apk update && \
  apk upgrade && \
  apk add --update --no-cache \
  bzip2
...

調査1: 報告があった脆弱性の概要

今回報告があった脆弱性について、冒頭に挙げたtrivyの出力内容から VULNERABILITY ID(CVE-2019-13638) を抽出し、ググってみました。
出てきたのは以下の報告書でした。
https://nvd.nist.gov/vuln/detail/CVE-2019-13638

GNU patch through 2.7.6 is vulnerable to OS shell command injection that can be exploited by opening a crafted patch file that contains an ed style diff payload with shell metacharacters. The ed editor does not need to be present on the vulnerable system. This is different from CVE-2018-1000156.

なんとなく、「シェルコマンドインジェクションをされる可能性があるよ」的なことを言っているのがわかります。ただ、具体的な対応方法については読み取れませんでした。
先ほどの引用から、「2.7.6までのGNU patchは脆弱性があるよ」ということも読み取れます。これについては、trivyの出力内容からも、「多分 GNU patch 2.7.6-r6を入れればいいんだろうな」ということはわかります。

ここで、GNU patchってなんぞや、という疑問が浮かびました。

調査2: GNU patch

GNUとは、linuxなどのライセンスを管理している団体の名称です。
GNUが配布しているpatchパッケージのことをGNU patchと表記しているようでした。
patchというと、既存のライブラリに対する修正用の差分適用ファイルのことかなと思っていたのですが、ここではpatchコマンドで呼び出すライブラリそのものを指します。

仮説

調査1と調査2を踏まえて、「現在Dockerのベースイメージとして利用しているバージョンのalpineに、脆弱性に対応したpatchライブラリが含まれていないのではないか」という仮説が生まれます。
これをもとに、まずはalpineイメージのバージョンアップデートを試みました。

試行1: ベースイメージのバージョンアップ

Dockerhubのnginxのページから、現状のベースイメージの最新版を探します。
nginxのページ: https://hub.docker.com/_/nginx

それっぽいものがあったので、一旦雑にDockerfileの記述を修正してみます。

FROM nginx:1.17.2-alpine

RUN set -e && \
  apk update && \
  apk upgrade && \
  apk add --update --no-cache \
  bzip2
...

修正を保存し、trivyコマンドを叩いてみます。

#!/bin/sh -eo pipefail
trivy --exit-code 1 --quiet --severity HIGH,CRITICAL --auto-refresh --ignore-unfixed -c --auto-refresh company-nginx
2019-08-14T04:36:37.190Z    INFO    Removing image caches...
2019-08-14T04:36:37.194Z    INFO    Updating vulnerability database...
2019-08-14T04:41:41.458Z    INFO    Updating debian-oval data...
2019-08-14T04:41:45.945Z    INFO    Updating ubuntu data...
2019-08-14T04:41:49.828Z    INFO    Updating nvd data...
2019-08-14T04:42:19.808Z    INFO    Updating alpine data...
2019-08-14T04:42:22.014Z    INFO    Updating redhat data...
2019-08-14T04:42:25.174Z    INFO    Updating debian data...
2019-08-14T04:42:31.060Z    INFO    Detecting Alpine vulnerabilities...

company-nginx (alpine 3.10.1)
=============================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION |             TITLE              |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| patch   | CVE-2019-13638   | CRITICAL | 2.7.6-r5          | 2.7.6-r6      | patch: OS shell command        |
|         |                  |          |                   |               | injection when processing      |
|         |                  |          |                   |               | crafted patch files            |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
Exited with code 1

ダメっぽい。alpineのバージョンは上がりましたが、まだ脆弱性対応済みのpatchパッケージが含まれていないようです。
ベースイメージのアップデートで対応できないので、個別にバージョンを指定してpatchパッケージをインストールしてみようと思います。

調査3: apk

alpineでは、パッケージマネージャとしてapkを使用します。
apkのコマンドについて詳しくないので、コマンドを叩きながら調査してみようと思います。

$ docker pull alpine
jUsing default tag: latest
latest: Pulling from library/alpine
050382585609: Pull complete
Digest: sha256:6a92cd1fcdc8d8cdec60f33dda4db2cb1fcdcacf3410a8e05b3741f44a9b5998
Status: Downloaded newer image for alpine:latest

alpineのイメージをpullできたので、コンテナを立てて中に入ります。

$ docker run -it alpine sh
/ #

apkのコマンド一覧を表示します。

/ # apk --help
apk-tools 2.10.4, compiled for x86_64.

Installing and removing packages:
  add       Add PACKAGEs to 'world' and install (or upgrade) them, while ensuring that all dependencies are met
  del       Remove PACKAGEs from 'world' and uninstall them

System maintenance:
  fix       Repair package or upgrade it without modifying main dependencies
  update    Update repository indexes from all remote repositories
  upgrade   Upgrade currently installed packages to match repositories
  cache     Download missing PACKAGEs to cache and/or delete unneeded files from cache

Querying information about packages:
  info      Give detailed information about PACKAGEs or repositories
  list      List packages by PATTERN and other criteria
  dot       Generate graphviz graphs
  policy    Show repository policy for packages

Repository maintenance:
  index     Create repository index file from FILEs
  fetch     Download PACKAGEs from global repositories to a local directory
  verify    Verify package integrity and signature
  manifest  Show checksums of package contents

Use apk <command> --help for command-specific help.
Use apk --help --verbose for a full command listing.

This apk has coffee making abilities.

ここではaddコマンドが適切そうということがわかりました。
そういえば元のDockerfileで apk add ...というコマンドを叩いていました。

RUN set -e && \
  apk update && \
  apk upgrade && \
  apk add --update --no-cache \
  bzip2

apk addコマンドの引数に,バージョンを指定したpatchパッケージを追記してみます。

試行2: apk add [package name]=[version]

FROM nginx:1.17.2-alpine

RUN set -e && \
  apk update && \
  apk upgrade && \
  apk add --update --no-cache \
  bzip2 \
  patch=2.7.6-r6

...

上記の修正を保存して、再度trivyコマンドを叩きます。

#!/bin/sh -eo pipefail
trivy --exit-code 1 --quiet --severity HIGH,CRITICAL --auto-refresh --ignore-unfixed -c --auto-refresh $DOCKER_IMAGE_REPO:$CIRCLE_SHA1
2019-08-14T05:40:29.881Z    INFO    Removing image caches...
2019-08-14T05:40:29.882Z    INFO    Updating vulnerability database...
2019-08-14T05:42:48.515Z    INFO    Updating nvd data...
2019-08-14T05:43:23.457Z    INFO    Updating alpine data...
2019-08-14T05:43:27.102Z    INFO    Updating redhat data...
2019-08-14T05:43:30.237Z    INFO    Updating debian data...
2019-08-14T05:43:33.431Z    INFO    Updating debian-oval data...
2019-08-14T05:43:38.458Z    INFO    Updating ubuntu data...
2019-08-14T05:44:05.219Z    INFO    Detecting Alpine vulnerabilities...
2019-08-14T05:44:05.222Z    INFO    Updating yarn Security DB...
2019-08-14T05:44:07.099Z    INFO    Detecting yarn vulnerabilities...

****************/*************/company:****7188208f40d4faf65 (alpine 3.9.4)
=========================================================================================================================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)


app/yarn.lock
=============
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)

通りました。

おわりに

雑なログで恐縮です。かつ、もろもろの解釈がややあやふやな気がしているので、「この表現は適切ではないよ」などあれば、コメントいただけると嬉しいですm(_ _)m