arver 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.textile +4 -0
- data/lib/arver/cli.rb +3 -0
- data/lib/arver/command_wrapper.rb +6 -3
- data/lib/arver/host.rb +11 -1
- data/lib/arver/ssh_command_wrapper.rb +16 -7
- data/lib/arver/systemd_open_action.rb +83 -0
- data/lib/arver/version.rb +1 -1
- data/lib/arver.rb +2 -1
- data/man/arver.5 +21 -1
- data/vendor/password-agent +0 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eeb29f1cdc8ba4b8fd5a05791fe282f1a016440253f0b3591c95e30f573343f5
|
4
|
+
data.tar.gz: d41505b368abe1d3aa20c3fdf0ed13c3e382aadeb18e9b000778f156279dce0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f63236b680841a83333b3fce1c6a6c379e0a35820554f016821f1aff3998011c844655a883cd5f0514481b20618490aec95d005f320cfa57472b9f95585c73ff
|
7
|
+
data.tar.gz: 5734e53e093a97465751ae5e9cd95cee18f9565337ea94208f7eea9448c7a32f79b53aa1f92a8e82f0ac4a88127ca13fd91ca6e9838f5b7aaa284a4b05ea8e91
|
data/CHANGELOG.textile
CHANGED
data/lib/arver/cli.rb
CHANGED
@@ -59,6 +59,8 @@ module Arver
|
|
59
59
|
opts.separator "Actions:"
|
60
60
|
opts.on_tail( "-o TARGET", "--open TARGET", String,
|
61
61
|
"Open target." ) { |arg| options[:argument][:target] = arg; options[:action] = :open; }
|
62
|
+
opts.on_tail( "--systemd-open TARGET", String,
|
63
|
+
"Open target during boot via systemd-asskpasswd." ) { |arg| options[:argument][:target] = arg; options[:action] = :systemd_open; }
|
62
64
|
opts.on_tail( "-c TARGET", "--close TARGET", String,
|
63
65
|
"Close target." ) { |arg| options[:argument][:target] = arg; options[:action] = :close; }
|
64
66
|
opts.on_tail( "--create TARGET", String,
|
@@ -118,6 +120,7 @@ module Arver
|
|
118
120
|
:gc => Arver::GCAction,
|
119
121
|
:create => Arver::CreateAction,
|
120
122
|
:open => Arver::OpenAction,
|
123
|
+
:systemd_open => Arver::SystemdOpenAction,
|
121
124
|
:close => Arver::CloseAction,
|
122
125
|
:adduser => Arver::AdduserAction,
|
123
126
|
:deluser => Arver::DeluserAction,
|
@@ -1,8 +1,7 @@
|
|
1
1
|
module Arver
|
2
2
|
class CommandWrapper
|
3
|
-
|
4
3
|
attr_accessor :command, :arguments_array, :return_value, :output
|
5
|
-
|
4
|
+
|
6
5
|
def self.create( cmd, args = [] )
|
7
6
|
c = CommandWrapper.new
|
8
7
|
c.command= cmd
|
@@ -10,8 +9,12 @@ module Arver
|
|
10
9
|
c
|
11
10
|
end
|
12
11
|
|
13
|
-
# copy from shellwords.rb
|
14
12
|
def shellescape(str)
|
13
|
+
CommandWrapper.shellescape(str)
|
14
|
+
end
|
15
|
+
|
16
|
+
# copy from shellwords.rb
|
17
|
+
def self.shellescape(str)
|
15
18
|
str = str.to_s
|
16
19
|
|
17
20
|
# An empty argument will be skipped, so return empty quotes.
|
data/lib/arver/host.rb
CHANGED
@@ -2,7 +2,7 @@ module Arver
|
|
2
2
|
class Host
|
3
3
|
|
4
4
|
attr_accessor :port, :username
|
5
|
-
attr_writer :address
|
5
|
+
attr_writer :address, :boot_address
|
6
6
|
|
7
7
|
include Arver::PartitionHierarchyNode
|
8
8
|
include Arver::NodeWithScriptHooks
|
@@ -25,6 +25,11 @@ module Arver
|
|
25
25
|
self.name
|
26
26
|
end
|
27
27
|
|
28
|
+
def boot_address
|
29
|
+
return @boot_address unless @boot_address.nil?
|
30
|
+
address
|
31
|
+
end
|
32
|
+
|
28
33
|
def port
|
29
34
|
return @port unless @port.nil?
|
30
35
|
'22'
|
@@ -44,6 +49,7 @@ module Arver
|
|
44
49
|
def to_yaml
|
45
50
|
yaml = ""
|
46
51
|
yaml += "'address': '"+@address+"'\n" unless @address.nil?
|
52
|
+
yaml += "'boot_address': '"+@boot_address+"'\n" unless @boot_address.nil?
|
47
53
|
yaml += "'port': '"+@port+"'\n" unless @port.nil?
|
48
54
|
yaml += "'username': '"+@username+"'\n" unless @username.nil?
|
49
55
|
yaml += script_hooks_to_yaml
|
@@ -61,6 +67,10 @@ module Arver
|
|
61
67
|
self.address = data
|
62
68
|
next
|
63
69
|
end
|
70
|
+
if( name == "boot_address" )
|
71
|
+
self.boot_address = data
|
72
|
+
next
|
73
|
+
end
|
64
74
|
if( name == "username" )
|
65
75
|
self.username= data
|
66
76
|
next
|
@@ -1,20 +1,29 @@
|
|
1
1
|
module Arver
|
2
2
|
class SSHCommandWrapper < CommandWrapper
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def self.create( cmd, args, host, as_root = false )
|
3
|
+
attr_accessor :host, :user, :port, :as_root, :on_boot
|
4
|
+
|
5
|
+
def self.create( cmd, args, host, as_root = false, on_boot = false)
|
7
6
|
c = SSHCommandWrapper.new
|
8
7
|
c.host= host
|
9
8
|
c.as_root= as_root
|
10
9
|
c.command= cmd
|
11
10
|
c.arguments_array= args
|
11
|
+
c.on_boot = on_boot
|
12
12
|
c
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def escaped_command
|
16
|
-
|
17
|
-
|
16
|
+
addr = (on_boot ? host.boot_address : nil) || host.address
|
17
|
+
user = on_boot ? 'root' : host.username
|
18
|
+
port = on_boot ? '22' : host.port
|
19
|
+
sudo = if as_root && on_boot && host.username != "root" then "sudo" else "" end
|
20
|
+
"ssh -p #{shellescape(port)} #{shellescape(user)}@#{shellescape(addr)} #{sudo} #{super}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.is_system_running?(partition)
|
24
|
+
wr = Arver::SSHCommandWrapper.create("systemctl", ["is-system-running"], partition.parent, true, true)
|
25
|
+
wr.execute
|
26
|
+
wr.success? && !['initializing','starting'].include?(wr.output.chomp)
|
18
27
|
end
|
19
28
|
end
|
20
29
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
module Arver
|
4
|
+
class SystemdOpenAction < Action
|
5
|
+
def initialize( target_list )
|
6
|
+
super( target_list )
|
7
|
+
self.open_keystore
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify?( partition )
|
11
|
+
if(Arver::SSHCommandWrapper.is_system_running?(partition))
|
12
|
+
Arver::Log.error( "#{partition.parent.name} already up. Use normal open, skipping." )
|
13
|
+
return false
|
14
|
+
end
|
15
|
+
return false unless load_key( partition )
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_socket(host, partid)
|
20
|
+
# Check which partitions are waiting for a password
|
21
|
+
# see https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents/
|
22
|
+
files_exec = Arver::SSHCommandWrapper.create("ls", ["/run/systemd/ask-password/ask.*"], host, true, true)
|
23
|
+
files_exec.execute
|
24
|
+
files = files_exec.output.split("\n")
|
25
|
+
|
26
|
+
# Find the socket for the partition we want to open
|
27
|
+
files.each do |f|
|
28
|
+
f_exec = Arver::SSHCommandWrapper.create("cat", [f], host, true, true)
|
29
|
+
f_exec.execute
|
30
|
+
ask_file = f_exec.output
|
31
|
+
if ask_file =~ /#{partid}/
|
32
|
+
ask_file =~ /Socket=(.*)/
|
33
|
+
return $1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute_partition( partition )
|
40
|
+
Arver::Log.info( "opening: "+partition.path )
|
41
|
+
socket = nil
|
42
|
+
partid = nil
|
43
|
+
host = partition.parent
|
44
|
+
|
45
|
+
# Find the uuid of this partition
|
46
|
+
partid_exec = Arver::SSHCommandWrapper.create("blkid", ["/dev/#{partition.device}"], host, true, true)
|
47
|
+
partid_exec.execute
|
48
|
+
partid = partid_exec.output.chomp.gsub(/.* UUID=\"([^"]+)\" .*/,'\1')
|
49
|
+
unless partid =~ /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
|
50
|
+
puts "Could not get uuid of disk"
|
51
|
+
throw( :abort_action )
|
52
|
+
end
|
53
|
+
|
54
|
+
socket = get_socket(host, partid)
|
55
|
+
if socket.nil?
|
56
|
+
puts "Disk is not waiting to be opened"
|
57
|
+
throw( :abort_action )
|
58
|
+
end
|
59
|
+
|
60
|
+
# Upload password-agent binary and supply password to the correct socket
|
61
|
+
binary = File.join(ROOT_DIR, "vendor", "password-agent")
|
62
|
+
unless File.exists?(binary)
|
63
|
+
puts "This gem is missing the native password-agent binary"
|
64
|
+
throw( :abort_action )
|
65
|
+
end
|
66
|
+
# This is an epic hack to have a binary with exec permission
|
67
|
+
# initrd does not have chmod, so we copy an existing binary and override it
|
68
|
+
r = Arver::SSHCommandWrapper.create("cp", ["/bin/true", "/run/password-agent"], host, true, true).execute
|
69
|
+
r = Arver::SSHCommandWrapper.create("cat", ["- > /run/password-agent"], host, true, true)
|
70
|
+
r.execute(File.read(binary))
|
71
|
+
unless r.success?
|
72
|
+
puts "Could not upload password-agent"
|
73
|
+
throw( :abort_action )
|
74
|
+
end
|
75
|
+
|
76
|
+
# Pass password
|
77
|
+
a = Arver::SSHCommandWrapper.create("/run/password-agent", [socket], host, true, true)
|
78
|
+
a.execute(key)
|
79
|
+
|
80
|
+
# Cannot check if it worked, since if it did, the server rebooted
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/arver/version.rb
CHANGED
data/lib/arver.rb
CHANGED
@@ -2,5 +2,6 @@
|
|
2
2
|
$:.unshift(File.dirname(__FILE__)) unless
|
3
3
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
4
4
|
|
5
|
-
%w{ gpg_key_manager luks_wrapper action initial_config_action refresh_action create_action list_action gc_action adduser_action deluser_action info_action close_action open_action target_list command_wrapper ssh_command_wrapper log_levels io_logger log string bootstrap local_config config test_config_loader node_with_script_hooks partition_hierarchy_node host hostgroup tree partition test_partition key_generator key_saver keystore runtime_config key_info_action dump_key_action }.each {|f| require "arver/#{f}" }
|
5
|
+
%w{ gpg_key_manager luks_wrapper action initial_config_action refresh_action create_action list_action gc_action adduser_action deluser_action info_action close_action open_action systemd_open_action target_list command_wrapper ssh_command_wrapper log_levels io_logger log string bootstrap local_config config test_config_loader node_with_script_hooks partition_hierarchy_node host hostgroup tree partition test_partition key_generator key_saver keystore runtime_config key_info_action dump_key_action }.each {|f| require "arver/#{f}" }
|
6
6
|
|
7
|
+
ROOT_DIR = File.expand_path('../..',__FILE__)
|
data/man/arver.5
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
.\" generated with Ronn/v0.7.3
|
2
2
|
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
3
3
|
.
|
4
|
-
.TH "ARVER" "5" "
|
4
|
+
.TH "ARVER" "5" "January 2022" "" ""
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBarver\fR \- LUKS on the loose
|
@@ -46,6 +46,10 @@ Creates LUKS partitions for \fBarver\fR on all targeted disks\.
|
|
46
46
|
Opens all targeted disks\.
|
47
47
|
.
|
48
48
|
.TP
|
49
|
+
\fB\-\-systemd\-open TARGET\fR
|
50
|
+
Same as above, but supplying password to systemd ask\-password, used during system startup\.
|
51
|
+
.
|
52
|
+
.TP
|
49
53
|
\fB\-\-close TARGET\fR
|
50
54
|
Closes all targeted disks\.
|
51
55
|
.
|
@@ -327,6 +331,22 @@ Those scripts have to be present at the actual host\.
|
|
327
331
|
.P
|
328
332
|
If you don\'t have a key for any of the disks that you wish to open it will be skipped (along with its script hooks)\.
|
329
333
|
.
|
334
|
+
.P
|
335
|
+
Arver can also open a disk that is waiting for a password by systemd\-ask\-password\. Typically this is happening during startup of a physical system, e\.g\., within the initrd\. For that there is a special mode called:
|
336
|
+
.
|
337
|
+
.IP "" 4
|
338
|
+
.
|
339
|
+
.nf
|
340
|
+
|
341
|
+
$ arver \-\-systemd\-open TARGET
|
342
|
+
.
|
343
|
+
.fi
|
344
|
+
.
|
345
|
+
.IP "" 0
|
346
|
+
.
|
347
|
+
.P
|
348
|
+
Note, due to the provided api by systemd, there is unfortunately no indication if the command suceeded\. Typically unlocking the last pending disk automatically continues booting the server\. In case the inird ssh has a differen hostname or address than the acutal system, there is an optional \fBboot_address\fR config in the disks configuration, to override the default one\. This mode expects ssh to be on port 22 and user root\.
|
349
|
+
.
|
330
350
|
.SH "Action Close"
|
331
351
|
Closing luks devices is simply done by invoking
|
332
352
|
.
|
Binary file
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- o
|
8
8
|
- andreas
|
9
9
|
- mh
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2022-01-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gpgme
|
@@ -128,16 +128,18 @@ files:
|
|
128
128
|
- lib/arver/runtime_config.rb
|
129
129
|
- lib/arver/ssh_command_wrapper.rb
|
130
130
|
- lib/arver/string.rb
|
131
|
+
- lib/arver/systemd_open_action.rb
|
131
132
|
- lib/arver/target_list.rb
|
132
133
|
- lib/arver/test_config_loader.rb
|
133
134
|
- lib/arver/test_partition.rb
|
134
135
|
- lib/arver/tree.rb
|
135
136
|
- lib/arver/version.rb
|
136
137
|
- man/arver.5
|
138
|
+
- vendor/password-agent
|
137
139
|
homepage: https://code.immerda.ch/immerda/apps/arver
|
138
140
|
licenses: []
|
139
141
|
metadata: {}
|
140
|
-
post_install_message:
|
142
|
+
post_install_message:
|
141
143
|
rdoc_options: []
|
142
144
|
require_paths:
|
143
145
|
- lib
|
@@ -152,8 +154,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
154
|
- !ruby/object:Gem::Version
|
153
155
|
version: 1.3.6
|
154
156
|
requirements: []
|
155
|
-
rubygems_version: 3.
|
156
|
-
signing_key:
|
157
|
+
rubygems_version: 3.1.2
|
158
|
+
signing_key:
|
157
159
|
specification_version: 4
|
158
160
|
summary: LUKS for groups
|
159
161
|
test_files: []
|