@@ -24,35 +24,84 @@ declare -r imds_token_path="api/token"
24
24
declare -r syslog_facility=" user"
25
25
declare -r syslog_tag=" ec2net"
26
26
declare -i -r rule_base=10000
27
+ declare -r primary_route=" PRIMARY"
27
28
28
29
# Systemd installs routes with a metric of 1024 by default. We
29
30
# override to a lower metric to ensure that our fully configured
30
31
# interfaces are preferred over those in the process of being
31
32
# configured.
32
33
declare -i -r metric_base=512
33
- declare imds_endpoint imds_token
34
+ declare imds_endpoint=" "
35
+ declare imds_token=" "
36
+ declare imds_interface=" "
37
+ declare self_iface_name=" "
38
+
39
+ make_token_request () {
40
+ local ep=${1:- " " }
41
+ local interface=${2:- " " }
42
+ local -a curl_opts=(--max-time 5 --connect-timeout 0.15 -s --fail -X PUT -H " X-aws-ec2-metadata-token-ttl-seconds: 60" )
43
+ if [ -n " $interface " ]; then
44
+ curl_opts+=(--interface " $interface " )
45
+ fi
46
+ curl " ${curl_opts[@]} " " ${ep} /${imds_token_path} "
47
+ }
48
+
49
+ get_lowest_secondary_interface () {
50
+ # This is the best effort guess at what the lowest secondary interface would be.
51
+ # It will return empty if there are no secondary interfaces.
52
+ local iface
53
+ local -a interfaces=()
54
+
55
+ for iface in /sys/class/net/* ; do
56
+ iface=${iface##*/ }
57
+ [[ $iface =~ ^(lo| docker| veth| dummy| vlan) ]] && continue
58
+ interfaces+=(" $iface " )
59
+ done
60
+ printf " %s\n" " ${interfaces[@]} " | sort -V | sed -n ' 2p'
61
+ }
34
62
35
63
get_token () {
36
- # try getting a token early, using each endpoint in
37
- # turn. Whichever endpoint responds will be used for the rest of
38
- # the IMDS API calls. On initial interface setup, we'll retry
64
+ # Try getting a token early, using each endpoint in
65
+ # turn. Whichever interface and endpoint responds will be used for all the IMDS calls
66
+ # used to setup the interface. For IMDS interface we will
67
+ # try to call the IMDS from its self first, failing that the
68
+ # primary eni, and failing that the best guess at the
69
+ # lowest secondary eni if available.
70
+ # On initial interface setup, we'll retry
39
71
# this operation for up to 30 seconds, but on subsequent
40
72
# invocations we avoid retrying
41
73
local deadline
74
+ local intf=$self_iface_name
42
75
deadline=$( date -d " now+30 seconds" +%s)
43
76
local old_opts=$-
77
+
44
78
while [ " $( date +%s) " -lt $deadline ]; do
45
79
for ep in " ${imds_endpoints[@]} " ; do
46
80
set +e
47
- imds_token=$( curl --max-time 5 --connect-timeout 0.15 -s --fail \
48
- -X PUT -H " X-aws-ec2-metadata-token-ttl-seconds: 60" ${ep} /${imds_token_path} )
81
+ imds_token=$( make_token_request " $ep " " $intf " )
82
+
83
+ if [ -z " $imds_token " ]; then
84
+ imds_token=$( make_token_request " $ep " )
85
+ intf=" $primary_route "
86
+ fi
87
+
88
+ if [ -z " $imds_token " ]; then
89
+ lowest_secondary=$( get_lowest_secondary_interface)
90
+ if [ -n " $lowest_secondary " ]; then
91
+ imds_token=$( make_token_request " $ep " " $intf " )
92
+ intf=" $lowest_secondary "
93
+ fi
94
+ fi
49
95
[[ $old_opts = * e* ]] && set -e
96
+
50
97
if [ -n " $imds_token " ]; then
51
- debug " Got IMDSv2 token from ${ep} "
98
+ debug " Got IMDSv2 token from ${ep} via ${intf} "
52
99
imds_endpoint=$ep
100
+ imds_interface=$intf
53
101
return
54
102
fi
55
103
done
104
+
56
105
if [ ! -v EC2_IF_INITIAL_SETUP ]; then
57
106
break
58
107
fi
@@ -85,11 +134,19 @@ get_meta() {
85
134
debug " [get_meta] Querying IMDS for ${key} "
86
135
87
136
get_token
88
-
137
+ if [[ -z $imds_endpoint || -z $imds_token || -z $imds_interface ]]; then
138
+ error " [get_meta] Unable to obtain IMDS token, endpoint, or interface"
139
+ return 1
140
+ fi
89
141
local url=" ${imds_endpoint} /meta-data/${key} "
90
142
local meta rc
143
+ local curl_opts=(-s --max-time 5 -H " X-aws-ec2-metadata-token:${imds_token} " -f)
144
+ if [[ " $imds_interface " != " $primary_route " ]]; then
145
+ curl_opts+=(--interface " $imds_interface " )
146
+ fi
147
+
91
148
while [ $attempts -lt $max_tries ]; do
92
- meta=$( curl -s --max-time 5 -H " X-aws-ec2-metadata-token: ${imds_token} " -f " $url " )
149
+ meta=$( curl " ${curl_opts[@]} " " $url " )
93
150
rc=$?
94
151
if [ $rc -eq 0 ]; then
95
152
echo " $meta "
@@ -472,6 +529,7 @@ setup_interface() {
472
529
local -i device_number network_card rc
473
530
iface=$1
474
531
ether=$2
532
+ self_iface_name=$1
475
533
476
534
network_card=$( _get_network_card " $iface " " $ether " )
477
535
device_number=$( _get_device_number " $iface " " $ether " " $network_card " )
0 commit comments