1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWS EC2 インスタンスのメタデータを取得する

Posted at

初めに

インスタンス内部からインスタンスIDを知りたいことがあったのでPythonで取得するコードを書いた。

インスタンスのメタデータとは

インスタンスIDやAMIのIDなどのインスタンス自身の情報のこと。インスタンスからcurl http://169.254.169.254/latest/meta-data/ を実行することで取得できる。

最初にシェルで取得しようとして以下のコードを書いたが、うまくいかないことがわかった。理由は実行結果を見るとわかるように、パスが深いところがあるため。例えば、identity-credentials/: ec2/ は、さらにcurl http://169.254.169.254/latest/meta-data/identity-credentials/ec2を実行しなければidentity-credentials(トークンなどの認証情報)の値は返ってこない。

data=`curl -s http://169.254.169.254/latest/meta-data/`

echo $data | sed 's/ /\n/g' | while read line
do
  echo "$line:" `curl -s http://169.254.169.254/latest/meta-data/$line`
done

実行結果(値は少し変えている)

ami-id: ami-06098fd00463352b6
ami-launch-index: 0
ami-manifest-path: (unknown)
block-device-mapping/: ami root
events/: maintenance/
hibernation/: configured
hostname: ip-172-31-38-1.ap-northeast-1.compute.internal
identity-credentials/: ec2/
instance-action: none
instance-id: i-0d25432b11k20tc94
instance-life-cycle: on-demand
instance-type: t2.micro
local-hostname: ip-172-31-38-1.ap-northeast-1.compute.internal
local-ipv4: 172.31.38.1
mac: 04:3r:66:3d:76:18
metrics/: vhostmd
network/: interfaces/
placement/: availability-zone availability-zone-id region
profile: default-hvm
public-hostname: ec2-13-125-99-211.ap-northeast-1.compute.amazonaws.com
public-ipv4: 13.125.99.211
public-keys/: 0=key
reservation-id: r-0e1bbhj32u77445y7
security-groups: default
services/: domain partition

この問題に対処するため、Pythonで再帰的にcurlを実行することにした。

つまり、以下の処理を再帰的に行う。

認証情報がほしい

curl http://169.254.169.254/latest/meta-data/

curl http://169.254.169.254/latest/meta-data/identity-credentials/

curl http://169.254.169.254/latest/meta-data/identity-credentials/ec2

認証情報取得

コード

実際に書いたコードがこちら。

import subprocess


def run_curl(url):
    args = ['curl', '-s', url]
    res = subprocess.run(args, encoding='utf-8', stdout=subprocess.PIPE)
    return res


def res_analysis(res):
    for path in res.stdout.split('\n'):
        if '/' in path:
            res_analysis(run_curl(res.args[2] + path))
        else:
            print('{}: {}'.format(path, run_curl(res.args[2] + path).stdout))


if __name__ == "__main__":
    url = 'http://169.254.169.254/latest/meta-data/'
    res_analysis(run_curl(url))

解説

Pythonでcurlコマンドを実行するため、subprocessをインポート。encodingを指定して、バイナリ文字をutf-8に変換する。標準出力を変数に格納するためにstdout=subprocess.PIPEを指定する。

対話モードで実行した場合

>>> subprocess.run(args, encoding='utf-8', stdout=subprocess.PIPE)
CompletedProcess(args=['curl', '-s', 'http://169.254.169.254/latest/meta-data/'], returncode=0, stdout='ami-id\nami-launch-index\nami-manifest-path\nblock-device-mapping/\nevents/\nhibernation/\nhostname\nidentity-credentials/\ninstance-action\ninstance-id\ninstance-life-cycle\ninstance-type\nlocal-hostname\nlocal-ipv4\nmac\nmetrics/\nnetwork/\nplacement/\nprofile\npublic-hostname\npublic-ipv4\npublic-keys/\nreservation-id\nsecurity-groups\nservices/')

以下の条件分岐だが、curlでパスが返ってきた場合とIDなどの値が返ってきた場合で処理を分けるために使用している。パスが返ってきた場合、URLにそのパスを追加して再度curlを実行する。値が返ってきた場合出力する。

if '/' in path:
    res_analysis(run_curl(res.args[2] + path))
else:
    print('{}: {}'.format(path, run_curl(res.args[2] + path).stdout))

書いていて一番気持ち悪いと思ったが、現状これが一番簡潔なのかなと思っているのが以下のコード。再利用のためsubprocess.runは1つのメソッドとして分けたかった。その結果、合成関数みたいになってしまった。

res_analysis(run_curl(url))

実行結果(値は少し変えている。...の部分は省略していることを表す。)

ami-id: ami-06098fd00463352b6
ami-launch-index: 0
ami-manifest-path: (unknown)
ami: /dev/xvda
root: /dev/xvda
history: []
scheduled: []
configured: false
hostname: ip-172-31-38-1.ap-northeast-1.compute.internal
info: {
  "Code" : "Success",
  "LastUpdated" : "2021-04-17T07:01:28Z",
  "AccountId" : "012..."
}
ec2-instance: {
  "Code" : "Success",
  "LastUpdated" : "2021-04-17T07:02:09Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIA...",
  "SecretAccessKey" : "OL...",
  "Token" : "IQ...",
  "Expiration" : "2021-04-17T13:07:15Z"
}
instance-action: none
instance-id: i-0d25432b11k20tc94
instance-life-cycle: on-demand
instance-type: t2.micro
local-hostname: ip-172-31-38-1.ap-northeast-1.compute.internal
local-ipv4: 172.31.38.1
mac: 06:2f:79:4c:69:19
vhostmd: <?xml version="1.0" encoding="UTF-8"?>
device-number: 0
interface-id: eni-6y01019922ooo176528
13.125.99.211: 172.31.38.1
local-hostname: ip-172-31-38-1.ap-northeast-1.compute.internal
local-ipv4s: 172.31.38.1
mac: 04:3r:66:3d:76:18
owner-id: 012...
public-hostname: ec2-13-125-99-211.ap-northeast-1.compute.amazonaws.com
public-ipv4s: 13.125.99.211
security-group-ids: sg-b78p90r2
security-groups: default
subnet-id: subnet-e6g098l4
subnet-ipv4-cidr-block: 172.31.32.0/20
vpc-id: vpc-c4b1weee
vpc-ipv4-cidr-block: 172.31.0.0/16
vpc-ipv4-cidr-blocks: 172.31.0.0/16
availability-zone: ap-northeast-1a
availability-zone-id: apne1-az4
region: ap-northeast-1
profile: default-hvm
public-hostname: ec2-13-125-99-211.ap-northeast-1.compute.amazonaws.com
public-ipv4: 13.125.99.211
0=key: <?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "..."
        "http://www...">
<html xmlns="http://www..." xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>

reservation-id: r-0e1bbhj32u77445y7
security-groups: default
domain: amazonaws.com
partition: aws

参考記事

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?