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
- IAM User
aws configure
デフォルトで IAM Role を使用し、profile=cfn で IAM User を使用できるよう設定します。
$ aws configure list Name Value Type Location ---- ----- ---- -------- profileNone 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
- IAM User で作成したStack
- 作成したEC2インスタンス(Alarm付)
- 作成したRecoveryAlarm
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 が失敗します。
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 が正常に終了します。
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)
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 が正常に終了しました。
マネジメントコンソール上と、 describe-alarms で RecoveryAlarm を確認してみましたが、どの権限(IAM)で作成されたかの情報は保持していませんでした。
RecoveryAlarm を作成した際は実行確認を行い、権限エラーが発生しない事を確認しておいた方が良さそうです。