EC2インスタンスから自身のMetadataを取得する

# 概要
接続中のインスタンス自身の情報を取得する方法とより簡単なコマンドについて説明します。
最後にAWS CLIで自身のインスタンスに設定されているタグを取得する例を紹介します。

# Metadataからコマンドを実行しているインスタンスのIDを取得する

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-metadata.html

公式ドキュメントの説明だと以下のAPIにリクエストを送ることでメタデータの取得が可能です。

- IPv4 `http://169.254.169.254/latest/meta-data/`
- IPv6 `http://[fd00:ec2::254]/latest/meta-data/`

実際に以下のように取得できます。

```
# categoryを取得
$ curl http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
tags/

# categoryを指定
$ curl http://169.254.169.254/latest/meta-data/ami-id
ami-xxxx
```

この方法はIMDS v1での取得方法であり、現在ではIMDS v2での取得が推奨です。

## IMDSとは

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html

インスタンスに対して手動やスクリプトに対してハードコーディングして利用するのではなく、実行時に取得して実行できるために用意されています。

https://aws.amazon.com/jp/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/

上記のようにv2はセキュリティ向上のために実行するための期限付きのTokenを発行してAPIを利用することを推奨しています。
IMDSの設定はEC2起動時のAdvanced detailsのセクションから設定が可能です。添付画像のようにメタデータのアクセス可否、利用APIのバージョンの制限が可能です。

![ec2-access.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/fcd8d4f6-0d8a-aa85-d073-fe3bbe48ee09.png)
![ec2-metadata_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/f7a890f9-ad6d-c091-7049-f6465fbfbd80.png)
![ec2-metadata_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/03158dc0-2916-4b36-79a7-4d159268cf4c.png)

## AWS SDKを利用して取得する
TOKENを取得する手順を踏むのは少し面倒に思うかもしれませんが、AWSのSDKではv2での利用をサポートしているのでこちらを使う方が簡単です。
今回はSessionManagerで接続したことを想定して、Linux向けにshellとWindows向けにPowershellの紹介をします。

### ec2-metadata command (Linux)
Linux向けのコマンドは以下のように実装されており、Tokenの取得の関数も組み込まれています。

https://github.com/amazonlinux/amazon-ec2-utils/blob/09b53f2a20c3e4d227acfb452138fdb672baaa1a/ec2-metadata#L51C10-L59

使い方
```shell
$ ec2-metadata --help
ec2-metadata v0.1.4
Use to retrieve EC2 instance metadata from within a running EC2 instance. 
e.g. to retrieve instance id: ec2-metadata -i
		 to retrieve ami id: ec2-metadata -a
		 to get help: ec2-metadata --help
For more information on Amazon EC2 instance meta-data, refer to the documentation at
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html

Usage: ec2-metadata <option>
Options:
--all                     Show all metadata information for this host (also default).
-a/--ami-id               The AMI ID used to launch this instance
-l/--ami-launch-index     The index of this instance in the reservation (per AMI).
-m/--ami-manifest-path    The manifest path of the AMI with which the instance was launched.
-n/--ancestor-ami-ids     The AMI IDs of any instances that were rebundled to create this AMI.
-b/--block-device-mapping Defines native device names to use when exposing virtual devices.
-i/--instance-id          The ID of this instance
-t/--instance-type        The type of instance to launch. For more information, see Instance Types.
-h/--local-hostname       The local hostname of the instance.
-o/--local-ipv4           Public IP address if launched with direct addressing; private IP address if launched with public addressing.
-k/--kernel-id            The ID of the kernel launched with this instance, if applicable.
-z/--availability-zone    The availability zone in which the instance launched. Same as placement
-R/--region               The region in which the instance launched.
-P/--partition            The AWS partition name.
-c/--product-codes        Product codes associated with this instance.
-p/--public-hostname      The public hostname of the instance.
-v/--public-ipv4          NATted public IP Address
-u/--public-keys          Public keys. Only available if supplied at instance launch time
-r/--ramdisk-id           The ID of the RAM disk launched with this instance, if applicable.
-e/--reservation-id       ID of the reservation.
-s/--security-groups      Names of the security groups the instance is launched in. Only available if supplied at instance launch time
-d/--user-data            User-supplied data.Only available if supplied at instance launch time.
-g/--tags                 Tags assigned to this instance.
--quiet                   Suppress tag keys from the output."

```

利用例
```shell
$ ec2-metadata -i
i-xxx
```


### Get-EC2InstanceMetadata command (Windows)
Windows向けのコマンドは.NETのSDKの関数をPowershellで呼び出す形のようです。こちらもTokenの取得の関数も組み込まれています。

https://github.com/aws/aws-sdk-net/blob/391116fc7aaef3095fbb778ec0763f89715b8c64/sdk/src/Core/Amazon.Util/EC2InstanceMetadata.cs#L745-L757

コマンドの詳細についてはこちらを確認ください。

https://docs.aws.amazon.com/powershell/latest/reference/items/Get-EC2InstanceMetadata.html

利用例
```powershell
$ Get-EC2InstanceMetadata -ListCategory
AmiId
LaunchIndex
ManifestPath
AncestorAmiId
BlockDeviceMapping
InstanceId
InstanceType
LocalHostname
LocalIpv4
KernelId
AvailabilityZone
ProductCode
PublicHostname
PublicIpv4
PublicKey
RamdiskId
Region
ReservationId
SecurityGroup
UserData
InstanceMonitoring
IdentityDocument
IdentitySignature
IdentityPkcs7
```

```powershell
$ Get-EC2InstanceMetadata -Category InstanceId
i-xxxx
```

# InstanceIdを使ってInstanceのタグを取得する
上記で紹介した方法を組み合わせてAWS CLIを実行してみます。


```sh
$ ec2-metadata -i
i-xxxx

# インスタンスに設定されているNameタグを取得する
$ aws ec2 describe-tags --region ap-northeast-1 --filters Name=key,Values=Name Name=resource-id,Values=i-xxxx
{
    "Tags": [
        {
            "ResourceType": "instance",
            "ResourceId": "i-xxxx",
            "Value": "yyyy",
            "Key": "Name"
        }
    ]
}
```

**filtersオプションの指定方法について**
基本的な指定方法
```
-filters Name=xxx,Values=yyy
```
Valuesを複数指定する
```
-filters Name=xxx,Values=yyy,zzz,aaa
```
filter条件を複数適用する
```
-filters Name=xxx,Values=yyy Name=zzz,Values=aaa
```

# IMDSを使ってタグを取得する

そもそもIMDSから取得すれば良いのですが、事前に準備が必要です。

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/work-with-tags-in-IMDS.html#allow-access-to-tags-in-IMDS

あらかじめインスタンスに対してタグのメタデータの取得を有効にするオプションを有効にしておく必要があります。管理コンソールからも設定は可能です。

```shell
# 公式ドキュメント引用
aws ec2 run-instances \
    --image-id ami-0abcdef1234567890 \
    --instance-type c3.large \
    ...
    --metadata-options "InstanceMetadataTags=enabled"
# or
aws ec2 modify-instance-metadata-options \
    --instance-id i-123456789example \
    --instance-metadata-tags enabled
```

以下のように取得できます

```shell
# 公式ドキュメント引用
# 全てのタグのKEYを取得
$ curl http://169.254.169.254/latest/meta-data/tags/instance
Name
Environment

# KEYを指定して取得
$ curl http://169.254.169.254/latest/meta-data/tags/instance/Name
MyInstance
```