윈도우에서 NTP Server 구축, NTP Client 설정하는 방법, 배치 파일 스크립트 작성하기 (폐쇄망에서 시간 동기화하는 요구사항 처리하기)
폐쇄망에서 시간 동기화가 하고싶다
이 포스트를 쓰게 된 배경에는 폐쇄망에 존재하는 PC들 사이에 시간을 동기화 하고 싶은 요구가 있었다.
스마트 팩토리를 지향하는 제조사에서 생산 장비에서 발생하는 데이터를 수집, 분석하는 요구가 많다.
이 데이터들을 수집, 분석하는데에 주요한 요소 중 하나가 데이터를 얻은 시간인데 이 장비들은 또 각각의 시스템 시간을 갖고 있어서 동기화를 해야하는 필요가 있다.
그러나 데이터 유출로 인한 피해가 예상되어 삼엄한 보안 관리(폐쇄망, 하드웨어/저장장치 등 반출 안됨, ...)를 적용하는게 대부분이라 인터넷에 있는 시간으로 동기화할 수 없는 문제가 있다.
이럴 때 시간 동기화 처리를 위한 방법으로 NTP서버를 만드는 것이 있다.
NTP란?
Network Time Protocol(NTP)은 네트워크로 연결되어 있는 컴퓨터들 간에 시간을 동기화하는데 사용하는 프로토콜이다.
NTP의 구조를 간단하게 설명하면 NTP서버, 즉 시간을 동기화를 제공하는 서버는 UDP의 "123" 포트에 NTP서버를 띄워놔야한다.
(기본적으로 NTP는 UDP 123번 포트를 쓴다. 마치 HTTP 80번 포트가 Web의 기본 포트 인 것과 같은 개념이라고 보면 된다.)
NTP 서버의 시간이 NTP 클라이언트들이 정확한 시간이라고 생각하고 동기화하는 기준 시간이라는 것을 인지해야한다.
NTP 클라이언트들은 NTP 서버가 있는 PC의 UDP 123번 포트로 동기화에 이용할 기준 시간을 요청하고 해당 시간으로 자신PC의 시스템 시간을 동기화한다.
위 그림에서 "192.168.0.2"라는 IP를 할당받은 PC가 NTP서버라면 같은 인터넷 망에 있는 다른 PC들은 해당 서버로 시간 동기화 요청을 할 수 있다.
폐쇄망이 아닌 일반적인 인터넷 상황에서는 NTP(아래 참조)서버를 따로 구축할 필요가 없다.
왜냐하면 국제적으로 표준 시간을 정확히 계산하고 동기화하기 위해 NTP서버를 이미 구축해서 관리하고 있기에, 그 해당 NTP서버에 시간을 요청해서 동기화하기만 하면 되기 때문이다. (클라이언트 역할로 이용만 하면 된다!)
NTP 서버 리스트(국내에서 쓸만한)는 아래에서 참고하도록 하자.
- 1.kr.pool.ntp.org
- 1.asia.pool.ntp.org
- time.kriss.re.kr
- time.google.com
- 기타...
위의 NTP서버를 이용해서 시간동기화를 마치면 우리가 좋아하는(?) 네이버 시계의 시간과 내 PC 시스템 시간이 정확히 일치하게되는 것을 볼 수 있을 것이다.
NTP Client에서 NTP Service의 IP(or domain)를 설정하고 시간을 맞춰보는 건 아래에서 해볼 예정이다.
다시 배경으로 돌아와서 폐쇄망에서는 앞서 말한 글로벌한 NTP Server를 이용할 수 없으므로, 폐쇄망 안에서 시간 동기화를 시키려면 NTP Server를 별도로 구축해야한다. (말이 구축이지 사실 간단한 설정)
윈도우10 NTP Server 만드는 방법
1) NTP Server 기능 ON
2) 방화벽 인바운드 설정 (UDP 123포트 연결 허용)
3) w32time 서비스 자동화
- NTPServer 기능 ON
→ 실행창(단축키 : window키 + R)을 키고 "regedit"입력하면 레지스트리 편집창이 뜬다.
이 편집창에서 "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer" 안에 있는 "Enabled" 의 값을 1로 설정한다.
그리고 "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config" 안에 있는 "AnnounceFlags"의 값을 5로 설정한다.
- 방화벽 인바운드 설정
→ 실행창(단축키 : window키 + R)을 키고 "wf.msc"를 입력하면 '고급 보안이 포함된 Windows Defender 방화벽'이 뜬다.
이 편집창에서 왼쪽 패널에 있는 "인바운드 규칙"을 누르고, 오른쪽 패널에서 "새 규칙..."을 누른다.
그러면 팝업창이 뜨는데 만드는 규칙 종류를 "포트"로 고른 후 "다음"을 눌러보면 규칙이 적용되는게 TCP냐 UDP냐를 물어본다.
우리는 NTP니까 UDP를 체크한다.
특정 로컬 포트에 우리가 원하는 "123"을 입력한다.
"연결허용"에 체크하고 다음을 누른다. 그 후에 규칙이 적용되는 시기가 언제냐고 나오는데 선택지로 '도메인', '개인', '공용'이라고 나온다.
전부 다 체크하고 "다음"을 누른다. 지금까지 정의했던 내용으로 규칙 이름과 설명을 이해하기 좋게 작성한다. ex) 이름 = MyNTPServer, 설명 = NTP서버 구축용으로 만든 규칙
(특별히 사진을 추가로 캡쳐하지 않아도 충분히 이해가 가능하리라 본다.)
- w32time 서비스 재시작
관리자의 권한으로 실행한 명령프롬프트(CMD)에서 "net stop w32time" → "net start w32time"을 입력해준다.
이렇게 하면 NTP 서버 설정이 끝난다.
그러나 우리는 배치 스크립트에서 처리하기를 원하니까 아래와 같이 배치 스크립트를 짜서 배치 파일을 만든 후 관리자의 권한으로 실행해서 단번에 끝내버리도록 한다.
@echo off
net start w32time
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer" /v "Enabled" /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config" /v "AnnounceFlags" /t REG_DWORD /d 5 /f
netsh advfirewall firewall add rule name="MyNTPServer" protocol=UDP dir=in localport=123 action=allow enable=yes
net stop w32time
net start w32time
위에서 열심히 레지스트리 찾아가면서 바꾼 것들과 힘겹게 방화벽으로 열어준 작업들이 저 위에 몇 문장으로 가볍게 끝난다.
위의 코드를 "ntpServer.bat" 파일이라고 이름을 짓고 저장을 한 뒤 관리자의 권한으로 실행만 하면 NTP 서버가 구축되는 것을 확인할 수 있다.
- 폐쇄망에서 안전성을 위해서 여러 PC 또는 라우터등이 NTPServer로 지정되는 것이 좋다. 왜냐하면 하나의 NTP서버에 요청이 몰리면 아까 말했듯 NTP서버의 시간의 정확성도 떨어지고 NTP서버가 죽었을 때 Failover 처리가 안되기 때문이다.
윈도우10 NTP Client 만드는 방법
1) NTPClient가 바라볼(접근하여 요청할) NTPServer의 IP를 설정한다.
2) 기타 필요한 설정들(요청 주기 등)을 설정한다.
-
- MaxPosPhaseCorrection/MaxNegPhaseCorrection : NTP 서버와 얼마의 시간 차이가 날 경우 동기화 진행을 하지 않겠다는 속성 (-1이면 시간차이에 상관없이 무조건 동기화, 3600이면 3600초 즉, 1시간 차이이상 벌어지면 동기화하지 않겠다는 의미다.)
- SpecialPollInterval : NTPServer로 몇 초마다 시간을 요청할 것인지 간격을 의미하는 속성 (600초면 10분마다 NTPServer로 요청하겠다는 의미다.)
- NTPClient가 요청할 NTPServer IP(domain) 설정
w32tm /config /syncfromflags:manual /manualpeerlist:"1.kr.pool.ntp.org" /reliable:yes /update
위의 명령어를 명령프롬프트(cmd)에서 치면, NTP Server를 "1.kr.pool.ntp.org"로 설정하는 것이다. 도메인이 아니라 IP여도 상관없고, 여러대의 서버를 등록해도 상관없다. (띄어쓰기로 구분)
w32tm /dumpreg /subkey:parameters
위의 명령어를 쳐보면 아래와 같은 화면이 나오는데 NtpServer의 값이 "1.kr.pool.ntp.org"로 나오는지를 확인해보자. (별도의 설정이 없었으면 "time.windows.com,0x9"로 나올 것이다.)
이제 위에서 말했던 설정값(SpecialPollInterval, MaxPosPhaseCorrection, MaxNegPhaseCorrection)을 변경해보자.
- 기타 설정들 설정하기
→ 실행창(단축키 : window키 + R)을 키고 "regedit"입력하면 레지스트리 편집창이 뜬다.
이 편집창에서 "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient" 안에 있는 "SpecialPollInterval"의 값을 600(10분)으로 지정한다.
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config"안에 있는 "MaxPosPhaseCorrection", "MaxNegPhaseCorrection" 값을 둘다 600으로 지정한다.
TIP → 1시간 주기로 NTP서버와 시간 동기화를 하면 30ms 내의 시간 차이가 난다고 한다. 그렇다고 너무 짧은 주기로 동기화를 하면 동기화 요청이 많아져서 NTP서버에서 계산중인 정밀한 시간에 문제가 생길 수도 있을 뿐더러 동기화가 더 잘되는 건 아니라고 한다.
→ w32time 서비스를 재시작한다.
위의 작업을 역시 스크립트로 짜는게 편하다.
@echo off
net start w32time
w32tm /config /syncfromflags:manual /manualpeerlist:"%*" /reliable:yes /update
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient" /v "SpecialPollInterval" /t REG_DWORD /d 600 /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config" /v "MaxPosPhaseCorrection" /t REG_DWORD /d 600 /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config" /v "MaxNegPhaseCorrection" /t REG_DWORD /d 600 /f
net stop w32time
net start w32time
w32tm /config /syncfromflags:manual /manualpeerlist:"%*" /reliable:yes /update
라고 되어있는 부분이 있는데 '%*' 이 문자는 배치파일을 시작할 때 arguments(parameters) 전부를 의미한다. '%1'은 첫번째 argument고 '%2'는 두 번째 argument다.
따라서 위의 코드로 된 배치파일을 수행할 때는 반드시 argument가 있어야한다. 그냥 더블클릭 또는 관리자의 권한으로 실행으로는 실행되지 않는다.
필자는 ntpClient.bat 라는 이름으로 배치 파일을 만들었고 실행은 관리자권한으로 실행된 명령프롬프트에서 "ntpClient.bat 192.168.0.2 192.168.0.3" 이라고 입력했다.
그러면 192.168.0.2와 192.168.0.3이 클라이언트가 바라볼 NTP서버가 되는 것이다.
끝으로 추가로 해야할 것들을 얘기해보면, 우리가 만든 배치파일을 재부팅할 때마다 혹은 서비스가 죽었을 때마다 다시 실행해야할 수 있다.
이 부분은 어떻게 해야할지 윈도우에 서비스로 등록하는 방법부터 시작프로그램에 등록하는 방법, 실행프로그램이 죽었는지 체크하는 배치등 해야할 일이 많다. 이부분은 추후에 알아보도록 한다.
배치 스크립트에서 레지스트리 값 수정하는 방법
명령어는 위에서 본 것 처럼 "reg add"로 시작하면 된다.
reg add "path" /v "value" /t [type] /d 값 /f
reg add로 레지스트리 값을 변경하려고 할 때 주요 파라미터다.
"path" : 변경하고자 하는 레지스트리 경로를 적어주면 된다.
"value" : 레지스트리 경로에 도달한 후 변경하고자 하는 레지스트리 속성값을 적어주면 된다.
[type] : 레지스트리 편집기 들어가보면 타입을 알 수 있는데 REG_SZ, REG_DWORD, REG_EXPAND_SZ, ... 등이 있다. 그 값을 넣어주면 된다.
값 : 말 그대로 값을 넣어주면된다. 위에서도 별도의 설정이 없었는데 10진수로 600이 들어갔었다.
/f : 이것은 강제로 덮어 쓰겠다는 의미다. 이 옵션이 없이 스크립트를 실행시켜보면 이미 값이 존재하는데 적용하겠냐는 문구가 나오고 Yes/No를 선택하라고 나온다. 그런 일련의 작업을 그냥 yes로 처리하려면 이 옵션을 넣어야한다.
참고 사이트
https://yangnoon.tistory.com/25