Article

1日で構築する情報セキュリティ体制

高田晃太郎
1日で構築する情報セキュリティ体制

IBM Cost of a Data Breach 2023では、1件あたりの平均コストは約4.45百万ドル、検知と封じ込めに平均277日を要したと報告されています。¹ 人の判断ミスが関与する割合はVerizon DBIR 2023でおよそ7割に達し²、長期化するほどコストは増大する傾向があります。⁴ だからこそ、完璧を目指して半年かけるより、今日の8時間で骨格を立てる方が、経営的にも技術的にも合理的です。実務で広く採られる結論は単純で、可視化・最小権限⁷・即時検知・自動化・簡易運用の5点を、目安の数値と期間を添えて組み立てれば、翌日からの運用でも主要リスクを大幅に下げられる可能性が高いということです。必要なのは、範囲を絞った決断と、現場に載る実装です。ここで示す数値や時間はあくまで一般的な目安であり、規模・体制・権限状況により変動します。

1日での最低限のセキュリティ体制とは

1日で作る体制は、完璧な網羅性ではなく、攻撃の入り口を狭め、侵入の痕跡を早期に掴み、運用初日から回る仕組みに焦点を当てます。具体的には、短時間で資産とリスクを見える化し(アセットディスカバリ)、長期鍵を止めて多要素認証(MFA: Multi-Factor Authentication)を強制し、クラウドとリポジトリに即時有効な検知を入れ、データの公開と暗号化を制御し、最後に運用の最低限を回して当日のうちにテストします。本稿ではこの順番を外さず、所要時間を0〜1時間、1〜3時間、3〜6時間、6〜8時間の四つのブロックで区切ります。期日を切った工程設計は、現場の集中力と意思決定の質を維持し、結果としてリスクを削る最短路になります。なお、組織の規模や承認フローにより前後や延伸が生じる点は織り込んでください。

8時間の設計原則と到達点

8時間という制約の下では、スコープを攻撃の現実に合わせて絞ることが重要です。優先度は人の入り口(アイデンティティ)と公開面(インターネット露出)に寄せます。到達点の目安として、全クラウドアカウントと主要リポジトリのインベントリを作り、公開設定の粗を即時列挙して是正します。MFAを全管理者に強制し、90日超のアクセスキーを停止します。クラウド側ではGuardDuty⁸やSecurity Command Center⁹などマネージド検知を有効化し、リポジトリにはCodeQL¹⁰(SAST: 静的解析)とシークレットスキャン¹¹を組み込みます。ストレージではサーバーサイド暗号化を強制し、パブリックアクセスを遮断するポリシーで保護します。最後に、単純でも運用できるインシデント初動(NISTのガイド⁵に沿った「検知→分析→封じ込め→根絶→復旧」の入口)を定義し、通知がSlackやメールに入る状態でテストします。これらはクラウドセキュリティやゼロトラスト(境界に依存せず常時検証)における業界標準の考え方に整合します。導入に伴う従量課金や誤検知の増加、既存ワークフローへの影響はリスクとして事前に説明しておくと良いでしょう。

成果指標を期間明示で定義する

短期ではMTTD(平均検知時間)を1営業日未満に、検知からの一次封じ込めを60分以内に収める、という目標例を置きます。設定逸脱の是正率は初日で80%前後、リポジトリスキャンのカバレッジは主要リポジトリの80%以上を当日有効化する、といった水準を目安にします。翌週以降の追補で100%を狙えばよく、初日は「漏れを検知できる」状態を最短で作るのが目的です。IBMの報告ではインシデント対応体制と演習のある組織は平均1.49百万ドルのコスト削減が示されています。³ これは、初日から運用し検知を早める意思決定に定量的な根拠を与えます。なお、これらの指標は体制・人員・システム規模により達成度が変動するため、あくまで暫定KPIとして扱い、翌週以降に現実値でリベースしてください。

0〜3時間で可視化とアイデンティティを固める

最初の数時間で、現状の輪郭を具体的に掴みます。クラウドの公開設定、セキュリティグループの過剰開放、放置されたアクセスキー、パブリックなリポジトリや機密のハードコーディングなど、攻撃の踏み台になりやすい地点を列挙して止血します。ここで大事なのは、完璧な台帳ではなく、誤設定の温床に素早くハイライトを当てる実務的な可視化です。次に、管理者とCIなど高特権の入り口にMFAを強制し、長期鍵の使用をやめ、短期資格情報(フェデレーションやロール引き受け)に寄せます。ゼロトラストの要諦である「最小権限」と「継続的検証」を、まず人の入り口から適用します。

資産の即席インベントリとリスクの見える化

クラウドの公開面から取るのが早道です。例えばAWSであれば、バケットの公開リスクや0.0.0.0/0に開いたセキュリティグループを洗い出します。以下のスクリプトは、標準的な検査を短時間で走らせ、見つかった項目をCSVに吐きます。失敗時は即座に停止します。環境によっては追加の権限やリージョン横断の考慮が必要になる点に注意してください。

#!/usr/bin/env bash
set -euo pipefail
trap 'echo "[ERROR] line $LINENO" >&2; exit 1' ERR
REGION="${AWS_REGION:-ap-northeast-1}"
TS=$(date +%Y%m%d-%H%M%S)
OUT="inventory-$TS.csv"

printf "type,name,detail\n" > "$OUT"

# S3 public access check
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
  pab=$(aws s3api get-public-access-block --bucket "$b" --query 'PublicAccessBlockConfiguration' --output json 2>/dev/null || echo '{}')
  acl=$(aws s3api get-bucket-acl --bucket "$b" --output json)
  if echo "$acl" | jq -e '.Grants[]?.Grantee.URI? | select(test("AllUsers|AuthenticatedUsers"))' >/dev/null; then
    echo "s3,$b,ACL allows public" >> "$OUT"
  fi
  if echo "$pab" | jq -e '.BlockPublicAcls!=true or .BlockPublicPolicy!=true or .RestrictPublicBuckets!=true or .IgnorePublicAcls!=true' >/dev/null; then
    echo "s3,$b,PublicAccessBlock not strict" >> "$OUT"
  fi
  enc=$(aws s3api get-bucket-encryption --bucket "$b" --query 'ServerSideEncryptionConfiguration' --output json 2>/dev/null || echo '{}')
  if [ "$enc" = "{}" ]; then
    echo "s3,$b,No default encryption" >> "$OUT"
  fi
done

# Security Groups with wide open ingress
aws ec2 describe-security-groups --region "$REGION" --output json \
| jq -r '.SecurityGroups[] as $g | $g.IpPermissions[]? as $p | $p.IpRanges[]? | select(.CidrIp=="0.0.0.0/0") | "sg,"+$g.GroupName+","+($p.FromPort|tostring)+"-"+($p.ToPort|tostring)' \
>> "$OUT"

echo "Wrote $OUT"

同様に、GCPではStorageのUniform bucket-level accessとPublic access preventionの状態、VPCファイアウォールの0.0.0.0/0許可を列挙すれば、可視化の筋は変わりません。ここで出た高リスクだけ、先に是正します。例えば全開放の22番ポートを閉じる、暗号化を必須化する、パブリックなバケットを私有化する、といった簡易修正です。変更は変更管理プロセスに則り、影響範囲とロールバック手順を簡潔に残しておくと安全です。

アクセス権の一括是正と鍵ローテーション

人の入り口を締める効果は即効性が高いです。管理アカウントとCIの実行ロールにMFAと短期資格情報を強制し、90日を超えるアクセスキーを停止します。以下はIAMユーザーの古いアクセスキーを無効化するPythonスクリプトです。例外は握りつぶさずログに残し、実行は段階的に行います。実運用では事前に影響アカウントを抽出し合意してから適用します。

import os
import sys
import datetime as dt
import boto3
from botocore.exceptions import ClientError

THRESHOLD_DAYS = int(os.getenv("THRESHOLD_DAYS", "90"))
now = dt.datetime.utcnow()
cutoff = now - dt.timedelta(days=THRESHOLD_DAYS)

iam = boto3.client("iam")

def disable_old_keys():
    try:
        paginator = iam.get_paginator("list_users")
        for page in paginator.paginate():
            for user in page.get("Users", []):
                uname = user["UserName"]
                keys = iam.list_access_keys(UserName=uname)["AccessKeyMetadata"]
                for k in keys:
                    if k["CreateDate"].replace(tzinfo=None) < cutoff and k["Status"] == "Active":
                        print(f"[INFO] Disabling key {k['AccessKeyId']} for {uname}")
                        iam.update_access_key(UserName=uname, AccessKeyId=k["AccessKeyId"], Status="Inactive")
    except ClientError as e:
        print(f"[ERROR] {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    disable_old_keys()
    print("[DONE] Checked and disabled old keys")

短期的にはユーザー型の鍵使用を抑え、ロールの引き受けとフェデレーションに寄せるのが定石です。SaaSやクラウド管理コンソールには必ずMFAを入れ、SSOと条件付きアクセスで外形を固めます。ここまでで、公開の粗と長期鍵の二つの致命的な穴は、最小限の運用負荷で塞げます。

3〜6時間で検知とCIの自動化を有効化する

攻撃はゼロにはなりません。だから検知を当日から動かし、アラートの最短経路を確保します。クラウド側はマネージド検知を使い、コードと依存関係はリポジトリのフックで自動スキャンします。初日のKPIは、主要プロジェクトの80%以上にスキャンを配備し、クラウドの全アカウントに検知サービスを有効化することです。誤検知(ノイズ)は必ず発生するため、初日は重大度の高いものの一次封じ込めを優先し、調整は翌日以降に回します。

クラウド検知基盤の即時有効化

AWSであればGuardDutyとSecurity Hub、Configを順に有効化します。Terraformで一括適用すると、複数環境でも十数分〜数十分で反映できることが多く、ロールバックの再現性も確保できます。以下は最小の構成例です。実際にはマルチアカウント統合や集約アカウント設定、Config用のIAMロール、リージョン展開の差分などの設計が必要になる場合があります。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0"
    }
  }
}

provider "aws" {
  region = var.region
}

variable "region" { default = "ap-northeast-1" }

resource "aws_guardduty_detector" "this" {
  enable = true
}

resource "aws_securityhub_account" "this" {}

resource "aws_securityhub_standards_subscription" "cis" {
  standards_arn = "arn:aws:securityhub:::standards/cis-aws-foundations-benchmark/v/1.4.0"
  depends_on    = [aws_securityhub_account.this]
}

resource "aws_config_configuration_recorder" "recorder" {
  name     = "default"
  role_arn = aws_iam_role.config.arn
}

# 省略: Config用のIAMロール定義

有効化直後から高優先度の検出が上がることがあります。初日は誤検知の是正よりも、重大アラートの一次封じ込めに集中し、誤検知調整は翌日以降に回します。GCPではSecurity Command CenterのStandard以上を有効化し、プロジェクトとフォルダのスコープに展開します。検知の到達時間は、おおむね即時から数分です。⁸⁹ 利用料金はイベント量や有効化範囲に比例するため、費用インパクトは事前に見積もっておきます。

リポジトリのSASTとシークレットスキャンの導入

アプリケーション側の入口には、コードと秘密情報の漏洩を検知する仕組みを当日から入れます。GitHub ActionsでCodeQLとTruffleHogを同居させる最小のワークフローは次の通りです。中規模リポジトリならCodeQLが十数分〜数十分、TruffleHogが数分で完走することが多く、PR時にも走らせれば、MTTDはコミット〜レビューの間隔まで短縮できます。¹⁰¹¹

name: security-scan
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
permissions:
  contents: read
  security-events: write
jobs:
  codeql:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: 'javascript,python,go'
      - uses: github/codeql-action/analyze@v3
  secrets:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: TruffleHog
        uses: trufflesecurity/trufflehog@v3.80.0
        with:
          path: .
          redact: true

インフラコードに対しては、Open Policy Agentで公開や暗号化の逸脱を弾くと効果が高いです。コンテナビルドにSLSAに準拠する署名を組み合わせれば、サプライチェーンのリスクも抑えられます。以下のRegoは、0.0.0.0/0を許すセキュリティグループを拒否する単純な例です。¹²¹⁸

package terraform.security

violation[sg] {
  input.resource_type == "aws_security_group_rule"
  input.change.after.cidr_blocks[_] == "0.0.0.0/0"
}

これをconftestでCIに組み込めば、レビューの前に危険な変更を差し戻せます。初日は最低限のルール一つで十分です。翌日に拡張すればよく、運用の摩擦を増やさないことが継続の鍵になります。

6〜8時間でデータ防御とインシデント運用を固める

最後のブロックは、データの公開遮断と暗号化の強制、そしてインシデント初動の回し方を作ります。S3やGCSのようなストレージは誤設定が直撃するので、明示的に遮断ポリシーを設定し、例外は申請制にします。アラートの通知は人が目にするチャネルに束ね、一次封じ込めの判断を単純化します。¹³¹⁴¹⁵ 余力があればデータ分類(機密/社外秘/公開)のラベルだけ決め、公開可否の判断軸を最低限揃えます。

暗号化強制と公開遮断のバケットポリシー

暗号化未設定の書き込みやパブリックアクセスを拒否するS3バケットポリシーは、数分で適用でき、誤設定の影響範囲を大きく狭めます。以下は典型例です。¹³ 実運用では必ずステージングで検証し、組織IDの条件は要件に応じて調整・削除してください。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnEncryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::YOUR_BUCKET/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": ["aws:kms", "AES256"]
        }
      }
    },
    {
      "Sid": "DenyPublicReadWrite",
      "Effect": "Deny",
      "Principal": "*",
      "Action": ["s3:PutBucketPolicy", "s3:PutObjectAcl", "s3:PutBucketAcl"],
      "Resource": [
        "arn:aws:s3:::YOUR_BUCKET",
        "arn:aws:s3:::YOUR_BUCKET/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:PrincipalOrgID": "o-EXAMPLE" 
        }
      }
    }
  ]
}

GCSの場合はPublic Access Preventionを”enforced”にし、Uniform bucket-level accessを有効化します。KMSの鍵管理は最初は単一の管理ポリシーで始め、用途別の鍵分割は翌日に回します。初日は公開と暗号化の二点だけを確実にします。¹⁴¹⁵

最低限のインシデント運用とテーブルトップ

通知チャネルを一つに決め、当日中に模擬アラートで回します。Slackなら専用チャンネルを用意し、GuardDutyやGitHubのアラートをWebhookで流します。誰が一次対応で、60分以内に何をするのかを一枚のRunbookに書き、関連リポジトリのトップに置きます。簡易テーブルトップは30分程度でも成立し、疑似インシデントを読み上げ、アクセス遮断、鍵無効化、ログ保全、関係者連絡の順に進めます。ここまででMTTDは分〜時間単位、一次封じ込めは60分以内まで現実的に下げられます。⁵

パフォーマンス指標、コスト、ROIの現実

初日の成果を数字で見ます。リスク可視化のスクリプトは数千リソース規模でも十数分〜数十分で完走するケースが多く、パレート則(上位の露出が大半のリスクを占める)から、当日中に重大露出の大部分を是正できることが期待できます。CodeQLは中規模モノレポで十数分前後、TruffleHogは数分で、開発の待ち時間として許容範囲に収まりやすいです。GuardDutyやSecurity Hubは有効化直後からイベントを流し、通知のレイテンシは秒〜分オーダーです。⁸ 費用面では、マネージド検知はアカウントとイベント量に比例する従量課金で、初日の導入コストの多くは人的コストです。中堅規模で2名×8時間程度の稼働を目安に見積もると現実的でしょう(体制や承認フローで変動)。IBMの報告にあるように、対応体制と演習がある組織は平均1.49百万ドルのコストを削減しており、³ 初日の小さな積み上げが翌月の大きな差につながる可能性は、公開データからも十分に示唆されます。

運用に載せるための現場の工夫

1日で作る体制の最大の落とし穴は、翌日から回らない設計にしてしまうことです。だから責務の分割と例外の窓口をあらかじめ用意します。公開遮断や暗号化が開発に与える影響は、例外申請のテンプレートを一枚用意すれば摩擦を減らせます。CIの失敗で開発が止まる時は、ブロックではなく警告から始め、違反の累積でブロックに昇格させる段階導入を取ります。検知のノイズは必ず出るので、最初の1週間は毎日15分のノイズシェーピングに投資します。少しの投資で、MTTDとMTTR(平均復旧時間)の改善が継続的に進み、管理職への説明も数字で通しやすくなります。現場で効く工夫は、難しいことではありません。たとえば、通知のサマリを毎朝1回だけチャンネルに投稿し、前日の逸脱是正率と未解決件数を自動で貼るだけでも、関係者の意識は明確に変わります。

ミニケース:午後だけでどこまで届くか(想定例)

B2CのWebプロダクト(中規模、単一クラウド)を想定すると、午後の4時間で、リポジトリのCodeQLとシークレットスキャンを主要数本に導入し、S3の公開遮断と暗号化強制を適用し、GuardDutyを立ち上げる、という構成は十分に現実的です。想定される成果として、長期鍵の露出がその日のうちに検知され、短時間で停止と再発防止の修正に至るケースは珍しくありません。開発の遅延は1PRあたり十数分〜数十分のスキャン待ちに収まりやすく、数週間のノイズチューニングでチームのベロシティは安定しやすいです。数字で見ると、公開リソースは初日でゼロを目指し、逸脱是正率は8割前後、翌週までに9割台に到達、というのが妥当なレンジです。これは最小の仕込みで、攻撃面の露出と検知遅延を着実に削るための一例です。

よくある質問の先回り

初日の適用が怖いという声には、スコープの限定と即時ロールバックの用意で応えます。TerraformやIaCでの変更は常にPlanを共有し、適用と同時にロールバックプランを文字で残します。パフォーマンスの懸念には、スキャンのタイムスライスとキャッシュを説明し、長い解析が必要な言語や巨大リポジトリは夜間にフルスキャン、日中は差分スキャンにします。SaaSや外部ベンダーとの整合性は、当日は通知連携だけ先に繋ぎ、細かい権限制御は翌日に回します。全ては、初日で検知が回る状態を作るための割り切りです。規制や監査(ISMS、SOC、CIS Benchmarks等)との整合は、初期値を当てた後にギャップ分析で追随させるのが現実的です。

簡易Runbookの雛形(抜粋)

Runbookは一枚で十分です。アラートを受けた一次対応者が60分以内にアクセス遮断、鍵無効化、ログ保全、影響範囲の仮説作成まで進めること、次の当番に引き継ぐときの記録形式、コミュニケーションの窓口と報告の閾値。この四点が明確なら、初動の品質は安定します。深夜と休日の当番表は、翌日までに決めればよく、初日は営業時間内のカバーだけでも大きな前進です。⁵⁶¹⁶¹⁷

まとめ:今日、最初の一手を打つ

完璧主義はセキュリティの敵です。8時間でできることに集中すれば、攻撃の入り口は狭まり、検知は当日から動き、封じ込めは現実的な時間に収まります。可視化と最小権限で露出を削り、クラウドとリポジトリに検知を入れ、データの公開と暗号化を制御して、最後に初動を回す。たったこれだけの骨格でも、MTTDは分〜時間、一次封じ込めは60分以内という目標範囲で、効果を期間明示できます。あなたの組織で、今日の午後を空けられるでしょうか。もし可能なら、この順番で着手し、最初のアラートを自分の目で確かめてみてください。明日には、違う景色が見えるはずです。

参考文献

  1. IBM Security. 2023 Cost of a Data Breach Report (Press release summary). https://newsroom.ibm.com/2023-07-24-IBM-Report-Half-of-Breached-Organizations-Unwilling-to-Increase-Security-Spend-Despite-Soaring-Breach-Costs
  2. Verizon. 2023 Data Breach Investigations Report (DBIR) — Summary. https://www.verizon.com/about/news/2023-data-breach-investigations-report
  3. IBM Community. Cost of a Data Breach 2023 Highlights — IR readiness saves $1.49M on average. https://community.ibm.com/community/user/blogs/sarah-dudley/2023/07/25/costofadatabreach2023
  4. Dark Reading. With Data Breach Costs, Time Is Money. https://www.darkreading.com/cyberattacks-data-breaches/with-data-breach-costs-time-is-money
  5. NIST SP 800-61 Rev. 2: Computer Security Incident Handling Guide. https://csrc.nist.gov/publications/detail/sp/800-61/rev-2/final
  6. NIST SP 800-53 Rev. 5: Security and Privacy Controls for Information Systems and Organizations. https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final
  7. NIST Glossary: Least Privilege (最小権限). https://csrc.nist.gov/glossary/term/least_privilege
  8. AWS GuardDuty — What is Amazon GuardDuty? https://docs.aws.amazon.com/guardduty/latest/ug/what-is-guardduty.html
  9. Google Cloud Security Command Center — Overview. https://cloud.google.com/security-command-center/docs/concepts-overview
  10. GitHub Docs — About CodeQL. https://docs.github.com/en/code-security/code-analysis/codeql/about-codeql
  11. TruffleHog — Find leaked credentials. https://github.com/trufflesecurity/trufflehog
  12. Open Policy Agent (OPA) — Policy-based control for cloud native environments. https://www.openpolicyagent.org/
  13. AWS S3 — Block Public Access. https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html
  14. Google Cloud Storage — Public Access Prevention. https://cloud.google.com/storage/docs/public-access-prevention
  15. Google Cloud Storage — Uniform bucket-level access. https://cloud.google.com/storage/docs/uniform-bucket-level-access
  16. CIS Controls v8. https://www.cisecurity.org/controls/v8
  17. OWASP Application Security Verification Standard (ASVS). https://owasp.org/www-project-application-security-verification-standard/
  18. SLSA Framework. https://slsa.dev/