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


#!/usr/bin/env python3

import argparse
import base64
import os
import json
import hvac

from dotenv import load_dotenv
from pathlib import Path
from jinja2 import Environment, FileSystemLoader

VAULT_MOUNT = "it-infradev"


# ============================================================
# VAULT LOGIN
# ============================================================

def vault_login():

    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


# ============================================================
# VAULT READ (DEBUG VERSION)
# ============================================================

def read_secret(client, path):

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

    data = response["data"]["data"]

    print("\n==============================")
    print(f"[VAULT PATH] {path}")
    print("KEYS:", list(data.keys()))

    for k, v in data.items():
        if isinstance(v, str):
            print(f" - {k}: str(len={len(v)}) preview={v[:80]}")
        else:
            print(f" - {k}: {type(v)} value={v}")

    print("==============================\n")

    return data


# ============================================================
# WRITE HELPERS
# ============================================================

def write_text(path, content):

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

    if content is None:
        raise ValueError(f"Trying to write None to {path}")

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


def write_binary(path, content):

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

    if content is None:
        raise ValueError(f"Trying to write None to {path}")

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


# ============================================================
# MAIN
# ============================================================

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}"

    # ============================================================
    # READ SECRETS
    # ============================================================

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

    # ============================================================
    # BUILD DIR
    # ============================================================

    build_dir = Path("build")

    # ============================================================
    # DJANGO
    # ============================================================

    django_env = django.get(".env")

    print("[DJANGO] using key: .env")
    print("[DJANGO] value exists:", django_env is not None)

    if not django_env:
        raise RuntimeError(f"Django missing .env, keys={list(django.keys())}")

    write_text(
        build_dir / "django-ma/src" / ".env",
        django_env
    )

    # ============================================================
    # KERBEROS
    # ============================================================

    print("\n[K5 DEBUG]")
    print("keys:", k5.keys())

    principal = k5.get("KRB_PRINCIPAL")
    keytab_b64 = k5.get("keytab") or k5.get("mailarchive.keytab")

    if not principal:
        raise RuntimeError("Missing principal in k5")

    if not keytab_b64:
        raise RuntimeError("Missing keytab in k5")

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


    write_binary(
        build_dir / "k5-ma-client" / "mailarchive.keytab",
        base64.b64decode(keytab_b64)
    )

    # ============================================================
    # WEBSERVER
    # ============================================================

    prepare_webserver(build_dir, webserver)

    print("\nDONE")
    print(f"Output: {build_dir.resolve()}")


# ============================================================
# WEBSERVER
# ============================================================

def prepare_webserver(build_dir, webserver):

    wd = build_dir / "webserver"
    wd.mkdir(parents=True, exist_ok=True)

    print("\n[WEBSERVER DEBUG]")
    print("keys:", list(webserver.keys()))

    # certs
    if "tls.crt" in webserver:
        write_text(wd / "tls.crt", webserver["tls.crt"])

    if "tls.key" in webserver:
        write_text(wd / "tls.key", webserver["tls.key"])

    # keytab
    keytab = webserver.get("infradev.keytab")

    if keytab:
        write_binary(
            wd / "infradev.keytab",
            base64.b64decode(keytab)
        )

    # template render
    templates_dir = Path("apache-ma/conf/sites-enabled")

    env = Environment(
        loader=FileSystemLoader(str(templates_dir)),
        autoescape=False
    )

    template = env.get_template("mailarchive.conf.j2")

    rendered = template.render(**webserver)

    write_text(wd / "mailarchive.conf", rendered)


if __name__ == "__main__":
    main()