]> Dogcows Code - chaz/groupsecret/blob - bin/groupsecret
Version 0.303
[chaz/groupsecret] / bin / groupsecret
1 #!perl
2 # PODNAME: groupsecret
3 # ABSTRACT: A simple tool for maintaining a shared group secret
4
5
6 use warnings FATAL => 'all';
7 use strict;
8
9 our $VERSION = '0.303'; # VERSION
10
11 use App::GroupSecret;
12
13 App::GroupSecret->new->main(@ARGV);
14 exit;
15
16 __END__
17
18 =pod
19
20 =encoding UTF-8
21
22 =head1 NAME
23
24 groupsecret - A simple tool for maintaining a shared group secret
25
26 =head1 VERSION
27
28 version 0.303
29
30 =head1 SYNOPSIS
31
32 groupsecret [--version] [--help] [-f <filepath>] [-k <privatekey_path>]
33 <command> [<args>]
34
35 groupsecret add-key [--embed] [--update] <publickey_path> ...
36
37 groupsecret delete-key <fingerprint>|<publickey_path> ...
38
39 groupsecret list-keys
40
41 groupsecret set-secret [--keep-passphrase] <path>|-|rand:<num_bytes>
42
43 groupsecret [print-secret] [--no-decrypt]
44
45 =head1 DESCRIPTION
46
47 L<groupsecret> is a program that makes it easy for groups to share a secret between themselves
48 without exposing the secret to anyone else. It could be used, for example, by a team to share an
49 L<ansible-vault(1)> password; see L</ansible-vault> for more about this particular use case.
50
51 The goal of this program is to be easy to use and have few dependencies (or only have dependencies
52 users are likely to already have installed).
53
54 groupsecret works by encrypting a secret with a symmetric cipher protected by a secure random
55 passphrase which is itself encrypted by one or more SSH2 RSA public keys. Only those who have access
56 to one of the corresponding private keys are able to decrypt the passphrase and access the secret.
57
58 The encrypted secret and passphrase are stored in a single keyfile. You can even commit the keyfile
59 in a public repo or in a private repo where some untrusted users may have read access; the secret is
60 locked away to all except those with a private key to a corresponding public key that has been added
61 to the keyfile.
62
63 The keyfile is just a YAML file, so it's human-readable (except of course for the encrypted parts).
64 This make it easy to add to version control and work with diffs. You can edit the keyfile by hand if
65 you learn its very simple structure, but this program makes it even easier to manage the keyfile.
66
67 =head1 OPTIONS
68
69 =head2 --version
70
71 Print the program name and version to C<STDOUT>, and exit.
72
73 Alias: C<-v>
74
75 =head2 --help
76
77 Print the synopsis to C<STDOUT>, and exit.
78
79 Alias: C<-h>
80
81 =head2 --file=path
82
83 Specify a path to a keyfile which stores a secret and keys.
84
85 Defaults to the value of the environment variable L</GROUPSECRET_KEYFILE> or F<groupsecret.yml>.
86
87 Alias: C<-f>
88
89 =head2 --private-key=path
90
91 Specify a path to a PEM private key. This is used by some commands to decrypt the passphrase that
92 protects the secret and is ignored by commands that don't need it.
93
94 Defaults to the value of the environment variable L</GROUPSECRET_PRIVATE_KEY> or F<~/.ssh/id_rsa>.
95
96 Alias: C<-k>
97
98 =head1 COMMANDS
99
100 =head2 add-key
101
102 groupsecret add-key path/to/mykey_rsa.pub
103
104 Adds one or more SSH2 RSA public keys to a keyfile. This allows the secret contained within the
105 keyfile to be accessed by whoever has the corresponding private key.
106
107 If the C<--embed> option is used, the public keys will be embeded in the keyfile. This may be
108 a useful way to make sure the actual keys are available in the future since they could be needed to
109 encrypt a new passphrase if it ever needs to be changed. Keys that are not embedded will be searched
110 for in the filesystem; see L</GROUPSECRET_PATH>.
111
112 If the C<--update> option is used and a key with the same fingerprint is added, the new key will
113 replace the existing key. The default behavior is to skip existing keys.
114
115 If the keyfile is storing a secret, the passphrase protecting the secret will need to be decrypted
116 so that access to the secret can be shared with the new key(s).
117
118 Alias: C<add-keys>
119
120 =head2 delete-key
121
122 groupsecret delete-key MD5:89:b3:fb:76:6c:f9:56:8e:a8:1a:df:ba:1c:ba:7d:05
123 groupsecret delete-key path/to/mykey_rsa.pub
124
125 Deletes one or more keys from a keyfile. This prevents the secret contained within the keyfile from
126 being accessed by whoever has the corresponding private key.
127
128 Of course, if the owners of the key(s) being removed have already had access to the keyfile prior to
129 their keys being removed, the secret is already exposed to them. It usually makes sense to follow up
130 this command with a L</set-secret> command in order to change the secret.
131
132 Aliases: C<delete-keys>, C<remove-key>, C<remove-keys>
133
134 =head2 list-keys
135
136 groupsecret list-keys
137
138 Prints the keys that have access to the secret contained in the keyfile to C<STDOUT>, one per line
139 in the following format:
140
141 <fingerprint> <comment>
142
143 =head2 set-secret
144
145 groupsecret set-secret path/to/secretfile.txt
146 groupsecret set-secret - <<END
147 > it's a secret to everybody
148 > END
149 groupsecret set-secret rand:48
150
151 Set or update the secret contained in a keyfile. The argument allows you to add a secret from
152 a file, from <STDIN>, or from a stream of secure random bytes.
153
154 If the keyfile already contains a secret, it will be replaced by the new secret. A keyfile can only
155 contain one secret at a time. If you think you want to store more than one secret at a time, store
156 a tarball instead.
157
158 By default, this will also change the passphrase protecting the secret and re-encrypt the passphrase
159 for each key currently in the keyfile. This requires all of the public keys to be available (see
160 L</GROUPSECRET_PATH>). If for some reason you want to protect the new secret with the current
161 passphrase, use the C<--keep-passphrase> option; this can be done without the public keys being
162 available, but it will require a private key to decrypt the passphrase.
163
164 Aliases: C<change-secret>, C<update-secret>
165
166 =head2 print-secret
167
168 groupsecret print-secret
169 groupsecret print-secret --no-decrypt
170
171 Print the secret contained in the keyfile to C<STDOUT>.
172
173 If the C<--no-decrypt> option is used, the secret will be printed in its encrypted form.
174
175 This requires a private key.
176
177 Aliases: (no command), C<show-secret>
178
179 =head1 REQUIREMENTS
180
181 =over 4
182
183 =item *
184
185 L<OpenSSH|https://www.openssh.com> (commands: L<ssh-keygen(1)>)
186
187 =item *
188
189 L<OpenSSL|https://www.openssl.org> (commands: L<openssl(1)>)
190
191 =back
192
193 =head1 INSTALL
194
195 There are a few ways to install groupsecret to your system. First, make sure you first have the
196 L</REQUIREMENTS> installed.
197
198 =head2 Using cpanm
199
200 You can install groupsecret using L<cpanm>. If you have a local perl (plenv, perlbrew, etc.), you
201 can just do this:
202
203 cpanm App::GroupSecret
204
205 to install the F<groupsecret> executable and its Perl module dependencies. The executable will be
206 installed to your perl's bin path, like F<~/perl5/perlbrew/bin/groupsecret>.
207
208 If you're installing to your system perl, you can do:
209
210 cpanm --sudo App::GroupSecret
211
212 to install the F<groupsecret> executable to a system directory, like F</usr/local/bin/groupsecret>
213 (depending on your perl).
214
215 =head2 For developers
216
217 If you're a developer and want to hack on the source, clone the repository and pull the
218 dependencies:
219
220 git clone https://github.com/chazmcgarvey/groupsecret.git
221 cd groupsecret
222 cpanm Dist::Zilla
223 dzil authordeps --missing | cpanm
224 dzil listdeps --author --develop --missing | cpanm
225
226 =head1 ENVIRONMENT
227
228 =head2 GROUPSECRET_KEYFILE
229
230 If set, this program will use the value as a path to the keyfile. The L</--file=path> option takes
231 precedence if used.
232
233 =head2 GROUPSECRET_PRIVATE_KEY
234
235 If set, this program will use the value as a path to private key used for decryption. The
236 L</--private-key=path> option takes precedence if used.
237
238 =head2 GROUPSECRET_PATH
239
240 The value of this variable should be a colon-separated list of directories in which to search for
241 public keys. By default, the actual keys are not embedded in keyfiles, but they may be needed to
242 encrypt a new passphrase if it ever needs to be changed. Keys that are not embedded will be searched
243 for in the filesystem based on the value of this environment variable.
244
245 Defaults to C<.:keys:$HOME/.ssh>.
246
247 =head1 EXAMPLES
248
249 =head2 ansible-vault
250
251 L<Ansible Vault|http://docs.ansible.com/ansible/latest/vault.html> is a great way to securely store
252 secret configuration variables for use in your playbooks. Vaults are secured using a password, which
253 is okay if you're the only one who will need to unlock the Vault, but as soon as you add team
254 members who also need to access the Vault you are then faced with how to manage knowledge of the
255 password. When a team member leaves, you'll also need to change the Vault password which means
256 you'll need a way to communicate the change to other team members who also have access. This becomes
257 a burden to manage.
258
259 You can use groupsecret to manage this very easily by storing the Vault password in a groupsecret
260 keyfile. That way, you can add or remove keys and change the secret (the Vault password) at any time
261 without affecting the team members that still have access. Team members always use their own SSH2
262 RSA keys to unlock the Vault, so no new password ever needs to be communicated out.
263
264 To set this up, first create a keyfile with the public keys of everyone on your team:
265
266 groupsecret -f vault-password.yml add-keys keys/*_rsa.pub
267
268 Then set the secret in the keyfile to a long random number:
269
270 groupsecret -f vault-password.yml set-secret rand:48
271
272 This will be the Ansible Vault password. You can see it if you want using the L</print-secret>
273 command, but you don't need to.
274
275 Then we'll take advantage of the fact that an Ansible Vault password file can be an executable
276 program that prints the Vault password to C<STDOUT>. Create a file named F<vault-password> with the
277 following script, and make it executable (C<chmod +x vault-password>):
278
279 #!/bin/sh
280 # Use groupsecret <https://github.com/chazmcgarvey/groupsecret> to access the Vault password
281 exec ${GROUPSECRET:-groupsecret} -f vault-password.yml print-secret
282
283 Commit both F<vault-password> and F<vault-password.yml> to your repository.
284
285 Now use L<ansible-vault(1)> to add files to the Vault:
286
287 ansible-vault --vault-id=vault-password encrypt foo.yml bar.yml baz.yml
288
289 These examples show the Ansible 2.4+ syntax, but it can be adapted for earlier versions. The
290 significant part of this command is C<--vault-id=vault-password> which refers to the executable
291 script we created earlier. You can use that argument with other ansible-vault commands to view or
292 edit the encrypted files.
293
294 You can also pass that same argument to L<ansible-playbook(1)> in order to use the Vault in
295 playbooks that refer to the encrypted variables:
296
297 ansible-playbook -i myinventory --vault-id=vault-password site.yml
298
299 What this does is execute F<vault-password> which executes groupsecret to print the secret contained
300 in the F<vault-password.yml> file (which is actually the Vault password) to C<STDOUT>. In order to
301 do this, groupsecret will decrypt the keyfile passphrase using any one of the private keys that have
302 associated public keys added to the keyfile.
303
304 That's it! Pretty easy.
305
306 If and when you need to change the Vault password (such as when a team member leaves), you can
307 follow this procedure which is probably mostly self-explanatory:
308
309 groupsecret -f vault-password.yml delete-key keys/revoked/jdoe_rsa.pub
310 groupsecret -f vault-password.yml print-secret >old-vault-password.txt
311 groupsecret -f vault-password.yml set-secret rand:48
312 echo "New Vault password: $(groupsecret -f vault-password.yml)"
313 ansible-vault --vault-id=old-vault-password.txt rekey foo.yml bar.yml baz.yml
314 # You will be prompted for the new Vault password which you can copy from the output above.
315 rm -f old-vault-password.txt
316
317 This removes access to the keyfile secret and to the Ansible Vault. Don't forget that you may also
318 want to change the variables being protected by the Vault. After all, those secrets are the actual
319 things we're protecting by doing all of this, and an exiting team member may have decided to take
320 a copy of those variables for himself before leaving.
321
322 =head1 BUGS
323
324 Please report any bugs or feature requests on the bugtracker website
325 L<https://github.com/chazmcgarvey/groupsecret/issues>
326
327 When submitting a bug or request, please include a test-file or a
328 patch to an existing test-file that illustrates the bug or desired
329 feature.
330
331 =head1 AUTHOR
332
333 Charles McGarvey <chazmcgarvey@brokenzipper.com>
334
335 =head1 COPYRIGHT AND LICENSE
336
337 This software is Copyright (c) 2017 by Charles McGarvey.
338
339 This is free software, licensed under:
340
341 The MIT (X11) License
342
343 =cut
This page took 0.051383 seconds and 4 git commands to generate.