36

There is a very good question on [How to] SSH to Elastic [an] Beanstalk instance, but one thing I noticed is that, through this method, it is only possible to add one SSH key.

How can I add multiple SSH keys to an instance? Is there a way to automatically add multiple keys to new instances?

Community
  • 1
  • 1
NT3RP
  • 14,302
  • 9
  • 56
  • 96

8 Answers8

42

To create a file named .ebextensions/authorized_keys.config is another way to do it.

files:
  /home/ec2-user/.ssh/authorized_keys:
    mode: "000400"
    owner: ec2-user
    group: ec2-user
    content: |
      ssh-rsa AAAB3N...QcGskx keyname
      ssh-rsa BBRdt5...LguTtp another-key

The name of file authorized_keys.config is arbitrary.

rch850
  • 625
  • 5
  • 13
  • 1
    This works perfectly. However, by default the authorized_keys will already have one ssh key (you have to choose one when creating the environment) and you need to remember to add that key to this file or it will be erased on deploy and you can lost the access to the server. – Roberto Schneiders Aug 05 '15 at 12:15
  • 1
    ^ and to get the ssh key `eb ssh` into the instance and type `cat ~ec2-user/.ssh/authorized_keys` – Ashley Coolman Feb 03 '16 at 12:20
  • During subsequent deployments wont it append keyname and another-key each time? Leading to duplications until you rebuild the environment? – Max Jun 30 '17 at 07:11
  • @Max No it won't. It will overwrite `authorized_keys`. – rch850 Jul 03 '17 at 04:17
  • This is a great solution - I wonder is it possible to add these files via an environment variable, in which case you would be able to manage access without rebuilding an environment? – contool Feb 22 '18 at 15:09
  • I'm glad I scrolled down until I found the right (laziest) answer. This should be it! – helsont May 09 '18 at 00:25
  • I had to quote the filename to get this to work, but works never the less – Dean Sep 21 '18 at 11:24
24

Combining rhunwicks's and rch850's answers, here's a clean way to add additional SSH keys, while preserving the one set through the AWS console:

files:
  /home/ec2-user/.ssh/extra_authorized_keys:
    mode: "000400"
    owner: ec2-user
    group: ec2-user
    content: |
      ssh-rsa AAAB3N...QcGskx keyname
      ssh-rsa BBRdt5...LguTtp another-key
commands:
  01_append_keys:
    cwd: /home/ec2-user/.ssh/
    command: sort -u extra_authorized_keys authorized_keys -o authorized_keys
  99_rm_extra_keys:
    cwd: /home/ec2-user/.ssh/
    command: rm extra_authorized_keys

Note that eb ssh will work only if the private key file has the same name as the private key defined in the AWS console.

scribu
  • 2,751
  • 4
  • 25
  • 43
14

Following on from Jim Flanagan's answer, you could get the keys added to every instance by creating .ebextensions/app.config in your application source directory with contents:

commands:
  copy_ssh_key_userA: 
    command: echo "ssh-rsa AAAB3N...QcGskx userA" >> /home/ec2-user/.ssh/authorized_keys
  copy_ssh_key_userB: 
    command: echo "ssh-rsa BBRdt5...LguTtp userB" >> /home/ec2-user/.ssh/authorized_keys
rhunwicks
  • 2,986
  • 21
  • 20
  • 1
    The problem of this approach is that it will concatenate the file on every deploy. The solution proposed by @rch850 doesn't have this problem. – Roberto Schneiders Aug 05 '15 at 12:09
  • When I copy pasted this code I get some bad chars that aren't spaces, please watch out for that – HaveAGuess Mar 08 '16 at 12:14
  • 3
    You could avoid the concatenation problem mentioned by @RobertoSchneiders by adding an additional deduping command: `command: sort -u /home/ec2-user/.ssh/authorized_keys -o /home/ec2-user/.ssh/authorized_keys` – mpatek Jun 22 '16 at 16:41
10

No, Elastic Beanstalk only supports a single key pair. You can manually add SSH keys to the authorized_keys file, but these will not be known to the Elastic Beanstalk tools.

Ken Liu
  • 21,056
  • 17
  • 71
  • 96
7

One way you could accomplish this is to create a user data script which appends the public keys of the additional key-pairs you want to use to ~ec2-user/.ssh/authorized_keys, and launch the instance with that user data, for example:

#!
echo ssh-rsa AAAB3N...QcGskx keyname >> ~ec2-user/.ssh/authorized_keys
echo ssh-rsa BBRdt5...LguTtp another-key >> ~ec2-user/.ssh/authorized_keys
Jim Flanagan
  • 2,059
  • 15
  • 19
  • That's true, but it would make it more difficult to manage keys through the various AWS tools. Is there some way within AWS to do this? – NT3RP Nov 02 '12 at 20:18
  • Elastic Beanstalk does not allows you to specify user-data – aldrinleal Dec 27 '12 at 02:13
  • You can use a file like `.ebextensions/app.config` in the source tree for the application version being deployed to add additional commands. See http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html – rhunwicks May 27 '13 at 15:11
5

The most dynamic way to add multiple SSH keys to Elastic Beanstalk EC2 instances

Step 1

Create a group in IAM. Call it something like beanstalk-access. Add the users who need SSH access to that group in IAM. Also add their public ssh key(s) to their IAM Security credentials.

Step 2

The deployment script below will be parsing JSON data from AWS CLI using a handy Linux tool called jq (jq official tutorial), so we need to add it in .ebextensions:

  packages:
    yum:
      jq: []

Step 3

Add the following BASH deployment script to .ebextensions:

  files:
    "/opt/elasticbeanstalk/hooks/appdeploy/post/980_beanstalk_ssh.sh":
      mode: "000755"
      owner: ec2-user
      group: ec2-user
      content: |
        #!/bin/bash
        rm -f /home/ec2-user/.ssh/authorized_keys
        users=$(aws iam get-group --group-name beanstalk-access | jq '.["Users"] | [.[].UserName]')
        readarray -t users_array < <(jq -r '.[]' <<<"$users")
        declare -p users_array
        for i in "${users_array[@]}"
        do
        user_keys=$(aws iam list-ssh-public-keys --user-name $i)
        keys=$(echo $user_keys | jq '.["SSHPublicKeys"] | [.[].SSHPublicKeyId]')
        readarray -t keys_array < <(jq -r '.[]' <<<"$keys")
        declare -p keys_array
        for j in "${keys_array[@]}"
        do
        ssh_public_key=$(aws iam get-ssh-public-key --encoding SSH --user-name $i --ssh-public-key-id $j | jq '.["SSHPublicKey"] .SSHPublicKeyBody' | tr -d \")
        echo $ssh_public_key >> /home/ec2-user/.ssh/authorized_keys
        done
        done
        chmod 600 /home/ec2-user/.ssh/authorized_keys
        chown ec2-user:ec2-user /home/ec2-user/.ssh/authorized_keys

Unfortunately, because this is YAML, you can't indent the code to make it more easily readable. But let's break down what's happening:

  • (In the code snippet directly below) We're removing the default SSH key file to give full control of that list to this deployment script.

      rm -f /home/ec2-user/.ssh/authorized_keys
    
  • (In the code snippet directly below) Using AWS CLI, we're getting the list of users in the beanstalk-access group, and then we're piping that JSON list into jq to extract only that list of `$users.

      users=$(aws iam get-group --group-name beanstalk-access | jq '.["Users"] | [.[].UserName]')
    
  • (In the code snippet directly below) Here, we're converting that JSON $users list into a BASH array and calling it $users_array.

    readarray -t users_array < <(jq -r '.[]' <<<"$users") declare -p users_array

  • (In the code snippet directly below) We begin looping through the array of users.

      for i in "${users_array[@]}"
      do
    
  • (In the code snippet directly below) This can probably be done in one line, but it's grabbing the list of SSH keys associated to each user in the beanstalk-access group. It has not yet turned it into a BASH array, it's still a JSON list.

      user_keys=$(aws iam list-ssh-public-keys --user-name $i)
      keys=$(echo $user_keys | jq '.["SSHPublicKeys"] | [.[].SSHPublicKeyId]')
    
  • (In the code snippet directly below) Now it's converting that JSON list of each users' SSH keys into a BASH array.

     readarray -t keys_array < <(jq -r '.[]' <<<"$keys")
     declare -p keys_array
    
  • (In the code snippet directly below) Now it's converting that JSON list into a BASH array.

     readarray -t keys_array < <(jq -r '.[]' <<<"$keys")
     declare -p keys_array
    
  • (In the code snippet directly below) Now we loop through each user's array of SSH keys.

     for j in "${keys_array[@]}"
     do
    
  • (In the code snippet directly below) We're adding each SSH key for each user to the authorized_keys file.

    ssh_public_key=$(aws iam get-ssh-public-key --encoding SSH --user-name $i --ssh-public-key-id $j | jq '.["SSHPublicKey"] .SSHPublicKeyBody' | tr -d \")
    echo $ssh_public_key >> /home/ec2-user/.ssh/authorized_keys
    
  • (In the code snippet directly below) Close out both the $users_array loop and $users_keys loop.

    done
    done
    
  • (In the code snippet directly below) Give the authorized_keys file the same permissions it originally had.

    chmod 600 /home/ec2-user/.ssh/authorized_keys
    chown ec2-user:ec2-user /home/ec2-user/.ssh/authorized_keys
    

Step 4

If your Elastic Beanstalk EC2 instance is in a public subnet, you can just ssh into it using:

ssh ec2-user@ip-address -i /path/to/private/key

If your Elastic Beanstalk EC2 instance is in a private subnet (as it should be for cloud security best practices), then you will need to have a "bastion server" EC2 instance which will act as the gateway for tunneling all SSH access to EC2 instances. Look up ssh agent forwarding or ssh proxy commands to get an idea of how to accomplish SSH tunneling.

Adding new users

All you do is add them to your IAM beanstalk-access group and run a deployment, and that script will add them to your Elastic Beanstalk instances.

Sam Malayek
  • 2,963
  • 2
  • 24
  • 40
  • This fails for me due to and aws iam command: 2018-10-16 13:43:24 ERROR [Instance: i-05cc43b96ffc69145] Command failed on instance. Return code: 1 Output: (TRUNCATED)...rform: iam:GetGroup on resource: group beanstalk-access – Joseph Crawford Oct 16 '18 at 13:47
  • @JosephCrawford Are you sure you created the IAM group called `beanstalk-access`? Then also make sure there are users assigned to that group. – Sam Malayek Oct 16 '18 at 17:06
  • Yes I did both of those but that is the error returned from beanstalk during a deploy. Also I removed the config file and removed jq from the yum packages and now I still cannot deploy as it is trying to run that command with every deploy which I found to be very odd. – Joseph Crawford Oct 16 '18 at 19:02
  • ls -la .ebextensions total 16 drwxrwxrwx@ 4 jcrawford staff 128 Oct 16 15:03 . drwxrwxrwx@ 36 jcrawford staff 1152 Oct 16 09:18 .. -rw-r--r--@ 1 jcrawford staff 744 Sep 18 10:07 composer.config -rw-r--r--@ 1 jcrawford staff 73 Oct 16 09:53 project.config 2018-10-16 19:05:05 INFO Deploying new version to instance(s). 2018-10-16 19:06:09 ERROR [Instance: i-05cc43b96ffc69145] Command failed on instance. Return code: 1 Output: (TRUNCATED)...erform: iam:GetGroup on resource: group BeanstalkAccess – Joseph Crawford Oct 16 '18 at 19:06
  • Finally was able to get our environment back into a running state. Will clone our QA environment upon further testing of enabling SSH. – Joseph Crawford Oct 17 '18 at 15:31
1

https://stackoverflow.com/a/16776129/7459377

the simplest method - like @rhunwicks but with one ">" symbol on first copy:

Regards.

Community
  • 1
  • 1
Kefir
  • 11
  • 2
  • Don't copy and paste the existing answers and apply minor changes. If you have something to contribute to an existing answer use the `share button` alongside with your new answer. – hmofrad Jan 23 '17 at 19:34
1

instead of running echo and storing your keys on Git, you can upload your public keys to IAM user's on AWS and than do:

commands:
  copy_ssh_key_userA: 
    command: rm -f /home/ec2-user/.ssh/authorized_keys;aws iam list-users --query "Users[].[UserName]" --output text | while read User; do aws iam list-ssh-public-keys --user-name "$User" --query "SSHPublicKeys[?Status == 'Active'].[SSHPublicKeyId]" --output text | while read KeyId; do aws iam get-ssh-public-key --user-name "$User" --ssh-public-key-id "$KeyId" --encoding SSH --query "SSHPublicKey.SSHPublicKeyBody" --output text >> /home/ec2-user/.ssh/authorized_keys; done; done;
user181163
  • 11
  • 1