Skip to content

Instantly share code, notes, and snippets.

@bradfordcp
Last active August 29, 2015 14:25
Show Gist options
  • Save bradfordcp/32cafe888bb7f9c88259 to your computer and use it in GitHub Desktop.
Save bradfordcp/32cafe888bb7f9c88259 to your computer and use it in GitHub Desktop.
Provides a CLI to manage SSH keys pulled from GitHub in ~/.ssh/authorized_keys.

gh_keys

A CLI tool to add public keys to your host. The keys are pulled via GitHub API.

Listing all keys for the current user

Lists all keys, it will break down keys by GitHub username.

gh_keys list
GitHub Keys:
############
bradfordcp: 
  SOME-GITHUB-KEY
  ANOTHER-GITHUB-KEY

Other Keys:
###########
ANOTHER-KEY
YET-ANOTHER-KEY With a comment

Adding a new key

Adds keys for the supplied GitHub username.

./gh_keys add bradfordcp
Added key: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtoIEWC462NCsowWBHuph4DZbUprmpheLD8BWZMIVTmBZW50VnRKLHVJF71hV2JQu2V16hQay3DvGg0VW0BjZnR1b651TRTw0rdSb5fKMTbq+MhtguV5vXe1Vs42PnEZS/ED7kYsP/jMAo9OorlJtq7U6NAPeLsxCyWMq/FPNaE7Io55NHT6LkGHdzL7PsrTTQUnK7OojNyCwx600kVUAF/AsFPEiZ03WSf28Ojdg0xtJGf1NTYmtDZ4qJlIFE1AQtUWMbdPB4hubgUdtQGrfAYCmQb8v3cbyFn1fHOzbdDH//iJGAcvA3Foq1DtwHPWC+0g7tn1kqyJIyi+Gl63RuQ==
Added key: ANOTHER-GITHUB-KEY

Removing a key

Removes all keys for the given GitHub username.

./gh_keys remove bradfordcp
Removed keys for bradfordcp

Refreshing keys

Use the add command, all keys will be replaced with the values pulled from GitHub.

#!/usr/bin/env ruby
require 'uri'
require 'net/http'
require 'json'
require 'optparse'
authorized_keys_file = File.expand_path '~/.ssh/authorized_keys'
key_matcher = /(ssh-rsa (?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=))( (GH:)?(.*))?/
options = {}
# Define root level parameters
global = OptionParser.new do |opts|
opts.banner = 'Usage: gh_keys command [username]'
end
# Define subcommands
subcommands = {
'list' => OptionParser.new do |opts|
opts.banner = 'Usage: gh_keys list'
end,
'add' => OptionParser.new do |opts|
opts.banner = 'Usage: gh_keys add username'
end,
'remove' => OptionParser.new do |opts|
opts.banner = 'Usage: gh_keys remove username'
end
}
# Helper method to force print help
def print_help(global_parser)
ARGV.delete_if {|_| true}
ARGV << '--help'
global_parser.order!
end
# Start parsing options
global.order!
if ARGV.length >= 1
command = ARGV.shift
if subcommands.key? command
subcommands[command].order!
options[:username] = ARGV.shift() if ARGV.length == 1
# Load all key information
gh_keys = {}
other_keys = []
File.open(authorized_keys_file, 'r') do |io|
lines = io.readlines
lines.each do |line|
matchdata = line.match key_matcher
if matchdata
if matchdata[3]
gh_keys[matchdata[4]] = [] unless gh_keys.key? matchdata[4]
gh_keys[matchdata[4]] << matchdata[1]
else
other_keys << "#{matchdata[1]}#{matchdata[2]}"
end
end
end
end
def write_keys file, gh_keys, other_keys
File.open(file, 'w') do |io|
gh_keys.each_pair do |username, keys|
keys.each do |key|
io.puts "#{key} GH:#{username}"
end
end
other_keys.each do |key|
io.puts key
end
end
end
case command
when 'list'
puts 'GitHub Keys:'
puts '############'
gh_keys.each_pair do |username, keys|
puts "#{username}: "
keys.each do |key|
puts " #{key}"
end
end
puts ''
puts 'Other Keys:'
puts '###########'
other_keys.each do |key|
puts key
end
puts ''
when 'add'
if options[:username]
uri = URI("https://api.github.com/users/#{options[:username]}/keys")
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
request = Net::HTTP::Get.new uri
response = http.request request
if response.code == '200'
gh_response = JSON.parse response.body
gh_keys[options[:username]] = []
gh_response.each do |gh_key|
gh_keys[options[:username]] << gh_key['key']
puts "Added key: #{gh_key['key']}"
end
end
end
write_keys authorized_keys_file, gh_keys, other_keys
else
puts 'Missing username'
print_help subcommands['add']
end
when 'remove'
gh_keys[options[:username]] = []
puts "Removed keys for #{options[:username]}"
write_keys authorized_keys_file, gh_keys, other_keys
end
else
puts "Unrecognized command: #{command}"
print_help global
end
else
print_help global
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment