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 を付与しています。
aws configure
デフォルトで IAM Role を使用し、profile=cfn で IAM User を使用できるよう設定します。
$ aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> 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 のテンプレートを用意します。
{
"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
RecoveryAlarm の実行確認
作成した RecoveryAlarm の状態を ALARM に更新し、挙動を確認します。
(システムステータスチェックのエラーを意図的に起こすことはできません。)
IAM Role で作成した RecoveryAlarm
# 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
# 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 を作成した際は実行確認を行い、権限エラーが発生しない事を確認しておいた方が良さそうです。