Some checks failed
CI / skip-ci-check (pull_request) Successful in 6s
CI / lint-and-test (pull_request) Failing after 9s
CI / ansible-validation (pull_request) Failing after 6s
CI / secret-scanning (pull_request) Successful in 5s
CI / dependency-scan (pull_request) Successful in 8s
CI / sast-scan (pull_request) Failing after 5s
CI / license-check (pull_request) Successful in 11s
CI / vault-check (pull_request) Failing after 6s
CI / playbook-test (pull_request) Failing after 6s
CI / container-scan (pull_request) Failing after 6s
CI / sonar-analysis (pull_request) Failing after 2s
CI / workflow-summary (pull_request) Successful in 4s
Document pve10 static IPs, monitoring stack, and site LXCs; add portfolio to inventory; Mailcow mailbox automation; vault import/export scripts; security audit guides and UniFi DHCP reference. Co-authored-by: Cursor <cursoragent@cursor.com>
82 lines
2.8 KiB
Bash
Executable File
82 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Write Ansible vault secrets into .env (for local scripts / reference).
|
|
# Does not print secret values. Does not overwrite non-empty .env keys.
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
ENV_FILE="${1:-${REPO_ROOT}/.env}"
|
|
VAULT_FILE="${REPO_ROOT}/inventories/production/group_vars/all/vault.yml"
|
|
VAULT_PASS="${HOME}/.ansible-vault-pass"
|
|
ANSIBLE_VAULT="${REPO_ROOT}/.venv/bin/ansible-vault"
|
|
|
|
[[ -f "${VAULT_PASS}" ]] || { echo "Missing ${VAULT_PASS}" >&2; exit 1; }
|
|
|
|
"${REPO_ROOT}/.venv/bin/python3" - "${ENV_FILE}" "${VAULT_FILE}" "${VAULT_PASS}" "${ANSIBLE_VAULT}" <<'PY'
|
|
import subprocess, sys, yaml
|
|
from pathlib import Path
|
|
|
|
env_file, vault_file, vault_pass, ansible_vault = sys.argv[1:5]
|
|
|
|
# vault key -> .env key
|
|
MAP = {
|
|
"vault_mailcow_api_key": "MAILCOW_API_KEY",
|
|
"vault_alerts_mailbox_password": "ALERTS_PASSWORD",
|
|
"vault_uptime_kuma_password": "KUMA_PASSWORD",
|
|
"vault_uptime_kuma_user": "KUMA_USER",
|
|
"vault_uptime_kuma_url": "KUMA_URL",
|
|
"vault_umami_admin_password": "UMAMI_ADMIN_PASSWORD",
|
|
"vault_umami_db_password": "UMAMI_DB_PASS",
|
|
"vault_umami_app_secret": "UMAMI_APP_SECRET",
|
|
"vault_kuma_smtp_host": "SMTP_HOST",
|
|
"vault_kuma_smtp_port": "SMTP_PORT",
|
|
"vault_kuma_smtp_user": "SMTP_USER",
|
|
"vault_kuma_smtp_password": "SMTP_PASS",
|
|
"vault_kuma_smtp_to": "SMTP_TO",
|
|
"vault_mattermost_url": "MATTERMOST_URL",
|
|
"vault_mattermost_token": "MATTERMOST_TOKEN",
|
|
"vault_mattermost_allowed_users": "MATTERMOST_ALLOWED_USERS",
|
|
}
|
|
|
|
def parse_env(text):
|
|
d = {}
|
|
for line in text.splitlines():
|
|
line = line.strip()
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
k, _, v = line.partition("=")
|
|
d[k.strip()] = v.strip().strip("'").strip('"')
|
|
return d
|
|
|
|
text = subprocess.check_output(
|
|
[ansible_vault, "view", vault_file, "--vault-password-file", vault_pass],
|
|
text=True,
|
|
)
|
|
data = yaml.safe_load(text) or {}
|
|
existing = parse_env(Path(env_file).read_text()) if Path(env_file).exists() else {}
|
|
merged = dict(existing)
|
|
|
|
for vk, ek in MAP.items():
|
|
val = data.get(vk)
|
|
if val is None or val == "":
|
|
continue
|
|
if merged.get(ek):
|
|
continue
|
|
merged[ek] = str(val)
|
|
|
|
pw = data.get("vault_mailcow_mailbox_passwords") or {}
|
|
if pw.get("alerts") and not merged.get("ALERTS_PASSWORD"):
|
|
merged["ALERTS_PASSWORD"] = str(pw["alerts"])
|
|
|
|
header = """# Merged from Ansible vault (make vault-export-env). Fill gaps manually.
|
|
# vault → .env: make vault-export-env
|
|
# .env → vault: make vault-import-env
|
|
# hosts → .env → vault: make vault-pull-infra-secrets
|
|
|
|
"""
|
|
body = "\n".join(f"{k}={v}" for k, v in sorted(merged.items())) + "\n"
|
|
Path(env_file).write_text(header + body)
|
|
print(f"Wrote {len(merged)} keys to {env_file} (existing non-empty keys kept)")
|
|
PY
|
|
|
|
chmod 600 "${ENV_FILE}" 2>/dev/null || true
|