Bitbucket pipelines - configure SSH Keys
Tags: devops, tutorial, development, version
Published: 2021-09-13 21:17:45

## Table Of Contents
  * [Intro](#intro)
  * [Why SSH Keys?](#why-ssh-keys)
  * [Single Key vs Multiple Keys?](#single-vs-multiple)
  * [Single SSH Key](#single-ssh)
  * [Multiple SSH Keys](#multiple-ssh)

## Intro <a name="intro"></a>
Hi there!
I'm writing this tutorial because I found the bitbucket documentation a little bit confusing explaining the configuration of ssh keys in pipelines. I hope you will find this tutorial useful.

*N.B.: to follow this tutorial you must already have a bitbucket repository where pipeline exists (no needs to be a complex pipeline) or is at least enabled. I assume you have a basic knowledge of pipelines and git*.

LET'S START!

## Why SSH Keys? <a name="why-ssh-keys"></a>
In some of my pipelines I needed to connect to my remote server and run commands/scripts. Bitbucket pipeline allows you to do that. You're on a docker container, based on the image indicated in the pipeline file (tipically ubuntu or another linux distro based) so you can install ssh package on the image, run ssh command to connect to the server and execute commands/scripts directly on the server.
I know you can automate the login passing your password to ssh command but I don't recommend it.
When the pipeline starts, you can't type password or run commands.
SSH Keys avoid you typing password each time you connect to the server and above all are more secure than passwords.



You can setup ssh keys in your pipeline in two ways:
- Single key
- Multiple keys 

### Single Key vs Multiple Keys? <a name="single-vs-multiple"></a>
The difference between choosing single key or multiple keys depends on how you're working.
Usually I associate each branch of the repository with a specific virtual host on my server and I prefer to have multiple keys due to security reasons.
Single key is automatically injected into the docker container when the pipeline starts.
For multiple keys instead, you need to configure the keys manually through little differents steps.
But don't worry and let's start with the single key. 

## Single SSH Keys <a name="single-ssh"></a>
To setup single ssh key we need to generate ssh keys pair. Go to:
*Repository Settings*
![Repository Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsyo7xiwe1nfsp9ygeo6.png)
*SSH Keys*
![SSH Keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zyij28am34clxdh9kgoh.png)
*Generate Keys*
![Generate Keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htxxutdn91qrafya8390.png)
Now you should have an ssh keys pair (private and public).
![SSh Keys Pair](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3f5butw6uziv6iyvtez.png)

Login into your remote server and cd into the hidden ssh folder in the user's home
```shell
cd ~/.ssh/
```

Take the public key generated previously and copy it into a file called *authorized_keys* on the server in the *.ssh* folder

**Known Hosts**
Return to *Repository Settings* -> *SSH Keys*.
In the *Known Hosts* section, type *Host address* then click *FETCH* and wait for response.
![Known Hosts](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sm7ienehcxqqvd2371e4.png)
When you got response (the fingerprint of server) click the blue button *ADD HOST*.

***IMPORTANT***: *if your server uses a different port than default (22) to connect via ssh you can type SERVERIP:PORT in the Host address field*

Bitbucket automatically injects in the known_host file of docker container the fingerprint of the server and bypass the message below while connecting via ssh for the first time (remember: when pipeline has already started you cannot type or accept anything).
![Fingerprint warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fv3lgzbfokb89hqw4tng.png)
Now in your pipeline file you can use ssh to connect to your server.
Between quotes you can add one or more commands you want to run on your server.
```shell
ssh -u USERNAME -h SERVER -p 22 'echo "hello from $USER on remote server"'
```
**Pulling changes**
Sometimes you may need to pull changes from the repository using *git pull*. In order to do this, login into your server through the terminal and run the command below to generate private and public keys for your server.
Press *enter* for all questions (filename, passphrase)
```shell
ssh-keygen
```

Copy all the content of id_rsa.pub file (public key) and paste it into the **key** field in *Repository Settings* -> *Access Keys* -> *Add Key*
Finally test the connection running this command on your server.
```shell
ssh -T git@bitbucket.org
```

You should see an output says:
> authenticated via a deploy key.
You can use git to connect to Bitbucket. Shell access is disabled.
This deploy key has read access to the following repositories:
accountName/repositoryName

## Multiple SSH Keys <a name="multiple-ssh"></a>
You saw how to configure single ssh key, now let's see how to setup multiple ssh keys.

Login in your server through terminal and generate ssh keys pair by running this command.
```shell
ssh-keygen
```

Convert the private key (id_rsa) in base64 format, because the bitbucket repository variables don't accept break lines
```shell
base64 -w 0 < id_rsa
```

Take the output, paste it into a repository variable (named SSH_KEY) in *Repository Settings* -> *Deployments* -> *your deployment environment*, let *Secured* checked and click *ADD*.
![Base64 String](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdepw64qv7nziwej087m.png)
Repository variables are useful, because in your pipeline file you don't need to write sensitive data like server ip, username, port etc...

Add 3 variables (keep the secured checkbox checked):

- USER with user
- SERVER with serverIp
- PORT with serverPort

More informations about repository variables:
https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/#Reference-variables-in-your-pipeline

Return to *Repository Settings* -> *SSH Keys*.
In the *Known Hosts* section, type *Host address* then click *FETCH* and after response appears click *ADD HOST*.

Setup your bitbucket-pipelines.yml like the code below:
- in *deployment* type name of your deployment environment where you previously added the base64 string variable (in my case test)
- in *script* add the umask string and the ssh command to test connection.
```yaml
image: atlassian/default-image:latest

pipelines:
  default:
    - step:
        name: Deploy to test
        deployment: test
        script:
          # Decode base64 private ssh key string variable and put content in the private key file on docker container
          - (umask  077 ; echo $SSH_KEY | base64 --decode > ~/.ssh/id_rsa)
          # Test ssh connection
          - ssh $USER@$SERVER -p$PORT 'echo "hello from $USER on remote server"'
```
Follow the *single key* procedure about **Pulling changes** if you need to pull changes from repository using *git pull*.

You can repeat multiple times the steps for multiple keys.
You can change deployment environment with different variables and connect to another server (remember: you need to duplicate the code after *default* keyword in pipeline file and change data).
Bitbucket doesn't allow you to use the same deployment environment in a different step.
With bitbucket free plan you can add up to 10 deployment environments.

I'll be happy to help you out if something went wrong :smile: