zarya/zarya-code.xml
2026-10-25 18:23:02 +03:00

1413 lines
59 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file is a merged representation of a subset of the codebase, containing specifically included files and files not matching ignore patterns, combined into a single document by Repomix.
The content has been processed where empty lines have been removed.
<file_summary>
This section contains a summary of this file.
<purpose>
This file contains a packed representation of a subset of the repository's contents that is considered the most important context.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
</purpose>
<file_format>
The content is organized as follows:
1. This summary section
2. Repository information
3. Directory structure
4. Repository files (if enabled)
5. Multiple file entries, each consisting of:
- File path as an attribute
- Full contents of the file
</file_format>
<usage_guidelines>
- This file should be treated as read-only. Any changes should be made to the
original repository files, not this packed version.
- When processing this file, use the file path to distinguish
between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
the same level of security as you would the original repository.
</usage_guidelines>
<notes>
- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Only files matching these patterns are included: bin/**, cmd/**, lib/**, layers/**, state/*.sh, config.env
- Files matching these patterns are excluded: state/snapshots/**, *.xml
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Empty lines have been removed from all files
- Files are sorted by Git change count (files with more changes are at the bottom)
</notes>
</file_summary>
<directory_structure>
bin/
fc
gg
op
zarya
cmd/
a.sh
disks.sh
errors.sh
exec.sh
flux.sh
git-credential.sh
logs.sh
net.sh
nodes.sh
pack.sh
pods.sh
run.sh
session.sh
snap.sh
unseal.sh
up.sh
layers/
00_host.sh
01_net.sh
02_tier0.sh
03_talos.sh
04_apps.sh
gc.sh
reset.sh
lib/
common.sh
kdbx_parser.py
log.sh
net.sh
session.sh
vault.sh
state/
00_workstation.sh
01_pve.sh
02_vps.sh
03_vyos.sh
04_tier0.sh
05_k8s.sh
collect_state.sh
config.env
</directory_structure>
<files>
This section contains the contents of the repository's files.
<file path="bin/fc">
#!/bin/bash
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Использование: fc <файл>"
exit 1
fi
if [[ -f "$1" ]]; then
wl-copy < "$1"
echo "'$1' +++"
else
echo "'$1'+++"
fi
</file>
<file path="bin/gg">
#!/bin/bash
set -euo pipefail
if [[ -z "${1:-}" ]]; then
echo "Тема СВО не раскрыта: gg \"сообщение\""
exit 1
fi
git add . && git commit -m "$1" && git push
</file>
<file path="bin/op">
#!/bin/bash
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Использование: op <файл...>"
exit 1
fi
for f in "$@"; do
printf "file://%s\r\n" "$(realpath "$f")"
done | wl-copy -t text/uri-list
</file>
<file path="cmd/a.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
unseal_vault
run_isolated bash -c "cd '${REPO_ROOT}/tofu' && tofu apply $*"
</file>
<file path="cmd/disks.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
echo -e "${BLUE}=== ФИЗИЧЕСКИЕ ПУЛЫ ХОСТА PROXMOX (ZFS) ===${NC}"
ssh -n -o BatchMode=yes -o ConnectTimeout=2 proxmox "zpool list -o name,size,alloc,free,cap,health" 2>/dev/null || log_err "PVE недоступен"
echo ""
echo -e "${BLUE}=== ПОЛЬЗОВАТЕЛЬСКИЕ ДАТАСЕТЫ TIER-0 (/astra/data) ===${NC}"
ssh -n -o BatchMode=yes -o ConnectTimeout=2 proxmox "zfs list -o name,used,avail,refer,mountpoint -r astra/data" 2>/dev/null || true
echo ""
echo -e "${BLUE}=== ТОМА ДИСКОВ KUBERNETES (ZVOL) ===${NC}"
kubectl get pvc -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,VOLUME:.spec.volumeName,SIZE:.status.capacity.storage 2>/dev/null || log_err "K8s API недоступен"
</file>
<file path="cmd/errors.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
has_errors=false
echo -e "${YELLOW}=== ТРИАЖ АВАРИЙ И СБОЕВ (K8s / Host / VyOS) ===${NC}"
bad_pods=$(kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded --no-headers 2>/dev/null | grep -v 'Completed' || true)
if [[ -n "${bad_pods}" ]]; then
has_errors=true
echo -e "${RED}[K8S] Проблемные поды:${NC}"
echo "${bad_pods}" | awk '{printf " %-16s %-36s %s\n", $1, $2, $3}'
fi
pve_failed=$(ssh -n -o BatchMode=yes -o ConnectTimeout=1 proxmox "systemctl --failed --no-legend --plain" 2>/dev/null || echo "UNREACHABLE")
if [[ "${pve_failed}" == "UNREACHABLE" ]]; then
has_errors=true
echo -e "${RED}[PVE] Гипервизор недоступен по SSH${NC}"
elif [[ -n "${pve_failed}" ]]; then
has_errors=true
echo -e "${RED}[PVE] Упавшие systemd-сервисы:${NC}"
echo "${pve_failed}" | awk '{print " " $1}'
fi
vyos_failed=$(ssh -n -o BatchMode=yes -o ConnectTimeout=1 vyos_router "systemctl --failed --no-legend --plain" 2>/dev/null || echo "UNREACHABLE")
if [[ "${vyos_failed}" == "UNREACHABLE" ]]; then
has_errors=true
echo -e "${RED}[VyOS] Роутер недоступен по SSH${NC}"
elif [[ -n "${vyos_failed}" ]]; then
has_errors=true
echo -e "${RED}[VyOS] Упавшие systemd-сервисы:${NC}"
echo "${vyos_failed}" | awk '{print " " $1}'
fi
if [[ "$has_errors" == false ]]; then
echo -e "${GREEN}✔ Все системы в норме. Сбоев не обнаружено.${NC}"
fi
</file>
<file path="cmd/exec.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
if [[ $# -eq 0 ]]; then
log_err "Использование: z exec <команда> [аргументы...]"
exit 1
fi
run_isolated "$@"
</file>
<file path="cmd/flux.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
subcmd="${1:-status}"
shift || true
case "${subcmd}" in
sync|reconcile|s)
log_info "Принудительная конвергенция FluxCD..."
flux reconcile source git atlas-repo -n flux-system 2>/dev/null || true
flux reconcile kustomization infra-sync -n flux-system 2>/dev/null || true
flux reconcile kustomization apps-sync -n flux-system 2>/dev/null || true
log_ok "Синхронизация завершена."
;;
logs|log|l)
log_info "Стриминг логов kustomize-controller..."
exec kubectl -n flux-system logs -l app.kubernetes.io/name=kustomize-controller --tail=50 -f
;;
status|st)
echo -e "${BLUE}=== СТАТУС РЕПОЗИТОРИЕВ И KUSTOMIZATION (FLUX) ===${NC}"
kubectl -n flux-system get gitrepositories,kustomizations,helmreleases 2>/dev/null || log_err "Flux недоступен"
;;
*)
kubectl -n flux-system get kustomizations 2>/dev/null || log_err "Flux недоступен"
;;
esac
</file>
<file path="cmd/logs.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
query="${1:-}"
if [[ -z "${query}" ]]; then
log_err "Использование: z logs <сервис> [-f] [-t <строки>]"
exit 1
fi
shift
follow_arg=""
tail_val="50"
while [[ $# -gt 0 ]]; do
case "$1" in
-f|--follow) follow_arg="-f"; shift ;;
-t|--tail) tail_val="$2"; shift 2 ;;
*) shift ;;
esac
done
pod_info=$(kubectl get pods -A --no-headers 2>/dev/null | awk -v q="${query}" 'tolower($1) ~ tolower(q) || tolower($2) ~ tolower(q) {print $1, $2; exit}')
if [[ -z "${pod_info}" ]]; then
log_err "Под с именем '${query}' не найден ни в одном namespace."
exit 1
fi
ns=$(echo "${pod_info}" | awk '{print $1}')
pod=$(echo "${pod_info}" | awk '{print $2}')
log_info "Логи ${ns}/${pod} (tail: ${tail_val}):"
exec kubectl logs -n "${ns}" "${pod}" --tail="${tail_val}" ${follow_arg}
</file>
<file path="cmd/net.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
echo -e "${BLUE}=== СЕТЕВОЙ РАДАР ИНФРАСТРУКТУРЫ (Таймаут 1 сек) ===${NC}"
printf "%-22s %-20s %-12s %s\n" "УЗЕЛ" "АДРЕС" "СТАТУС" "ЗАДЕРЖКА"
echo "------------------------------------------------------------------"
check_target() {
local name="$1"
local host="$2"
local port="$3"
local start end dur
start=$(date +%s%N)
if nc -z -w 1 "${host}" "${port}" 2>/dev/null; then
end=$(date +%s%N)
dur=$(( (end - start) / 1000000 ))
printf "%-22s %-20s \033[32m%-12s\033[0m %d ms\n" "${name}" "${host}:${port}" "UP" "${dur}"
else
printf "%-22s %-20s \033[31m%-12s\033[0m -\n" "${name}" "${host}:${port}" "DOWN"
fi
}
check_target "Proxmox Host (PVE)" "192.168.1.177" 8006
check_target "Edge Router (VyOS)" "192.168.1.2" 22
check_target "Technitium DNS" "10.0.10.11" 53
check_target "OpenBao Vault" "10.0.10.12" 8200
check_target "Forgejo GitOps" "10.0.10.13" 3000
check_target "NFS Storage (NAS)" "10.0.10.14" 2049
check_target "Traefik L2 VIP" "10.0.30.200" 443
check_target "Perimeter VPS" "153.76.194.24" 443
</file>
<file path="cmd/nodes.sh">
#!/bin/bash
set -u
watch_mode=false
while [[ $# -gt 0 ]]; do
case "$1" in
-w|--watch) watch_mode=true; shift ;;
*) shift ;;
esac
done
render_nodes() {
local raw
raw=$(kubectl get nodes -L topology.kubernetes.io/zone,topology.kubernetes.io/region 2>/dev/null || true)
echo "$raw" | awk '
BEGIN {
ERR = "\033[38;2;255;46;76m"
RUN = "\033[38;2;166;227;161m"
HEAD = "\033[38;2;147;154;183m"
RST = "\033[0m"
}
NR==1 { print HEAD $0 RST; next }
{
if ($2 ~ /Ready/ && $2 !~ /NotReady/) {
print RUN $0 RST
}
else {
print ERR $0 RST
}
}'
}
if [[ "$watch_mode" == true ]]; then
trap 'tput cnorm 2>/dev/null || true; echo ""; exit 0' INT TERM
tput civis 2>/dev/null || true
clear
while true; do
tput cup 0 0 2>/dev/null || true
render_nodes
tput ed 2>/dev/null || true
sleep 1
done
else
render_nodes
fi
</file>
<file path="cmd/pods.sh">
#!/bin/bash
set -u
watch_mode=false
ns_filter=""
query=""
all_namespaces=false
while [[ $# -gt 0 ]]; do
case "$1" in
-w|--watch) watch_mode=true; shift ;;
-n|--namespace) ns_filter="$2"; shift 2 ;;
-s|--service) query="$2"; shift 2 ;;
-A|--all) all_namespaces=true; shift ;;
all) all_namespaces=true; shift ;;
*) query="$1"; shift ;;
esac
done
render_pods() {
local raw
if [[ "$all_namespaces" == true ]]; then
raw=$(kubectl get pods -A -o wide 2>/dev/null || true)
elif [[ -n "$ns_filter" ]]; then
raw=$(kubectl get pods -n "$ns_filter" -o wide 2>/dev/null || true)
elif [[ -n "$query" ]]; then
raw=$(kubectl get pods -A -o wide 2>/dev/null | awk -v q="$query" 'NR==1 || tolower($1) ~ tolower(q) || tolower($2) ~ tolower(q)' || true)
else
raw=$(kubectl get pods -A -o wide 2>/dev/null | awk 'NR==1 || ($1 !~ /^(kube-system|flux-system|cert-manager|external-secrets)$/ && $4 != "Completed")' || true)
fi
echo "$raw" | awk '
BEGIN {
ERR = "\033[38;2;255;46;76m"
RUN = "\033[38;2;180;190;254m"
WARN = "\033[38;2;250;179;135m"
HEAD = "\033[38;2;147;154;183m"
RST = "\033[0m"
}
NR==1 { print HEAD $0 RST; next }
{
if ($0 ~ /CrashLoopBackOff|Error|OOMKilled|ImagePullBackOff/) { print ERR $0 RST }
else if ($0 ~ /ContainerCreating|Pending|Terminating|Init:/ || ($0 ~ /Running/ && $2 ~ /^0\//)) { print WARN $0 RST }
else if ($0 ~ /Running/) { print RUN $0 RST }
else { print $0 }
}'
}
if [[ "$watch_mode" == true ]]; then
trap 'tput cnorm 2>/dev/null || true; echo ""; exit 0' INT TERM
tput civis 2>/dev/null || true
clear
while true; do
tput cup 0 0 2>/dev/null || true
render_pods
tput ed 2>/dev/null || true
sleep 1
done
else
render_pods
fi
</file>
<file path="cmd/run.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
resolve_playbook() {
local id="$1"
local found
found=$(find "${REPO_ROOT}/ansible/playbooks" -maxdepth 1 -name "${id}_*.yml" | head -n1)
if [[ -z "${found}" ]]; then
log_err "Плейбук с префиксом [${id}] не найден в ansible/playbooks/"
exit 1
fi
echo "${found}"
}
if [[ $# -eq 0 ]] || [[ "${1:-}" == "list" ]]; then
echo -e "${BLUE}=== Каталог плейбуков (${REPO_ROOT}/ansible/playbooks/) ===${NC}"
for pb in $(ls -1 "${REPO_ROOT}/ansible/playbooks"/[0-9][0-9]_*.yml 2>/dev/null | sort); do
echo " $(basename "${pb}")"
done
exit 0
fi
for id in "$@"; do
pb_path=$(resolve_playbook "${id}")
log_info "==> Исполнение: $(basename "${pb_path}")..."
run_isolated ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${pb_path}"
done
log_ok "Плейбуки выполнены."
</file>
<file path="cmd/session.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
action="${1:-start}"
shift || true
case "${action}" in
start|login)
hours="${1:-1}"
ensure_prerequisites
load_secrets_to_ram "${hours}"
unseal_vault
log_ok "Сессия Zarya активна (TTL: ${hours} ч)."
;;
clean|logout)
rm -f "${RAM_CACHE}" /dev/shm/.atlas_core
log_ok "RAM-кэш и ключи уничтожены."
;;
esac
</file>
<file path="cmd/snap.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
target="${1:-all}"
"${ZARYA_DIR}/state/collect_state.sh" "${target}"
</file>
<file path="cmd/unseal.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
ensure_prerequisites
unseal_vault
</file>
<file path="cmd/up.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
target="${1:-all}"
case "${target}" in
host) run_isolated "${ZARYA_DIR}/layers/00_host.sh" ;;
net) run_isolated "${ZARYA_DIR}/layers/01_net.sh" ;;
tier0) run_isolated "${ZARYA_DIR}/layers/02_tier0.sh" ;;
talos) run_isolated "${ZARYA_DIR}/layers/03_talos.sh" ;;
apps) "${ZARYA_DIR}/layers/04_apps.sh" ;;
all)
run_isolated "${ZARYA_DIR}/layers/00_host.sh"
run_isolated "${ZARYA_DIR}/layers/01_net.sh"
run_isolated "${ZARYA_DIR}/layers/02_tier0.sh"
run_isolated "${ZARYA_DIR}/layers/03_talos.sh"
"${ZARYA_DIR}/layers/04_apps.sh"
log_ok "Инфраструктура Atlas развернута."
;;
*)
log_err "Неизвестный слой: ${target}. Доступны: host, net, tier0, talos, apps, all"
exit 1
;;
esac
</file>
<file path="layers/00_host.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
load_secrets_to_ram
log_info "[Layer 0: PVE Host] Подготовка хоста, шаблонов и базовых директорий ZFS..."
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/01_pve_host_day0.yml"
log_info "[Layer 0: PVE Host] Инициализация compute-скелетов ВМ и LXC через OpenTofu..."
cd "${REPO_ROOT}/tofu" && tofu apply \
-target=proxmox_virtual_environment_vm.vyos_router \
-target=proxmox_virtual_environment_container.dns0 \
-target=proxmox_virtual_environment_container.vault0 \
-target=proxmox_virtual_environment_container.git0 \
-target=proxmox_virtual_environment_container.storage0 \
-target=proxmox_virtual_environment_container.registry0 \
-target=proxmox_virtual_environment_vm.talos_master_1 \
-target=proxmox_virtual_environment_vm.talos_worker_1 \
-target=proxmox_virtual_environment_vm.talos_worker_2 \
-auto-approve
log_info "[Layer 0: PVE Host] Применение постоянных ZFS-маунтов (mp) на созданные LXC..."
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/01_pve_host_day0.yml"
log_ok "Layer 0 готов: хост настроен, ВМ и LXC созданы, ZFS смонтирован."
</file>
<file path="layers/01_net.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
load_secrets_to_ram
log_info "[Layer 1: VyOS & Perimeter] Накатка конфигурации сети..."
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/02_vyos_network_day0.yml"
log_ok "Layer 1 готов."
</file>
<file path="layers/02_tier0.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
load_secrets_to_ram
log_info "[Layer 2: Tier-0 Air-Gap] Развертывание базовой инфраструктуры (Registry, DNS, Vault)..."
for pb in 03_zot_registry.yml 04_technitium_dns.yml 05_openbao_vault.yml; do
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/${pb}"
done
log_info "[Layer 2: Tier-0 Air-Gap] Распечатывание OpenBao Vault..."
unseal_vault
log_info "[Layer 2: Tier-0 Air-Gap] Наполнение Vault секретами через OpenTofu..."
cd "${REPO_ROOT}/tofu" && tofu apply -auto-approve
log_info "[Layer 2: Tier-0 Air-Gap] Развертывание зависимых сервисов (Forgejo, NAS Storage)..."
for pb in 06_forgejo_git.yml 07_nas_storage.yml; do
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/${pb}"
done
log_info "[Layer 2: Tier-0 Air-Gap] Автоматическая первичная синхронизация Git в Forgejo (SEC-03 RAM auth)..."
CURRENT_BRANCH=$(git -C "${REPO_ROOT}" branch --show-current 2>/dev/null || echo "master")
git -C "${REPO_ROOT}" push -u http://10.0.10.13:3000/atlas/atlas.git "${CURRENT_BRANCH}" 2>/dev/null || \
git -C "${REPO_ROOT}" push http://10.0.10.13:3000/atlas/atlas.git "${CURRENT_BRANCH}" 2>/dev/null || true
log_ok "Layer 2 готов. Базовые сервисы, секреты и GitOps-репозиторий развернуты."
</file>
<file path="layers/03_talos.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
load_secrets_to_ram
unseal_vault
log_info "[Layer 3: Talos & Kubernetes] Проверка конфигураций машинных манифестов..."
if [[ ! -f "${REPO_ROOT}/talos/clusterconfig/controlplane.yaml" ]]; then
log_info "Генерация машинных конфигураций Talos..."
cd "${REPO_ROOT}" && talos/generate_config.sh
fi
log_info "[Layer 3: Talos & Kubernetes] Бутстрап кластера..."
cd "${REPO_ROOT}/talos" && ./bootstrap.sh
sync_k8s_vault_token
log_ok "Layer 3 готов."
</file>
<file path="layers/04_apps.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
log_info "[Layer 4: Apps] Применение манифестов FluxCD..."
kubectl apply -f "${REPO_ROOT}/kubernetes/bootstrap/sync.yaml"
log_ok "Layer 4 готов."
</file>
<file path="layers/gc.sh">
#!/bin/bash
set -uo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
ensure_prerequisites
log_info "🧹 Запуск генеральной очистки кластера (dep gc)..."
# 1. Удаление зомби-нод в статусе NotReady
NOT_READY_NODES=$(kubectl get nodes --no-headers 2>/dev/null | grep 'NotReady' | awk '{print $1}' || true)
if [[ -n "${NOT_READY_NODES}" ]]; then
for node in ${NOT_READY_NODES}; do
log_warn "Удаляем мертвую ноду: ${node}"
kubectl delete node "${node}" --timeout=5s 2>/dev/null || true
done
fi
# 2. Мгновенная зачистка зависших в Terminating
kubectl get pods -A --no-headers 2>/dev/null | awk '/Terminating/ {print $1, $2}' | while read -r ns pod; do
log_warn "Принудительно удаляем: ${ns}/${pod}"
kubectl -n "${ns}" delete pod "${pod}" --force --grace-period=0 2>/dev/null || true
done
# 3. Сброс бэкоффа для упавших подов (CrashLoopBackOff, Error, OOMKilled, CreateContainerConfigError)
kubectl get pods -A --no-headers 2>/dev/null | grep -E 'CrashLoopBackOff|Error|OOMKilled|CreateContainerConfigError|ImagePullBackOff' | awk '{print $1, $2}' | while read -r ns pod; do
log_info "Сбрасываем упавший под: ${ns}/${pod}"
kubectl -n "${ns}" delete pod "${pod}" --force --grace-period=0 2>/dev/null || true
done
# 4. Очистка завершенных одноразовых Job
COMPLETED_JOBS=$(kubectl get jobs -A --field-selector status.successful=1 --no-headers 2>/dev/null | awk '{print $1, $2}' || true)
if [[ -n "${COMPLETED_JOBS}" ]]; then
echo "${COMPLETED_JOBS}" | while read -r ns job; do
kubectl -n "${ns}" delete job "${job}" >/dev/null 2>&1 || true
done
fi
log_ok "Кластер очищен. Все сервисы пересоздаются против живых БД и NFS."
</file>
<file path="layers/reset.sh">
#!/bin/bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
RESET_WIPE_HISTORY="${RESET_WIPE_HISTORY:-false}"
log_warn "ВНИМАНИЕ! Инициирована процедура полного уничтожения инфраструктуры Proxmox VE."
log_info "Очистка текущей RAM-сессии. Требуется физическая повторная аутентификация..."
rm -f "${RAM_CACHE}" /dev/shm/.atlas_core
read -s -p "Master Password для подтверждения сноса: " KP_PASS
echo ""
yk_args=()
if ykman info >/dev/null 2>&1; then
yk_args=("-y" "2")
log_info "Приготовьтесь к аппаратному подтверждению (касание YubiKey)..."
fi
tmp_verify="/dev/shm/.verify_$$"
if ! echo "${KP_PASS}" | timeout 15 keepassxc-cli export "${yk_args[@]}" "${KDBX_PATH}" -f xml > "${tmp_verify}" 2>/dev/null; then
log_err "Аппаратная проверка провалена или таймаут касания. Доступ заблокирован."
rm -f "${tmp_verify}"
unset KP_PASS
if [[ "${RESET_WIPE_HISTORY}" == "true" ]]; then
history -c 2>/dev/null || true
fi
exit 1
fi
rm -f "${tmp_verify}"
unset KP_PASS
log_ok "Аппаратная проверка YubiKey и пароля подтверждена."
read -r -p "Введите 'CONFIRM-DESTRUCTION' для безвозвратного уничтожения: " confirm
if [[ "${confirm}" != "CONFIRM-DESTRUCTION" ]]; then
log_warn "Отмена операции."
exit 0
fi
log_info "Снятие защиты и уничтожение виртуальных машин и контейнеров на Proxmox..."
ssh proxmox bash << 'SSHEOF'
for id in 100 201 202 203; do
qm stop $id --skiplock 1 2>/dev/null || true
qm destroy $id --purge 1 --destroy-unreferenced-disks 1 2>/dev/null || true
done
for id in 101 102 103 104 105; do
pct set $id -protection 0 2>/dev/null || true
pct stop $id --skiplock 1 2>/dev/null || true
pct destroy $id --purge 1 --force 1 2>/dev/null || true
done
SSHEOF
log_info "Очистка локального стейта OpenTofu..."
rm -f "${REPO_ROOT}/tofu/terraform.tfstate"* "${REPO_ROOT}/tofu/.terraform.tfstate.lock.info"
rm -f "${RAM_CACHE}" /dev/shm/.atlas_core
if [[ "${RESET_WIPE_HISTORY}" == "true" ]]; then
history -c 2>/dev/null || true
fi
log_ok "Сервер зачищен до голого железа."
</file>
<file path="lib/common.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
export ATLAS_DIR="${ATLAS_DIR:-$HOME/Projects/atlas}"
export REPO_ROOT="${ATLAS_DIR}"
source "${ZARYA_DIR}/config.env" 2>/dev/null || true
source "${ZARYA_DIR}/lib/log.sh"
source "${ZARYA_DIR}/lib/net.sh"
source "${ZARYA_DIR}/lib/vault.sh"
source "${ZARYA_DIR}/lib/session.sh"
</file>
<file path="lib/kdbx_parser.py">
import sys
import xml.etree.ElementTree as ET
import os
dump_file = sys.argv[1]
cache_file = sys.argv[2]
key_file = sys.argv[3]
ttl_sec = sys.argv[4]
pve_endpoint = sys.argv[5]
vault_addr = sys.argv[6]
tree = ET.parse(dump_file)
root = tree.getroot()
for h in root.findall(".//History"):
h.clear()
for g in root.findall(".//Group"):
name = g.find("./Name")
if name is not None and name.text == "Recycle Bin":
g.clear()
entries = {}
for entry in root.findall(".//Entry"):
title = ""
username = ""
password = ""
notes = ""
for string in entry.findall("./String"):
key_elem = string.find("./Key")
val_elem = string.find("./Value")
if key_elem is not None and val_elem is not None and key_elem.text:
k = key_elem.text
v = val_elem.text or ""
if k == "Title": title = v.strip()
elif k == "UserName": username = v.strip()
elif k == "Password": password = v.strip()
elif k == "Notes": notes = v.strip()
if title and title not in entries:
entries[title] = {
"username": username,
"password": password,
"notes": notes
}
ssh_loaded = False
for title in ("Atlas Core Key", "AtlasCoreKey", "Atlas Core"):
entry_data = entries.get(title, {})
for field in ("password", "notes"):
val = entry_data.get(field, "")
if "-----BEGIN" in val or "PRIVATE KEY" in val:
with open(key_file, "w") as kf:
kf.write(val.strip() + "\n")
os.chmod(key_file, 0o600)
ssh_loaded = True
break
if ssh_loaded:
break
if not ssh_loaded:
sys.stderr.write("Внимание: приватный SSH-ключ не найден в полях Password/Notes записи Atlas Core Key.\n")
with open(cache_file, "w") as f:
f.write(f"# TTL_SECONDS={ttl_sec}\n")
f.write(f"export PROXMOX_VE_API_TOKEN={repr(entries.get('ProxmoxAPI', {}).get('password', ''))}\n")
f.write(f"export TF_VAR_proxmox_api_token={repr(entries.get('ProxmoxAPI', {}).get('password', ''))}\n")
f.write(f"export TF_VAR_state_passphrase={repr(entries.get('TofuState', {}).get('password', ''))}\n")
f.write(f"export PROXMOX_VE_ENDPOINT={repr(pve_endpoint)}\n")
f.write(f"export VAULT_ADDR={repr(vault_addr)}\n")
f.write(f"export VAULT_TOKEN={repr(entries.get('OpenBaoToken', {}).get('password', ''))}\n")
f.write(f"export VAULT_UNSEAL_KEY={repr(entries.get('OpenBaoUnseal', {}).get('password', ''))}\n")
f.write(f"export TECHNITIUM_PASSWORD={repr(entries.get('Technitium', {}).get('password', 'admin'))}\n")
f.write(f"export TF_VAR_vaultwarden_admin_token={repr(entries.get('VaultwardenAdmin', {}).get('password', ''))}\n")
f.write(f"export TF_VAR_forgejo_runner_token={repr(entries.get('ForgejoRunnerToken', {}).get('password', ''))}\n")
f.write(f"export TF_VAR_forgejo_oidc_client_id={repr(entries.get('ForgejoOIDC', {}).get('username', 'forgejo'))}\n")
f.write(f"export TF_VAR_forgejo_oidc_secret={repr(entries.get('ForgejoOIDC', {}).get('password', ''))}\n")
f.write(f"export ATLAS_PUSH_TOKEN={repr(entries.get('AtlasPushToken', {}).get('password', ''))}\n")
f.write(f"export VYOS_WG_PRIVATE_KEY={repr(entries.get('VyosWG', {}).get('password', ''))}\n")
os.chmod(cache_file, 0o600)
</file>
<file path="lib/log.sh">
#!/bin/bash
# Log formatting and color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${BLUE}==>${NC} $*"; }
log_ok() { echo -e "${GREEN}✔${NC} $*"; }
log_warn() { echo -e "${YELLOW}⚠${NC} $*"; }
log_err() { echo -e "${RED}✖${NC} $*"; }
</file>
<file path="lib/vault.sh">
#!/bin/bash
# OpenBao Vault operations and Kubernetes Secret synchronization
sync_k8s_vault_token() {
if kubectl --request-timeout=2s cluster-info >/dev/null 2>&1; then
log_info "Синхронизация токена OpenBao в Kubernetes..."
local bao_tok
bao_tok=$(grep '^export VAULT_TOKEN=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2- | tr -d '"'"'")
if [[ -n "${bao_tok}" ]]; then
kubectl create namespace external-secrets --dry-run=client -o yaml | kubectl apply -f - >/dev/null 2>&1 || true
kubectl -n external-secrets create secret generic openbao-token \
--from-literal=token="${bao_tok}" \
--dry-run=client -o yaml | kubectl apply -f - >/dev/null 2>&1
kubectl -n external-secrets rollout restart deployment external-secrets >/dev/null 2>&1 || true
log_ok "Токен OpenBao в Kubernetes актуализирован."
fi
fi
}
unseal_vault() {
local unseal_key target_vault_addr seal_status resp
unseal_key=$(grep '^export VAULT_UNSEAL_KEY=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2- | tr -d '"'"'")
target_vault_addr=$(grep '^export VAULT_ADDR=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2- | tr -d '"'"'")
target_vault_addr="${target_vault_addr:-$VAULT_ADDR}"
seal_status=$(curl -s --connect-timeout 2 "${target_vault_addr}/v1/sys/seal-status" 2>/dev/null || echo "")
if [[ -z "${seal_status}" ]]; then
log_warn "OpenBao (${target_vault_addr}) недоступен. Пропуск ансила."
return 0
fi
if echo "${seal_status}" | grep -q '"sealed":true'; then
log_info "OpenBao запечатан. Ансил..."
resp=$(printf '{"key":"%s"}' "${unseal_key}" | curl -s -X POST -H "Content-Type: application/json" --data-binary @- "${target_vault_addr}/v1/sys/unseal")
if echo "${resp}" | grep -q '"sealed":false'; then
log_ok "OpenBao успешно распечатан."
sync_k8s_vault_token
else
log_err "Ошибка ансила OpenBao: ${resp}"
return 1
fi
else
log_ok "OpenBao распечатан."
sync_k8s_vault_token
fi
}
</file>
<file path="state/00_workstation.sh">
#!/bin/bash
set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
echo "## 0. Рабочая станция администратора (Operator Environment)"
echo "### Инфраструктурные SSH-хосты (~/.ssh/config):"
echo '```text'
if [[ -f ~/.ssh/config ]]; then
awk '/^Host (router|proxmox|vyos|10\.|fin21|ded|incserv)/, /^$/' ~/.ssh/config
else
echo "Файл ~/.ssh/config не найден"
fi
echo '```'
echo "### Рабочие алиасы и функции оператора (Active Workflow Aliases):"
echo '```bash'
if [[ -f ~/.bashrc ]] && grep -q '# >>> ATLAS C2 WORKFLOW >>>' ~/.bashrc; then
sed -n '/# >>> ATLAS C2 WORKFLOW >>>/,/# <<< ATLAS C2 WORKFLOW <<</p' ~/.bashrc | grep -v '>>>'
else
echo "# Маркер # >>> ATLAS C2 WORKFLOW >>> не найден в ~/.bashrc"
fi
echo '```'
echo "### Статус RAM-кэша секретов (/dev/shm/.atlas_secrets_cache):"
echo '```text'
if [[ -f /dev/shm/.atlas_secrets_cache ]]; then
stat -c "Размер: %s байт | Права: %a | Создан: %y" /dev/shm/.atlas_secrets_cache
else
echo "Кэш секретов в RAM отсутствует"
fi
echo '```'
echo "### Проверка Git Credential Helper (git.svo88.space):"
echo '```text'
printf "protocol=https\nhost=git.svo88.space\n" | git credential fill 2>&1 | awk -F= '/^username/ {print "Username:", $2} /^password/ {print "Password: [PRESENT in RAM]"}' || echo "Credential helper не вернул учетных данных"
echo '```'
echo "### Ядро, память, ZRAM и параметры Coredump:"
echo '```text'
echo -n "Kernel: "; uname -r
echo -n "Swapon: "; swapon --show 2>&1 || echo "swapon недоступен"
zramctl 2>&1 || echo "zramctl недоступен"
echo "Coredump config:"
cat /etc/systemd/coredump.conf.d/*.conf 2>/dev/null || grep -E "Storage|ProcessSizeMax" /etc/systemd/coredump.conf 2>/dev/null || echo "Дефолтная конфигурация coredump"
echo '```'
echo "### Токены безопасности и ключи в ssh-agent:"
echo '```text'
echo "Active SSH Agent keys:"
ssh-add -l 2>&1 || true
echo "YubiKey / FIDO2 Status:"
ykman info 2>/dev/null || echo "Токен YubiKey не обнаружен"
echo '```'
echo "### Зеркала пакетов Pacman (Mirrorlist):"
echo '```text'
grep -E "^Server|^\[" /etc/pacman.conf /etc/pacman.d/* 2>/dev/null | head -n 15 || echo "Нет данных о зеркалах"
echo '```'
echo "### Маршрутизация на хосте (Routing to C2):"
echo '```text'
ip route show | grep -E "10.0.|192.168." || echo "Маршруты к ЦОД не обнаружены"
echo '```'
echo "### Версии локальных инструментов:"
echo '```text'
echo -n "OpenTofu: "; tofu version 2>/dev/null | head -n1 || echo "not installed"
echo -n "Kubectl: "; kubectl version --client -o yaml 2>/dev/null | grep gitVersion | head -n1 || echo "not installed"
echo -n "Talosctl: "; talosctl version --client --short 2>/dev/null || echo "not installed"
echo '```'
echo "### Состояние локального Git-репозитория (SSOT Source):"
echo '```text'
git -C "${REPO_ROOT}" status -sb
echo "Последний коммит: $(git -C "${REPO_ROOT}" log -1 --format='%h - %s (%cr)')"
echo "Remote URL: $(git -C "${REPO_ROOT}" remote -v 2>/dev/null | head -n1 | awk '{print $1, $2}' || echo 'no remote')"
echo '```'
echo "---"
</file>
<file path="state/01_pve.sh">
#!/bin/bash
set -uo pipefail
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=3 proxmox"
echo "## 1. Гипервизор Proxmox VE (192.168.1.177)"
echo "### Память хоста, Uptime и Температура CPU:"
echo '```text'
timeout 4s ${SSH_CMD} "uptime; echo ''; free -h; echo ''; sensors 2>/dev/null | grep -E 'Tctl|Package|temp1' || cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | awk '{print \"CPU Temp: \" \$1/1000 \"°C\"}'" 2>&1 || echo "PVE недоступен"
echo '```'
echo "### Здоровье физических дисков (SMART):"
echo '```text'
timeout 5s ${SSH_CMD} "for d in sda sdb sdc sdd sde sdf; do echo -n \"/dev/\$d: \"; smartctl -H /dev/\$d 2>/dev/null | grep -E 'result|PASSED|FAILED' || echo 'N/A'; done" 2>&1 || echo "SMART недоступен"
echo '```'
echo "### Статус шифрования ZFS (Encryption & Keys):"
echo '```text'
timeout 4s ${SSH_CMD} "zfs get encryption,keystatus,keyformat,keylocation astra terra 2>/dev/null" 2>&1 || echo "Ошибка сбора шифрования ZFS"
echo '```'
echo "### Здоровье и емкость ZFS-пулов:"
echo '```text'
timeout 4s ${SSH_CMD} "zpool list -o name,size,alloc,free,frag,cap,health; echo ''; zfs list -o name,used,avail,refer,mountpoint -r astra terra" 2>&1 || echo "Ошибка сбора ZFS"
echo '```'
echo "### Физическая емкость каталогов на /terra:"
echo '```text'
timeout 5s ${SSH_CMD} "du -sh /terra/* 2>/dev/null" 2>&1 || echo "Ошибка чтения /terra"
echo '```'
echo "### Блочные устройства хоста и тома ZVOL (lsblk):"
echo '```text'
timeout 4s ${SSH_CMD} "lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINTS" 2>&1 || echo "Ошибка сбора lsblk"
echo '```'
echo "### Виртуальные диски K8s и ВМ (ZVOLs на astra):"
echo '```text'
timeout 4s ${SSH_CMD} "zfs list -t volume -o name,volsize,used,referenced" 2>&1 || echo "Ошибка чтения ZVOL"
echo '```'
echo "### Модули ядра (nfsd, zfs):"
echo '```text'
timeout 4s ${SSH_CMD} "lsmod | grep -E '^(nfsd|zfs) '" 2>&1 || echo "Модули не загружены"
echo '```'
echo "### Теги сетевых карт ВМ 100 (VyOS) в Proxmox:"
echo '```text'
timeout 4s ${SSH_CMD} "qm config 100 2>/dev/null | grep -E '^net[0-9]'" 2>&1 || echo "Ошибка чтения qm config 100"
echo '```'
echo "### Точки монтирования LXC-контейнеров (/etc/pve/lxc/*.conf):"
echo '```text'
timeout 4s ${SSH_CMD} "grep -H -E '^mp[0-9]:' /etc/pve/lxc/*.conf 2>/dev/null" 2>&1 || echo "Ошибка чтения lxc conf"
echo '```'
echo "### Флаги автостарта ВМ и Контейнеров (onboot):"
echo '```text'
timeout 4s ${SSH_CMD} "grep -H -E '^onboot:' /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf 2>/dev/null" 2>&1 || echo "Ошибка чтения onboot"
echo '```'
echo "### Виртуальные машины (QEMU) и Контейнеры (LXC):"
echo '```text'
timeout 4s ${SSH_CMD} "qm list; echo ''; pct list" 2>&1 || echo "Ошибка получения списка ВМ/LXC"
echo '```'
echo "---"
</file>
<file path="state/02_vps.sh">
#!/bin/bash
set -uo pipefail
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=4 fin21"
echo "## 2. Периметр: Белый VPS (Host: fin21, IP: 153.76.194.24)"
echo "### WireGuard wg0 на VPS:"
echo '```text'
timeout 4s ${SSH_CMD} "sudo wg show wg0" 2>&1 || echo "VPS или WireGuard недоступен"
echo '```'
echo "### Статус системных сервисов (Edge Stack):"
echo '```text'
timeout 4s ${SSH_CMD} "sudo systemctl is-active wg-quick@wg0 haproxy xray nginx | paste -d' ' -s - | awk '{print \"WireGuard:\", \$1, \"| HAProxy:\", \$2, \"| Xray:\", \$3, \"| Nginx:\", \$4}'" 2>&1 || echo "Ошибка проверки systemd"
echo '```'
echo "### Прослушиваемые сокеты (Ports 80, 443, 4443, 8443, 51820):"
echo '```text'
timeout 4s ${SSH_CMD} "sudo ss -tulpn | grep -E '80|443|4443|8443|51820'" 2>&1 || echo "Ошибка ss"
echo '```'
echo "### Тест аварийной заглушки Nginx (127.0.0.1:8443):"
echo '```text'
timeout 3s ${SSH_CMD} "curl -k -s https://127.0.0.1:8443" 2>&1 || echo "Nginx fallback не отвечает"
echo '```'
echo "### Конфигурация SSH-демона (sshd runtime):"
echo '```text'
timeout 4s ${SSH_CMD} "sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin'" 2>&1 || echo "Ошибка проверки sshd"
echo '```'
echo "---"
</file>
<file path="state/03_vyos.sh">
#!/bin/bash
set -uo pipefail
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=3 vyos"
echo "## 3. Маршрутизатор VyOS (192.168.1.2)"
echo "### Сетевые интерфейсы и L2-транк (VLANs 10, 20, 30):"
echo '```text'
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces" 2>&1 || echo "Ошибка получения интерфейсов"
echo '```'
echo "### ARP-таблица K8s-интерфейса eth1 (проверка связности с нодами):"
echo '```text'
timeout 4s ${SSH_CMD} "ip neigh show dev eth1 2>/dev/null" 2>&1 || echo "Ошибка чтения ARP"
echo '```'
echo "### DHCP-сервер и выданные лизы (Options 3, 6):"
echo '```text'
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show dhcp server leases" 2>&1 || echo "Ошибка получения DHCP лизов"
echo '```'
echo "### Перехват DNS через DNAT (Rule 53 -> 127.0.0.42:53):"
echo '```text'
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show nat destination rules" 2>&1 || echo "Ошибка получения NAT правил"
echo '```'
echo "### Контейнеры маршрутизатора (Sing-Box & Zapret2):"
echo '```text'
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show container" 2>&1 || echo "Ошибка получения контейнеров"
echo '```'
echo "### Наличие /dev/net/tun внутри контейнера sing-box:"
echo '```text'
timeout 4s ${SSH_CMD} "sudo podman exec sing-box ls -l /dev/net/tun 2>/dev/null" 2>&1 || echo "Контейнер sing-box не запущен или tun отсутствует"
echo '```'
echo "### Задержка VLESS-канала через Clash API (Main-1-out -> fin21):"
echo '```text'
timeout 4s ${SSH_CMD} "curl -s http://127.0.0.1:9090/proxies/Main-1-out 2>/dev/null" 2>&1 || echo "Clash API недоступен"
echo '```'
echo "### Статус таймера автосинхронизации Git (singbox-sync):"
echo '```text'
timeout 4s ${SSH_CMD} "sudo systemctl status singbox-sync.timer --no-pager; echo ''; sudo journalctl -u singbox-sync.service -n 5 --no-pager" 2>&1 || echo "Ошибка проверки таймера"
echo '```'
echo "### Статус WireGuard туннеля wg0 и пинг до VPS:"
echo '```text'
timeout 4s ${SSH_CMD} "sudo wg show wg0; echo ''; /opt/vyatta/bin/vyatta-op-cmd-wrapper ping 10.8.0.1 count 2" 2>&1 || echo "VyOS или туннель недоступен"
echo '```'
echo "### Таблица маршрутизации (show ip route):"
echo '```text'
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show ip route" 2>&1 || echo "Ошибка получения маршрутов"
echo '```'
echo "---"
</file>
<file path="state/04_tier0.sh">
#!/bin/bash
set -uo pipefail
SSH_VYOS="ssh -n -o BatchMode=yes -o ConnectTimeout=3 vyos"
SSH_STORAGE="ssh -n -o BatchMode=yes -o ConnectTimeout=3 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -J vyos root@10.0.10.14"
echo "## 4. Сервисы Tier-0 (Air-Gap фундамент)"
echo "### Technitium DNS (10.0.10.11:53):"
echo "* **Внутренний домен (*.svo88.space -> 10.0.30.200):** $(timeout 3s ${SSH_VYOS} "dig @10.0.10.11 vw.svo88.space +short" 2>&1 | tr '\n' ' ')"
echo "* **Внешний резолв (google.com):** $(timeout 3s ${SSH_VYOS} "dig @10.0.10.11 google.com +short" 2>&1 | head -n1)"
echo "### OpenBao Vault (10.0.10.12:8200):"
echo '```json'
timeout 3s ${SSH_VYOS} "curl -s http://10.0.10.12:8200/v1/sys/seal-status" 2>&1 || echo '{"error": "Vault недоступен"}'
echo '```'
echo "### Zot OCI Registry (10.0.10.15:5000):"
echo '```json'
timeout 3s ${SSH_VYOS} "curl -s http://10.0.10.15:5000/v2/_catalog" 2>&1 || echo '{"error": "Zot недоступен"}'
echo '```'
echo "### Forgejo GitOps Server (10.0.10.13:3000):"
echo '```json'
timeout 3s ${SSH_VYOS} "curl -s http://10.0.10.13:3000/api/v1/version" 2>&1 || echo '{"error": "Forgejo недоступен"}'
echo '```'
echo "### Ядерный NFS nfsd (storage0 - 10.0.10.14):"
echo '```text'
timeout 4s ${SSH_STORAGE} "echo '== Активные экспорты ядра (exportfs):'; exportfs -v; echo ''; echo '== Емкость смонтированных ZFS-датасетов:'; df -h /media /torrents /backups /models; echo ''; echo '== Права точки монтирования OpenCloud:'; ls -ld /backups/opencloud-users" 2>&1 || echo "NFS (storage0) недоступен"
echo '```'
echo "---"
</file>
<file path="state/05_k8s.sh">
#!/bin/bash
set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TALOSCONFIG="${REPO_ROOT}/talos/clusterconfig/talosconfig"
KUBECONFIG_PATH="${HOME}/.kube/config"
echo "## 5. Kubernetes Платформа & Нагрузки"
echo "### Участники кластера Talos (OS-level):"
echo '```text'
timeout 5s talosctl --talosconfig="${TALOSCONFIG}" -n 10.0.20.10 -e 10.0.20.10 get members 2>&1 || echo "Talos API недоступен"
echo '```'
echo "### Ноды кластера K8s:"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get nodes -o wide 2>&1 || echo "K8s API недоступен"
echo '```'
echo "### Топологические лейблы нод (Proxmox-CSI topology):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get nodes -L topology.kubernetes.io/zone,topology.kubernetes.io/region 2>&1 || echo "Не удалось получить лейблы нод"
echo '```'
echo "### Статус ExternalSecrets (Синхронизация из Vault):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get clustersecretstores,externalsecrets -A 2>&1 || echo "Не удалось получить ExternalSecrets"
echo '```'
echo "### Сетевой ingress, сертификаты TLS и L2 Fast-Path VIP:"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get certificates,ingresses -A 2>&1 || echo "Не удалось получить Ingress/TLS"
echo ''
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n kube-system get ciliuml2announcementpolicies,ciliumloadbalancerippools 2>&1 || echo "Не удалось получить Cilium L2"
echo ''
timeout 3s curl -k -s -o /dev/null -w "Traefik VIP (10.0.30.200:443) HTTP Status: %{http_code}\n" https://10.0.30.200 2>&1 || echo "Traefik VIP недоступен"
echo '```'
echo "### Диски и тома (PVC / PV):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get pvc,pv -A 2>&1 || echo "Не удалось получить PVC"
echo '```'
echo "### Статус DaemonSet Proxmox-CSI Node:"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n kube-system get daemonset proxmox-csi-plugin-node 2>&1 || echo "Не удалось получить DaemonSet CSI"
echo '```'
echo "### Статус пространства мониторинга (VictoriaMetrics & Grafana):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n monitoring get statefulsets,pods,pvc 2>&1 || echo "Не удалось получить мониторинг"
echo '```'
echo "### Логи ошибок Proxmox CSI Plugin (последние строки):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n kube-system logs -l app.kubernetes.io/name=proxmox-csi-plugin --tail=15 --prefix=true 2>&1 || echo "Нет логов CSI"
echo '```'
echo "### Синхронизация GitOps (FluxCD):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get gitrepositories,kustomizations,helmreleases -A 2>&1 || echo "Flux не установлен или недоступен"
echo '```'
echo "### Проблемные поды (Non-Running):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get pods -A --field-selector=status.phase!=Running 2>&1 || echo "Все поды в статусе Running"
echo '```'
echo "### Последние события-предупреждения (Warning Events):"
echo '```text'
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get events -A --field-selector type=Warning --sort-by='.lastTimestamp' 2>&1 | tail -n 15 || echo "Нет предупреждений"
echo '```'
echo "### Реальный объем данных OpenCloud (/var/lib/opencloud-users):"
echo '```text'
timeout 10s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n storage exec statefulset/opencloud -c opencloud -- du -sh /var/lib/opencloud-users 2>&1 || echo "Не удалось получить размер данных OpenCloud"
echo '```'
</file>
<file path="state/collect_state.sh">
#!/bin/bash
set -uo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
STATE_DIR="${ZARYA_DIR}/state"
SNAPSHOTS_DIR="${STATE_DIR}/snapshots"
TARGET="${1:-all}"
MODULES=(
"00_workstation.sh"
"01_pve.sh"
"02_vps.sh"
"03_vyos.sh"
"04_tier0.sh"
"05_k8s.sh"
)
mkdir -p "${SNAPSHOTS_DIR}"
generate_header() {
local mod_name="$1"
local timestamp branch short_hash commit_msg
timestamp=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
branch=$(git -C "${ATLAS_DIR:-$HOME/Projects/atlas}" branch --show-current 2>/dev/null || echo "unknown")
short_hash=$(git -C "${ATLAS_DIR:-$HOME/Projects/atlas}" rev-parse --short HEAD 2>/dev/null || echo "none")
commit_msg=$(git -C "${ATLAS_DIR:-$HOME/Projects/atlas}" log -1 --format='%s' 2>/dev/null || echo "none")
cat <<EOF
# Sovereign C2 Runtime: ${mod_name}
**Срез:** ${timestamp} | **Git:** ${branch}@${short_hash} ("${commit_msg}")
EOF
}
run_single_module() {
local mod="$1"
local mod_name="${mod%.sh}"
local script="${STATE_DIR}/${mod}"
local out_file="${SNAPSHOTS_DIR}/${mod_name}.md"
local tmp_file="${out_file}.tmp"
echo " -> Сбор модуля: ${mod_name}..."
generate_header "${mod_name}" > "${tmp_file}"
if [[ -x "${script}" ]]; then
"${script}" >> "${tmp_file}" 2>&1
else
bash "${script}" >> "${tmp_file}" 2>&1
fi
mv "${tmp_file}" "${out_file}"
}
if [[ "${TARGET}" == "all" ]]; then
echo "==> Сбор полного аудита Sovereign C2 в ${SNAPSHOTS_DIR}..."
for mod in "${MODULES[@]}"; do
run_single_module "${mod}"
done
echo "✔ Все модули телеметрии успешно сохранены."
else
case "${TARGET}" in
00_workstation|workstation|host) run_single_module "00_workstation.sh" ;;
01_pve|pve) run_single_module "01_pve.sh" ;;
02_vps|vps) run_single_module "02_vps.sh" ;;
03_vyos|vyos|net) run_single_module "03_vyos.sh" ;;
04_tier0|tier0) run_single_module "04_tier0.sh" ;;
05_k8s|k8s|talos) run_single_module "05_k8s.sh" ;;
*)
echo "Неизвестный модуль: ${TARGET}"
exit 1
;;
esac
fi
</file>
<file path="config.env">
#!/bin/bash
# Atlas C2 Configuration SSOT
KDBX_PATH="${HOME}/Projects/atlas-secrets.kdbx"
RAM_CACHE="/dev/shm/.atlas_secrets_cache"
RAM_KEY="/dev/shm/.atlas_core"
VAULT_ADDR="http://10.0.10.12:8200"
VYOS_ROUTER_IP="192.168.1.2"
NET_PREFIX="10.0.0.0/16"
GIT_HOST="git.svo88.space"
PVE_ENDPOINT="https://192.168.1.177:8006/"
DEFAULT_SESSION_TTL=1
</file>
<file path="bin/zarya">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
SUBCMD="${1:-help}"
shift || true
case "${SUBCMD}" in
git-credential) exec "${ZARYA_DIR}/cmd/git-credential.sh" "$@" ;;
exec) exec "${ZARYA_DIR}/cmd/exec.sh" "$@" ;;
p|pod|pods) exec "${ZARYA_DIR}/cmd/pods.sh" "$@" ;;
node|nodes) exec "${ZARYA_DIR}/cmd/nodes.sh" "$@" ;;
flux) exec "${ZARYA_DIR}/cmd/flux.sh" "$@" ;;
e|err|errors) exec "${ZARYA_DIR}/cmd/errors.sh" "$@" ;;
l|log|logs) exec "${ZARYA_DIR}/cmd/logs.sh" "$@" ;;
n|net) exec "${ZARYA_DIR}/cmd/net.sh" "$@" ;;
d|df|disks) exec "${ZARYA_DIR}/cmd/disks.sh" "$@" ;;
unseal) exec "${ZARYA_DIR}/cmd/unseal.sh" "$@" ;;
login|start) exec "${ZARYA_DIR}/cmd/session.sh" "start" "$@" ;;
logout|clean) exec "${ZARYA_DIR}/cmd/session.sh" "clean" "$@" ;;
up) exec "${ZARYA_DIR}/cmd/up.sh" "$@" ;;
run) exec "${ZARYA_DIR}/cmd/run.sh" "$@" ;;
a|apply) exec "${ZARYA_DIR}/cmd/a.sh" "$@" ;;
snap) exec "${ZARYA_DIR}/cmd/snap.sh" "$@" ;;
pack) exec "${ZARYA_DIR}/cmd/pack.sh" "$@" ;;
reset|nuke) exec "${ZARYA_DIR}/layers/reset.sh" "$@" ;;
gc) exec "${ZARYA_DIR}/layers/gc.sh" "$@" ;;
help|--help|-h)
cat <<EOF
ZARYA Operator Interface (z)
Диагностика и мониторинг:
z pods [-w] [-n <ns>] [-s <query>] [-A] Просмотр подов
z nodes [-w] Статус нод, роли, зона и регион
z errors Мгновенный триаж сломанных сервисов
z logs <service> [-f] [-t <N>] Логи сервиса без ввода неймспейса
z net Сетевой радар доступности узлов (1 сек)
z disks Срез пулов astra/terra и томов K8s
GitOps и оркестрация:
z flux [status|sync|logs] Управление GitOps-конвергенцией
z exec <команда...> Вызов бинарников внутри RAM-изоляции
Сессия и доступы:
z login [TTL] Открытие смены (YubiKey + RAM)
z logout Мгновенная очистка RAM
z unseal Распечатывание OpenBao Vault
Деплой и IaC:
z up [layer] Макро-слои (host, net, tier0, talos, apps, all)
z run <selector> Плейбуки Ansible (01, 02)
z a [-auto-approve] OpenTofu apply в RAM-изоляции
Телеметрия и LLM:
z snap Снятие аудита в state/snapshots/
z pack [all|atlas|code|state] Сборка контекстов Repomix для LLM
EOF
;;
*)
log_err "Неизвестная команда: ${SUBCMD}. Введите 'z help'."
exit 1
;;
esac
</file>
<file path="cmd/git-credential.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
if [[ -f "${RAM_CACHE}" ]]; then
token=$(grep '^export ATLAS_PUSH_TOKEN=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2- | tr -d '"'\'' ' || true)
if [[ -n "${token}" ]]; then
echo "username=atlas"
echo "password=${token}"
fi
fi
exit 0
</file>
<file path="cmd/pack.sh">
#!/bin/bash
set -euo pipefail
ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${ZARYA_DIR}/lib/common.sh"
mode="${1:-all}"
pack_atlas() {
log_info "==> [1/3] Упаковка чистой архитектуры Atlas (atlas-code.xml)..."
(cd "${ATLAS_DIR}" && repomix --config "${ATLAS_DIR}/repomix.config.json")
log_ok "Файл ${ATLAS_DIR}/atlas-code.xml готов."
}
pack_zarya() {
log_info "==> [2/3] Упаковка станции оператора Zarya (zarya-code.xml)..."
(cd "${ZARYA_DIR}" && repomix --config "${ZARYA_DIR}/repomix.config.json")
log_ok "Файл ${ZARYA_DIR}/zarya-code.xml готов."
}
pack_state() {
log_info "==> [3/3] Снятие живого аудита и упаковка телеметрии (zarya-state.xml)..."
"${ZARYA_DIR}/state/collect_state.sh" all
(cd "${ZARYA_DIR}" && repomix --config "${ZARYA_DIR}/repomix.state.json")
log_ok "Файл ${ZARYA_DIR}/zarya-state.xml готов."
}
case "${mode}" in
all)
pack_atlas
echo ""
pack_zarya
echo ""
pack_state
echo ""
log_ok "Все три контекста Repomix собраны без ошибок."
;;
atlas)
pack_atlas
;;
code)
pack_zarya
;;
state)
pack_state
;;
*)
log_err "Использование: z pack [all|atlas|code|state]"
exit 1
;;
esac
</file>
<file path="lib/net.sh">
#!/bin/bash
ensure_prerequisites() {
local target_ip="${VAULT_ADDR#*//}"
target_ip="${target_ip%%:*}"
if ! ip route get "${target_ip}" 2>/dev/null | grep -q "${VYOS_ROUTER_IP}"; then
log_info "Восстанавливаем маршрут к ${NET_PREFIX} через VyOS (${VYOS_ROUTER_IP})..."
sudo ip route replace "${NET_PREFIX}" via "${VYOS_ROUTER_IP}" 2>/dev/null || true
fi
local target_helper="!${ZARYA_DIR}/bin/zarya git-credential"
local current_helper
current_helper=$(git config --global --get credential."https://${GIT_HOST}".helper 2>/dev/null || true)
if [[ "${current_helper}" != "${target_helper}" ]]; then
git config --global credential."https://${GIT_HOST}".helper "${target_helper}"
fi
local direct_helper
direct_helper=$(git config --global --get credential."http://10.0.10.13:3000".helper 2>/dev/null || true)
if [[ "${direct_helper}" != "${target_helper}" ]]; then
git config --global credential."http://10.0.10.13:3000".helper "${target_helper}"
fi
local ssh_hosts="proxmox pve0 vyos vyos_router 10.0.* dns0 vault0 git0 storage0 registry0"
if [[ -f "${HOME}/.ssh/config" ]] && ! grep -q "IdentityFile ${RAM_KEY}" "${HOME}/.ssh/config"; then
printf "\nHost %s\n IdentityFile %s\n IdentitiesOnly yes\n" "${ssh_hosts}" "${RAM_KEY}" >> "${HOME}/.ssh/config"
fi
}
</file>
<file path="lib/session.sh">
#!/bin/bash
load_secrets_to_ram() {
local hours="${1:-$DEFAULT_SESSION_TTL}"
local now
now=$(date +%s)
ensure_prerequisites
if [[ -f "${RAM_CACHE}" ]] && [[ -f "${RAM_KEY}" ]] && [[ -s "${RAM_KEY}" ]]; then
local created age cached_ttl
created=$(stat -c %Y "${RAM_CACHE}" 2>/dev/null || echo 0)
age=$(( now - created ))
cached_ttl=$(grep '^# TTL_SECONDS=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2 || echo 3600)
if [[ "${cached_ttl}" -ne 0 ]] && (( age >= cached_ttl )); then
log_warn "Время сессии истекло ($(( age / 60 )) мин >= $(( cached_ttl / 60 )) мин). Инвалидация кэша..."
rm -f "${RAM_CACHE}" "${RAM_KEY}"
else
return 0
fi
fi
local ttl_seconds
if [[ "${hours}" -eq 0 ]]; then
ttl_seconds=0
else
ttl_seconds=$(( hours * 3600 ))
fi
log_info "🔐 Вход в защищенный контур Zarya..."
read -s -p "Master Password: " KP_PASS
echo ""
local yk_args=()
if ykman info >/dev/null 2>&1; then
yk_args=("-y" "2")
log_info "YubiKey обнаружен. Приготовьтесь к аппаратному подтверждению (1 касание)..."
fi
local tmp_dump="/dev/shm/.kdbx_dump_${now}_$$.xml"
rm -f "${tmp_dump}"
touch "${tmp_dump}"
chmod 600 "${tmp_dump}"
if ! echo "${KP_PASS}" | keepassxc-cli export "${yk_args[@]}" "${KDBX_PATH}" -f xml > "${tmp_dump}" 2>/dev/null; then
log_err "Ошибка расшифровки базы KDBX (неверный пароль или таймаут касания YubiKey)"
rm -f "${tmp_dump}"
unset KP_PASS
return 1
fi
unset KP_PASS
python3 "${ZARYA_DIR}/lib/kdbx_parser.py" "${tmp_dump}" "${RAM_CACHE}" "${RAM_KEY}" "${ttl_seconds}" "${PVE_ENDPOINT}" "${VAULT_ADDR}"
rm -f "${tmp_dump}"
log_ok "База расшифрована за 1 касание. Ключ и секреты в RAM (TTL: ${hours}ч)"
}
run_isolated() {
ensure_prerequisites
load_secrets_to_ram
(
set -a
source "${RAM_CACHE}"
set +a
"$@"
)
}
</file>
</files>