본문 바로가기
IOT스마트홈 만들기 (Home Assistant)/(armbian OS) RK3328에 HA 설치

RK3328이 탑재된 SBC보드 (NanoPi Neo3) 사용기 (5) HA 기본 세팅 및 보안 강화

by ProjectDH 2021. 8. 7.

SSH 보안 강화

CC2538 동글에 지그비 기기 페어링

기타 HA 설정

순으로 포스팅을 진행하겠습니다.

 

1. SSH 보안 강화

 

NanoPI Neo3의 SSH 보안을 강화해보겠습니다. 먼저 SSH 포트 변경입니다.

 

vi /etc/ssh/sshd_config 를 입력하고 수정모드로 진입 (i키 입력)

#Port 22 부분을 자신이 사용하고 싶은 포트로 변경 (#은 주석이므로 제거하셔야 합니다.)

Port 포트번호

 

저장방법 ESC => :wq 입력

이후 systemctl restart ssh 를 입력하면 포트 변경 됩니다.

 

 

포트를 변경하기만 해도 어느정도 안심할 수 있겠다고 생각하지만

전혀 그렇지 않습니다.

 

해외 ip로 무차별 대입 방식으로 SSH 접속이 계속 들어옵니다.

그래서 3번이상 로그인을 실패하면 자동으로 ip를 차단시키게 구축해보겠습니다.

 

우선 설정하기 위해서는 SSH 로그인 로그를 자동으로 남기게 해야합니다.

apt install rsyslog 명령어를 입력하면 됩니다. (설치가 안 되어 있다면 설치 필수)

 

이 rsyslog를 설치하면 자동으로 SSH 로그인 로그가 남게 됩니다.

 

apt install fail2ban 을 입력해서 fail2ban을 설치합니다.

cd /etc/fail2ban 를 입력해서 폴더로 이동하고

vi jail.conf 를 입력해서 설정 파일을 수정해봅시다.

 

[default]

bantime = -1

findtime = 10m

maxretry = 5

 

[sshd]

enabled = yes

port = ssh

filter = sshd

 

 

내리다가 옵션값 변경 및 추가는 이렇게만 수정해주시고

 

저장방법 ESC => :wq 입력

이후 systemctl restart fail2ban 을 입력하면 fail2ban 설정이 완료됩니다.

10분이내에 5회 이상 로그인 실패시 영구 차단입니다.

 

차단 해제는 fail2ban-client set sshd unbanip [ip주소]를 입력하면 되고

차단 목록은 iptables -L을 입력하면 확인 가능합니다.

 

 

 

2. CC2538에 z2m 장치 페어링하기

 

이번에는 기존에 사용하던 CC2531 동글 대신에 CC2538 동글을 NEO3에 장착한 후에 z2m을 설정해보려고합니다.

라우터를 변경한 후에는 다시 페어링을 해야하므로 기존에 있던 도커 컨테이너를 삭제 후에 다시 생성했습니다.

 

docker stop z2m
docker rm z2m
docker run -d --name="z2m" --net=host --restart=always -v /home/pi/ha/z2m:/app/data --device=/dev/ttyUSB0 -v /run/udev:/run/udev:ro -e TZ=Asia/Seoul --privileged=true koenkk/zigbee2mqtt

 

CC2538을 사용하기 위해서는 ttyACM0 부분을 ttyUSB0으로 수정하여합니다.

 

cd /home/pi/ha/z2m
rm -r ./*
docker restart z2m
vi configuration.yaml

 

ttyACM0을 ttyUSB0 으로 수정 후 Esc => :wq 로 종료

또한 permit_join을 yes로 바꾼 후에 

docker restart z2m을 입력해서 서버를 재시작한 후에

지그비 기기들을 모두 페어링합니다. (모두 페어링 하고나서 no로 변경)

 

페어링을 했는데 신호감도(lqi)가 안좋다면 채널 변경도 해봐야합니다.

(configuration.yaml 에서 수정)

 

advanced:

   channel: 11

 

 

적절하게 수정 후 ESC => :wq 엔터로 종료

기본채널은 11입니다.

 

자세한건 이곳 참조

https://www.zigbee2mqtt.io/information/configuration.html

 

제가 붙인 기기는 다음과 같습니다.

 

 

다원 플러그의 경우 실시간 전력 측정이 되는데, 기본 설정시 5초마다 올라오므로 과부하를 일으킬 가능성이 있습니다.

이에따라 리포팅 주기를 변경하는 방법을 소개합니다.

 

=========리포팅 주기 변경법=========

1. docker z2m 컨테이너에서 devices.js 파일 다운로드

 

docker cp 컨테이너이름:/app/node_modules/zigbee-herdsman-converters/devices.js devices.js

 

현재 경로에 devices.js 파일을 다운로드 합니다.

다음은 docker 컨테이너에서 devices.js를 삭제하는 방법입니다.

 

docker exec -it z2m sh
rm /app/node_modules/zigbee-herdsman-converters/devices.js

 

이 명령어를 입력해서 파일 삭제를 합니다. 이후 컨트롤 + D 키를 동시에 눌러서 도커에서 빠져 나옵니다.

 

devices.js 파일을 pc로 가져와서 notepad ++로 열어줍니다.

B540을 검색하고,

기존에

await reporting.instantaneousDemand(endpoint);

이 문장을

await reporting.instantaneousDemand(endpoint, {min: 60, max: repInterval.MINUTES_5, change: 10});

요렇게 수정합니다.

 

(60초에 한번, 10와트 이상 전력 사용량 변화시 z2m에 반영됨)

 

아래의 명령어를 입력하여 수정한 디바이스 파일을 복사하고 z2m 서버를 재시작합니다.

 

 

docker cp devices.js z2m:/app/node_modules/zigbee-herdsman-converters/devices.js 
docker restart z2m

 

이후 z2m의 configuration.yaml에서 다원플러그를 삭제 후 다원 플러그 초기화, 이후 페어링을 다시합니다.

 

그리고 나서는 5초에 한 번 리포팅 되지 않아서, 무리가 가지 않습니다. 실시간 전력을 못 보는건 아쉽지만, 대략적으로 사용하고 있는 전력은 알 수 있습니다.

=========리포팅 주기 변경법 끝=========

 

3. 기타 HA 설정

 

고급모드 설정하기

 

 

프로필 클릭 (armbian)

 

고급 모드 켜기를 누르면 됩니다.

고급 모드를 켜야 configuration.yaml 파일 문법 검사가 가능해집니다.

 

로그 파일 최적화

 

로그 파일은 가면 갈수록 많아지고, 기본설정으로 두었다가는 서버가 뻑나가는 경우도 있습니다.

이것도 부하가 많이 갑니다.

 

vi /data/homeassistant/config/configuration.yaml

 

recorder:
  auto_purge: true
  purge_keep_days: 4
  commit_interval: 10
  exclude:
    entity_globs:
      - "sensor.*_linkquality"
      - "sensor.*_url"
      - "sensor.*_voltage"
    entities:
      - sensor.time
      - sensor.date_time
      - sensor.date
      - sensor.bus
      - sensor.bus_tts
      - sensor.node_name_uptime  

 

로그를 남기지 않을 엔티티들을 적절하게 넣은 후 Esc => :wq로 저장후 종료

이후 HA에서 구성 내용 검사 후 재시작합니다.

 

그리고 개발자도구 => 서비스에서 recorder.purge를 입력하고 4 day, repack 체크 후 명령어 호출을 합니다.

그러면 로그파일 정리 완료

 

SSL 인증서 발급 + https 보안 설정

 

이번에는 HA서버서 http 대신에 https 프로토콜을 사용하는 방법을 소개해드리겠습니다.

우선 https는 http 보다 안전합니다. https를 사용하려면 SSL 인증서가 필요한데, 이 인증서가 https 통신을 할 때 암호화를 해서 전송하기 때문입니다. http 통신을 할 때에는 암호화되지 않아서 서버의 취약점이 많습니다. 따라서 https 통신으로 교체하기를 권고하는 바입니다.

 

SSL 인증서 발급 업체는 많이 있지만, 대표적으로 무료로 https에서 사용 가능한 SSL 인증서 발급을 해주는 업체는 Let's encrypt입니다. 이 업체는 신뢰할 수 있는 ssl 인증서를 무료로 발급해주고있고, 비영리 업체입니다. 하지만 3개월마다 인증서를 갱신해야 한다는 단점이 있습니다.

하지만 갱신을 crontab(자동 실행)을 이용하면 수동으로 연장하지 않아도 자동으로 연장되게 할 수 있습니다.

 

먼저 인증서 발급을 해보겠습니다.

 

인증서 발급은 certbot이라는 도구를 이용할 것입니다.

기본적으로 certbot이 설치되어 있을 확률은 높으나 설치 방법부터 알려드리겠습니다. 설치방법은 아래의 명령어를 입력합니다.

 

 

apt update
apt install -y certbot

 

이제 인증서를 발급받아 보겠습니다.

오늘 인증서 발급에 사용할 인증 방식은 DNS 인증 방식입니다. let's encrypt에서 요구하는 랜덤 값을 dns txt 레코드에 입력하면 인증서가 발급됩니다.

 

바로 발급 방법을 알려드리겠습니다.

발급 받으려는 도메인을 임의로 myhost.com 이라고 지정했습니다.

또한, 인증서 발급시 넣어야하는 이메일 주소는 abc@gmail.com 이라고 지정했습니다. 이 메일 주소로는 인증서 만료 기간이 다가오면 메일이 옵니다.

 

certbot certonly --manual -d *.myhost.com -d myhost.com --email abc@gmail.com --agree-tos --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory

 

 

이메일로 let's encrypt에서 제공하는 소식지를 받고싶은지 물어보는 건데, n을 입력후 엔터치시면 거절입니다.

 

 

ip 주소가 로그된다는 뜻입니다. 동의하지 않으면 인증서 발급이 중단되므로, y를 입력후 엔터

이렇게 입력하면 곧 dns txt 레코드에 특정 값을 추가하라고 뜹니다.

 

 

이제 txt record를 인증하러 가보겠습니다.

저는 namecheap을 사용 중이므로 제 기준으로 보여드리겠습니다.

(도메인 제공사 홈페이지에서 DNS TXT 를 생성하시면 됩니다.)

 

 

 

이렇게 추가했습니다. 반영이 되고있는지 확인하려면 이 사이트에서 _acme-challenge.myhost.com을 입력하고 txt를 클릭해서 현재의 dns txt 값이 무엇인지 확인하세요.

https://toolbox.googleapps.com/apps/dig/#TXT/

 

반영 되었으면 엔터를 입력하세요. 한번 더 인증하라고 표시됩니다.

 

여기서는 아까 추가했던 dns record를 삭제하지 말라고 하네요. 같은 txt 레코드로 하나 더 생성해줍니다.

그리고 엔터를 입력하면 이제 발급이 끝납니다.

 

 

/etc/letsencrypt/live/myhost.com/privkey.pem  /etc/letsencrypt/live/myhost.com/fullchain.pem 파일이 생겼으면 발급이 완료된 것입니다.

유효 기간은 3개월 이므로 인증서 만료 1개월 전인 2~3개월마다 certbot renew를 입력해서 연장을 해야 할까 싶지만, 자동으로 연장되게 crontab 작업을 걸어주면 됩니다.

 

 

3개월이 끝나기 전에 수시로 인증서를 생성할 때 사용한 명령어를 입력해서 신규 발급을 해야합니다.

certbot certonly --manual -d *.myhost.com -d myhost.com --email abc@gmail.com --agree-tos --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory

 

 

그 다음으로는 dhparam을 생성해보겠습니다. dhparam을 웹서버에 적용하면 SSL 통신할 때 암호화를 시켜서 전송합니다. 웹 보안상을 위해 발급하는 것입니다. 2048비트나 1024비트를 대부분 사용합니다. 4096은 생성하는 시간이 오래 걸리고, 2048로 보안을 유지하더라도 뚫기 힘듭니다.

 

발급 방법은 아래의 명령어를 입력합니다. 저는 1024로 처음에 했다가 2048로 다시 생성했습니다.

 

openssl dhparam -out /etc/ssl/certs/dhparams.pem 2048

 

2048로 하면 10분정도면 완료되는 듯 합니다. 환경에 따라서 달라지겠지만, .. * + 이런 것이 끝나고 명령어 입력이 가능해질 때까지 기다립니다.

 

 

이렇게 되면 완료되었습니다.

 

이제 필요한 인증서 발급과 dhparam 생성이 완료되었습니다. nginx reverse proxy 적용 방법을 소개해드리겠습니다.

nginx 프록시를 사용하는 이유는 바로 보안때문입니다.HA 서버에 직접 접속하게 되면 보안상 취약한 점이 있습니다.nginx를 설정하면 보안이 강해집니다.

아래에서 제가 다음과 같이 nginx proxy 를 설정해볼 것입니다.

 

 

http로 접근시 자동으로 https로 리다이렉트 (SSL 인증서 적용하였기 때문에)

중국과 러시아에서는 HA 서버에 접속 차단 (해킹시도가 많은 국가)

서버의 host가 지정된 호스트가 아니라면 HA 서버에 접속 차단 (지정된 도메인을 통해서 접속해야지만 HA 접속이 가능함)

 

먼저 중국과 러시아에서 접속을 차단해보겠습니다.

 

아래의 명령어를 입력해서 geoip 데이터베이스를 설치합니다.

 

apt install -y geoip-database libgeoip1

 

/etc/nginx/nginx.conf 에 다음과 같이 적절히 수정합니다.

 

http {
        geoip_country /usr/share/GeoIP/GeoIP.dat;
        map $geoip_country_code $allowed_country {
            default yes;
            RU no;
            CN no;
}

 

한편으로 제가 올린 geo ip 관련 글입니다.

https://cafe.naver.com/koreassistant/4908

 

다음은 HA에 nginx proxy를 본격적으로 설정해보겠습니다.

nginx sites 프로필은 github에 올려놓습니다.

 

hass_nginx 파일입니다. (오른쪽 마우스 클릭후 다른이름으로 저장)

https://raw.githubusercontent.com/projectdhs/ha/main/hass_nginx

 

 

nginx의 프로필을 다운받았다면 iot.myhost.com 을 반드시 자신의 iot 서버로 설정할 주소로 설정하시고 myhost.com은 도메인 주소로 변경하면 됩니다.

(도메인명 수정 및 인증서 경로 적절히 변경)

 

그리고나서 hass_nginx 파일을 /etc/nginx/sites-available/ 경로에 넣으시고 아래의 명령어를 입력하여 프로필을 활성화 시킵니다.

 

ln -s /etc/nginx/sites-available/hass_nginx /etc/nginx/sites-enabled/hass_nginx

 

이제 systemctl restart nginx 를 입력하면 nginx 재시작이 되면서 프로필이 적용됩니다.

 

만약에 정상적으로 재시작이 안 된다면 systemctl status nginx 를 입력하여서 오류 내용이 무엇인지 확인하시고 수정하시길 바랍니다. 오류 해결이 어렵다면 제 개인톡으로 문의 주시면 해결해드리겠습니다.

 

다음으로는 도메인 관리 페이지에서 서브 도메인 iot를 A 레코드에 자신의 서버 ip 주소로 설정합니다.

ha 서버는 이제 https://iot.myhost.com:8443 으로 접속 가능합니다. 

보안을 위해서 기존에 사용하던 ha의 포트인 8123은 포트포워딩을 해제하시길 바랍니다.

이제는 8443으로 접속하면 SSL 보안 통신이 가능합니다.

 

그리고 아래의 텍스트를 복사해서 ha의 configuration.yaml에 추가합니다.

HA 로그인 5회 이상 실패시 해당 ip 자동 차단이 됩니다.

 

http:
   server_port: 8123
   use_x_forwarded_for: true
   trusted_proxies: 
     - 127.0.0.1
     - ::1
     - 172.17.0.0/16
   ip_ban_enabled: true
   login_attempts_threshold: 5

 

HA를 재시작합니다.

 

DDNS 설정 방법 (자동으로 A record 연동)

 

외부 ip는 언제 변경될 지 모릅니다. 도메인에 a record가 연결되어 있더라도 외부 ip가 바뀌면 직접 ip 주소를 알아내는 방법을 사용하지 않고서는 서버 접속이 어려워 질 수 있습니다.

 

이럴때 활용하는게 ddns (dynamic dns)입니다.

 

iptime ddns가 주로 공유기에서 제공해주는 ddns이고, 저는 namecheap 도메인에 직접 ddns를 설정했습니다.

iptime ddns가 작동된다면 굳이 이 설정은 할 필요가 없습니다.

 

 

저같은 경우에는 10분에 한 번씩 ip 주소로 ddns를 재설정하게 cron 작업을 걸어놓았습니다.

namecheap 에서도 url에 get으로 접속하기만 하면 바로 접속한 기기의 외부 ip 주소로 ddns를 변경해주는 시스템을 제공해주고 있습니다.

namecheap 기준 a+dynamic dns record로 설정하면 ddns로 사용할 수 있게 됩니다.

 

 

실제로 여러개 사용 중입니다.

 

advanced dns에서 dynamic dns를 찾고 활성화 하면 ddns 설정시 필요한 암호가 뜹니다. 외부로 노출되면 안됩니다.

 

 

 

https://dynamicdns.park-your-domain.com/update?host=iot&domain=myhost.com&password=비밀번호

 

이 링크에 접속하게 되면 도메인의 A record 주소가 접속한 기기의 ip 주소로 변경됩니다.

리눅스에서 wget으로 호출을 하여서 ip 변경을 요청하는 방법은 아래의 명령어를 입력하면 됩니다.

wget -q -O - 'https://dynamicdns.park-your-domain.com/update?host=iot&domain=myhost.com&password=비밀번호'

 

따라서 cron 작업을 걸려면 아래처럼 crontab 에디터에서 수정하면 됩니다. (crontab -e)

/10 * * * * wget -q -O - 'https://dynamicdns.park-your-domain.com/update?host=iot&domain=myhost.com&password=비밀번호'

 

 10분에 한 번씩 dns 갱신 요청을 하게 됩니다. 이러면 이제 ip 주소가 변경되어도 걱정하지 않아도 됩니다.

 

Project DH 연락 수단

설치하다가 막히는 거나, 질문이 있으시면 언제든지 들어오셔서
문의해주세요.

 

- 1:1 오픈채팅방: https://open.kakao.com/o/sjdstfkc (추천)

- 문의 이메일: admin@projectdh.link

 

 

댓글