🔐

Security Command Center でガードレールを作る

2024/04/22に公開

※本記事は、2022年7月24日に公開済みの記事を移行して再掲載したものです。

はじめに

フェズでエンジニアをしている321です
クラウドのアカウント管理やセキュリティ等、開発チームがプロダクトを適正に提供するための基盤を整備する事もミッションとしています
今回は、その中でもフェズのプロダクトにおいてメインで利用しているGoogle Cloudのセキュリティ施策についてご紹介します

背景

フェズでは、プロダクトの大部分がGoogle Cloudで稼働しています
特に、BigQueryを中心にしたデータ基盤には顧客からお預かりしたデータが存在しています
そこでデータを安全に管理するために、クラウドのセキュリティが担保されている状態を可視化し不適切な設定を検知できる仕組みを検討する事にしました

Security Command Center

という事で、導入したサービスが Security Command Center (以下、SCC)です
Google Cloud 環境をスキャンして、構成ミスや脆弱性などのセキュリティ&リスクを管理してくれるプラットフォームです
※Google Cloud 環境で組織 (Organization) を構成していることが利用の前提条件です

現時点で以下のようなサービスが提供されています (今回はSecurity Health Analytics を中心の話になります )

サービス 概要
Security Health Analytics 環境内の一般的な構成ミス(ポートが開いているFW、公開されているバケット、CIS 違反など)を特定
Web Security Scanner ウェブ アプリケーションを危険にさらす、XSSや古いライブラリなどの一般的な脆弱性を検出
Event Threat Detection Cloud Platform、ID、データ、コンピューティングインスタンスに対する脅威をリアルタイムで検出
ontainer Threat Detection カーネルレベルの計測機能を使用して、不審なバイナリを含め、コンテナの潜在的な危険性を特定
Virtual Machine Threat Detection Compute Engine インスタンスを分析して、クリプトマイニングの不正などの脅威を特定

Security Command Center のプラン

SCCのプランには スタンダード ティアプレミアム ティア があります

各プランの料金

SCCの料金体系
上記の通り、スタンダードは基本無料で利用できるのですが、プレミアムに関しては以下のような記述になっています

Security Command Center のプレミアム ティアは、1 年間または複数年の固定料金サブスクリプションでご利用いただけます。
Google Cloud の年間費用またはコミット契約の合計が 1,500万ドルを超える場合は、利用可能な料金オプションについて営業担当者にお問い合わせください。
Google Cloud の年間費用またはコミット契約の合計額が 1,500 万ドル未満の場合、
Security Command Center Premium の年間コストは、次のうちの金額が大きい方の 5% になります。
  - 契約した Google Cloud の年間費用(コミット契約の期間までの取引)
  - 現在の実際の Google Cloud の費用の年換算額(最大 1 年間の取引)

プレミアムの一部だけを利用できる柔軟なプランがあれば良いのですが、、、現時点では対応していないとの事です~
(Google Cloudのサポートにお聞きした所、そういった要望はかなり多いらしいので将来的に対応される可能性はあるかも)

※これは再掲時の2024年4月時点では対応されています 🎉

各プランで利用できるサービス

SCCのティア
上記の通り、プレミアムは前述したような機能を全て利用できる一方、
スタンダードに関しては Security Health Analytics の一部しか利用ができません (無料なので当然といえば当然ですが)

Security Command Center の利用と課題

先述の通り、プレミアム ティアを利用するにはそれなりのコストが発生します
また、プレミアムを利用できたとしても、その全ての脆弱性に対応していくには組織としてそれなりに体力が必要になります
現在、フェズではクラウドセキュリティの対応は私がほぼ1人で担っている状況なので、プレミアムを契約したとしても満足に活用できない可能性が高いです

そのため、フェズでは現時点で スタンダード の利用にとどめています
SCC利用開始は、以下のドキュメントの通りにコンソールからポチポチすればできるので割愛します
Security Command Center を設定する

とはいえ、スタンダードだとかゆい所に手が届かないのも事実で
脆弱性に関する検出
↑上記のリンクの通り、 Security Health Analytics の検出項目もほとんどがプレミアムです

が、中には是が非でも検出しておきたい重要な構成ミスも存在します
例えば、重要なデータを管理するデータストア関連、それにアクセスするためのIAM関連の脆弱性に関しては特にチェックしておきたい所。。。
という事で、なんとかプレミアム ティアの力を借りずに脆弱性の検知を自作できないかと考えました

Security Command Center に独自で検出した脆弱性を登録する

結論から言うと、以下のAPIを利用すれば脆弱性のあるアセットを検出して、それをSCCに登録することができました
google-cloud-asset
google-cloud-securitycenter

前者は Google Asset Inventry というサービスで、組織内の全てのリソースを取得する事ができます
後者はSCCのAPIで、Asset Inventry で検知した脆弱性を SCC に登録する際に利用します
検出するだけなら前者のAPIだけでも十分なのですが、、、

SCCのダッシュボードは非常に見やすく、また、スタンダード ティアで検出した脆弱性はGoogle Cloudコンソール上のダッシュボードに表示されます
自作したスクリプトで検出した脆弱性も同じダッシュボード上で可視化したかったので、後者のAPIを利用してSCCに登録しています
コードを見た方が分かりやすいと思うので、FireWallルールでMySQLのポートが開放されている事を検知するサンプルを記載します

import datetime
import hashlib

from google.cloud import asset_v1
from google.cloud import compute_v1
from google.cloud import securitycenter_v1

asset_client = asset_v1.AssetServiceClient()
firewall_client = compute_v1.FirewallsClient()
scc_client = securitycenter_v1.SecurityCenterClient()

asset_types = ["compute.googleapis.com/Firewall"]
category = "OPEN_MYSQL_PORT"
event_time = datetime.datetime.now(tz=datetime.timezone.utc)
scope = "organizations/[organization_id]"

def main(event, context):
    # 組織のFireWall一覧を取得する
    resources = asset_client.search_all_resources(
        request={
            "scope": scope,
            "asset_types": asset_types,
        }
    )
    for resource in resources:
        # FireWallの詳細設定を取得する
        firewall = firewall_client.get(
            request={
                "firewall": resource.display_name,
                "project": resource.project.split('/')[1],
            }
        )
        for allow in firewall.allowed:
            # FireWallルールにおいて、TCPで3306ポートが開放されているものが存在するかチェック
            if allow.I_p_protocol == "tcp" and '3306' in allow.ports:
                now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
                resource_name = resource.name
                source_name = "{}/sources/[source_id]".format(scope)
                # 検知した脆弱性を一意に特定する検出IDを作成する (このサンプルでは「検出カテゴリ+時刻+アセット名」したものをハッシュ化しているが、重複しなければ何でも良い)
                finding_string = "openmysqlport{}{}".format(now, resource_name)
                finding_id = hashlib.md5(finding_string.encode()).hexdigest()

                # 検出したアセットが既にSCCに登録されているかチェック
                request = securitycenter_v1.ListFindingsRequest(
                    parent=source_name,
                    filter="resource_name=\"{}\" \
                            AND category=\"{}\" \
                            AND state=\"ACTIVE\" \
                            AND (mute=\"UNDEFINED\" OR mute=\"UNMUTED\") \
                           ".format(resource_name, category)
                )
                if scc_client.list_findings(request=request).total_size == 0:
                    # 検出された脆弱性が未登録なら、SCCに登録する
                    finding = securitycenter_v1.Finding(
                        state=securitycenter_v1.Finding.State.ACTIVE,
                        resource_name=resource_name,
                        category=category,
                        event_time=event_time,
                        severity="HIGH",
                        finding_class="MISCONFIGURATION",
                        description="MySQL Port is open in FireWall",
                    )

                    created_finding = scc_client.create_finding(
                        request={
                            "parent": source_name,
                            "finding_id": finding_id,
                            "finding": finding
                        }
                    )
                    print(created_finding)
                else:
                    print("Finding already exists, Skip Create Finding: {}.{}"
                          .format(category, resource_name))

上記のようなスクリプトを、Cloud Scheduler → Pub/Sub → Cloud Functions で定期的に実行してチェックしています
※ 組織全体のAssetsを取得する必要があるので、Cloud Functions を実行するSAには以下のロールを組織レベルで付与しています

  • Cloud Asset オーナー: roles/cloudasset.owner
  • セキュリティ センター管理者: roles/securitycenter.admin
  • 閲覧者: roles/viewer

実際に3306ポートを開放したFWを作成して上記のスクリプトを実行すれば、以下のようにSCCに脆弱性が登録されます

Security Command Center で検出した脆弱性をSlackに通知する

ここまでで、SCCのダッシュボード上で脆弱性を可視化する事ができました
定期的にダッシュボードをチェックしてもいいのですが、なるべくなら脆弱性が検出された時点で把握し対応したいものです
Pub/Sub の検出結果を通知する

上記の通り、SCCには検知したらPub/Subに通知する機能が備わっている(これは無料)ので、Pub/SubからCloud Functionsを起動してSlackに通知するように設定しています
以下、通知スクリプトのサンプルです

import base64
import json
import os
import requests

scc_base_url = \
    "https://console.cloud.google.com/security/command-center/findingsv2"
token = os.environ['SLACK_BOT_OAUTH_TOKEN']

def main(event, context):
    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    message_json = json.loads(pubsub_message)
    finding = message_json['finding']
    # URLの/をエンコード
    name_encoded = finding['name'].replace("/", "%2F")
    orgnization_id = finding['name'].split("/")[1]
    # Slackの通知メッセージからSCCダッシュボードにすぐに遷移できるようにURLを組み立てる
    scc_url = "{};name={}?organizationId={}".format(
        scc_base_url, name_encoded, orgnization_id)
    print(finding)

    requests.post("https://slack.com/api/chat.postMessage", data={
        "token": token,
        "channel": "#cloud_management_alert",
        "attachments": json.dumps([
            {
                "title": "Security Command Center Alert",
                "color": "danger",
                "text": "<!channel>",
                "fields": [
                    {
                        "title": "Category",
                        "value": finding['category']
                    },
                    {
                        "title": "resourceName",
                        "value": finding['resourceName']
                    },
                    {
                        "title": "sccURL",
                        "value": "<{}|SCC Finding URL>".format(scc_url)
                    }
                ]
            }
        ])
    })

まとめ

ご紹介したのはSCC の一部ですが、Google Cloud 組織全体の “最低限” の構成ミスを把握し対策する事ができました
とはいえ、まだまだ検出・対応しておきたい項目も残っているので、継続的に改善活動を続けていく予定です

また、今回は Security Health Analytics についてご紹介しましたが、SCCの他サービス利用を検討する日が近い将来に必ず来ると思っています
今回ご紹介したのは、それまでの “繋ぎ” の施策と考えていますので、進展があればまたこちらでご紹介できればと思います

フェズ開発ブログ

Discussion