🆙

SecurityHubの運用フローの改善について

2024/07/25に公開

はじめに

Septeni Japan株式会社でプロダクト開発&インフラセキュリティ対策を行っているエンジニアの市原と申します。
以前、ControlTowerの導入に伴い、SecurityHubの導入の記事を公開しましたが、運用していくうちに課題が出てきたので、運用フローの改善を行った話となります。

https://zenn.dev/septeni_japan/articles/8bccdca841ea1c
https://zenn.dev/septeni_japan/articles/fa385f5980a284

前提

  • 導入済みAWSサービス: SecurityHub
  • セキュリティリスク検出時に開発エンジニアチームへslack通知する仕組みを構築済み
  • 役割分担
    • インフラエンジニアチーム: 全体統制やルールの意思決定
    • 開発エンジニアチーム: 検出された脆弱性の修復

発生した課題

  1. 開発エンジニアチームがセキュリティ対応と開発タスクの優先順位を判断しづらく、情報漏洩インシデントに繋がる高レベルの検出内容とインシデントに直結しない低レベルの検出内容が同じように扱われていた
  2. インフラエンジニアチーム視点では、AuditアカウントのSecurityHubの管理画面の機能が不足しており、現状把握が難しかった
    • 全アカウントを横断したセキュリティスコア
    • 抑制済み(= 当社としてテイクしているリスク)の一覧

解決策1

重要度によって、優先度と対応期限を明確にしたフローを整備しました。

重要度: Criticalの場合

重要度がCriticalの場合は、リソースが情報漏洩インシデントにつながる可能性のある設定となっている為、Slack通知を受け取ったら、開発エンジニアチームは即時調査に動き出します。問題の有無を確認し、もし問題がある場合はインフラエンジニアチームへ報告を上げ、その後、開発エンジニアチームは設定を修復します。

重要度: High,Medium,Low

Criticalの項目で重大なリスクは回避できている為、重要度がHigh,Medium,Lowの項目は対策の上積みという位置づけで捉えています。その為、開発タスクとのバランスを考え、1週間以内に対応方針(抑制するか/修復するか)を決めるという形を取っています。

抑制する場合はインフラエンジニアチームへ相談して対応を協議します。修復する場合は開発エンジニアチームでスケジュールを設定して対応していきます。

解決策2

セキュリティスコアの可視化

SecurityHubAPIを活用することで、アカウントを横断した情報を取得できることが分かりました。

セキュリティスコアに関しては、検出結果の一覧をAPIで取得してスプレッドシートに出力し、スプレッドシート関数を活用することで簡易的なダッシュボードを作成しました。

抑制済みの一覧化

抑制済みとしたリソースをAPIで取得してスプレッドシートに一覧として出力しました。なお、抑制済みとする際に、開発エンジニアチームに理由を入力してもらうことで、妥当性を確認できるようにしています。

使用したエンドポイント

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/securityhub/command/GetFindingsCommand/

サンプルコード

検出結果一覧を取得するコード

const {SecurityHubClient, GetFindingsCommand} = require('@aws-sdk/client-securityhub')

class SecurityHub {
    constructor(region = 'ap-northeast-1') {
        this.client = new SecurityHubClient({region})
    }

    async _getFindings (filters) {
        let nextToken
        let findings = []
        do {
            const input = {
                Filters: filters,
                NextToken: nextToken,
                MaxResults: 100
            }
            const command = new GetFindingsCommand(input)
            const {Findings, NextToken} = await this.client.send(command)
            findings = findings.concat(Findings)
            nextToken = NextToken
        } while(nextToken)

        return findings
    }

    // 検出一覧を取得する
    async getNotifiedFindings () {
        return this._getFindings({
            ProductName: [{Value: 'Security Hub', Comparison: 'EQUALS'}],
            WorkflowStatus: [{Value: 'NOTIFIED', Comparison: 'EQUALS'}],
            RecordState: [{Value: 'ACTIVE', Comparison: 'EQUALS'}],
            SeverityLabel: [{Value: 'INFORMATIONAL', Comparison: 'NOT_EQUALS'}],
            LastObservedAt: [{DateRange: {Unit: 'DAYS', Value: 30}}]
        })
    }

    // 抑制済み一覧を取得する
    async getSuppressedFindings () {
        return this._getFindings({
            ProductName: [{Value: 'Security Hub', Comparison: 'EQUALS'}],
            WorkflowStatus: [{Value: 'SUPPRESSED', Comparison: 'EQUALS'}],
            RecordState: [{Value: 'ACTIVE', Comparison: 'EQUALS'}],
            SeverityLabel: [{Value: 'INFORMATIONAL', Comparison: 'NOT_EQUALS'}]
        })
    }

まとめ

SecurityHubの運用は、重大なセキュリティホールは迅速に、それ以外はセキュリティ対応と開発タスクの優先順位のバランスを考えて対応していくという運用フローで、リスクとタスク負荷のバランスをとりました。

運用という目線では、当たり前ではありますが、ツールを導入して終わりではなく、実態に合わせて改善していくことが重要だと思っていますので、アップデートできる情報があれば、また記事を書いていきたいと思います。

次回

SecurityHubの対応を自動化することで、現在行っている手動の対応を、より迅速にミスなく対応することができる自動修復アクションを導入した話を記事にしたいと思ってます。

Discussion