経緯
・AWSのEC2で作成したサーバーに、railsのアプリケーションをAnsibleでデプロイしたかった。
・アプリケーションを公開したくなかったため、GitHubのリポジトリはPrivateにしていた。
・Ansibleのgit モジュールを使用するも、権限問題でNGとなる。
Permission denied (publickey).
概要
①トークンを作成
-
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などで分けたファイルに下記を追記
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などでデプロイする際に、トークンを記載しなければならないのがセキュリティ的に心配