インターネットサービスを提供しているサーバーに脆弱性があると、侵入や改ざん、情報漏えいといったセキュリティインシデントを引き起こす原因となってしまうのは皆さんもよくご存じかと思います。
次々に発見されるOSの脆弱性はもちろん、ミドルウェアのバージョン変更によっても脆弱性が生じることもあるため、このような被害を防ぐためには、定期的にサーバーの脆弱性診断を行うことが重要です。
ニフティクラウド脆弱性スキャンを使えば、ご利用中のサーバーの脆弱性を簡単に検知することができます。
今回は、Jenkinsを使って脆弱性診断を自動で実行し、結果をSlackに通知する仕組みを構築してみました。
設定
スキャンテンプレートの作成
ニフティクラウドのコンパネにログインし、メニューより「脆弱性スキャン」のページへ移動してスキャンテンプレートを作成します。
今回はニフティクラウドのeast-1リージョンに構築した「webserver」の脆弱性をスキャンしてみます。
Jenkins
脆弱性診断を自動で実行するためにJenkinsを構築します。 Jenkinsを起動するために、ニフティクラウドにCentOS 7.1のサーバーを作成します。
Jenkinsのインストール
サーバー作成が完了したら、サーバーにログインして以下のようにJenkinsをインストールします。
[root@jenkins]
# yum -y install java-1.8.0-openjdk
# curl -L -o /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
# rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
# yum -y install jenkins
# chkconfig jenkins on
# systemctl start jenkins
インストールが完了したら、ブラウザーから http://サーバーのIPアドレス:8080
にアクセスするとJenkinsのUI画面が表示されます。
表示される画面にしたがってJenkinsの初期設定を実施し、ユーザーを作成してログインします。
この時「install suggested plugins」を選択しておきます。
Slackの通知設定
脆弱性スキャンの結果をSlackに通知させるために設定を行います。 SlackのApps&integrationから、Jenkinsで検索して追加し通知したいチャネルを指定します。 生成されたTokenはJenkins側で設定する必要があるのでメモを取っておきます。
JenkinsのUIにて、[Jenkinsの管理]→[プラグインの管理]から利用可能タブで「slack」と検索し「Slack Notification Plugin」をインストールします。
インストールが完了したら、[Jenkinsの管理]→[システムの管理]から「Global Slack Notifier Settings」セクションにて先ほどSlackから追加したJenkinsのTokenを入力して保存します。
CLIツールのインストール
Jenkinsから脆弱性スキャンを実行するためにはNIFTY Cloud 脆弱性スキャンAPIをリクエストする必要があります。 APIをリクエストするために、go-ncvs-cliというコマンドラインツールを作ってみました。 個人で作ったもので、ニフティクラウドの公式ツールではありませんが、基本的なAPI操作は可能となっています。 サーバーにて、以下のようにインストールします。
[root@jenkins]
# curl -L -o /usr/local/bin/ncvs-cli https://github.com/harikiriboy/go-ncvs-cli/releases/download/v1.0.0/ncvs-cli
# chmod +x /usr/local/bin/ncvs-cli
インストールが完了したら、JenkinsのUIで[Jenkinsの管理]→[システムの管理]から「グローバル プロパティ」セクションにて環境変数を設定します。 コンパネから取得したアクセスキーをシークレットキーを[AWS_ACCESS_KEY_ID] [AWS_SECRET_ACCESS_KEY] に入力します。 CLIを実行するために/usr/local/binにもパスを通しておきます。
ジョブの作成
準備が整ったので、脆弱性スキャンを実行するジョブを作成します。 [新規ジョブの作成]から任意のジョブ名を入力して[Pipeline]を選択します。
「ビルドのパラメーター化」にチェックを入れ、文字列パラメーター[scan_template_name]を追加します。
「Pipeline」欄に以下のようなスクリプトを入力し、保存します。
import groovy.json.JsonSlurperClassic
node('master') {
currentBuild.result = "SUCCESS"
try {
def scan_history_uuid
stage('execute-scan') {
def json = sh returnStdout: true, script: "ncvs-cli execute-scan -scan-template-name ${scan_template_name}"
def resp = jsonParse(json)
scan_history_uuid = resp.ScanHistory.ScanHistoryUUID
}
stage('describe-scan-histories') {
waitUntil {
sleep 60
def json = sh returnStdout: true, script: "ncvs-cli describe-scan-histories -scan-template-name ${scan_template_name}"
def resp = jsonParse(json)
def scan_history = findScanHistory(resp.ScanHistories, scan_history_uuid)
echo "Status is ${scan_history.Status}"
if (scan_history.Status == "running") {
return false
}
if (scan_history.Status == "waiting") {
return false
}
if (scan_history.Status == "completed") {
return true
}
throw new RuntimeException("Status is ${scan_history.Status}.")
}
}
stage('describe-scan-results') {
def json = sh returnStdout: true, script: "ncvs-cli describe-scan-results -scan-history-uuid ${scan_history_uuid}"
def resp = jsonParse(json)
for (def scan_result: resp.ScanResults) {
def color
switch (scan_result.Severity) {
case 0:
color = "#357abd"
break
case 1:
color = "#4cae4c"
break
case 2:
color = "#bcd323"
break
case 3:
color = "#ee9336"
break
case 4:
color = "#ff0000"
break
default:
break
}
slackSend color: color, message: "NIFTY Cloud Vulnerability Scan Result\n - ${scan_result.Rule.RuleName}\n - see more information https://console.cloud.nifty.com/web/#vss/scan-history/${scan_history_uuid}"
}
}
} catch (err) {
currentBuild.result = "FAILURE"
throw err
}
}
@NonCPS
def jsonParse(def json) {
return new groovy.json.JsonSlurperClassic().parseText(json)
}
@NonCPS
def findScanHistory(list, uuid) {
return list.find {
it.ScanHistoryUUID == uuid
}
}
実行
以上でジョブの設定は完了です。 試しにパラメーター付きビルドからジョブを実行してみます。 [scan_template_name]には実行したいスキャンテンプレート名を入力します。
ジョブを実行すると、実際にスキャンが開始されます。 スキャンが完了し、結果がSlackに通知されていれば成功です。
あとは、このジョブを「定期的に実行」にしておけば継続的な脆弱性スキャンが自動で実行できますし、アプリケーションのデプロイジョブの後に実行するように設定しておくことで、環境更新後の脆弱性有無のチェックも自動で行えます。 Jenkinsで実行するScriptをカスタマイズして条件文を入れれば、CVSSスコア○○以上の場合のみ通知といったことも可能です。
まとめ
ニフティクラウド脆弱性スキャンを使えば、脆弱性スキャンを自動で簡単に実施することができました。 ニフティクラウドタイマーとも連携しているので、単純に脆弱性スキャンをスケジュール実行したい場合はタイマーを使うのもおすすめです。この場合は、自分でJenkinsサーバーを構築する必要もありません。
とても便利なので皆様も是非使ってみてください。