สร้าง config ไฟล์สำหรับควบคุมการใช้ ssh key หลายๆคีย์
วันนี้ขอแชร์ประสบการณ์การใช้การสร้าง config file เพื่อลองรับการใช้ ssh key หลาย key ในเครื่องเดียวกัน เพื่อให้ ssh agent รู้ว่าต้องใช้ key ไหน ในการยืนยันตัวตนกับเซอร์วิสต่างๆ
ใน tutorial นี้จะสร้าง ssh keys ทั้งหมด 4 keys
- สำหรับ hosting digital ocean 1 key
- สำหรับ gitlab account 1 key
- สำหรับ github account 2 keys
(เพราะผมมี 2 users — ของบริษัท 1 key ของส่วนตัว 1 key)
เริ่มสร้าง ssh key ทั้ง 4 กันเลย
Question: ปกติไม่ได้มีแค่ id_rsa หรอกเหรอ? ทำไมมีหลายคีย์ได้
สามารถมีได้ถ้าตอนสร้างระบุชื่อไฟล์ว่าชื่ออะไร
ถ้าไม่ระบุ ssh-keygen จะใช้ชื่อ id_rsa
เช่น
$ ssh-keygen -t rsa -b 4096 -C "chakkapanr@gmail.com"Generating public/private rsa key pair.
Enter file in which to save the key (/Users/chakkapanr/.ssh/id_rsa):
ขั้นตอนนี้ถ้ากด enter ไปเลย ก็จะได้ id_rsa
กับ id_rsa.pub
แต่ถ้าใครอยากได้ชื่อคีย์ที่อ่านแล้วเข้าใจง่ายว่าเป็นคีย์สำหรับโฮสท์ไหนก็พิมพ์ลงไปได้เลย (พาร์ทเต็ม)
Enter file in which to save the key (/Users/chakkapanr/.ssh/id_rsa): /Users/chakkapanr/.ssh/digitalocean_rsa
พาสเวิร์ดจะใส่ไม่ใส่ก็ได้ ถ้าไม่ใส่ก็กด enter ข้ามไปเลย
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/chakkapanr/.ssh/digitalocean_rsa.
Your public key has been saved in /Users/chakkapanr/.ssh/digitalocean_rsa.pub.
The key fingerprint is: SHA256:uWeZ3gLrCeTEmlkhvbOqqLtz6P4zRLdlmFpkhXcUdgw chakkapanr@gmail.com
The key's randomart image is:
+---[RSA 4096]----+
| o..E+. |
| = ..... |
| + * . |
| . B = . |
| . + @ S |
| o X o.. o |
| .. + + .o= |
|o..o . ..=.. |
|OBoo+ .o ... |
+----[SHA256]-----+
ถึงตรงนี้ผมจะได้มา 2 ไฟล์ เป็นไปรเวทคีย์ และ พับบลิกคีย์
$ ls ~/.ssh/
digitalocean_rsa
digitalocean_rsa.pub
จากนั้นก็บอก ssh-agent ให้รู้จัก key ใหม่นี้
$ ssh-add ~/.ssh/digitalocean_rsa
ขอสารภาพว่า ไม่แน่ใจ ssh-add มีความสำคัญยังไง เหมือนว่าเคยไม่ใช้ ก็ไม่มีปัญหาอะไร?
สร้างแบบนี้ให้ครบทั้ง 4 keys
$ ls ~/.ssh/
digitalocean_rsa
digitalocean_rsa.pub
gitlab_rsa
gitlab_rsa.pub
github_birdbyrd_rsa
github_birdbyrd_rsa.pub
github_office_rsa
github_office_rsa.pub
นำ public key ไปรีจิสเตอร์ตามเซอร์วิสที่ต้องการใช้
เคสของผมก็จะเป็นที่ digital ocean
, gitlab
และ github x2 accounts
copy ข้อมูลในไฟล์ *.pub
ไปแปะให้ตรงตามเซอร์วิส
- digitalocean_rsa.pub ➡️️ digitalocean.com
- gitlab_rsa.pub ➡️️ gitlab.com
- github_birdbyrd_rsa.pub ➡️️ github.com (account ส่วนตัว)
- github_office_rsa.pub ➡️️ github.com (account office)
เช่น ใน github.com
ถ้าลองใช้งาน โดยไม่มีการเซ็ต config file จะเกิดอะไรขึ้น?
ลองเรียกใช้เซอร์วิสต่างๆโดยไม่มี config file จะพบว่าไม่สามารถใช้งานได้
ได้ permission denied (publickey) ทั้งๆที่เราก็มี key ที่ถูกต้อง
gitlab & github
$ git clone git@gitlab.com:birdbyrd/hello-world.git
Cloning into 'hello-world'...
Permission denied (publickey).
fatal: Could not read from remote repository.Please make sure you have the correct access rights
and the repository exists.
digital ocean
$ ssh root@xxx.xxx.xx.xx
root@xxx.xxx.xx.xxx's password:
ที่เป็นแบบนี้เพราะ โดยส่วนใหญ่คำสั่งต่างๆจะใช้ id_rsa (ส่วนที่เป็น private key) ในการยืนยันตัวตนโดยอัติโนมัติ ซึ่งในเคสนี้เราไม่ได้ register ssh key บน digital ocean, github และ gitlab ด้วย id_rsa ทำให้ยืนยันตัวตนไม่ได้
วิธีแก้คือ เราต้องสร้าง config เพื่อจะบอกคำสั่งต่างๆให้รู้ว่าต้องใช้ ssh key จากไฟล์ไหน
มาสร้าง config file กันเลย
เริ่มจากส่วนที่ง่ายกว่าก่อน นั่นคือ digital ocean และ gitlab เพราะแต่ละที่มีเพียง ssh key เดียวเท่านั้น
สามารถสร้างได้ง่ายมากๆด้วยเพิ่ม config ดังนี้
# gitlab
Host gitlab.com
HostName gitlab.com
IdentityFile ~/.ssh/gitlab_rsa# digital ocean
Host xxx.xxx.xx.xxx
Hostname xxx.xxx.xx.xxx
IdentityFile ~/.ssh/digitalocean_rsa
User root
ค่อนข้างตรงไปตรงมา นั่นคือ
Host
ชื่อเรียก (เปลี่ยนเป็นชื่อเล่นที่ตั้งไว้ใน host file ได้)HostName
ชื่อ host จริงๆIdentityFile
พาร์ทของ ssh key private key ที่จะใช้กับ server นี้User
ถ้าหากมีหลาย user ใน server นี้ สามารถระบุ user ได้
ลองเรียกใช้ digital ocean และ gitlab อีกครั้ง พบว่าผ่านแล้ว
digital ocean
$ ssh root@xxx.xxx.xx.xxx
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-43-generic x86_64)
root@xxx.xxx.xx.xxx:~#
gitlab
$ git clone git@gitlab.com:birdbyrd/hello-world.git
Cloning into 'hello-world'...
remote: Counting objects: 11405, done.
objects: 2% (117/5822)
github
มาที่ส่วนที่ซับซ้อนกันบ้าง นั่นคือ github ซึ่งมี 2 accounts และต้องใช้ 2 ssh-key
เราสามารถ config ssh ได้ดังนี้
# github office
Host github.com-office
HostName github.com
IdentityFile ~/.ssh/github_office_rsa
User git# github birdbyrd
Host github.com-birdbyrd
HostName github.com
IdentityFile ~/.ssh/github_birdbyrd_rsa
User git
จะเห็นว่าที่ Host เราจะเพิ่ม user name เข้าไปข้างหลัง github.com
จากนั้นเวลาจะเช็คเอาท์โค๊ด ก็ให้เลือกใช้ hostname ให้ถูกต้องด้วย เช่น
โปรเจ็คที่ 1: account ส่วนตัว
ปกติทำแบบนี้
git clone git@github.com:birdbyrd/hello-world.git
ก็ให้เปลี่ยน host จาก github.com เป็น github.com-birdbyrd ตามที่เซ็ตไว้ใน config
git clone git@github.com-birdbyrd:birdbyrd/hello-world.git
------------
โปรเจ็คที่ 2: account office
ปกติทำแบบนี้
git clone git@github.com:tomserreutons/onkaidosktep.git
ก็ให้เปลี่ยน host จาก github.com เป็น github.com-office ตามที่เซ็ตไว้ใน config
git clone git@github.com-office:tomserreutons/onkaidosktep.git
------------
ทำแบบนี้ก็จะสามารถ checkout code ผ่านได้ด้วยดี
$ git clone git@github.com-office:tomserreutons/onkaidosktep.git
Cloning into 'onkaidosktep'...
remote: Counting objects: 11405, done.
objects: 2% (117/5822)
แล้วโปรเจ็คที่เคย checkout มาก่อนแล้วล่ะ? ตอนนั้นมีแค่ account เดียวเลยยังไม่มีปัญหาอะไร พอมาตอนนี้มี 2 account แล้ว (ส่วนตัว / ออฟฟิศ)
แบบนี้เวลามี commit / push git จะรู้ได้ไงว่าเราอยากใช้ account ไหน
คำตอบของคำถามนี้คือการใช้ git config ช่วยครับ
มาดู config github
ของแต่ละโปรเจ็คกัน โดยเช็ค config ที่ชื่อว่า remote
ก็จะเห็นว่าแต่ละโปรเจ็คจะยังใช้ Host เก่า (เวอร์ชันไม่มี username ต่อท้าย) ซึ่งแบบนี้ทำให้ git วิ่งมา ssh key ของเราไม่ถูก
วิธีแก้ก็คือ เข้าไปแก้ remote ให้ถูกต้อง
โปรเจ็คที่ 1: account ส่วนตัว
cd /to/birdbyrd/github/project/hello-world
nano .git/config
แล้วแก้ remote origin จาก git@github.com
เป็น git@github.com-birdbyrd
ตามที่ตั้งค่าไว้ใน ssh config ดังนี้
before
name = birdbyrd
email = chakkapanr@gmail.com
[remote "origin"]
url = git@github.com:birdbyrd/tutorials-dittaa.git
fetch = +refs/heads/*:refs/remotes/origin/*
after
[user]
name = birdbyrd
email = chakkapanr@gmail.com
[remote "origin"]
url = git@github.com-birdbyrd:birdbyrd/hello-world.git
------------
fetch = +refs/heads/*:refs/remotes/origin/*
โปรเจ็คที่ 2: account office
แก้ remote origin จาก git@github.com
เป็น git@github.com-office
ตามที่ตั้งค่าไว้ใน ssh config ดังนี้
cd /to/tomserreutons/onkaidosktep
nano .git/config
before
[user]
name = chakkapan.rapeepunpi
email = chakkapan.rapeepunpi@tomserreutons.com
[remote "origin"]
url = git@github.com:tomserreutons/onkaidosktep.git
fetch = +refs/heads/*:refs/remotes/origin/*
after
[user]
name = chakkapan.rapeepunpi
email = chakkapan.rapeepunpi@tomserreutons.com
[remote "origin"]
url = git@github.com-office:tomserreutons/onkaidosktep.git
----------
fetch = +refs/heads/*:refs/remotes/origin/*
ลองทดสอบด้วยการ push change ดู น่าจะผ่านได้ด้วยดีทั้ง 2 account และได้ user ที่ต้องในแต่ละ commit :D
อันดับถัดไป bower
bower — https://github.com/xxx/yyy
Please make sure you have the correct access rights and the repository exists.
นี่คือ error ที่คุณ bower ฟ้องเวลาไม่สามารถเข้าถึง component ที่ต้องการได้ ซึ่งสาเหตก็มาจากเรามีการใช้ bower repository จากหลายๆที่
- บ้างก็คงมาจาก public github repo
- บ้างก็มาจาก github ส่วนตัวของคุณ
- ร้ายสุด ก็คงมาจาก github office ซึ่งเป็น private repository
แล้วแบบนี้ bower จะรู้ได้ไงว่าต้องใช้ ssh key ไหนในการดึง component จาก repository ดังกล่าว?
ตอบ bower จะสมารถรู้ได้ด้วย gitconfig
อีกแล้วครับท่าน ด้วยการใช้ property พิเศษที่ชื่อว่า url > insteadOf
เช่น ใน project github office ของผม มีการดึง bower ของ internal component ใน github office
"dependencies": { "internal-awesome-js": "2.4.1" }
ถ้าเราสั่ง bower install เฉยๆ ก็น่าจะเห็นบรรทัดนี้ใน log
bower internal-awesome-js#2.4.1 resolved https://github.com/tomserreutons/internal-awesome-js.git#2.4.1
ซึ่งไม่ถูกต้อง
- เราอยากใช้ ssh ไม่ใช่ https
- เราต้องใช้ ssh ด้วย git url แบบนี้ git@github.com-office
มาลองแก้กันเลย เปิด git config ขึ้นมาโลด
cd /to/tomserreutons/onkaidosktep
nano .git/config
แก้ปัญหาที่ 1 ด้วยการเพิ่ม config ดังนี้
[url "ssh://git@github.com"]
----------
insteadOf = "https://github.com"
--------
ซึ่งหมายความว่า ถ้าเจอ url https://github.com
ให้เปลี่ยนเป็น ssh://git@github.com
แทน ทำแบบนี้ bower install ก็จะดึงของจาก git ด้วย ssh แทนครับ
จากนั้นแก้ปัญหาที่ 2 ด้วยการเพิ่ม url config อีกเช่นกัน
[url "ssh://git@github.com"]
insteadOf = "https://github.com"
[url "git@github.com-office:tomserreutons"]
------------------------
insteadOf = "git@github.com:tomserreutons"
-----------------
ซึ่งหมายความว่า ถ้ามีการดึงโค๊ดจาก git@github.com:onkaidosktep
ให้เปลี่ยนเป็นดึงจาก git@github.com-office:onkaidosktep
แทน ซึงก็จะพอเหมาะพอดีกับสิ่งที่เราตั้งค่าไว้ใน ssh config
เราสามารถใช้ git config นี้กับ global config ได้เช่นกัน เพื่อที่จะทำให้มีผลกับทุกโปรเจ็คไปเลย
สรุป
ssh config file สุดท้ายหน้าตาแบบนี้
# gitlab
Host gitlab.com
HostName gitlab.com
IdentityFile ~/.ssh/gitlab_rsa# digital ocean
Host xxx.xxx.xx.xxx
Hostname xxx.xxx.xx.xxx
IdentityFile ~/.ssh/digitalocean_rsa
User root# github office
Host github.com-office
HostName github.com
IdentityFile ~/.ssh/github_office_rsa
User git# github birdbyrd
Host github.com-birdbyrd
HostName github.com
IdentityFile ~/.ssh/github_birdbyrd_rsa
User git
git config file สุดท้ายหน้าตาแบบนี้
# ส่วนนี้อยู่ใน global git config
# gitlab - มี account เดียว ไม่ต้องระบุ user
[url "ssh://git@gitlab.com"]
insteadOf = "https://gitlab.com"
# github - 2 accounts ต้องใช้ account ให้ถูกต้องกับ host
[url "ssh://git@github.com"]
insteadOf = "https://github.com"
[url "git@github.com-office:tomserreutons"]
insteadOf = "git@github.com:tomserreutons"# ส่วนนี้อยู่ใน git config ของ office
[user]
name = chakkapan.rapeepunpi
email = chakkapan.rapeepunpi@tomserreutons.com
[remote "origin"]
url = git@github.com-office:tomserreutons/onkaidosktep.git
fetch = +refs/heads/*:refs/remotes/origin/*# ส่วนนี้อยู่ใน git config ของ birdbyrd
[user]
name = birdbyrd
email = chakkapanr@gmail.com
[remote "origin"]
url = git@github.com-birdbyrd:birdbyrd/hello-world.git
fetch = +refs/heads/*:refs/remotes/origin/*
หวังว่าจะมีประโยชน์ โดยเฉพาะเดวีลอปเปอร์ที่มีหลายมิติ (work place)ในการทำงาน Happy Hacking จ้ะ :D
Originally published at buggy.birdbyrd.com on February 2, 2017.