#!/usr/bin/env bash secrets_init() { local key_file local key_dir local recipient local config_file="${SOPS_CONFIG:-${REPO_ROOT}/.sops.yaml}" local example_file="${REPO_ROOT}/.sops.yaml.example" require_debian_server "secrets-init" ensure_sops_age_tools key_file="$(sops_age_key_file)" key_dir="$(dirname "${key_file}")" mkdir -p "${key_dir}" chmod 700 "${key_dir}" if [[ ! -s "${key_file}" ]]; then echo "Generating age identity at ${key_file}..." age-keygen -o "${key_file}" chmod 600 "${key_file}" else echo "Using existing age identity at ${key_file}." chmod 600 "${key_file}" fi recipient="$(sops_age_recipient "${key_file}")" if [[ -z "${recipient}" ]]; then echo "Could not read the public recipient from ${key_file}." >&2 exit 1 fi if [[ -e "${config_file}" ]]; then if grep -q 'age1replacewithyourpublicrecipient' "${config_file}"; then echo "${config_file} still contains the placeholder age recipient." >&2 exit 1 fi echo "SOPS config already exists: ${config_file}" else if [[ ! -s "${example_file}" ]]; then echo "Missing ${example_file}" >&2 exit 1 fi sed "s/age1replacewithyourpublicrecipient/${recipient}/g" "${example_file}" >"${config_file}" echo "Wrote ${config_file} with Debian host age recipient ${recipient}." fi echo "Private age key: ${key_file}" echo "Public age recipient: ${recipient}" echo "Review and commit ${config_file}; never commit ${key_file}." } secrets_check_file() { local file="$1" local key_file="$2" case "${file}" in *.json) grep -q '"sops"' "${file}" || { echo "${file} does not look SOPS-encrypted." >&2 return 1 } ;; *) grep -q '^sops:' "${file}" || { echo "${file} does not look SOPS-encrypted." >&2 return 1 } ;; esac if [[ -s "${key_file}" ]]; then SOPS_AGE_KEY_FILE="${key_file}" sops -d "${file}" >/dev/null fi } secrets_check() { local config_file="${SOPS_CONFIG:-${REPO_ROOT}/.sops.yaml}" local key_file local recipient="" local failures=0 local found_files=0 local file key_file="$(sops_age_key_file)" if [[ ! -s "${config_file}" ]]; then echo "Missing ${config_file}. Run ./jeannie secrets-init on the Debian host." >&2 failures=$((failures + 1)) elif grep -q 'age1replacewithyourpublicrecipient' "${config_file}"; then echo "${config_file} still contains the placeholder age recipient." >&2 failures=$((failures + 1)) fi if [[ -s "${key_file}" ]]; then recipient="$(sops_age_recipient "${key_file}")" if [[ -n "${recipient}" && -s "${config_file}" ]] && ! grep -q "${recipient}" "${config_file}"; then echo "${config_file} does not include this host's age recipient ${recipient}." >&2 failures=$((failures + 1)) fi else echo "No local age key found at ${key_file}; encrypted file structure will be checked without decrypting." fi if command -v git >/dev/null 2>&1; then while IFS= read -r file; do [[ -n "${file}" ]] || continue found_files=$((found_files + 1)) secrets_check_file "${REPO_ROOT}/${file}" "${key_file}" || failures=$((failures + 1)) done < <(git -C "${REPO_ROOT}" ls-files '*.secret.yaml' '*.secret.yml' '*.secret.json' '*.enc.yaml' '*.enc.yml' '*.enc.json') fi if ((failures > 0)); then echo "Secret checks failed with ${failures} issue(s)." >&2 exit 1 fi if ((found_files == 0)); then echo "SOPS config checks passed. No encrypted secret files are committed yet." else echo "SOPS config checks passed for ${found_files} encrypted secret file(s)." fi } security_scan() { require_debian_server "security-scan" "${REPO_ROOT}/scripts/security-scan" all } security_prepare() { require_debian_server "security-prepare" "${REPO_ROOT}/scripts/security-scan" prepare } security_zap() { require_debian_server "security-zap" "${REPO_ROOT}/scripts/security-scan" zap } security_host() { require_debian_server "security-host" "${REPO_ROOT}/scripts/security-scan" host } security_trivy() { require_debian_server "security-trivy" "${REPO_ROOT}/scripts/security-scan" trivy } security_secrets() { require_debian_server "security-secrets" "${REPO_ROOT}/scripts/security-scan" secrets } security_nuclei() { require_debian_server "security-nuclei" "${REPO_ROOT}/scripts/security-scan" nuclei } security_web() { require_debian_server "security-web" "${REPO_ROOT}/scripts/security-scan" web } security_logs() { require_debian_server "security-logs" "${REPO_ROOT}/scripts/security-logs" } security_runtime() { require_debian_server "security-runtime" if ! command -v kubectl >/dev/null 2>&1; then echo "kubectl is required for security-runtime." >&2 exit 1 fi kubectl --kubeconfig "${KUBECONFIG_PATH}" -n kube-system rollout status daemonset/tetragon --timeout=30s kubectl --kubeconfig "${KUBECONFIG_PATH}" -n kube-system get pods -l app.kubernetes.io/name=tetragon -o wide cat <<'EOF' Watch recent Tetragon events: kubectl -n kube-system logs -l app.kubernetes.io/name=tetragon -c export-stdout --tail=100 -f Useful practice trigger: kubectl -n security-lab exec deploy/juice-shop -- sh -c 'id; uname -a' EOF } security_attack_path() { require_debian_server "security-attack-path" "${REPO_ROOT}/scripts/security-attack-path" "${@:2}" }