@@ -24,35 +24,77 @@ declare -r imds_token_path="api/token"
2424declare -r syslog_facility=" user"
2525declare -r syslog_tag=" ec2net"
2626declare -i -r rule_base=10000
27+ declare -r default_route=" DEFAULT"
2728
2829# Systemd installs routes with a metric of 1024 by default. We
2930# override to a lower metric to ensure that our fully configured
3031# interfaces are preferred over those in the process of being
3132# configured.
3233declare -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+ # We know that systemd will use either en or eth as default prefix.
52+ # It will return empty if there are no secondary interfaces.
53+ basename -a /sys/class/net/* | grep -E ' ^e(n|th)' | sort -V | sed -n ' 2p'
54+ }
3455
3556get_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
57+ # Try getting a token early, using each endpoint in
58+ # turn. Whichever interface and endpoint responds will be used for all the IMDS calls
59+ # used to setup the interface. For IMDS interface we will
60+ # try to call the IMDS from its self first, failing that the
61+ # primary eni, and failing that the best guess at the
62+ # lowest secondary eni if available.
63+ # On initial interface setup, we'll retry
3964 # this operation for up to 30 seconds, but on subsequent
4065 # invocations we avoid retrying
4166 local deadline
67+ local intf=$self_iface_name
4268 deadline=$( date -d " now+30 seconds" +%s)
4369 local old_opts=$-
70+
4471 while [ " $( date +%s) " -lt $deadline ]; do
4572 for ep in " ${imds_endpoints[@]} " ; do
4673 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} )
74+ imds_token=$( make_token_request " $ep " " $intf " )
75+
76+ if [ -z " $imds_token " ]; then
77+ imds_token=$( make_token_request " $ep " )
78+ intf=" $default_route "
79+ fi
80+
81+ if [ -z " $imds_token " ]; then
82+ lowest_secondary=$( get_lowest_secondary_interface)
83+ if [ -n " $lowest_secondary " ]; then
84+ imds_token=$( make_token_request " $ep " " $lowest_secondary " )
85+ intf=" $lowest_secondary "
86+ fi
87+ fi
4988 [[ $old_opts = * e* ]] && set -e
89+
5090 if [ -n " $imds_token " ]; then
51- debug " Got IMDSv2 token from ${ep} "
91+ debug " Got IMDSv2 token for interface ${self_iface_name} from ${ep} via ${intf }"
5292 imds_endpoint=$ep
93+ imds_interface=$intf
5394 return
5495 fi
5596 done
97+
5698 if [ ! -v EC2_IF_INITIAL_SETUP ]; then
5799 break
58100 fi
@@ -85,11 +127,19 @@ get_meta() {
85127 debug " [get_meta] Querying IMDS for ${key} "
86128
87129 get_token
88-
130+ if [[ -z $imds_endpoint || -z $imds_token || -z $imds_interface ]]; then
131+ error " [get_meta] Unable to obtain IMDS token, endpoint, or interface"
132+ return 1
133+ fi
89134 local url=" ${imds_endpoint} /meta-data/${key} "
90135 local meta rc
136+ local curl_opts=(-s --max-time 5 -H " X-aws-ec2-metadata-token:${imds_token} " -f)
137+ if [[ " $imds_interface " != " $default_route " ]]; then
138+ curl_opts+=(--interface " $imds_interface " )
139+ fi
140+
91141 while [ $attempts -lt $max_tries ]; do
92- meta=$( curl -s --max-time 5 -H " X-aws-ec2-metadata-token: ${imds_token} " -f " $url " )
142+ meta=$( curl " ${curl_opts[@]} " " $url " )
93143 rc=$?
94144 if [ $rc -eq 0 ]; then
95145 echo " $meta "
@@ -472,6 +522,7 @@ setup_interface() {
472522 local -i device_number network_card rc
473523 iface=$1
474524 ether=$2
525+ self_iface_name=$1
475526
476527 network_card=$( _get_network_card " $iface " " $ether " )
477528 device_number=$( _get_device_number " $iface " " $ether " " $network_card " )
0 commit comments