In order to let Ansible know where to look for the password file, you have two options:
1. In ansible.cfg
file, add the line: vault_password_file = /path/to/password/file
under [defaults]
2. Create an environment variable:
Great! Now go ahead and paste the generated encrypted variable into vars/main.yml
file
Aside from GITHUB_ACCESS_TOKEN
, there are seven other variables that we will be using in our role:
KEY_TITLE
: The title of the SSH key to be added to the GitHub account
KEY_PATH
: Full path of the directory where the SSH key should be stored. A typical location would be ~/.ssh/id_rsa.git
GIT_REPO
: The SSH url of the GitHub repository to be cloned. An example would be ssh://git@github.com/zbrewdev/zbrew.git
GIT_BRANCH
: Switch to this branch after cloning
CLONE_DEST
: The folder where repository should be cloned to
KNOWN_HOSTS_PATH
: Location of the SSH known_hosts
file on the target machine. A typical location would be ~/.ssh/known_hosts
GIT_EXECUTABLE
: The location of the git binary on the target machine. For example /usr/bin/git
Role Development
Once the variables are set, let's begin developing our role. The first thing we need to do is to generate a new SSH key and capture the contents of the public key, which we will be using later.
- name: Check if SSH key is already present
stat:
path: "{{ KEY_PATH }}"
register: key_stat_result
- name: Generate SSH key for accessing GitHub
command: "ssh-keygen -t rsa -f {{ KEY_PATH }} -N ''"
when: not key_stat_result.stat.exists
- name: Get key content
command: "cat {{ KEY_PATH }}.pub"
register: key_content
Next, we need to make sure that GitHub is present in known_hosts
of the remote system. If a known_hosts
file does not exist, it should be created.
- name: Check if known_host exists
stat:
path: "{{ KNOWN_HOSTS_PATH }}"
register: known_hosts_stat
- name: Create known_hosts if it doesn't exist
file:
path: "{{ KNOWN_HOSTS_PATH }}"
state: touch
when: not known_hosts_stat.stat.exists
- name: Get the content of known hosts
shell: "cat {{ KNOWN_HOSTS_PATH }} | grep github.com"
register: host_stat
failed_when: host_stat.rc > 1
We need to fetch GitHub's public key and add it to known_hosts
file
- name: Modify known hosts
block:
- name: Fetch GitHub public key
command: ssh-keyscan -T 10 github.com
register: keyscan
- name: Add GitHub public key to ssh known_hosts
lineinfile:
path: "{{ KNOWN_HOSTS_PATH }}"
create: yes
line: "{{ item }}"
with_items: '{{ keyscan.stdout_lines }}'
when: host_stat.rc == 1
Once we have added GitHub's public key to known_hosts
file, we need to make sure the SSH key that we generated is added to your GitHub account. In order to do so, we will be using GitHub's REST API to send a POST request with the key content as payload and the personal access token for authentication. If the key we are trying to add is already being used, then the task should continue without failing.
- name: Add SSH public key to GitHub account
uri:
url: https://api.github.com/user/keys
validate_certs: no
method: POST
body:
title: "{{ KEY_TITLE }}"
key: "{{ key_content.stdout }}"
body_format: json
headers:
Content-Type: "application/json"
Authorization: "token {{ GITHUB_ACCESS_TOKEN }}"
register: task_log
failed_when: task_log.content.find('key is already in use') == 0
Finally, the moment of truth! Before executing git clone, the GIT_SSH_COMMAND environment variable should be set with the correct SSH key path.
- name: Clone the repository
shell: GIT_SSH_COMMAND="ssh -i {{ KEY_PATH }} -v -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" {{ GIT_EXECUTABLE }} clone {{ GIT_REPO }} {{ CLONE_DEST }}
And there you have it! If all goes well, the private repository should be cloned to the destination specified by CLONE_DEST
variable. You can check out the complete role here.
Special Thanks