diff --git a/README.md b/README.md index f8de0d6..9d68d3e 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,17 @@ $ gh-auth add --users=chrishunt --command="tmux attach" Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys' ``` +Allowing someone to SSH to your machine can be a scary thing. Restricting them +to a single command goes a little way to help secure things, but if you want to +keep them from forwarding ports and such, try the lockdown option. It prepends +their key file entry with `no-port-forwarding,no-X11-forwarding,no-agent-forwarding` +For more information check out the [8th Chapter of the SSH book](http://oreilly.com/catalog/sshtdg/chapter/ch08.html): + +```bash +$ gh-auth add --users=chrishunt --lockdown +Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys' +``` + That was easy! When we're done working, you can revoke my access with: ```bash diff --git a/lib/github/auth/cli.rb b/lib/github/auth/cli.rb index c0a1cca..aa7d0c6 100644 --- a/lib/github/auth/cli.rb +++ b/lib/github/auth/cli.rb @@ -8,6 +8,7 @@ class CLI < Thor option :users, type: :array, required: true option :command, type: :string + option :lockdown, type: :boolean desc 'add', 'Add GitHub users to authorized keys' long_desc <<-LONGDESC `gh-auth add` is used to add one or more GitHub user's public SSH keys @@ -22,11 +23,16 @@ class CLI < Thor the `--command` option. > $ gh-auth add --users=chrishunt --command="tmux attach" + + You may also "lockdown" shell access, preventing forwarding, by + including the `--lockdown` option. + + > $ gh-auth add --users=chrishunt --lockdown LONGDESC def add on_keys_file :write!, "Adding #{keys.count} key(s) to '#{keys_file.path}'", - { command: options[:command] } + { command: options[:command], lockdown: options[:lockdown] } end option :users, type: :array, required: true diff --git a/lib/github/auth/keys_file.rb b/lib/github/auth/keys_file.rb index a450468..d26f097 100644 --- a/lib/github/auth/keys_file.rb +++ b/lib/github/auth/keys_file.rb @@ -1,7 +1,7 @@ module Github::Auth # Write and delete keys from the authorized_keys file class KeysFile - attr_reader :path, :command + attr_reader :path, :command, :lockdown PermissionDeniedError = Class.new StandardError FileDoesNotExistError = Class.new StandardError @@ -10,7 +10,8 @@ class KeysFile def initialize(options = {}) @path = File.expand_path(options[:path] || DEFAULT_PATH) - @command = options[:command] + @command = options[:command] + @lockdown = options.fetch(:lockdown){ false } end def write!(keys) @@ -20,7 +21,7 @@ def write!(keys) unless keys_file_content.empty? || keys_file_content.end_with?("\n") keys_file.write "\n" end - keys_file.write "#{"command=\"#{command}\" " if command}#{key}\n" + keys_file.write key_line(key) end end end @@ -69,5 +70,19 @@ def keys_file_content_without(keys) content << "\n" unless content.empty? || content.end_with?("\n") end end + + def key_line_prefixes + prefixes = [] + prefixes << 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding' if lockdown + prefixes << %Q{command="#{command}"} if command + prefixes.join(',') + end + + def key_line(key) + line = [] + line << key_line_prefixes unless key_line_prefixes.empty? + line << "#{key}\n" + line.join(' ') + end end end diff --git a/spec/acceptance/github/auth/cli_spec.rb b/spec/acceptance/github/auth/cli_spec.rb index 889af5e..2c7f276 100644 --- a/spec/acceptance/github/auth/cli_spec.rb +++ b/spec/acceptance/github/auth/cli_spec.rb @@ -54,6 +54,17 @@ def cli(args = []) expect(keys_file.read.strip).to be_empty end + it 'supports ssh "lockdown"' do + cli %w(add --users=chrishunt --lockdown) + + expect(keys_file.read).to include 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding' + + keys_file.rewind + cli %w(remove --users=chrishunt) + + expect(keys_file.read.strip).to be_empty + end + it 'prints version information' do output = capture_stdout do cli %w(version) diff --git a/spec/unit/github/auth/keys_file_spec.rb b/spec/unit/github/auth/keys_file_spec.rb index c6d046c..4a1494d 100644 --- a/spec/unit/github/auth/keys_file_spec.rb +++ b/spec/unit/github/auth/keys_file_spec.rb @@ -92,6 +92,19 @@ end end + context 'with "lockdown"' do + let(:options) {{ path: path, lockdown: true }} + let(:keys) {[ Github::Auth::Key.new('chris', 'abc123') ]} + + it_should_behave_like 'a successful key addition' + + it 'prefixes the key with "lockdown" options' do + subject.write! keys + + expect(keys_file.read).to include 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding' + end + end + context 'with existing keys in the keys file' do let(:existing_keys) { %w(abc123 def456 ghi789) } let(:keys) {[ Github::Auth::Key.new('chris', 'jkl012') ]}