aws-ec2-instance-connect-config-1.1.12/000077500000000000000000000000001361013163600175315ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/.github/000077500000000000000000000000001361013163600210715ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000002511361013163600246700ustar00rootroot00000000000000*Issue #, if available:* *Description of changes:* By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. aws-ec2-instance-connect-config-1.1.12/CODE_OF_CONDUCT.md000066400000000000000000000004671361013163600223370ustar00rootroot00000000000000## Code of Conduct This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. aws-ec2-instance-connect-config-1.1.12/CONTRIBUTING.md000066400000000000000000000071031361013163600217630ustar00rootroot00000000000000# Contributing Guidelines Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional documentation, we greatly value feedback and contributions from our community. Please read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution. ## Reporting Bugs/Feature Requests We welcome you to use the GitHub issue tracker to report bugs or suggest features. When filing an issue, please check [existing open](https://github.com/awslabs/aws-ec2-instance-connect-config/issues), or [recently closed](https://github.com/awslabs/aws-ec2-instance-connect-config/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: * A reproducible test case or series of steps * The version of our code being used * Any modifications you've made relevant to the bug * Anything unusual about your environment or deployment ## Contributing via Pull Requests Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 1. You are working against the latest source on the *master* branch. 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. To send us a pull request, please: 1. Fork the repository. 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 3. Ensure local tests pass. 4. Commit to your fork using clear commit messages. 5. Send us a pull request, answering any default questions in the pull request interface. 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). ## Finding contributions to work on Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-ec2-instance-connect-config/labels/help%20wanted) issues is a great place to start. ## Code of Conduct This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. ## Security issue notifications If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. ## Licensing See the [LICENSE](https://github.com/awslabs/aws-ec2-instance-connect-config/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. aws-ec2-instance-connect-config-1.1.12/LICENSE000066400000000000000000000261361361013163600205460ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License 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. aws-ec2-instance-connect-config-1.1.12/Makefile000066400000000000000000000006631361013163600211760ustar00rootroot00000000000000VERSION_FILE=./VERSION pkgver=$(shell cat $(VERSION_FILE)) version = $(firstword $(subst -, ,$(pkgver))) release = $(lastword $(subst -, ,$(pkgver))) default: clean ; deb: ./bin/make_deb.sh $(version) $(release) rpm: ./bin/make_rpm.sh $(version) $(release) clean: $(shell rm -rf ec2-instance-connect*) $(shell rm -rf ./rpmbuild/SOURCES) $(shell rm -rf ./deb-src) $(shell rm -rf ./srpm_results) $(shell rm -rf ./rpm_results) aws-ec2-instance-connect-config-1.1.12/NOTICE000066400000000000000000000001511361013163600204320ustar00rootroot00000000000000AWS Ec2 Instance Connect Config Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. aws-ec2-instance-connect-config-1.1.12/README.md000066400000000000000000000217131361013163600210140ustar00rootroot00000000000000# AWS EC2 Instance Connect Configuration This package contains the EC2 instance configuration and scripts necessary to enable AWS EC2 Instance Connect. ## AuthorizedKeysCommand The AuthorizedKeysCommand is split into three parts: * eic_run_authorized_keys is the main entry point and wraps the rest in a 5 second timeout * eic_curl_authorized_keys, which is the entry point for sshd on an ssh call * eic_parse_authorized_keys, which is the main authorized keys command logic This split is intentional - as parse takes all necessary pieces as command inputs is can be unit tested independently. curl, however, obviously needs to curl EC2 Instance Metadata Service and so cannot be tested without mocking the actual service. ### eic_curl_authorized_keys The curl script verifies we are actually running on an EC2 instance and cURLs relevant information from EC2 Instance Metadata Service and send it to parse. Note that it must make several curl commands to proceed. If it cannot do so it fast-fails to prevent blocking the ssh daemon. The command also queries several OCSP staples from EC2 Instance Metadata Service. These OCSP staples are provided from the AWS EC2 Instance Connect Service to avoid needing to query each CRL or OCSP authority at ssh calltime as that would have major performance implications. The staples are passed to and used by parse_authorized_keys to check certificate validity without the need for extra external calls. ### eic_parse_authorized_keys In addition to the fields required to complete all the below process, a key fingerprint may be provided. If a key fingerprint is specified then only ssh keys found matching that fingerprint will be returned. #### Certificate Validation The core idea behind AWS EC2 Instance Connect is that all ssh keys vended have been trusted by AWS. This can be verified by checking each key's signature (more on that later) and vetting the signing certificate used. The signing certificate goes through a deep verification flow that checks: * The CN matches the service * The certificate trust chain can be verified up through the Amazon Trust Services Certificate Authority * The entire certificate chain is valid - ie, none of them have been revoked The first and second are done via standard openssl checks. The third, however, does not query the relevant CRLs or OCSP authorities at runtime to avoid adding a network call to sshd. Instead, OCSP staples are expected to be provided by the invoker (i.e., eic_curl_authorized_keys). As OCSP staples are cryptographically signed and can be verified against a trusted authority these are considered a sufficient validity check. #### Key Processing The keys are expected to be presented to the script in the format
# Key Metadata
# Key Metadata
# Key Metadata
[ssh key]
signature
Currently, the expected metadata is, in order, 1. Expiration timestamp 2. Instance ID 3. IAM Caller 4. Request ID Once this data has been loaded, the following checks are run: * Has the expiration timestamp passed? * Is the instance ID correct? * Does the signature match the provided data? * If a specific key fingerprint was provided to search for, does this key match that fingerprint? The signature is specifically expected to be for the *entire* key blob - all metadata entries plus the ssh key. It should have been generated by the AWS EC2 Instance Connect service's private key, which is verified using the vetted signing certificate. If all of these checks pass then the key will be presented to the ssh daemon. Otherwise, it will be ignored and the next key will be processed. Any time a key is provided to the ssh daemon it will be logged to the system authpriv log for auditing purposes. ## Host Key Harvesting The fourth script, eic_harvest_hostkeys, has no direct relation to the AuthorizedKeysCommand. Instead, it is used to pass the instance's ssh host keys back to the EC2 Instance Connect Service. This is necessary to establish trust for the EC2 Console for the console's one-click in-browser ssh terminal feature. ### systemd Module The systemd module provided for host key harvesting is a basic one-shot to invoke eic_harvest_hostkeys. ### eic_harvest_host_keys The host key harvesting script has to run similar logic to eic_curl_authorized_keys to get some basic information from Instance Metadata Service about the instance itself. It then reads the ssh host keys on the machine, then creates and signs an AWS Signature Version 4 Request to ## Unit Testing As parse_authorized_keys requires a valid certificate, CA, and OCSP staples, unit testing is a somewhat involved process. This has been automated to a convenient entry point: `bin/unit_test_suite.sh`. This will 1. Invoke `bin/unit-test/setup_certificates.sh` to generate a test CA and trust chain 2. Invoke `bin/unit-test/generate_ocsp.sh` to generate OCSP staples for the certificates 3. Iterate over unit-test/input/direct and unit-test/input/unsigned and test all entries via `bin/unit-test/test_authorized_keys.sh`, expecting the matching contents of unit-test/expected-output unit-test/input/direct's contents are passed directly as-is as they are not expected to contain valid signatures. unit-test/input/unsigned's contents, however, are expected to get far enough in the process to (potentially) need a valid signature. As such, signatures are generated on-the-fly using the pre-generated certificate's private key. The structure of unit-test/input/unsigned, rather than files, is directories to test. The directory's contents should be in a numeric order that the test script will iterate. Each file should have *one* test key blob to sign. The actual test input will be the result of generating signatures for each file and constructing an imitation of the service's key bundle. ## End-to-End Testing Integration testing requires running these scriptlets on an actual EC2 instance. This has been scripted for your convenience. To run integration tests against a given platform (eg, RHEL or Ubuntu): 1. Build a test package (for example, `make deb`) 2. Select an AMI of the platform you desire (for example, the latest Ubuntu AMI) 3. Configure your VPC for testing * Configure an EC2 keypair. Make sure to save the private key! * Configure your security group to allow SSH from your test-run machine * Set your subnet to auto-assign public IPs. Testing currently requires SSHing via public IP. 4. Determine the appropriate EC2 username for your platform (see below) 5. Determine the "config name" for your platform (see below) 6. Determine instance types you would like to test (or all supported in your subnet's zone) 7. The actual tests are invoked by the following command: `./bin/integration_test_suite.sh -r [region] -a [ami id] -u [ec2 username] -k [ec2 keypair name] -s [subnet id] -g [security group id] -l [config name] -p [/path/to/private/key] -i [/path/to/test/package] [-t [instance,type,list]] [-d [/output/directory]]` This will run all tests under the integration-test/test directory against all requested instance types (or all types in the zone if not specified). Any error output will be written in files pathed /path/instance-type/test-name in the output directory. An output directory will be autogenerated if none is specified. EC2 usernames and "config names" for each supported platform is as follows: | Platform | EC2 Username | "Config" Name | | --- | --- | --- | | Amazon Linux | ec2-user | amazon-linux | | Ubuntu | ubuntu | ubuntu | | RHEL | ec2-user | rhel | Again, please note that if you do not specify instance types then all supported by the subnet's zone will be run. This can take a very long time. It is therefore recommended you specify at least one Nitro and at least one non-Nitro instance type, such as t2.micro and m5.large. ## Building RPM/Debian Packaging If desired, this scripting can be added to an EC2 instance for further testing. A convenience pair of scripts - bin/make_rpm.sh and bin/make_deb.sh - have been provided to quickly build test packages. Each may be invoked via `make rpm` and `make deb` respectively. Debian packaging in particular requires you have a GPG key configured on your system. Be sure to update VERSION! If you use the same VERSION as the latest public release then test instances will not see it as an update! **Debian packaging tools are intended for testing purposes only. Please follow standard Debian process to submit patches.** ### Why is it generic.rpm? "generic.rpm" is used internally to differentiate the specfile for Fedora/RHEL/CentOS from Amazon Linux. There is a separate Amazon-proprietary rpmspec and build process optimized for Amazon Linux. ## Why UNIX shell? This package is intended as a simple reference implementation of the instance-side pieces of the EC2 Instance Connect feature, though as time has gone on it has become much more complex than originally intended. Amazon is considering reimplementation in another language for the future but for the time being we will continue to iterate on the shell implementation. ## License This library is licensed under the Apache 2.0 License. aws-ec2-instance-connect-config-1.1.12/VERSION000066400000000000000000000000071361013163600205760ustar00rootroot000000000000001.1-12 aws-ec2-instance-connect-config-1.1.12/bin/000077500000000000000000000000001361013163600203015ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/bin/integration-test/000077500000000000000000000000001361013163600236015ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/bin/integration-test/get_zone_instance_types.sh000077500000000000000000000021231361013163600310600ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Load the list of instance types supported in a given zone. # XXX: The mechanism for this is based on reserved instances. This may not be exhaustive in every zone. region=$1 zone=$2 raw=$(aws ec2 describe-reserved-instances-offerings --filters "Name=availability-zone,Values=$zone" --region "${region}") types=$(echo "{$raw}" | grep "InstanceType" | cut -d '"' -f 4) echo "${types}" aws-ec2-instance-connect-config-1.1.12/bin/integration-test/run_instance.sh000077500000000000000000000063121361013163600266320ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Attempts to launch an instance to the given specification # Outputs instance ID on success or where it failed otherwise while getopts ":t:r:a:k:s:g:n:o:p:" opt ; do case "${opt}" in t) instance_type="${OPTARG}" ;; r) region="${OPTARG}" ;; a) ami_id="${OPTARG}" ;; k) key_name="${OPTARG}" ;; s) subnet_id="${OPTARG}" ;; g) security_group_id="${OPTARG}" ;; n) name_tag="${OPTARG}" ;; o) osuser="${OPTARG}" ;; p) private_key="${OPTARG}" ;; *) echo "Usage: $0 -t instance-type -r aws-region -a ami -k ec2-key-pair -s subnet -g security-group -n name-tag-value" exit 1 ;; esac done launch_output=$(aws ec2 run-instances --region "${region}" --image-id "${ami_id}" --key-name "${key_name}" --security-group-ids "${security_group_id}" --subnet-id "${subnet_id}" --instance-initiated-shutdown-behavior "terminate" --instance-type "${instance_type}" --tag-specifications "[{\"ResourceType\":\"instance\",\"Tags\":[{\"Key\":\"Name\",\"Value\":\"${name_tag}\"}]}]") launch_code=$? if [ "${launch_code}" -ne 0 ] ; then echo "Instance launch failed!" exit "${launch_code}" fi instance_id=$(echo "${launch_output}" | grep \"InstanceId\" | cut -d '"' -f 4) running=0 try="0" # Wait up to 5 minutes for the instance to come up, checking every 5 seconds while [ $try -lt 60 ] ; do aws ec2 describe-instances --instance-ids "${instance_id}" | grep "Name" | grep -q "running" launch_code=$? if [ "${launch_code}" -eq 0 ] ; then try="60" running=1 else try=$((try+1)) sleep 5 fi done if [ $running -eq 0 ] ; then echo "Timed out waiting for instance to enter 'running' state" exit 1 fi # Wait a bit extra to let sshd come up ssh_try="0" public_ip=$(aws ec2 describe-instances --instance-ids "${instance_id}" | grep "PublicIp" | cut -d '"' -f 4 | uniq) while [ $ssh_try -lt 30 ] ; do ssh -q -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" exit 2>&1 launch_code="${?}" if [ "${launch_code}" -eq 0 ] ; then # Everything's ready echo "${instance_id}" exit 0 fi ssh_try=$((ssh_try+1)) sleep 10 done echo "Timed out waiting for sshd to start on instance (or keypair is misconfigured)" exit 1 aws-ec2-instance-connect-config-1.1.12/bin/integration-test/run_test_sweep.sh000077500000000000000000000036071361013163600272140ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 TOPDIR=$(dirname "$( cd "$( dirname "$( dirname "${BASH_SOURCE[0]}" )" )" && pwd)") while getopts ":i:p:k:u:z:o:l:f:" opt ; do case "${opt}" in i) instance_id="${OPTARG}" ;; p) public_ip="${OPTARG}" ;; k) keypath="${OPTARG}" ;; u) osuser="${OPTARG}" ;; z) zone="${OPTARG}" ;; o) output_directory="${OPTARG}" ;; l) distro="${OPTARG}" ;; f) package_path="${OPTARG}" ;; *) ;; esac done overall_success=0 for testscript in "${TOPDIR}"/integration-test/test/* ; do filename="${testscript##*/}" test_output=$($testscript -i "${instance_id}" -p "${public_ip}" -z "${zone}" -u "${osuser}" -k "${keypath}" -l "${distro}" -t "${package_path}") test_exit="${?}" if [ "${test_exit}" -ne 0 ] ; then echo "${test_output}" > "${output_directory}/${filename}" echo "Test ${filename} FAILED" overall_success=1 else echo "Test ${filename} PASSED" fi done exit "${overall_success}" aws-ec2-instance-connect-config-1.1.12/bin/integration_test_suite.sh000077500000000000000000000144211361013163600254350ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Runs our full suite of integration tests against all known instance types # Basic string concat w/ newline concat () { printf "%s\n%s" "${1}" "${2}" } TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)") if [ $# -lt 8 ] ; then echo "Usage: $0 -r region -a ami -k ec2-key-pair -s subnet -g security-group -p /private/key/path -u ec2-os-user -l ami-linux-distro-name -i /path/to/package/file [-d /test/output/directory] [-t instance,types,list]" exit 1 fi types_specified=0 while getopts ":r:a:k:s:g:d:p:t:u:l:i:" opt ; do case "${opt}" in r) region="${OPTARG}" ;; a) ami_id="${OPTARG}" ;; k) key_name="${OPTARG}" ;; s) subnet_id="${OPTARG}" ;; g) security_group_id="${OPTARG}" ;; d) output_directory="${OPTARG}" ;; p) private_key="${OPTARG}" ;; t) IFS=',' read -r -a instance_types <<< "${OPTARG}" types_specified=1 ;; u) osuser="${OPTARG}" ;; l) distro="${OPTARG}" ;; i) package_path="${OPTARG}" ;; *) echo "Usage: $0 -r region -a ami -k ec2-key-pair -s subnet -g security-group -p /private/key/path -u ec2-os-user -l ami-linux-distro-name -i /path/to/package/file [-d /test/output/directory] [-t instance,types,list]" exit 1 ;; esac done # Ensure we have config for this distro if [ ! -f "${TOPDIR}/integration-test/config/${distro}" ] ; then echo "Unsupported distro ${distro} will not be tested" exit 1 fi source "${TOPDIR}/integration-test/config/${distro}" package_name="${package_path##*/}" if [ -z "${output_directory}" ] ; then timestamp=$(/bin/date -u "+%Y-%m-%d_%H:%M:%S") # TODO: Better autogenerated directory. Include AMI/test name? output_directory="/tmp/eic_integ_test_${timestamp}" echo "No output directory set. Creating & using ${output_directory}" mkdir "${output_directory}" fi # Fetch information about the subnet (AZ, etc) subnet_output=$(aws ec2 describe-subnets --subnet-ids "${subnet_id}") subnet_status=$? if [ "${subnet_status}" -ne 0 ] ; then echo "Failed to query subnet information:" echo "${subnet_output}" exit "${subnet_status}" fi zone=$(echo "${subnet_output}" | grep "\"AvailabilityZone\"" | cut -d '"' -f 4) if [ $types_specified -eq 0 ] ; then echo "Instance types not specified. Will test all supported in this subnet." instance_types=$("${TOPDIR}/bin/integration-test/get_zone_instance_types.sh" "${region}" "${zone}") IFS=$'\n' read -d '' -r -a instance_types <<< "${instance_types}" fi overall_exit=0 for instance_type in "${instance_types[@]}" ; do echo "Testing ${instance_type}" mkdir "${output_directory}/${instance_type}" output="" instance_exit=0 # Run instance launch_output=$("${TOPDIR}/bin/integration-test/run_instance.sh" -t "${instance_type}" -a "${ami_id}" -k "${key_name}" -s "${subnet_id}" -g "${security_group_id}" -n "EIC Integration Test ${instance_type}" -r "${region}" -o "${osuser}" -p "${private_key}") launch_status=$? if [ "${launch_status}" -ne 0 ] ; then output=$(concat "${output}" "${launch_output}") instance_exit=1 else instance_id=$launch_output public_ip=$(aws ec2 describe-instances --instance-ids "${instance_id}" | grep "PublicIp" | cut -d '"' -f 4 | uniq) # scp the package file to the instance and install it output=$(concat "${output}" "scping package file to instance") scp_out=$(scp -i "${private_key}" -o StrictHostKeyChecking=no "${package_path}" "${osuser}@${public_ip}:/tmp/${package_name}" 2>&1) install_status=$? output=$(concat "${output}" "${scp_out}") if [ "${install_status}" -eq 0 ] ; then # FIXME: Ubuntu AMIs fail here due to dpkg lock contention ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" "${INSTALL} /tmp/${package_name}" 1>/dev/null 2>&1 install_status=$? output=$(concat "${output}" "${scp_out}") else output=$(concat "${output}" "Failed to scp package to instance.") instance_exit=1 fi if [ "${install_status}" -ne 0 ] ; then output=$(concat "${output}" "Failed to install EIC package on instance.") instance_exit=1 else # Run the actual tests "${TOPDIR}/bin/integration-test/run_test_sweep.sh" -i "${instance_id}" -p "${public_ip}" -k "${private_key}" -u "${osuser}" -z "${zone}" -o "${output_directory}/${instance_type}" -l "${distro}" -f "${package_path}" test_exit=$? if [ "${test_exit}" -ne 0 ] ; then overall_exit=1 else rmdir "${output_directory}/${instance_type}" fi fi # Terminate the instance aws ec2 terminate-instances --instance-ids "${instance_id}" 1>/dev/null fi if [ "${instance_exit}" -ne 0 ] ; then echo "Could not run tests on instance." echo "${output}" > "${output_directory}/${instance_type}/setup" overall_exit=1 fi done if [ "${overall_exit}" -ne 0 ] ; then echo "Some instance types failed. Please check the contents of ${output_directory} for details." else echo "All instance types passed! Removing failed output directory since it is empty." rmdir "${output_directory}" fi exit "${overall_exit}" aws-ec2-instance-connect-config-1.1.12/bin/make_deb.sh000077500000000000000000000047371361013163600224020ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # XXX: This script builds a local 3.0 (native) package for testing purposes. # Any actual patches should be developed and submitted using apt-source and Quilt. # Note: this will only work on a system with dpkg build tools installed (ie, Debian & its derivatives) # It is also strongly recommended you install devtools (dch, etc) to assist with package building # You are *REQUIRED* to have debhelper and devscripts installed! if [ $# -ne 2 ] ; then echo "Usage: make_deb.sh [version] [release]" echo " ie, make_deb.sh [1.1] [1]" exit 1 fi md5 () { echo -n "${1}" | md5sum | sed 's/\s.*$//' } sha1 () { echo -n "${1}" | sha1sum | sed 's/\s.*$//' } sha256 () { echo -n "${1}" | sha256sum | sed 's/\s.*$//' } TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )") version=$1 release=$2 pkgdir="${TOPDIR}/ec2-instance-connect-${version}-${release}" # Copy source files mkdir "${pkgdir}" mkdir -p "${pkgdir}/ec2-instance-connect" cp "${TOPDIR}"/src/bin/* "${pkgdir}/ec2-instance-connect/" # Dump /bin, /usr/bin, etc from binary paths names since we want to use $PATH on Ubuntu/etc sed -i "s%/usr/bin/%%g" "${pkgdir}"/ec2-instance-connect/* sed -i "s%^/bin/%%g" "${pkgdir}"/ec2-instance-connect/* sed -i "s%\([^\#][^\!]\)/bin/%\1%g" "${pkgdir}"/ec2-instance-connect/* # Copy ec2-instance-connect service file cp -r "${TOPDIR}/src/deb_systemd/ec2-instance-connect.service" "${pkgdir}/" cp -r "${TOPDIR}/src/ec2-instance-connect.preset" "${pkgdir}/95-ec2-instance-connect.preset" mkdir "${pkgdir}/debian" cp -r "${TOPDIR}"/debian/* "${pkgdir}/debian/" sed -i "s/\!VERSION\!/${version}-${release}/" "${pkgdir}/debian/control" # Do the actual packaging return_dir=$(pwd) cd "${pkgdir}" || exit 1 debuild # Clean up cd "${return_dir}" || exit 1 rm -rf "${pkgdir}" aws-ec2-instance-connect-config-1.1.12/bin/make_rpm.sh000077500000000000000000000053231361013163600224360ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Note: this will only work on a system with rpm build tools installed (ie, RHEL & its derivatives) if [ $# -ne 2 ] ; then echo "Usage: make_rpm.sh [version] [release]" echo " ie, make_rpm.sh [1.1] [1]" exit 1 fi TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )") BUILDDIR="${TOPDIR}/rpmbuild" mkdir -p "${BUILDDIR}" version="${1}" release="${2}" mkdir -p "${BUILDDIR}"/{BUILD,RPMS,SOURCES,SPECS,SRPMS,ec2-instance-connect-"${version}",tmp} mkdir -p "${BUILDDIR}/ec2-instance-connect-${version}/opt/aws/bin" cp "${TOPDIR}"/rpmsrc/SPECS/generic.spec "${BUILDDIR}/SPECS/ec2-instance-connect.spec" cp "${TOPDIR}"/src/bin/* "${BUILDDIR}/ec2-instance-connect-${version}/opt/aws/bin/" cp "${TOPDIR}"/rpmsrc/.rpmmacros "${BUILDDIR}/" /bin/sed -i "s%^ca_path=/etc/ssl/certs$%ca_path=/etc/ssl/certs/ca-bundle.crt%" "${BUILDDIR}/ec2-instance-connect-${version}/opt/aws/bin/eic_curl_authorized_keys" # Trick rpmbuild into thinking this is homedir to read .rpmmacros REALHOME="${HOME}" export HOME="${BUILDDIR}" function cleanup { export HOME="${REALHOME}" rm -rf "${BUILDDIR}"/{BUILD,SOURCES,tmp} rm -rf "${BUILDDIR}/BUILDROOT" # In case we got far enough for this to exist rm -rf "${BUILDDIR}/ec2-instance-connect-${version}" } trap cleanup EXIT cp "${TOPDIR}/src/rpm_systemd/ec2-instance-connect.service" "${BUILDDIR}/SOURCES/" cp "${TOPDIR}/src/ec2-instance-connect.preset" "${BUILDDIR}/SOURCES" ls "${BUILDDIR}/SOURCES" cd "${BUILDDIR}" || exit 1 # Will ensure some paths are set correctly in rpmbuild # Compress the scripts tar -czf "${BUILDDIR}/SOURCES/ec2-instance-connect-${version}.tar.gz" "ec2-instance-connect-${version}/" # Fill in the placeholders sed -i "s/\!VERSION\!/${version}/" "${BUILDDIR}/SPECS/ec2-instance-connect.spec" sed -i "s/\!RELEASE\!/${release}/" "${BUILDDIR}/SPECS/ec2-instance-connect.spec" # Build the package rpmbuild -ba "${BUILDDIR}/SPECS/ec2-instance-connect.spec" cp "${BUILDDIR}/RPMS/noarch/ec2-instance-connect-${version}-${release}.noarch.rpm" "${TOPDIR}/" aws-ec2-instance-connect-config-1.1.12/bin/make_tarball.sh000077500000000000000000000024621361013163600232620ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )") verrel="$(cat "${TOPDIR}/VERSION")" version="${verrel%-*}" pkgver="ec2-instance-connect-${version}" mkdir -p "${TOPDIR}/${pkgver}/opt/aws/bin" cp "${TOPDIR}"/src/bin/* "${TOPDIR}/${pkgver}/opt/aws/bin/" if [ $# -eq 1 ] ; then # TODO: better check. Low-priority. /bin/sed -i "s%^ca_path=/etc/ssl/certs$%ca_path=/etc/ssl/certs/ca-bundle.crt%" "${TOPDIR}/${pkgver}/opt/aws/bin/eic_curl_authorized_keys" fi tar -czf "${TOPDIR}/${pkgver}.tar.gz" -C "${TOPDIR}" "${pkgver}/" rm -rf "${TOPDIR:?}/${pkgver:?}"/* rmdir "${TOPDIR}/${pkgver}" aws-ec2-instance-connect-config-1.1.12/bin/unit-test/000077500000000000000000000000001361013163600222355ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/bin/unit-test/generate_ocsp.sh000077500000000000000000000032651361013163600254200ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Unit test helper to generate an OCSP response in the desired location if [ -z "${1}" ] ; then echo "No openssl provided" exit 1 fi if [ -z "${2}" ] ; then echo "No certificate file provided" exit 2 fi if [ -z "${3}" ] ; then echo "No CA filepath provided (do not include file extension - this path will be used with .crt, .key, and .cdb.index)" exit 3 fi if [ -z "${4}" ] ; then echo "No output file specified" exit 4 fi tmpfile=$(mktemp /dev/shm/tmp-XXXXXXXX) # Generate the OCSP request "${1}" ocsp -no_nonce -issuer "${3}.crt" -cert "${2}" -VAfile "${3}".crt -reqout "${tmpfile}" # Generate the response # Yes, we're using the CA to sign the response as well. Since this is for unit testing use we don't need strict security. "${1}" ocsp -index "${3}.db.index" -rsigner "${3}.crt" -rkey "${3}.key" -CA "${3}.crt" -VAfile "${3}.crt" -reqin "${tmpfile}" -respout "${4}" > /dev/null 2>&1 # Drop the request, we don't need it anymore rm -f "${tmpfile}" aws-ec2-instance-connect-config-1.1.12/bin/unit-test/setup_certificates.sh000077500000000000000000000122341361013163600264630ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Quick script to generate a CA, intermediate, and end certificate if [ -z "${1}" ] ; then echo "No openssl provided" exit 1 fi if [ -z "${2}" ] ; then echo "No target directory provided" exit 2 fi OPENSSL="${1}" certpath="${2}" # Configure the CA mkdir -p "${certpath}/ca.db.certs" touch "${certpath}/ca.db.index" echo 01 > "${certpath}/ca.db.serial" cat > "${certpath}/ca.conf" <<'EOF' default_ca = ca_default [ca_default] dir = REPLACE_WITH_CERTPATH certs = $dir new_certs_dir = $dir/ca.db.certs database = $dir/ca.db.index serial = $dir/ca.db.serial RANDFILE = $dir/ca.db.rand certificate = $dir/ca.crt private_key = $dir/ca.key default_days = 1 default_crl_days = 1 default_md = sha256 preserve = no policy = generic_policy x509_extensions = usr_cert [generic_policy] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [usr_cert] authorityInfoAccess = OCSP;URI:http://localhost:8080 subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer [v3_ocsp] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = OCSPSigning [v3_ca] subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always basicConstraints = CA:TRUE [req] distinguished_name = req_distinguished_name [req_distinguished_name] EOF sed -i "s|REPLACE_WITH_CERTPATH|${certpath}|" "${certpath}/ca.conf" # Generate the CA "${OPENSSL}" genrsa -out "${certpath}/ca.key" 2048 > /dev/null 2>&1 "${OPENSSL}" req -x509 -new -nodes -key "${certpath}/ca.key" -sha256 -days 1 -out "${certpath}/ca.crt" -subj "/CN=managedssh.amazonaws.com" > /dev/null 2>&1 "${OPENSSL}" x509 -in "${certpath}/ca.crt" -outform PEM -out "${certpath}/ca.pem" subject=$("${OPENSSL}" x509 -noout -subject -in "${certpath}/ca.pem" | sed -n -e 's/^.*CN=//p') # Add "# subject" to start sed -i '1s;^;# '"$subject"'\n;' "${certpath}/ca.crt" # Configure the intermediary mkdir -p "${certpath}/intermediate.db.certs" touch "${certpath}/intermediate.db.index" echo 01 > "${certpath}/intermediate.db.serial" cat > "${certpath}/intermediate.conf" <<'EOF' default_ca = ca_default [ca_default] dir = REPLACE_WITH_CERTPATH certs = $dir new_certs_dir = $dir/intermediate.db.certs database = $dir/intermediate.db.index serial = $dir/intermediate.db.serial RANDFILE = $dir/intermediate.db.rand certificate = $dir/intermediate.crt private_key = $dir/intermediate.key default_days = 1 default_crl_days = 1 default_md = sha256 preserve = no policy = generic_policy x509_extensions = usr_cert [generic_policy] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [usr_cert] authorityInfoAccess = OCSP;URI:http://localhost:8080 subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer [v3_ocsp] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = OCSPSigning [req] distinguished_name = req_distinguished_name [req_distinguished_name] EOF sed -i "s|REPLACE_WITH_CERTPATH|${certpath}|" "${certpath}/intermediate.conf" # Generate & sign the intermediary "${OPENSSL}" genrsa -out "${certpath}/intermediate.key" 2048 > /dev/null 2>&1 "${OPENSSL}" req -new -nodes -config "${certpath}/ca.conf" -key "${certpath}/intermediate.key" -out "${certpath}/intermediate.csr" -extensions v3_ocsp -subj "/CN=intermediate.managedssh.amazonaws.com" > /dev/null 2>&1 yes | "${OPENSSL}" ca -config "${certpath}/ca.conf" -in "${certpath}/intermediate.csr" -cert "${certpath}/ca.crt" -keyfile "${certpath}/ca.key" -out "${certpath}/intermediate.crt" -extensions v3_ocsp -extensions v3_ca > /dev/null 2>&1 "${OPENSSL}" x509 -in "${certpath}/intermediate.crt" -outform PEM -out "${certpath}/intermediate.pem" # Generate and sign the test cert "${OPENSSL}" genrsa -out "${certpath}/unittest.key" 2048 > /dev/null 2>&1 "${OPENSSL}" req -new -nodes -config "${certpath}/intermediate.conf" -key "${certpath}/unittest.key" -out "${certpath}/unittest.csr" -subj "/CN=unittest.managedssh.amazonaws.com" > /dev/null 2>&1 yes | "${OPENSSL}" ca -config "${certpath}/intermediate.conf" -in "${certpath}/unittest.csr" -cert "${certpath}/intermediate.crt" -keyfile "${certpath}/intermediate.key" -out "${certpath}/unittest.crt" > /dev/null 2>&1 "${OPENSSL}" x509 -in "${certpath}/unittest.crt" -outform PEM -out "${certpath}/unittest.pem" aws-ec2-instance-connect-config-1.1.12/bin/unit-test/sign_data.sh000077500000000000000000000033701361013163600245300ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Unit test helper. Takes a directory containing key blobs in files, signs the data in each, and consolidates into a final output. if [ -z "${1}" ] ; then echo "No openssl provided" exit 1 fi if [ -z "${2}" ] ; then echo "Signing key not provided." exit 2 fi if [ -z "${3}" ] ; then echo "Input directory not provided." exit 3 fi if [ -z "${4}" ] ; then echo "Target file not provided." exit 4 fi OPENSSL="${1}" private_key="${2}" input_dir="${3}" target="${4}" signing_temp=$(mktemp -d /dev/shm/tmp-XXXXXXXX) trap 'rm -rf "${signing_temp}"' EXIT for file in "${input_dir}"/* ; do # Generate the signature "${OPENSSL}" dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -sign "${private_key}" -out "${signing_temp}/signature" "${file}" # Base64 encode it base64 "${signing_temp}/signature" > "${signing_temp}/encoded" # Add the input file dump & its signature to the target cat "${file}" "${signing_temp}/encoded" >> "${target}" # Append a newline echo >> "${target}" done aws-ec2-instance-connect-config-1.1.12/bin/unit-test/test_authorized_keys.sh000077500000000000000000000050001361013163600270370ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Authorized keys command unit test script. Takes the script to test, certificate, CA, input, and expected output. # TODO: Switch to named args/getopts if [ -z "${1}" ] ; then echo "No openssl provided" exit 1 fi if [ -z "${2}" ] ; then echo "Script file not provided" exit 2 fi if [ -z "${3}" ] ; then echo "No certificate file provided" exit 3 fi if [ -z "${4}" ] ; then echo "No CA file provided" exit 4 fi if [ -z "${5}" ] ; then echo "OCSP responses directory not provided" exit 5 fi if [ -z "${6}" ] ; then echo "No input file provided" exit 6 fi if [ -z "${7}" ] ; then echo "No expected output file provided" exit 7 fi OPENSSL=$1 certificate=$(cat "${3}") filename="${6##*/}" expected_output=$(cat "${7}") expected_exit=0 if [ -z "${expected_output}" ] ; then # If expected output is empty then we expect the script not to exit success expected_exit=255 fi testdir=$(mktemp -d /dev/shm/tmp-XXXXXXXX) # The key fingerprint is for a pre-generated ssh key used in several test inputs # Some test inputs contain other keys as well # The test outputs, however, *only* match this key - we expect the other keys to be rejected test_output=$(${2} -x true -p "${6}" -o "${OPENSSL}" -d "${testdir}" -s "${certificate}" -i "i-abcd1234" -c "unittest.managedssh.amazonaws.com" -a "${4}" -v "${5}" -f "SHA256:F3e4S8/QjcVquqrvmyq9AWAhOxIXfpbpnmDVFdA0sPU") test_status=$? exit_status=0 if [[ $test_status -eq $expected_exit && "${test_output}" = "${expected_output}" ]] ; then echo "${filename} PASSED" else echo "${filename} FAILED" echo "EXPECTED: exit ${expected_exit} with output" echo "${expected_output}" echo "ACTUAL: exit ${test_status} with output" echo "${test_output}" exit_status=1 fi rm -rf "${testdir}" exit "${exit_status}" aws-ec2-instance-connect-config-1.1.12/bin/unit_test_suite.sh000077500000000000000000000063361361013163600240770ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Script to run our entire unit test suite. # Iterates over the contents of test/input/direct and test/input/unsigned and validates we get the matching contents of unit-test/expected-output OPENSSL="/usr/bin/openssl" TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)") tmpdir=$(mktemp -d /dev/shm/tmp-XXXXXXXX) trap 'rm -rf "${tmpdir}"' EXIT # Generate test certificates "${TOPDIR}/bin/unit-test/setup_certificates.sh" "${OPENSSL}" "${tmpdir}" # Combine unittest & intermediate into the trust chain for the actual AuthorizedKeysCommand cat "${tmpdir}/unittest.pem" "${tmpdir}/intermediate.pem" "${tmpdir}/ca.pem" > "${tmpdir}/chain.pem" intermediate_fingerprint="$(openssl x509 -noout -fingerprint -sha1 -inform pem -in "${tmpdir}/intermediate.pem" | sed -n 's/SHA1 Fingerprint=\(.*\)/\1/p' | tr -d ':')" unittest_fingerprint="$(openssl x509 -noout -fingerprint -sha1 -inform pem -in "${tmpdir}"/unittest.pem | sed -n 's/SHA1 Fingerprint=\(.*\)/\1/p' | tr -d ':')" # Generate OCSP for those certificates "${TOPDIR}/bin/unit-test/generate_ocsp.sh" "${OPENSSL}" "${tmpdir}/intermediate.crt" "${tmpdir}/ca" "${tmpdir}/${intermediate_fingerprint}" "${TOPDIR}/bin/unit-test/generate_ocsp.sh" "${OPENSSL}" "${tmpdir}/unittest.crt" "${tmpdir}/intermediate" "${tmpdir}/${unittest_fingerprint}" exit_status=0 # Direct input tests for testfile in "${TOPDIR}"/unit-test/input/direct/* ; do filename="${testfile##*/}" "${TOPDIR}/bin/unit-test/test_authorized_keys.sh" "${OPENSSL}" "${TOPDIR}/src/bin/eic_parse_authorized_keys" "${tmpdir}/chain.pem" "${tmpdir}/ca.crt" "${tmpdir}" "${testfile}" "${TOPDIR}/unit-test/expected-output/${filename}" result="${?}" if [ "${result}" -ne 0 ] ; then exit_status=1 fi done # Tests that require signing input data for testdir in "${TOPDIR}"/unit-test/input/unsigned/* ; do # Generate signatures for key blobs filename="${testdir##*/}" if [ "$("${TOPDIR}/bin/unit-test/sign_data.sh" "${OPENSSL}" "${tmpdir}/unittest.key" "${testdir}" "${tmpdir}/${filename}")" ] ; then echo "Unable to run test ${filename}: signature generation failed" else # Run the actual test "${TOPDIR}/bin/unit-test/test_authorized_keys.sh" "${OPENSSL}" "${TOPDIR}/src/bin/eic_parse_authorized_keys" "${tmpdir}/chain.pem" "${tmpdir}/ca.crt" "${tmpdir}" "${tmpdir}/${filename}" "${TOPDIR}/unit-test/expected-output/${filename}" result="${?}" if [ "${result}" -ne 0 ] ; then exit_status=1 fi fi done rm -rf "${tmpdir:?}" exit "${exit_status}" aws-ec2-instance-connect-config-1.1.12/integration-test/000077500000000000000000000000001361013163600230315ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/integration-test/config/000077500000000000000000000000001361013163600242765ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/integration-test/config/amazon-linux000066400000000000000000000002331361013163600266410ustar00rootroot00000000000000INSTALL="sudo yum -y install" REMOVE="sudo yum -y remove" SSHD_CONFIG_MODIFIED="1" SCRIPT_PATH="/opt/aws/bin" SSHD_SERVICE="sshd" MISSING_SSHD_NEWLINE="0" aws-ec2-instance-connect-config-1.1.12/integration-test/config/rhel000066400000000000000000000002331361013163600251510ustar00rootroot00000000000000INSTALL="sudo yum -y install" REMOVE="sudo yum -y remove" SSHD_CONFIG_MODIFIED="0" SCRIPT_PATH="/opt/aws/bin" SSHD_SERVICE="sshd" MISSING_SSHD_NEWLINE="1" aws-ec2-instance-connect-config-1.1.12/integration-test/config/ubuntu000066400000000000000000000002341361013163600255420ustar00rootroot00000000000000INSTALL="sudo apt-get -y install" REMOVE="sudo apt-get -y remove" SSHD_CONFIG_MODIFIED="0" SCRIPT_PATH="/etc/share/ec2-instance-connect" SSHD_SERVICE="ssh" aws-ec2-instance-connect-config-1.1.12/integration-test/test/000077500000000000000000000000001361013163600240105ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/integration-test/test/custom_config.sh000077500000000000000000000076501361013163600272160ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Test that package uninstall removes customizations and reinstall re-adds them TOPDIR=$(dirname "$( cd "$( dirname "$( dirname "${BASH_SOURCE[0]}" )" )" && pwd)") while getopts ":i:p:z:u:k:l:t:" opt ; do case "${opt}" in i) instance_id="${OPTARG}" ;; p) public_ip="${OPTARG}" ;; z) zone="${OPTARG}" ;; u) osuser="${OPTARG}" ;; k) private_key="${OPTARG}" ;; l) distro="${OPTARG}" ;; t) package_path="${OPTARG}" ;; *) ;; esac done source "${TOPDIR}/integration-test/config/${distro}" package_name="${package_path##*/}" # Construct the test script scriptfile=$(mktemp /tmp/tmp-XXXXXXXX) trap 'rm -f "${scriptfile}"' EXIT if [ "${SSHD_CONFIG_MODIFIED}" -ne 0 ] ; then config_check="\"\$(sudo grep \"^AuthorizedKeysCommand[[:blank:]]/opt/aws/bin/eic_run_authorized_keys[[:blank:]]%u[[:blank:]]%f$\" /etc/ssh/sshd_config)\"" else config_check="-f /lib/systemd/system/${SSHD_SERVICE}.service.d/ec2-instance-connect.conf" fi echo '#!/bin/bash' > "${scriptfile}" echo "set -e" >> "${scriptfile}" printf "%s\n%s\n" "echo \"Uninstalling package\"" "${REMOVE} ec2-instance-connect 2>&1" >> "${scriptfile}" printf "%s\n%s\n%s\n%s\n" "if [ ${config_check} ] ; then" "echo \"Package was not installed or deconfigured correctly\"" "exit 1" "fi" >> "${scriptfile}" # We need an extra newline before the custom AKC due to some distros, eg RHEL, not having a newline at end of file printf "%s\n%s\n" "echo \"Adding override config to sshd_config\"" "printf \"\n%s\n\" \"AuthorizedKeysCommand exit\" | sudo tee -a /etc/ssh/sshd_config" >> "${scriptfile}" printf "%s\n%s\n" "echo \"Installing package\"" "${INSTALL} /tmp/${package_name} 2>&1" >> "${scriptfile}" printf "%s\n%s\n%s\n%s\n" "if [ ${config_check} ] ; then" "echo \"Package overwrote existing customizations!\"" "exit 1" "fi" >> "${scriptfile}" echo "scping test script to instance" scp -i "${private_key}" -o StrictHostKeyChecking=no "${scriptfile}" "${osuser}@${public_ip}:/tmp/eic_custom_config_test.sh" 2>&1 scp_result="${?}" if [ "${scp_result}" -ne 0 ] ; then exit 1 fi echo "Running test script" fail=0 ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" 'chmod +x /tmp/eic_custom_config_test.sh ; /tmp/eic_custom_config_test.sh' 2>&1 test_result="${?}" if [ "${test_result}" -ne 0 ] ; then fail=1 fi if [ "${fail}" -eq 0 ] ; then echo "Invoking EIC end-to-end test for final validation" "${TOPDIR}/integration-test/test/ssh_test.sh" -i "${instance_id}" -p "${public_ip}" -z "${zone}" -u "${osuser}" -k "${private_key}" -l "${distro}" -t "${package_path}" 2>&1 ssh_result="${?}" if [ "${ssh_result}" -eq 0 ] ; then echo "ssh via EIC succeeded but should have failed!" fail=1 fi fi # Reset back to start-of-test conditions clean_cmd="${REMOVE} ec2-instance-connect 2>&1 ; sudo sed -i \"\~^AuthorizedKeysCommand[[:blank:]]exit\$~d\" /etc/ssh/sshd_config ; ${INSTALL} /tmp/${package_name} 2>&1" ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" "${clean_cmd}" exit $fail aws-ec2-instance-connect-config-1.1.12/integration-test/test/hostkey_test.sh000077500000000000000000000142401361013163600270750ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Test of EIC host key harvesting mechanism. Regenerate rsa host key, re-trigger harvest, and ensure new key is returned. # NOTE THIS TEST REQUIRES THE EC2 OS USER HAVE SUDO PERMISSION FOR SSH HOST KEY REGENERATION AND RESTARTING HOST KEY HARVEST while getopts ":i:p:z:u:k:l:t:" opt ; do case "${opt}" in i) instance_id="${OPTARG}" ;; p) public_ip="${OPTARG}" ;; z) zone="${OPTARG}" ;; u) osuser="${OPTARG}" ;; k) private_key="${OPTARG}" ;; l) distro="${OPTARG}" ;; t) package_path="${OPTARG}" ;; *) ;; esac done scriptfile=$(mktemp /tmp/tmp-XXXXXXXX) trap 'rm -f "${scriptfile}"' EXIT cat > "${scriptfile}" << 'EOF' #!/bin/bash set -e echo "Generating new host key" keydir=$(mktemp -d /tmp/tmp-XXXXXXXX) trap 'rm -rf "${keydir}"' EXIT keyfile="${keydir}/eic_test_host_key" ssh-keygen -t rsa -f "${keyfile}" -P '' -N '' -C '' -q echo "Moving new host key to /etc/ssh" sudo mv /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.bak sudo mv /etc/ssh/ssh_host_rsa_key.pub /etc/ssh/ssh_host_rsa_key.pub.bak sudo mv "${keyfile}" /etc/ssh/ssh_host_rsa_key sudo mv "${keyfile}.pub" /etc/ssh/ssh_host_rsa_key.pub sudo chmod 640 /etc/ssh/ssh_host_rsa_key sudo chmod 644 /etc/ssh/ssh_host_rsa_key.pub pubkey=$(cat /etc/ssh/ssh_host_rsa_key.pub | awk '{$1=$1};1') echo "Retriggering host key harvesting" sudo systemctl restart ec2-instance-connect.service echo "Retrieving keys from service" sign () { printf "${2}" | openssl dgst -binary -hex -sha256 -mac HMAC -macopt hexkey:"${1}" | sed 's/.* //' } getsigv4key () { local base=$(echo -n "AWS4${1}" | od -A n -t x1 | sed ':a;N;$!ba;s/[\n ]//g') local kdate=$(sign "${base}" "${2}") local kregion=$(sign "${kdate}" "${3}") local kservice=$(sign "${kregion}" "${4}") sign "${kservice}" "aws4_request" } 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")" accountId=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/dynamic/instance-identity/document" | grep -oP '(?<="accountId" : ")[^"]*(?=")') domain=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/services/domain/") zone=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/placement/availability-zone/") region=$(echo "${zone}" | sed -n 's/\(\([a-z]\+-\)\+[0-9]\+\).*/\1/p') instance=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/instance-id/") val='{"AccountID":"'${accountId}'","AvailabilityZone":"'${zone}'","InstanceId":"'${instance}'"}' creds=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance/") AWS_ACCESS_KEY_ID=$(echo "${creds}" | sed -n 's/.*"AccessKeyId" : "\(.*\)",/\1/p') AWS_SECRET_ACCESS_KEY=$(echo "${creds}" | sed -n 's/.*"SecretAccessKey" : "\(.*\)",/\1/p') AWS_SESSION_TOKEN=$(echo "${creds}" | sed -n 's/.*"Token" : "\(.*\)",/\1/p') host="ec2-instance-connect.${region}.${domain}" endpoint="https://${host}" timestamp=$(date -u "+%Y-%m-%d %H:%M:%S") isoTimestamp=$(date -ud "${timestamp}" "+%Y%m%dT%H%M%SZ") isoDate=$(date -ud "${timestamp}" "+%Y%m%d") canonicalQuery="" canonicalHeaders="host:${host}\nx-amz-date:${isoTimestamp}\nx-amz-security-token:${AWS_SESSION_TOKEN}\n" signedHeaders="host;x-amz-date;x-amz-security-token" payloadHash=$(echo -n "${val}" | sha256sum | sed 's/\s.*$//') canonicalRequest="$(printf "POST\n/GetEC2HostKeys/\n%s\n${canonicalHeaders}\n${signedHeaders}\n%s" "${canonicalQuery}" "${payloadHash}")" requestHash=$(echo -n "${canonicalRequest}" | sha256sum | sed 's/\s.*$//') credentialScope="${isoDate}/${region}/ec2-instance-connect/aws4_request" toSign="AWS4-HMAC-SHA256\n${isoTimestamp}\n${credentialScope}\n${requestHash}" signingKey=$(getsigv4key "${AWS_SECRET_ACCESS_KEY}" "${isoDate}" "${region}" "ec2-instance-connect") signature=$(sign "${signingKey}" "${toSign}") authorizationHeader="AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY_ID}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}" host_keys=$(curl -X POST -H "Content-Encoding: amz-1.0" -H "Authorization: ${authorizationHeader}" -H "Content-Type: application/json" -H "x-amz-content-sha256: ${payloadHash}" -H "x-amz-date: ${isoTimestamp}" -H "x-amz-security-token: ${AWS_SESSION_TOKEN}" -H "x-amz-target: com.amazon.aws.sshaccessproxyservice.AWSEC2InstanceConnectService.GetEC2HostKeys" -d "${val}" "${endpoint}/GetEC2HostKeys/" 2>/dev/null) echo "Verifying new key was harvested" rsa_key=$(echo "ssh-rsa$(echo "${host_keys}" | sed -e 's/.*ssh-rsa\(.*\)\".*/\1/')") if [ "${rsa_key}" = "${pubkey}" ] ; then echo "SUCCESS" exit 0 else echo "FAILURE" exit 1 fi EOF echo "scping test script to instance" scp -i "${private_key}" -o StrictHostKeyChecking=no "${scriptfile}" "${osuser}@${public_ip}:/tmp/eic_host_key_test.sh" 2>&1 ssh_status=$? if [ $ssh_status -eq 0 ] ; then echo "Running test script" ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" 'chmod +x /tmp/eic_host_key_test.sh ; /tmp/eic_host_key_test.sh' 2>&1 ssh_status=$? fi exit "${ssh_status}" aws-ec2-instance-connect-config-1.1.12/integration-test/test/ssh_test.sh000077500000000000000000000054721361013163600262130ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Basic EIC functionality test: push a key and ssh to the instance while getopts ":i:p:z:u:" opt ; do case "${opt}" in i) instance_id="${OPTARG}" ;; p) public_ip="${OPTARG}" ;; z) zone="${OPTARG}" ;; u) osuser="${OPTARG}" ;; k) private_key="${OPTARG}" ;; l) distro="${OPTARG}" ;; t) package_path="${OPTARG}" ;; *) ;; esac done echo "Testing EC2 Instance Connect end-to-end ssh functionality..." keydir=$(mktemp -d /tmp/tmp-XXXXXXXX) trap 'rm -rf "${keydir}"' EXIT keyfile="${keydir}/eic_test_key" ssh-keygen -t rsa -b 2048 -f "${keyfile}" -P "" -q # We will make 3 tries as certain elements (eg network calls) may cause transient failure try="0" success=1 while [ $try -lt 3 ] ; do # Make 3 attempts to push a key awstry="0" while [ $awstry -lt 3 ] ; do aws ec2-instance-connect send-ssh-public-key --region us-west-2 --instance-id "${instance_id}" --availability-zone "${zone}" --instance-os-user "${osuser}" --ssh-public-key "file://${keyfile}.pub" 1>/dev/null aws_code=$? if [ $aws_code -ne 0 ] ; then sleep 5 awstry=$((awstry+1)) echo "${instance_id} EIC call ${awstry} failed" else awstry="3" fi done sshtry="0" # Make 3 attempts to ssh while [ $sshtry -lt 3 ] ; do ssh -q -i "${keyfile}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" exit 2>&1 success=$? if [ $success -eq 0 ] ; then echo "${instance_id} ssh succeeded!" sshtry="3" try="3" else sleep 5 sshtry=$((sshtry+1)) echo "${instance_id} ssh call ${sshtry} failed" fi done if [ $success -ne 0 ] ; then try=$((try+1)) echo "${instance_id} EIC test attempt ${try} failed" fi done if [ $success -eq 0 ] ; then echo "SUCCESS" else echo "FAILURE" fi exit $success aws-ec2-instance-connect-config-1.1.12/integration-test/test/uninstall_reinstall.sh000077500000000000000000000062441361013163600304430ustar00rootroot00000000000000#!/bin/bash # 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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 # Test that package uninstall removes customizations and reinstall re-adds them TOPDIR=$(dirname "$( cd "$( dirname "$( dirname "${BASH_SOURCE[0]}" )" )" && pwd)") while getopts ":i:p:z:u:k:l:t:" opt ; do case "${opt}" in i) instance_id="${OPTARG}" ;; p) public_ip="${OPTARG}" ;; z) zone="${OPTARG}" ;; u) osuser="${OPTARG}" ;; k) private_key="${OPTARG}" ;; l) distro="${OPTARG}" ;; t) package_path="${OPTARG}" ;; *) ;; esac done source "${TOPDIR}/integration-test/config/${distro}" package_name="${package_path##*/}" # Construct the test script scriptfile=$(mktemp /tmp/tmp-XXXXXXXX) trap 'rm -f "${scriptfile}"' EXIT if [ "${SSHD_CONFIG_MODIFIED}" -ne 0 ] ; then config_check="grep -q \"^AuthorizedKeysCommand[[:blank:]]/opt/aws/bin/eic_run_authorized_keys[[:blank:]]%u[[:blank:]]%f$\" /etc/ssh/sshd_config" else config_check="-f /lib/systemd/system/${SSHD_SERVICE}.service.d/ec2-instance-connect.conf" fi echo "#!/bin/bash" > "${scriptfile}" echo "set -e" >> "${scriptfile}" printf "%s\n%s\n" "echo \"Uninstalling package\"" "${REMOVE} ec2-instance-connect 2>&1" >> "${scriptfile}" printf "%s\n%s\n%s\n%s\n" "if [ ${config_check} ] ; then" "echo \"Package was not installed or deconfigured correctly\"" "exit 1" "fi" >> "${scriptfile}" printf "%s\n%s\n" "echo \"Reinstalling package\"" "${INSTALL} /tmp/${package_name} 2>&1" >> "${scriptfile}" printf "%s\n%s\n%s\n%s\n" "if [ ! ${config_check} ] ; then" "echo \"Package not installed/configured correctly\"" "exit 1" "fi" >> "${scriptfile}" echo "scping test script to instance" scp -i "${private_key}" -o StrictHostKeyChecking=no "${scriptfile}" "${osuser}@${public_ip}:/tmp/eic_uninstall_reinstall_test.sh" 2>&1 scp_result="${?}" if [ "${scp_result}" -ne 0 ] ; then exit 1 fi echo "Running test script" ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" 'chmod +x /tmp/eic_uninstall_reinstall_test.sh ; /tmp/eic_uninstall_reinstall_test.sh' 2>&1 test_result="${?}" if [ "${test_result}" -ne 0 ] ; then exit 1 fi echo "Invoking EIC end-to-end test for final validation" "${TOPDIR}/integration-test/test/ssh_test.sh" -i "${instance_id}" -p "${public_ip}" -z "${zone}" -u "${osuser}" -k "${private_key}" -l "${distro}" -t "${package_path}" 2>&1 exit "${?}" aws-ec2-instance-connect-config-1.1.12/rpmsrc/000077500000000000000000000000001361013163600210375ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/rpmsrc/.rpmmacros000066400000000000000000000000541361013163600230420ustar00rootroot00000000000000%_topdir %(pwd) %_tmppath %{_topdir}/tmp aws-ec2-instance-connect-config-1.1.12/rpmsrc/SPECS/000077500000000000000000000000001361013163600217145ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/rpmsrc/SPECS/generic.spec000066400000000000000000000200041361013163600242000ustar00rootroot00000000000000# 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. %define __spec_install_post %{nil} %define debug_package %{nil} %define __os_install_post %{_dbpath}/brp-compress Summary: EC2 instance scripting and configuration for EC2 Instance Connect Name: ec2-instance-connect Version: !VERSION! Release: !RELEASE! License: ASL2.0 BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: systemd Source0: %{name}-%{version}.tar.gz Source1: ec2-instance-connect.service Source2: ec2-instance-connect.preset Requires: openssh >= 6.9.0, coreutils, openssh-server >= 6.9.0, openssl, curl, systemd Requires(pre): /usr/bin/getent, /usr/sbin/adduser, /usr/sbin/usermod, systemd, systemd-units Requires(post): /bin/grep, /usr/bin/printf, openssh-server >= 6.9.0, systemd, systemd-units Requires(preun): systemd, systemd-units Requires(postun): /usr/sbin/userdel, systemd, systemd-units %description %{summary} %prep %setup -q %build # no-op %install /bin/rm -rf %{buildroot} /bin/mkdir -p %{buildroot} /usr/bin/install -D -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/ec2-instance-connect.service # While the former is the RHEL standard, both are populated. And not symlinked. /usr/bin/install -D -m 644 %{SOURCE2} %{buildroot}/usr/lib/systemd/system-preset/95-ec2-instance-connect.preset /usr/bin/install -D -m 644 %{SOURCE2} %{buildroot}/lib/systemd/system-preset/95-ec2-instance-connect.preset /bin/mkdir -p %{buildroot}/lib/systemd/hostkey.d /bin/echo 'ec2-instance-connect.service' > %{buildroot}/lib/systemd/hostkey.d/60-ec2-instance-connect.list # in builddir /bin/cp -a * %{buildroot} %clean /bin/rm -rf %{buildroot} %files %defattr(755, root, root, -) /opt/aws/bin/eic_run_authorized_keys /opt/aws/bin/eic_curl_authorized_keys /opt/aws/bin/eic_parse_authorized_keys /opt/aws/bin/eic_harvest_hostkeys %defattr(644, root, root, -) %{_unitdir}/ec2-instance-connect.service /lib/systemd/hostkey.d/60-ec2-instance-connect.list /lib/systemd/system-preset/95-ec2-instance-connect.preset /usr/lib/systemd/system-preset/95-ec2-instance-connect.preset %pre # Create/configure system user /usr/bin/getent passwd ec2-instance-connect || /usr/sbin/useradd -r -M -s /sbin/nologin ec2-instance-connect /usr/sbin/usermod -L ec2-instance-connect %post %systemd_post ec2-instance-connect.service # XXX: %system_post just loads any presets (ie, auto-enable/disable). It does NOT try to start the service! /usr/bin/systemctl start ec2-instance-connect.service modified=1 # Configure sshd to use EC2 Instance Connect's AuthorizedKeysCommand EXEC_OVERRIDE='ExecStart=/usr/sbin/sshd -D -o "AuthorizedKeysCommand /opt/aws/bin/eic_run_authorized_keys %%%%u %%%%f" -o "AuthorizedKeysCommandUser ec2-instance-connect" $SSHD_OPTS' # If there is nothing in the AuthorizedKeysCommand field of sshd_config *and* nothing in any sshd override, add our config if ! /bin/grep -q '^[^#]*AuthorizedKeysCommand[[:blank:]]\+.*$' /etc/ssh/sshd_config ; then if ! /bin/grep -q '^[^#]*AuthorizedKeysCommandUser[[:blank:]]\+.*$' /etc/ssh/sshd_config ; then if ! /bin/grep -q '^[^#]*AuthorizedKeysCommandRunAs[[:blank:]]\+.*$' /etc/ssh/sshd_config ; then # If systemd unit contains AKC don't override it if ! /bin/grep -q "AuthorizedKeysCommand" /lib/systemd/system/sshd.service ; then can_modify=1 if [ -d /lib/systemd/system/sshd.service.d ] ; then # If *any* override contains an ExecStart, don't override it if ! /bin/grep -Rq "ExecStart" /lib/systemd/system/sshd.service.d/ ; then can_modify=0 fi else # Or there are no overrides /bin/mkdir /lib/systemd/system/sshd.service.d can_modify=0 fi if [ $can_modify -eq 0 ] ; then # Add our configuration /usr/bin/printf "%s\n%s\n%s\n" "[Service]" "ExecStart=" "${EXEC_OVERRIDE}" > /lib/systemd/system/sshd.service.d/ec2-instance-connect.conf modified=0 fi fi fi fi fi if [ $modified -eq 0 ] ; then # Restart sshd systemctl daemon-reload if /bin/systemctl is-active --quiet sshd ; then /bin/systemctl restart sshd fi fi %preun %systemd_preun ec2-instance-connect.service if [ $1 -eq 0 ] ; then modified=1 # Remove EC2 Instance Connect sshd override if present if [ -f /lib/systemd/system/sshd.service.d/ec2-instance-connect.conf ] ; then /bin/rm -f /lib/systemd/system/sshd.service.d/ec2-instance-connect.conf if [ -z "$(ls -A /lib/systemd/system/sshd.service.d)" ] ; then # There were no other overrides, clean up /bin/rmdir /lib/systemd/system/sshd.service.d fi modified=0 fi # Restart sshd if [ $modified -eq 0 ] ; then /bin/systemctl daemon-reload if /bin/systemctl is-active --quiet sshd ; then /bin/systemctl restart sshd fi fi fi %postun %systemd_postun_with_restart ec2-instance-connect.service if [ $1 -eq 0 ] ; then # Delete system user /usr/sbin/userdel ec2-instance-connect fi %changelog * Tue Nov 19 2019 Daniel Anderson 1.1-12 - Adding support for Instance Metadata Service Version 2 - Modifying cURL invocation to avoid need for eval - Cleaning up shellcheck catches * Wed Aug 21 2019 Daniel Anderson 1.1-11 - Removing errant write to /tmp - Cleaning up bad bash practices, including umask race condition * Wed Jul 3 2019 Daniel Anderson 1.1-10 - Fix for an update to openssl (or dependencies) affecting behavior of CApath option on openssl verify - Fixing Nitro behavior of hostkey harvesting and post-installation systemd hooks * Wed May 15 2019 Daniel Anderson 1.1-9 - Fixing existing AuthorizedKeysCommand detection - Adding additional licensing headers - Improved mechanism for detection if script is running on an EC2 instance * Wed Apr 24 2019 Daniel Anderson 1.1-8 - Better detection of existing user customization * Fri Mar 29 2019 Daniel Anderson 1.1-7 - Change to Amazon Linux configuration * Wed Mar 20 2019 Daniel Anderson 1.1-6 - Verification of EC2 hypervisor UUID * Fri Mar 15 2019 Daniel Anderson 1.1-5 - Added slightly stronger checks that we're getting valid data from Instance Metadata Service/on an instance * Wed Jan 30 2019 Daniel Anderson 1.1-4 - Fixed a bug in reading instance-identity credentials as part of hostkey harvesting and dropped AWS CLI dependency - Added support for non-Amazon Linux yum distributions, such as RHEL and CentOS - Hardened error handling * Fri Dec 21 2018 Daniel Anderson 1.1-3 - Fixing an issue with the hostkey harvesting script - it was using default creds instead of instance-identity * Fri Dec 7 2018 Daniel Anderson 1.1-2 - Minor changes to package build process to share code with Debian packaging * Tue Oct 23 2018 Anshumali Prasad 1.1-1 - Hostkey harvesting for EC2 Instance Connect. * Mon Oct 22 2018 Daniel Anderson 1.0-3 - Updating exit status on no-data case, improving support for newer openssl versions * Tue Oct 9 2018 Daniel Anderson 1.0-2 - Cleaning up package requirements & post installation hook * Wed Jun 13 2018 Daniel Anderson 1.0-1 - Initial RPM build for EC2 Instance Connect targeting Amazon Linux 2. aws-ec2-instance-connect-config-1.1.12/src/000077500000000000000000000000001361013163600203205ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/bin/000077500000000000000000000000001361013163600210705ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/bin/eic_curl_authorized_keys000077500000000000000000000145231361013163600261010ustar00rootroot00000000000000#!/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 aws-ec2-instance-connect-config-1.1.12/src/bin/eic_harvest_hostkeys000077500000000000000000000162331361013163600252500ustar00rootroot00000000000000#!/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. set -e umask 077 # 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")" if [ -z "${IMDS_TOKEN}" ] ; then # Fast fail exit 255 fi # Verify the instance ID itself instance=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/instance-id/") if [ -z "${instance}" ] ; then exit 255 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 255 # 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. exit 255 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. exit 255 fi elif [ "$(/usr/bin/cut -c1-3 < /sys/hypervisor/uuid)" != "ec2" ] ; then # Leading bytes are not "ec2" exit 255 fi # Calculate the SHA256 of a given string # sha256 [string] sha256 () { /bin/echo -n "${1}" | /usr/bin/sha256sum | /bin/sed 's/\s.*$//' } # Sign a message with a given key # sign [key] [msg] sign () { /usr/bin/printf "${2}" | /usr/bin/openssl dgst -binary -hex -sha256 -mac HMAC -macopt hexkey:"${1}" | /bin/sed 's/.* //' } # Derive a sigv4 signing key for the given secret # get_sigv4_key [key] [datestamp] [region name] [service name] getsigv4key () { base="$(/bin/echo -n "AWS4${1}" | /usr/bin/od -A n -t x1 | /bin/sed ':a;N;$!ba;s/[\n ]//g')" kdate="$(sign "${base}" "${2}")" kregion="$(sign "${kdate}" "${3}")" kservice="$(sign "${kregion}" "${4}")" sign "${kservice}" "aws4_request" } # Verify that we have instance identity credentials. Fast-exit if we do not. creds_status="$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" -o /dev/null -I -w %{http_code} "http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance/")" if [ "${creds_status}" != "200" ] then # No keys for this user. Nothing to do. exit 0 fi #Iterates overs /etc/ssh to get the host keys for file in /etc/ssh/*.pub; do /usr/bin/test -r "${file}" || continue key=$(/usr/bin/awk '{$1=$1};1' < "${file}") keys="${keys:+${keys},}\"${key}\"" done #Temporary path to store request parameters userpath=$(/bin/mktemp -d /dev/shm/eic-hostkey-XXXXXXXX) trap 'rm -rf "${userpath}"' EXIT #Get zone information zone=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/placement/availability-zone/") zone_exit="${?}" if [ "${zone_exit}" -ne 0 ] then exit "${zone_exit}" fi # Validate the zone /bin/echo "${zone}" | /usr/bin/head -n 1 | /bin/grep -Eq "^([a-z]+-){2,3}[0-9][a-z]$" || exit 255 # Get domain for calls domain=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/services/domain/") domain_exit="${?}" if [ "${domain_exit}" -ne 0 ] then exit "${domain_exit}" fi #Extract region from zone region=$(/bin/echo "${zone}" | /bin/sed -n 's/\(\([a-z]\+-\)\+[0-9]\+\).*/\1/p') hostkeys=$(/bin/echo "${keys:?}") accountId=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/dynamic/instance-identity/document" | /bin/grep -oP '(?<="accountId" : ")[^"]*(?=")') /bin/echo "${accountId}" | /usr/bin/head -n 1 | /bin/grep -Eq "^[0-9]{12}$" || exit 255 val='{"AccountID":"'${accountId}'","AvailabilityZone":"'${zone}'","HostKeys":['${hostkeys}'],"InstanceId":"'${instance}'"}' # Pull the creds we need for the call creds=$(/usr/bin/curl -s -f -m 1 -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" "http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance/") creds_exit="${?}" if [ "${creds_exit}" -ne 0 ] ; then # We failed to load instance-identity credentials exit "${creds_exit}" fi AWS_ACCESS_KEY_ID=$(/bin/echo "${creds}" | /bin/sed -n 's/.*"AccessKeyId" : "\(.*\)",/\1/p') AWS_SECRET_ACCESS_KEY=$(/bin/echo "${creds}" | /bin/sed -n 's/.*"SecretAccessKey" : "\(.*\)",/\1/p') AWS_SESSION_TOKEN=$(/bin/echo "${creds}" | /bin/sed -n 's/.*"Token" : "\(.*\)",/\1/p') unset creds clearcreds () { unset AWS_SESSION_TOKEN unset AWS_SECRET_ACCESS_KEY unset AWS_ACCESS_KEY_ID } trap clearcreds EXIT # Generate, sign, and send the sigv4 request host="ec2-instance-connect.${region}.${domain}" endpoint="https://${host}" timestamp=$(/bin/date -u "+%Y-%m-%d %H:%M:%S") isoTimestamp=$(/bin/date -ud "${timestamp}" "+%Y%m%dT%H%M%SZ") isoDate=$(/bin/date -ud "${timestamp}" "+%Y%m%d") canonicalQuery="" # We are using POST data, not a querystring canonicalHeaders="host:${host}\nx-amz-date:${isoTimestamp}\nx-amz-security-token:${AWS_SESSION_TOKEN}\n" signedHeaders="host;x-amz-date;x-amz-security-token" payloadHash=$(/bin/echo -n "${val}" | /usr/bin/sha256sum | /bin/sed 's/\s.*$//') canonicalRequest="$(/usr/bin/printf "POST\n/PutEC2HostKeys/\n%s\n${canonicalHeaders}\n${signedHeaders}\n%s" "${canonicalQuery}" "${payloadHash}")" requestHash=$(/bin/echo -n "${canonicalRequest}" | /usr/bin/sha256sum | /bin/sed 's/\s.*$//') # Derive the signature credentialScope="${isoDate}/${region}/ec2-instance-connect/aws4_request" toSign="AWS4-HMAC-SHA256\n${isoTimestamp}\n${credentialScope}\n${requestHash}" signingKey=$(getsigv4key "${AWS_SECRET_ACCESS_KEY}" "${isoDate}" "${region}" "ec2-instance-connect") signature=$(sign "${signingKey}" "${toSign}") authorizationHeader="AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY_ID}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}" # Attempt to publish host keys # 5 second timeout helps avoid choking launches in private subnets (see https://github.com/aws/aws-ec2-instance-connect-config/issues/8) /usr/bin/curl -sS -m 5 -X POST -H "Content-Encoding: amz-1.0" -H "Authorization: ${authorizationHeader}" -H "Content-Type: application/json" -H "x-amz-content-sha256: ${payloadHash}" -H "x-amz-date: ${isoTimestamp}" -H "x-amz-security-token: ${AWS_SESSION_TOKEN}" -H "x-amz-target: com.amazon.aws.sshaccessproxyservice.AWSEC2InstanceConnectService.PutEC2HostKeys" -d "${val}" "${endpoint}/PutEC2HostKeys/" unset AWS_SESSION_TOKEN unset AWS_SECRET_ACCESS_KEY unset AWS_ACCESS_KEY_ID aws-ec2-instance-connect-config-1.1.12/src/bin/eic_parse_authorized_keys000077500000000000000000000365201361013163600262470ustar00rootroot00000000000000#!/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 authorized keys blob $3 and prints verified, unexpired keys # Openssl to use provided as $1 # Signer public key file path provided as $2 set -e # Set umask so only we can touch temp files umask 077 # Failure reporting & exit # Format: fail [is_debug] [message] fail () { if [ "${1}" = true ] ; then /bin/echo "${2}" else /usr/bin/logger -i -p authpriv.info "${2}" fi exit 1 } # Helper to determine if a string starts with a given prefix # Format: startswith [string] [prefix] startswith () { [ "${1#${2}}x" != "${1}x" ] } # Helper function to strip out a prefix from a string # Format: removeprefix [string] [prefix] removeprefix () { /usr/bin/printf '%s' "${1#${2}}" } # Helper to verify an arbitrary ocsp response body given the certificate and issuer # Format: verifyocsp [is_debug] [openssl command] [certificate] [issuer] [ocsp directory] 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[[:blank:]]*=[[:blank:]]*//p') 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) ocsp_exit="${?}" if [ "${ocsp_exit}" -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." fi } while getopts ":x:p:o:d:s:i:c:a:v:f:" o; do case "${o}" in x) is_debug="${OPTARG}" ;; p) keys_path="${OPTARG}" ;; o) OPENSSL="${OPTARG}" ;; d) tmpdir="${OPTARG}" ;; s) signer="${OPTARG}" ;; i) current_instance_id="${OPTARG}" ;; c) expected_cn="${OPTARG}" ;; a) ca_path="${OPTARG}" ;; v) ocsp_dir_path="${OPTARG}" ;; f) expected_key="${OPTARG}" ;; *) /bin/echo "Usage: $0 [-x debug] [-r key read command] [-o openssl command] [-d tmpdir] [-s signer certificate] [-i instance id] [-c cname] [-a ca path] [-v ocsp dir] [-f key fingerprint]" exit 1 ;; esac done # Verify we have sufficient inputs if [ $# -lt 1 ] ; then # No args whatsoever # Unit test log (ignored by sshd) /bin/echo "Usage: $0 [-x debug] [-r key read command] [-o openssl command] [-d tmpdir] [-s signer certificate] [-i instance id] [-c cname] [-a ca path] [-v ocsp dir] [-f key fingerprint]" # System log /usr/bin/logger -i -p authpriv.info "Unable to run EC2 Instance Connect: insufficient args provided. Please check your sshd configuration." exit 1 fi # Verify the signer certificate we have been provided - CN, trust chain, and revocation status # Split the chain into pieces /bin/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}/eic-cert-XXXXXXXX") end=$(/usr/bin/find "${tmpdir}" -maxdepth 1 -type f -name "cert*.pem" -regextype sed -regex ".*/cert[0-9]\+\.pem" | wc -l) if [ "${end}" -gt 0 ] ; then # First see if we already have them 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[[:space:]]*=[[:space:]]*//p') underscored=$(/bin/echo "${subject}" | /usr/bin/tr -s ' ' '_') 2>/dev/null if [ -f "${ca_path_dir}/${underscored}.pem" ] ; then # We already have it /bin/cp "${ca_path_dir}/${underscored}.pem" "${ca_bundles_dir}/${underscored}" else 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 /bin/touch "${tmpdir}/ca-trust.pem" for i in $(/usr/bin/seq 1 "${end}") ; do /bin/cat "${tmpdir}/cert${i}.pem" >> "${tmpdir}/ca-trust.pem" done 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}" | /usr/bin/tr -s ' ' '_') 2>/dev/null /bin/cat "${ca_bundles_dir}/${underscored}" >> "${tmpdir}/ca-trust.pem" 2>/dev/null else /bin/cat "${ca_path}" >> "${tmpdir}/ca-trust.pem" 2>/dev/null fi # At this point ca-trust is final /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[[: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 if [ -d "${ca_path}" ] ; then verify_out=$("${OPENSSL}" verify -x509_strict -CApath "${ca_path}" -CAfile "${tmpdir}/ca-trust.pem" "${tmpdir}/cert.pem") verify_status=$? else # If the CA path is not a directory then do not use it - openssl will throw errors on versions 1.1.1+ verify_out=$("${OPENSSL}" verify -x509_strict -CAfile "${tmpdir}/ca-trust.pem" "${tmpdir}/cert.pem") verify_status=$? fi if [ $verify_status -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 # Verify no certificates have been revoked # 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[[: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[[: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 # Already trusted, no need to OCSP verify break fi fi verifyocsp "${is_debug}" "${OPENSSL}" "${tmpdir}/cert${i}.pem" "${tmpdir}/cert$((i + 1)).pem" "${ocsp_dir_path}" done # At this point we no longer need the CA information /bin/rm -rf "${ca_bundles_dir}" # Extract cert public key /bin/echo "${signer}" | "${OPENSSL}" x509 -pubkey -noout > "${tmpdir}/pubkey" 2>/dev/null extract="${?}" if [ "${extract}" -ne 0 ] ; then fail "${is_debug}" "EC2 Instance Connect failed to extract the public key from the signer certificate. No keys have been trusted." fi # Begin actual parsing of authorized keys data if [ -n "${expected_key+x}" ] ; then # An expected fingerprint was given if [ "${is_debug}" = false ] ; then /usr/bin/logger -i -p authpriv.info "Querying EC2 Instance Connect keys for matching fingerprint: ${expected_key}" fi fi # Set current time as expiration marker curtime=$(/bin/date +%s) # We want to prevent variables from leaving the parser's scope # We also want to capture overall exit code # We also need to redirect the input into our loop # The simplest solution to all of the above is to take advantage of how sh pipes spawn a subprocess output=$( exitcode=255 # Exit code if no valid keys are provided count=0 # Read loop - pull timestamp line at start of iteration while read -r line do pathprefix="${tmpdir}/${count}" # Clear our temp buffers to prevent any sort of injection /bin/rm -f "${pathprefix}-key" /bin/rm -f "${pathprefix}-signedData" /bin/rm -f "${pathprefix}-sig" /bin/rm -f "${pathprefix}-decoded" # Pre-initialize key validation fields timestamp=0 instance_id="" caller="" request="" # We do not pre-initialize the actual key or signature fields /bin/touch "${pathprefix}-signedData" # Loop to read keys & parse out values # This is not sub-shelled as we want to maintain variable scope with the outer loop # Loop condition is until we reach a line that lacks the "#Key" format while startswith "${line}" "#" do # Note that not all of these may be present depending on service deployments # Similarly, this list is not meant to be exhaustive - there may be new fields to be checked in a later version if startswith "${line}" "#Timestamp=" ; then timestamp=$(removeprefix "${line}" "#Timestamp=") elif startswith "${line}" "#Instance=" ; then instance_id=$(removeprefix "${line}" "#Instance=") elif startswith "${line}" "#Caller=" ; then caller=$(removeprefix "${line}" "#Caller=") elif startswith "${line}" "#Request=" ; then request=$(removeprefix "${line}" "#Request=") # Otherwise it's a #Key we don't recognize (i.e., this version of AuthorizedKeysCommand is outdated) fi # We verify on all fields in-order, whether we recognize them or not. Similarly, we don't force fields not present. # As such we always add this to the signature verification file /usr/bin/printf '%s\n' "${line}" >> "${pathprefix}-signedData" # Read the next line read -r line done # At this point, line should contain the key if startswith "${line}" "ssh" ; then key="${line}" /usr/bin/printf '%s\n' "${key}" >> "${pathprefix}-signedData" # At this point we do not need to modify signedData /bin/chmod 400 "${pathprefix}-signedData" # Read key signature - may be multi-line encodedsigfile="${pathprefix}-sig" /bin/touch "${encodedsigfile}" read -r sigline || sigline="" while [ "${sigline}" != "" ] do /usr/bin/printf '%s\n' "${sigline}" >> "${encodedsigfile}" read -r sigline || sigline="" done /bin/chmod 400 "${encodedsigfile}" /usr/bin/printf '%s\n' "${key}" > "${pathprefix}-key" # Begin validation if [ -n "${instance_id}" ] && [ "${timestamp}" -ne 0 ] ; then fingerprint=$(/usr/bin/ssh-keygen -lf "${pathprefix}-key" | cut -d ' ' -f 2) # Get only the actual fingerprint, ignore key size & source # If we were told to expect a specific key and this isn't it, skip it if [ -z "${expected_key}" ] || [ "$fingerprint" = "${expected_key}" ] ; then # Check instance ID matches & timestamp is still valid if [ "${current_instance_id}" = "${instance_id}" ] && [ "${timestamp}" -gt "${curtime}" ] ; then # Decode the signature (/usr/bin/base64 --decode "${encodedsigfile}" > "${pathprefix}-decoded" || rm -f "${pathprefix}-decoded") 2>/dev/null if [ -f "${pathprefix}-decoded" ] ; then # Verify signature $OPENSSL dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -verify "${tmpdir}/pubkey" -signature "${pathprefix}-decoded" "${pathprefix}-signedData" 1>/dev/null 2>/dev/null verify="${?}" if [ "${verify}" -eq 0 ] ; then # Signature verified. # Record this in syslog callermessage="Providing ssh key from EC2 Instance Connect with fingerprint: ${fingerprint}" if [ "${request}" != "" ] ; then callermessage="${callermessage}, request-id: ${request}" fi if [ "${caller}" != "" ] ; then callermessage="${callermessage}, for IAM principal: ${caller}" fi if [ "${is_debug}" = false ] ; then /usr/bin/logger -i -p authpriv.info "${callermessage}" fi # Return key to the ssh daemon /bin/echo "${key}" exitcode=0 fi fi fi fi fi else # We didn't find a key. Skip until we hit a blank line or EOF while [ "${line}" != "" ] do read -r line || line="" done fi # Clean up any tempfiles /bin/rm -f "${pathprefix}-key" /bin/rm -f "${pathprefix}-signedData" /bin/rm -f "${pathprefix}-sig" /bin/rm -f "${pathprefix}-decoded" count=$((count + 1)) done < "${keys_path}" # This is the loop subprocess's exit code, not the script's exit $exitcode ) # Re-capture the exit code exitcode=$? # Print keys & exit /bin/rm -rf "${tmpdir}/pubkey" /bin/echo "${output}" exit $exitcode aws-ec2-instance-connect-config-1.1.12/src/bin/eic_run_authorized_keys000077500000000000000000000014671361013163600257430ustar00rootroot00000000000000#!/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. # Quickie to wrap curl_authorized_keys in a timeout # Necessary for older versions of openssh where AuthorizedKeysCommand must be a filepath set -e DIR="$( cd "$( dirname "${0}" )" && pwd )" /usr/bin/timeout 5s "${DIR}/eic_curl_authorized_keys" "$@" aws-ec2-instance-connect-config-1.1.12/src/deb_systemd/000077500000000000000000000000001361013163600226225ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/deb_systemd/ec2-instance-connect.service000066400000000000000000000003641361013163600301110ustar00rootroot00000000000000[Unit] Description=EC2 Instance Connect Host Key Harvesting Before=ssh.service After=network.target ssh-keygen.service [Install] WantedBy=multi-user.target [Service] Type=oneshot ExecStart=/usr/share/ec2-instance-connect/eic_harvest_hostkeys aws-ec2-instance-connect-config-1.1.12/src/deb_systemd/ssh.service.d/000077500000000000000000000000001361013163600253005ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/deb_systemd/ssh.service.d/ec2-instance-connect.conf000066400000000000000000000003131361013163600320460ustar00rootroot00000000000000[Service] ExecStart= ExecStart=/usr/sbin/sshd -D -o "AuthorizedKeysCommand /usr/share/ec2-instance-connect/eic_run_authorized_keys %%u %%f" -o "AuthorizedKeysCommandUser ec2-instance-connect" $SSHD_OPTS aws-ec2-instance-connect-config-1.1.12/src/ec2-instance-connect.preset000066400000000000000000000000441361013163600254440ustar00rootroot00000000000000enable ec2-instance-connect.service aws-ec2-instance-connect-config-1.1.12/src/rpm_systemd/000077500000000000000000000000001361013163600226665ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/rpm_systemd/ec2-instance-connect.service000066400000000000000000000003431361013163600301520ustar00rootroot00000000000000[Unit] Description=EC2 Instance Connect Host Key Harvesting Before=sshd.service After=network.target sshd-keygen.service [Install] WantedBy=multi-user.target [Service] Type=oneshot ExecStart=/opt/aws/bin/eic_harvest_hostkeys aws-ec2-instance-connect-config-1.1.12/src/rpm_systemd/sshd.service.d/000077500000000000000000000000001361013163600255105ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/src/rpm_systemd/sshd.service.d/ec2-instance-connect.conf000066400000000000000000000002701361013163600322600ustar00rootroot00000000000000[Service] ExecStart= ExecStart=/usr/sbin/sshd -D -o "AuthorizedKeysCommand /opt/aws/bin/eic_run_authorized_keys %%u %%f" -o "AuthorizedKeysCommandUser ec2-instance-connect" $SSHD_OPTS aws-ec2-instance-connect-config-1.1.12/unit-test/000077500000000000000000000000001361013163600214655ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/000077500000000000000000000000001361013163600246245ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/different-fingerprint000066400000000000000000000000001361013163600310300ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/empty000066400000000000000000000000001361013163600256730ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/expired-timestamp000066400000000000000000000000001361013163600301760ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/invalid-instance000066400000000000000000000000001361013163600277650ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/invalid-signature000066400000000000000000000000001361013163600301620ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/missing-data000066400000000000000000000005751361013163600271360ustar00rootroot00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/mixed000066400000000000000000000021671361013163600256630ustar00rootroot00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/expected-output/valid-key000066400000000000000000000005751361013163600264430ustar00rootroot00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/000077500000000000000000000000001361013163600226245ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/direct/000077500000000000000000000000001361013163600240765ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/direct/empty000066400000000000000000000000001361013163600251450ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/direct/invalid-signature000066400000000000000000000010351361013163600274450ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR this is not a valid signature aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/000077500000000000000000000000001361013163600244405ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/different-fingerprint/000077500000000000000000000000001361013163600307335ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/different-fingerprint/1000066400000000000000000000007771361013163600310310ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIw1S08VWxugMRmPrMOCLbC/0oaOCvpYrzJBA9vQ2Mx68SwWb9Dt5TJ0c8/mIr5R/riHqUn1WxWuxpESbfT2wFd8wVDlp+sIElDCfVvJOY8O9KJL9OOeP8y+mnxAy9ZK2CnGH49P8fHlcPFs9xQGXB48rU2WY73KMGjg1COVdFZHiFNociNAKtpsrPuxK8HZ8pcRrmVFJHl8sgvH8/n8al+DFFebCyE2HIU5kQndWSMoYuBiNhlYDdte7HTxutyzFzawYHfObVoZnjQcIy9A66Zaf8qBt7vQn0LCxJ3FtTDwY+S9UTdenZ3G+Rq/mIB6Tmh2YAeVao72O7+ngEnAsX aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/expired-timestamp/000077500000000000000000000000001361013163600301015ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/expired-timestamp/1000066400000000000000000000007771361013163600301770ustar00rootroot00000000000000#Timestamp=0000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/invalid-instance/000077500000000000000000000000001361013163600276705ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/invalid-instance/1000066400000000000000000000007771361013163600277660ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-mismatch #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/missing-data/000077500000000000000000000000001361013163600270205ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/missing-data/1000066400000000000000000000007511361013163600271060ustar00rootroot00000000000000#Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/missing-data/2000066400000000000000000000007521361013163600271100ustar00rootroot00000000000000#Timestamp=2000000000 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/missing-data/3000066400000000000000000000006501361013163600271060ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/missing-data/4000066400000000000000000000002021361013163600271000ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/000077500000000000000000000000001361013163600255465ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/1000066400000000000000000000007771361013163600256440ustar00rootroot00000000000000#Timestamp=0000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/2000066400000000000000000000007771361013163600256450ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/3000066400000000000000000000007771361013163600256460ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-mismatch #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/4000066400000000000000000000007771361013163600256470ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIw1S08VWxugMRmPrMOCLbC/0oaOCvpYrzJBA9vQ2Mx68SwWb9Dt5TJ0c8/mIr5R/riHqUn1WxWuxpESbfT2wFd8wVDlp+sIElDCfVvJOY8O9KJL9OOeP8y+mnxAy9ZK2CnGH49P8fHlcPFs9xQGXB48rU2WY73KMGjg1COVdFZHiFNociNAKtpsrPuxK8HZ8pcRrmVFJHl8sgvH8/n8al+DFFebCyE2HIU5kQndWSMoYuBiNhlYDdte7HTxutyzFzawYHfObVoZnjQcIy9A66Zaf8qBt7vQn0LCxJ3FtTDwY+S9UTdenZ3G+Rq/mIB6Tmh2YAeVao72O7+ngEnAsX aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/5000066400000000000000000000007771361013163600256500ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/6000066400000000000000000000007471361013163600256460ustar00rootroot00000000000000#Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR ec2-user@localhost aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/mixed/7000066400000000000000000000007771361013163600256520ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/valid-key/000077500000000000000000000000001361013163600263255ustar00rootroot00000000000000aws-ec2-instance-connect-config-1.1.12/unit-test/input/unsigned/valid-key/1000066400000000000000000000007771361013163600264230ustar00rootroot00000000000000#Timestamp=2000000000 #Instance=i-abcd1234 #Caller=arn:aws:iam::123412341234:role/myrole #Request=1234abcd-1234-abcd-1234abcd1234 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQmefSRJyiAUSlICBKAO+4heV1kkA46PQm5ZQVxxhv7pF1yWWLhgFJ9IG9qmeeKIQ3bzKBzGv5UHSeJbuRfwY6ZtKynBfjzN1WRuYY2oaDjlh2vzK5WgvVttUJk8oAYcZM2h+aXpJtlWV95yqaTSD4XcuWOg3E3KCTcK2Xf/BaB4IN/pJF1SyuLg5ygWh0dKi4X+tH81aHcEg8pWfDLFkdKUF0d6GwIi+iCJxfb5bubY3/+0qYc0IqWOxa4vf6ggW7yI5m3mOX0kRuOAPEY/6fe4KfcGqLZvraKe1ZLYMgQUKuawhpPzooVeI/EtI3gtFDC0b8YAPjA2CUDc/3APR