初めに
インスタンス内部からインスタンス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
参考記事