vtk 0.8.0 → 0.9.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 +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +12 -0
- data/CHANGELOG.md +22 -4
- data/README.md +19 -0
- data/exe/vtk +1 -1
- data/lib/vtk/commands/socks.rb +18 -0
- data/lib/vtk/commands/socks/on.rb +1 -1
- data/lib/vtk/commands/socks/setup.rb +469 -0
- data/lib/vtk/templates/socks/setup/.gitkeep +1 -0
- data/lib/vtk/templates/socks/setup/gov.va.socks.plist.erb +35 -0
- data/lib/vtk/templates/socks/setup/va_gov_socks.service.erb +12 -0
- data/lib/vtk/version.rb +1 -1
- data/vtk.gemspec +2 -0
- metadata +35 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 469019fb5bc0695ac68a0deab5ff68305f62852cbe38207bbb199cfee99f805b
|
|
4
|
+
data.tar.gz: e81be7f9896a0f057bf4c0c5fb55e904ffecd1fbd56951a84ac8fe9d334e9e0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '01898cc5e93c4db7ff791b222f087d64f80730f20388ed35c8fdce2ad4adaec71e4fc417d515876baba10ddf64d38ac9978d1759e10e2418d44f71731f5b616f'
|
|
7
|
+
data.tar.gz: eddd67f1661dd3a0b7eefe49ab8e531ce1c3b26f4bd534cae9583dfee00c4cf721ae64179bbf42de31bf85c3b961b839c85700852401ef21eb8d54e37eb4afc7
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2021-07-29 22:40:06 UTC using RuboCop version 1.8.1.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: CountComments, CountAsOne.
|
|
11
|
+
Metrics/ClassLength:
|
|
12
|
+
Max: 351
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased](https://github.com/department-of-veterans-affairs/vtk/tree/HEAD)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.8.0...HEAD)
|
|
6
|
+
|
|
7
|
+
**Merged pull requests:**
|
|
8
|
+
|
|
9
|
+
- Command Analytics [\#8](https://github.com/department-of-veterans-affairs/vtk/pull/8) ([ericboehs](https://github.com/ericboehs))
|
|
10
|
+
|
|
11
|
+
## [v0.8.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.8.0) (2021-03-01)
|
|
12
|
+
|
|
13
|
+
[Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.7.0...v0.8.0)
|
|
14
|
+
|
|
15
|
+
**Merged pull requests:**
|
|
16
|
+
|
|
17
|
+
- Updating name [\#17](https://github.com/department-of-veterans-affairs/vtk/pull/17) ([alexpappasoddball](https://github.com/alexpappasoddball))
|
|
18
|
+
- Made changes to how the arguments are handled [\#15](https://github.com/department-of-veterans-affairs/vtk/pull/15) ([thilton-oddball](https://github.com/thilton-oddball))
|
|
19
|
+
|
|
20
|
+
## [v0.7.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.7.0) (2021-03-01)
|
|
21
|
+
|
|
22
|
+
[Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.5.0...v0.7.0)
|
|
23
|
+
|
|
3
24
|
## [v0.5.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.5.0) (2021-02-19)
|
|
4
25
|
|
|
5
26
|
[Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.4.0...v0.5.0)
|
|
@@ -59,6 +80,7 @@
|
|
|
59
80
|
**Merged pull requests:**
|
|
60
81
|
|
|
61
82
|
- fixing markdown in README … [\#3](https://github.com/department-of-veterans-affairs/vtk/pull/3) ([thilton-oddball](https://github.com/thilton-oddball))
|
|
83
|
+
- Open Jenkins [\#1](https://github.com/department-of-veterans-affairs/vtk/pull/1) ([cvalarida](https://github.com/cvalarida))
|
|
62
84
|
|
|
63
85
|
## [v0.1.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.1.0) (2021-01-04)
|
|
64
86
|
|
|
@@ -72,10 +94,6 @@
|
|
|
72
94
|
|
|
73
95
|
[Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/79143038509757799edb2bb9be2f925b7d985221...oclif)
|
|
74
96
|
|
|
75
|
-
**Merged pull requests:**
|
|
76
|
-
|
|
77
|
-
- Open Jenkins [\#1](https://github.com/department-of-veterans-affairs/vtk/pull/1) ([cvalarida](https://github.com/cvalarida))
|
|
78
|
-
|
|
79
97
|
|
|
80
98
|
|
|
81
99
|
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/README.md
CHANGED
|
@@ -35,6 +35,25 @@ This above command runs a custom rails generator. For more information see the [
|
|
|
35
35
|
|
|
36
36
|
Handles connecting to VA network via SOCKS.
|
|
37
37
|
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
$ vtk socks setup
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The **setup subcommand** will do the following:
|
|
45
|
+
- Download the recommended `.ssh/config` if missing.
|
|
46
|
+
- Generate a VA SSH key if missing (and opens the access request form).
|
|
47
|
+
- Add your VA SSH key to your ssh agent and keychain.
|
|
48
|
+
- Test the SOCKS tunnel via SSH and HTTP
|
|
49
|
+
- Configure your system to start the SOCKS tunnel on boot
|
|
50
|
+
- Configure your system proxy for use on VA.gov domains (all other traffic bypasses the proxy).
|
|
51
|
+
- Allow you to troubleshoot your SOCKS connection by running it again.
|
|
52
|
+
|
|
53
|
+
**NOTE**: Running `vtk socks on` and/or `vtk socks off` is not necessary when using `vtk socks setup`.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
38
57
|
```
|
|
39
58
|
$ vtk socks on
|
|
40
59
|
----> Connecting...
|
data/exe/vtk
CHANGED
data/lib/vtk/commands/socks.rb
CHANGED
|
@@ -8,6 +8,24 @@ module Vtk
|
|
|
8
8
|
class Socks < Thor
|
|
9
9
|
namespace :socks
|
|
10
10
|
|
|
11
|
+
desc 'setup', 'Configures local machine for VA SOCKS access'
|
|
12
|
+
method_option :help, aliases: '-h', type: :boolean,
|
|
13
|
+
desc: 'Display usage information'
|
|
14
|
+
method_option :boot_script_path, type: :string, desc: 'Path to install boot script (e.g. ~/Library)'
|
|
15
|
+
method_option :ssh_key_path, type: :string, desc: 'Path to SSH key (e.g. ~/.ssh/id_rsa_vagov)'
|
|
16
|
+
method_option :ssh_config_path, type: :string, desc: 'Path to SSH config (e.g. ~/.ssh/config)'
|
|
17
|
+
method_option :port, aliases: '-p', type: :string,
|
|
18
|
+
desc: 'Port that SOCKS server is running on'
|
|
19
|
+
method_option :skip_test, type: :boolean, desc: 'Skip testing SOCKS connection'
|
|
20
|
+
def setup(*)
|
|
21
|
+
if options[:help]
|
|
22
|
+
invoke :help, ['setup']
|
|
23
|
+
else
|
|
24
|
+
require_relative 'socks/setup'
|
|
25
|
+
Vtk::Commands::Socks::Setup.new(options).execute
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
11
29
|
desc 'off', 'Disconnects from VA SOCKS'
|
|
12
30
|
method_option :help, aliases: '-h', type: :boolean,
|
|
13
31
|
desc: 'Display usage information'
|
|
@@ -50,7 +50,7 @@ module Vtk
|
|
|
50
50
|
return output.puts "\r----> Connected to SOCKS."
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
output.puts "\r----> ERROR: Could not connect to SOCKS."
|
|
53
|
+
output.puts "\r----> ERROR: Could not connect to SOCKS. Try running `vtk socks setup` first."
|
|
54
54
|
output.puts "----> Verbose Output from SSH log:\n\n"
|
|
55
55
|
|
|
56
56
|
output.puts File.read '/tmp/socks.log'
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../command'
|
|
4
|
+
require 'tty-prompt'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'erb'
|
|
7
|
+
|
|
8
|
+
module Vtk
|
|
9
|
+
module Commands
|
|
10
|
+
class Socks
|
|
11
|
+
# Sets up socks access to the VA network
|
|
12
|
+
class Setup < Vtk::Command
|
|
13
|
+
PROXY_URL = 'https://raw.githubusercontent.com/department-of-veterans-affairs/va.gov-team/master/' \
|
|
14
|
+
'scripts/socks/proxy.pac'
|
|
15
|
+
|
|
16
|
+
attr_reader :ssh_config_path, :input, :output, :boot_script_path, :ssh_key_path, :prompt, :port, :skip_test
|
|
17
|
+
|
|
18
|
+
def initialize(options)
|
|
19
|
+
@options = options
|
|
20
|
+
@prompt = TTY::Prompt.new interrupt: :exit
|
|
21
|
+
@port = options['port'] || '2001'
|
|
22
|
+
@boot_script_path = options['boot_script_path'] || "#{ENV['HOME']}/Library"
|
|
23
|
+
@ssh_key_path = options['ssh_key_path'] || "#{ENV['HOME']}/.ssh/id_rsa_vagov"
|
|
24
|
+
@ssh_config_path = options['ssh_config_path'] || "#{ENV['HOME']}/.ssh/config"
|
|
25
|
+
@skip_test = options['skip_test'] || false
|
|
26
|
+
|
|
27
|
+
super()
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def execute(input: $stdin, output: $stdout)
|
|
31
|
+
@input = input
|
|
32
|
+
@output = output
|
|
33
|
+
|
|
34
|
+
setup_ssh_config
|
|
35
|
+
check_ssh_key
|
|
36
|
+
ssh_agent_add
|
|
37
|
+
|
|
38
|
+
test_ssh_connection unless skip_test
|
|
39
|
+
|
|
40
|
+
configure_system_boot
|
|
41
|
+
configure_system_proxy
|
|
42
|
+
|
|
43
|
+
test_http_connection unless skip_test
|
|
44
|
+
|
|
45
|
+
log 'SOCKS setup complete.'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def check_ssh_key
|
|
51
|
+
return true if key_exists?
|
|
52
|
+
|
|
53
|
+
generate_key_and_open_key_access_request
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def key_exists?
|
|
57
|
+
File.exist? ssh_key_path
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def public_key_exists?
|
|
61
|
+
File.exist? "#{ssh_key_path}.pub"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def generate_key_and_open_key_access_request
|
|
65
|
+
log 'VA key missing. Generating now...'
|
|
66
|
+
system "ssh-keygen -f #{ssh_key_path} #{'-N ""' if ENV['TEST']}"
|
|
67
|
+
|
|
68
|
+
if prompt.yes?(copy_and_open_gh)
|
|
69
|
+
copy_key_to_clipboard
|
|
70
|
+
`#{'xdg-' unless macos?}open "#{access_request_template_url}" 2> /dev/null`
|
|
71
|
+
else
|
|
72
|
+
log "You'll need to submit ~/.ssh/id_rsa_vagov.pub for approval to: #{access_request_template_url}."
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def copy_key_to_clipboard
|
|
77
|
+
ssh_key_contents = File.read "#{ssh_key_path}.pub"
|
|
78
|
+
|
|
79
|
+
if macos?
|
|
80
|
+
copy_command = 'pbcopy'
|
|
81
|
+
elsif ubuntu_like?
|
|
82
|
+
system 'sudo apt-get install -y xsel' if `which xsel`.empty?
|
|
83
|
+
copy_command = 'xsel --clipboard'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
IO.popen(copy_command, 'w') { |f| f << ssh_key_contents }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def access_request_template_url
|
|
90
|
+
'https://github.com/department-of-veterans-affairs/va.gov-team/issues/new?' \
|
|
91
|
+
'assignees=&labels=external-request%2C+operations&template=Environment-Access-Request-Template.md&' \
|
|
92
|
+
'title=Access+for+%5Bindividual%5D'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def copy_and_open_gh
|
|
96
|
+
'----> An SSH key has been created. Would you like to copy the key to your clipboard and open the access ' \
|
|
97
|
+
'request issue in GitHub now?'
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def setup_ssh_config
|
|
101
|
+
create_ssh_directory
|
|
102
|
+
install_ssh_config
|
|
103
|
+
configure_ssh_config_with_keychain
|
|
104
|
+
ssh_config_clean_up
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def install_ssh_config
|
|
108
|
+
return true if ssh_config_configured?
|
|
109
|
+
|
|
110
|
+
if ssh_config_exists? && !prompt.yes?("----> #{pretty_ssh_config_path} incomplete. Backup and replace now?")
|
|
111
|
+
return false
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
log 'Installing SSH config...'
|
|
115
|
+
|
|
116
|
+
download_ssh_config unless File.exist? '/tmp/dova-devops'
|
|
117
|
+
backup_existing_ssh_config
|
|
118
|
+
FileUtils.cp '/tmp/dova-devops/ssh/config', ssh_config_path
|
|
119
|
+
FileUtils.chmod 0o600, "#{File.dirname ssh_config_path}/config"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def ssh_config_configured?
|
|
123
|
+
return false unless ssh_config_exists?
|
|
124
|
+
|
|
125
|
+
download_ssh_config
|
|
126
|
+
ssh_config_local = File.read ssh_config_path
|
|
127
|
+
ssh_config = File.read '/tmp/dova-devops/ssh/config'
|
|
128
|
+
ssh_config_local.include? ssh_config
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def ssh_config_exists?
|
|
132
|
+
File.exist? ssh_config_path
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def download_ssh_config
|
|
136
|
+
install_git
|
|
137
|
+
|
|
138
|
+
ssh_config_clean_up
|
|
139
|
+
|
|
140
|
+
ssh_agent_add
|
|
141
|
+
cloned = system(
|
|
142
|
+
"git clone --quiet#{' --depth 1' if macos?} --no-checkout --filter=blob:none #{repo_url} '/tmp/dova-devops'"
|
|
143
|
+
)
|
|
144
|
+
exit 1 unless cloned
|
|
145
|
+
|
|
146
|
+
`cd /tmp/dova-devops; git checkout master -- ssh/config`
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def install_git
|
|
150
|
+
if macos?
|
|
151
|
+
install_brew
|
|
152
|
+
elsif ubuntu_like?
|
|
153
|
+
return true unless `which git`.empty?
|
|
154
|
+
|
|
155
|
+
system 'sudo apt-get install -y git'
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def install_brew
|
|
160
|
+
return false unless macos?
|
|
161
|
+
|
|
162
|
+
installed = !`which brew`.empty?
|
|
163
|
+
return true if installed
|
|
164
|
+
|
|
165
|
+
log 'Homebrew not installed. Installing now...'
|
|
166
|
+
system '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def ssh_config_clean_up
|
|
170
|
+
FileUtils.rm_rf '/tmp/dova-devops'
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def repo_url
|
|
174
|
+
@repo_url ||= begin
|
|
175
|
+
keyscan_github_com
|
|
176
|
+
|
|
177
|
+
if github_ssh_configured
|
|
178
|
+
'git@github.com:department-of-veterans-affairs/devops.git'
|
|
179
|
+
else
|
|
180
|
+
'https://github.com/department-of-veterans-affairs/devops.git'
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def keyscan_github_com
|
|
186
|
+
return true if File.exist?('~/.ssh/known_hosts') && !`ssh-keygen -F github.com`.empty?
|
|
187
|
+
|
|
188
|
+
`ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2> /dev/null`
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def github_ssh_configured
|
|
192
|
+
!`ssh -T git@github.com 2>&1`.include?('Permission denied')
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def backup_existing_ssh_config
|
|
196
|
+
return true unless ssh_config_exists?
|
|
197
|
+
|
|
198
|
+
if File.exist? "#{ssh_config_path}.bak"
|
|
199
|
+
log "!!! ERROR: Could not make backup of #{pretty_ssh_config_path} as #{pretty_ssh_config_path}.bak " \
|
|
200
|
+
'exists. Aborting.'
|
|
201
|
+
exit 1
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
FileUtils.mv ssh_config_path, "#{ssh_config_path}.bak"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def create_ssh_directory
|
|
208
|
+
ssh_dir = File.dirname ssh_config_path
|
|
209
|
+
FileUtils.mkdir_p ssh_dir
|
|
210
|
+
FileUtils.chmod 0o700, ssh_dir
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def configure_ssh_config_with_keychain
|
|
214
|
+
return unless macos?
|
|
215
|
+
return if ssh_config_configured_with_keychain?
|
|
216
|
+
|
|
217
|
+
keychain_config = <<~CFG
|
|
218
|
+
|
|
219
|
+
# Maintain SSH keys in macOS Keychain
|
|
220
|
+
Host *
|
|
221
|
+
UseKeychain yes
|
|
222
|
+
AddKeysToAgent yes
|
|
223
|
+
IdentityFile #{pretty_ssh_key_path}
|
|
224
|
+
CFG
|
|
225
|
+
|
|
226
|
+
IO.write ssh_config_path, keychain_config, mode: 'a'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def ssh_config_configured_with_keychain?
|
|
230
|
+
return false unless ssh_config_exists?
|
|
231
|
+
|
|
232
|
+
ssh_config_local = File.readlines ssh_config_path
|
|
233
|
+
ssh_config_local.grep(/UseKeychain yes/).size.positive?
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def ssh_agent_add
|
|
237
|
+
FileUtils.chmod 0o600, ssh_key_path if key_exists?
|
|
238
|
+
FileUtils.chmod 0o600, "#{ssh_key_path}.pub" if public_key_exists?
|
|
239
|
+
|
|
240
|
+
if macos?
|
|
241
|
+
`ssh-add -AK 2> /dev/null; ssh-add -AK #{ssh_key_path} 2> /dev/null`
|
|
242
|
+
elsif ubuntu_like?
|
|
243
|
+
`[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)";
|
|
244
|
+
ssh-add 2> /dev/null; ssh-add #{ssh_key_path} 2> /dev/null`
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def test_ssh_connection
|
|
249
|
+
output.print '----> Testing SOCKS SSH connection...'
|
|
250
|
+
|
|
251
|
+
add_ip_to_known_hosts
|
|
252
|
+
|
|
253
|
+
ssh_output = `ssh -i #{ssh_key_path} -F #{ssh_config_path} -o ConnectTimeout=5 -q socks -D #{port} exit 2>&1`
|
|
254
|
+
|
|
255
|
+
if ssh_output.include? 'This account is currently not available.'
|
|
256
|
+
output.puts ' ✅'
|
|
257
|
+
else
|
|
258
|
+
check_ssh_error ssh_output
|
|
259
|
+
exit 1
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def add_ip_to_known_hosts
|
|
264
|
+
jump_box_ip = `grep -A 2 'Host socks' ~/.ssh/config | grep ProxyCommand | awk '{print $6}'`.chomp
|
|
265
|
+
socks_ip = `grep -A 2 'Host socks' ~/.ssh/config | grep HostName | awk '{print $2}'`.chomp
|
|
266
|
+
|
|
267
|
+
return unless `ssh-keygen -F #{socks_ip}`.empty?
|
|
268
|
+
|
|
269
|
+
`ssh-keyscan -H #{jump_box_ip} >> ~/.ssh/known_hosts 2> /dev/null`
|
|
270
|
+
`ssh -i #{ssh_key_path} dsva@#{jump_box_ip} 'ssh-keyscan -H #{socks_ip}' >> ~/.ssh/known_hosts 2> /dev/null`
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def check_ssh_error(ssh_output)
|
|
274
|
+
if ssh_output.include? 'Permission denied (publickey)'
|
|
275
|
+
@skip_test = true
|
|
276
|
+
output.puts '⚠️ WARN: SSH key is not approved yet. Once it is, re-run `vtk socks setup`.'
|
|
277
|
+
else
|
|
278
|
+
ssh_command = "ssh -i #{ssh_key_path} -F #{ssh_config_path} -o ConnectTimeout=5 -vvv socks -D #{port} -N"
|
|
279
|
+
output.puts ' ❌ ERROR: SSH Connection to SOCKS server unsuccessful. Error message:'
|
|
280
|
+
output.puts ssh_command
|
|
281
|
+
output.puts `#{ssh_command}`
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def configure_system_boot
|
|
286
|
+
log 'Configuring SOCKS tunnel to run on system boot...' do
|
|
287
|
+
install_autossh && (install_launch_agent || install_systemd_service)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def launch_agent_label
|
|
292
|
+
@launch_agent_label ||= begin
|
|
293
|
+
launch_agent_label = 'gov.va.socks'
|
|
294
|
+
launch_agent_label += "-test-#{rand 1000}" if ENV['TEST'] == 'test'
|
|
295
|
+
launch_agent_label
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def install_autossh
|
|
300
|
+
installed = !`which autossh`.empty?
|
|
301
|
+
return true if installed
|
|
302
|
+
|
|
303
|
+
if macos?
|
|
304
|
+
system 'brew install autossh'
|
|
305
|
+
elsif ubuntu_like?
|
|
306
|
+
system 'sudo apt-get install -y autossh'
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def install_launch_agent
|
|
311
|
+
return false unless macos?
|
|
312
|
+
|
|
313
|
+
unless File.exist? "#{boot_script_path}/LaunchAgents/gov.va.socks.plist"
|
|
314
|
+
FileUtils.mkdir_p "#{boot_script_path}/Logs/gov.va.socks"
|
|
315
|
+
FileUtils.mkdir_p "#{boot_script_path}/LaunchAgents"
|
|
316
|
+
|
|
317
|
+
write_launch_agent
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
system "launchctl unload #{boot_script_path}/LaunchAgents/gov.va.socks.plist 2> /dev/null"
|
|
321
|
+
system "launchctl load -w #{boot_script_path}/LaunchAgents/gov.va.socks.plist"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def write_launch_agent
|
|
325
|
+
erb_template = File.read File.realpath "#{__dir__}/../../templates/socks/setup/gov.va.socks.plist.erb"
|
|
326
|
+
erb = ERB.new erb_template
|
|
327
|
+
launch_agent_contents = erb.result(
|
|
328
|
+
launch_agent_variables.instance_eval { binding }
|
|
329
|
+
)
|
|
330
|
+
File.write "#{boot_script_path}/LaunchAgents/gov.va.socks.plist", launch_agent_contents
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def launch_agent_variables
|
|
334
|
+
OpenStruct.new(
|
|
335
|
+
label: launch_agent_label,
|
|
336
|
+
autossh_path: `which autossh`.chomp,
|
|
337
|
+
port: @port,
|
|
338
|
+
boot_script_path: File.realpath(boot_script_path),
|
|
339
|
+
user: ENV['USER']
|
|
340
|
+
)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def install_systemd_service
|
|
344
|
+
return false unless ubuntu_like?
|
|
345
|
+
|
|
346
|
+
write_systemd_service unless File.exist? '/etc/systemd/system/va_gov_socks.service'
|
|
347
|
+
|
|
348
|
+
system 'sudo systemctl daemon-reload'
|
|
349
|
+
system 'sudo systemctl enable va_gov_socks'
|
|
350
|
+
system 'sudo systemctl start va_gov_socks'
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def write_systemd_service
|
|
354
|
+
erb_template = File.read File.realpath "#{__dir__}/../../templates/socks/setup/va_gov_socks.service.erb"
|
|
355
|
+
erb = ERB.new erb_template
|
|
356
|
+
systemd_service_contents = erb.result(
|
|
357
|
+
systemd_service_variables.instance_eval { binding }
|
|
358
|
+
)
|
|
359
|
+
File.write '/tmp/va_gov_socks.service', systemd_service_contents
|
|
360
|
+
system 'sudo mv /tmp/va_gov_socks.service /etc/systemd/system/va_gov_socks.service'
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def systemd_service_variables
|
|
364
|
+
OpenStruct.new(
|
|
365
|
+
autossh_path: `which autossh`.chomp,
|
|
366
|
+
port: @port,
|
|
367
|
+
ssh_key_path: ssh_key_path,
|
|
368
|
+
user: ENV['USER']
|
|
369
|
+
)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def configure_system_proxy
|
|
373
|
+
return log 'Skipping system proxy configuration as custom --port was used.' unless port == '2001'
|
|
374
|
+
|
|
375
|
+
if macos?
|
|
376
|
+
mac_configure_system_proxy
|
|
377
|
+
elsif ubuntu_like?
|
|
378
|
+
ubuntu_configure_system_proxy
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def mac_configure_system_proxy
|
|
383
|
+
return true if mac_system_proxy_already_configured?
|
|
384
|
+
|
|
385
|
+
log 'Configuring system proxy to use SOCKS tunnel...' do
|
|
386
|
+
network_interfaces.map do |network_interface|
|
|
387
|
+
system %(networksetup -setautoproxyurl "#{network_interface}" "#{PROXY_URL}")
|
|
388
|
+
end.all?
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def ubuntu_configure_system_proxy
|
|
393
|
+
return true if `gsettings get org.gnome.system.proxy mode` == "'auto'\n"
|
|
394
|
+
|
|
395
|
+
log 'Configuring system proxy to use SOCKS tunnel...' do
|
|
396
|
+
`gsettings set org.gnome.system.proxy mode 'auto'` &&
|
|
397
|
+
`gsettings set org.gnome.system.proxy autoconfig-url "#{PROXY_URL}"`
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def mac_system_proxy_already_configured?
|
|
402
|
+
network_interfaces.map do |network_interface|
|
|
403
|
+
output = `networksetup -getautoproxyurl "#{network_interface}"`
|
|
404
|
+
output == "URL: #{PROXY_URL}\nEnabled: Yes\n"
|
|
405
|
+
end.all?
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def network_interfaces
|
|
409
|
+
@network_interfaces ||= begin
|
|
410
|
+
`networksetup -listallnetworkservices`.split("\n").drop(1).select do |network_interface|
|
|
411
|
+
`networksetup -getautoproxyurl "#{network_interface}"`.start_with?('URL: (null)')
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def test_http_connection
|
|
417
|
+
output.print '----> Testing SOCKS HTTP connection...'
|
|
418
|
+
|
|
419
|
+
success = 5.times.map do
|
|
420
|
+
sleep 1
|
|
421
|
+
not_connected = system "nscurl http://grafana.vfs.va.gov 2>&1 | grep -q 'hostname could not be found'"
|
|
422
|
+
|
|
423
|
+
break [true] unless not_connected
|
|
424
|
+
end.all?
|
|
425
|
+
|
|
426
|
+
output.puts success ? ' ✅' : ' ❌ ERROR: SOCKS connection failed HTTP test. Try running setup again.'
|
|
427
|
+
|
|
428
|
+
exit 1 unless success
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def macos?
|
|
432
|
+
RUBY_PLATFORM.include? 'darwin'
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def ubuntu_like?
|
|
436
|
+
return false if `which apt-get`.empty? && `which gsettings`.empty?
|
|
437
|
+
|
|
438
|
+
true
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def pretty_ssh_config_path
|
|
442
|
+
pretty_path ssh_config_path
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def pretty_ssh_key_path
|
|
446
|
+
pretty_path ssh_key_path
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def pretty_path(path)
|
|
450
|
+
path.gsub ENV['HOME'], '~'
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def log(message)
|
|
454
|
+
if block_given?
|
|
455
|
+
output.print "----> #{message}"
|
|
456
|
+
|
|
457
|
+
return_value = yield
|
|
458
|
+
|
|
459
|
+
output.puts return_value ? ' ✅' : ' ❌'
|
|
460
|
+
|
|
461
|
+
return_value
|
|
462
|
+
else
|
|
463
|
+
output.puts "----> #{message}"
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string><%= label %></string>
|
|
7
|
+
|
|
8
|
+
<key>RunAtLoad</key>
|
|
9
|
+
<true/>
|
|
10
|
+
|
|
11
|
+
<key>ProgramArguments</key>
|
|
12
|
+
<array>
|
|
13
|
+
<string><%= autossh_path %></string>
|
|
14
|
+
<string>-v</string>
|
|
15
|
+
<string>-M</string>
|
|
16
|
+
<string>0</string>
|
|
17
|
+
<string>-D</string>
|
|
18
|
+
<string><%= port %></string>
|
|
19
|
+
<string>socks</string>
|
|
20
|
+
<string>-N</string>
|
|
21
|
+
</array>
|
|
22
|
+
|
|
23
|
+
<key>StandardOutPath</key>
|
|
24
|
+
<string><%= boot_script_path %>/Logs/gov.va.socks/autossh.stdout</string>
|
|
25
|
+
|
|
26
|
+
<key>StandardErrorPath</key>
|
|
27
|
+
<string><%= boot_script_path %>/Logs/gov.va.socks/autossh.stderr</string>
|
|
28
|
+
|
|
29
|
+
<key>User</key>
|
|
30
|
+
<string><%= user %></string>
|
|
31
|
+
|
|
32
|
+
<key>ThrottleInterval</key>
|
|
33
|
+
<integer>30</integer>
|
|
34
|
+
</dict>
|
|
35
|
+
</plist>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=VA SOCKS Tunnel
|
|
3
|
+
After=network.target
|
|
4
|
+
|
|
5
|
+
[Service]
|
|
6
|
+
Environment="AUTOSSH_GATETIME=0"
|
|
7
|
+
ExecStart=<%= autossh_path %> -v -M 0 -D <%= port %> -i <%= ssh_key_path %> socks -N
|
|
8
|
+
Restart=always
|
|
9
|
+
User=<%= user %>
|
|
10
|
+
|
|
11
|
+
[Install]
|
|
12
|
+
WantedBy=multi-user.target
|
data/lib/vtk/version.rb
CHANGED
data/vtk.gemspec
CHANGED
|
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.require_paths = ['lib']
|
|
30
30
|
|
|
31
31
|
spec.add_dependency 'thor', '> 0.20.3'
|
|
32
|
+
spec.add_dependency 'tty-command', '~> 0.10.0'
|
|
33
|
+
spec.add_dependency 'tty-prompt', '~> 0.23.0'
|
|
32
34
|
|
|
33
35
|
spec.add_development_dependency 'github_changelog_generator', '~> 1.15.0'
|
|
34
36
|
spec.add_development_dependency 'pry', '~> 0.13.0'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vtk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Boehs
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: exe
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2021-
|
|
13
|
+
date: 2021-08-02 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: thor
|
|
@@ -26,6 +26,34 @@ dependencies:
|
|
|
26
26
|
- - ">"
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
28
|
version: 0.20.3
|
|
29
|
+
- !ruby/object:Gem::Dependency
|
|
30
|
+
name: tty-command
|
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
|
32
|
+
requirements:
|
|
33
|
+
- - "~>"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: 0.10.0
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - "~>"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: 0.10.0
|
|
43
|
+
- !ruby/object:Gem::Dependency
|
|
44
|
+
name: tty-prompt
|
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - "~>"
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 0.23.0
|
|
50
|
+
type: :runtime
|
|
51
|
+
prerelease: false
|
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - "~>"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 0.23.0
|
|
29
57
|
- !ruby/object:Gem::Dependency
|
|
30
58
|
name: github_changelog_generator
|
|
31
59
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -139,6 +167,7 @@ files:
|
|
|
139
167
|
- ".gitignore"
|
|
140
168
|
- ".rspec"
|
|
141
169
|
- ".rubocop.yml"
|
|
170
|
+
- ".rubocop_todo.yml"
|
|
142
171
|
- ".tool-versions"
|
|
143
172
|
- CHANGELOG.md
|
|
144
173
|
- Gemfile
|
|
@@ -163,8 +192,12 @@ files:
|
|
|
163
192
|
- lib/vtk/commands/socks.rb
|
|
164
193
|
- lib/vtk/commands/socks/off.rb
|
|
165
194
|
- lib/vtk/commands/socks/on.rb
|
|
195
|
+
- lib/vtk/commands/socks/setup.rb
|
|
166
196
|
- lib/vtk/templates/.gitkeep
|
|
167
197
|
- lib/vtk/templates/module/add/.gitkeep
|
|
198
|
+
- lib/vtk/templates/socks/setup/.gitkeep
|
|
199
|
+
- lib/vtk/templates/socks/setup/gov.va.socks.plist.erb
|
|
200
|
+
- lib/vtk/templates/socks/setup/va_gov_socks.service.erb
|
|
168
201
|
- lib/vtk/version.rb
|
|
169
202
|
- vtk.gemspec
|
|
170
203
|
homepage: https://github.com/department-of-veterans-affairs/vtk
|