AnsibleにてGitHubのPrivateリポジトリからgit cloneする方法

# 経緯
・AWSのEC2で作成したサーバーに、railsのアプリケーションをAnsibleでデプロイしたかった。
・アプリケーションを公開したくなかったため、GitHubのリポジトリはPrivateにしていた。
・Ansibleのgit モジュールを使用するも、権限問題でNGとなる。
```
Permission denied (publickey).
```




# 概要

大雑把にまとめると、以下①~⑧を実行しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641225/d3caccc1-bb10-1966-681d-53108b8ceb17.png)








## ①トークンを作成
* GitHubにて、Settings → Developer settings →　Personal access tokens にアクセス

* 下記権限でトークンを作成
・repo
・admin:public_key
・user
・admin:gpg_key



## ②トークンの暗号化のパスワード作成
* Ansible Serverの任意のディレクトリに、暗号化したパスワードファイルを設置

```:/(Ansible Server環境)
echo "トークンの暗号化のパスワード(任意)" | openssl aes-256-cbc -a -salt > "任意のディレクトリ"/password_file.txt
```



## ③トークンの暗号化

* 下記を実行
```:/(Ansible Server環境)
ansible-vault encrypt_string 'GitHubで作成したトークン' --name 'GITHUB_ACCESS_TOKEN' --vault-password-file=任意のディレクトリ/password_file.txt
```

* 実行結果を控えておく
　※Ansibleでplaybookを実行する際に、変数として値を渡します。
```
[ec2-user@hogehoge]$ ansible-vault encrypt_string 'your_access_token' --name 'GITHUB_ACCESS_TOKEN' --vault-password-file=任意のディレクトリ/password_file.txt
#コピー開始位置
GITHUB_ACCESS_TOKEN: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          37303661663935393637373662313430353138353563653732343833393563643239303365356633
          6336356666626239353061326532343234393233656462640a653233306363326166386438663837
          61616136376566643633663532656537646163646462616535356433653538313264313164363535
          3361643662343934310a363634626133643930306332333166663138653532353164346631626663
          63636335376661636439376332623339366539373938623537396234333939313462　#コピー終了位置
Encryption successful
```
## ③別の方法
* Ansibleのconfigにて、valitコマンドで暗号化した場合のパスワードファイルを指定
※毎度パスワードを指定しなくてもいいのでCI向き
```:/etc/ansible/ansible.cfg
#defaults配下に下記を追加
vault_password_file = $HOME/ansible/roles/git_clone/password/password_file.txt
```
```:/(Ansible Server環境)
ansible-vault encrypt_string 'GitHubで作成したトークン' --name 'GITHUB_ACCESS_TOKEN'
```
## ④~⑧Playbookを実行
* Playbook実行用に、下記変数を定義
```
KEY_TITLE: GitHub アカウントに追加する SSH キーのタイトル
KEY_PATH:  SSH キーを格納するディレクトリの絶対パス
GIT_REPO: クローンする GitHub リポジトリの SSH URL
GIT_BRANCH: クローン後に切り替えたいブランチ
CLONE_DEST: リポジトリのクローン先となるディレクトリ
KNOWN_HOSTS_PATH: APP Server の SSH known_hostsファイルの場所
GIT_EXECUTABLE: ターゲットマシン上のgitバイナリの場所 ※bash -lcやsourceで読み込んでいる場合は不要
GITHUB_ACCESS_TOKEN: 先ほどコピーしたもの
```
* playbookもしくは、rolesなどで分けたファイルに下記を追記
```yml:playbook.yml
#----------------------------------------
#5　SSHキーペアを作成
#----------------------------------------
- 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

- 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

#----------------------------------------
#6 known hostsにGitHubの公開鍵を登録
#  GitHub公開鍵を登録することで、SSH初回接続で対話式になるのを回避
#----------------------------------------
- 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

- name:  Git Clone directory created
  become: yes
  file:
    path: "/var/www"
    state: directory
    owner: "{{user_name}}"
    group: "{{user_name}}"
    mode: "775"

#----------------------------------------
#7 SSHの公開鍵をGitHubに登録
#----------------------------------------
- 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

#----------------------------------------
#8 git clone
#----------------------------------------
- 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 }}
```


# 実施してみての感想
Publicリポジトリにしてcloneした方がやっぱり楽。。
CircleCIなどでデプロイする際に、トークンを記載しなければならないのがセキュリティ的に心配

[参考にしたサイト](https://community.ibm.com/community/user/ibmz-and-linuxone/blogs/asif-mahmud1/2020/03/15/cloning-private-git-repository-using-ansible)