|
| 1 | +# Git authentication with SSH keys |
| 2 | + |
| 3 | +When using [environment variables](../usage/ci-configuration.md#authentication) to set up the Git authentication, the remote Git repository will automatically be accessed via [https](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols#_the_http_protocols), independently of the [`repositoryUrl`](../usage/configuration.md#repositoryurl) format configured in the **semantic-release** [Configuration](../usage/configuration.md#configuration) (the format will be automatically converted as needed). |
| 4 | + |
| 5 | +Alternatively the Git repository can be accessed via [SSH](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols#_the_ssh_protocol) by creating SSH keys, adding the public one to your Git hosted account and making the private one available on the CI environment. |
| 6 | + |
| 7 | +## Generating the SSH keys |
| 8 | + |
| 9 | +In your local repository root: |
| 10 | + |
| 11 | +```bash |
| 12 | +$ ssh-keygen -t rsa -b 4096 -C "<your_email>" -f git_deploy_key -N "<ssh_passphrase>" |
| 13 | +``` |
| 14 | + |
| 15 | +`your_email` must be the email associated with your Git hosted account. `ssh_passphrase` must be a long and hard to guess string. It will be used later. |
| 16 | + |
| 17 | +This will generate a public key in `git_deploy_key.pub` and a private key in `git_deploy_key`. |
| 18 | + |
| 19 | +## Adding the SSH public key to the Git hosted account |
| 20 | + |
| 21 | +Step by step instructions are provided for the following Git hosted services: |
| 22 | +- [GitHub](#adding-the-ssh-public-key-to-github) |
| 23 | + |
| 24 | +### Adding the SSH public key to GitHub |
| 25 | + |
| 26 | +Open the `git_deploy_key.pub` file (public key) and copy the entire content. |
| 27 | + |
| 28 | +In GitHub **Settings**, click on **SSH and GPG keys** in the sidebar, then on the **New SSH Key** button. |
| 29 | + |
| 30 | +Paste the entire content of `git_deploy_key.pub` file (public key) and click the **Add SSH Key** button. |
| 31 | + |
| 32 | +Delete the `git_deploy_key.pub` file: |
| 33 | + |
| 34 | +```bash |
| 35 | +$ rm git_deploy_key.pub |
| 36 | +``` |
| 37 | + |
| 38 | +See [Adding a new SSH key to your GitHub account](https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/) for more details. |
| 39 | + |
| 40 | +## Adding the SSH private key to the CI environment |
| 41 | + |
| 42 | +In order to be available on the CI environment, the SSH private key must be encrypted, committed to the Git repository and decrypted by the CI service. |
| 43 | + |
| 44 | +Step by step instructions are provided for the following environments: |
| 45 | +- [Travis CI](#adding-the-ssh-private-key-to-travis-ci) |
| 46 | +- [Circle CI](#adding-the-ssh-private-key-to-circle-ci) |
| 47 | + |
| 48 | +### Adding the SSH private key to Travis CI |
| 49 | + |
| 50 | +Install the [Travis CLI](https://github.com/travis-ci/travis.rb#installation): |
| 51 | + |
| 52 | +```bash |
| 53 | +$ gem install travis |
| 54 | +``` |
| 55 | + |
| 56 | +[Login](https://github.com/travis-ci/travis.rb#login) to Travis with the CLI: |
| 57 | + |
| 58 | +```bash |
| 59 | +$ travis login |
| 60 | +``` |
| 61 | + |
| 62 | +Add the [environment](https://github.com/travis-ci/travis.rb#env) variable `SSH_PASSPHRASE` to Travis with the value set during the [SSH keys generation](#generating-the-ssh-keys) step: |
| 63 | + |
| 64 | +```bash |
| 65 | +$ travis env set SSH_PASSPHRASE <ssh_passphrase> |
| 66 | +``` |
| 67 | + |
| 68 | +[Encrypt](https://github.com/travis-ci/travis.rb#encrypt) the `git_deploy_key` (private key) using a symmetric encryption (AES-256), and store the secret in a secure environment variable in the Travis environment: |
| 69 | + |
| 70 | +```bash |
| 71 | +$ travis encrypt-file git_deploy_key |
| 72 | +``` |
| 73 | + |
| 74 | +The `travis encrypt-file` will encrypt the private key into the `git_deploy_key.enc` file and output in the console the command to add to your `.travis.yml` file. It should look like `openssl aes-256-cbc -K $encrypted_KKKKKKKKKKKK_key -iv $encrypted_VVVVVVVVVVVV_iv -in git_deploy_key.enc -out git_deploy_key -d`. |
| 75 | + |
| 76 | +Copy this command to your `.travis.yml` file in the `before_install` step. Change the output path to write the unencrypted key in `/tmp`: `-out git_deploy_key` => `/tmp/git_deploy_key`. This will avoid to commit / modify / delete the unencrypted key by mistake on the CI. Then add the commands to decrypt the ssh private key and make it available to `git`: |
| 77 | + |
| 78 | +```yaml |
| 79 | +before_install: |
| 80 | + # Decrypt the git_deploy_key.enc key into /tmp/git_deploy_key |
| 81 | + - openssl aes-256-cbc -K $encrypted_KKKKKKKKKKKK_key -iv $encrypted_VVVVVVVVVVVV_iv -in git_deploy_key.enc -out /tmp/git_deploy_key -d |
| 82 | + # Make sure only the current user can read the private key |
| 83 | + - chmod 600 /tmp/git_deploy_key |
| 84 | + # Create a script to return the passphrase environment variable to ssh-add |
| 85 | + - echo 'echo ${SSH_PASSPHRASE}' > /tmp/askpass && chmod +x /tmp/askpass |
| 86 | + # Start the authentication agent |
| 87 | + - eval "$(ssh-agent -s)" |
| 88 | + # Add the key to the authentication agent |
| 89 | + - DISPLAY=":0.0" SSH_ASKPASS="/tmp/askpass" setsid ssh-add /tmp/git_deploy_key </dev/null |
| 90 | +``` |
| 91 | +
|
| 92 | +See [Encrypting Files](https://docs.travis-ci.com/user/encrypting-files) for more details. |
| 93 | +
|
| 94 | +Delete the local private key as it won't be used anymore: |
| 95 | +
|
| 96 | +```bash |
| 97 | +$ rm git_deploy_key |
| 98 | +``` |
| 99 | + |
| 100 | +Commit the encrypted private key and the `.travis.yml` file to your repository: |
| 101 | + |
| 102 | +```bash |
| 103 | +$ git add git_deploy_key.enc .travis.yml |
| 104 | +$ git commit -m "ci(travis): Add the encrypted private ssh key" |
| 105 | +$ git push |
| 106 | +``` |
| 107 | + |
| 108 | +### Adding the SSH private key to Circle CI |
| 109 | + |
| 110 | +First we encrypt the `git_deploy_key` (private key) using a symmetric encryption (AES-256). Run the following `openssl` command and *make sure to note the output which we'll need later*: |
| 111 | + |
| 112 | +```bash |
| 113 | +$ openssl aes-256-cbc -e -p -in git_deploy_key -out git_deploy_key.enc -K `openssl rand -hex 32` -iv `openssl rand -hex 16` |
| 114 | +salt=SSSSSSSSSSSSSSSS |
| 115 | +key=KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK |
| 116 | +iv =VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV |
| 117 | +``` |
| 118 | + |
| 119 | +Add the following [environment variables](https://circleci.com/docs/2.0/env-vars/#adding-environment-variables-in-the-app) to Circle CI: |
| 120 | +- `SSL_PASSPHRASE` - the value set during the [SSH keys generation](#generating-the-ssh-keys) step. |
| 121 | +- `REPO_ENC_KEY` - the `key` (KKK) value from the `openssl` step above. |
| 122 | +- `REPO_ENC_IV` - the `iv` (VVV) value from the `openssl` step above. |
| 123 | + |
| 124 | +Then add to your `.circleci/config.yml` the commands to decrypt the ssh private key and make it available to `git`: |
| 125 | + |
| 126 | +```yaml |
| 127 | +version: 2 |
| 128 | +jobs: |
| 129 | + coverage_test_publish: |
| 130 | + # docker, working_dir, etc |
| 131 | + steps: |
| 132 | + - run: |
| 133 | + # Decrypt the git_deploy_key.enc key into /tmp/git_deploy_key |
| 134 | + - openssl aes-256-cbc -d -K $REPO_ENC_KEY -iv $REPO_ENC_IV -in git_deploy_key.enc -out /tmp/git_deploy_key |
| 135 | + # Make sure only the current user can read the private key |
| 136 | + - chmod 600 /tmp/git_deploy_key |
| 137 | + # Create a script to return the passphrase environment variable to ssh-add |
| 138 | + - echo 'echo ${SSH_PASSPHRASE}' > /tmp/askpass && chmod +x /tmp/askpass |
| 139 | + # Start the authentication agent |
| 140 | + - eval "$(ssh-agent -s)" |
| 141 | + # Add the key to the authentication agent |
| 142 | + - DISPLAY=":0.0" SSH_ASKPASS="/tmp/askpass" setsid ssh-add /tmp/git_deploy_key </dev/null |
| 143 | + # checkout, restore_cache, run: yarn install, save_cache, etc. |
| 144 | + # Run semantic-release after all the above is set. |
| 145 | +``` |
| 146 | + |
| 147 | +The unencrypted key is written to `/tmp` to avoid to commit / modify / delete the unencrypted key by mistake on the CI environment. |
| 148 | + |
| 149 | +Delete the local private key as it won't be used anymore: |
| 150 | + |
| 151 | +```bash |
| 152 | +$ rm git_deploy_key |
| 153 | +``` |
| 154 | + |
| 155 | +Commit the encrypted private key and the `.circleci/config.yml` file to your repository: |
| 156 | + |
| 157 | +```bash |
| 158 | +$ git add git_deploy_key.enc .circleci/config.yml |
| 159 | +$ git commit -m "ci(cicle): Add the encrypted private ssh key" |
| 160 | +$ git push |
| 161 | +``` |
0 commit comments