Keypairs

EC2 allows public and private keypairs to be associated with your AWS account as a KeyPair resource that is stored in the EC2 environment. The service will generate a named keypair on demand and will provide you with a once-only downloadable private key. The service keeps an internal copy of the public key corresponding to the private key. When you launch an instance in the service, you can ask the environment to provide the public key from one of your keypairs to the instance as contextual data. The instance can then use this public key as one half of the access credentials required to perform a secure login, so that only someone with access to the corresponding private key can access the instance.

This technique makes it possible to restrict access to EC2 instances to only the user who started a particular instance, despite the fact that many different users may use the same AMI as a starting point for their instance. The keypair access mechanism takes advantage of the EC2 environment’s ability to provide contextual data to an instance (see Instance Data” in Chapter 6), and it relies on the instance being configured to obtain the public key and apply it as a login credential (see Startup Scripts” in Chapter 6).

The publicly available AMIs provided by Amazon are configured to allow secure login based on a keypair that belongs to the user who launches an instance. Because we will be starting with these public AMIs to demonstrate the EC2 API, we must create a keypair before launching an instance.

Note

If an AMI is configured to allow only keypair-based access, and you start an instance without assigning it a keypair of your own, you will be unable to log in to the instance to customize its content. You will be able to control the instance’s lifecycle and terminate it, but that will be the limit of your control.

Let us take a look at the EC2 API operations for working with keypairs.

The DescribeKeyPairs operation shown in Table 5-3 lists information about your keypairs, including their names and fingerprints. You can filter the listing by name to display the details of specific keypairs.

Here is an XML document returned by the operation:

<DescribeKeyPairsResponse xmlns='http://ec2.amazonaws.com/doc/2007-08-29/'>
  <keySet>
    <item>    
      <keyName>ec2-private-key</keyName>
      <keyFingerprint>5e:93:4c:dd:c3:cb:a6...:d6:4e:13:4d:85</keyFingerprint>
    </item>
  </keySet>
</DescribeKeyPairsResponse>

The document includes a set of item elements inside the keySet element. As Table 5-4 shows, each item contains two elements with information about a keypair.

Example 5-2 defines a method that lists the keypairs you have created in your EC2 account as an array of hash dictionary objects.

Because this is our first EC2 API implementation method, we should take a close look at how it works. To prepare the request parameter inputs we must provide to the service, we invoke the build_query_params method with two hash variables. The first variable is the set of standard parameter names and value mappings that will be included unmodified in the request. The second variable is a set of indexed parameters. The indexed parameters must be converted into multiple parameter name-and-value pairs with a unique number suffix for each parameter name, a task performed by the build_query_params method (see Example 2-6).

The query execution performed by the AWS module’s do_query method is quite straightforward; it simply provides the the operation-specific parameters and performs the request using the default HTTP method and EC2 endpoint URI constants defined in the EC2 class. When the EC2 service sends an XML document in response to a request, we interpret the document and store the information in a Ruby data structure for easier access.

If you have not yet created your own keypairs, you will see the following result when you run the new method:

# Load the EC2 library for the first time and create an EC2 client object
irb> require 'EC2'
irb> ec2 = EC2.new

# List your keypairs
irb> ec2.describe_keypairs
=> []

That empty listing of keypairs is a sorry sight; we have no credentials to our name. We will remedy this straightaway by creating a new keypair.

The hard work of creating a keypair is performed by the CreateKeyPair operation, outlined in Table 5-5. This action instructs EC2 to generate a 2,048-bit public and private keypair using the RSA (Rivest-Shamir-Adleman) public-key cryptographic algorithm and to assign this pair a name. The public key component is stored in your EC2 environment and can be referenced using the name you assigned to the keypair. The private key is provided to you in the action’s response message. It is your responsibility to store the private key, keep it safe, and provide it when you log in to your instances.

Warning

Your private key will only be provided to you once, at the time the keypair is created. If you forget to save your private key data or lose it, you will not be able to use the keypair; you will have to create a new one.

Here is an XML document returned by the operation:

<CreateKeyPairResponse xmlns='http://ec2.amazonaws.com/doc/2007-08-29/'>
  <keyName>ec2-private-key</keyName>
  <keyFingerprint>8a:e3:e4:9e:3b:4b:9f:32:02:56:c4:b2:0b:8d:2b:cb:f1:70:bf:22</keyFingerprint>
  <keyMaterial>—————BEGIN RSA PRIVATE KEY—————
MIIEogIBAAKCAQEApDs8hK6g88TwTkn+kXYQIh9djl4DD3tYUeJ0oRc7nD+/FvYWLjqcYb3YcNAk
r+mMog5fvvcagJhhEaglKpEytxho4/Rh4Y5N4iuHAR8mXPfwge6PdwR4gC9BHOJGakZUBLkEBAUf
zDXKmmYip7Gu7EO7KtK+PJZ1BDtyaFjUdRWM3Bz+liMAijMwATCCQbnZ++mZe/41CA8cw2TLRamg
...YfwdpnslPpw/7SiWlGhJRyeBCB9GwuVXxnRlp9hQEkwBAoGAN+QSK4H22ULTSLUwAfigwXsnhQiS
8W836EP6GOlGcKBBNtmW+BE1u0xy40KKxRMNw994nVVhCKkFvj6ugmTepwMDISrnOG0EK/L/3aaV
2yN9ear1nkK4DQAu5zRcym0QK/qt66Dk2+tUIJSxxkrTzpCLWTs3Bz1V4n9jjORttFo=
—————END RSA PRIVATE KEY—————</keyMaterial>
</CreateKeyPairResponse>

The response document includes the name and fingerprint details of the newly created keypair. These are the same details we saw above in the discussion of the DescribeKeyPairs operation. However, the most important part of this message is the keyMaterial element.

The keyMaterial element contains the private key data for the new keypair, encoded as an unencrypted RSA key in the PEM format. You must store this data somewhere safe on your computer, so you can use the private key to access the instances you launch. If you are concerned about the security of your private key, as you should be, it would be wise to encrypt it so it can only be accessed with a password. We will demonstrate how to do this below.

Example 5-3 defines a method that creates a new keypair in your EC2 account. If the method’s autosave parameter is set to the value true, as it is by default, the private key material returned by the service will be automatically written to a file named after the keypair name.

We will run this method now to create a keypair that we can use later on to gain access to the EC2 instances we launch. In this book, we will use the name “ec2-private-key” for this keypair.

irb> keypair = ec2.create_keypair('ec2-private-key', true)
=> {
:name=>"ec2-private-key", 
:fingerprint=>"99:e4:32:8d:5c:2c:52:22:99:a2:a6:27:ac:2f:78:27:26:61:88:e4",
:file_name=>"ec2-private-key.pem", 
:material=>"—————BEGIN RSA PRIVATE KEY—————\n
MIIEpAIBAAKCAQEAjW+Y70NBdp4Cw1lD9xTrUKYlp6iaOo1EuOcK793RAqBaaOV7I5eRUGQbgwb2\
. . . 
B2zgtZqfc7x2mZ+U+Jsp2W6KooInOiSI5tlW22DZ5zF3nkZtQstoA0jCcjGQ==\n
—————END RSA PRIVATE KEY—————"
}

Because we ran this method with the autosave parameter set to true, the method will have written the vital private key data to a file and returned the name of this file in the hash item named :file_name.

irb> keypair[:file_name] # => "ec2-private-key.pem"

If you wish to encrypt your private key file, as we recommend you do, you can run the following OpenSSL command at a command prompt to encrypt the file using the DES3 algorithm.

$ openssl rsa -des3 -inform PEM -outform PEM \ 
  -in ec2-private-key.pem -out ec2-private-key.enc

When you run this command, you will be prompted to enter a password, and the key will be encrypted and written to a new filename you provide to the -out option. Once this is done, you will have to supply the correct password before you will be able to access the encrypted key file. After you have encrypted the file, be sure to delete the original, unencrypted file, once you have confirmed that the new encrypted version works properly.

To confirm that the new keypair is installed in our EC2 account, we will again list all our keypairs.

irb> ec2.describe_keypairs
=> [{
:name=>"ec2-private-key",
:fingerprint=>"5e:93:4c:dd:c3:cb:a6:32:25:6a:aa:9a:2d:d7:42:d6:4e:13:4d:85"
}]

Now that we have created a keypair and saved the private key component as a local file, we will be able to work with the access control mechanism used by the Amazon public AMIs.

The DeleteKeyPair operation shown in Table 5-6 removes a named keypair from your EC2 account. There will be times when you want to delete a keypair, such as if you lose your private key data file, or if you are security-conscious and disciplined enough to change your keys at regular intervals.

Here is an XML document returned by the operation. It is very simple, containing only a return element with a Boolean value that indicates whether or not the keypair was successfully deleted.

<DeleteKeyPairResponse xmlns='http://ec2.amazonaws.com/doc/2007-08-29/'>
  <return>true</return>
</DeleteKeyPairResponse>

Example 5-4 defines a method that deletes a keypair from your account. The method always returns true, unless the operation fails with an error.

Here is the command to delete a keypair that is no longer needed:

irb> ec2.delete_keypair('keypair-name')
=> true