From 0b034c93fac4a656b15fc74b80669af2437641e0 Mon Sep 17 00:00:00 2001 From: Julien Vehent Date: Thu, 8 Oct 2015 08:35:42 -0400 Subject: [PATCH] Added version number to sops branch, to support multiple parsers later --- example.json | 7 ++-- example.txt | 2 +- example.yaml | 3 +- setup.py | 2 +- sops/__init__.py | 83 ++++++++++++++++++++++++++++++++---------------- 5 files changed, 64 insertions(+), 33 deletions(-) diff --git a/example.json b/example.json index f32012b4f..465bc313f 100644 --- a/example.json +++ b/example.json @@ -19,7 +19,7 @@ } ], "sops": { - "mac": "ENC[AES256_GCM,data:kYZgjW5lpTuTPZOs/rJTKajAxF9yAGRiRZzCFYuRR1UPkLeOzBlh4qLBngw1eu3wLkjJo+Aj6zPuVsZAOHlwGRlYsNzhzMFMTuuNaG2bN8FNl7Z/0qz/LIsuLov3RdaGyC9u++Vsm3NWoAsDLyKATS73F54SrakysIBCK1q4aZk=,iv:+fYGJ0hx/e9eR+i7Un4Ogvf6x5H+6mK8r90f9P9GLdA=,tag:1DV1d7qGh7zP2ZWwi+//uA==,type:str]", + "mac": "ENC[AES256_GCM,data:sMQOEOLOyVoamdHBRCFceMgNfdXNzyb1DQYRPIjU5IMU3kGSP3qMVxBbf8Mv26AwrCo65/ai/Z0af81cxs2nIg1XegwuCMNpAgNi5q9+bZ1xG0rmrwUOmBaH/fIfmZeUbPYmczre89J8nfD2aTetIWqu1PwC/TyD2/snrif3Vns=,iv:MxMABoPMrUCBwzI/gX2xGpvT0/qo5k0CYuUuIt2U+G4=,tag:K4aeS24U+PzzeSrGJAcfvw==,type:str]", "attention": "This section contains key material that should only be modified with extra care. See `sops -h`.", "kms": [ { @@ -39,6 +39,7 @@ "created_at": 1444233151.309663, "enc": "-----BEGIN PGP MESSAGE-----\nVersion: GnuPG v1\n\nhQIMA0t4uZHfl9qgARAAgQdMpnTNMCdbdFRpBsC9kxi334LbBrFUkp5lI+YzutZy\nSic85ea06FGL3O93tII9mwGAsESwKlN4nX0d31vuh/lYxMDakyd1IK/BkMG4Z1xG\n52MsACG/pyitMBXkIIyjmR0tVR+CixDsy5cUJxoWq+mfuE2ywziPY+KbEZ50hFXg\naAdKCdInXlLHdId+aXhThhXUGN1seQjtdyZjVXnp8c9hHS2YQdyp/SZf47NJ4A2y\nkO40kNS4oaHUUZIZLtzaFhWytZlpWEJJkIgH/vefL3jLW4SiIiqz24wr7MncsF+A\np8Pteulc5VrvA5CzQIq9qF3Zwn9HV2a0KWLZ/J29EYzSM8u9HLOYqsmNKt0TcVbX\n6eoG3JTJoRDrzO0DZvR3pMm4gQ0WXzHKzpu8g+JYnoQ19AMWJAPbTp5ej3MWHcXD\nXFjz4gsSYbwc4h/zVBOWsYoHlyTLUMwg2BA1YiL89xs8MIhIHOAmvM0mv+QuZQ7S\nCfc1mS04CZSmJvTcNkvE5n76n2iXs6nYNk8TYyQlhYebuQmJQKJuUYjKIHhuxZFa\n30WaSGnKHqIQn1pl7jqyqm8sVTzaKMyhbM0T+UQUJhXcWVr7r+CtRAt8XjVnJMvo\nviJwTWy1Ddo0Vu1licMFJXMnQbQlVh+CZS6FHqcbxfPaYfe7JldGmhwKg+F/NEHS\nXgEf78iLm3FNb4yeOkB/z2xjiZ3XvUAQjsUK5ofF1CJYcQ//YIFex1oO55Z0+qIt\njdDtqivLgf4SFRf0uhOxUrQNuFAvY361F1mvrGPcTubh/Ygq0aVzWzgC9gn7DTo=\n=uQw0\n-----END PGP MESSAGE-----\n" } - ] + ], + "version": 0.8 } -} \ No newline at end of file +} diff --git a/example.txt b/example.txt index 85104d50d..58b618ed1 100644 --- a/example.txt +++ b/example.txt @@ -1,2 +1,2 @@ ENC[AES256_GCM,data:qe/cYirOA9x9zFw8AtonYzcRT+Sr9KEMtiRN55YOn1SNBEX7sE9s/M09KSfneKCbHIsNVdh5902vYNAwSFpJ6NhzO/6YR65ucwS1eBx4EQ7s3PYkEWHipgcibW0hXiNvEJGpR/4ZQ/er/xns2cpCUAgpv07Ry9DiGW+us4HM+gA5dplTpYUCdzMl7zGYoPYcIiJVHjkjaHK70w==,iv:v2BgZ6Oa895KpYAeikA0c9g9R8wcu2YOe2kp6vPEMX8=,tag:zQ/C7u2+veEuOVLSAEc1Mg==,type:str] -SOPS={"attention": "This section contains key material that should only be modified with extra care. See `sops -h`.", "kms": [{"arn": "arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e", "created_at": 1444233233.692422, "enc": "CiC6yCOtzsnFhkfdIslYZ0bAf//gYLYCmIu87B3sy/5yYxKnAQEBAgB4usgjrc7JxYZH3SLJWGdGwH//4GC2ApiLvOwd7Mv+cmMAAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAxatks17s0ZWQIyPi8CARCAO65vxmVs4SOASbNDdnwdeOlg75rz7oeqWId2JyQU8sNyz7+TNvvsLIjIR50AGMwnbMIgTmbM99LDi6Vo"}, {"arn": "arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d", "created_at": 1444233235.129884, "enc": "CiBdfsKZbRNf/Li8Tf2SjeSdP76DineB1sbPjV0TV+meTxKnAQEBAgB4XX7CmW0TX/y4vE39ko3knT++g4p3gdbGz41dE1fpnk8AAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzI3YJKPROE+fG2vJYCARCAO2IeX+3IeMkOOOsQauVrUTP9FVFmcmpXYDT41PDt8nhFvU/Q9RUUoVG1OLeWK+KBDZgu1NWGeUTN3TTs"}], "mac": "ENC[AES256_GCM,data:1Xhgsh64dJ2FM8AhbrRPVik2iXAuZV/kwHD93cConQwJDZw96joPn3S9jD//YcawPiniy4hjOoTxdkTcjdmy0NCGB3VUbetKDRUGgWatTvVMw2msL6UZYkCaqj6c66KgtUHPCgsr0GhsTOCN/F4+hg3qlLykJ6DJVLck0HZ7K9I=,iv:RL0nykJwmnRWXegD1VUQ5fNC8i2AnJHK/Y3jorfwYMI=,tag:JFRq575pT0jjk4xAwkMfog==,type:str]", "pgp": [{"created_at": 1444233235.135862, "enc": "-----BEGIN PGP MESSAGE-----\nVersion: GnuPG v1\n\nhQIMA0t4uZHfl9qgAQ/9GNa5B4AkO7UODicvjpsgEGLd++1mJteKOwww/08src+H\nnfe/VtTvOdCNVNwvkeKtANvM5DCX9RVTjul4SH7iKd/O9XmTFXA66fhgAbRmEczm\npzQXog/res0u/q+mVwdSDqx/6qBViIcz1Zgc5oFnAneRlAke2/UsNFuFbtaQDZZh\nuralZFdrLx/DWjqEWXEh9D+caek2z/Tjhl/PQ6JNPEa7aZfMLjuTuaoPkSgd87Zc\ndnz/UL77Wx1zdv/cLtO2XvJhOvi0BF9dkg4evouTtNJs+WjQvkBCAijwdC5JdjTz\nWj4mV4H/YdlOn+j2ng3GGmF6GIX5x9FLLD5a9PjSgHVvAH8ZpXkCVY2U8e7QAW7+\nv3KLKGZFWvke62pmypj3777Z5MBj/SJAlzmuPdCLQCXIIpozqK4N4qTvg4Rt5TsN\n8YH9HYfWhX6fHvd67alwrz4IV3g1LgCKCGQd0EXl8pjYwErspGym3UOyZKSD4dDb\nH8zdbr2bQxZ2dJR3o+DVTdohfFjxUqHAZ8bO3vkUT4xblY8n2NnIUWxw3tDHdV/6\niXWVfRcgsIRmFM8qZ7CwwxDZFgLGY3oPhzNmze+B1g5xMG/l4MbKwjCb2EQ38CDr\nDG11GMG5ewhZUDwry4aDpxQMUhvuLBupve+caHzs62zTyWxurwLwfzOHbUyCxbjS\nXAEQ++zCoKncWsAxJdaoIvAvTJBEJeRyGToPESe8iYjmkT1jYZCMj30opOmOZ94M\nE0X4OYpb8FGL/QhOASMe8eW+wYUycySePsQZaQfdIkky7olIsMTBQmSxB16D\n=lXuh\n-----END PGP MESSAGE-----\n", "fp": "85D77543B3D624B63CEA9E6DBC17301B491B3F21"}]} \ No newline at end of file +SOPS={"attention": "This section contains key material that should only be modified with extra care. See `sops -h`.", "kms": [{"arn": "arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e", "created_at": 1444233233.692422, "enc": "CiC6yCOtzsnFhkfdIslYZ0bAf//gYLYCmIu87B3sy/5yYxKnAQEBAgB4usgjrc7JxYZH3SLJWGdGwH//4GC2ApiLvOwd7Mv+cmMAAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAxatks17s0ZWQIyPi8CARCAO65vxmVs4SOASbNDdnwdeOlg75rz7oeqWId2JyQU8sNyz7+TNvvsLIjIR50AGMwnbMIgTmbM99LDi6Vo"}, {"arn": "arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d", "created_at": 1444233235.129884, "enc": "CiBdfsKZbRNf/Li8Tf2SjeSdP76DineB1sbPjV0TV+meTxKnAQEBAgB4XX7CmW0TX/y4vE39ko3knT++g4p3gdbGz41dE1fpnk8AAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzI3YJKPROE+fG2vJYCARCAO2IeX+3IeMkOOOsQauVrUTP9FVFmcmpXYDT41PDt8nhFvU/Q9RUUoVG1OLeWK+KBDZgu1NWGeUTN3TTs"}], "mac": "ENC[AES256_GCM,data:k6Y50bHFLFSgMLOUa7TnX7OzdPf+DAHYySIW4ASNRBE7pkKrn9TY0NEXgeYaWxGeVpE66c12fr9m8s483xjCOw9zBbjxsVF5myUX2SfguYH5giHuf7XvpzEp8d+zRh15CktOLdexipo39xuHPtr8iXz0MogVhG0IOelCHew0LN8=,iv:LG7hsalNUjna9ORMQP8RTWVVdpmEgxe7VFgKyX2RiHs=,tag:YNJWewM6/4MoaPRwt3z3LA==,type:str]", "pgp": [{"created_at": 1444233235.135862, "enc": "-----BEGIN PGP MESSAGE-----\nVersion: GnuPG v1\n\nhQIMA0t4uZHfl9qgAQ/9GNa5B4AkO7UODicvjpsgEGLd++1mJteKOwww/08src+H\nnfe/VtTvOdCNVNwvkeKtANvM5DCX9RVTjul4SH7iKd/O9XmTFXA66fhgAbRmEczm\npzQXog/res0u/q+mVwdSDqx/6qBViIcz1Zgc5oFnAneRlAke2/UsNFuFbtaQDZZh\nuralZFdrLx/DWjqEWXEh9D+caek2z/Tjhl/PQ6JNPEa7aZfMLjuTuaoPkSgd87Zc\ndnz/UL77Wx1zdv/cLtO2XvJhOvi0BF9dkg4evouTtNJs+WjQvkBCAijwdC5JdjTz\nWj4mV4H/YdlOn+j2ng3GGmF6GIX5x9FLLD5a9PjSgHVvAH8ZpXkCVY2U8e7QAW7+\nv3KLKGZFWvke62pmypj3777Z5MBj/SJAlzmuPdCLQCXIIpozqK4N4qTvg4Rt5TsN\n8YH9HYfWhX6fHvd67alwrz4IV3g1LgCKCGQd0EXl8pjYwErspGym3UOyZKSD4dDb\nH8zdbr2bQxZ2dJR3o+DVTdohfFjxUqHAZ8bO3vkUT4xblY8n2NnIUWxw3tDHdV/6\niXWVfRcgsIRmFM8qZ7CwwxDZFgLGY3oPhzNmze+B1g5xMG/l4MbKwjCb2EQ38CDr\nDG11GMG5ewhZUDwry4aDpxQMUhvuLBupve+caHzs62zTyWxurwLwfzOHbUyCxbjS\nXAEQ++zCoKncWsAxJdaoIvAvTJBEJeRyGToPESe8iYjmkT1jYZCMj30opOmOZ94M\nE0X4OYpb8FGL/QhOASMe8eW+wYUycySePsQZaQfdIkky7olIsMTBQmSxB16D\n=lXuh\n-----END PGP MESSAGE-----\n", "fp": "85D77543B3D624B63CEA9E6DBC17301B491B3F21"}], "version": 0.8} \ No newline at end of file diff --git a/example.yaml b/example.yaml index 77801b829..9e5194ca4 100644 --- a/example.yaml +++ b/example.yaml @@ -14,7 +14,7 @@ an_array: - ENC[AES256_GCM,data:oAkO6uRAV70w+ZOSScMLzUk5rtwybj0epc2tesZkeXuNuM9R0I8l34yQ2/jjCEgLcGYtqB6+i4ljGg==,iv:bniytY7Y+oZen0T3OjBBlQMoHVx4TwnYUI5IgHbf2AY=,tag:7CRdL76zQkwbumga9kWgsg==,type:str] - ENC[AES256_GCM,data:n5ZMVViz/IZwqRDgIljrQg==,iv:8A9X2UyYwyGsFKwoTO1MH69MCpUa31QJ3jSgde9i2Pc=,tag:vG4j9Y01cVg+oJ7peeA6PQ==,type:str] sops: - mac: ENC[AES256_GCM,data:rNiflHDZo2IayVwE4Wghr1VObZ4TDvg45qurpEK0+BCdi5KoNXrfmWuAr9O8baBNYvMTfPC4Yi1Yuu6bwk7NU0+uzKmWFZxGjC4GH9dAbyg5dTMF1WFIug+91wBoUC3lWwZ+ltwMvbfshNvGGebvoPlnONsM6NYC51u8s58/Hmk=,iv:M+XC1Yue8b7LW/DZl0NsQJaQFjBZagc7xZC2+PffoC4=,tag:MjDeR64LXMi7jX6WE8LEww==,type:str] + mac: ENC[AES256_GCM,data:sTti+RCOa7zLNhcgqiMTG7ikbYEr34WqESP+38M1KdF2tIADPNLe4JuRZlhRLbdKYuBhhOG+pAHpMyzz0DMlFHTzONACFL1CMivBj0ZyjZtaXLke8HXFO4wK4/7qEzTXBA2JrxzL4x3qSQYCRE+rKjhiWa8xHdS35dN8rjejPA4=,iv:mqb80ZfTgROVilsEr2XIWVycJJZSCpo3ZAGKKrki4+M=,tag:tWrQOMgxPlIISMGV3/UJbg==,type:str] attention: This section contains key material that should only be modified with extra care. See `sops -h`. kms: @@ -24,6 +24,7 @@ sops: - created_at: 1444233192.474385 enc: CiBdfsKZbRNf/Li8Tf2SjeSdP76DineB1sbPjV0TV+meTxKnAQEBAgB4XX7CmW0TX/y4vE39ko3knT++g4p3gdbGz41dE1fpnk8AAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAww2lEDZcq5evsCFcACARCAOxuzZh55fs9x7WE/ZpiRKIG85bvTWVn8wFnFozK/dT3tlPmNv5JwGiXQw1BG6e+fw31npvcGoIvzkwje arn: arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d + version: 0.8 pgp: - fp: 85D77543B3D624B63CEA9E6DBC17301B491B3F21 created_at: 1444233192.486551 diff --git a/setup.py b/setup.py index 67353b601..4bec5b2bc 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ def read(fname): setup( name="sops", py_modules=['sops'], - version="0.7", + version="0.8", author="Julien Vehent", author_email="jvehent@mozilla.com", description="Secrets OPerationS (sops) is an editor of encrypted files", diff --git a/sops/__init__.py b/sops/__init__.py index 90a300b95..02b30c8dc 100644 --- a/sops/__init__.py +++ b/sops/__init__.py @@ -35,19 +35,17 @@ else: import json from collections import OrderedDict +VERSION = 0.8 DESC = """ `sops` is an encryption manager and editor for files that contains secrets. -`sops` supports both AWS, KMS and PGP encryption: - +`sops` supports AWS KMS and PGP encryption: * To encrypt or decrypt a document with AWS KMS, specify the KMS ARN in the `-k` flag or in the ``SOPS_KMS_ARN`` environment variable. (you need valid credentials in ~/.aws/credentials) - * To encrypt or decrypt using PGP, specify the PGP fingerprint in the - `-g` flag or in the ``SOPS_PGP_FP`` environment variable. - + `-p` flag or in the ``SOPS_PGP_FP`` environment variable. Those flags are ignored if the document already stores encryption info. Internally the KMS and PGP key IDs are stored in the document under ``sops.kms`` and ``sops.pgp``. @@ -120,7 +118,7 @@ def main(): help="file to edit; create it if it doesn't exist") argparser.add_argument('-k', '--kms', dest='kmsarn', help="ARN of KMS key used for encryption") - argparser.add_argument('-g', '--pgp', dest='pgpfp', + argparser.add_argument('-p', '--pgp', dest='pgpfp', help="fingerprint of PGP key for decryption") argparser.add_argument('-d', '--decrypt', action='store_true', dest='decrypt', @@ -344,46 +342,69 @@ def verify_or_create_sops_branch(tree, kms_arns=None, pgp_fps=None): indicate that an encryption is needed when returning. """ + need_new_data_key = False if 'sops' not in tree: tree['sops'] = OrderedDict() tree['sops']['attention'] = 'This section contains key material' + \ ' that should only be modified with extra care. See `sops -h`.' + tree['sops']['version'] = VERSION + if 'kms' in tree['sops'] and isinstance(tree['sops']['kms'], list): # check that we have at least one ARN to work with for entry in tree['sops']['kms']: if 'arn' in entry and entry['arn'] != "" and entry['enc'] != "": - return tree, False + return tree, need_new_data_key + # if we're here, no arn was found if 'pgp' in tree['sops'] and isinstance(tree['sops']['pgp'], list): # check that we have at least one fingerprint to work with for entry in tree['sops']['pgp']: if 'fp' in entry and entry['fp'] != "" and entry['enc'] != "": - return tree, False - # if we're here, no fingerprint was found either + return tree, need_new_data_key + + # if we're here, no pgp fingerprint was found either has_at_least_one_method = False + need_new_data_key = True if not (kms_arns is None): - tree['sops']['kms'] = list() - for arn in kms_arns.split(','): - arn = arn.replace(" ", "") - entry = {} - rolepos = arn.find("+arn:aws:iam::") - if rolepos > 0: - entry = {"arn": arn[:rolepos], "role": arn[rolepos+1:]} - else: - entry = {"arn": arn} - tree['sops']['kms'].append(entry) - has_at_least_one_method = True + tree, has_at_least_one_method = parse_kms_arn(tree, kms_arns) if not (pgp_fps is None): - tree['sops']['pgp'] = list() - for fp in pgp_fps.split(','): - entry = {"fp": fp.replace(" ", "")} - tree['sops']['pgp'].append(entry) - has_at_least_one_method = True + tree, has_at_least_one_method = parse_pgp_fp(tree, pgp_fps) if not has_at_least_one_method: panic("Error: No KMS ARN or PGP Fingerprint found to encrypt the data " "key, read the help (-h) for more information.", 111) - # return True to indicate an encryption key needs to be created - return tree, True + return tree, need_new_data_key + + +def parse_kms_arn(tree, kms_arns): + """Take a string that contains one or more KMS ARNs, possibly with roles, + and transform them it into KMS entries of the sops tree + """ + has_at_least_one_method = False + tree['sops']['kms'] = list() + for arn in kms_arns.split(','): + arn = arn.replace(" ", "") + entry = {} + rolepos = arn.find("+arn:aws:iam::") + if rolepos > 0: + entry = {"arn": arn[:rolepos], "role": arn[rolepos+1:]} + else: + entry = {"arn": arn} + tree['sops']['kms'].append(entry) + has_at_least_one_method = True + return tree, has_at_least_one_method + + +def parse_pgp_fp(tree, pgp_fps): + """Take a string of PGP fingerprint + and create pgp entries in the sops tree + """ + has_at_least_one_method = False + tree['sops']['pgp'] = list() + for fp in pgp_fps.split(','): + entry = {"fp": fp.replace(" ", "")} + tree['sops']['pgp'].append(entry) + has_at_least_one_method = True + return tree, has_at_least_one_method def update_sops_branch(tree, key): @@ -410,6 +431,14 @@ def update_sops_branch(tree, key): print("updating pgp entry") updated = encrypt_key_with_pgp(key, entry) tree['sops']['pgp'][i] = updated + + # update version number if newer than current + if 'version' in tree['sops']: + if tree['sops']['version'] < VERSION: + tree['sops']['version'] = VERSION + else: + tree['sops']['version'] = VERSION + return tree