arver 0.1.5 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.textile +8 -0
- data/README.textile +4 -1
- data/lib/arver/action.rb +5 -1
- data/lib/arver/bootstrap.rb +2 -1
- data/lib/arver/cli.rb +8 -0
- data/lib/arver/command_wrapper.rb +6 -3
- data/lib/arver/config.rb +19 -7
- data/lib/arver/dump_key_action.rb +29 -0
- data/lib/arver/host.rb +22 -6
- data/lib/arver/info_action.rb +38 -6
- data/lib/arver/key_generator.rb +3 -1
- data/lib/arver/key_saver.rb +6 -3
- data/lib/arver/keystore.rb +10 -6
- data/lib/arver/partition_hierarchy_node.rb +1 -3
- data/lib/arver/runtime_config.rb +1 -1
- data/lib/arver/ssh_command_wrapper.rb +16 -7
- data/lib/arver/systemd_open_action.rb +83 -0
- data/lib/arver/test_config_loader.rb +1 -0
- data/lib/arver/version.rb +1 -1
- data/lib/arver.rb +3 -2
- data/man/arver.5 +65 -5
- data/vendor/password-agent +0 -0
- metadata +31 -60
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eeb29f1cdc8ba4b8fd5a05791fe282f1a016440253f0b3591c95e30f573343f5
|
4
|
+
data.tar.gz: d41505b368abe1d3aa20c3fdf0ed13c3e382aadeb18e9b000778f156279dce0d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f63236b680841a83333b3fce1c6a6c379e0a35820554f016821f1aff3998011c844655a883cd5f0514481b20618490aec95d005f320cfa57472b9f95585c73ff
|
7
|
+
data.tar.gz: 5734e53e093a97465751ae5e9cd95cee18f9565337ea94208f7eea9448c7a32f79b53aa1f92a8e82f0ac4a88127ca13fd91ca6e9838f5b7aaa284a4b05ea8e91
|
data/CHANGELOG.textile
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.1.9 2022-01-29
|
2
|
+
|
3
|
+
* Add a new --open-systemd to support opening disks at startup. This mode is compatible with systemd-ask-password which is used to open disks in the initrd.
|
4
|
+
|
5
|
+
=== 0.1.7 2018-09-01
|
6
|
+
|
7
|
+
* Updated gems to work with 2.5.1
|
8
|
+
|
1
9
|
=== 0.1.4 2012-07-24
|
2
10
|
|
3
11
|
* Introducing the --refresh action to renew the luks key. You should always run this command, when receiving a new permission.
|
data/README.textile
CHANGED
@@ -46,7 +46,6 @@ contains an arver package we recommend installation by your package manager.
|
|
46
46
|
The following ruby gems are required for arver:
|
47
47
|
|
48
48
|
* gpgme 2
|
49
|
-
* activesupport 2
|
50
49
|
* escape
|
51
50
|
* highline
|
52
51
|
|
@@ -68,6 +67,10 @@ h1. Limitations
|
|
68
67
|
|
69
68
|
h2. Known Issues
|
70
69
|
|
70
|
+
It is strongly advised not to set any 'encrypt-to' option in your gnupgp.conf.
|
71
|
+
Otherwise, when you issue a key to another person, you can still decrypt it
|
72
|
+
yourself, since gpg always encrypts it to this additional recipient.
|
73
|
+
|
71
74
|
h3. GPGME and gpg-agent
|
72
75
|
|
73
76
|
If arver asks you multiple times for the password, you might consider to use
|
data/lib/arver/action.rb
CHANGED
@@ -54,7 +54,11 @@ module Arver
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def load_key( partition )
|
57
|
-
|
57
|
+
if Arver::RuntimeConfig.instance.global_key_path
|
58
|
+
self.key= keystore.luks_key_for_path( Arver::RuntimeConfig.instance.global_key_path )
|
59
|
+
else
|
60
|
+
self.key= keystore.luks_key( partition )
|
61
|
+
end
|
58
62
|
|
59
63
|
if( key.nil? )
|
60
64
|
Arver::Log.error( "No permission on #{partition.path}. Skipping." )
|
data/lib/arver/bootstrap.rb
CHANGED
@@ -7,7 +7,7 @@ class Arver::Bootstrap
|
|
7
7
|
|
8
8
|
return true if options[:action] == :init
|
9
9
|
|
10
|
-
|
10
|
+
if "#{local.username}".empty?
|
11
11
|
Arver::Log.error( "No user defined" )
|
12
12
|
return false
|
13
13
|
end
|
@@ -32,6 +32,7 @@ class Arver::Bootstrap
|
|
32
32
|
rtc.violence = options[:violence]
|
33
33
|
rtc.test_mode = options[:test_mode]
|
34
34
|
rtc.trust_all = options[:trust_all]
|
35
|
+
rtc.global_key_path = options[:global_key_path]
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
data/lib/arver/cli.rb
CHANGED
@@ -34,6 +34,8 @@ module Arver
|
|
34
34
|
"Show this help message.") { Arver::Log.write opts; return }
|
35
35
|
opts.on("--ask-password",
|
36
36
|
"Ask for an existing LUKS password when adding a new user.") { options[:ask_password] = true }
|
37
|
+
opts.on("--set-key KEYNAME", String,
|
38
|
+
"Manuall choose a key to use. The KEYNAME is in the format /LOCATION/MACHINE/DISK.") { |arg| options[:global_key_path] = arg }
|
37
39
|
opts.on("-t", "--trust-all",
|
38
40
|
"Use untrusted GPG Keys.") { options[:trust_all] = true }
|
39
41
|
opts.on("--force",
|
@@ -57,6 +59,8 @@ module Arver
|
|
57
59
|
opts.separator "Actions:"
|
58
60
|
opts.on_tail( "-o TARGET", "--open TARGET", String,
|
59
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; }
|
60
64
|
opts.on_tail( "-c TARGET", "--close TARGET", String,
|
61
65
|
"Close target." ) { |arg| options[:argument][:target] = arg; options[:action] = :close; }
|
62
66
|
opts.on_tail( "--create TARGET", String,
|
@@ -75,6 +79,8 @@ module Arver
|
|
75
79
|
"LUKS info about a target.") { |arg| options[:argument][:target] = arg; options[:action] = :info; }
|
76
80
|
opts.on_tail( "-l", "--list-targets",
|
77
81
|
"List targets." ) { options[:action] = :list; }
|
82
|
+
opts.on_tail( "--dump-key TARGET", String,
|
83
|
+
"Dump raw luks passphrase." ) { |arg| options[:argument][:target] = arg; options[:action] = :dump; }
|
78
84
|
opts.on_tail( "--init",
|
79
85
|
"Setup a sample configuration." ) { options[:action] = :init; }
|
80
86
|
|
@@ -114,6 +120,7 @@ module Arver
|
|
114
120
|
:gc => Arver::GCAction,
|
115
121
|
:create => Arver::CreateAction,
|
116
122
|
:open => Arver::OpenAction,
|
123
|
+
:systemd_open => Arver::SystemdOpenAction,
|
117
124
|
:close => Arver::CloseAction,
|
118
125
|
:adduser => Arver::AdduserAction,
|
119
126
|
:deluser => Arver::DeluserAction,
|
@@ -121,6 +128,7 @@ module Arver
|
|
121
128
|
:key_info => Arver::KeyInfoAction,
|
122
129
|
:init => Arver::InitialConfigAction,
|
123
130
|
:refresh => Arver::RefreshAction,
|
131
|
+
:dump => Arver::DumpKeyAction,
|
124
132
|
}
|
125
133
|
|
126
134
|
action = (actions[ action ]).new( target_list )
|
@@ -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/config.rb
CHANGED
@@ -15,17 +15,22 @@ module Arver
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def load
|
18
|
-
if
|
19
|
-
Arver::Log.error(
|
20
|
-
exit
|
18
|
+
if !File.directory?(path)
|
19
|
+
Arver::Log.error("config "+path+" does not exist")
|
20
|
+
exit 1
|
21
21
|
end
|
22
|
-
@users=
|
22
|
+
@users = load_file(File.join(path,'users')) || {}
|
23
|
+
|
23
24
|
tree.clear
|
24
|
-
tree.from_hash(
|
25
|
+
tree.from_hash(load_file(File.join(path,'disks')))
|
25
26
|
end
|
26
27
|
|
27
28
|
def load_file( filename )
|
28
|
-
|
29
|
+
if !File.exists?(filename)
|
30
|
+
Arver::Log.error("missing config #{filename}")
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
YAML.load(File.read(filename))
|
29
34
|
end
|
30
35
|
|
31
36
|
def save
|
@@ -35,7 +40,7 @@ module Arver
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def exists?( user )
|
38
|
-
!
|
43
|
+
!users[user].nil?
|
39
44
|
end
|
40
45
|
|
41
46
|
def gpg_key user
|
@@ -45,6 +50,13 @@ module Arver
|
|
45
50
|
def slot user
|
46
51
|
users[user]['slot'] if exists?(user)
|
47
52
|
end
|
53
|
+
|
54
|
+
def user_at(slot)
|
55
|
+
users.each do |name, conf|
|
56
|
+
return name if slot == conf['slot']
|
57
|
+
end
|
58
|
+
'unknown'
|
59
|
+
end
|
48
60
|
|
49
61
|
def == other
|
50
62
|
return tree == other.tree && users == other.users if other.is_a?(Arver::Config)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Arver
|
2
|
+
class DumpKeyAction < Action
|
3
|
+
def initialize(target_list)
|
4
|
+
super(target_list)
|
5
|
+
self.open_keystore
|
6
|
+
end
|
7
|
+
|
8
|
+
def verify?(partition)
|
9
|
+
load_key(partition)
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute_partition( partition )
|
13
|
+
Arver::Log.info("key for #{partition.path}:")
|
14
|
+
Arver::Log.info(key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def pre_host( host )
|
18
|
+
end
|
19
|
+
|
20
|
+
def pre_partition( partition )
|
21
|
+
end
|
22
|
+
|
23
|
+
def post_partition( partition )
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_host( host )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
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,21 +25,33 @@ 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'
|
31
36
|
end
|
32
37
|
|
33
38
|
def username
|
34
|
-
|
35
|
-
|
39
|
+
case @username
|
40
|
+
when nil
|
41
|
+
'root'
|
42
|
+
when '#arveruser'
|
43
|
+
Arver::LocalConfig.instance.username
|
44
|
+
else
|
45
|
+
@username
|
46
|
+
end
|
36
47
|
end
|
37
48
|
|
38
49
|
def to_yaml
|
39
50
|
yaml = ""
|
40
|
-
yaml += "'address': '"
|
41
|
-
yaml += "'
|
42
|
-
yaml += "'
|
51
|
+
yaml += "'address': '"+@address+"'\n" unless @address.nil?
|
52
|
+
yaml += "'boot_address': '"+@boot_address+"'\n" unless @boot_address.nil?
|
53
|
+
yaml += "'port': '"+@port+"'\n" unless @port.nil?
|
54
|
+
yaml += "'username': '"+@username+"'\n" unless @username.nil?
|
43
55
|
yaml += script_hooks_to_yaml
|
44
56
|
yaml += super
|
45
57
|
end
|
@@ -55,6 +67,10 @@ module Arver
|
|
55
67
|
self.address = data
|
56
68
|
next
|
57
69
|
end
|
70
|
+
if( name == "boot_address" )
|
71
|
+
self.boot_address = data
|
72
|
+
next
|
73
|
+
end
|
58
74
|
if( name == "username" )
|
59
75
|
self.username= data
|
60
76
|
next
|
data/lib/arver/info_action.rb
CHANGED
@@ -3,6 +3,7 @@ module Arver
|
|
3
3
|
def initialize( target_list )
|
4
4
|
super( target_list )
|
5
5
|
self.open_keystore
|
6
|
+
Arver::Log.info("Warning: existence of a keyslot is not a guarantee that the user can access it")
|
6
7
|
end
|
7
8
|
|
8
9
|
def pre_host( host )
|
@@ -10,13 +11,44 @@ module Arver
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def execute_partition(partition)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
cmd = Arver::LuksWrapper.dump(partition)
|
15
|
+
cmd.execute
|
16
|
+
info = cmd.output
|
17
|
+
info =~ /Version:[\s]+(\d)/
|
18
|
+
version = $1
|
19
|
+
slots = []
|
20
|
+
|
21
|
+
head = " #{sprintf("%0-10s",partition.name[0...10])} :"+
|
22
|
+
" #{sprintf("%0-30s",partition.device_path[0...30])}"
|
23
|
+
|
24
|
+
if version != '1' && version != '2'
|
25
|
+
Arver::Log.info("#{head} : Unsupported luks version")
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
if version == '1'
|
30
|
+
info.each_line do |line|
|
31
|
+
if line =~ /Key Slot (\d): ENABLED/
|
32
|
+
slots << Integer($1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
keyslots = []
|
37
|
+
start = false
|
38
|
+
info.each_line do |line|
|
39
|
+
if line =~ /Keyslots:/
|
40
|
+
start = true
|
41
|
+
next
|
42
|
+
end
|
43
|
+
next unless start
|
44
|
+
break unless line =~ /^\s/
|
45
|
+
if line =~ /[\s]+(\d): luks2/
|
46
|
+
slots << Integer($1)
|
47
|
+
end
|
48
|
+
end
|
18
49
|
end
|
19
|
-
|
50
|
+
slots = slots.map{|s| "#{Config.instance.user_at(s)}(#{s})"}.join(",")
|
51
|
+
Arver::Log.info("#{head} : #{slots}")
|
20
52
|
end
|
21
53
|
end
|
22
54
|
end
|
data/lib/arver/key_generator.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module Arver
|
2
4
|
class KeyGenerator
|
3
5
|
def initialize
|
@@ -5,7 +7,7 @@ module Arver
|
|
5
7
|
end
|
6
8
|
|
7
9
|
def generate_key( partition )
|
8
|
-
key =
|
10
|
+
key = SecureRandom.base64(192)
|
9
11
|
@keys[partition] = key
|
10
12
|
end
|
11
13
|
|
data/lib/arver/key_saver.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module Arver
|
2
4
|
class KeySaver
|
3
5
|
|
@@ -37,6 +39,7 @@ module Arver
|
|
37
39
|
#compress the key before applying padding, so the size after encryption+compression by gpg is more stable...
|
38
40
|
key = deflate(key)
|
39
41
|
unless GPGKeyManager.check_key_of( user )
|
42
|
+
Arver::Log.error( "Error no key for #{user}" )
|
40
43
|
return
|
41
44
|
end
|
42
45
|
gpg_key = GPGKeyManager.key_of( user )
|
@@ -115,19 +118,19 @@ module Arver
|
|
115
118
|
end
|
116
119
|
|
117
120
|
def self.add_padding( key )
|
118
|
-
marker = "--"+
|
121
|
+
marker = "--"+SecureRandom.base64( 82 )
|
119
122
|
size = 200000
|
120
123
|
padding_size = size - key.size
|
121
124
|
if padding_size <= 0
|
122
125
|
padding_size = 0
|
123
126
|
Arver::Log.warn( "Warning: Your arver keys exceed the maximal padding size, therefore i can no longer disguise how many keys you possess.")
|
124
127
|
end
|
125
|
-
padding =
|
128
|
+
padding = SecureRandom.base64( padding_size )[0..padding_size]
|
126
129
|
marker +"\n"+ key + "\n" + marker + "\n" + padding
|
127
130
|
end
|
128
131
|
|
129
132
|
def self.substract_padding( key )
|
130
|
-
if
|
133
|
+
if key[0...4] == "--- "
|
131
134
|
Arver::Log.warn( "Warning: you are using deprecated unpadded keyfiles. Please run garbage collect!" )
|
132
135
|
return key
|
133
136
|
end
|
data/lib/arver/keystore.rb
CHANGED
@@ -15,23 +15,23 @@ module Arver
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
attr_reader :username, :loaded
|
19
19
|
|
20
20
|
def initialize( name )
|
21
21
|
@keys = {}
|
22
22
|
@key_versions = {}
|
23
|
-
|
24
|
-
|
23
|
+
@username = name
|
24
|
+
@loaded = false
|
25
25
|
end
|
26
26
|
|
27
27
|
def load
|
28
28
|
flush_keys
|
29
|
-
KeySaver.read(
|
29
|
+
KeySaver.read(username).each do | loaded |
|
30
30
|
YAML.load( loaded ).each do | target, key |
|
31
31
|
load_luks_key(target,key)
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
@loaded = true
|
35
35
|
end
|
36
36
|
|
37
37
|
def save
|
@@ -51,9 +51,13 @@ module Arver
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def luks_key(partition)
|
54
|
-
|
54
|
+
luks_key_for_path(partition.path)
|
55
55
|
end
|
56
56
|
|
57
|
+
def luks_key_for_path(path)
|
58
|
+
@keys[path][:key] unless ! @keys[path]
|
59
|
+
end
|
60
|
+
|
57
61
|
def load_luks_key(partition, new_key)
|
58
62
|
if( new_key.kind_of? Hash )
|
59
63
|
if( ! @keys[partition] || @keys[partition][:time] <= new_key[:time] )
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext'
|
2
|
-
|
3
1
|
module Arver
|
4
2
|
module PartitionHierarchyNode
|
5
3
|
|
@@ -72,7 +70,7 @@ module Arver
|
|
72
70
|
def find( name )
|
73
71
|
found = []
|
74
72
|
self.each_node do | node |
|
75
|
-
found += [ node ] if (
|
73
|
+
found += [ node ] if (node.name == name || node.path =~ /#{name}$/)
|
76
74
|
end
|
77
75
|
found
|
78
76
|
end
|
data/lib/arver/runtime_config.rb
CHANGED
@@ -5,7 +5,7 @@ module Arver
|
|
5
5
|
|
6
6
|
include Singleton
|
7
7
|
|
8
|
-
attr_accessor :test_mode, :dry_run, :force, :violence, :ask_password, :trust_all
|
8
|
+
attr_accessor :test_mode, :dry_run, :force, :violence, :ask_password, :trust_all, :global_key_path
|
9
9
|
|
10
10
|
instance.test_mode= false
|
11
11
|
instance.dry_run= false
|
@@ -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
@@ -1,6 +1,7 @@
|
|
1
|
-
%w{singleton yaml fileutils rubygems
|
1
|
+
%w{singleton yaml fileutils rubygems highline/import gpgme openssl zlib}.each {|f| require f }
|
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}.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
|
.
|
@@ -193,15 +197,16 @@ The \fBdisks\fR file contains the following hash tree in yaml notation:
|
|
193
197
|
\'disk2\' :
|
194
198
|
\'device\' : \'sdb1\'
|
195
199
|
\'host2\':
|
196
|
-
\'address\': \'host2\.example\.com\'
|
197
|
-
\'port\'
|
198
|
-
\'
|
200
|
+
\'address\' : \'host2\.example\.com\'
|
201
|
+
\'port\' : \'2222\'
|
202
|
+
\'username\': \'hans\'
|
203
|
+
\'mails\' :
|
199
204
|
\'device\' : \'nonraid/mails\'
|
200
205
|
\'pre_open\': \'pre_open_disk_script\.sh\'
|
201
206
|
\'hostgroup2\':
|
202
207
|
\'host3\':
|
203
208
|
\'address\' : \'host3\.example\.com\'
|
204
|
-
\'username\': \'
|
209
|
+
\'username\': \'#arveruser\'
|
205
210
|
\'secure\' :
|
206
211
|
\'device\' : \'storage/secure\'
|
207
212
|
.
|
@@ -235,6 +240,19 @@ will present you the tree of the various targets in your \fBdisks\fR configurati
|
|
235
240
|
\fBhost1\fR, \fBhost2\fR and \fBhost3\fR are identifiers for different hosts\. These host\- objects can contain multiple disks and can have further information such as the \fBaddress\fR of the host or the ssh\-\fBport\fR number if the ssh daemon is not running on the standart port\.
|
236
241
|
.
|
237
242
|
.P
|
243
|
+
\fBusername\fR defines the ssh login\-user\. By default it is \fBroot\fR\. To always use the same username as arver (as defined by \fB\-u\fR or in \fB\.arver\fR) set the username to \fB#arveruser\fR\. If the user is not \fBroot\fR, the actual LUKS commands will be executed via \fBsudo\fR and you need the following entry in your sudoers file on this machine (assuming the user is in the admin group):
|
244
|
+
.
|
245
|
+
.IP "" 4
|
246
|
+
.
|
247
|
+
.nf
|
248
|
+
|
249
|
+
%admin ALL=NOPASSWD: /usr/bin/test, /sbin/cryptsetup
|
250
|
+
.
|
251
|
+
.fi
|
252
|
+
.
|
253
|
+
.IP "" 0
|
254
|
+
.
|
255
|
+
.P
|
238
256
|
You can also add script hooks to any host or disk\. Those will be run during the \fBopen\fR and \fBclose\fR actions at the appropriate time\. The possible options are: \fBpre_open\fR, \fBpre_close\fR, \fBpost_open\fR and \fBpost_close\fR\.
|
239
257
|
.
|
240
258
|
.P
|
@@ -313,6 +331,22 @@ Those scripts have to be present at the actual host\.
|
|
313
331
|
.P
|
314
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)\.
|
315
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
|
+
.
|
316
350
|
.SH "Action Close"
|
317
351
|
Closing luks devices is simply done by invoking
|
318
352
|
.
|
@@ -436,6 +470,32 @@ $ arver \-g
|
|
436
470
|
.P
|
437
471
|
If you use a version controll system to store your \fBarverdata\fR you should do this always before commiting the \fBarverdata\fR\.
|
438
472
|
.
|
473
|
+
.SH "Migrating keys"
|
474
|
+
If you want to move a disk to a different server or a server to a different location, there is currently no nice way of doing this\. You can however apply the following workaround, after you moved/renamed a disk in the config file:
|
475
|
+
.
|
476
|
+
.IP "" 4
|
477
|
+
.
|
478
|
+
.nf
|
479
|
+
|
480
|
+
$ arver \-\-set\-key /OLD_LOCATION/OLD_MACHINE/OLD_NAME \-\-refresh NEW_NAME
|
481
|
+
.
|
482
|
+
.fi
|
483
|
+
.
|
484
|
+
.IP "" 0
|
485
|
+
.
|
486
|
+
.P
|
487
|
+
For example after moving \fBa_disk\fR from \fBa_server\fR at \fBa_location\fR to \fBsome_server\fR at \fBsome_location\fR in the config, you can restore your access with:
|
488
|
+
.
|
489
|
+
.IP "" 4
|
490
|
+
.
|
491
|
+
.nf
|
492
|
+
|
493
|
+
$ arver \-\-set\-key /a_location/a_server/a_disk \-\-refresh /some_location/some_server/a_disk
|
494
|
+
.
|
495
|
+
.fi
|
496
|
+
.
|
497
|
+
.IP "" 0
|
498
|
+
.
|
439
499
|
.SH "SEE ALSO"
|
440
500
|
\fBcryptsetup\fR(8)\. \fBgnupg\fR(7)\.
|
441
501
|
.
|
Binary file
|
metadata
CHANGED
@@ -1,122 +1,98 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.9
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- o
|
9
8
|
- andreas
|
10
9
|
- mh
|
11
|
-
autorequire:
|
10
|
+
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
|
-
date:
|
13
|
+
date: 2022-01-29 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: gpgme
|
18
17
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
18
|
requirements:
|
21
|
-
- -
|
19
|
+
- - ">="
|
22
20
|
- !ruby/object:Gem::Version
|
23
21
|
version: 2.0.0
|
24
22
|
type: :runtime
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
25
|
requirements:
|
29
|
-
- -
|
26
|
+
- - ">="
|
30
27
|
- !ruby/object:Gem::Version
|
31
28
|
version: 2.0.0
|
32
|
-
- !ruby/object:Gem::Dependency
|
33
|
-
name: activesupport
|
34
|
-
requirement: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
|
-
requirements:
|
37
|
-
- - <
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: 3.0.0
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
|
-
requirements:
|
45
|
-
- - <
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 3.0.0
|
48
29
|
- !ruby/object:Gem::Dependency
|
49
30
|
name: highline
|
50
31
|
requirement: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
32
|
requirements:
|
53
|
-
- -
|
33
|
+
- - ">="
|
54
34
|
- !ruby/object:Gem::Version
|
55
35
|
version: 1.6.2
|
56
36
|
type: :runtime
|
57
37
|
prerelease: false
|
58
38
|
version_requirements: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
39
|
requirements:
|
61
|
-
- -
|
40
|
+
- - ">="
|
62
41
|
- !ruby/object:Gem::Version
|
63
42
|
version: 1.6.2
|
64
43
|
- !ruby/object:Gem::Dependency
|
65
44
|
name: cucumber
|
66
45
|
requirement: !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
46
|
requirements:
|
69
|
-
- -
|
47
|
+
- - ">="
|
70
48
|
- !ruby/object:Gem::Version
|
71
49
|
version: 0.10.2
|
72
50
|
type: :development
|
73
51
|
prerelease: false
|
74
52
|
version_requirements: !ruby/object:Gem::Requirement
|
75
|
-
none: false
|
76
53
|
requirements:
|
77
|
-
- -
|
54
|
+
- - ">="
|
78
55
|
- !ruby/object:Gem::Version
|
79
56
|
version: 0.10.2
|
80
57
|
- !ruby/object:Gem::Dependency
|
81
58
|
name: rspec
|
82
59
|
requirement: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
60
|
requirements:
|
85
|
-
- -
|
61
|
+
- - ">="
|
86
62
|
- !ruby/object:Gem::Version
|
87
63
|
version: 2.5.0
|
88
64
|
type: :development
|
89
65
|
prerelease: false
|
90
66
|
version_requirements: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
67
|
requirements:
|
93
|
-
- -
|
68
|
+
- - ">="
|
94
69
|
- !ruby/object:Gem::Version
|
95
70
|
version: 2.5.0
|
96
71
|
- !ruby/object:Gem::Dependency
|
97
72
|
name: rake
|
98
73
|
requirement: !ruby/object:Gem::Requirement
|
99
|
-
none: false
|
100
74
|
requirements:
|
101
|
-
- -
|
75
|
+
- - ">="
|
102
76
|
- !ruby/object:Gem::Version
|
103
77
|
version: 0.9.2
|
104
78
|
type: :development
|
105
79
|
prerelease: false
|
106
80
|
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
none: false
|
108
81
|
requirements:
|
109
|
-
- -
|
82
|
+
- - ">="
|
110
83
|
- !ruby/object:Gem::Version
|
111
84
|
version: 0.9.2
|
112
|
-
description: Arver helps you to
|
113
|
-
|
85
|
+
description: Arver helps you to share access to LUKS devices easily and safely in
|
86
|
+
a team
|
114
87
|
email: arver@lists.immerda.ch
|
115
88
|
executables:
|
116
89
|
- arver
|
117
90
|
extensions: []
|
118
91
|
extra_rdoc_files: []
|
119
92
|
files:
|
93
|
+
- CHANGELOG.textile
|
94
|
+
- README.textile
|
95
|
+
- bin/arver
|
120
96
|
- lib/arver.rb
|
121
97
|
- lib/arver/action.rb
|
122
98
|
- lib/arver/adduser_action.rb
|
@@ -127,6 +103,7 @@ files:
|
|
127
103
|
- lib/arver/config.rb
|
128
104
|
- lib/arver/create_action.rb
|
129
105
|
- lib/arver/deluser_action.rb
|
106
|
+
- lib/arver/dump_key_action.rb
|
130
107
|
- lib/arver/gc_action.rb
|
131
108
|
- lib/arver/gpg_key_manager.rb
|
132
109
|
- lib/arver/host.rb
|
@@ -151,40 +128,34 @@ files:
|
|
151
128
|
- lib/arver/runtime_config.rb
|
152
129
|
- lib/arver/ssh_command_wrapper.rb
|
153
130
|
- lib/arver/string.rb
|
131
|
+
- lib/arver/systemd_open_action.rb
|
154
132
|
- lib/arver/target_list.rb
|
155
133
|
- lib/arver/test_config_loader.rb
|
156
134
|
- lib/arver/test_partition.rb
|
157
135
|
- lib/arver/tree.rb
|
158
136
|
- lib/arver/version.rb
|
159
|
-
- README.textile
|
160
|
-
- CHANGELOG.textile
|
161
137
|
- man/arver.5
|
162
|
-
-
|
163
|
-
homepage: https://
|
138
|
+
- vendor/password-agent
|
139
|
+
homepage: https://code.immerda.ch/immerda/apps/arver
|
164
140
|
licenses: []
|
165
|
-
|
141
|
+
metadata: {}
|
142
|
+
post_install_message:
|
166
143
|
rdoc_options: []
|
167
144
|
require_paths:
|
168
145
|
- lib
|
169
146
|
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
-
none: false
|
171
147
|
requirements:
|
172
|
-
- -
|
148
|
+
- - ">="
|
173
149
|
- !ruby/object:Gem::Version
|
174
|
-
version: '
|
175
|
-
segments:
|
176
|
-
- 0
|
177
|
-
hash: 947642704890013429
|
150
|
+
version: '2.2'
|
178
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
-
none: false
|
180
152
|
requirements:
|
181
|
-
- -
|
153
|
+
- - ">="
|
182
154
|
- !ruby/object:Gem::Version
|
183
155
|
version: 1.3.6
|
184
156
|
requirements: []
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
summary: Open crypted devices automatically
|
157
|
+
rubygems_version: 3.1.2
|
158
|
+
signing_key:
|
159
|
+
specification_version: 4
|
160
|
+
summary: LUKS for groups
|
190
161
|
test_files: []
|