EC2 Systems Managerを使ってEC2のパッチを自動で適用、集計する

目的

Spectre, Meltdownと脆弱性の話題が頻繁に聞かれるので、EC2のセキュリティパッチを自動的、継続的に適用していきましょう。 AWSが提供するSystems Managerを使って、パッチの適用状況を把握したり、適用したりするのを自動的に行います。

注意

下記の内容は作成から日が経っているので、このページではSystems Managerという単語だけ覚えて、具体的な設定方法についてはAWS公式サイト等を参照することをおすすめします。 aws.amazon.com

またGCPVMのGCEでも類似のサービスが利用可能です。 cloud.google.com

全体像

f:id:translucens:20200326014912p:plain
Systems Manager全体像

用語の解説

  • SSMagent - AWSが提供するエージェントソフトウェア。これをインストールしたEC2インスタンスは、EC2 Systems Managerから操作が行えるようになる
  • Systems Managerが持つ機能
    • Maintenance Windows - 定期的にコマンドを実行する
    • Patch Manager - パッチの自動適用や適用状況を集計する
    • Document - Systems Managerでいう「ドキュメント」とは、自動実行される内容(≓スクリプト)を表す
  • S3 - 自動実行された結果のログを保管

初期はEC2ダッシュボードの一部だったのですが、今は独立した画面を持つようになったので、AWSコンソールを Systems Manager で検索してください。

なお、Systems ManagerはEC2ダッシュボードのメニューのAuto Scalingの下、つまり一番下にあります。

f:id:translucens:20200326014938p:plain
初期のSystems ManagerはEC2のメニューに存在した

事前準備(管理者)

Patch Baselineの作成

Patch Baselineとは、どのパッチを適用対象にするのかという基準のことです。AWS側でもデフォルトの基準が用意されていますが、必要に応じてカスタムの基準を作ることもできます。メニューの Patch Baselines を選び、Create Patch Baselineボタンから作成することができます。

f:id:translucens:20200326015035p:plain
Patch Baselineの作成

Windows Server, Amazon Linux, RedHat Enterprise Linuxではパッチが公開されてからの日数を条件に入れることができますが、Ubuntuでは設定できないので注意が必要です。他にパッチの種類や重要度を選ぶことができます。また、特定のパッチのみ適用対象にしたり、反対に除外したりすることもできます。

今回は開発環境に使うルールなので、AWSデフォルトよりも早くパッチを適用することにしました。

Patch Groupの設定

Patch Groupとは、EC2をグループ化してパッチを適用する仕組みです。 Patch GroupというキーでEC2側にタグを付けます。

例: Production-Web-AmazonLinux

次に、Patch BaselineにPatch Groupを登録します。 登録しないと、デフォルトのPatch Baseline(初期設定ではAWS提供のルール)が使用されます。

作成したPatch Baselineを右クリックするとModify Patch Groupsという項目があります。その中にAdd new patch groupというボタンがあるので、ここからPatch Groupタグに設定した値を登録します。

Maintenance Windowsの設定

Maintenance Windowsは時間帯または間隔を指定し、特定の作業を実施する機能です。今回はパッチの適用作業を行う時間帯を設定します。

まずはCreate maintenance windowボタンからMaintenance Windowを作成します。

f:id:translucens:20200326015128p:plain
Maintenance Windowの作成

毎日5:00から2時間の間をWindowとする例です。

次に、対象とするインスタンスを登録します。登録したWindowを右クリックし、Register targetsを選びます。インスタンスを直接指定する方法と、インスタンスのタグを指定する方法が選べますが、インスタンスの増減を考えるとタグがよいでしょう。タグの場合、最大5種類のタグをAND条件で指定することができます。

次に、Windowに自動実行するタスクを登録します。登録したWindowを右クリックし、Register run command taskを選びます。AWS-RunPatchBaselineというドキュメントが提供されているので、これを実行するようにします。

Targetは先に指定した対象のインスタンス(かそのグループ)を指定します。

RoleはWindowに付与するロールですが、AmazonSSMMaintenanceWindowRoleというポリシーが提供されているのでこれを含むロールを付与すればよいです。

OperationScanを選ぶとパッチの適用状況の取得、Installを選ぶとインストールと必要に応じて再起動まで実施されます。

また、SSM側ではコマンドの実行ログは最初の2500byte分のみ保存されるので、一番下にあるAdvancedセクションのWrite to S3にチェックを入れ、S3へログを保存することを推奨します。保存しないと、パッケージマネージャの不整合等でエラーが発生したとき、原因を調べることが難しくなります。 またエラー時にSNSで通知されるようにすることもできます。

集計結果の確認

Mainteinance Window終了後、メニューからPatch Complianceを開きます。Report Typeを選び、インスタンスIDかPatch Groupを選ぶと、指定されたインスタンスのパッチ適用状況が表示されます。

f:id:translucens:20200326015149p:plain
パッチ適用状況の確認

緑色のup to dateは指定されたパッチが当たっているインスタンスの数、オレンジ色のmissing updatesはScanした結果何らかのパッチが適用されていないインスタンス、赤のerror stateは自動実行中にエラーが発生したインスタンスです。

Maintenance Windowよりも前にテスト実行したい場合、Run CommandからAWS-RunPatchBaselineを手動で起動することもできます。

EC2利用者の設定

SSMエージェントのインストール

OSごとの手順がAWS公式ドキュメントに載っているので、その手順を参照してください。 https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-install-ssm-agent.html Amazon Linux 2017.09以降、Windows ServerのAMIにはデフォルトで入っているので不要です。

SSM用IAMロールの割り当て

2019/06/12追記: AmazonEC2RoleforSSM の使用は推奨されなくなりました。AWS公式のリファレンスを参照して必要なポリシー、ロールを作ってください。

既にIAMロールがインスタンスに割り当てられている場合、AWS提供の AmazonEC2RoleforSSM というポリシーを追加してください。IAMロールを付与していないインスタンスの場合、上記ポリシーを持ったIAMロールを付与します。

タグの付与

Patch Groupというタグを付与します。値は管理者の指示にしたがってください。

注意点

  • Run Commandで指定したコマンドはroot権限で実行されます。AWS-RunShellScriptにて任意のコマンドが実行可能であるため、不要なユーザには権限を付与しない、AWSコンソールのパスワードを強固にしたり、二要素認証を有効にしたり等必要なセキュリティ対策をしてください。
  • 似たような名称のAWS-ApplyPatchBaselineがありますが、これはWindows専用なのでLinuxには使えません。
  • rootでAWS CLIの認証情報が設定されていてSSMの権限がないと権限不足で止まってしまいます(そもそもアクセスキーをEC2に保存することは推奨されていません。EC2にはIAM Roleを設定するようにしましょう)。
  • セキュリティを重視するのであればhttps://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-setting-up-vpc.htmlを利用してSystems Managerと接続する方がよいです

SSMagent未インストールのEC2インスタンスの抽出

下記のコマンドを実行すると、実行中だがSSMagentがインストールされていないEC2のインスタンスIDを出力することができます。 ※要AWS CLI、jq

aws ec2 describe-instances --filter Name=instance-state-name,Values=running --query Reservations[*].Instances[*].InstanceId[] | jq --raw-output .[] | sort > running-ec2.txt
aws ssm describe-instance-information --query InstanceInformationList[*].InstanceId | jq --raw-output .[] | sort > managed-instances.txt
diff --changed-group-format='%<' --unchanged-group-format='' running-ec2.txt managed-instances.txt | tee not-managed-ec2.txt

さらに下記のスクリプトを使ってSSMagentを自動でインストールすることができます(Amazon Linux用)。

#! /bin/bash

if test $# -ne 2 ; then
    echo usage: ./install.sh instanceIdList.txt sshkey
    exit
fi

for instanceid in `cat $1`; do
    publicIp=$(aws ec2 describe-instances --instance-ids $instanceid | jq ".Reservations[] | .Instances[0].PublicIpAddress" -r)
    echo $instanceid $publicIp
    ssh -t -i $2 ec2-user@$publicIp -o StrictHostKeyChecking=no "cd /tmp;sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm"
    if test $? -ne 0 ; then
        echo $instanceid >> error.txt
        continue
    fi
    aws ec2 associate-iam-instance-profile --instance-id $instanceid --iam-instance-profile Name=EC2-SimpleSystemsManager-enabled
    if test $? -ne 0 ; then
        echo $instanceid >> error.txt
        continue
    fi
    aws ec2 create-tags --resources $instanceid --tags "Key=\"Patch Group\",Value=amazon-security-patch"
done