Загрузка данных


#!/usr/bin/env python3

"""
Получение секретов MailArchive из Vault.

Запуск:

python vault_sync.py --env dev

Подготовить .env:

VAULT_ADDR=https://vault.company.ru
VAULT_USERNAME=svc_mailarchive_builder
VAULT_PASSWORD=super_secret_password
"""

import argparse
import base64
import os
from pathlib import Path

import hvac
from dotenv import load_dotenv

VAULT_MOUNT = "it-infradev"


def vault_login():
    """
    LDAP login в Vault.
    """

    client = hvac.Client(
        url=os.environ["VAULT_ADDR"]
    )

    login = client.auth.ldap.login(
        username=os.environ["VAULT_USERNAME"],
        password=os.environ["VAULT_PASSWORD"]
    )

    client.token = login["auth"]["client_token"]

    if not client.is_authenticated():
        raise RuntimeError(
            "Vault authentication failed"
        )

    return client


def read_secret(client, path):

    response = (
        client.secrets.kv.v2.read_secret_version(
            mount_point=VAULT_MOUNT,
            path=path
        )
    )

    return response["data"]["data"]


def write_text(path, content):

    path.parent.mkdir(
        parents=True,
        exist_ok=True
    )

    with open(path, "w") as f:
        f.write(content)


def write_binary(path, content):

    path.parent.mkdir(
        parents=True,
        exist_ok=True
    )

    with open(path, "wb") as f:
        f.write(content)


def main():

    load_dotenv()

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--env",
        choices=["dev", "stage", "prod"],
        required=True
    )

    args = parser.parse_args()

    env = args.env

    client = vault_login()

    base = f"projects/mailarchive/{env}"

    #
    # Получаем секреты
    #

    django = read_secret(
        client,
        f"{base}/django"
    )

    webserver = read_secret(
        client,
        f"{base}/webserver"
    )

    k5 = read_secret(
        client,
        f"{base}/k5-ma-client"
    )

    #
    # Итоговая структура:
    #
    # build/
    # ├── django
    # ├── webserver
    # └── k5-ma-client
    #

    build_dir = Path("build")

    ####################################################################
    # DJANGO
    ####################################################################

    #
    # Предполагается что в Vault лежит поле:
    #
    # env
    #

    write_text(
        build_dir /
        "django" /
        ".env",
        django["env"]
    )

    ####################################################################
    # K5 CLIENT
    ####################################################################

    #
    # Предполагается:
    #
    # principal
    # keytab
    #

    write_text(
        build_dir /
        "k5-ma-client" /
        "principal",
        k5["principal"]
    )

    write_binary(
        build_dir /
        "k5-ma-client" /
        "service.keytab",
        base64.b64decode(
            k5["keytab"]
        )
    )

    ####################################################################
    # WEBSERVER
    ####################################################################

    #
    # НАЗВАНИЯ ПОЛЕЙ ПРИДЁТСЯ
    # ПОДОГНАТЬ ПОД ТВОЙ VAULT
    #

    write_text(
        build_dir /
        "webserver" /
        "server.crt",
        webserver["ssl_cert"]
    )

    write_text(
        build_dir /
        "webserver" /
        "server.key",
        webserver["ssl_key"]
    )

    write_binary(
        build_dir /
        "webserver" /
        "ldap.keytab",
        base64.b64decode(
            webserver["ldap_keytab"]
        )
    )

    #
    # Тут пока просто пример.
    #
    # Я бы потом заменил на Jinja2.
    #

    vhost = f"""
<VirtualHost *:443>

ServerName {webserver['server_name']}

SSLEngine on

SSLCertificateFile /etc/httpd/ssl/server.crt
SSLCertificateKeyFile /etc/httpd/ssl/server.key

</VirtualHost>
"""

    write_text(
        build_dir /
        "webserver" /
        "vhost.conf",
        vhost
    )

    print()
    print("Secrets downloaded successfully")
    print(f"Environment: {env}")
    print(f"Output dir: {build_dir.resolve()}")


if __name__ == "__main__":
    main()