こんにちは。AWS CLIが好きな福島です。
今回は、セキュリティ強化のため、EC2でIMDSv2を強制化するのに伴い、 AWS CLIを使い、全てのEC2でIMDSv1の使用履歴を確認したので、その方法をご紹介いたします。
IMDSv2については、以下のブログで紹介しているため、ご興味がある方は、ぜひご覧ください。
実行環境
今回、コマンドを実行した環境は、以下の通りとなります。
(本記事でご紹介しているコマンドの中には、Linuxのコマンドを利用している箇所があります。)
# uname -a Linux LAPTOP-CNM26HN6 4.4.0-18362-Microsoft #1049-Microsoft Thu Aug 14 12:01:00 PST 2020 x86_64 x86_64 x86_64 GNU/Linux #
結論
以下のコマンドを実行しました。
◆ポイント
- CloudWatchで取得できるメトリクス「MetadataNoToken」の値を利用
- メトリクス「MetadataNoToken」の1時間ごとの最大値を2週間分、取得
- MetadataNoToken$(date +"%Y%m%d_%H%M%S").csvファイルに結果を出力
- B列を空けているため、1時間ごとの最大値をSUM関数により計算することでIMDSv1の使用履歴を確認
- 値がNoneになる場合があります。(推測ですが、インスタンスを停止しているなどで値を取得できない場合にNoneになるかと存じます。)
CSV_FILE=MetadataNoToken_$(date +"%Y_%m%d_%H%M%S").csv;\ aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId]" --output text | while read line do cat << EOF > json [ { "Id":"q1", "MetricStat": { "Metric": { "Namespace":"AWS/EC2", "MetricName":"MetadataNoToken", "Dimensions":[ { "Name":"InstanceId", "Value":"$line" } ] }, "Period":3600, "Stat":"Maximum" } } ] EOF echo $line,, > /tmp/awscli.tmp ;\ aws cloudwatch get-metric-data --metric-data-queries file://json --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "30 days ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --query "MetricDataResults[].[\ Values[1],Values[2],Values[3],Values[4],Values[5],Values[6],Values[7],\ Values[8],Values[9],Values[10],Values[11],Values[12],Values[13],Values[14],\ Values[15],Values[16],Values[17],Values[18],Values[19],Values[20],Values[21],\ Values[22],Values[23],Values[24],Values[25],Values[26],Values[27],Values[28],\ Values[29],Values[30],Values[31],Values[32],Values[33],Values[34],Values[35],\ Values[36],Values[37],Values[38],Values[39],Values[40],Values[41],Values[42],\ Values[43],Values[44],Values[45],Values[46],Values[47],Values[48],Values[49],\ Values[50],Values[51],Values[52],Values[53],Values[54],Values[55],Values[56],\ Values[57],Values[58],Values[59],Values[60],Values[61],Values[62],Values[63],\ Values[64],Values[65],Values[66],Values[67],Values[68],Values[69],Values[70],\ Values[71],Values[72],Values[73],Values[74],Values[75],Values[76],Values[77],\ Values[78],Values[79],Values[80],Values[81],Values[82],Values[83],Values[84],\ Values[85],Values[86],Values[87],Values[88],Values[89],Values[90],Values[91],\ Values[92],Values[93],Values[94],Values[95],Values[96],Values[97],Values[98],\ Values[99],Values[100],Values[101],Values[102],Values[103],Values[104],Values[105],\ Values[106],Values[107],Values[108],Values[109],Values[110],Values[111],Values[112],\ Values[113],Values[114],Values[115],Values[116],Values[117],Values[118],Values[119],\ Values[120],Values[121],Values[122],Values[123],Values[124],Values[125],Values[126],\ Values[127],Values[128],Values[129],Values[130],Values[131],Values[132],Values[133],\ Values[134],Values[135],Values[136],Values[137],Values[138],Values[139],Values[140],\ Values[141],Values[142],Values[143],Values[144],Values[145],Values[146],Values[147],\ Values[148],Values[149],Values[150],Values[151],Values[152],Values[153],Values[154],\ Values[155],Values[156],Values[157],Values[158],Values[159],Values[160],Values[161],\ Values[162],Values[163],Values[164],Values[165],Values[166],Values[167],Values[168],\ StatusCode]" --output text | tr "\t" "," >> /tmp/awscli.tmp cat /tmp/awscli.tmp | tr "\n" " " | sed 's/ //g' >> ${CSV_FILE} echo "" >> ${CSV_FILE} done
- 実行結果
ExcelのSUM関数を利用して計算
B列が0のインスタンスは、IMDSv1を使用していない(2週間)ことが分かる。
処理の説明
CSV_FILE=MetadataNoToken_$(date +"%Y_%m%d_%H%M%S").csv;\
⇒変数名の定義
aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId]" --output text | while read line
⇒全EC2のインスタンスIDをwhileにより1つずつline変数に代入
cat << EOF > json [ { "Id":"q1", "MetricStat": { "Metric": { "Namespace":"AWS/EC2", "MetricName":"MetadataNoToken", "Dimensions":[ { "Name":"InstanceId", "Value":"$line" ★ } ] }, "Period":3600, "Stat":"Maximum" } } ] EOF
⇒CloudWatchコマンドで使うJSONファイルを生成。
Value(★)にインスタンスIDを記載。
aws cloudwatch get-metric-data --metric-data-queries file://json --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "30 days ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --query "MetricDataResults[].[\ Values[1],Values[2],Values[3],Values[4],Values[5],Values[6],Values[7],\ Values[8],Values[9],Values[10],Values[11],Values[12],Values[13],Values[14],\ Values[15],Values[16],Values[17],Values[18],Values[19],Values[20],Values[21],\ Values[22],Values[23],Values[24],Values[25],Values[26],Values[27],Values[28],\ Values[29],Values[30],Values[31],Values[32],Values[33],Values[34],Values[35],\ Values[36],Values[37],Values[38],Values[39],Values[40],Values[41],Values[42],\ Values[43],Values[44],Values[45],Values[46],Values[47],Values[48],Values[49],\ Values[50],Values[51],Values[52],Values[53],Values[54],Values[55],Values[56],\ Values[57],Values[58],Values[59],Values[60],Values[61],Values[62],Values[63],\ Values[64],Values[65],Values[66],Values[67],Values[68],Values[69],Values[70],\ Values[71],Values[72],Values[73],Values[74],Values[75],Values[76],Values[77],\ Values[78],Values[79],Values[80],Values[81],Values[82],Values[83],Values[84],\ Values[85],Values[86],Values[87],Values[88],Values[89],Values[90],Values[91],\ Values[92],Values[93],Values[94],Values[95],Values[96],Values[97],Values[98],\ Values[99],Values[100],Values[101],Values[102],Values[103],Values[104],Values[105],\ Values[106],Values[107],Values[108],Values[109],Values[110],Values[111],Values[112],\ Values[113],Values[114],Values[115],Values[116],Values[117],Values[118],Values[119],\ Values[120],Values[121],Values[122],Values[123],Values[124],Values[125],Values[126],\ Values[127],Values[128],Values[129],Values[130],Values[131],Values[132],Values[133],\ Values[134],Values[135],Values[136],Values[137],Values[138],Values[139],Values[140],\ Values[141],Values[142],Values[143],Values[144],Values[145],Values[146],Values[147],\ Values[148],Values[149],Values[150],Values[151],Values[152],Values[153],Values[154],\ Values[155],Values[156],Values[157],Values[158],Values[159],Values[160],Values[161],\ Values[162],Values[163],Values[164],Values[165],Values[166],Values[167],Values[168],\ StatusCode]" --output text | tr "\t" "," >> /tmp/awscli.tmp
⇒CloudWatchコマンドによりメトリクス「MetadataNoToken」の1時間ごとの最大値を2週間分、取得。
cat /tmp/awscli.tmp | tr "\n" " " | sed 's/ //g' >> ${CSV_FILE} echo "" >> ${CSV_FILE}
⇒CSVファイルへ出力
おまけ①
上記スクリプトでは、IMDSv1が使用履歴を確認することはできますが、
詳細な時間まで確認することはできません。
詳細な時間を確認したい場合は、cloudwatchコマンドのqueryで「Timestamps[0]」、「Timestamps[1]」と指定します。
- 実行例
aws cloudwatch get-metric-data --metric-data-queries file://json \ --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "30 days ago") \ --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") \ --query "MetricDataResults[].[Timestamps[0],Values[0],Timestamps[1],Values[1],StatusCode]" --output text | tr "\t" ","
- 実行結果
2021-02-09T09:00:00+00:00,3.0,2021-02-09T08:00:00+00:00,3.0,Complete
おまけ②(IMDSv2設定確認)
IMDSv2を強制化できているか確認するコマンドは、以下の通りです。 ※メタデータのHttpTokensおよびHttpEndpointの設定値を確認します。
- 実行例
aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId,MetadataOptions.HttpTokens,MetadataOptions.HttpEndpoint]" --output text
- 実行結果
i-0f6126b7aeedfabd6 required enabled i-050536efdd9dc1126 optional enabled i-0b66442bd16bf7f21 optional enabled i-0808672558492fde8 optional enabled
⇒ 2列目が「required」、3列目が「enabled」になっていれば、IMDSv2のみ使う設定になっています。
おまけ③(IMDSv2設定変更)
- 実行例
aws ec2 modify-instance-metadata-options --instance-id i-0f61b7aedddabd6 --http-tokens required --http-endpoint enabled
おまけ④(Nameタグ付き)
CSV_FILE=MetadataNoToken_$(date +"%Y_%m%d_%H%M%S").csv;\ aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId,Tags[?Key=='Name'] | [0].Value]" --output text | tr "\t" "," | while read line do instance_id=$(echo $line | awk -F, '{print $1}') name_tag=$(echo $line | awk -F, '{print $2}') cat << EOF > json [ { "Id":"q1", "MetricStat": { "Metric": { "Namespace":"AWS/EC2", "MetricName":"MetadataNoToken", "Dimensions":[ { "Name":"InstanceId", "Value":"$instance_id" } ] }, "Period":3600, "Stat":"Maximum" } } ] EOF echo $instance_id,$name_tag,, > /tmp/awscli.tmp ;\ aws cloudwatch get-metric-data --metric-data-queries file://json --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "30 days ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --query "MetricDataResults[].[\ Values[1],Values[2],Values[3],Values[4],Values[5],Values[6],Values[7],\ Values[8],Values[9],Values[10],Values[11],Values[12],Values[13],Values[14],\ Values[15],Values[16],Values[17],Values[18],Values[19],Values[20],Values[21],\ Values[22],Values[23],Values[24],Values[25],Values[26],Values[27],Values[28],\ Values[29],Values[30],Values[31],Values[32],Values[33],Values[34],Values[35],\ Values[36],Values[37],Values[38],Values[39],Values[40],Values[41],Values[42],\ Values[43],Values[44],Values[45],Values[46],Values[47],Values[48],Values[49],\ Values[50],Values[51],Values[52],Values[53],Values[54],Values[55],Values[56],\ Values[57],Values[58],Values[59],Values[60],Values[61],Values[62],Values[63],\ Values[64],Values[65],Values[66],Values[67],Values[68],Values[69],Values[70],\ Values[71],Values[72],Values[73],Values[74],Values[75],Values[76],Values[77],\ Values[78],Values[79],Values[80],Values[81],Values[82],Values[83],Values[84],\ Values[85],Values[86],Values[87],Values[88],Values[89],Values[90],Values[91],\ Values[92],Values[93],Values[94],Values[95],Values[96],Values[97],Values[98],\ Values[99],Values[100],Values[101],Values[102],Values[103],Values[104],Values[105],\ Values[106],Values[107],Values[108],Values[109],Values[110],Values[111],Values[112],\ Values[113],Values[114],Values[115],Values[116],Values[117],Values[118],Values[119],\ Values[120],Values[121],Values[122],Values[123],Values[124],Values[125],Values[126],\ Values[127],Values[128],Values[129],Values[130],Values[131],Values[132],Values[133],\ Values[134],Values[135],Values[136],Values[137],Values[138],Values[139],Values[140],\ Values[141],Values[142],Values[143],Values[144],Values[145],Values[146],Values[147],\ Values[148],Values[149],Values[150],Values[151],Values[152],Values[153],Values[154],\ Values[155],Values[156],Values[157],Values[158],Values[159],Values[160],Values[161],\ Values[162],Values[163],Values[164],Values[165],Values[166],Values[167],Values[168],\ StatusCode]" --output text | tr "\t" "," >> /tmp/awscli.tmp cat /tmp/awscli.tmp | tr "\n" " " | sed 's/ //g' >> ${CSV_FILE} echo "" >> ${CSV_FILE} done
おわりに
今回は、IMDSv1の使用履歴を確認するスクリプトをご紹介しました。
どなたかのお役に立てれば幸いです。