-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy patheic_curl_authorized_keys
executable file
·165 lines (142 loc) · 6.33 KB
/
eic_curl_authorized_keys
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/bin/sh
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
# Reads and echoes EC2 Metadata to get the authorized keys blob for the user $1
set -e
# Set umask so only we can touch temp files
umask 077
IMDS="http://169.254.169.254/latest/meta-data"
# cURL wrapper to ensure we always use the desired flags
curl_cmd () {
/usr/bin/curl -s -f -m 1 -H "${1}" "${2}"
}
# Fetch the IMDSv2 access token. 5 seconds is overall AKC timeout so we use that.
IMDS_TOKEN="$(/usr/bin/curl -s -f -m 1 -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 5")"
token_exit="${?}"
if [ "${token_exit}" -ne 0 ] ; then
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect failed to establish trust with Instance Metadata Service"
exit 255
fi
if [ -z "${IMDS_TOKEN}" ] ; then
# Fast fail
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect failed to get a token to invoke Instance Metadata Service"
exit 255
fi
IMDS_TOKEN_HEADER="X-aws-ec2-metadata-token: ${IMDS_TOKEN}"
# Verify the instance ID itself
# Note: if IMDSv1 is disabled here and IMDS_TOKEN is unset we fast-fail out right now.
instance=$(curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/instance-id/")
if [ -z "${instance}" ] ; then
exit 0
fi
# Validate the instance ID is i-abcd1234 (8 or 17 char, hex)
# We have it buffered to 32 chars to futureproof any further EC2 format changes (given some other EC2 resources are already 32 char)
/bin/echo "${instance}" | /usr/bin/head -n 1 | /bin/grep -Eq "^i-[0-9a-f]{8,32}$" || exit 0
# Verify we have an EC2 uuid
if [ ! -f /sys/hypervisor/uuid ] ; then
# Nitro, switch to DMI check
if [ ! -f /sys/devices/virtual/dmi/id/board_asset_tag ] ; then
# We're out of options. This is definitely not an instance.
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect was invoked on a non-instance and will do nothing."
exit 0
elif [ "$(/bin/cat /sys/devices/virtual/dmi/id/board_asset_tag)" != "${instance}" ] ; then
# The board_asset_tag does not match the instance id. This is not a valid instance.
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect was invoked on a non-instance and will do nothing."
exit 0
fi
elif [ "$(/usr/bin/cut -c1-3 < /sys/hypervisor/uuid)" != "ec2" ] ; then
# Leading bytes are not "ec2"
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect was invoked on a non-instance and will do nothing."
exit 0
fi
# At this point we're reasonably confident we're running on an EC2 instance.
OPENSSL=/usr/bin/openssl
if [ -z "${1}" ] ; then
# No user provided, not really anything to query for. Fail out.
/usr/bin/logger -i -p authpriv.info "EC2 Instance Connect was invoked without a user to authorize and will do nothing."
exit 1
fi
/usr/bin/id -u "${1}" > /dev/null 2>&1
id_exit="${?}"
if [ "${id_exit}" -ne 0 ] ; then
# User doesn't actually exist. Let sshd deal with it.
exit 0
fi
# Verify that we have active keys. Fast-exit if we do not.
keys_status="$(/usr/bin/curl -s -f -m 1 -H "${IMDS_TOKEN_HEADER}" -o /dev/null -I -w %{http_code} "${IMDS}/managed-ssh-keys/active-keys/${1}/")"
if [ "${keys_status}" != "200" ]
then
# No keys for this user. Nothing to do.
exit 0
fi
# We are not checking format here - that is parse_authorized_keys's job
zone=$(curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/placement/availability-zone/")
zone_exit="${?}"
if [ "${zone_exit}" -ne 0 ]
then
exit "${zone_exit}"
fi
# Validate the zone is aa-bb-#c (or aa-bb-cc-#d for special partitions like AWS GovCloud)
/bin/echo "${zone}" | /usr/bin/head -n 1 | /bin/grep -Eq "^([a-z]+-){2,3}[0-9][a-z]$" || exit 255
region=$(/bin/echo "${zone}" | /bin/sed -n 's/\(\([a-z]\+-\)\+[0-9]\+\).*/\1/p')
domain=$(curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/services/domain/")
domain_exit="${?}"
if [ "${domain_exit}" -ne 0 ]
then
exit "${domain_exit}"
fi
expected_signer=$(/usr/bin/printf 'managed-ssh-signer.%s.%s' "${region}" "${domain}")
userpath=$(/bin/mktemp -d /dev/shm/eic-XXXXXXXX)
trap 'rm -rf "${userpath:?}"' EXIT
# Read the current signer cert
# This will overwrite whatever currently exists, so it will remain up-to-date
certificate=$(curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/managed-ssh-keys/signer-cert/")
cert_exit="${?}"
if [ "${cert_exit}" -ne 0 ] || [ -z "${certificate}" ]
then
exit "${cert_exit}"
fi
# parse_authorized_keys will verify this
# Read the signer OCSP staples
staple_paths=$(curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/managed-ssh-keys/signer-ocsp/")
staple_exit="${?}"
if [ "${staple_exit}" -ne 0 ]
then
exit "${staple_exit}"
fi
ocsp_path=$(/bin/mktemp -d "${userpath}/eic-ocsp-XXXXXXXX")
for word in $staple_paths
do
curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/managed-ssh-keys/signer-ocsp/${word}" | /usr/bin/base64 -d > "${ocsp_path}/${word}"
staple_exit="${?}"
if [ "${staple_exit}" -ne 0 ]
then
exit "${staple_exit}"
fi
/bin/chmod 400 "${ocsp_path}/${word}" # Disable access to staple file
done
# parse_authorized_keys will verify these
# Invoke key parser (will automagically echo the results)
keys_file="${userpath}/eic-keys"
curl_cmd "${IMDS_TOKEN_HEADER}" "${IMDS}/managed-ssh-keys/active-keys/${1}/" > "${keys_file}"
DIR="$( cd "$( dirname "${0}" )" && pwd )"
ca_path=/etc/ssl/certs
if [ -z "${2}" ] ; then
output="$("${DIR}/eic_parse_authorized_keys" -x false -p "${keys_file}" -o "${OPENSSL}" -d "${userpath}" -s "${certificate}" -i "${instance}" -c "${expected_signer}" -a "${ca_path}" -v "${ocsp_path}")"
exitcode=$? # not quote-escaped since this must be numeric 0-255
else
output="$("${DIR}/eic_parse_authorized_keys" -x false -p "${keys_file}" -o "${OPENSSL}" -d "${userpath}" -s "${certificate}" -i "${instance}" -c "${expected_signer}" -a "${ca_path}" -v "${ocsp_path}" -f "${2}")"
exitcode=$? # not quote-escaped since this must be numeric 0-255
fi
/bin/echo "${output}"
exit $exitcode