LoginSignup
27
22

More than 5 years have passed since last update.

AWS Inspector で脆弱性診断。Jenkins で自動実行し、結果を Slack に通知する。

Last updated at Posted at 2016-09-18

概要

新規サービスの開発に較べて、どうしても後回しになりがちな脆弱性のテストについて、ついに、ちゃんとやらねばならぬ時が来てしまいました。

AWS Inspector を使えば、手軽に、かつ、網羅的に診断を行うことが可能になっています。
AWS Inspector ユーザガイド

毎回、手動で実行していては忘れてしまうことがあるため、以下のように、Jenkins で定期的に自動実行し、かつ、結果を Slack に通知してくれる仕組みを構築しました。

スクリーンショット 2016-09-18 14.27.54.png

構築手順について、忘れないうちに Qiita化 しておきます。

設定

準備

まず、EC2に Agent をインストールして実行しておく必要があります。

サポート対象OS

Amazon Linux (2015.03 以降)
Ubuntu (14.04 LTS)
Red Hat Enterprise Linux (7.2)
CentOS (7.2)
Windows Server 2008 R2 および Windows Server 2012

Agent インストール手順

# wget https://d1wk0tztpsntt1.cloudfront.net/linux/latest/install
# bash install
# /etc/init.d/awsagent start

Inspector

AWS Inspector では、以下の4種類のルールパッケージから【複数】選択することができます。

名前 内容
一般的な脆弱性と曝露 評価ターゲット内の EC2 インスタンス が一般的な脆弱性や曝露 (CVE) に曝露されているかどうかを確認
例えば OpenSSLの脆弱性「ハートブリード」 CVE-2014-0160 が含まれます
CIS オペレーティングシステムのセキュリティ設定ベンチマーク 組織がセキュリティを評価して強化できるよう明確に定義された、公平でコンセンサスベースの業界のベストプラクティスを提供
セキュリティのベストプラクティス システムが安全に設定されているかどうかの判断
実行時の動作の分析 インスタンスの動作を分析し、EC2 インスタンスのセキュリティを高めるためのガイダンスを提供

ルールパッケージ、対象となるEC2のタグ、評価時間 を選択して、一つの「評価テンプレート」を作成します。
イベントをSNSに発火するように設定しておきます。

注意

  • 評価テンプレートは、作成後は編集はできません。
    (SNSトピックだけは、後から追加変更ができるようです)
  • 対象となるEC2インスタンスは、タグによって、評価テンプレート作成後でも増減できます。
  • 評価中のEC2インスタンスは、同時に他の評価をすることはできません。

スクリーンショット 2016-09-18 14.51.37.png

SNS

以下のイベントがSNSに向けて発火されてきます。

No event newstate
1 ASSESSMENT_RUN_STATE_CHANGED CREATED
2 ASSESSMENT_RUN_STATE_CHANGED START_DATA_COLLECTION_IN_PROGRESS
3 ASSESSMENT_RUN_STATE_CHANGED START_DATA_COLLECTION_PENDING
4 ASSESSMENT_RUN_STATE_CHANGED COLLECTING_DATA
5 ASSESSMENT_RUN_STARTED
6 ASSESSMENT_RUN_STATE_CHANGED STOP_DATA_COLLECTION_PENDING
7 ASSESSMENT_RUN_STATE_CHANGED DATA_COLLECTED
8 ASSESSMENT_RUN_STATE_CHANGED EVALUATING_RULES
9 FINDING_REPORTED
10 ASSESSMENT_RUN_COMPLETED
11 ASSESSMENT_RUN_STATE_CHANGED COMPLETED

以下に対応しているようです。

イベント event
実行開始 ASSESSMENT_RUN_STARTED
実行完了 ASSESSMENT_RUN_COMPLETED
実行ステータスが変更されました ASSESSMENT_RUN_STATE_CHANGED
報告された結果 FINDING_REPORTED

Slack通知で ASSESSMENT_RUN_STATE_CHANGED は必要ないですね。開始/完了/結果 を通知するようにします。

Lambda

Slackに通知する、以下の Lambda 関数を作成しました。
Node.js 4.3 を選択しています。
AWS API で Promise が使えますね。
外部 npm モジュールを使わないので、インラインで Lambda を構築できます。

// https://nodejs.org/docs/v4.3.2/api/

// Set your slack url here.
const slack = "/services/T0DD9AQER/B0DDBKWSX/xxxxxxxxxxxxxxxxxxxxxxxx";

const AWS = require("aws-sdk");

AWS.config.apiVersions = {
  inspector: "2016-02-16"
};

const inspector = new AWS.Inspector();

const https = require('https');


//
// Slack message format.
//
function build(template, target, finding, message) {

  var events = {
    "ASSESSMENT_RUN_STARTED": "実行開始",
    "ASSESSMENT_RUN_COMPLETED": "実行完了",
    "ASSESSMENT_RUN_STATE_CHANGED": "実行ステータス変更",
    "FINDING_REPORTED": "結果報告"
  };

  var buff = [
    [
      target.name,
      template.name,
      events[message.event]
    ].join(":")
  ];

  switch (message.event) {
    case "FINDING_REPORTED":
      buff.push("```");
      buff.push("[" + finding.severity + "] " + finding.id);
      buff.push(finding.title);
      buff.push("```");
      break;
    case "ASSESSMENT_RUN_STARTED":
    case "ASSESSMENT_RUN_COMPLETED":
      break;
    case "ASSESSMENT_RUN_STATE_CHANGED":
      buff.push(message.newstate);
      break;
    default:
      buff = null; // 通知しない
      break;
  }

  return buff && buff.join("\n");
}

//
// Lambda entry point
//
exports.handler = function (event, context, callback) {
  console.log("inspector lambda start : " + new Date());

  var messages = event.Records.reduce(function (memo, v) {
    if (v.Sns && v.Sns.Message) {
      memo.push(JSON.parse(v.Sns.Message));
    }
    return memo;
  }, []);

  Promise.all([
    inspector.describeAssessmentTemplates({
      assessmentTemplateArns: pluck(messages, "template")
    }).promise(),
    inspector.describeAssessmentTargets({
      assessmentTargetArns: pluck(messages, "target")
    }).promise(),
    inspector.describeFindings({
      findingArns: pluck(messages, "finding", "")
    }).promise()
  ]).then(function (result) {
    var templates = result[0].assessmentTemplates;
    var targets = result[1].assessmentTargets;
    var findings = result[2].findings;
    return Promise.all(messages.map(function (message, idx) {
      var text = build(templates[idx], targets[idx], findings[idx], message);
      console.log(text);
      return text && request({text: text});
    }));
  }).then(function () {
    callback();
  }).catch(function (err) {
    console.log(err);
    callback(err);
  });
};

//
// Slack
//
function request(data) {
  return new Promise(function (resolve, reject) {
    var body = JSON.stringify(data);

    var req = https.request({
      hostname: "hooks.slack.com",
      port: 443,
      path: slack,
      method: "POST",
      headers: {
        'Content-Type': 'application/json; charser=UTF-8',
        "Content-Length": Buffer.byteLength(body)
      }
    }, function (res) {
      res.statusCode === 200 ? resolve(res) : reject(res);
    });
    req.end(body);
  });
}

// utility

function pluck(array, propertyName, _default) {
  return array.map(function (v) {
    return v[propertyName] !== undefined ? v[propertyName] : _default;
  });
}

SNS でトリガーされるように設定します。

スクリーンショット_2016-09-18_15_49_13.png

Slack

このような感じで、 Slack に通知されます。
スクリーンショット_2016-09-20_14_41_16.png

何か問題があれば「報告された結果」として通知されます。
詳細(対処方法)は Inspector の「結果」画面で確認してください。

上記の例では、次のような指摘をされています。

  • node.js が古い
  • ポート 80番 で HTTP が動作している
  • root で ssh ログイン可能な設定になっている

たしかに。ごもっとも。

Jenkins

手持ちの Jenkins で定期的に実行するようにしておくと、安心ですね。

Jenkins では 「シェルの実行」を選択し、
Inspector 操作権限のあるアカウントのIDとパスワードを環境変数に設定してから、「評価テンプレート」を指定して inspector start-assessment-run を実行します。

シェルの例

# IAM : InspectorJenkins
export AWS_ACCESS_KEY_ID=AKIAIXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=ap-northeast-1

# テンプレート
TEMPLATE="arn:aws:inspector:ap-northeast-1:663889673734:target/0-FcroYIWk/template/0-0h8lMLYY"

/opt/pyenv/shims/aws inspector start-assessment-run --assessment-template-arn ${TEMPLATE}

おわりに

何台かのEC2インスタンスで本番サービスを運用していますが、いままで後手後手になっていた脆弱性診断が自動化されて、ほっと一安心しています。
さらに、ペネトレーション的な診断をしてくれるサービスが出てくることを、強く期待しています!!

27
22
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
22