diff --git a/README.rst b/README.rst index 98cfa17c9..e58af39e7 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,6 @@ SOPS: Secrets OPerationS ======================== + `sops` is a secrets management tool that encrypts YAML, JSON and TEXT files using AWS KMS and/or PGP (via GnuPG). @@ -138,6 +139,20 @@ Given that, the only command a `sops` user need is: encrypted if modified, and saved back to its original location. All of these steps, apart from the actual editing, are transparent to the user. +Key Rotation +~~~~~~~~~~~~ + +It is recommend to renew the data key on a regular basis. `sops` supports key +rotation via the `-r` flag. A simple approach is to decrypt and reencrypt all +files in place with rotation enabled: + +.. code:: bash + + for file in $(find . -type f -name "*.yaml"); do + sops -d -i $file + sops -e -i -r $file + done + Cryptographic details --------------------- @@ -273,11 +288,13 @@ Mozilla Public License Version 2.0 Authors ------- * Julien Vehent +* Daniel Thornton Credits ------- -`sops` is inspired by projects like `hiera-eyaml -`_, `credstash -`_ and `sneaker -`_. +`sops` is inspired by `hiera-eyaml `_, +`credstash `_ , +`sneaker `_, +`password store `_ and too many years managing +PGP encrypted files by hand... diff --git a/sops/__init__.py b/sops/__init__.py index e8510437e..ff49ea471 100755 --- a/sops/__init__.py +++ b/sops/__init__.py @@ -103,6 +103,10 @@ def main(): dest='in_place', help="write output back to instead " "of stdout for encrypt/decrypt") + argparser.add_argument('-r', '--rotate', action='store_true', + dest='rotate', + help="generate a new data encryption key and " + "encrypt all values with the new key") argparser.add_argument('--input-type', dest='input_type', help="input type (yaml, json, ...), " "if undef, use file extension") @@ -147,9 +151,13 @@ def main(): tree = dict() tree, need_key = verify_or_create_sops_branch(tree) + if args.rotate: + need_key = True + if args.encrypt: # Encrypt mode: encrypt, display and exit key, tree = get_key(tree, need_key) + tree = walk_and_encrypt(tree, key) elif args.decrypt: @@ -481,9 +489,6 @@ def encrypt_key_with_kms(key, tree): i = -1 for entry in tree['sops']['kms']: i += 1 - if 'enc' in entry and entry['enc'] != "": - # key is already encrypted with kms, skipping - continue if 'arn' not in entry or entry['arn'] == "": print("KMS ARN not found, skipping entry %d" % i, file=sys.stderr) continue @@ -547,9 +552,6 @@ def encrypt_key_with_pgp(key, tree): i = -1 for entry in tree['sops']['pgp']: i += 1 - if 'enc' in entry and entry['enc'] != "": - # key is already encrypted with pgp, skipping - continue if 'fp' not in entry or entry['fp'] == "": print("PGP fingerprint not found, skipping entry %d" % i, file=sys.stderr)