diff --git a/.gitignore b/.gitignore index a8b42eb6..7b00ee5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.retry +scripts/inventory_re2o.ini +__pycache__ diff --git a/ansible.cfg b/ansible.cfg index 8d528bd6..94ea095d 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -5,7 +5,8 @@ # Do not create .retry files retry_files_enabled = False -# Use inventory +# Generate inventory +#inventory = ./scripts/inventory_re2o.py inventory = ./hosts # Custom header in templates diff --git a/group_vars/all/vault.yml b/group_vars/all/vault.yml deleted file mode 100644 index 39ef710a..00000000 --- a/group_vars/all/vault.yml +++ /dev/null @@ -1,40 +0,0 @@ -$ANSIBLE_VAULT;1.1;AES256 -37373933363563303566623732633165343839663164663535316638633462626636326135316534 -3839346634623331363336663863353363376665613764390a383866613635363238323637386235 -61623963366463636561346162616532626133306165343161393333616363656339643933393531 -6662343239653361320a633064306238363836346166653931356334376537636266646237323438 -65316261636463336261643831653661383863346633323764346339373834363433373730383861 -64613139366566653035656531363933313234343265653535636464323839336165653637323432 -61386236383830663230613335303437633737346232316135353262396433376439643562353438 -62393431396262383965303436663431326239626666353735636465656530333236326137313062 -38323866346433646261633633373031346334396561323536376563363035633565643137346137 -33393930326166303439623463623631333339383566383565363536333036626630303130633432 -32646364336665363966626665323465346363346137636536303362663935643831326536633739 -34353361656635623965383332643936336663373330653563353837353230326531366238353035 -32356465653966643831633963623239666136393436663932353366633231343534626234336539 -32663133616162366238323635616531373335383535653732373432613938396535343339383037 -37376461646438383434633364373339303137333134333138323630633731366533633061373634 -38353034356332373134373833393431346539306265313965623663343433343361613634646563 -35383234623362633935383362393763363938643864373266336339373265353933336232303965 -61666133356430663764323437373632643533333066616232336236633164363965356339326161 -63626437663736666536373965316230303239653764356338613638623233643835383637386661 -38616330623739306338396639323739383661363431396531613963393732396433346363616438 -33303030663231313263616163346563336631643563316465373866383162356562653165333766 -33333966303932396336393263363039383930353334313061316335313238363564313639646637 -34316562386366306238376465326631336539643936663264306631303335346131343939663965 -62316566393236643938633731356465373435646238646661333935323563333231363361663638 -31313832613032636466316263386561363665333432653931393835346535653837303937363764 -65353561326162313831303865393665353732346536653262316131643863373039636336616132 -38666362363137663266306634346438636430353036616536613332376535633662326432383431 -66353539376132373165633634376230393738393831313831663535613430633937383732356163 -32356639626237303861336364376663306465393130373136366461666233626333346437316563 -65616132326637313134656665323439366362613634376536373631656234343934396532333539 -62306163313062393365613338326464633136376562383130303638616364366139373734346236 -36333665306666633465396437633161356664643235326665633537666366316662643339626430 -66393335343463663662363561626534386435373636626131393263626664336164633062393239 -39613737383834363661343662323436326236326464343732326232316264303135613035323039 -62313539363532333738343664663830373163346436636533663164333438623338623332303136 -37633065336162326361333430363464656662626237366530343765643937333866373831666336 -36333363633830343836383235613562633435663166386264343936666264323561343938393232 -38323235636266616266333535376661663063363562376461336437376661633734633165326661 -326437613235333261643465663663343838 diff --git a/scripts/inventory_re2o.ini.example b/scripts/inventory_re2o.ini.example new file mode 100644 index 00000000..582e09ab --- /dev/null +++ b/scripts/inventory_re2o.ini.example @@ -0,0 +1,7 @@ +# Ansible Re2o Inventory settings +# + +[Re2o] +hostname = re2o.example.net +username = my_api_username +password = my_api_password diff --git a/vars_plugins/vault_cranspassword.ini b/vars_plugins/vault_cranspassword.ini new file mode 100644 index 00000000..2df78e29 --- /dev/null +++ b/vars_plugins/vault_cranspassword.ini @@ -0,0 +1,6 @@ +# Ansible Vault CransPassword settings +# + +[cranspassword] +#: Commande exécutée sur le client pour appeler le script sur le serveur distant. +server_cmd=/usr/bin/ssh odlyd.crans.org sudo -n /usr/local/bin/cranspasswords-server diff --git a/vars_plugins/vault_cranspassword.py b/vars_plugins/vault_cranspassword.py new file mode 100755 index 00000000..886b69f6 --- /dev/null +++ b/vars_plugins/vault_cranspassword.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +# (c) 2019 Cr@ns +# Authors : Alexandre IOOSS +# Based on cranspasswords by : Daniel Stan +# Vincent Le Gallic +# +# This file is part of Cr@ns ansible deploiement + +""" +Ansible Vault CransPassword script. +======================================== + +Returns Ansible vault from CransPassword. + +Configuration is read from `vault_cranspassword.ini`. +""" + +import json +import os +import subprocess +import sys + +from ansible.module_utils.six.moves import configparser +from ansible.plugins.vars import BaseVarsPlugin + + +class VarsModule(BaseVarsPlugin): + @staticmethod + def gpg_decrypt(crypt_text): + full_command = ['gpg', '-d'] + proc = subprocess.Popen(full_command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=sys.stderr, + close_fds=True) + proc.stdin.write(crypt_text.encode()) + proc.stdin.close() + clear_text = proc.stdout.read().decode() + return clear_text + + def getfile_command(self, filename): + """Exécute la commande distante, et retourne la sortie de cette + commande""" + # Get full command from settings file + command = self.config.get('cranspassword', 'server_cmd').split(" ") + command.append("getfiles") + proc = subprocess.Popen( + command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=sys.stderr, + close_fds=True + ) + proc.stdin.write(json.dumps([filename]).encode()) + proc.stdin.flush() + + raw_out, raw_err = proc.communicate() + ret = proc.returncode + + if ret != 0: + print("Mauvais code retour côté serveur", file=sys.stderr) + sys.exit(ret) + + try: + answer = json.loads(raw_out.strip()) + except ValueError: + print("Impossible de parser le résultat", file=sys.stderr) + sys.exit(42) + + return answer[0] + + def get_encrypted(self, filename): + """ + Get encrypted content of a cranspassword file + """ + gotit, value = self.getfile_command(filename) + if not gotit: + print(value, file=sys.stderr) # value contient le message d'erreur + else: + crypt_text = value['contents'] + return crypt_text + + def __init__(self): + super().__init__() + + # Load config + self.config = configparser.ConfigParser() + self.config.read(os.path.dirname(os.path.realpath(__file__)) + + '/vault_cranspassword.ini') + + def get_vars(self, loader, path, entities, cache=True): + """ + Get all vars for entities, called by Ansible + """ + super().get_vars(loader, path, entities) + + # We do not want to request N time the same file from cranspassword + # But VarsModule object get instanced each time + # So the hack is to use loader._FILE_CACHE that *should* be private + # Sorry for this, don't judge me on this please <3 + + if 'cranspassword' not in loader._FILE_CACHE: + # Get text then decrypt and return + crypt_text = self.get_encrypted('ansible_vault') + clear_text = self.gpg_decrypt(crypt_text) + data = loader.load(clear_text) + loader._FILE_CACHE['cranspassword'] = data + else: + data = loader._FILE_CACHE['cranspassword'] + + return data