로컬 머신 시간을 조정하지 않고 LXC에서 ntpd만 서버로 실행하는 방법

로컬 머신 시간을 조정하지 않고 LXC에서 ntpd만 서버로 실행하는 방법

장치의 시계를 LXC 내에서 실행되는 CentOS-7 서버와 동기화해야 합니다. 서버에서는 패키지 ntpd에서 사용하려고 시도하지만 다른 제품에는 열려 있습니다. ntp이 질문은 ntpd서버 또는 이에 상응하는 설정에 관한 것입니다.

지금까지 나는 이것을 시도했다/etc/ntp.conf

driftfile /var/lib/ntp/drift
restrict default nomodify notrap nopeer noquery

restrict 127.0.0.1
restrict ::1

server 127.127.1.1 iburst
fudge  127.127.1.1 stratum 8

disable monitor

여기에는 두 가지 문제가 있습니다.

  1. ntpd녹음 후 종료cap_set_proc() failed to drop root privileges: Operation not permitted
  2. ntpd현지 시간을 조정하려고 합니다. 실패했지만 시도했습니다. 이것이 유일한 문제이고 로그에 오류 메시지가 있는 경우에는 괜찮습니다.

/var/log/messagesntpd를 시작하려고 시도한 결과 전체 출력:

systemd: Starting Network Time Service...
ntpd[20154]: ntpd [email protected] Wed Apr 12 21:24:06 UTC 2017 (1)
ntpd[20155]: proto: precision = 0.120 usec
ntpd[20155]: ntp_adjtime() failed: Operation not permitted
systemd: Started Network Time Service.
ntpd[20155]: 0.0.0.0 c01d 0d kern kernel time sync enabled
ntpd[20155]: Listen and drop on 0 v4wildcard 0.0.0.0 UDP 123
ntpd[20155]: Listen and drop on 1 v6wildcard :: UDP 123
ntpd[20155]: Listen normally on 2 lo 127.0.0.1 UDP 123
ntpd[20155]: Listen normally on 3 eth0 hidden:A.B.C.D UDP 123
ntpd[20155]: Listen normally on 4 tun0 hidden:E.F.G.H UDP 123
ntpd[20155]: Listening on routing socket on fd #21 for interface updates
ntpd[20155]: 0.0.0.0 c016 06 restart
ntpd[20155]: ntp_adjtime() failed: Operation not permitted
ntpd[20155]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
ntpd[20155]: 0.0.0.0 c011 01 freq_not_set
ntpd[20155]: cap_set_proc() failed to drop root privileges: Operation not permitted
systemd: ntpd.service: main process exited, code=exited, status=255/n/a
systemd: Unit ntpd.service entered failed state.
systemd: ntpd.service failed.

답변1

댓글에서 논의한 바와 같이,만성병 환자-x최근에는 시스템 시계 변경을 시도하지 않는 새로운 옵션이 추가 되어 특히 컨테이너 작업에 적합합니다. 안타깝게도 이 옵션을 받은 첫 번째 버전(3.2)은 철저하지 않았으며 여전히 Linux 기능을 요청했기 때문에 여전히 실패했습니다.

깁스CentOS7 LXC 컨테이너(CentOS가 아닌 호스트 포함)의 chronyd 패키지 chrony 버전 3.2-2.el7에는 옵션이 포함되어 있지만 -x실제로 버그 수정은 여기에 없습니다.

# strace /usr/sbin/chronyd -x -d

[...]

[pid   571] capget({_LINUX_CAPABILITY_VERSION_3, 0}, NULL) = 0
[pid   571] capset({_LINUX_CAPABILITY_VERSION_3, 0}, {1<<CAP_NET_BIND_SERVICE|1<<CAP_SYS_TIME, 1<<CAP_NET_BIND_SERVICE|1<<CAP_SYS_TIME, 0}) = -1 EPERM (Operation not permitted)

따라서 수정할 수 없는 바이너리 크로니드가 금지된 기능을 요청하는 것을 방지할 수 있다면 작동할 것입니다(3.3 버그 수정이 바로 이것이었습니다). 좋은 소식입니다. LD_PRELOAD/를 사용할 수 있습니다 .dlsym()포장지.

다른 Linux 시스템에서 컴파일(실제로는 Debian 9 호스트에서 컴파일되었으며 CentOS7 컨테이너에서 문제 없이 실행됨) 이 코드는 이라고 불리며 capsetwrapper.c구조 정의가 발견되었습니다.거기예를 들어(커널 3.10에서도 변경되지 않았습니다).

#define _GNU_SOURCE 1
#include <dlfcn.h>

#include <sys/capability.h>

int capset(cap_user_header_t hdrp, const cap_user_data_t datap) {
    int (*orig_capset)(cap_user_header_t,const cap_user_data_t)=dlsym(RTLD_NEXT,"capset");
    datap->effective &= ~ (1<<CAP_SYS_TIME);
    datap->permitted &= ~ (1<<CAP_SYS_TIME);
    return orig_capset(hdrp, datap);
}

다음과 같은 특정 방법을 사용하십시오(라이브러리를 LD_PRELOAD사용하기에 적합하게 만들기 위해):

gcc -shared -fPIC -o libcapsetwrapper.so capsetwrapper.c -ldl

작동 방식은 다음과 같습니다.

[root@centos7-amd64bis ~]# LD_PRELOAD=/root/libcapsetwrapper.so /usr/sbin/chronyd -x -d
2019-03-24T10:09:58Z chronyd version 3.2 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SECHASH +SIGND +ASYNCDNS +IPV6 +DEBUG)
2019-03-24T10:09:58Z Disabled control of system clock
2019-03-24T10:09:58Z Frequency 0.000 +/- 1000000.000 ppm read from /var/lib/chrony/drift

런타임 시 기능을 확인하세요.

# egrep '^Cap(Prm|Eff)' /proc/$(pidof chronyd)/status
CapPrm: 0000000000000400
CapEff: 0000000000000400

위에 표시된 나머지인 0x400을 표시합니다 1<<CAP_NET_BIND_SERVICE.

시스템에 통합하려면:

  • 포장지를 다음 libcapsetwrapper.so과 같이 배치합니다./usr/local/lib/libcapsetwrapper.so

  • systemctl edit chronyd재정의 검사를 사용하면 CAP_SYS_TIME실행 파일이 다음과 같이 시작됩니다.

    [Unit]
    ConditionCapability=
    
    [Service]
    ExecStart=
    ExecStart=/bin/sh -c 'export LD_PRELOAD=/usr/local/lib/libcapsetwrapper.so; exec /usr/sbin/chronyd -x'
    

    죄송합니다. 매개변수를 재사용할 수 없습니다 $OPTIONS(비어 있으므로 -x옵션을 에서 로드해야 함 /etc/sysconfig/chronyd). 하지만 더 체계화된 지식이 있으면 가능합니다.

작업 결과:

# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
  Drop-In: /etc/systemd/system/chronyd.service.d
           `-override.conf
   Active: active (running) since Sun 2019-03-24 10:24:26 UTC; 13min ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 843 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
  Process: 839 ExecStart=/bin/sh -c export LD_PRELOAD=/usr/local/lib/libcapsetwrapper.so; exec /usr/sbin/chronyd -x (code=exited, status=0/SUCCESS)
 Main PID: 841 (chronyd)
   CGroup: /system.slice/chronyd.service
           `-841 /usr/sbin/chronyd -x

테스트되지 않은 것은 기본 SELinux 환경(여기에서는 사용할 수 없음)이 사전 로드 작업을 허용하는지 아니면 더 많은 작업을 수행해야 하는지 /usr/local/lib/libcapsetwrapper.so(반드시 사용 restorecon)입니다.

답변2

버전 이후1908년 7월 7일CentOS에는 chrony버전이 있습니다3.4이 플래그를 올바르게 지원 하며 -x약간의 구성 조정을 통해 LXC에서 실행될 수 있습니다.

  • 기본적 으로 /usr/lib/systemd/system/chronyd.serviceLXC에서 ConditionCapability=CAP_SYS_TIME실행할 때는 없어야 하므로 -x파일에 이 삭제 항목을 추가하여 제거하세요./etc/systemd/system/chronyd.service.d/lxc.conf
    [Unit]
    # Default service has:
    # ConditionCapability=CAP_SYS_TIME
    # which does not work under LXC and causes service to refuse to start
    # Clear it.
    ConditionCapability=
  • 편집 /etc/sysconfig/chronyd하고 마지막 -x에 추가하세요OPTIONSOPTIONS="-x"

  • /etc/chrony.confNTP 서버와 동기화하지 않고 대신 로컬 시계의 시간을 제공하도록 변경합니다 . 다른 모든 server항목을 제거/비활성화하고 다음을 추가합니다.

    # Comment out default/other server entries
    #server 0.centos.pool.ntp.org iburst
    #server 1.centos.pool.ntp.org iburst
    #server 2.centos.pool.ntp.org iburst
    #server 3.centos.pool.ntp.org iburst
    #
    # Add these as per https://www.thegeekdiary.com/centos-rhel-7-chrony-how-to-sync-to-local-clock/
    server 127.127.1.0
    local stratum 10
    allow all

예제의 내용이 귀하에게 적합하지 않을 수 있으므로 allow귀하의 필요에 맞게 지침을 검토하십시오 .allow all

  • 서비스를 다시 로드하고 다시 시작하세요.
    systemctl daemon-reload
    systemctl restart chronyd

그래야 합니다.

답변3

작동하게 하는 방법을 찾았지만 내 솔루션이 만족스럽지 않아 여전히 더 나은 답변을 찾고 있습니다.

ntpd파트 1: 루트 권한을 포기하려는 시도를 차단했습니다 .

기본 값은 다음 /usr/lib/systemd/system/ntpd.service과 같습니다:

[Service]
EnvironmentFile=-/etc/sysconfig/ntpd
ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS

-u ntp:ntp그래서 배치하여 "제거"합니다./etc/systemd/system/ntpd.service.d/local.conf

[Service]
ExecStart=
ExecStart=/usr/sbin/ntpd $OPTIONS

이를 통해 ntpd루트로 계속 실행할 수 있습니다. 작동하지만 이 접근 방식은 만족스럽지 않습니다.

2부. 현지 시간 부분을 업데이트하지 않음

/etc/ntp.conf이 줄을 추가하면 서비스가 시작될 때 오류를 설정하지 않고 3번 기록하는 대신 1번의 오류만 기록 disable kernel하게 됩니다 . 시계를 변경할 수 없으므로 이는 허용됩니다. 이상적으로는 시계를 변경하려고 시도하지도 않습니다.ntpdntp_adjtime() failed: Operation not permitted

관련 정보