AWS EC2 インスタンスには、 Status Checked Failed 発生時に自動的に復旧を試みる機能があります。
設定自体は正しく行えているように見えるのに、いざ異常発生時に復旧に失敗するケースに当たりました。

Action failed. Encountered error calling EC2 recover. (401: AWS was not able to validate the provided access credentials)

復旧に失敗した RecoveryAlarm は IAM Role を使用して CloudFormation で作成していましたが、作成(設定)自体は正常に行えていました。
結論としてはドキュメントに記載があるのですが、IAM Role で復旧アラームを作成している場合、復旧アクションは動作しません。

IAM ロール (たとえば、Amazon EC2 インスタンスプロファイル) を使用している場合は、アラームアクションを使用してインスタンスを停止、終了、または再起動することはできません。

尚、復旧(recover)アクションと同様に、 停止(stop)、終了(terminate)、再起動(reboot) を実行するアラームを作成できますが、 復旧(recover)とその他のアクションでは使用される実行権限が異なります。 (アラーム作成時の権限が使用されるのは 復旧(revocer) の場合のみ)

IAM ロールに基づいて、アラームアクションを使用してインスタンスを停止、終了、または再起動する場合は、EC2ActionsAccess ロールしか使用できません。他の IAM ロールはサポートされていません。別の IAM ロールを使用している場合は、インスタンスを停止、終了、または再起動できません。
AWS Security Token Service (AWS STS) を用いて許可された一時的な認証情報を使用している場合は、アラームアクションを用いて Amazon EC2 インスタンスを復旧することはできません。

ドキュメントの内容だけではわかり難かったので、実際に復旧アクションの挙動を確認してみました。

IAM 準備

IAM Role と IAM User での比較を行います。

IAM Role / IAM User

IAM Role と IAM User を準備します。今回はいずれも PowerUserAccess を付与しています。

  • IAM Role

20160816230225

  • IAM User

20160816230226

aws configure

デフォルトで IAM Role を使用し、profile=cfn で IAM User を使用できるよう設定します。

$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                             None    None
access_key     ****************EFEA         iam-role
secret_key     ****************dE0o         iam-role
    region           ap-northeast-1      config-file    ~/.aws/config
$ cat ~/.aws/credentials
[default]
region = ap-northeast-1

[cfn]
aws_access_key_id = ****************VO2A
aws_secret_access_key = ************************************QPgI
region = ap-northeast-1

Cloud Formation テンプレート準備

EC2 + RecoveryAlarm のテンプレートを用意します。

  • ec2.json
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Outputs": {
    "InstanceID" : {
      "Value" : { "Ref" : "Ec2Instance" }
    },
    "RecoveryAlarm" : {
      "Value" : { "Ref" : "RecoveryAlarm" }
    }
  },
  "Resources": {
    "Ec2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "ami-374db956",
        "InstanceType" : "t2.micro",
        "BlockDeviceMappings" : [
          {
            "DeviceName": "/dev/xvda",
            "Ebs": {
              "VolumeType": "gp2",
              "VolumeSize": "8"
            }
          }
        ]
      }
    },
    "RecoveryAlarm": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "Namespace": "AWS/EC2" ,
        "MetricName": "StatusCheckFailed",
        "Statistic": "Minimum",
        "Period": "60",
        "EvaluationPeriods": "5",
        "ComparisonOperator": "GreaterThanThreshold",
        "Threshold": "0",
        "AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
        "Dimensions": [{"Name": "InstanceId","Value": {"Ref": "Ec2Instance"}}]
      }
    }
  }
}

RecoveryAlarm の作成

IAM Role と IAM User それぞれで CreateStack を実行します。

# IAM Role
aws cloudformation create-stack \
  --stack-name ec2-recoveryalarm-role \
  --template-body file://ec2.json
# IAM User
aws cloudformation create-stack \
  --stack-name ec2-recoveryalarm-user \
  --template-body file://ec2.json \
  --profile cfn
  • IAM Role で作成したStack

20160816230228

  • IAM User で作成したStack

20160816230227

  • 作成したEC2インスタンス(Alarm付)

20160816230229

  • 作成したRecoveryAlarm

20160816230230

RecoveryAlarm の実行確認

作成した RecoveryAlarm の状態を ALARM に更新し、挙動を確認します。 (システムステータスチェックのエラーを意図的に起こすことはできません。

IAM Role で作成した RecoveryAlarm

$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-1SXN4O9QLTKH" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

401 エラーが発生し、Action が失敗します。

20160816230231

IAM User で作成したRecoveryAlarm

$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-user-RecoveryAlarm-1HG4YDX2YZ90H" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

IAM User で作成した場合は問題無く、 Action が正常に終了します。

20160816230232

RecoveryAlarm を再作成

IAM Role で作成し、401エラーとなった RecoveryAlarm を IAM User からの実行で作成し直します。

$ diff ec2.json ec2_update.json
30a31
>         "AlarmName": "ec2-recoveryalarm-role-RecoveryAlarm-renew",
$ aws cloudformation update-stack --stack-name ec2-recoveryalarm-role --template-body file://ec2_update.json --profile cfn
  • RecoveryAlarm の再作成(Delete/Update)
    20160816230233

IAM User で “再作成” した RecoveryAlarm

作成し直した RecoveryAlarm の実行確認をします。

$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-renew" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

IAM User で再作成した場合も、Action が正常に終了しました。
20160816230234

マネジメントコンソール上と、 describe-alarms で RecoveryAlarm を確認してみましたが、どの権限(IAM)で作成されたかの情報は保持していませんでした。
RecoveryAlarm を作成した際は実行確認を行い、権限エラーが発生しない事を確認しておいた方が良さそうです。

元記事はこちら

AWS EC2 インスタンスの復旧(Auto Recovery)設定の落とし穴