적대적 보안 감사에서 확정된 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 콜백·카메라 촬영·업로드 정상 확인. |
||
|---|---|---|
| .. | ||
| systemd | ||
| .gitignore | ||
| config.py | ||
| config_local.example.py | ||
| install.sh | ||
| leak_sensor.py | ||
| README.md | ||
| requirements.txt | ||
| test_connection.py | ||
| vendor.sh | ||
| WIRING.html | ||
누수감지 센서 모듈 — Raspberry Pi 4 Model B 전용
e-con 5C-08 저항형 누수감지센서를 Raspberry Pi 4 Model B 의 GPIO 로 읽어, 누수 발생 시 즉시 PHP API 서버에 보고(+SMS 발송 트리거)하고 Pi Camera 로 현장 사진을 촬영해 업로드하는 모니터링 모듈입니다.
원래 Raspberry Pi Zero 2 W 용으로 작성된 모듈을 Pi 4 Model B 전용으로 이식한 폴더입니다. GPIO(BCM) 번호 체계와
rpicam/libcamera카메라 스택은 두 보드가 동일해 센서·촬영 로직은 그대로이며, 차이는 배선/전원/이더넷/카메라 커넥터와 설치 환경뿐입니다.
1. 구성 파일
| 파일 | 역할 |
|---|---|
leak_sensor.py |
메인 — GPIO 인터럽트 누수 감지, 주기 보고, 누수 시 촬영+업로드 |
config.py |
비밀이 아닌 기본 설정(센서/임계/간격/카메라). config_local 에서 비밀값 로드 |
config_local.example.py |
운영·비밀값 템플릿 → config_local.py 로 복사해 사용(미커밋) |
requirements.txt |
Python 의존성(핀 고정) |
install.sh |
Pi 4 설치 스크립트(폐쇄망 오프라인 + 온라인 폴백) |
vendor.sh |
폐쇄망용 의존성 사전 다운로드(빌드 머신에서 실행) |
test_connection.py |
서버 연결/서명 점검 |
systemd/leak-sensor.service |
부팅 자동 실행 서비스 유닛 |
2. 하드웨어 (Pi 4 Model B 기준)
- Raspberry Pi 4 Model B (BCM2711) + Raspberry Pi OS Bookworm 64-bit
- e-con 5C-08 누수감지센서(저항형, 고임피던스 ~1.5MΩ)
- 외부 4.7MΩ 풀다운 저항 (필수 — 내부 풀저항은 끔)
- (선택) Pi Camera — Pi 4 = 15핀(1.0mm 피치) 표준 CSI, Zero 2 W = 22핀(0.5mm 피치) CSI → 리본/카메라 보드 호환 안 됨 (Pi 4용 15핀 리본 또는 15↔22 변환 어댑터 필요)
- 전원: USB-C 5V/3A (카메라 사용 시 여유 전원 권장)
- 네트워크: Pi 4 Gigabit Ethernet(유선) 또는 WiFi
2.1 핀 배치 (기본 센서 1개)
| 신호 | BCM | 40핀 헤더 물리 핀 |
|---|---|---|
| 센서 입력 | GPIO17 | 11 |
| 3.3V | — | 1 |
| GND | — | 6 (또는 9/14/20/25/30/34/39) |
센서를 추가하려면
config.py의SENSORS에 BCM 번호로 항목을 추가합니다. (예: GPIO27=물리 13번, GPIO22=물리 15번)
2.2 전기 설계 (중요)
ACTIVE_LOW = False: 건조 시 GPIO=LOW(0), 누수 시 GPIO=HIGH(1)USE_INTERNAL_PULL = False(PUD_OFF 유지): 내부 50kΩ 풀다운을 켜면 1.5MΩ 센서가 GPIO 를 HIGH 로 끌어올리지 못해 감지 실패합니다. 외부 4.7MΩ 풀다운만 사용하세요.
3. 서버 호환성 (반드시 확인)
이 모듈은 leak_alert / leak_recovery 이벤트와 photo_upload.php 를 수신하는 서버에
보고합니다.
✅ 이 repo 의
php/서버가 바로 그 서버입니다(단일 서버 통합 완료). 1번(누수+카메라)·2번(SHT30 온습도) 두 모듈 모두 동일한 cafe24php/서버에 raw-body 서명X-Signature = lowercase_hex(HMAC-SHA256(key=API_KEY, msg=요청본문 바이트))로 보고하며, 누수 상태·사진·온습도가 하나의 대시보드(dashboard.php)에 함께 표시됩니다.
- 신규 설치:
sql/schema_sht30.sql하나만 실행 — 누수 요소 (leak_sensor_log.is_leak/leak_sensor_status.is_leak컬럼,leak_incident,leak_photo,leak_ingest_nonce테이블)가 이미 포함되어 있습니다.
config_local.py의API_URL/PHOTO_UPLOAD_URL을 이 통합 서버로 설정하고,API_KEY는 서버config.local.php의API_KEY와 바이트 단위로 동일하게 맞춥니다.
4. 설치
4.1 설정값 준비
cp config_local.example.py config_local.py
# config_local.py 를 열어 API_URL / PHOTO_UPLOAD_URL / API_KEY / DEVICE_ID 채움
config_local.py 가 없으면 실행 시 명확한 오류로 즉시 중단됩니다(fail closed).
config_local.py 와 API_KEY 는 절대 커밋하지 마세요(.gitignore 처리됨).
4.2 온라인 설치 (인터넷 가능 환경)
chmod +x install.sh
./install.sh
4.3 폐쇄망(air-gapped) 오프라인 설치
인터넷이 되는 동일 아키텍처(aarch64, 가급적 동일 Pi 4 + Bookworm 64-bit) 머신에서 의존성을 먼저 받아 번들을 만든 뒤, 타깃 Pi 4 로 옮겨 설치합니다.
# (빌드 머신, 인터넷 O) wheelhouse/ + debs/ 생성
./vendor.sh
# wheelhouse/ 와 debs/ 를 타깃 Pi 4 의 이 폴더로 복사한 뒤:
# (타깃 Pi 4, 인터넷 X)
./install.sh # debs/ · wheelhouse/ 가 있으면 자동으로 오프라인 설치
install.sh는debs/가 있으면dpkg오프라인,wheelhouse/가 있으면pip --no-index오프라인으로 설치합니다. 둘 다 없을 때만 인터넷 apt/pip 로 폴백합니다. wheel/deb 는 아키텍처 종속이므로 x86_64 PC 에서 받은 것은 Pi 4 에서 동작하지 않습니다.
5. 실행
source venv/bin/activate
python3 leak_sensor.py
RPi.GPIO 가 없는 환경(개발 PC 등)에서는 자동으로 시뮬레이션 모드로 동작합니다.
연결 점검
source venv/bin/activate
python3 test_connection.py
6. 부팅 자동 실행 (systemd)
# 폴더를 /home/pi/raspberry_pi4 에 배치했다고 가정 (다르면 .service 의 경로 수정)
sudo cp systemd/leak-sensor.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable leak-sensor
sudo systemctl start leak-sensor
sudo systemctl status leak-sensor
journalctl -u leak-sensor -f
SupplementaryGroups=video 가 카메라 접근에 필요합니다.
7. 보안 메모
- 비밀값(
API_KEY)·서버 URL·기기 정보는config_local.py(미커밋)에만 둡니다. 커밋되는 파일에는 placeholder 만 존재합니다. - 보고 본문은 raw-body HMAC 서명으로 위변조를 방지합니다:
X-Signature = lowercase_hex(HMAC-SHA256(key=API_KEY, msg=요청본문 바이트))(leak_sensor.sign_raw↔ 서버config.php::verify_signature_raw, 2번 모듈과 동일 스킴).- 사진 업로드 서명의 canonical 문자열은
device_id|sensor_id|log_id|timestamp(공백 없음)입니다 (config_local.example.py참고). - 구버전의
sha256(API_KEY + 정렬 JSON)body-field 서명은 폐기되었고, 서버 기본 설정이 거부합니다(ALLOW_LEGACY_BODY_SIGNATURE=false,php/config.php).
- 사진 업로드 서명의 canonical 문자열은
config_local.py노출 시 즉시API_KEY를 교체(서버 동시 변경)하세요.