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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +105 -0
- data/lib/sshkit/ec2instanceconnect/backend.rb +132 -0
- data/lib/sshkit/ec2instanceconnect/ssh_key.rb +26 -0
- data/lib/sshkit/ec2instanceconnect/timed_hash.rb +42 -0
- data/lib/sshkit/ec2instanceconnect/tunnel.rb +77 -0
- data/lib/sshkit/ec2instanceconnect/version.rb +7 -0
- data/lib/sshkit/ec2instanceconnect.rb +52 -0
- metadata +207 -0
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
|
+
[](https://badge.fury.io/rb/sshkit-ec2instanceconnect)
|
|
4
|
+
[](https://github.com/KentaaNL/sshkit-ec2instanceconnect/actions)
|
|
5
|
+
[](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,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: []
|