Skip to content

Commit

Permalink
Absorb host keys in a tempfile rather than saving them.
Browse files Browse the repository at this point in the history
  • Loading branch information
martinemde committed Nov 27, 2012
1 parent 77322f7 commit a7ba1e4
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 25 deletions.
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
Encapsulate the code you need to write out a permissive GIT\_SSH script that
can be used to connect git to protected git@github.com repositories.

Now includes a bin `git-ssh-wrapper` that can be used inline to call git with
GIT\_SSH set to the private key you need.
Includes two bin scripts, `git-ssh-wrapper` and `git-ssh` that can be used
inline to call git with GIT\_SSH set properly. See examples below.

## What it does

Expand All @@ -16,6 +16,9 @@ This is especially useful for scripts that need to automate connections to a
server using keys that are not intended to be part of the system on which the
script is running.

This script is designed to *always work* even if hosts keys change or the ssh
agent is being too paranoid or having a bad day.

A common use case is connecting to github.com to retrieve repositories,
submodules, or ref listings using read-only "deploy keys" or bundling a Gemfile
that contains private repositories accessible by a certain deploy key.
Expand All @@ -28,11 +31,13 @@ You can use the included command line tool to call git commands directly.
$ git merge origin/master
$ git-ssh-wrapper ~/.ssh/id_rsa git push origin master

$ git-ssh-wrapper ~/.ssh/id_rsa bundle install

A shortcut command `git-ssh` is also included that inserts `git` automatically.

$ git-ssh ~/.ssh/id_rsa fetch origin # git fetch origin

Most of the time you'll use this version if you're writing commands by hand.
You'll probably use this version if you're writing commands by hand.

## Ruby Example

Expand All @@ -50,7 +55,7 @@ OR

def get_refs
private_key_data_string = get_key_data_somehow
GitSSHWrapper.new(:private_key => private_key_data_string) do |wrapper|
GitSSHWrapper.with_wrapper(:private_key => private_key_data_string) do |wrapper|
wrapper.set_env
`git ls-remote git@github.com:martinemde/git-ssh-wrapper.git`
end
Expand All @@ -73,17 +78,21 @@ is set, git will use $GIT\_SSH instead of `ssh` to connect.
The script generated will look something like this:
(as long as I've kept this documentation up-to-date properly)

#!/bin/sh
unset SSH_AUTH_SOCK
ssh -o 'CheckHostIP no' \
-o 'IdentitiesOnly yes' \
-o 'LogLevel LOG_LEVEL' \
-o 'StrictHostKeyChecking no' \
-o 'PasswordAuthentication no' \
-o 'UserKnownHostsFile /dev/null' \
-o 'IdentityFile PRIVATE_KEY_PATH' \
ssh -o CheckHostIP=no \
-o IdentitiesOnly=yes \
-o LogLevel=LOG_LEVEL \
-o StrictHostKeyChecking=no \
-o PasswordAuthentication=no \
-o UserKnownHostsFile=TEMPFILE \
-o IdentityFile=PRIVATE_KEY_PATH \
$*

The result is an ssh connection that won't use your ssh-added keys, won't prompt
for passwords, doesn't save known hosts and doesn't require strict host key
checking.

A tempfile is generated to absorb known hosts to prevent these constant warnings:
`Warning: Permanently added 'xxx' (RSA) to the list of known hosts.`

The tempfile is cleaned when the wrapper is unlinked or the program exits.
6 changes: 5 additions & 1 deletion lib/git-ssh-wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@ def script(private_key_path, log_level)
tempfile(<<-SCRIPT, EXEC_MODE)
#!/bin/sh
unset SSH_AUTH_SOCK
ssh -o 'CheckHostIP no' -o 'IdentitiesOnly yes' -o 'LogLevel #{log_level}' -o 'StrictHostKeyChecking no' -o 'PasswordAuthentication no' -o 'UserKnownHostsFile /dev/null' -o 'IdentityFile #{private_key_path}' $*
ssh -o CheckHostIP=no -o IdentitiesOnly=yes -o LogLevel=#{log_level} -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o UserKnownHostsFile=#{known_hosts_file} -o IdentityFile=#{private_key_path} $*
SCRIPT
end

def known_hosts_file
@known_hosts_file ||= tempfile('')
end

def tempfile(content, mode=SAFE_MODE)
file = Tempfile.new("git-ssh-wrapper")
file << content
Expand Down
4 changes: 2 additions & 2 deletions spec/bin_git_ssh_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'spec_helper'

describe 'git-ssh script' do
let(:bin) { ROOT_PATH.join('bin/git-ssh') }
let(:bin) { GIT_SSH_BIN }
let(:usage) { "usage:\tgit-ssh ssh.key command\n" }

it "prints usage information with no args" do
Expand Down Expand Up @@ -34,6 +34,6 @@

it "does not delete the keyfile" do
run_succeeds(bin, private_key_path, 'status')
Pathname.new(private_key_path).should exist
private_key_path.should exist
end
end
8 changes: 4 additions & 4 deletions spec/bin_wrapper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe 'git-ssh-wrapper script' do
let(:print_env) { ROOT_PATH.join('spec/print_env') }
let(:bin) { ROOT_PATH.join('bin/git-ssh-wrapper') }
let(:bin) { WRAPPER_BIN }
let(:usage) { "usage:\tgit-ssh-wrapper ssh.key command\n" }

it "prints usage information with no args" do
Expand All @@ -29,12 +29,12 @@
end

it "sets the GIT_SSH environment variable" do
run_succeeds(bin, private_key_path, print_env).chomp.should =~ /git-ssh-wrapper/ # the tempfile includes this in the name
run_succeeds(bin, private_key_path, print_env_script).chomp.should =~ /git-ssh-wrapper/ # the tempfile includes this in the name
end

it "cleans up after execution" do
run_succeeds(bin, private_key_path, 'true')
`#{print_env}`.chomp.should be_empty
`#{print_env_script}`.chomp.should be_empty
ENV['GIT_SSH'].should be_nil
end

Expand All @@ -45,6 +45,6 @@

it "does not delete the keyfile" do
run_succeeds(bin, private_key_path, 'true')
Pathname.new(private_key_path).should exist
private_key_path.should exist
end
end
5 changes: 2 additions & 3 deletions spec/git_ssh_wrapper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@
it_should_behave_like "a GIT_SSH wrapper"

it "should not delete the keyfile when unlinked" do
pathname = Pathname.new(private_key_path)
pathname.should be_exist
private_key_path.should exist
subject.unlink
pathname.should be_exist
private_key_path.should exist
end
end

Expand Down
15 changes: 12 additions & 3 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,28 @@
require 'git-ssh-wrapper'
require 'rspec'

ROOT_PATH = Pathname.new("..").expand_path(File.dirname(__FILE__))
ROOT_PATH = Pathname.new("..").expand_path(File.dirname(__FILE__))
PRIVATE_KEY_PATH = ROOT_PATH.join('spec/test_key').realpath.freeze
PRIVATE_KEY = PRIVATE_KEY_PATH.read.freeze
GIT_SSH_BIN = ROOT_PATH.join('bin/git-ssh').freeze
WRAPPER_BIN = ROOT_PATH.join('bin/git-ssh-wrapper').freeze
PRINT_ENV_SCRIPT = ROOT_PATH.join('spec/print_env').freeze

module SpecHelpers
def exist
be_exist
end

def private_key
private_key_path.read
PRIVATE_KEY
end

def private_key_path
Pathname.new('spec/test_key').realpath
PRIVATE_KEY_PATH
end

def print_env_script
PRINT_ENV_SCRIPT
end

def run_succeeds(bin, *args)
Expand Down

0 comments on commit a7ba1e4

Please sign in to comment.