Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
Convert to fact hash command and remove fact decrypt. Closes #251.
Browse files Browse the repository at this point in the history
  • Loading branch information
chambridge committed Aug 30, 2017
1 parent abbc095 commit 04517b5
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 236 deletions.
16 changes: 11 additions & 5 deletions README.rst
Expand Up @@ -115,7 +115,11 @@ These python packages are required for the rho install machine to run rho:
* json
* subprocess
* xmlrpclib
* ansible.module_utils.basic
* ansible
* pexpect
* future
* sh
* pyxdg

The following python packages are required to build & test rho from source:
* python-devel
Expand All @@ -126,6 +130,10 @@ The following python packages are required to build & test rho from source:
* flake8
* pylint
* Coverage
* enum34
* configparser
* six
* docutils

-------------
Installation
Expand All @@ -140,8 +148,7 @@ You can find the appropriate architecture and version on the `EPEL wiki <https:/
2. Next, add the COPR repo to your server.
You can find the appropriate architecture and version on the `COPR rho page <https://copr.fedorainfracloud.org/coprs/chambridge/rho/>`_::

cd /etc/yum.repos.d/
wget https://copr.fedorainfracloud.org/coprs/chambridge/rho/repo/epel-7/chambridge-rho-epel-7.repo
wget -O /etc/yum.repos.d/chambridge-rho-epel-7.repo https://copr.fedorainfracloud.org/coprs/chambridge/rho/repo/epel-7/chambridge-rho-epel-7.repo

3. Then, install the rho package:

Expand Down Expand Up @@ -170,8 +177,7 @@ There are four rho commands:
``fact`` has four subcommands:
* ``list`` - to display the list of facts that can be scanned
* ``redact`` - to remove sensitive facts from a scanned report
* ``encrypt`` - to encrypt sensitive facts within report
* ``decrypt`` - to decrypt sensitive facts within report
* ``hash`` - to hash sensitive facts within report

The complete list of options for each command and subcommand are listed in the
rho manpage with other usage examples. The common options are listed with the
Expand Down
3 changes: 1 addition & 2 deletions doc/command_syntax_usage.rst
Expand Up @@ -21,8 +21,7 @@ There are four rho commands:
``fact`` has three subcommands:
* ``list`` - to display the list of facts that can be scanned
* ``redact`` - to remove sensitive facts from a scanned report
* ``encrypt`` - to encrypt sensitive facts within report
* ``decrypt`` - to decrypt sensitive facts within report
* ``hash`` - to hash sensitive facts within report

The complete list of options for each command and subcommand are listed in the
rho manpage with other usage examples. The common options are listed with the
Expand Down
31 changes: 4 additions & 27 deletions doc/rho.1
Expand Up @@ -350,14 +350,14 @@ The path and filename of the comma-separated values (CSV) file to read from.
The path and filename of the comma-separated values (CSV) file to be written.
.PP
.B
Encrypting Facts
Hashing Facts
.PP
Sensitive facts can be encrypted within a report CSV file using the 'encrypt' command. The command will prompt for a password to encrypt values and should be used when decrypting these values. The password does not have to be the same as the rho vault password. The facts that are encrypted with this command are:
Sensitive facts can be encrypted within a report CSV file using the 'hash' command. The facts that are hashed with this command are:
.I connection.host, connection.port, uname.all,
and
.I uname.hostname.
.PP
.B rho fact encrypt
.B rho fact hash
.B --reportfile=
.I file
.B [--outputfile=
Expand All @@ -366,30 +366,7 @@ and
.PP
.TP
--reportfile=file
The path and filename of the comma-separated values (CSV) file to alter.
.PP
.TP
--outputfile=path
The path and filename of the comma-separated values (CSV) file to be written.
.PP
.B
Decrypting Facts
.PP
Sensitive facts can be decrypted within a report CSV file using the 'decrypt' command. The command will prompt for a password to decrypt values and should be the same that was used when encrypting these values. The facts that are decrypted with this command are:
.I connection.host, connection.port, uname.all,
and
.I uname.hostname.
.PP
.B rho fact decrypt
.B --reportfile=
.I file
.B [--outputfile=
.I path
.B ]
.PP
.TP
--reportfile=file
The path and filename of the comma-separated values (CSV) file to alter.
The path and filename of the comma-separated values (CSV) file to read.
.PP
.TP
--outputfile=path
Expand Down
3 changes: 1 addition & 2 deletions rho/cli.py
Expand Up @@ -29,8 +29,7 @@
from rho.authshowcommand import AuthShowCommand # noqa
from rho.factlistcommand import FactListCommand # noqa
from rho.factredactcommand import FactRedactCommand # noqa
from rho.factencryptcommand import FactEncryptCommand # noqa
from rho.factdecryptcommand import FactDecryptCommand # noqa
from rho.facthashcommand import FactHashCommand # noqa
from rho.profileaddcommand import ProfileAddCommand # noqa
from rho.profileclearcommand import ProfileClearCommand # noqa
from rho.profileeditcommand import ProfileEditCommand # noqa
Expand Down
123 changes: 0 additions & 123 deletions rho/factdecryptcommand.py

This file was deleted.

73 changes: 39 additions & 34 deletions rho/factencryptcommand.py → rho/facthashcommand.py
Expand Up @@ -7,33 +7,41 @@
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.

"""Encrypt sensitive facts."""
"""Hash sensitive facts."""

from __future__ import print_function

import csv
import sys
import os
from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module
import hashlib
from rho import utilities
from rho.clicommand import CliCommand
from rho.translation import _
from rho.utilities import multi_arg, _read_in_file, write_csv_data
from rho.vault import get_vault

PROMPT = "Please enter your encryption password: "

def compute_md5_hash(input_string):
""" Computes the md5 hash for a string
:param input_string: The string to hash
:returns: The hex hash value
"""
hasher = hashlib.md5()
hasher.update(input_string.encode('utf-8'))
return hasher.hexdigest()


# pylint: disable=too-few-public-methods
class FactEncryptCommand(CliCommand):
"""Encrypt sensitive facts."""
class FactHashCommand(CliCommand):
"""Hash sensitive facts."""

def __init__(self):
usage = _('usage: %prog fact encrypt')
shortdesc = _('encrypt facts within a report created by rho')
desc = _('encrypt sensitive facts within a report created by rho.')
usage = _('usage: %prog fact hash')
shortdesc = _('hash facts within a report created by rho')
desc = _('hash sensitive facts within a report created by rho.')

CliCommand.__init__(self, 'fact encrypt', usage, shortdesc, desc)
CliCommand.__init__(self, 'fact hash', usage, shortdesc, desc)

self.parser.add_option("--reportfile", dest="report_path",
metavar="REPORTFILE",
Expand All @@ -43,12 +51,12 @@ def __init__(self):
action="callback", callback=multi_arg,
default=[], help=SUPPRESS_HELP)

self.parser.add_option("--outputfile", dest="encrypted_path",
metavar="ENCRYPTEDPATH",
help=_("Location for the encrypted file"),
self.parser.add_option("--outputfile", dest="hashed_path",
metavar="HASHEDPATH",
help=_("Location for the hashed file"),
default=None)

self.facts_to_encrypt = None
self.facts_to_hash = None

def _validate_options(self):
CliCommand._validate_options(self)
Expand All @@ -66,59 +74,56 @@ def _validate_options(self):
# perform fact validation
facts = self.options.facts
if facts == [] or facts == ['default']:
self.facts_to_encrypt = list(utilities.SENSITIVE_FACTS_TUPLE)
self.facts_to_hash = list(utilities.SENSITIVE_FACTS_TUPLE)
elif os.path.isfile(facts[0]):
self.facts_to_encrypt = _read_in_file(facts[0])
self.facts_to_hash = _read_in_file(facts[0])
else:
assert isinstance(facts, list)
self.facts_to_encrypt = facts
# check facts_to_encrypt is subset of utilities.DEFAULT_FACTS
self.facts_to_hash = facts
# check facts_to_hash is subset of utilities.DEFAULT_FACTS
all_facts = utilities.DEFAULT_FACTS
facts_to_encrypt_set = set(self.facts_to_encrypt)
if not facts_to_encrypt_set.issubset(all_facts):
invalid_facts = facts_to_encrypt_set.difference(all_facts)
facts_to_hash_set = set(self.facts_to_hash)
if not facts_to_hash_set.issubset(all_facts):
invalid_facts = facts_to_hash_set.difference(all_facts)
print(_("Invalid facts were supplied to the command: " +
",".join(invalid_facts)))
self.parser.print_help()
sys.exit(1)

def read_and_encrypt(self, path, vault):
""" Read the given CSV file and encrypt the prescribed facts
utilizing the given password.
def read_and_hash(self, path):
""" Read the given CSV file and hash the prescribed facts
:param path: The csv file to read
:returns: The keys (set) and data (dict) composing the csv file
"""
facts_not_found = set()
facts_encrypted = set()
facts_hashed = set()
data = []
keys = None

with open(path, 'r') as read_file:
reader = csv.DictReader(read_file, delimiter=',')
for row in reader:
for fact in self.facts_to_encrypt:
for fact in self.facts_to_hash:
if fact in row:
row[fact] = vault.dump(row[fact])
facts_encrypted.add(fact)
row[fact] = compute_md5_hash(row[fact])
facts_hashed.add(fact)
else:
facts_not_found.add(fact)
if keys is None:
keys = set(row.keys())
data.append(row)

for fact in facts_encrypted:
print(_("Fact %s encrypted" % fact))
for fact in facts_hashed:
print(_("Fact %s hashed" % fact))
for fact in facts_not_found:
print(_("Fact %s was not present in %s" %
(fact, self.options.report_path)))

return keys, data

def _do_command(self):
vault = get_vault(prompt=PROMPT)
normalized_path = os.path.normpath(self.options.report_path)
encrypted_path = (self.options.encrypted_path or
normalized_path + '-encrypted')
hashed_path = (self.options.hashed_path or normalized_path + '-hashed')

keys, data = self.read_and_encrypt(normalized_path, vault)
write_csv_data(keys, data, encrypted_path)
keys, data = self.read_and_hash(normalized_path)
write_csv_data(keys, data, hashed_path)

0 comments on commit 04517b5

Please sign in to comment.