SSM Patch Managerでカスタムパッチベースラインを作成(Linux)

LinuxインスタンスにSSM Patch Managerを実行する構成

SSM Patch Managerでカスタムパッチベースラインを作成してパッチ配信する構成

System Manager(SSM) Patch Managerは、EC2インスタンスへのパッチ適用の自動化する機能です。

今回はAmazon Linux 2インスタンスを対象とします。デフォルトのAWS-AmazonLinux2DefaultPatchBaselineに加え、独自のパッチベースライン(カスタムパッチベースライン)を作成し、両者を実行することで、Patch Managerの挙動を確認します。

Windowsインスタンスに対するSSM Patch Managerの実行については、以下のページをご確認ください。

あわせて読みたい
SSM Patch Managerでカスタムパッチベースラインを作成(Windows) 【SSM Patch Managerでカスタムパッチベースラインを作成してWindowsインスタンスにパッチ配信する構成】 System Manager(SSM) Patch Managerは、EC2インスタンスへのパ...

SSM Patch Manager関係の用語整理

最初にSSMやPatch Managerに関する用語を簡単に整理します。取り上げる用語は3つです。

マネージドインスタンス

1つ目はマネージドインスタンスです。マネージドインスタンスはSSMで操作可能な状態のEC2インスタンスを意味します。

マネージドインスタンスは、Systems Manager で使用するために設定された Amazon EC2 インスタンスです。マネージドインスタンスでは、Run Command、Patch Manager、Session Manager などの、Systems Manager サービスを使用できます。

Systems Manager コンソールの [マネージドインスタンス] に EC2 インスタンスが表示されないのはなぜですか?

パッチベースライン

2つ目はパッチベースラインです。パッチベースラインはPatch Managerからパッチを配信するためのルールに相当するリソースです。

パッチベースラインは、インスタンスへのインストールを承認するパッチを定義します。パッチの承認または拒否は個別に指定できます。また、自動承認ルールを作成して特定のタイプの更新 (例: 重要な更新) を自動承認するよう指定できます。

事前定義されたパッチベースラインおよびカスタムパッチベースラインについて

パッチベースラインを作成する際は、パッチ配信の対象OSや、承認するパッチの条件(分類や重要度)を指定します。

パッチグループ

3つ目はパッチグループです。パッチグループは、パッチベースラインに従って、パッチを配信する対象をまとめる枠組みです。

パッチグループを使用して、AWS Systems Manager の一機能であるパッチマネージャーでインスタンスを特定のパッチベースラインに関連付けることができます。パッチグループは、正しい一連のインスタンスに、関連するパッチベースラインのルールに基づいて、適切なパッチをデプロイしていることを確認するのに役立ちます。

パッチグループについて

同様のルールでパッチを配信したいインスタンスが複数ある場合、同じパッチグループに所属させることで、統一的にパッチを配信することができます。

構築する環境

Diagram of SSM Patch Manager on Linux instance.

プライベートサブネット内に、EC2インスタンスを2つ配置します。一方はデフォルトのAWS-AmazonLinux2DefaultPatchBaselineを適用し、もう一方はカスタムパッチベースラインを適用します。
S3バケットにPatch Managerの実行ログを保存します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートファイルを設置します。

https://github.com/awstut-an-r/awstut-soa/tree/main/04/001

テンプレートファイルのポイント解説

今回のアーキテクチャを構成するための、各テンプレートファイルのポイントを取り上げます。

Patch Managerログ格納用バケットを用意する

Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref Prefix
      AccessControl: Private
Code language: YAML (yaml)

S3バケットを作成します。Patch Manager実行時のログを格納するためのバケットです。特別な設定は不要です。

VPCエンドポイントでプライベートサブネット内のインスタンスでもPatch Managerが実行できるようにする

プライベートサブネットのインスタンスに対して、Patch Managerを実行するためには、大別すると2種類のVPCエンドポイントが必要となります。

SSM用VPCエンドポイント

1つ目はSSM用のVPCエンドポイントです。

Resources:
  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EC2MessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ec2messages"
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC
Code language: YAML (yaml)

SSMのVPCエンドポイントを作成する場合、少なくとも2つのインターフェースエンドポイントが必要とされています。

com.amazonaws.region.ssm: Systems Manager サービスのエンドポイント。

com.amazonaws.region.ec2messages: Systems Manager は、このエンドポイントを使用して、SSM Agent から Systems Manager サービスへの呼び出しを行います。

ステップ 6: (オプション) Virtual Private Cloud エンドポイントの作成

上記に従い、2つのエンドポイントリソースを作成します。

S3用VPCエンドポイント

2つ目はS3用エンドポイントです。

Resources:
  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal: "*"
            Action: "*"
            Resource: "*"
      RouteTableIds:
        - !Ref PrivateRouteTable
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
      VpcId: !Ref VPC
Code language: YAML (yaml)

こちらもSSMでインスタンスを操作するために必須のエンドポイントとされています。

com.amazonaws.region.s3: Systems Manager は、このエンドポイントを使用して、SSM Agent の更新、パッチ適用オペレーションの実行、および S3 バケットに格納する出力ログのアップロード、バケットに格納するスクリプトまたはその他のファイルの取得などのタスクを行います。

ステップ 6: (オプション) Virtual Private Cloud エンドポイントの作成

Patch Managerを実行する上で、具体的にアクセスする必要があるバケットについては、インスタンスに適用するIAMロールの項目にてご説明します。

インスタンスが所属するパッチグループをタグで指定する

まずEC2インスタンス本体を定義します。ポイントはインスタンスに付与するタグ設定です。

Resources:
  Instance1:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PrivateSubnet
          GroupSet:
            - !Ref InstanceSecurityGroup

  Instance2:
    Type: AWS::EC2::Instance
    Properties:
      ...
      Tags:
        - Key: Patch Group
          Value: !Sub "${Prefix}-patch-group"
Code language: YAML (yaml)

2台のインスタンスを定義します。設定はタグ設定を除き、全く同じように設定します。Instance2のみタグを設定します。
EC2インスタンスが所属するパッチグループはタグで指定します。

パッチグループでは、タグキーとして Patch Group を使用する必要があります。任意のタグ値を指定できますが、タグキーは Patch Group とする必要があります。

パッチグループの作成 (コンソール)

上記に従い、Instance2のTagsプロパティ内のKeyプロパティに「Patch Group」、Valueプロパティにパッチグループ名を指定します。今回は組み込み関数Fn::Subを使用して、パッチグループ「soa-04-001-patch-group」に所属するように設定します。

なおEC2インスタンスのベースとなるAMIは、最新版ではなく、敢えて少し古いものを指定しました。これは最新版のAMIを選択した場合、Patch Managerで適用する予定のパッチが、既に適用済みのインスタンスが作成されてしまう可能性があるためです。

SSMマネージドインスタンスの条件を満たす権限をIAMロールで用意する

続いてEC2インスタンスに割り当てるIAMロールを定義します。

Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      Policies:
        - PolicyName: PutPatchBaselineLog
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - !Sub "arn:aws:s3:::aws-windows-downloads-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::amazon-ssm-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::amazon-ssm-packages-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::${AWS::Region}-birdwatcher-prod/*"
                  - !Sub "arn:aws:s3:::aws-ssm-document-attachments-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::patch-baseline-snapshot-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::aws-ssm-${AWS::Region}/*"
                  - !Sub "arn:aws:s3:::aws-patchmanager-macos-${AWS::Region}/*"
              - Effect: Allow
                Action:
                  - s3:PutObject
                Resource:
                  - !Sub "${S3BucketArn}/*"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Code language: YAML (yaml)

マネージドインスタンスとして扱われるためには、以下の条件を満たす必要があります。

インスタンスをマネージドインスタンスにするには、次の前提条件を満たす必要があります。

AWS Systems Manager エージェント(SSM エージェント)がインストールされ実行中である。

SSM エージェントを使用して Systems Manager エンドポイントに接続されている。

適切な AWS Identity and Access Management (IAM) ロールがアタッチされている。

インスタンスメタデータサービスに接続している。

Systems Manager コンソールの [マネージドインスタンス] に EC2 インスタンスが表示されないのはなぜですか?

特に上3つの条件がポイントです。
1つ目のSSMエージェントですが、Amazon Linux 2ベースのEC2インスタンスでは、デフォルトでSSMエージェントがインストールされ、動作しています。そのため既に条件を満たしています。
2つ目のエンドポイントですが、先述のVPCエンドポイントを設置しますので、こちらも条件を満たしています。
3つ目のIAMロールですが、EC2インスタンスにアタッチすべきIAMロールについて、SSMに関して、以下のように言及されています。

Systems Manager エンドポイントへの API コールを行うには、AmazonssmmanagedInstanceCore アクセス許可ポリシーを、インスタンスにアタッチされた IAM ロールに追加します。

Systems Manager コンソールの [マネージドインスタンス] に EC2 インスタンスが表示されないのはなぜですか?

またSSMを実行する上で、特定のS3バケットにアクセスする必要があるともされています。

さまざまな Systems Manager のオペレーションを実行する過程で、AWS Systems Manager Agent (SSM Agent) は多数の Amazon Simple Storage Service (Amazon S3) バケットにアクセスします。

SSM Agent と AWS マネージド S3 バケットとの通信

以上より、条件を満たすようなIAMロールを作成します。

ManagedPolicyArnsプロパティでAWS管理ポリシーを指定できます。先ほど確認したように、「AmazonSSMManagedInstanceCore」を指定します。

次にPoliciesプロパティでインラインポリシーを定義します。
1つ目のポリシーは、SSMを実行する上でアクセスするS3バケットに対して、オブジェクトを取得することを許可します。
2つ目のポリシーは、Patch Managerの実行ログを保存するバケットに対して、オブジェクトを保存することを許可します。

カスタムベースライン作成には、OS・パッチグループ・承認ルールがポイント

カスタムベースラインを確認します。

Resources:
  MyPatchBaseline:
    Type: AWS::SSM::PatchBaseline
    Properties:
      ApprovalRules:
        PatchRules:
          - ApproveAfterDays: 7
            ComplianceLevel: UNSPECIFIED
            EnableNonSecurity: false
            PatchFilterGroup:
              PatchFilters:
                - Key: CLASSIFICATION
                  Values:
                    - Security
                - Key: SEVERITY
                  Values:
                    - Critical
                    #- Important
          #- ApproveAfterDays: 7
          #  ComplianceLevel: UNSPECIFIED
          #  EnableNonSecurity: false
          #  PatchFilterGroup:
          #    PatchFilters:
          #      - Key: CLASSIFICATION
          #        Values:
          #          - Bugfix
      Description: Test Patch Baseline.
      Name: !Sub ${Prefix}-MyPatchBaseline
      OperatingSystem: AMAZON_LINUX_2
      PatchGroups:
        - !Sub ${Prefix}-patch-group
Code language: YAML (yaml)

カスタムベースラインを作成するためには、様々なパラメータがありますが、重要なパラメータは3つです。
1つ目は対象OSです。作成するパッチベースラインでパッチ配信の対象とするOSを指定します。OperatingSystemプロパティでOSを設定します。今回はAmazon Linux 2で動作するEC2インスタンスを対象としますので、「AMAZON_LINUX_2」を指定します。
2つ目はパッチグループです。パッチベースラインでパッチ配信の対象とするマネージドインスタンスを、パッチグループという形で指定します。PatchGroupsプロパティでパッチグループを設定します。今回はIsntance2に設定したタグと同様の値を指定します。
3つ目は承認ルールです。配信するパッチの条件や自動承認までの猶予時間等について設定します。今回はデフォルトのパッチベースラインAWS-AmazonLinux2DefaultPatchBaselineを参考に、一部のパラメータを変更して、カスタムパッチベースラインを作成します。

以下の画像がAWS-AmazonLinux2DefaultPatchBaselineの詳細です。

Outline of AWS-AmazonLinux2DefaultPatchBaseline

今回は分類がSecurityで、かつ重要度がCriticalのもののみを対象するカスタムパッチベースラインを作成します。
承認ルールはApprovalRulesプロパティで定義します。同プロパティ内のPatchRulesプロパティにて、1ルール単位で具体的な内容を定義します。
ApproveAfterDaysプロパティで本ルールに該当するパッチが自動承認するまでの猶予日数を指定できます。今回は「7(日)」を指定します。
ComplianceLevelプロパティで、本ルールに該当するパッチに割り当てるレベルを指定することができます。今回は「UNSPECIFIED」で「未指定」としました。
EnableNonSecurityプロパティで、セキュリティ以外のパッチも配信するかどうかを指定できます。今回は「false」として’、配信しないこととします。
PatchFilterGroupプロパティで分類および重要度に関する設定を行います。同プロパティ内のPatchFilterGroupプロパティにて、それぞれ指定します。分類を定義する場合は、Keyプロパティに「CLASSIFICATION」を指定し、重要度を指定する場合は「SEVERITY」を指定します。今回は分類は「Security」、重要度は「Critical」をValuesプロパティに指定します。

なおコメントアウトを外すと、AWS-AmazonLinux2DefaultPatchBaselineと同様の設定となります。

パッチベースラインの実行

2つのインスタンスに対して、SSMドキュメントとの関連(Association)を作成して、パッチベースラインを実行します。

Resources:
  AWSRunPatchBaselineAssociation:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-AWSRunPatchBaselineAssociation"
      Name: AWS-RunPatchBaseline
      OutputLocation:
        S3Location:
          OutputS3BucketName: !Ref S3BucketName
          OutputS3KeyPrefix: !Sub "AWSRunPatchBaselineAssociation"
      Parameters:
        Operation:
          - Install
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance1
            - !Ref Instance2
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

パッチベースラインを実行するためには、SSMドキュメントAWS-RunPatchBaselineとの関連を作成します。Nameプロパティで同ドキュメントの名前を指定します。
OutputLocationプロパティでPatch Manager実行時のログを保存するバケットを指定します。
ParamatersでAWS-RunPatchBaselineを実行するためのパラメータを指定します。必須のパラメータであるOperationプロパティに、Installを指定します。詳細はAWS-RunPatchBaseline SSM ドキュメントについてをご確認ください。
TargetsプロパティでSSMドキュメントを関連付ける対象を指定します。今回は先述の2台のインスタンスのIDを指定します。

今回の構成でAWS-RunPatchBaseline実行時の挙動を整理します。

  • Instance1:タグ(パッチグループ)設定なし -> デフォルトのAWS-AmazonLinux2DefaultPatchBaselineが実行される
  • Instance2:タグ(パッチグループ)設定あり -> カスタムパッチグループ(MyPatchBaseline)が実行される

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • ログ保存用バケットの名前:soa-04-001
  • Instance1のID:i-07d21ade1467247e6
  • Instance2のID:i-09327871f0830e91e
  • カスタムパッチベースライン名:soa-04-001-MyPatchBaseline
  • カスタムパッチベースラインのID:pb-0b520c1268ad72b19
  • カスタムパッチベースライン用のパッチグループ:soa-04-001-patch-group

作成されたカスタムパッチベースラインを確認します。

Details of the Custom Patch Baseline I created.

Amazon Linux 2を対象として、セキュリティがクリティカルなパッチのみを承認するルールが作成されています。Patch groupsの項目をみると、本ベースラインの適用対象が「soa-04-001-patch-group」ということもわかります。

次にインスタンスに付与されたタグを確認します。

Instance1 is not configured with a tag for patch groups.
Instance2 is configured with a tag for the patch group.

Instance2の方にだけ、Patch Groupのタグがあります。このタグの値が先ほど確認したカスタムパッチベースラインのパッチグループと同名ということがわかります。これでInstance2はパッチグループに所属していることになります。

Patch Manager実行結果を確認する

準備が整いましたので、Patch Managerの実行結果を確認します。SSM Run Commandのページから確認することができます。

Results of running SSM Patch Manager.

2台のインスタンスに対して、Patch Managerの実行が成功していることがわかります。

次に各インスタンスの実行結果を確認します。まずInstance1を確認します。

Result of running AWS-AmazonLinux2DefaultPatchBaseline.

デフォルトのAWS-AmazonLinux2DefaultPatchBaselineが実行され、65のパッチが適用されたことがわかります。

次にInstance2を確認します。

Result of running Custom Patch Baseline.

カスタムパッチベースライン(soa-04-001-MyPatchBaseline)が実行され、9のパッチが適用されたことがわかります。

最後に実行ログを確認します。ログは指定したバケットに、インスタンスIDごとに設置されます。

The execution log of SSM Patch Manager is saved in the S3 bucket.

上の画像はInstance1のログですが、実行ログはstdout.txtとして設置されます。Instance1側の実行ログの中身を確認します。

/usr/bin/python3
/usr/bin/python2.7
/usr/bin/python2
/usr/bin/python
/usr/bin/yum
Using Yum version: 3.4.3
Using python binary: 'python2.7'
Using Python Version: Python 2.7.18

...

01/21/2022 23:26:08 root [INFO]: [{'OperationStartTime': '2022-01-21T23:25:15Z', 'BaselineId': u'pb-00fda5699d1ae3942', 'InstalledPendingRebootCount': '0', 'FailedCount': '0', 'MissingCount': '0', 'NotApplicableCount': '825', 'RebootOption': u'RebootIfNeeded', 'OperationEndTime': '2022-01-21T23:26:08Z', 'SecurityNonCompliantCount': '0', 'PatchGroup': u'', 'ExecutionId': '4fbe03b6-0e37-4cbf-995a-0f13a99f952a', 'InstalledRejectedCount': '0', 'OtherNonCompliantCount': '0', 'InstalledOtherCount': '377', 'CriticalNonCompliantCount': '0', 'SnapshotId': u'5839c3cf-0024-4a17-bdb2-302c3606223a', 'InstalledCount': '65', 'OperationType': u'Install'}]

...
Code language: plaintext (plaintext)

パッチ適用の流れを確認することができます。

まとめ

SSM Patch Managerを使用し、EC2インスタンス(Linux)にパッチ配信できることを確認しました。

デフォルトのAWS-AmazonLinux2DefaultPatchBaselineに加え、カスタムパッチベースラインを作成して実行することで、パッチ適用結果の確認方法やログ出力状況を確認しました。