Git 이론 (4) - 4

김태규·2024년 6월 22일
0

Git 공식문서 학습

목록 보기
9/9
post-thumbnail

HTTP 암호 저장, Credential 저장소

SSH 프로토콜을 사용하여 리모트 저장소에 접근할 때 Passphase 없이 생성한 SSH Key를 사용하면 사용자이름과 암호를 입력하지 않고도 안전하게 데이터를 주고받을 수 있다. 반면 HTTP 프로토콜을 사용하는 경우는 매번 사용자이름과 암호를 입력해야 한다.

다행히도 Git은 이렇게 매번 인증정보를 입력하는 경우 인증정보를 저장해두고 자동으로 입력해주는 시스템을 제공한다. Git Credential 기능이 제공하는 옵션은 다음과 같다.

  • 일단 기본적으로 아무런 설정도 하지 않으면 어떤 암호도 저장하지 않는다. 이 경우 인증이 필요한 때 매번 사용자 이름과 암호를 입력해야 한다.
  • cache 모드로 설정하면 일정 시간동안 메모리에 사용자이름과 암호 같은 인증정보를 기억한다. 이 정보를 Disk에 저장하지는 않으며 메모리에서도 15분 까지만 유지한다.
  • store 모드로 설정하면 인증정보를 Disk의 텍스트 파일로 저장하며 계속 유지한다. 계속 유지한다는 말은 리모트의 인정정보를 변경하지 않는 한 다시 인증정보를 입력하지 않아도 접근할 수 있다는 말이다. store 모드를 사용할 때 주의할 점은 인증정보가 사용자 홈 디렉토리 아래에 일반 텍스트 파일로 저장된다는 점이다.
  • Mac에서 Git을 사용하는 경우, osxkeychain모드를 사용하면 Mac에서 제공하는 Keychain 시스템에 사용자이름과 암호를 현재 로그인 계정에 속하게 저장한다. store 모드와 비교하면 인증정보를 Disk에 저장하고 인증정보가 만료되지 않는 점은 같지만, Safari 브라우저가 인증정보를 저장하는 것과 같은 수준으로 암호화해서 저장한다는 점이 다르다.
  • Windows 환경에서는, 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
  1. 이 명령으로 인증정보를 얻어오는 과정을 시작한다.
  2. 이제 Git-credential 명령은 표준 입력으로 사용자의 입력을 기다린다. 인증정보가 필요한 대상의 프로토콜과 호스트이름을 입력한다.
  3. 빈 라인을 하나 입력하면 입력이 끝났다는 것을 의미한다. 이제 입력한 내용에 해당하는 인증정보를 응답해야 한다.
  4. Git-credential 명령이 전달받은 내용으로 인증정보를 찾아보고 찾으면 표준출력으로 찾은 정보를 응답한다.
  5. 요청에 대한 인증정보가 없을 수도 있다. 이렇게 되면 Git이 사용자이름과 암호를 사용자가 입력하도록 메시지를 띄우고 값도 입력받는다. 입력받은 값을 다시 표준출력으로 응답한다.

이 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에서 인증정보를 삭제하는 액션

storeerase는 따로 결과를 출력할 필요가 없다. 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
  1. git-credential-store Helper에게 인증정보를 저장하도록 한다. 저장할 인증정보는 사용자이름이 “bob”, 암호가 “s3cre7” 이다. 프로토콜과 호스트가 https://mygithost 일 때 사용한다.
  2. 저장한 인증정보를 가져온다. 이미 아는 https://mygithost 리모트 주소를 호스트와 프로토콜로 나누어 표준입력으로 전달하고 한 라인을 비운다.
  3. git-credential-store 명령은 (1)에서 저장한 사용자이름과 암호를 표준출력으로 응답한다.

생성된 ~/git.store 파일의 내용은 다음과 같다.

https://bob:s3cre7@mygithost

맞춤 Credential

git-credential-store 나 다른 명령도 독립된 프로그램이므로 아무 스크립트나 프로그램도 Git Credential Helper가 될 수 있다. 맞춤 Helper는 아래와 같은 기능을 제공해야 한다.

  1. 새 맞춤 Helper가 집중해야 할 액션은 get 뿐이다. store 나 erase 액션은 저장하는 기능이기 때문에 이 액션을 받으면 깔끔하게 바로 종료한다.
  2. 공유하는 Credential 파일은 git-credential-store 명령이 저장하는 형식과 같은 형식을 사용한다.
  3. Credential 파일의 위치는 기본 값을 사용해도 되지만 파일 경로를 넘길 수 있다.

아래 예제는 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
  1. 우선 명령 옵션을 처리한다. 옵션으로는 Credential 파일명이 들어온다. 기본 값은 ~/.git-credentials 이다.
  2. Helper 프로그램은 get 액션만 처리하며 Credential 파일이 존재하는 경우만 처리한다.
  3. 이후에는 빈 라인이 나타날 때까지 표준입력으로부터 한 줄 한 줄 읽는다. 각 라인을 파싱하여 known 해시에 저장하고 <4>의 응답에서 사용한다.
  4. 이 루프에서 Credential 파일을 읽어서 <3>의 해시에 해당하는 정보를 찾는다. known 해시에서 프로토콜과 호스트 정보가 일치하는 경우 사용자이름과 암호를 포함하여 결과를 출력한다.

이 파일을 git-credential-read-only 로 저장하고 PATH 에 등록된 디렉토리 중 하나에 위치시키고 실행 권한을 부여한다. 위에서 저장한 파일 이름이 “git-” 으로 시작하기 때문에 아래와 같이 간단한 이름으로 설정해서 사용할 수 있다.

$ git config --global credential.helper 'read-only --file /mnt/shared/creds'
profile
Frontend, Mobile Developer

0개의 댓글