conssh 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3747759ebf30a2156d2a3e27b22bb5203010b91c4ce7ddb9c46fa5edcb3ec9da
4
+ data.tar.gz: 77808aa31fa8e883827484a657527aada101f5c932984c182da989c83ff526d1
5
+ SHA512:
6
+ metadata.gz: 2553fd95a8a13aa3fcc942d1d662a094b2c9fdf035fa00b7b0ea8e2f49960c0af079b56dc18107b5e48edb5b49f762b5bc2c28183db42466ac743182adec0e38
7
+ data.tar.gz: 6843d3750e387672c5c911e8fcce5741c3d5084ec4a57ad39da63b8a8838d52ce02ceb4cfaaffd77cad6a5fbda2f0cbdea61a162f019e3d034d8cc4c0419fab6
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # Don't include this in gems
14
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.5
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ before_install: gem install bundler -v 1.16.0
Binary file
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in conssh.gemspec
6
+ gemspec
@@ -0,0 +1,52 @@
1
+ # Conssh
2
+
3
+ ![A drawing of a conch shell](Conch_drawing.jpg)
4
+
5
+ Conssh is a utility to configure SSH. It generates config files with connection
6
+ information for a fleet of EC2 instances.
7
+
8
+ Use it together with an autocompletion tool that understands SSH, like
9
+ [bash-completion] or [fzf].
10
+
11
+ Basic usage:
12
+
13
+ ```
14
+ $ AWS_REGION=us-west-1 AWS_PROFILE=staging bundle exec conssh > ~/.ssh/config
15
+ $ ssh …
16
+ ```
17
+
18
+ [bash-completion]: https://github.com/scop/bash-completion
19
+ [fzf]: https://github.com/junegunn/fzf
20
+
21
+ ## Background
22
+
23
+ It is inspired by similar tools such as [ec2ssh] and [aws-ssh-config].
24
+
25
+ This is experimental code. See the issues section for the work to make it more
26
+ robust.
27
+
28
+ Notable features:
29
+
30
+ * Written in [Ruby] using version 3 of the [AWS SDK]
31
+ * Unit tested using the [Moto] mock AWS API server
32
+ * Packaged as a Ruby gem to use as a library or an executable
33
+
34
+ [ec2ssh]: https://github.com/mirakui/ec2ssh
35
+ [aws-ssh-config]: https://github.com/gianlucaborello/aws-ssh-config
36
+ [Ruby]: https://www.ruby-lang.org/
37
+ [AWS SDK]: https://github.com/aws/aws-sdk-ruby/
38
+ [Moto]: https://github.com/spulec/moto
39
+
40
+ ## How do I get set up?
41
+
42
+ See the [setup](setup.md) document for an early version step-by-step setup.
43
+
44
+ ## Demo
45
+
46
+ Build the docker container and follow the instructions when the container runs.
47
+
48
+ ```bash
49
+ cd demo
50
+ docker build --tag demo .
51
+ docker run -it demo
52
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "conssh"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'conssh' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("conssh", "conssh")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'htmldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("diff-lcs", "htmldiff")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("diff-lcs", "ldiff")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ruby-parse' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("parser", "ruby-parse")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ruby-rewrite' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("parser", "ruby-rewrite")
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,20 @@
1
+ image: ruby:2.5.0
2
+
3
+ pipelines:
4
+ default:
5
+ - step:
6
+ caches:
7
+ - bundler
8
+ - pip
9
+ - pythonpackages
10
+ script:
11
+ - apt-get update
12
+ - apt-get --assume-yes install --yes python-pip
13
+ - pip install --user moto flask
14
+ - bundle install --path vendor/bundle
15
+ - MOTO_SERVER=~/.local/bin/moto_server rspec
16
+
17
+ definitions:
18
+ caches:
19
+ bundler: ./vendor
20
+ pythonpackages: ~/.local
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "conssh/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "conssh"
8
+ spec.version = Conssh::VERSION
9
+ spec.authors = ["Iain Samuel McLean Elder"]
10
+ spec.email = ["iainelder@hotmail.co.uk"]
11
+
12
+ spec.summary = %q{Configure SSH to connect to an EC2 fleet}
13
+ spec.description = <<~DESCRIPTION
14
+ Conssh is a utility to configure SSH. It generates config files with
15
+ connection information for a fleet of EC2 instances. Use it together with
16
+ an autocompletion tool that understands SSH, like bash-completion or fzf.
17
+ DESCRIPTION
18
+ spec.homepage = "https://bitbucket.org/isme/conssh"
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
21
+ f.match(%r{^(test|spec|features)/})
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.16"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rspec", "~> 3.0"
30
+
31
+ spec.add_dependency "aws-sdk-ec2", "~> 1.0"
32
+ end
@@ -0,0 +1,7 @@
1
+ FROM ubuntu:16.04
2
+
3
+ COPY setup.sh run.sh /
4
+
5
+ RUN /setup.sh
6
+
7
+ CMD ["bash", "/run.sh"]
@@ -0,0 +1,32 @@
1
+ #/bin/bash
2
+
3
+ while : ; do
4
+ read -p "AWS Profile Name: " profile
5
+ if [[ "${profile}" = "" ]]; then
6
+ break
7
+ fi
8
+ aws configure --profile "${profile}"
9
+ done
10
+
11
+ read -p "Press a key to edit SSH private key."
12
+ vim ~/.ssh/id_rsa
13
+
14
+ read -p "Press a key to edit SSH public key."
15
+ vim ~/.ssh/id_rsa.pub
16
+
17
+ read -p "Press a key to edit host config."
18
+ echo "
19
+ Host <%= profile %>_<%= tags['Name'] %>_<%= instance_id %>
20
+ Hostname <%= public_dns_name %>
21
+ " > ~/.ssh/ec2_host.erb
22
+ vim ~/.ssh/ec2_host.erb
23
+
24
+ echo "Generating SSH config..."
25
+ profile_list=$(grep "\[" ~/.aws/credentials | tr -d '[]' | paste -sd ',' -)
26
+ /ec2-ssh-config-generator/generate-config.rb "${profile_list}" > ~/.ssh/config
27
+
28
+ echo "To regenerate: \`/ec2-ssh-config-generator/generate-config.rb ${profile_list} > ~/.ssh/config\`"
29
+
30
+ echo "Type 'ssh **' then TAB to start!"
31
+
32
+ bash
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+
3
+ # A fresh Ubuntu image doesn't have a package list, so we need to update it
4
+ # first before any of the install commands will work.
5
+ apt-get update
6
+
7
+ # The image doesn't have a bunch of things that you will expect to be there when
8
+ # you setting up and playing around. I assume you know what these are, let's
9
+ # just get them installed!
10
+ apt-get install --yes vim less man wget git
11
+
12
+ # The image doesn't have an SSH client either, so let's install that. We will
13
+ # also quickly set up the usual files with the right permissions so that ssh
14
+ # won't complain.
15
+ apt-get install --yes openssh-client
16
+ mkdir ~/.ssh/
17
+ touch ~/.ssh/{known_hosts,config,id_rsa,id_rsa.pub}
18
+ chmod --recursive 0600 ~/.ssh/
19
+
20
+ # Installing AWS CLI is not strictly necessary, but it is the easiest way to
21
+ # configure the AWS profiles.
22
+ apt-get install --yes awscli
23
+
24
+ # Install the best autocomplete tool.
25
+ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
26
+ ~/.fzf/install --all
27
+
28
+ # The config generator is a Ruby app, so we need to install it.
29
+ # The app is not packaged as a gem but installed from source, so we also have to use bundler
30
+ # to install the other Ruby dependencies.
31
+ apt-get install --yes ruby
32
+ gem install bundler
33
+
34
+ # Install the config generator.
35
+ git clone https://isme@bitbucket.org/isme/ec2-ssh-config-generator.git
36
+ cd ec2-ssh-config-generator
37
+ bundle install
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'conssh'
4
+
5
+ conssh = Conssh::App.new
6
+ conssh.generate_config
@@ -0,0 +1,8 @@
1
+ require "conssh/version"
2
+ require "conssh/inventory"
3
+ require "conssh/config_writer"
4
+ require "conssh/app"
5
+
6
+ module Conssh
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'inventory'
2
+ require_relative 'config_writer'
3
+
4
+ module Conssh
5
+ class App
6
+ def generate_config
7
+ ConfigWriter.new(:out => STDOUT).render(Inventory.new.hosts)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ module Conssh
2
+ class ConfigWriter
3
+
4
+ def initialize(args={})
5
+ @out = args[:out] || File.new('host_config', 'w+')
6
+ end
7
+
8
+ def render(inst)
9
+ first, *rest = *Array(inst)
10
+ render_one(first) if first
11
+ rest.each do |i|
12
+ @out.puts
13
+ render_one(i)
14
+ end
15
+ end
16
+
17
+ private def render_one(inst)
18
+ @out.puts("Host #{inst.id}")
19
+ @out.puts("HostName #{inst.public_ip_address}")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ require 'aws-sdk-ec2'
2
+
3
+ module Conssh
4
+ class Inventory
5
+
6
+ def initialize(args={})
7
+ args[:client] ||= Aws::EC2::Client.new
8
+ @ec2 = Aws::EC2::Resource.new(:client => args[:client])
9
+ end
10
+
11
+ def hosts
12
+ @ec2.instances.to_a
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Conssh
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,178 @@
1
+ I assume you have just one SSH keypair to access all of your EC2 instances, and you keep it locally.
2
+
3
+ I also assume you need to access instances in multiple accounts and multiple regions.
4
+
5
+ I assume you have docker installed and ready to use in your environment.
6
+
7
+ Before we start, get the all the credentials required to access the API of your AWS account and the SSH sessions of your EC2 instances.
8
+
9
+ The brackets here are just a fancy way to generate filenames with a common prefix. Saves a bit of typing.
10
+
11
+ ```
12
+ less ~/.aws/credentials ~/.ssh/id_rsa{,.pub}
13
+ ```
14
+
15
+ Start a new Ubuntu container.
16
+
17
+ ```
18
+ docker run -it ubuntu:16.04
19
+ ```
20
+
21
+ A fresh Ubuntu image doesn't have a package list, so we need to update it first before any of the install commands will work.
22
+
23
+ ```
24
+ apt-get update
25
+ ```
26
+
27
+ The image doesn't have a bunch of things that you will expect to be there when you setting up and playing around. I assume you know what these are, let's just get them installed!
28
+
29
+ ```
30
+ apt-get install vim less man wget git
31
+ ```
32
+
33
+ The bash-completion package is also expected, and deserves a special mention here because it's what makes the magic happen later when have the correct SSH config.
34
+
35
+ Change the default bindings to make the autocomplete behavior a bit nicer in bash.
36
+
37
+ To make it take effect in the existing session we have to source the global profile again.
38
+
39
+ ```
40
+ apt-get install bash-completion
41
+ bind "TAB:menu-complete"
42
+ bind "set show-all-if-ambiguous on"
43
+ source /etc/profile
44
+ ```
45
+
46
+ The image doesn't have an SSH client either, so let's install that.
47
+
48
+ We will also quickly set up the usual file with the right permissions so that ssh won't complain.
49
+
50
+ See way below for how to install a later version of the client that supports the Include directive.
51
+
52
+ ```
53
+ apt-get install openssh-client
54
+ mkdir ~/.ssh/
55
+ touch ~/.ssh/{known_hosts,config,id_rsa,id_rsa.pub}
56
+ chmod --recursive 0600 ~/.ssh/
57
+ ```
58
+
59
+ While we are here, we can configure it with our SSH keys we will use to access the instances.
60
+
61
+ ```
62
+ vim ~/.ssh/id_rsa
63
+ vim ~/.ssh/id_rsa.pub
64
+ ```
65
+
66
+ Installing AWS CLI is not strictly necessary, but it is the easiest way to configure the AWS profiles.
67
+
68
+ Paste access key and secret key from aws credentials.
69
+
70
+ Check it works by querying your user info.
71
+
72
+ ```
73
+ apt-get install awscli
74
+ aws configure --profile staging
75
+ aws iam get-user --profile staging
76
+ aws configure --profile production
77
+ aws iam get-user --profile production
78
+ ```
79
+
80
+ As ec2ssh is a Ruby gem, we first have to install Ruby so that we can use gem to install it.
81
+
82
+ It unfortunately depends on the Nokogiri gem, so we have to install a bunch of other non-Ruby stuff to make it work.
83
+
84
+ ```
85
+ apt-get install ruby
86
+ apt-get install build-essential patch ruby-dev zlib1g-dev liblzma-dev
87
+ gem install ec2ssh
88
+ ```
89
+
90
+ Run init and check that an empty block is created and that the default config is set up.
91
+
92
+ ```
93
+ ec2ssh init
94
+ cat ~/.ssh/config
95
+ cat ~/.ec2ssh
96
+ ```
97
+
98
+ In the default config you'll see sections for sets of credentials and a list of regions.
99
+
100
+ First let's set up the tool to query all regions so we are sure the list is complete.
101
+
102
+ ```
103
+ aws ec2 describe-regions --region us-east-1 --query 'Regions[].RegionName' --output text
104
+ ```
105
+
106
+ Paste the output of that command into the region directive (there is a commented-out example).
107
+
108
+ ```
109
+ vim ~/.ec2ssh
110
+ ```
111
+
112
+ The list is static, so you will have to update it when Amazon adds a new region. Thankfully here that happens relatvively infrequently.
113
+
114
+ Unfortunately the program queries each region serially, so you might have a to wait a while. It would be great to do the queries in parallel, but it probably requires modifying the program.
115
+
116
+ If you don't mind having a copy of your credentials in the ec2ssh config, then set up a staging and a production section with your keys.
117
+
118
+ Otherwise see the next section for how to generate an equivalent ssh config using just the prodi
119
+
120
+ If no credentials are set in the config, it will use whatever profile is set in the environment.
121
+
122
+ If you prefer to manage all your AWS credentials as CLI profiles, then you simulate the behavior with a few extra steps.
123
+
124
+ It would be awesome if the program was profile aware, but that probably requires modifying the program.
125
+
126
+ ```
127
+ ec2ssh init --path ~/.ssh/config_staging
128
+ AWS_PROFILE=staging ec2ssh update --path ~/.ssh/config_staging
129
+ ec2ssh init --path ~/.ssh/config_production
130
+ AWS_PROFILE=production ec2ssh update --path ~/.ssh/config_production
131
+ ```
132
+
133
+ As of SSH 7.3 (Mac OS X Sierra has 7.4) , you can include these compartmentalizied configrations using the new Include directive.
134
+
135
+ However, bash and zsh still don't support completion for included configs (although the feature appears to be on its way for zsh).
136
+
137
+ For now, the easiest thing is just to combine the two configs together into one file.
138
+
139
+ This also has the advantage of working with older versions of SSH that don't support the Include directive (Ubuntu Xenial has 7.2).
140
+
141
+ ```
142
+ cat ~/.ssh/config_{staging,production} > ~/.ssh/config
143
+ ```
144
+
145
+ Edit the config how we see fit.
146
+
147
+ ```
148
+ vim ~/.ec2ssh # add public_ip_address
149
+ ec2ssh update
150
+ ````
151
+
152
+ Bunch of commands to install ssh 7.4, part of ubuntu's latest stable release (Zesty Zapus) and the same version on Mac OS X.
153
+
154
+ ```
155
+ wget https://launchpad.net/ubuntu/+source/openssh/1:7.4p1-10/+build/12390736/+files/openssh-client_7.4p1-10_amd64.deb
156
+ dpkg -i openssh-client_7.4p1-10_amd64.deb
157
+ wget https://launchpad.net/ubuntu/+source/openssh/1:7.4p1-10/+build/12390736/+files/ssh-krb5_7.4p1-10_all.deb
158
+ dpkg -i ssh-krb5_7.4p1-10_all.deb
159
+ wget https://launchpad.net/ubuntu/zesty/amd64/libgssapi-krb5-2/1.15-1
160
+ wget http://launchpadlibrarian.net/296470446/libgssapi-krb5-2_1.15-1_amd64.deb
161
+ dpkg -i libgssapi-krb5-2_1.15-1_amd64.deb
162
+ wget http://launchpadlibrarian.net/296470457/libkrb5support0_1.15-1_amd64.deb
163
+ dpkg -i libkrb5support0_1.15-1_amd64.deb
164
+ dpkg -i libgssapi-krb5-2_1.15-1_amd64.deb
165
+ wget http://launchpadlibrarian.net/296470455/libkrb5-3_1.15-1_amd64.deb
166
+ deb -i libkrb5-3_1.15-1_amd64.deb
167
+ dbkg -i libkrb5-3_1.15-1_amd64.deb
168
+ dpkg -i libkrb5-3_1.15-1_amd64.deb
169
+ apt-get upgrade
170
+ wget https://launchpad.net/ubuntu/+source/krb5/1.15-1/+build/11519847/+files/libk5crypto3_1.15-1_amd64.deb
171
+ dpkg -i libk5crypto3_1.15-1_amd64.deb
172
+ deb -i libkrb5-3_1.15-1_amd64.deb
173
+ dpkg -i libkrb5-3_1.15-1_amd64.deb
174
+ ls *.deb
175
+ dpkg -i openssh-client_7.4p1-10_amd64.deb
176
+ dpkg -i libgssapi-krb5-2_1.15-1_amd64.deb
177
+ dpkg -i openssh-client_7.4p1-10_amd64.deb
178
+ ```
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: conssh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Iain Samuel McLean Elder
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aws-sdk-ec2
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ description: |
70
+ Conssh is a utility to configure SSH. It generates config files with
71
+ connection information for a fleet of EC2 instances. Use it together with
72
+ an autocompletion tool that understands SSH, like bash-completion or fzf.
73
+ email:
74
+ - iainelder@hotmail.co.uk
75
+ executables:
76
+ - conssh
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - ".bundle/config"
81
+ - ".gitignore"
82
+ - ".rspec"
83
+ - ".ruby-version"
84
+ - ".travis.yml"
85
+ - Conch_drawing.jpg
86
+ - Gemfile
87
+ - README.md
88
+ - Rakefile
89
+ - bin/bundle
90
+ - bin/console
91
+ - bin/conssh
92
+ - bin/htmldiff
93
+ - bin/ldiff
94
+ - bin/rake
95
+ - bin/rspec
96
+ - bin/rubocop
97
+ - bin/ruby-parse
98
+ - bin/ruby-rewrite
99
+ - bin/setup
100
+ - bitbucket-pipelines.yml
101
+ - conssh.gemspec
102
+ - demo/Dockerfile
103
+ - demo/run.sh
104
+ - demo/setup.sh
105
+ - exe/conssh
106
+ - lib/conssh.rb
107
+ - lib/conssh/app.rb
108
+ - lib/conssh/config_writer.rb
109
+ - lib/conssh/inventory.rb
110
+ - lib/conssh/version.rb
111
+ - setup.md
112
+ homepage: https://bitbucket.org/isme/conssh
113
+ licenses: []
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.7.3
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Configure SSH to connect to an EC2 fleet
135
+ test_files: []