From 2c190e4950bbcccd9f4681db1456c007129d4ea8 Mon Sep 17 00:00:00 2001 From: LordAlfredo Date: Tue, 23 Oct 2018 15:24:46 -0700 Subject: [PATCH] Fixing license year Improving SSL certificate bundle handling to support different /etc/ssl/cert structures --- README.md | 2 + bin/configure_sshd.sh | 2 +- bin/make_tarball.sh | 2 +- bin/modify_amazon_linux.sh | 18 +++++++++ bin/reset_sshd.sh | 2 +- bin/test/generate_ocsp.sh | 2 +- bin/test/run_authorized_keys_tests.sh | 2 +- bin/test/setup_certificates.sh | 2 +- bin/test/sign_data.sh | 2 +- bin/test/test_authorized_keys.sh | 2 +- src/opt/aws/bin/curl_authorized_keys | 15 ++++--- src/opt/aws/bin/parse_authorized_keys | 57 ++++++++++++++++++++------- 12 files changed, 80 insertions(+), 28 deletions(-) create mode 100755 bin/modify_amazon_linux.sh diff --git a/README.md b/README.md index cccb93f..962ca63 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This package contains the EC2 instance configuration and scripts necessary to enable AWS EC2 Instance Connect. +This package does *not* include the build configuration or packaging for EC2's package repositories - such packaging is handled by the Amazon Linux maintainers. + ## AuthorizedKeysCommand The AuthorizedKeysCommand is split into two parts, both under src/opt/aws/bin/ diff --git a/bin/configure_sshd.sh b/bin/configure_sshd.sh index a494299..ac0beb2 100755 --- a/bin/configure_sshd.sh +++ b/bin/configure_sshd.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/make_tarball.sh b/bin/make_tarball.sh index c600251..2dd934c 100755 --- a/bin/make_tarball.sh +++ b/bin/make_tarball.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/modify_amazon_linux.sh b/bin/modify_amazon_linux.sh new file mode 100755 index 0000000..fd5578d --- /dev/null +++ b/bin/modify_amazon_linux.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Copyright 2018 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. + +# Amazon Linux has its installed CAs in a single file called "ca-bundle.crt". We point to that directly instead of just the ssl certs dir. + +/bin/sed -ir "/^ca_path=\/etc\/ssl\/certs$/cca_path=\/etc\/ssl\/certs\/ca-bundle.crt" /opt/aws/bin/curl_authorized_keys diff --git a/bin/reset_sshd.sh b/bin/reset_sshd.sh index eb2c90b..79975f6 100644 --- a/bin/reset_sshd.sh +++ b/bin/reset_sshd.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/test/generate_ocsp.sh b/bin/test/generate_ocsp.sh index 1653979..6ce3251 100755 --- a/bin/test/generate_ocsp.sh +++ b/bin/test/generate_ocsp.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/test/run_authorized_keys_tests.sh b/bin/test/run_authorized_keys_tests.sh index 2d785a9..a77be88 100755 --- a/bin/test/run_authorized_keys_tests.sh +++ b/bin/test/run_authorized_keys_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/test/setup_certificates.sh b/bin/test/setup_certificates.sh index 2fc4a0c..a06c792 100755 --- a/bin/test/setup_certificates.sh +++ b/bin/test/setup_certificates.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/test/sign_data.sh b/bin/test/sign_data.sh index d68b0e6..7a2477a 100755 --- a/bin/test/sign_data.sh +++ b/bin/test/sign_data.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/bin/test/test_authorized_keys.sh b/bin/test/test_authorized_keys.sh index eb38174..235e99a 100755 --- a/bin/test/test_authorized_keys.sh +++ b/bin/test/test_authorized_keys.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 diff --git a/src/opt/aws/bin/curl_authorized_keys b/src/opt/aws/bin/curl_authorized_keys index 7cebc56..97f55d0 100755 --- a/src/opt/aws/bin/curl_authorized_keys +++ b/src/opt/aws/bin/curl_authorized_keys @@ -18,12 +18,15 @@ # Reads and echoes EC2 Metadata to get the authorized keys blob for the user $1 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 if [ $? -ne 0 ] ; then - exit 1 + # User doesn't actually exist. Let sshd deal with it. + exit 0 fi userpath=$(/bin/mktemp -d /dev/shm/tmp-XXXXXXXX) @@ -35,10 +38,11 @@ keysfile=allowed-keys OPENSSL=/usr/bin/openssl curl_cmd="/usr/bin/curl -s -f -m 1" -# Verify that we have active keys. Fast-fail if we do not. +# Verify that we have active keys. Fast-exit if we do not. if [ $(eval "${curl_cmd} -o /dev/null -I -w %{http_code} http://169.254.169.254/latest/meta-data/managed-ssh-keys/active-keys/${1}/") -eq 404 ] then - exit 255 + # No keys for this user. Nothing to do. + exit 0 fi # Read the current signer cert @@ -91,11 +95,12 @@ expected_signer=$(/usr/bin/printf 'managed-ssh-signer.%s.%s' "${region}" "${doma # Invoke key parser (will automagically echo the results) curl_command="${curl_cmd} http://169.254.169.254/latest/meta-data/managed-ssh-keys/active-keys/${1}/" DIR="$( cd "$( dirname "${0}" )" && pwd )" +ca_path=/etc/ssl/certs if [ -z "${2}" ] ; then - output=$($DIR/parse_authorized_keys -x false -r "${curl_command}" -o "${OPENSSL}" -d "${userpath}" -s "${certificate}" -i "${instance}" -c "${expected_signer}" -a "/etc/ssl/certs/ca-bundle.crt" -v "${ocsp_path}") + output=$($DIR/parse_authorized_keys -x false -r "${curl_command}" -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/parse_authorized_keys -x false -r "${curl_command}" -o "${OPENSSL}" -d "${userpath}" -s "${certificate}" -i "${instance}" -c "${expected_signer}" -a "/etc/ssl/certs/ca-bundle.crt" -v "${ocsp_path}" -f "${2}") + output=$($DIR/parse_authorized_keys -x false -r "${curl_command}" -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 diff --git a/src/opt/aws/bin/parse_authorized_keys b/src/opt/aws/bin/parse_authorized_keys index a3087ba..9c31249 100755 --- a/src/opt/aws/bin/parse_authorized_keys +++ b/src/opt/aws/bin/parse_authorized_keys @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2018 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 @@ -13,7 +13,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -# EC2 Instance Connect AuthorizedKeysCommand v 1.0.0 +# EC2 Instance Connect AuthorizedKeysCommand v 1.0.1 # Reads authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 @@ -47,7 +47,7 @@ removeprefix () { verifyocsp() { # First check if this cert is already trusted cname=$($2 x509 -noout -subject -in $3 2>/dev/null | /bin/sed -n -e 's/^.*CN=//p') - fingerprint=$($2 x509 -noout -fingerprint -sha1 -inform pem -in $3 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint=\(.*\)/\1/p' | tr -d ':') + fingerprint=$($2 x509 -noout -fingerprint -sha1 -inform pem -in $3 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint[[:space:]]*=[[:space:]]*\(.*\)/\1/p' | tr -d ':') ocsp_out=$($2 ocsp -no_nonce -issuer $4 -cert $3 -VAfile $4 -respin $5/$fingerprint 2>/dev/null) if [ $? -ne 0 ] || ! startswith "${ocsp_out}" "${3}: good" ; then fail $1 "EC2 Instance Connect could not verify certificate ${cname} has not been revoked. No keys have been trusted." @@ -109,34 +109,61 @@ fi echo "${signer}" | /usr/bin/awk -v dir="${tmpdir}" 'split_after==1{n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > dir "/cert" n ".pem"}' # We want visibility into the CA bundle so we can skip verifying entries in the chain that are already trusted +if [ -d "${ca_path}" ] ; then + ca_path_dir=$ca_path +else + ca_path_dir=$(dirname "${ca_path}") +fi ca_bundles_dir=$(/bin/mktemp -d $tmpdir/tmp-XXXXXXXX) /bin/chmod 700 $ca_bundles_dir end=$(/usr/bin/find $tmpdir -maxdepth 1 -type f -name "cert*.pem" -regextype sed -regex ".*/cert[0-9]\+\.pem" | wc -l) if [ $(/usr/bin/expr $end) -gt 0 ] ; then + # First see if we already have them + exist=true for i in `/usr/bin/seq 1 $end` ; do - subject=$($OPENSSL x509 -noout -subject -in "${tmpdir}/cert$i.pem" | /bin/sed -n -e 's/^.*CN=//p') - # Try to pull this CN from the CA bundle - /bin/sed -n -e '/#[[:space:]]'"$subject"'$/,$p' "${ca_path}" | /bin/sed '/-----END[[:space:]]CERTIFICATE-----.*/,$d' | /bin/sed -n '1!p' > "${ca_bundles_dir}/${subject}" - if [ -s "${ca_bundles_dir}/${subject}" ] ; then - /bin/echo "-----END CERTIFICATE-----" >> "${ca_bundles_dir}/${subject}" + subject=$($OPENSSL x509 -noout -subject -in "${tmpdir}/cert$i.pem" | /bin/sed -n -e 's/^.*CN[[:space:]]*=[[:space:]]*//p') + underscored=$(/bin/echo "${subject// /_}") 2>/dev/null + if [ -f "${ca_path_dir}/${underscored}.pem" ] ; then + # We already have it + /bin/cp "${ca_path_dir}/${subject}.pem" "${ca_bundles_dir}/${subject}" else - /bin/rm -f "${ca_bundles_dir}/${subject}" + if [ ! -d "${ca_path}" ] ; then + # Try to pull this CN from the CA bundle + /bin/sed -n -e '/#[[:space:]]'"$subject"'$/,$p' "${ca_path}" 2>/dev/null | /bin/sed '/-----END[[:space:]]CERTIFICATE-----.*/,$d' | /bin/sed -n '1!p' > "${ca_bundles_dir}/${subject}" + if [ -s "${ca_bundles_dir}/${subject}" ] ; then + /bin/echo "-----END CERTIFICATE-----" >> "${ca_bundles_dir}/${subject}" + else + /bin/rm -f "${ca_bundles_dir}/${subject}" + fi + fi fi done fi # Build the intermediate trust chain -cat $(/usr/bin/find $tmpdir -maxdepth 1 -type f -name "cert*.pem" -regextype sed -regex ".*/cert[0-9]\+\.pem$") "${ca_path}" > $tmpdir/ca-trust.pem +cat $(/usr/bin/find $tmpdir -maxdepth 1 -type f -name "cert*.pem" -regextype sed -regex ".*/cert[0-9]\+\.pem$") > $tmpdir/ca-trust.pem +if [ -d "${ca_path}" ] ; then + subject=$($OPENSSL x509 -noout -subject -in "${tmpdir}/cert$end.pem" | /bin/sed -n -e 's/^.*CN[[:space:]]*=[[:space:]]*//p') + underscored=$(/bin/echo "${subject// /_}") + cat "${ca_bundles_dir}/${underscored}" >> $tmpdir/ca-trust.pem +else + cat "${ca_path}" >> $tmpdir/ca-trust.pem +fi /bin/chmod 400 "${tmpdir}/ca-trust.pem" # Verify the CN -signer_cn=$($OPENSSL x509 -noout -subject -in $tmpdir/cert.pem | /bin/sed -n -e 's/^.*CN=//p') +signer_cn=$($OPENSSL x509 -noout -subject -in $tmpdir/cert.pem | /bin/sed -n -e 's/^.*CN[[:space:]]*=[[:space:]]*//p') if [ "${signer_cn}" != "${expected_cn}" ] ; then fail $is_debug "EC2 Instance Connect encountered an unrecognized signer certificate. No keys have been trusted." fi # Verify the trust chain -verify_out=$($OPENSSL verify -x509_strict -CApath /dev/null -CAfile $tmpdir/ca-trust.pem $tmpdir/cert.pem) +if [ -d "${ca_path}" ] ; then + ca_path_option="${ca_path}" +else + ca_path_option="/dev/null" +fi +verify_out=$($OPENSSL verify -x509_strict -CApath ${ca_path_option} -CAfile $tmpdir/ca-trust.pem $tmpdir/cert.pem) if [ $? -ne 0 ] || [ "${verify_out}" != "${tmpdir}/cert.pem: OK" ] ; then fail $is_debug "EC2 Instance Connect could not verify the signer trust chain. No keys have been trusted." fi @@ -145,13 +172,13 @@ fi # Iterate from first to second-to-last cert & validate OCSP staples /bin/mv $tmpdir/cert.pem $tmpdir/cert0.pem # Better naming consistency for loop for i in `/usr/bin/seq 0 $(( $end - 1 ))` ; do - subject=$($OPENSSL x509 -noout -subject -in "${tmpdir}/cert${i}.pem" | /bin/sed -n -e 's/^.*CN=//p') + subject=$($OPENSSL x509 -noout -subject -in "${tmpdir}/cert${i}.pem" | /bin/sed -n -e 's/^.*CN[[:space:]]*=[[:space:]]*//p') if [ -f "${ca_bundles_dir}/${subject}" ] ; then # If we encounter a certificate that's in the CA bundle we can skip the rest as implicitly trusted hash=$($OPENSSL x509 -hash -noout -in "${tmpdir}/cert${i}.pem" 2>/dev/null) trusted_hash=$($OPENSSL x509 -hash -noout -in "${ca_bundles_dir}/${subject}" 2>/dev/null) - fingerprint=$($OPENSSL x509 -noout -fingerprint -sha1 -in "${tmpdir}/cert${i}.pem" 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint=\(.*\)/\1/p' | tr -d ':') - trusted_fingerprint=$($OPENSSL x509 -noout -fingerprint -sha1 -in "${ca_bundles_dir}/${subject}" 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint=\(.*\)/\1/p' | tr -d ':') + fingerprint=$($OPENSSL x509 -noout -fingerprint -sha1 -in "${tmpdir}/cert${i}.pem" 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint[[:space:]]*=[[:space:]]*\(.*\)/\1/p' | tr -d ':') + trusted_fingerprint=$($OPENSSL x509 -noout -fingerprint -sha1 -in "${ca_bundles_dir}/${subject}" 2>/dev/null | /bin/sed -n 's/SHA1 Fingerprint[[:space:]]*=[[:space:]]*\(.*\)/\1/p' | tr -d ':') pkey=$($OPENSSL x509 -pubkey -noout -in "${tmpdir}/cert${i}.pem") trusted_pkey=$($OPENSSL x509 -pubkey -noout -in "${ca_bundles_dir}/${subject}" ) if [ "${hash}" = "${trusted_hash}" ] && [ "${fingerprint}" = "${trusted_fingerprint}" ] && [ "${pkey}" = "${trusted_pkey}" ] ; then