コード例 #1
0
ファイル: vault.py プロジェクト: inferiorhumanorgans/aomi
def initial_token(vault_client, opt):
    """Generate our first token based on workstation configuration"""
    token_file = os.environ.get('VAULT_TOKEN_FILE',
                                "%s/.vault-token" % os.environ['HOME'])
    app_file = os.environ.get('AOMI_APP_FILE',
                              "%s/.aomi-app-token" % os.environ['HOME'])
    token_file = os.path.abspath(token_file)
    app_file = os.path.abspath(app_file)
    if 'VAULT_TOKEN' in os.environ and len(os.environ['VAULT_TOKEN']) > 0:
        log('Token derived from VAULT_TOKEN environment variable', opt)
        return os.environ['VAULT_TOKEN'].strip()
    elif 'VAULT_USER_ID' in os.environ and \
         'VAULT_APP_ID' in os.environ and \
         len(os.environ['VAULT_USER_ID']) > 0 and \
         len(os.environ['VAULT_APP_ID']) > 0:
        token = app_token(vault_client, os.environ['VAULT_APP_ID'].strip(),
                          os.environ['VAULT_USER_ID'].strip())
        log("Token derived from VAULT_APP_ID and VAULT_USER_ID", opt)
        return token
    elif os.path.exists(app_file):
        token = yaml.load(open(app_file).read().strip())
        if 'app_id' in token and 'user_id' in token:
            token = app_token(vault_client, token['app_id'], token['user_id'])
            log("Token derived from %s" % app_file, opt)
            return token
    elif os.path.exists(token_file):
        log("Token derived from %s" % token_file, opt)
        return open(token_file, 'r').read().strip()
    else:
        problems('Unable to determine vault authentication method')
コード例 #2
0
def files(client, secret, opt):
    """Seed files into Vault"""
    if 'mount' not in secret or 'path' not in secret:
        problems("Invalid files specification %s" % secret)

    obj = {}
    vault_path = "%s/%s" % (secret['mount'], secret['path'])
    if not is_tagged(secret.get('tags', []), opt.tags):
        log("Skipping %s as it does not have appropriate tags" % vault_path,
            opt)
        return

    for f in secret.get('files', []):
        if 'source' not in f or 'name' not in f:
            problems("Invalid file specification %s" % f)

        filename = hard_path(f['source'], opt.secrets)
        data = open(filename, 'r').read()
        obj[f['name']] = data
        log('writing file %s into %s/%s' % (filename, vault_path, f['name']),
            opt)

    ensure_mounted(client, 'generic', secret['mount'])

    client.write(vault_path, **obj)
コード例 #3
0
ファイル: vault.py プロジェクト: inferiorhumanorgans/aomi
def app_token(vault_client, app_id, user_id):
    """Returns a vault token based on the app and user id."""
    resp = vault_client.auth_app_id(app_id, user_id)
    if 'auth' in resp and 'client_token' in resp['auth']:
        return resp['auth']['client_token']
    else:
        problems('Unable to retrieve app token')
コード例 #4
0
def ensure_mounted(client, backend, mount):
    """Will ensure a mountpoint exists, or bail with a polite error"""
    backends = client.list_secret_backends()
    if not is_mounted(mount, backends, backend):
        try:
            client.enable_secret_backend(backend, mount_point=mount)
        except hvac.exceptions.InvalidRequest as e:
            m = re.match('existing mount at (?P<path>.+)', str(e))
            if m:
                problems("%s has a mountpoint conflict with %s" %
                         (mount, m.group('path')))
コード例 #5
0
def subdir_file(item, relative):
    """Returns a file path relative to another file."""
    item_bits = item.split(os.sep)
    relative_bits = relative.split(os.sep)
    for i in range(0, len(item_bits)):
        if i == len(relative_bits) - 1:
            return os.sep.join(item_bits[i:])
        else:
            if item_bits[i] != relative_bits[i]:
                problems("gitignore and secrets paths diverge!")

    return None
コード例 #6
0
def raw_file(client, src, dest):
    """Write the contents of a vault path/key to a file"""
    path_bits = src.split('/')
    path = '/'.join(path_bits[0:len(path_bits) - 1])
    key = path_bits[len(path_bits) - 1]
    resp = client.read(path)
    if not resp:
        problems("Unable to retrieve %s" % path)
    else:
        if 'data' in resp and key in resp['data']:
            secret = resp['data'][key]
            open(os.path.abspath(dest), 'w').write(secret)
        else:
            problems("Key %s not found in %s" % (key, path))
コード例 #7
0
def template(client, src, dest, vault_path):
    """Writes a template using variables from a vault path"""
    template_src = Template(open(os.path.abspath(src), 'r').read())
    secrets = client.read(vault_path)
    if not secrets:
        problems("Unable to retrieve %s" % vault_path)

    obj = {}
    for k, v in secrets['data'].items():
        norm_path = [x for x in vault_path.split('/') if x]
        v_name = ("%s_%s" % ('_'.join(norm_path), k)).lower()
        obj[v_name] = v

    output = template_src.render(**obj)
    open(os.path.abspath(dest), 'w').write(output)
コード例 #8
0
ファイル: vault.py プロジェクト: inferiorhumanorgans/aomi
def seed(vault_client, opt):
    """Will provision vault based on the definition within a Secretfile"""
    config = yaml.load(open(os.path.abspath(opt.secretfile)).read())
    for secret in config.get('secrets', []):
        if 'var_file' in secret:
            aomi.seed.var_file(vault_client, secret, opt)
        elif 'aws_file' in secret:
            aomi.seed.aws(vault_client, secret, opt)
        elif 'files' in secret:
            aomi.seed.files(vault_client, secret, opt)
        else:
            problems("Invalid secret element %s" % secret)

    for app in config.get('apps', []):
        if 'app_file' in app:
            aomi.seed.app(vault_client, app, opt)
        else:
            problems("Invalid app element %s" % app)
コード例 #9
0
def aws(client, path, opt):
    """Renders a shell environment snippet with AWS information"""
    creds = client.read(path)
    if creds and 'data' in creds:
        print("AWS_ACCESS_KEY_ID=\"%s\"" % creds['data']['access_key'])
        print("AWS_SECRET_ACCESS_KEY=\"%s\"" % creds['data']['secret_key'])
        if 'security_token' in creds['data'] \
           and creds['data']['security_token']:
            token = creds['data']['security_token']
            print("AWS_SECURITY_TOKEN=\"%s\"" % token)
    else:
        problems("Unable to generate AWS credentials from %s" % path)

    if opt.export:
        print("export AWS_ACCESS_KEY_ID")
        print("export AWS_SECRET_ACCESS_KEY")
        if 'security_token' in creds['data'] \
           and creds['data']['security_token']:
            print("export AWS_SECURITY_TOKEN")
コード例 #10
0
def var_file(client, secret, opt):
    """Seed a var_file into Vault"""
    path = "%s/%s" % (secret['mount'], secret['path'])
    var_file_name = hard_path(secret['var_file'], opt.secrets)
    varz = yaml.load(open(var_file_name).read())
    if 'var_file' not in secret \
       or 'mount' not in secret \
       or 'path' not in secret:
        problems("Invalid generic secret definition %s" % secret)

    if not is_tagged(secret.get('tags', []), opt.tags):
        log("Skipping %s as it does not have appropriate tags" % path, opt)
        return

    ensure_mounted(client, 'generic', secret['mount'])

    client.write(path, **varz)
    log(
        'wrote var_file %s into %s/%s' %
        (var_file_name, secret['mount'], secret['path']), opt)
コード例 #11
0
def aws(client, secret, opt):
    """Seed an aws_file into Vault"""
    if 'aws_file' not in secret or 'mount' not in secret:
        problems("Invalid aws secret definition" % secret)

    aws_file_path = hard_path(secret['aws_file'], opt.secrets)
    aws_obj = yaml.load(open(aws_file_path, 'r').read())

    if 'access_key_id' not in aws_obj \
       or 'secret_access_key' not in aws_obj \
       or 'region' not in aws_obj \
       or 'roles' not in aws_obj:
        problems("Invalid AWS secrets" % aws)

    aws_path = "%s/config/root" % secret['mount']
    if not is_tagged(secret.get('tags', []), opt.tags):
        log("Skipping %s as it does not have appropriate tags" % aws_path, opt)
        return

    ensure_mounted(client, 'aws', secret['mount'])

    obj = {
        'access_key': aws_obj['access_key_id'],
        'secret_key': aws_obj['secret_access_key'],
        'region': aws_obj['region']
    }
    client.write(aws_path, **obj)
    log('wrote aws_file %s into %s' % (aws_file_path, aws_path), opt)

    ttl_obj = {}
    lease_msg = ''
    if 'lease' in aws_obj:
        ttl_obj['lease'] = aws_obj['lease']
        lease_msg = "%s lease:%s" % (lease_msg, ttl_obj['lease'])

    if 'lease_max' in aws_obj:
        ttl_obj['lease_max'] = aws_obj['lease_max']
    else:
        if 'lease' in ttl_obj:
            ttl_obj['lease_max'] = ttl_obj['lease']

    if 'lease_max' in ttl_obj:
        lease_msg = "%s lease_max:%s" % (lease_msg, ttl_obj['lease_max'])

    if ttl_obj:
        client.write("%s/config/lease" % (secret['mount']), **ttl_obj)
        log("Updated lease for %s %s" % (secret['mount'], lease_msg), opt)

    for role in aws_obj['roles']:
        if 'policy' not in role or 'name' not in role:
            problems("Invalid role definition %s" % role)

        data = open(hard_path(role['policy'], opt.policies), 'r').read()
        role_path = "%s/roles/%s" % (secret['mount'], role['name'])
        client.write(role_path, policy=data)
コード例 #12
0
def gitignore(opt):
    """Will check directories upwards from the Secretfile in order
    to ensure the gitignore file is set properly"""
    directory = os.path.dirname(abspath(opt.secretfile))
    gitignore_file = find_file('.gitignore', directory)
    if gitignore_file:
        secrets_path = subdir_file(abspath(opt.secrets), gitignore_file)
        if not secrets_path:
            problems("Unable to determine relative location of secretfile")

        if not in_file(secrets_path, gitignore_file):
            problems("The path %s was not found in %s" %
                     (secrets_path, gitignore_file))
    else:
        problems("You should really have a .gitignore")
コード例 #13
0
def app(client, app_obj, opt):
    """Seed an app file into Vault"""
    if 'app_file' not in app_obj:
        problems("Invalid app definition %s" % app_obj)

    name = None
    if 'name' in app_obj:
        name = app_obj['name']
    else:
        name = os.path.splitext(os.path.basename(app_obj['app_file']))[0]

    if not is_tagged(app_obj.get('tags', []), opt.tags):
        log("Skipping %s as it does not have appropriate tags" % name, opt)
        return

    app_file = hard_path(app_obj['app_file'], opt.secrets)
    data = yaml.load(open(app_file).read())
    if 'app_id' not in data \
       or 'policy' not in data:
        problems("Invalid app file %s" % app_file)

    policy_name = None
    if 'policy_name' in data:
        policy_name = data['policy_name']
    else:
        policy_name = name

    policy = open(hard_path(data['policy'], opt.policies), 'r').read()
    client.set_policy(name, policy)
    app_path = "auth/app-id/map/app-id/%s" % data['app_id']
    app_obj = {'value': policy_name, 'display_name': name}
    client.write(app_path, **app_obj)
    users = data.get('users', [])
    for user in users:
        if 'id' not in user:
            problems("Invalid user definition %s" % user)

        user_path = "auth/app-id/map/user-id/%s" % user['id']
        user_obj = {'value': data['app_id']}
        if 'cidr' in user:
            user_obj['cidr_block'] = user['cidr']

        client.write(user_path, **user_obj)

    log('created %d users in application %s' % (len(users), name), opt)
コード例 #14
0
ファイル: vault.py プロジェクト: inferiorhumanorgans/aomi
def client(operation, opt):
    """Return a vault client"""
    if 'VAULT_ADDR' not in os.environ:
        problems('VAULT_ADDR must be defined')

    vault_host = os.environ['VAULT_ADDR']

    ssl_verify = True
    if 'VAULT_SKIP_VERIFY' in os.environ:
        if os.environ['VAULT_SKIP_VERIFY'] == '1':
            log('Skipping SSL Validation!', opt)
            ssl_verify = False

    log("Connecting to %s" % vault_host, opt)
    vault_client = hvac.Client(vault_host, verify=ssl_verify)
    vault_client.token = initial_token(vault_client, opt)
    if not vault_client.is_authenticated():
        problems("Unable to retrieve initial token")

    vault_client.token = operational_token(vault_client, operation, opt)
    if not vault_client.is_authenticated():
        problems("Unable to retrieve operational token")

    return vault_client