적대적 보안 감사에서 확정된 medium 6건 보완 (critical/high 0): - systemd 유닛(양 노드): NoNewPrivileges + ProtectSystem=strict/ ProtectHome=read-only/ProtectKernel*/ProtectControlGroups/RestrictSUIDSGID/ LockPersonality/RestrictRealtime/RestrictAddressFamilies(+AF_NETLINK) 샌드박싱. - harden_pi.sh: SSH 차단을 마지막 단계([6/6])로 재정렬 — 앞 단계 실패 시 set -e 로 SSH 가 살아있는 상태에서 중단(원격 복구 가능). nftables·unattended-upgrades 를 오프라인(debs/ --no-download)으로도 설치 지원(폐쇄망 harden). 미발견 secret 경고. - install.sh(양 노드): config_local.py 설치 즉시 chmod 600 (harden 전 노출창 제거). - vendor.sh(양 노드): .deb 를 파일명이 아닌 dpkg-deb Architecture 필드로 실검사 (arm64/all 만 허용, 그 외 hard-fail). nftables·unattended-upgrades 를 번들에 포함. 검증(3-리뷰어 워크플로)이 잡은 회귀 동반 수정: - [critical] ProtectHome=read-only 가 lgpio 의 작업디렉터리(.lgd-nfy 파이프) 쓰기를 막아 add_event_detect(누수 인터럽트 등록) 실패 → 데몬 크래시루프 → 감지 불능. Environment=LG_WD=/tmp 로 PrivateTmp 쓰기가능 /tmp 이동(누수 노드 한정, SHT30 무관). - [medium] 오프라인 설치에 --no-install-recommends 추가(vendor --no-recommends 정합, 네트워크 폴백 방지) — install.sh x2 + harden_pi.sh. - SupplementaryGroups=video gpio 명시 · nft|head 에 ||true(SIGPIPE 중단 방지) · online harden 분기에 apt-get update. ※ 온디바이스 런타임 테스트 1회 필요(빌드머신 Windows 에선 systemd 실행 불가): 실 Pi 에서 systemctl start 후 add_event_detect 콜백·카메라 촬영·업로드 정상 확인.
75 lines
3.9 KiB
Bash
75 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# vendor.sh - 폐쇄망 설치용 의존성 사전 다운로드 (SHT30 2번 모듈)
|
|
# 인터넷에 연결된 빌드/스테이징 머신에서 실행한다.
|
|
# 산출물: wheelhouse/ (pip wheel + sdist), debs/ (apt .deb) → 타깃 Pi 4 로 전송.
|
|
#
|
|
# requests 는 arch 종속이 적으나 smbus2 는 순수 파이썬(py3-none-any)이라 어떤
|
|
# 빌드 머신에서 받아도 Pi 4 에서 동작한다. wheel 핀은 타깃(Bookworm 64-bit,
|
|
# aarch64, Python 3.11)에 맞춘다. .deb 는 타깃 OS/arch 에서 받는 것이 가장 안전.
|
|
# 환경변수: TARGET_PLATFORM(기본 manylinux2014_aarch64), TARGET_PYVER(기본 311)
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
|
|
TARGET_PLATFORM="${TARGET_PLATFORM:-manylinux2014_aarch64}"
|
|
TARGET_PYVER="${TARGET_PYVER:-311}"
|
|
TARGET_ABI="${TARGET_ABI:-cp${TARGET_PYVER}}"
|
|
|
|
echo "[vendor] (1/2) Python wheel → wheelhouse/ (platform=${TARGET_PLATFORM}, py=${TARGET_PYVER})"
|
|
mkdir -p wheelhouse
|
|
# requests 등 arch 종속 wheel: 타깃 플랫폼 명시 핀.
|
|
python3 -m pip download -r requirements.txt -d wheelhouse \
|
|
--only-binary=:all: \
|
|
--platform "${TARGET_PLATFORM}" \
|
|
--python-version "${TARGET_PYVER}" \
|
|
--implementation cp \
|
|
--abi "${TARGET_ABI}" \
|
|
|| echo "[WARN] 일부 wheel 의 타깃 플랫폼 핀 실패 — 순수파이썬(any) 폴백을 아래에서 받는다."
|
|
# smbus2(py3-none-any) 등 순수 파이썬 wheel 및 sdist 폴백.
|
|
python3 -m pip download -r requirements.txt -d wheelhouse \
|
|
|| echo "[WARN] sdist/any 폴백 일부 실패 (바이너리 wheel 이 모두 있으면 무시 가능)"
|
|
WHEEL_COUNT="$(ls -A wheelhouse 2>/dev/null | wc -l)"
|
|
echo " wheelhouse 파일 수: ${WHEEL_COUNT}"
|
|
[ "${WHEEL_COUNT}" -gt 0 ] || { echo "[ERROR] wheelhouse 비어있음"; exit 1; }
|
|
|
|
echo "[vendor] (2/2) apt .deb → debs/"
|
|
mkdir -p debs
|
|
# nftables·unattended-upgrades 도 포함 → harden_pi.sh 를 폐쇄망에서 오프라인 실행 가능.
|
|
BASE_PKGS="python3-requests python3-venv i2c-tools nftables unattended-upgrades"
|
|
DEPS="$(apt-cache depends --recurse --no-recommends --no-suggests \
|
|
--no-conflicts --no-breaks --no-replaces --no-enhances ${BASE_PKGS} \
|
|
| awk '/^\w/{print $1}' | sort -u)"
|
|
( cd debs && apt-get download ${BASE_PKGS} ${DEPS} ) 2>/dev/null \
|
|
|| echo "[WARN] 일부 .deb 다운로드 실패 (가상패키지/전이 의존성일 수 있음 — 필수 패키지는 아래에서 검증)"
|
|
|
|
MISS=0
|
|
for p in ${BASE_PKGS}; do
|
|
if ! ls debs/"${p}"_*.deb >/dev/null 2>&1; then
|
|
echo "[ERROR] 필수 패키지 .deb 누락: ${p}"
|
|
MISS=1
|
|
fi
|
|
done
|
|
[ "${MISS}" = 0 ] || { echo "[ERROR] 필수 .deb 누락 — 반드시 타깃 arch(aarch64 Bookworm)에서 vendor.sh 를 실행하세요."; exit 1; }
|
|
echo " debs 파일 수: $(ls debs/*.deb 2>/dev/null | wc -l) (필수 패키지 모두 확인됨)"
|
|
|
|
# 아키텍처 실검사 — 파일명이 아니라 .deb 내부 Architecture 필드로 타깃(arm64/all) 검증.
|
|
# (호스트가 amd64면 apt-get download 가 amd64 .deb 를 받아, 타깃 Pi 에서 dpkg 가
|
|
# "wrong architecture" 로 깨진다. 파일명만 보는 검사는 이를 못 잡는다.)
|
|
BAD_ARCH=0
|
|
for deb in debs/*.deb; do
|
|
[ -e "$deb" ] || continue
|
|
arch="$(dpkg-deb --field "$deb" Architecture 2>/dev/null || echo '?')"
|
|
case "$arch" in
|
|
arm64|all) : ;;
|
|
*) echo "[ERROR] arch 불일치: $(basename "$deb") = ${arch} (arm64/all 아님)"; BAD_ARCH=1 ;;
|
|
esac
|
|
done
|
|
if [ "${BAD_ARCH}" != 0 ]; then
|
|
echo "[ERROR] 타깃(aarch64/arm64) 이 아닌 .deb 가 있습니다. 호스트 arch=$(dpkg --print-architecture 2>/dev/null || echo unknown)." >&2
|
|
echo " 반드시 arm64 Pi(또는 arm64 chroot/qemu)에서 vendor.sh 를 실행하세요." >&2
|
|
exit 1
|
|
fi
|
|
echo " arch 검사 통과 (모든 .deb = arm64/all)"
|
|
|
|
echo "[vendor] 완료. wheelhouse/ 와 debs/ 를 타깃 Pi 4 로 전송 후 install.sh 실행."
|