summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md289
1 files changed, 289 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5c543f4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,289 @@
1# etoolkit
2
3*etoolkit* is a simple toolkit for defining and setting environment variables
4in a flexible and secure way.
5
6
7## General
8
9*etoolkit* started as a simple idea while I was working at the University
10of Oslo. Later I felt the need for even more flexible solution. The following
11goals were set:
12
13- the ability to define env. var. "instances" with support for inheritance
14
15- encrypting values using a master password
16
17- the ability to spawn a child process with the defined variables
18
19- support for macros
20
21
22## Requirements
23
24Apart from Python >= 3.7, the only requirement is
25[cryptography](https://pypi.org/project/cryptography/)
26
27
28## Overview
29
30In a typical UNIX environment, env. variables are usually set in one
31or more of the initialization / startup files like f.i. */etc/profile*,
32*~/.bash_profile*, *~/.bashrc*, *~/.tcshrc*, *~/.cshrc* ... depending
33on the OS, shell, distribution... etc.
34Env. variables represent key-value pairs (env. variable name and its value).
35
36A potential problem when dealing with env. variables containing sensitive
37values like passwords, tokens, connection strings... is that they are inherited
38by all child processes spawned from the login / interactive shell.
39
40A malicious / exploited process (like f.i. web browser) will then be able to
41fetch those values by using *getenv*. Such process may in addition be able to
42simply read *~/.bashrc* or any similar file readable by the process owner and
43get the values from there if necessary.
44
45*etoolkit* attempts to solve both of these problems.
46
47When started, it reads env. variables from its own configuration file.
48Sensitive data may be encrypted using a master password. Hence reading
49etoolkit's configuration file will not reveal the real value of the data.
50
51When *etoolkit* has processed (decryption, macro replacement, etc) its data,
52it may define new env. variables corresponding to that data and may start a new
53interactive shell. The processed environment variables will not be available
54for processes that were not spawned by that same *etoolkit* session.
55
56
57## Installation
58
59### pip (pypi)
60
61 ```bash
62 pip install etoolkit
63 ```
64
65
66### Gentoo
67
68 ```bash
69 layman -a sgs
70 emerge dev-python/etoolkit
71 ```
72
73
74## Setup and examples
75
76Most users (including me) will simply use the command line interface (CLI).
77
78
79### CLI
80
81*etoolkit* comes with a simple CLI:
82
83 ```bash
84 python -m etoolkit -h
85 ```
86
87... or even (if *etoolkit* was installed using the methods described above)
88
89 ```bash
90 etoolkit -h
91 ```
92
93
94The *etoolkit* CLI loads the configuration located by default in
95*~/.etoolkit.json*. That file is based on
96[etoolkit_sample.json](https://github.com/blackm0re/etoolkit/blob/master/etoolkit_sample.json).
97
98The *"instances"* part of the configuration defines unique instances, each of
99which represents its own environment with its own defined env. variables.
100Each instance consists of key-value pairs corresponding to env. name and value.
101All pairs will result in corresponding env. variables being defined, with the
102exception of the following *etoolkit* internal keys:
103
104- **ETOOLKIT_PARENT** - string - reference to another instance
105
106- **ETOOLKIT_SENSITIVE** - list - env. variables containing sensitive data
107
108All pairs defined in *"general"* (currently only **MASTER_PASSWORD_HASH**) are
109*etoolkit* internal as well.
110
111An instance may inherit (and if desired overwrite) key value pairs from its
112parent.
113
114Variables containing sensitive data can be encrypted / decrypted using a master
115password. Currently *etoolkit* requires that all values in a configuration
116file are encrypted with the same master password. Setting a master password
117hash is a recommended but not mandatory.
118
119 ```bash
120 etoolkit -p
121 ```
122
123That command will prompt for master password and output a hash that can then
124be stored
125in ["general"]["MASTER_PASSWORD_HASH"].
126The hash is only used for verifying that a correct master password has been
127provided at a later time. Issuing:
128
129 ```bash
130 etoolkit -e
131 ```
132
133will prompt for the master password, then for the value to be encrypted and
134finally display the encrypted string of the value. Unless invoked with the
135*-E* / *--echo* parameter *etoolkit* will not display the value that is about
136to be encrypted.
137
138More than one value can be encrypted / decrypted with a single master password
139prompt if *-m* / *--multiple-values* parameter is provided. Manual decryption
140of single value(s):
141
142 ```bash
143 etoolkit -d -m
144 ```
145
146Listing all available instances defined in the configuration file and then
147loading a specific instance can be achieved by:
148
149 ```bash
150 etoolkit -l
151 etoolkit <instance-name>
152 ```
153
154*etoolkit* will prompt for the master password the first time it encounters
155and encrypted value. Once provided the master password will be used to decrypt
156the rest of the encrypted values.
157
158When all values are fetched from a given instance (and its parents) and then
159decrypted, they are further processed by replacing macros with their
160corresponding values. Currently the following macros are supported:
161
162- **%h** - the home directory of the user running *etoolkit* (~/)
163
164- **%i** - the names of the instance that is about to be loaded
165
166- **%u** - the username of the user running *etoolkit* (*getpass.getuser()*)
167
168In addition, value starting with *":"* is appended to the existing value
169(if any) of the env. variable about to be set
170(like *MYVAR=$MYVAR\<new value\>)*).
171The opposite is true for value ending with *":"* (*MYVAR=\<new value\>$MYVAR*).
172
173When the variables are finally processed, *etoolkit* sets / changes them as env.
174variables (using *setenv* / *os.environ.update*) and spawns an interactive
175child process (by invoking *system($SHELL)*).
176
177One can also spawn a different process than an interactive shell by using the
178*-s* / *--spawn* parameter.
179
180 ```bash
181 etoolkit -s /bin/othershell <instance-name>
182 ```
183
184Contact the author for questions and suggestions! :)
185
186
187### Using the *EtoolkitInstance* class
188
189*etoolkit* comes with its own *etoolkit* package that contains the
190*EtoolkitInstance* class.
191
192The class encapsulates the function of creating and processing instances
193from a given structure (dict).
194
195It may be useful if one should prefer for example making her own CLI interface.
196or the *instances* structure being loaded from a diferent configuration file
197(f.i. .yml).
198
199 ```python
200 import os
201
202 import etoolkit
203
204
205 # using some static methods in order to create encrypted values
206 etoolkit.EtoolkitInstance.encrypt('the very secret passwd', 'secret1')
207 # Out: 'enc-val$1$Y/TBb1F3siHTw6qZg9ERzZfA8PLPf2CwGSQLpu9jYWw=$FT5tS9o+ABvsxogIXpJim16Gz5SVtV8='
208
209 etoolkit.EtoolkitInstance.encrypt('the very secret passwd', 'secret2')
210 # Out: 'enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo='
211
212
213 # The encrypted values will be used in our configuration structure
214 # The following structure defines the 3 instances: default, dev and secret
215 instances = {
216 "general": {
217 },
218 "instances": {
219 "default": {
220 "ETOOLKIT_PROMPT": "(%i)"
221 },
222 "dev": {
223 "ETOOLKIT_PARENT": "default",
224 "PYTHONPATH": ":/home/user/.pythonpath",
225 "DB_CONNECTION": "enc-val$1$Y/TBb1F3siHTw6qZg9ERzZfA8PLPf2CwGSQLpu9jYWw=$FT5tS9o+ABvsxogIXpJim16Gz5SVtV8="
226 },
227 "secret": {
228 "ETOOLKIT_PARENT": "default",
229 "ETOOLKIT_SENSITIVE": ["PASSWORD"],
230 "GNUPGHOME": "%h/private/.gnupg",
231 "PASSWORD": "enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo="
232 }
233 }
234 }
235
236
237 dev_instance = etoolkit.EtoolkitInstance('dev', instances)
238
239 # fetch the variables before the processing stage (calling get_environ())
240 # since raw_env_variables is a dict, it can be modified (f.i. .update())
241 dev_instance.raw_env_variables
242
243 dev_instance.master_password = 'the very secret passwd' # or perhaps using getpass
244 env_vars = dev_instance.get_env()
245 print(env_vars['PASSWORD']) # outputs: 'secret2'
246
247 inst.dump_env(env_vars) # prints all values, with the exception of 'PASSWORD'
248
249 # set the env. variables.
250 os.environ.update(env_vars)
251 ```
252
253
254### Tips
255
256When starting a new interactive process (f.i. bash), the process will
257in turn invoke its startup script (f.i. *~/.bashrc*).
258Avoid redefining the env. variables that have just been set by *etoolkit*!
259
260If you want your shell prompt to display the name of the loaded instance, you
261can set a new env. variable (f.i. "ETOOLKIT_PROMPT" as shown in the sample
262configuration above) and then add the following at the bottom of your startup
263file (f.i. ~/.bashrc):
264
265 ```bash
266 if [ -n "$ETOOLKIT_PROMPT" ]; then
267 export PS1="$ETOOLKIT_PROMPT$PS1"
268 fi
269 ```
270
271
272## Support and contributing
273
274*etoolkit* is hosted on GitHub: https://github.com/blackm0re/etoolkit
275
276
277## Author
278
279Simeon Simeonov - sgs @ LiberaChat
280
281
282## [License](https://github.com/blackm0re/etoolkit/blob/master/LICENSE)
283
284Copyright (c) 2021, Simeon Simeonov
285All rights reserved.
286
287[Licensed](https://github.com/blackm0re/etoolkit/blob/master/LICENSE) under the
288GNU General Public License v3.0 or later.
289SPDX-License-Identifier: GPL-3.0-or-later