AWSSupport-StartEC2RescueWorkflow オートメーションを使う際の注意点

AWSSupport-StartEC2RescueWorkflow オートメーションを使う際の注意点

Clock Icon2024.07.22

しばたです。

先週末からCrowdStrike社のセキュリティ対策製品であるCrowdStrike Falconの不具合を発端とする障害が世界中で発生しており、AWSにおいても当該製品を扱うWindows環境が影響を受けています。

AWSからはAWS Health Dashboardにおいて状況と対応策に関するアナウンスが行われています。

important-point-to-use-awssupport-startec2rescueworkflow-01

対応策に関して7/19~7/20の間に何度か更新され、7/20日の早朝ごろにre:Postの以下の投稿に別記される様になりました。

AWSSupport-StartEC2RescueWorkflow を使った復旧について

このre:Postの投稿では、影響を受けたEC2インスタンスに対して

    1. CrowdStrike社側の更新を受け再起動で復旧したインスタンスに対しては追加の対処不要
    1. 再起動で復旧しないインスタンスに関してはEC2Rescueを使い当該インスタンスで問題となっているファイルを削除する

方法を提示しており、2.のEC2Rescueの使用に関して

  • 2-1. SSMオートメーションAWSSupport-StartEC2RescueWorkflowを使ったEC2Rescueの自動実行
  • 2-2. 手作業で復旧用インスタンスを作成しEC2Rescueを手動実行

の2パターン記載されています。

AWSSupport-StartEC2RescueWorkflowは2-2.にある一連の手作業を自動化するものであり、障害からの復旧において人間によるミスを防ぐ点もあるので可能であればこちらを使う方が良いでしょう。

ただ、このAWSSupport-StartEC2RescueWorkflowは初見ではちょっと扱いにくいため本記事で注意点を解説していきます。

免責事項

AWSSupport-StartEC2RescueWorkflow オートメーションを使う際の注意点

AWSSupport-StartEC2RescueWorkflowオートメーションを使う際の注意点を5点紹介します。

1. インスタンスの種類

ドキュメントに

Important
Amazon EC2 instances created from Marketplace Amazon Machine Images (AMIs) are not supported by this automation.

との記述がありAWS Marketplaceからサブスクライブしているインスタンスに対してはこのオートメーションは使えません。
実行時チェックにより処理が中断されます。

恐らくこれは商用製品が導入されている場合のコンテンツ保護を意図したものだと予想します。

2. オートメーション実行時の権限

このオートメーションは、処理の内容が

  • 処理用の一時EC2インスタンスを作成する
    • このインスタンスはCloudFormationで作られる
    • 併せて専用のIAMロールを作成しアタッチする
  • 復旧対象のEC2を停止し、EBSボリュームをアタッチしなおした上マウントする
    • EBSボリュームが暗号化されている場合はKMSに対する権限も必要

というものであるため実行時にかなり多くの権限を必要とします。

厳密にはAmazonSSMAutomationRoleマネージドポリシーの内容に加え、次の権限が必要となります。

クリックして展開
AWSドキュメントより引用した追加で必要な権限(これだけでは不十分)
{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Action": [
            "lambda:InvokeFunction",
            "lambda:DeleteFunction",
            "lambda:GetFunction"
         ],
         "Resource": "arn:aws:lambda:*:<An-AWS-Account-ID>:function:AWSSupport-EC2Rescue-*",
         "Effect": "Allow"
      },
      {
         "Action": [
            "s3:GetObject",
            "s3:GetObjectVersion"
         ],
         "Resource": [
            "arn:aws:s3:::awssupport-ssm.*/*.template",
            "arn:aws:s3:::awssupport-ssm.*/*.zip"
         ],
         "Effect": "Allow"
      },
      {
         "Action": [
            "iam:CreateRole",
            "iam:CreateInstanceProfile",
            "iam:GetRole",
            "iam:GetInstanceProfile",
            "iam:PutRolePolicy",
            "iam:DetachRolePolicy",
            "iam:AttachRolePolicy",
            "iam:PassRole",
            "iam:AddRoleToInstanceProfile",
            "iam:RemoveRoleFromInstanceProfile",
            "iam:DeleteRole",
            "iam:DeleteRolePolicy",
            "iam:DeleteInstanceProfile"
         ],
         "Resource": [
            "arn:aws:iam::<An-AWS-Account-ID>:role/AWSSupport-EC2Rescue-*",
            "arn:aws:iam::<An-AWS-Account-ID>:instance-profile/AWSSupport-EC2Rescue-*"
         ],
         "Effect": "Allow"
      },
      {
         "Action": [
            "lambda:CreateFunction",
            "ec2:CreateVpc",
            "ec2:ModifyVpcAttribute",
            "ec2:DeleteVpc",
            "ec2:CreateInternetGateway",
            "ec2:AttachInternetGateway",
            "ec2:DetachInternetGateway",
            "ec2:DeleteInternetGateway",
            "ec2:CreateSubnet",
            "ec2:DeleteSubnet",
            "ec2:CreateRoute",
            "ec2:DeleteRoute",
            "ec2:CreateRouteTable",
            "ec2:AssociateRouteTable",
            "ec2:DisassociateRouteTable",
            "ec2:DeleteRouteTable",
            "ec2:CreateVpcEndpoint",
            "ec2:DeleteVpcEndpoints",
            "ec2:ModifyVpcEndpoint",
            "ec2:Describe*"
         ],
         "Resource": "*",
         "Effect": "Allow"
      }
   ]
}

そして実際に動作確認したところ、これでも足りず、追加で

  • autoscaling:DescribeAutoScalingInstances
  • ec2:CreateLaunchTemplate
  • ec2:DeleteLaunchTemplate
  • iam:TagRole
  • cloudformation:DescribeStackResource
  • ec2:ModifyInstanceAttribute
  • ec2:DetachVolume
  • ec2:AttachVolume
  • ec2:DescribeVolumes

も必要でした...
恐らくオートメーション本体の更新に対してドキュメントの修正が間に合っていない雰囲気なのですが、これは緊急時に必要となるものなので正直よろしくないですね。

緊急時にこれらの権限まわりを厳密に設定することは難しいと思いますので、事前に専用のロールを用意しておくことをお勧めします。
一応簡単なCloudFormation Templateを用意しておいたので適宜改変してご利用ください。

StartEC2RescueWorkflowRole ロール
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Role for AWSSupport-StartEC2RescueWorkflow automation invocation.
Parameters:
  RoleName:
    Description: "Input role name."
    Type: String
    Default: "StartEC2RescueWorkflowRole"
Resources:
  # IAM Role
  EC2RescueWorkflowRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:
        Fn::Sub: "${RoleName}"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ssm.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
  # Inline policy
  EC2RescueWorkflowPolicy:
    Type: AWS::IAM::RolePolicy
    Properties:
      RoleName:
        Ref: EC2RescueWorkflowRole
      PolicyName: "StartEC2RescueWorkflowPolicy"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action:
              - "lambda:InvokeFunction"
              - "lambda:DeleteFunction"
              - "lambda:GetFunction"
            Resource:
              Fn::Sub: "arn:${AWS::Partition}:lambda:*:${AWS::AccountId}:function:AWSSupport-EC2Rescue-*"
          - Effect: "Allow"
            Action:
              - "s3:GetObject"
              - "s3:GetObjectVersion"
            Resource:
              - "arn:aws:s3:::awssupport-ssm.*/*.template"
              - "arn:aws:s3:::awssupport-ssm.*/*.zip"
          - Effect: "Allow"
            Action:
              - "iam:CreateRole"
              - "iam:CreateInstanceProfile"
              - "iam:GetRole"
              - "iam:GetInstanceProfile"
              - "iam:PutRolePolicy"
              - "iam:DetachRolePolicy"
              - "iam:AttachRolePolicy"
              - "iam:PassRole"
              - "iam:AddRoleToInstanceProfile"
              - "iam:RemoveRoleFromInstanceProfile"
              - "iam:DeleteRole"
              - "iam:DeleteRolePolicy"
              - "iam:DeleteInstanceProfile"
              - "iam:TagRole"
            Resource:
              - Fn::Sub: "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/AWSSupport-EC2Rescue-*"
              - Fn::Sub: "arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/AWSSupport-EC2Rescue-*"
          - Effect: "Allow"
            Action:
              - "lambda:CreateFunction"
              - "ec2:CreateVpc"
              - "ec2:ModifyVpcAttribute"
              - "ec2:DeleteVpc"
              - "ec2:CreateInternetGateway"
              - "ec2:AttachInternetGateway"
              - "ec2:DetachInternetGateway"
              - "ec2:DeleteInternetGateway"
              - "ec2:CreateSubnet"
              - "ec2:DeleteSubnet"
              - "ec2:CreateRoute"
              - "ec2:DeleteRoute"
              - "ec2:CreateRouteTable"
              - "ec2:AssociateRouteTable"
              - "ec2:DisassociateRouteTable"
              - "ec2:DeleteRouteTable"
              - "ec2:CreateVpcEndpoint"
              - "ec2:DeleteVpcEndpoints"
              - "ec2:ModifyVpcEndpoint"
              - "ec2:Describe*"
            Resource: "*"
          - Effect: "Allow"
            Action:
              - "autoscaling:DescribeAutoScalingInstances"
              - "ec2:CreateLaunchTemplate"
              - "ec2:DeleteLaunchTemplate"
              - "cloudformation:DescribeStackResource"
              - "ec2:ModifyInstanceAttribute"
              - "ec2:DetachVolume"
              - "ec2:AttachVolume"
              - "ec2:DescribeVolumes"
            Resource: "*"

3. 一時EC2インスタンスはSSMのマネージドインスタンスになる (要エンドポイントアクセス)

SSMを使って処理を行う都合、一時EC2インスタンスはSSMのマネージドインスタンスである必要があります。
すなわち、

  • EC2インスタンスがインターネットアクセス可能
  • EC2インスタンスがSSMのVPC Endpointへアクセス可能

のどちらかを満たす必要があります。

オートメーション実行時にEC2を配置するサブネット[2]やグローバルIP付与の有無を指定可能ですので環境に合わせた内容にしてください。

4. 一時EC2インスタンスのセキュリティグループ指定

オートメーション実行時に一時EC2インスタンスに割り当てるセキュリティグループを指定可能です。
指定しなかった場合デフォルトのDefaultセキュリティグループが選ばれます。

Security Hubの指摘によりDefaultセキュリティグループの通信を制限している場合、独自のセキュリティグループを明示しないと一切のアウトバウント通信ができずタイムアウトエラーとなりますのでご注意ください。

5. 実行するスクリプトのエンコーディング

このオートメーションでは復旧用のEBSボリュームに対する処理をPowerShellで記述することができます。
記述したスクリプトの内容はBASE64エンコードした形で引数として指定します。

ここで、ドキュメント上はスクリプトのエンコーディングをUnicode (UTF-16)で扱う記述となっているのですが、オートメーション側ではASCII固定でデコードします。

オートメーションの Automation step 28 runScriptForWindows から一部抜粋
# ・・・前略・・・
    # オートメーション側はASCIIコードの想定でBASE64エンコードされた文字列をデコードしてしまう
    "    $scriptblock = [scriptblock]::Create([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String('・・・BASE64エンコードされた文字列・・・')))",
    "    & $scriptblock",
# ・・・後略・・・

このため公式ドキュメントの内容に倣うと実行時エラーとなってしまいます。

間違い
# 公式ドキュメントの間違った記述 (Unicodeでエンコードされている)
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes([System.IO.File]::ReadAllText('PATH_TO_FILE')))

正しくは以下の様にASCIIでエンコードしてください。

正解
# 指定側も ASCII でエンコードしてやる
[System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.IO.File]::ReadAllText('PATH_TO_FILE')))

これは明確なバグですのであとでAWSへフィードバックしておこうと思います。
なので将来的には修正されるかもしれません。

動作確認

ここからは実際に動作確認をしていきます。

内容としてはAWSの指示に従い今回の障害への対応「Option 1 - Use the AWS Systems Manager automation runbook」を行います。

0. 検証環境

今回は私の検証用AWSアカウントの東京リージョンにVPCを一つ用意し、そこにある日本語版Windows Server 2022 EC2インスタンスが障害を起こした体とします。

important-point-to-use-awssupport-startec2rescueworkflow-02

  • EC2のAMIは本日時点で最新のami-082a6b0eaa477ae3d (Windows_Server-2022-Japanese-Full-Base-2024.07.10)としています

このインスタンスに対しAWS指定の手順に従いAWSSupport-StartEC2RescueWorkflowオートメーションを実行して問題を起こしているファイルを削除し復旧を試みます。

本日時点では厳密に環境を再現できないため、通常起動させたEC2に「C:\Windows\System32\drivers\CrowdStrike\C-00000291-xxxxxxxx-xxxxxxxx.sys」というダミーファイルを配置し、このファイルが消えたことをもって復旧した扱いとします。

important-point-to-use-awssupport-startec2rescueworkflow-03
「CrowdStrike-Broken」という名前で障害インスタンスを用意

important-point-to-use-awssupport-startec2rescueworkflow-04
削除予定ファイルをあらかじめ配備ずみ

1. 専用IAMロールの準備

前節で説明したオートメーション用のIAMロールはStartEC2RescueWorkflowRoleという名前で事前に作成ずみです。

important-point-to-use-awssupport-startec2rescueworkflow-05

2. 実行スクリプトの準備

オートメーションを実行する前に最初に実行するスクリプトの準備を行います。
AWSの手順としては、以下のコマンドを使い障害の原因となるファイルを削除する手順となっています。

障害の原因となっている .sys ファイルを削除するコマンド
get-childitem -path "$env:EC2RESCUE_OFFLINE_DRIVE\Windows\System32\drivers\CrowdStrike\" -Include C-00000291*.sys -Recurse | foreach { $_.Delete()}

オートメーションで使うにはこの内容をBASE64エンコーディングする必要があります。
PowerShellコンソールを起動し、以下の手順で得られる$encodedCommandの内容を取得します。

BASE64エンコードされたコマンドを取得
# AWSドキュメントの手順とは異なり、エンコーディングを ASCII にすること
$command = 'get-childitem -path "$env:EC2RESCUE_OFFLINE_DRIVE\Windows\System32\drivers\CrowdStrike\" -Include C-00000291*.sys -Recurse | foreach { $_.Delete()}'
$encodedCommand = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($command))
$encodedCommand

important-point-to-use-awssupport-startec2rescueworkflow-06

ここで得られた

正しくBASE64エンコードされたコマンド
Z2V0LWNoaWxkaXRlbSAtcGF0aCAiJGVudjpFQzJSRVNDVUVfT0ZGTElORV9EUklWRVxXaW5kb3dzXFN5c3RlbTMyXGRyaXZlcnNcQ3Jvd2RTdHJpa2VcIiAtSW5jbHVkZSBDLTAwMDAwMjkxKi5zeXMgLVJlY3Vyc2UgfCBmb3JlYWNoIHsgJF8uRGVsZXRlKCl9

を後で使います。

余談1 : エンコード結果の検証

エンコード結果の検証は以下の様に行ってください。

検証手順
# BASE64文字列をデコードして検証
[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($encodedCommand))

AWS提供の手順ではUTF-8前提となっており、厳密には誤った指定なのですが、今回に関してはこちらでも問題ありません。

AWS提供の検証手順
# AWSの手順ではUTF-8文字列を扱う形になっているが、今回に関してはASCIIと同様の結果を得られるので問題ない
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("REPLACE_WITH_BASE64_HERE"))

余談2 : Unicode を使った場合のコマンド

AWSドキュメントに従いUnicode文字列をBASE64エンコードした結果は以下となり、前述のものと異なることが分かります。

間違ってBASE64エンコードされたコマンド
# DO NOT USE : これは使わないこと
ZwBlAHQALQBjAGgAaQBsAGQAaQB0AGUAbQAgAC0AcABhAHQAaAAgACIAJABlAG4AdgA6AEUAQwAyAFIARQBTAEMAVQBFAF8ATwBGAEYATABJAE4ARQBfAEQAUgBJAFYARQBcAFcAaQBuAGQAbwB3AHMAXABTAHkAcwB0AGUAbQAzADIAXABkAHIAaQB2AGUAcgBzAFwAQwByAG8AdwBkAFMAdAByAGkAawBlAFwAIgAgAC0ASQBuAGMAbAB1AGQAZQAgAEMALQAwADAAMAAwADAAMgA5ADEAKgAuAHMAeQBzAA==

なお、誤ってこちらを使っても「gというコマンドは無い」という旨のエラー[3]となるだけで副作用はありませんのでご安心ください。

The term 'g' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

3. オートメーションの実行

マネジメントコンソールから「AWS Systems Manager」→「オートーメーション」を選択し、新規の「Execution automation」をクリックします。

important-point-to-use-awssupport-startec2rescueworkflow-07

ランブック一覧からAWSSupport-StartEC2RescueWorkflowを選んで選択すると、

important-point-to-use-awssupport-startec2rescueworkflow-08

画面下部に詳細が表示されるのでそのまま「次へ」進みます。

important-point-to-use-awssupport-startec2rescueworkflow-09

今回は単一環境への実行となるため「Simple execution」を選びます。

important-point-to-use-awssupport-startec2rescueworkflow-10

入力パラメーターの指定で最初に復旧対象のEC2インスタンスを選択します。
今回はInteractive pickerを使っていますが、あらかじめインスタンスIDが分かっている場合はこれを使わず直接インスタンスIDを指定することもできます。

important-point-to-use-awssupport-startec2rescueworkflow-11

その他のパラメーターは環境に応じた内容にします。

important-point-to-use-awssupport-startec2rescueworkflow-12

特に注意すべきパラメータに関しては下表のとおりです。

パラメーター名 指定内容 備考
AutomationAssumeRole オートメーション実行時の実行ロールを指定 前述の権限が必要
OfflineScript BASE64エンコードされたPowerShellスクリプト ASCIIコードの文字列を使う
SubnetId 一時インスタンスを配置するサブネットID 幾つかの特殊文字列による指定も可能。SelectedInstanceSubnetと指定すると復旧対象と同じサブネットになる(デフォルト値)
CreatePreRescueBackup EC2Rescue実行前にバックアップを取るか否か
CreatePostRescueBackup EC2Rescue実行後にバックアップを取るか否か
AllowEncryptedVolume 対象EBSが暗号化されているか否か 暗号化EBSの場合はTrueにする
AssociatePublicIpAddress 一時インスタンスにPublic IPを割り当てるか否か Publicサブネットで復旧する場合はTrueにする
HelperInstanceSecurityGroupId 一時インスタンスに割り当てるセキュリティグループID 未指定時はdefaultセキュリティグループが使われる

今回は

  • 実行ロールは事前準備したStartEC2RescueWorkflowRole
  • 一時インスタンスのサブネットは復旧対象と同じに
  • 実行前バックアップを取得
  • 実行後バックアップは不要
  • EBSボリュームは暗号化されているため AllowEncryptedVolume パラメーターを指定
  • セキュリティグループはアウトバウント通信全許可のものを明示的に指定

という内容にしています。

指定内容に問題がなければ「Execute」をクリックしてオートメーションを実行します。

important-point-to-use-awssupport-startec2rescueworkflow-13

完了まで結構時間がかかるので待ちます。

important-point-to-use-awssupport-startec2rescueworkflow-14

また、処理中は下図の様に一時インスタンスが立ち上がり、復旧対象インスタンスは停止されます。

important-point-to-use-awssupport-startec2rescueworkflow-15

最終的にエラー無く完了すればOKです。

important-point-to-use-awssupport-startec2rescueworkflow-16

この時点で一時インスタンスが破棄され、復旧対象インスタンスは再起動されています。

important-point-to-use-awssupport-startec2rescueworkflow-17

復旧対象インスタンスにRDP接続してスクリプトの実行結果を確認すると無事C-00000291で始まるファイルだけ削除されているのが確認できました。

important-point-to-use-awssupport-startec2rescueworkflow-18
C-00000291で始まるファイルだけ削除されている

バックアップはAMIの形で保存されます。

important-point-to-use-awssupport-startec2rescueworkflow-19
事前バックアップを取った場合の例

これで無事期待通りの復旧ができました。

最後に

以上となります。

本記事の内容が今回の障害対応および将来の対応に役立てば幸いです。

脚注
  1. 弊社クラスメソッドメンバーズご利用のお客様は弊社サポートまでお問い合わせください。 ↩︎

  2. デフォルトでは復旧対象と同じサブネット ↩︎

  3. PowerShell内部的に「g e t - c h i l d i t e m ...後略...」と1文字ずつ分かれてしまった形で解釈されてしまうのが直接の原因です ↩︎

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.