Commit cc5ef01e authored by ale's avatar ale

Support includes in passwords.yml

Distribute a default passwords.yml file for users to include. Mirrors
the setup used for services.yml.
parent 58aae5bb
- name: sso_session_auth_secret
description: sso-server cookie auth key
type: binary
length: 64
- name: sso_session_enc_secret
description: sso-server cookie encryption key
type: binary
length: 16
- name: sso_csrf_secret
description: sso-server cookie-based CSRF secret
type: binary
length: 64
- name: sso_device_manager_auth_secret
description: sso-server cookie-based device manager secret
type: binary
length: 64
- name: ssoproxy_session_auth_key
description: sso-proxy cookie authentication key
type: binary
length: 64
- name: ssoproxy_session_enc_key
description: sso-proxy cookie encryption key
type: binary
length: 32
- name: ldap_root_password
description: LDAP cn=manager password
- name: ldap_replica_password
description: LDAP cn=replica password
- name: ldap_authserver_password
description: LDAP cn=authserver password
- name: ldap_keystore_password
description: LDAP cn=keystore password
- name: ldap_accountserver_password
description: LDAP cn=accountserver password
- name: grafana_session_secret
description: session secret for Grafana
length: 32
- name: acme_tsig_key
type: tsig
......@@ -27,6 +27,10 @@
# First of all, generate secrets from the passwords.yml file.
- name: Initialize secrets
local_action: command ../scripts/pwgen.py --vars "{{ credentials_dir }}/secrets.yml" "{{ passwords_file }}"
register: pwgen_result
changed_when: "pwgen_result.rc == 1"
failed_when: "pwgen_result.rc > 1"
- name: Link secrets.yml from the vars directory
file:
src: "{{ credentials_dir }}/secrets.yml"
......
......@@ -6,18 +6,49 @@
from __future__ import print_function
import argparse
import base64
import sys
import optparse
import os
import random
import shutil
import subprocess
import string
import sys
import tempfile
import yaml
# Possible exit codes for this program.
EXIT_NOTHING_TO_DO = 0
EXIT_CHANGED = 1
EXIT_ERROR = 2
# Returns the absolute path to a file. If the given path is relative,
# it will be evaluated based on the given path_reference.
def _abspath(path, relative_to='/'):
if path.startswith('/'):
return path
return os.path.abspath(os.path.join(os.path.dirname(relative_to), path))
# A version of yaml.safe_load that supports the special 'include'
# top-level attribute and recursively merges included files.
def _read_yaml(path):
with open(path) as fd:
data = yaml.safe_load(fd)
if not isinstance(data, list):
raise Exception('data in %s is not a list' % (path,))
# Find elements that include other files.
out = []
for entry in data:
if 'include' in entry:
out.extend(_read_yaml(_abspath(entry['include'], path)))
else:
out.append(entry)
return out
def decrypt(src):
return subprocess.check_output(
['ansible-vault', 'decrypt', '--output=-', src])
......@@ -99,38 +130,48 @@ def generate_password(entry):
def main():
parser = optparse.OptionParser(usage='%prog <password file>')
parser.add_option('--vars', metavar='FILE', dest='vars',
default='vars/passwords',
help='Output vars file')
opts, args = parser.parse_args()
if len(args) != 1:
parser.error('Not enough arguments')
parser = argparse.ArgumentParser(description='''
Autogenerate secrets for use with Ansible.
Secrets are encrypted with Ansible Vault, so the
ANSIBLE_VAULT_PASSWORD_FILE environment variable must be defined.
''')
parser.add_argument(
'--vars', metavar='FILE', dest='vars_file',
help='Output vars file')
parser.add_argument(
'password_file',
help='Secrets metadata')
args = parser.parse_args()
if not os.getenv('ANSIBLE_VAULT_PASSWORD_FILE'):
print("You need to set ANSIBLE_VAULT_PASSWORD_FILE", file=sys.stderr)
sys.exit(2)
raise Exception("You need to set ANSIBLE_VAULT_PASSWORD_FILE")
password_file = args[0]
vars_file = opts.vars
passwords = {}
if os.path.exists(vars_file):
passwords.update(yaml.load(decrypt(vars_file)))
if os.path.exists(args.vars_file):
passwords.update(yaml.safe_load(decrypt(args.vars_file)))
changed = False
with open(password_file) as fd:
for entry in yaml.load(fd):
name = entry['name']
if name not in passwords:
print("Generating password for '%s'" % name, file=sys.stderr)
passwords[name] = generate_password(entry)
changed = True
for entry in _read_yaml(args.password_file):
name = entry['name']
if name not in passwords:
print("Generating password for '%s'" % name, file=sys.stderr)
passwords[name] = generate_password(entry)
changed = True
if changed:
encrypt(yaml.dump(passwords), vars_file)
encrypt(yaml.dump(passwords), args.vars_file)
return EXIT_CHANGED
return EXIT_NOTHING_TO_DO
if __name__ == '__main__':
main()
try:
sys.exit(main())
except Exception as e:
print("Error: %s" % str(e), file=sys.stderr)
sys.exit(EXIT_ERROR)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment