Path: blob/develop/awscli/customizations/ec2/decryptpassword.py
1567 views
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.1#2# Licensed under the Apache License, Version 2.0 (the "License"). You3# may not use this file except in compliance with the License. A copy of4# the License is located at5#6# http://aws.amazon.com/apache2.0/7#8# or in the "license" file accompanying this file. This file is9# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF10# ANY KIND, either express or implied. See the License for the specific11# language governing permissions and limitations under the License.12import logging13import os14import base6415import rsa1617from botocore import model1819from awscli.arguments import BaseCLIArgument202122logger = logging.getLogger(__name__)232425HELP = """<p>The file that contains the private key used to launch26the instance (e.g. windows-keypair.pem). If this is supplied, the27password data sent from EC2 will be decrypted before display.</p>"""282930def ec2_add_priv_launch_key(argument_table, operation_model, session,31**kwargs):32"""33This handler gets called after the argument table for the34operation has been created. It's job is to add the35``priv-launch-key`` parameter.36"""37argument_table['priv-launch-key'] = LaunchKeyArgument(38session, operation_model, 'priv-launch-key')394041class LaunchKeyArgument(BaseCLIArgument):4243def __init__(self, session, operation_model, name):44self._session = session45self.argument_model = model.Shape('LaunchKeyArgument', {'type': 'string'})46self._operation_model = operation_model47self._name = name48self._key_path = None49self._required = False5051@property52def cli_type_name(self):53return 'string'5455@property56def required(self):57return self._required5859@required.setter60def required(self, value):61self._required = value6263@property64def documentation(self):65return HELP6667def add_to_parser(self, parser):68parser.add_argument(self.cli_name, dest=self.py_name,69help='SSH Private Key file')7071def add_to_params(self, parameters, value):72"""73This gets called with the value of our ``--priv-launch-key``74if it is specified. It needs to determine if the path75provided is valid and, if it is, it stores it in the instance76variable ``_key_path`` for use by the decrypt routine.77"""78if value:79path = os.path.expandvars(value)80path = os.path.expanduser(path)81if os.path.isfile(path):82self._key_path = path83endpoint_prefix = \84self._operation_model.service_model.endpoint_prefix85event = 'after-call.%s.%s' % (endpoint_prefix,86self._operation_model.name)87self._session.register(event, self._decrypt_password_data)88else:89msg = ('priv-launch-key should be a path to the '90'local SSH private key file used to launch '91'the instance.')92raise ValueError(msg)9394def _decrypt_password_data(self, parsed, **kwargs):95"""96This handler gets called after the GetPasswordData command has been97executed. It is called with the and the ``parsed`` data. It checks to98see if a private launch key was specified on the command. If it was,99it tries to use that private key to decrypt the password data and100replace it in the returned data dictionary.101"""102if self._key_path is not None:103logger.debug("Decrypting password data using: %s", self._key_path)104value = parsed.get('PasswordData')105if not value:106return107try:108with open(self._key_path) as pk_file:109pk_contents = pk_file.read()110private_key = rsa.PrivateKey.load_pkcs1(pk_contents.encode("latin-1"))111value = base64.b64decode(value)112value = rsa.decrypt(value, private_key)113logger.debug(parsed)114parsed['PasswordData'] = value.decode('utf-8')115logger.debug(parsed)116except Exception:117logger.debug('Unable to decrypt PasswordData', exc_info=True)118msg = ('Unable to decrypt password data using '119'provided private key file.')120raise ValueError(msg)121122123