如何在 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
這裡有兩個問題。
ntpd
記錄後終止cap_set_proc() failed to drop root privileges: Operation not permitted
ntpd
正在嘗試調整當地時間。它失敗了,但它會嘗試。如果這是唯一的問題並且我在日誌中有錯誤消息,我可以接受。
/var/log/messages
嘗試啟動 ntpd 導致的完整輸出:systemd: Starting Network Time Service... ntpd[20154]: ntpd 4.2.6p5@1.2349-o 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.
正如評論中所討論的,chrony最近收到了一個
-x
不嘗試更改系統時鐘的新選項,使其特別適用於容器操作。唉,接收這個選項的第一個版本(3.2)並不徹底,仍然要求 Linux 功能,所以仍然失敗。使用選項從CentOS7 LXC 容器(帶有非 CentOS 主機)中的 chrony 版本 3.2-2.el7 中跟踪 chronyd
-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)
因此,如果您可以阻止不可修改的二進制 chronyd 請求禁止的功能,它將執行(這就是 3.3 錯誤修復的內容)。好消息,可以使用
LD_PRELOAD
/dlsym()
包裝器。在其他地方的其他 Linux 系統上編譯(編譯實際上是在 Debian 9 主機上進行的,在 CentOS7 容器上執行沒有任何麻煩)這個程式碼稱為,例如在那裡
capsetwrapper.c
找到結構定義(這沒有t 從核心 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
1<<CAP_NET_BIND_SERVICE
顯示 0x400 這是上面看到的剩餘部分。要將其集成到系統中:
- 將
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
它)。