sshkit-ec2instanceconnect 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4457259f1ad225bf3974f58d58c4b77e5141b94c66506423101dc874438e13d0
4
+ data.tar.gz: 2b98209f24ec5f55837b4e8e1f790e0fc1f47dc909083dd52c3d80396d059c23
5
+ SHA512:
6
+ metadata.gz: 2a754e8d2ffb490deb94b01fe7378d8fcd10d02722d406882d2cb95266e6af8335325a01ef3af690cfe3dea2dd73343b94d4639423f1abf47837d7e5c8aede91
7
+ data.tar.gz: c9c8696b44a6c310031b5981c3406309d6e68ca296ba3ae1e7a8cd61ad65ed257e6ae1da4095154d46d4cd00006e741484dda1e33dcd0ac50191d640d4d992a2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Kentaa BV
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # sshkit-ec2instanceconnect
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/sshkit-ec2instanceconnect.svg)](https://badge.fury.io/rb/sshkit-ec2instanceconnect)
4
+ [![Build Status](https://github.com/KentaaNL/sshkit-ec2instanceconnect/actions/workflows/test.yml/badge.svg)](https://github.com/KentaaNL/sshkit-ec2instanceconnect/actions)
5
+ [![CodeQL](https://github.com/KentaaNL/sshkit-ec2instanceconnect/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/KentaaNL/sshkit-ec2instanceconnect/actions/workflows/github-code-scanning/codeql)
6
+
7
+ A [SSHKit](https://github.com/capistrano/sshkit) backend that integrates with
8
+ [AWS EC2 Instance Connect](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-linux-inst-eic.html) .
9
+
10
+ This backend automatically generates ephemeral SSH keys, delivers the public key to the target instance using EC2 Instance Connect, and refreshes the key before it expires. It is designed for use with [Capistrano](https://github.com/capistrano/capistrano) deployments on AWS.
11
+
12
+ Additionally, the backend can optionally connect through an [EC2 Instance Connect Endpoint](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-with-ec2-instance-connect-endpoint.html) by establishing a tunnel and routing SSH traffic through it.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'sshkit-ec2instanceconnect'
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ Global configuration can be set during application boot (e.g., in a Capistrano initializer).
25
+ Default configuration:
26
+
27
+ ```ruby
28
+ SSHKit::EC2InstanceConnect.configure do |config|
29
+ config.ssh_key_refresh_enabled = true # Enable ephemeral SSH keys and refresh them periodically
30
+ config.ssh_key_size = 3072 # Ephemeral SSH key size (RSA)
31
+ config.tunnel_enabled = false # Enable EC2 Instance Connect Endpoint tunneling
32
+ config.tunnel_ports = 8000...8100 # Local port range used when allocating a tunnel
33
+ end
34
+ ```
35
+
36
+ To use this backend with Capistrano, add to your `config/deploy.rb`:
37
+
38
+ ```ruby
39
+ set :sshkit_backend, SSHKit::EC2InstanceConnect::Backend
40
+ ```
41
+
42
+ Ensure your server definitions include the `instance_id` property:
43
+
44
+ ```ruby
45
+ server 'ec2-hostname', user: 'ec2-user', roles: %w[app web], instance_id: 'i-0abcdef1234567890'
46
+ ```
47
+
48
+ When using [capistrano-asg-rolling](https://github.com/KentaaNL/capistrano-asg-rolling), no additional configuration is needed; it automatically passes the correct `instance_id` to the backend.
49
+
50
+ ## EC2 Instance Connect Endpoint (Tunneling)
51
+
52
+ This gem supports connecting to EC2 instances through an [EC2 Instance Connect Endpoint](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-with-ec2-instance-connect-endpoint.html) by invoking the AWS CLI command `aws ec2-instance-connect open-tunnel`.
53
+
54
+ When tunneling is enabled:
55
+ 1. A local port is selected from the configured `tunnel_ports` range.
56
+ 2. A tunnel is opened to the target instance through the EC2 Instance Connect Endpoint.
57
+ 3. SSHKit connects through the tunnel transparently.
58
+ 4. The tunnel is automatically closed when the session ends.
59
+
60
+ This is particularly useful in VPC environments where instances do not have public IPs and can only be accessed through an EC2 Instance Connect Endpoint.
61
+
62
+ To enable tunneling, set:
63
+
64
+ ```ruby
65
+ config.tunnel_enabled = true
66
+ ```
67
+
68
+ **Note**: Tunneling requires the AWS CLI (`aws ec2-instance-connect`) to be installed and configured.
69
+
70
+ ## IAM Policy
71
+
72
+ Sending ephemeral SSH keys and opening tunnels require the correct IAM permissions.
73
+ For example:
74
+
75
+ ### EC2 Instance Connect
76
+
77
+ ```json
78
+ {
79
+ "Version": "2012-10-17",
80
+ "Statement": [
81
+ {
82
+ "Effect": "Allow",
83
+ "Action": ["ec2-instance-connect:SendSSHPublicKey"],
84
+ "Resource": "*"
85
+ }
86
+ ]
87
+ }
88
+ ```
89
+
90
+ ### EC2 Instance Connect Endpoint (Tunneling)
91
+
92
+ ```json
93
+ {
94
+ "Version": "2012-10-17",
95
+ "Statement": [
96
+ {
97
+ "Effect": "Allow",
98
+ "Action": ["ec2-instance-connect:OpenTunnel"],
99
+ "Resource": "*"
100
+ }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ Please refer to the AWS documentation for further details.
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-ec2instanceconnect'
4
+ require 'concurrent/hash'
5
+ require 'forwardable'
6
+ require 'sshkit'
7
+
8
+ module SSHKit
9
+ module EC2InstanceConnect
10
+ # SSHKit backend that integrates with EC2 Instance Connect.
11
+ #
12
+ # It ensures that SSH keys are automatically created and send to
13
+ # the server before executing any command. It also ensures
14
+ # a timely refresh of the SSH key before it expires.
15
+ class Backend < SSHKit::Backend::Abstract
16
+ # SSH keys using EC2 Instance Connect are valid for 60 seconds,
17
+ # so refresh them a bit earlier.
18
+ EXPIRES_IN = 50
19
+
20
+ # Store SSH keys per instance with expiration.
21
+ @ssh_keys = SSHKit::EC2InstanceConnect::TimedHash.new(expires_in: EXPIRES_IN)
22
+
23
+ @tunnels = Concurrent::Hash.new
24
+
25
+ # Make sure to stop any tunnels before the Ruby process exits.
26
+ at_exit { @tunnels.each_value(&:stop) }
27
+
28
+ class << self
29
+ attr_accessor :ssh_keys, :tunnels
30
+ end
31
+
32
+ extend Forwardable
33
+
34
+ # Define delegators to the config object.
35
+ def_delegators :config, :ssh_key_size, :random_tunnel_port, :logger
36
+ private :ssh_key_size, :random_tunnel_port, :logger
37
+
38
+ def initialize(host, &)
39
+ super
40
+ @backend = SSHKit::Backend::Netssh.new(host)
41
+ end
42
+
43
+ def self.configure(&)
44
+ SSHKit::Backend::Netssh.configure(&)
45
+ end
46
+
47
+ def upload!(local, remote, options = {})
48
+ ensure_connection
49
+ @backend.send(:upload!, local, remote, options)
50
+ end
51
+
52
+ def download!(remote, local = nil, options = {})
53
+ ensure_connection
54
+ @backend.send(:download!, remote, local, options)
55
+ end
56
+
57
+ def execute_command(cmd)
58
+ ensure_connection
59
+ @backend.send(:execute_command, cmd)
60
+ end
61
+
62
+ private
63
+
64
+ def ensure_connection
65
+ if SSHKit::EC2InstanceConnect.config.tunnel_enabled
66
+ tunnel = self.class.tunnels[instance_id] ||= setup_tunnel
67
+ update_host_and_port(tunnel: tunnel)
68
+ end
69
+
70
+ if SSHKit::EC2InstanceConnect.config.ssh_key_refresh_enabled
71
+ ssh_key = self.class.ssh_keys[instance_id] ||= refresh_ssh_key
72
+ update_host_ssh_options(private_key: ssh_key.private_key)
73
+ end
74
+ end
75
+
76
+ def setup_tunnel
77
+ logger.debug { "Setting up tunnel for instance #{instance_id}" }
78
+
79
+ Tunnel.new(instance_id: instance_id, port: random_tunnel_port).tap do |tunnel|
80
+ tunnel.start
81
+
82
+ logger.debug { "Tunnel (#{tunnel}) started for instance #{instance_id}" }
83
+ end
84
+ end
85
+
86
+ def update_host_and_port(tunnel:)
87
+ host.hostname = tunnel.host
88
+ host.port = tunnel.port
89
+ end
90
+
91
+ def refresh_ssh_key
92
+ logger.debug { "Refreshing SSH key for instance #{instance_id}" }
93
+
94
+ SSHKey.new(size: ssh_key_size).tap do |ssh_key|
95
+ logger.debug { "SSH key generated, sending to instance #{instance_id}" }
96
+
97
+ send_ssh_public_key(public_key: ssh_key.public_key)
98
+ end
99
+ end
100
+
101
+ def send_ssh_public_key(public_key:)
102
+ client = Aws::EC2InstanceConnect::Client.new
103
+ client.send_ssh_public_key(
104
+ instance_id: instance_id,
105
+ instance_os_user: instance_user,
106
+ ssh_public_key: public_key
107
+ )
108
+ end
109
+
110
+ def update_host_ssh_options(private_key:)
111
+ host.ssh_options ||= {}
112
+ host.ssh_options.merge!(
113
+ keys: [],
114
+ key_data: [private_key],
115
+ keys_only: true
116
+ )
117
+ end
118
+
119
+ def instance_user
120
+ host.user
121
+ end
122
+
123
+ def instance_id
124
+ host.properties.fetch(:instance_id)
125
+ end
126
+
127
+ def config
128
+ SSHKit::EC2InstanceConnect.config
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/ssh'
4
+ require 'openssl'
5
+
6
+ module SSHKit
7
+ module EC2InstanceConnect
8
+ # Generate a private/public SSH keypair.
9
+ class SSHKey
10
+ def initialize(size:)
11
+ @key = OpenSSL::PKey::RSA.generate(size)
12
+ end
13
+
14
+ def private_key
15
+ @key.to_pem
16
+ end
17
+
18
+ def public_key
19
+ blob = @key.public_key.to_blob
20
+ encoded = [blob].pack('m0')
21
+
22
+ "ssh-rsa #{encoded}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent/map'
4
+
5
+ module SSHKit
6
+ module EC2InstanceConnect
7
+ # A thread-safe Hash that expires keys after a given time.
8
+ class TimedHash
9
+ def initialize(expires_in:)
10
+ @expires_in = expires_in
11
+ @store = Concurrent::Map.new
12
+ end
13
+
14
+ def []=(key, value)
15
+ @store[key] = { value: value, expires_at: Time.now + @expires_in }
16
+ end
17
+
18
+ def [](key)
19
+ now = Time.now
20
+
21
+ data = @store.compute_if_present(key) do |value|
22
+ # Expired → delete by returning nil.
23
+ if now > value[:expires_at]
24
+ nil
25
+ else
26
+ value # keep
27
+ end
28
+ end
29
+
30
+ data&.fetch(:value)
31
+ end
32
+
33
+ def size
34
+ @store.values.count { |value| Time.now <= value[:expires_at] }
35
+ end
36
+
37
+ def clear
38
+ @store.clear
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pty'
4
+
5
+ module SSHKit
6
+ module EC2InstanceConnect
7
+ # Manages a tunnel using the EC2 Instance Connect Endpoint Service, for secure SSH access to EC2 instances.
8
+ class Tunnel
9
+ attr_reader :host, :port
10
+
11
+ def initialize(instance_id:, host: 'localhost', port: '8000')
12
+ @instance_id = instance_id
13
+ @host = host
14
+ @port = port
15
+ end
16
+
17
+ # Start the tunnel subprocess and wait until it is listening for connections.
18
+ def start
19
+ mutex = Mutex.new
20
+ condition = ConditionVariable.new
21
+ ready = false
22
+ error = nil
23
+
24
+ @thread = Thread.new do
25
+ PTY.spawn(command) do |stdout, _stdin, pid|
26
+ @pid = pid
27
+
28
+ stdout.each_line do |line|
29
+ next unless line.start_with?('Listening for connections')
30
+
31
+ mutex.synchronize do
32
+ ready = true
33
+ condition.signal
34
+ end
35
+ end
36
+ rescue Errno::EIO
37
+ # PTY closed — safe to ignore
38
+ end
39
+ rescue Errno::ENOENT => e
40
+ mutex.synchronize do
41
+ error = e
42
+ condition.signal
43
+ end
44
+ end
45
+
46
+ mutex.synchronize { condition.wait(mutex) until ready || error }
47
+
48
+ raise error if error
49
+ end
50
+
51
+ # Stop the tunnel process.
52
+ def stop
53
+ return if @pid.nil?
54
+
55
+ begin
56
+ Process.kill('TERM', @pid)
57
+ rescue Errno::ESRCH
58
+ # Process already exited — safe to ignore
59
+ end
60
+ @pid = nil
61
+
62
+ @thread&.join
63
+ end
64
+
65
+ def to_s
66
+ "#{@host}:#{@port}"
67
+ end
68
+
69
+ private
70
+
71
+ # Generate the AWS CLI command to open the tunnel.
72
+ def command
73
+ "aws ec2-instance-connect open-tunnel --instance-id #{@instance_id} --local-port #{@port}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SSHKit
4
+ module EC2InstanceConnect
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'securerandom'
5
+
6
+ require_relative 'ec2instanceconnect/timed_hash'
7
+ require_relative 'ec2instanceconnect/ssh_key'
8
+ require_relative 'ec2instanceconnect/tunnel'
9
+ require_relative 'ec2instanceconnect/backend'
10
+ require_relative 'ec2instanceconnect/version'
11
+
12
+ module SSHKit
13
+ # SSHKit backend that integrates with EC2 Instance Connect.
14
+ module EC2InstanceConnect
15
+ # :nodoc:
16
+ class Configuration
17
+ attr_accessor :logger, :ssh_key_refresh_enabled, :ssh_key_size, :tunnel_enabled, :tunnel_ports
18
+
19
+ def initialize
20
+ @logger = ::Logger.new(IO::NULL)
21
+ @ssh_key_refresh_enabled = true
22
+ @ssh_key_size = 3072
23
+ @tunnel_enabled = false
24
+ @tunnel_ports = 8000...8100
25
+ end
26
+
27
+ # Returns a secure random tunnel port.
28
+ def random_tunnel_port
29
+ random_number = SecureRandom.random_number(tunnel_ports.size)
30
+
31
+ case tunnel_ports
32
+ when Array
33
+ tunnel_ports[random_number]
34
+ when Range
35
+ tunnel_ports.begin + random_number
36
+ else
37
+ raise ArgumentError, 'tunnel_ports must be an Array or Range'
38
+ end
39
+ end
40
+ end
41
+
42
+ class << self
43
+ def config
44
+ @config ||= Configuration.new
45
+ end
46
+
47
+ def configure
48
+ yield(config)
49
+ end
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sshkit-ec2instanceconnect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kentaa
8
+ - iRaiser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2026-01-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws-sdk-ec2instanceconnect
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.63'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.63'
28
+ - !ruby/object:Gem::Dependency
29
+ name: concurrent-ruby
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.2'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: logger
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '13.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '13.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: sshkit
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.24'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '1.24'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.13'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3.13'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rubocop
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '1.78'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.78'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop-performance
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '1.25'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.25'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rubocop-rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '3.6'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '3.6'
140
+ - !ruby/object:Gem::Dependency
141
+ name: simplecov
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '0.22'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '0.22'
154
+ - !ruby/object:Gem::Dependency
155
+ name: webmock
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '3.26'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '3.26'
168
+ description:
169
+ email:
170
+ - tech-arnhem@iraiser.eu
171
+ executables: []
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - LICENSE.txt
176
+ - README.md
177
+ - lib/sshkit/ec2instanceconnect.rb
178
+ - lib/sshkit/ec2instanceconnect/backend.rb
179
+ - lib/sshkit/ec2instanceconnect/ssh_key.rb
180
+ - lib/sshkit/ec2instanceconnect/timed_hash.rb
181
+ - lib/sshkit/ec2instanceconnect/tunnel.rb
182
+ - lib/sshkit/ec2instanceconnect/version.rb
183
+ homepage: https://github.com/KentaaNL/sshkit-ec2instanceconnect
184
+ licenses:
185
+ - MIT
186
+ metadata:
187
+ rubygems_mfa_required: 'true'
188
+ post_install_message:
189
+ rdoc_options: []
190
+ require_paths:
191
+ - lib
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: 3.3.0
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ requirements: []
203
+ rubygems_version: 3.5.22
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: SSHKit backend that integrates with EC2 Instance Connect
207
+ test_files: []