SSH 프로토콜을 사용하여 리모트 저장소에 접근할 때 Passphase 없이 생성한 SSH Key를 사용하면 사용자이름과 암호를 입력하지 않고도 안전하게 데이터를 주고받을 수 있다. 반면 HTTP 프로토콜을 사용하는 경우는 매번 사용자이름과 암호를 입력해야 한다.
다행히도 Git은 이렇게 매번 인증정보를 입력하는 경우 인증정보를 저장해두고 자동으로 입력해주는 시스템을 제공한다. Git Credential 기능이 제공하는 옵션은 다음과 같다.
cache
모드로 설정하면 일정 시간동안 메모리에 사용자이름과 암호 같은 인증정보를 기억한다. 이 정보를 Disk에 저장하지는 않으며 메모리에서도 15분 까지만 유지한다.store
모드로 설정하면 인증정보를 Disk의 텍스트 파일로 저장하며 계속 유지한다. 계속 유지한다는 말은 리모트의 인정정보를 변경하지 않는 한 다시 인증정보를 입력하지 않아도 접근할 수 있다는 말이다. store 모드를 사용할 때 주의할 점은 인증정보가 사용자 홈 디렉토리 아래에 일반 텍스트 파일로 저장된다는 점이다.osxkeychain
모드를 사용하면 Mac에서 제공하는 Keychain 시스템
에 사용자이름과 암호를 현재 로그인 계정에 속하게 저장한다. store
모드와 비교하면 인증정보를 Disk에 저장하고 인증정보가 만료되지 않는 점은 같지만, Safari 브라우저가 인증정보를 저장하는 것과 같은 수준으로 암호화해서 저장한다는 점이 다르다.Git Credential Manager for Windows
라는 Helper가 있다. osxkeychain
Helper와 비슷하게 동작하며 Windows Credential Store를 사용하여 안전하게 인증정보를 저장한다. 링크에서 다운받아 사용할 수 있다.위에서 언급한 모드 중 하나를 아래와 같이 설정할 수 있다.
$ git config --global credential.helper cache
추가 옵션을 지정할 수 있는 Helper도 있다. store
는 --file <path>
옵션을 사용하여 인증정보를 저장할 텍스트 파일의 위치를 지정한다. 기본 값은 ~/.git-credentials
이다. cache
는 --timeout <seconds>
옵션을 사용하여 인증정보의 유지시간을 설정한다. 기본 값은 900초, 15분이다. 기본 경로가 아닌 다른 경로를 지정해서 인증정보를 저장하려면 아래와 같이 실행한다.
git config --global credential.helper 'store --file ~/.my-credentials'
Helper를 여러개 섞어서 사용할 수도 있다. 인증이 필요한 리모드에 접근할 때 Git은 인증정보를 찾는데 Helper가 여러개 있으면 순서대로 찾는다. 반대로 인증정보를 저장할 때는 설정한 모든 모드에 저장한다. 아래 예제는 첫 번째 Path에 대해 인증정보를 읽거나 저장에 실패하면 두 번째 모드에 따라 메모리에서만 인증정보를 유지한다.
[credential]
helper = store --file /mnt/thumbdrive/.git-credentials
helpre = cache --timeout 30000
Git의 Credential-Helper 시스템의 기본 명령을 git credential
이다. 이 명령ㅇ ㅣ하위 명령이나 옵션, 표준입력으로 필요한 정보를 입력받아 전달한다.
아래는 예제이다. Credential Helper를 사용하도록 설정하고 mygithost
라는 호스트의 인증정보가 저장된 상태이다. 아래 예제는 fill
명령으로 Git이 특정 호스트에 대한 인증정보를 얻으려는 과정을 보여준다.
$ git credential fill (1)
protocol=https (2)
host=mygithost
(3)
protocol=https (4)
host=mygithost
username=bob
passwords3cre7
$ git credential fill (5)
protocol=https
host=unknownhost
Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
이 Credential 시스템은 사실 Git과 분리된 독립적인 프로그램을 실행시켜 동작한다. 어떤 프로그램을 실행시킬지는 credential.helper 설정 값에 따른다. 이 설정 값을 아래와 같이 설정한다.
foo
: git-credential-foo
실행foo -a -opt=bcd
: git-credential-foo -a -opt=bcd
실행/abolute/path/foo -xyz
: /abolute/path/foo -xyz
실행!f() { echo "password=s3cre7"; }; f
: !
뒤의 코드를 쉘에서 실행따라서 위에서 살펴본 여러 Helper는 사실 git-credential-cache, git-credential-store 같은 명령이다. 설정을 통해 이 명령들이 옵션이나 하위 명령을 받아서 실행하게 한다. 이 명령의 일반적인 형태는 git-credential-foo [args] <action>
이다. git-credential 명령과 마찬가지로 표준입력/표준출력을 프로토콜로 사용하지만 처리하는 액션(하위 명령)은 아래와 같이 다소 다르다.
get
: 사용자이름과 함호를 요구하는 액션store
: Helper에서 인증정보를 저장하는 액션erase
: Helper에서 인증정보를 삭제하는 액션store
나 erase
는 따로 결과를 출력할 필요가 없다. get
의 결과는 git이 모니터링하여 가져다 사용하므로 중요하다. Helper는 인증 정보가 없다면 결과를 출력하지 않고 종료되면, 적당한 결과를 찾으면 전달받은 인증정보를 추가하여 결과로 응답한다. 결과는 몇 라인의 할당 구문으로 구성하며 Git은 이 결과를 받아서 사용한다.
아래 예제는 git-credential
대신 git-credential-store
명령어를 직접 사용한 것이다.
$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost
username=bob (3)
password=s3cre7
생성된 ~/git.store
파일의 내용은 다음과 같다.
https://bob:s3cre7@mygithost
git-credential-store
나 다른 명령도 독립된 프로그램이므로 아무 스크립트나 프로그램도 Git Credential Helper가 될 수 있다. 맞춤 Helper는 아래와 같은 기능을 제공해야 한다.
아래 예제는 Ruby를 사용한 Helper의 소스코드이다.
#!/usr/bin/env ruby
require 'optparse'
path = File.expand_path '~/.git-credentials' # (1)
OptionParser.new do |opts|
opts.banner = 'USAGE: git-credential-read-only [options] <action>'
opts.on('-f', '--file PATH', 'Specify path for backing store') do |argpath|
path = File.expand_path argpath
end
end.parse!
exit(0) unless ARGV[0].downcase == 'get' # (2)
exit(0) unless File.exists? path
known = {} # (3)
while line = STDIN.gets
break if line.strip == ''
k,v = line.strip.split '=', 2
known[k] = v
end
File.readlines(path).each do |fileline| # (4)
prot,user,pass,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
if prot == known['protocol'] and host == known['host'] and user == known['username'] then
puts "protocol=#{prot}"
puts "host=#{host}"
puts "username=#{user}"
puts "password=#{pass}"
exit(0)
end
end
이 파일을 git-credential-read-only 로 저장하고 PATH 에 등록된 디렉토리 중 하나에 위치시키고 실행 권한을 부여한다. 위에서 저장한 파일 이름이 “git-” 으로 시작하기 때문에 아래와 같이 간단한 이름으로 설정해서 사용할 수 있다.
$ git config --global credential.helper 'read-only --file /mnt/shared/creds'