Exemplo n.º 1
0
 def download_ssh_pubkey( self, ec2_keypair ):
     try:
         bucket = self.s3.get_bucket( self.s3_bucket_name )
         s3_entry = S3Key( bucket )
         s3_entry.key = self.ssh_pubkey_s3_key_prefix + ec2_keypair.fingerprint
         ssh_pubkey = s3_entry.get_contents_as_string( )
     except S3ResponseError as e:
         if e.status == 404:
             raise UserError(
                 "There is no matching SSH pub key stored in S3 for EC2 key pair %s. Has "
                 "it been registered, e.g using the cgcloud's register-key command?" %
                 ec2_keypair.name )
         else:
             raise
     fingerprint_len = len( ec2_keypair.fingerprint.split( ':' ) )
     if fingerprint_len == 20:  # 160 bit SHA-1
         # The fingerprint is that of a private key. We can't get at the private key so we
         # can't verify the public key either. So this is inherently insecure. However,
         # remember that the only reason why we are dealing with n EC2-generated private
         # key is that the Jenkins' EC2 plugin expects a 20 byte fingerprint. See
         # https://issues.jenkins-ci.org/browse/JENKINS-20142 for details. Once that issue
         # is fixed, we can switch back to just using imported keys and 16-byte fingerprints.
         pass
     elif fingerprint_len == 16:  # 128 bit MD5
         fingerprint = ec2_keypair_fingerprint( ssh_pubkey )
         if ec2_keypair.fingerprint != fingerprint:
             raise UserError(
                 "Fingerprint mismatch for key %s! Expected %s but got %s. The EC2 keypair "
                 "doesn't match the public key stored in S3." %
                 (ec2_keypair.name, ec2_keypair.fingerprint, fingerprint) )
     return ssh_pubkey
Exemplo n.º 2
0
 def download_ssh_pubkey(self, ec2_keypair):
     try:
         bucket = self.s3.get_bucket(self.s3_bucket_name)
         s3_entry = S3Key(bucket)
         s3_entry.key = self.ssh_pubkey_s3_key_prefix + ec2_keypair.fingerprint
         ssh_pubkey = s3_entry.get_contents_as_string()
     except S3ResponseError as e:
         if e.status == 404:
             raise UserError(
                 "There is no matching SSH pub key stored in S3 for EC2 key pair %s. Has "
                 "it been registered, e.g using the cgcloud's register-key command?"
                 % ec2_keypair.name)
         else:
             raise
     fingerprint_len = len(ec2_keypair.fingerprint.split(':'))
     if fingerprint_len == 20:  # 160 bit SHA-1
         # The fingerprint is that of a private key. We can't get at the private key so we
         # can't verify the public key either. So this is inherently insecure. However,
         # remember that the only reason why we are dealing with n EC2-generated private
         # key is that the Jenkins' EC2 plugin expects a 20 byte fingerprint. See
         # https://issues.jenkins-ci.org/browse/JENKINS-20142 for details. Once that issue
         # is fixed, we can switch back to just using imported keys and 16-byte fingerprints.
         pass
     elif fingerprint_len == 16:  # 128 bit MD5
         fingerprint = ec2_keypair_fingerprint(ssh_pubkey)
         if ec2_keypair.fingerprint != fingerprint:
             raise UserError(
                 "Fingerprint mismatch for key %s! Expected %s but got %s. The EC2 keypair "
                 "doesn't match the public key stored in S3." %
                 (ec2_keypair.name, ec2_keypair.fingerprint, fingerprint))
     return ssh_pubkey
Exemplo n.º 3
0
 def __generate_keypair( self, ec2_keypair_name, private_key_path ):
     """
     Generate a keypair in EC2 using the given name and write the private key to the file at
     the given path. Return the private and public key contents as a tuple.
     """
     ec2_keypair = self.ctx.ec2.create_key_pair( ec2_keypair_name )
     if not ec2_keypair.material:
         raise AssertionError( "Created key pair but didn't get back private key" )
     ssh_privkey = ec2_keypair.material
     put( local_path=StringIO( ssh_privkey ), remote_path=private_key_path )
     assert ec2_keypair.fingerprint == ec2_keypair_fingerprint( ssh_privkey )
     run( 'chmod go= %s' % private_key_path )
     ssh_pubkey = private_to_public_key( ssh_privkey )
     self.ctx.upload_ssh_pubkey( ssh_pubkey, ec2_keypair.fingerprint )
     return ssh_privkey, ssh_pubkey
Exemplo n.º 4
0
    def register_ssh_pubkey(self, ec2_keypair_name, ssh_pubkey, force=False):
        """
        Import the given OpenSSH public key  as a 'key pair' into EC2.

        There is no way to get to the actual public key once it has been imported to EC2.
        Openstack lets you do that and I don't see why Amazon decided to omit this functionality.
        To work around this, we store the public key in S3, identified by the public key's
        fingerprint. As long as we always check the fingerprint of the downloaded public SSH key
        against that of the EC2 keypair key, this method is resilient against malicious
        modifications of the keys stored in S3.

        :param ec2_keypair_name: the desired name of the EC2 key pair

        :param ssh_pubkey: the SSH public key in OpenSSH's native format, i.e. format that is used in ~/
        .ssh/authorized_keys

        :param force: overwrite existing EC2 keypair of the given name
        """
        fingerprint = ec2_keypair_fingerprint(ssh_pubkey,
                                              reject_private_keys=True)
        ec2_keypair = self.ec2.get_key_pair(ec2_keypair_name)
        if ec2_keypair is not None:
            if ec2_keypair.name != ec2_keypair_name:
                raise AssertionError("Key pair names don't match.")
            if ec2_keypair.fingerprint != fingerprint:
                if force:
                    self.ec2.delete_key_pair(ec2_keypair_name)
                    ec2_keypair = None
                else:
                    raise UserError(
                        "Key pair %s already exists in EC2, but its fingerprint %s is "
                        "different from the fingerprint %s of the key to be imported. Use "
                        "the force option to overwrite the existing key pair."
                        % (ec2_keypair.name, ec2_keypair.fingerprint,
                           fingerprint))

        if ec2_keypair is None:
            ec2_keypair = self.ec2.import_key_pair(ec2_keypair_name,
                                                   ssh_pubkey)
        assert ec2_keypair.fingerprint == fingerprint

        self.upload_ssh_pubkey(ssh_pubkey, fingerprint)
        self.__publish_key_update_agent_message()
        return ec2_keypair
Exemplo n.º 5
0
    def register_ssh_pubkey(self, ec2_keypair_name, ssh_pubkey, force=False):
        """
        Import the given OpenSSH public key  as a 'key pair' into EC2.

        There is no way to get to the actual public key once it has been imported to EC2.
        Openstack lets you do that and I don't see why Amazon decided to omit this functionality.
        To work around this, we store the public key in S3, identified by the public key's
        fingerprint. As long as we always check the fingerprint of the downloaded public SSH key
        against that of the EC2 keypair key, this method is resilient against malicious
        modifications of the keys stored in S3.

        :param ec2_keypair_name: the desired name of the EC2 key pair

        :param ssh_pubkey: the SSH public key in OpenSSH's native format, i.e. format that is used in ~/
        .ssh/authorized_keys

        :param force: overwrite existing EC2 keypair of the given name
        """
        fingerprint = ec2_keypair_fingerprint(ssh_pubkey, reject_private_keys=True)
        ec2_keypair = self.ec2.get_key_pair(ec2_keypair_name)
        if ec2_keypair is not None:
            if ec2_keypair.name != ec2_keypair_name:
                raise AssertionError("Key pair names don't match.")
            if ec2_keypair.fingerprint != fingerprint:
                if force:
                    self.ec2.delete_key_pair(ec2_keypair_name)
                    ec2_keypair = None
                else:
                    raise UserError(
                        "Key pair %s already exists in EC2, but its fingerprint %s is "
                        "different from the fingerprint %s of the key to be imported. Use "
                        "the force option to overwrite the existing key pair."
                        % (ec2_keypair.name, ec2_keypair.fingerprint, fingerprint)
                    )

        if ec2_keypair is None:
            ec2_keypair = self.ec2.import_key_pair(ec2_keypair_name, ssh_pubkey)
        assert ec2_keypair.fingerprint == fingerprint

        self.upload_ssh_pubkey(ssh_pubkey, fingerprint)
        self.__publish_key_update_agent_message()
        return ec2_keypair
Exemplo n.º 6
0
 def __verify_generated_keypair( self, ec2_keypair, private_key_path ):
     """
     Verify that the given EC2 keypair matches the private key at the given path. Return the
     private and public key contents as a tuple.
     """
     ssh_privkey = StringIO( )
     get( remote_path=private_key_path, local_path=ssh_privkey )
     ssh_privkey = ssh_privkey.getvalue( )
     fingerprint = ec2_keypair_fingerprint( ssh_privkey )
     if ec2_keypair.fingerprint != fingerprint:
         raise UserError(
             "The fingerprint {ec2_keypair.fingerprint} of key pair {ec2_keypair.name} doesn't "
             "match the fingerprint {fingerprint} of the private key file currently present on "
             "the instance. Please delete the key pair from EC2 before retrying. "
                 .format( **locals( ) ) )
     ssh_pubkey = self.ctx.download_ssh_pubkey( ec2_keypair )
     if ssh_pubkey != private_to_public_key( ssh_privkey ):
         raise RuntimeError( "The private key on the data volume doesn't match the "
                             "public key in EC2." )
     return ssh_privkey, ssh_pubkey