From af42f14803a3745eeff58ede7f215d5979ae99ec Mon Sep 17 00:00:00 2001 From: xuans Date: Mon, 31 Aug 2026 23:42:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8A=A8=E6=80=81=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=8A=A0=E5=9B=BA=E5=B9=B6=E7=A8=B3=E5=AE=9ADNS?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/dnsprovider/tester_test.go | 5 ++++ backend/internal/servicehost/linux.go | 18 ++++++++++++- backend/internal/servicehost/linux_test.go | 18 ++++++++++++- doc/Scert开发任务清单.md | 30 ++++++++++++++++++++- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/backend/internal/dnsprovider/tester_test.go b/backend/internal/dnsprovider/tester_test.go index 87b07d6..2caf446 100644 --- a/backend/internal/dnsprovider/tester_test.go +++ b/backend/internal/dnsprovider/tester_test.go @@ -61,6 +61,7 @@ func (missingTXTResolver) LookupTXT(context.Context, string) ([]string, error) { } func TestTesterCreatesAndCleansChallengeRecord(t *testing.T) { + t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") provider := &fakeProvider{} tester := NewTesterWithResolver(fakeFactory{provider: provider}, fakeTXTResolver{provider: provider}) report, err := tester.Verify(t.Context(), Cloudflare, "example.com", map[string]string{"api_token": "secret-token"}) @@ -81,6 +82,7 @@ func TestTesterCreatesAndCleansChallengeRecord(t *testing.T) { } func TestTesterUsesConfiguredPropagationSettings(t *testing.T) { + t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") provider := &fakeProvider{} tester := NewTesterWithResolverAndSettings(fakeFactory{provider: provider}, missingTXTResolver{}, 20*time.Millisecond, 5*time.Millisecond) started := time.Now() @@ -97,6 +99,7 @@ func TestTesterUsesConfiguredPropagationSettings(t *testing.T) { } func TestTesterDoesNotCleanupWhenPresentFails(t *testing.T) { + t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") provider := &fakeProvider{presentErr: errors.New("拒绝访问")} tester := NewTester(fakeFactory{provider: provider}) _, err := tester.Verify(t.Context(), Cloudflare, "example.com", map[string]string{"api_token": "secret-token"}) @@ -109,6 +112,7 @@ func TestTesterDoesNotCleanupWhenPresentFails(t *testing.T) { } func TestTesterCleansUpWithIndependentContextAfterQueryCancellation(t *testing.T) { + t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") provider := &fakeProvider{} tester := NewTesterWithResolver(fakeFactory{provider: provider}, missingTXTResolver{}) ctx, cancel := context.WithCancel(context.Background()) @@ -127,6 +131,7 @@ func TestTesterCleansUpWithIndependentContextAfterQueryCancellation(t *testing.T } func TestTesterReportsCleanupFailureAfterQueryFailure(t *testing.T) { + t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") provider := &fakeProvider{cleanupErr: errors.New("权限不足")} tester := NewTesterWithResolver(fakeFactory{provider: provider}, missingTXTResolver{}) ctx, cancel := context.WithCancel(context.Background()) diff --git a/backend/internal/servicehost/linux.go b/backend/internal/servicehost/linux.go index 3099960..6be121b 100644 --- a/backend/internal/servicehost/linux.go +++ b/backend/internal/servicehost/linux.go @@ -181,9 +181,25 @@ func renderUnitFile(options Options) (string, error) { "Restart=on-failure", "UMask=0077", "NoNewPrivileges=yes", + "CapabilityBoundingSet=", + "AmbientCapabilities=", "PrivateTmp=yes", + "PrivateDevices=yes", "ProtectHome=yes", - "ProtectSystem=full", + "ProtectSystem=strict", + "ProtectHostname=yes", + "ProtectClock=yes", + "ProtectKernelTunables=yes", + "ProtectKernelModules=yes", + "ProtectControlGroups=yes", + "ProtectKernelLogs=yes", + "LockPersonality=yes", + "MemoryDenyWriteExecute=yes", + "RestrictNamespaces=yes", + "RestrictRealtime=yes", + "RestrictSUIDSGID=yes", + "RemoveIPC=yes", + "SystemCallArchitectures=native", "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6", ) if len(normalized.ReadWritePaths) > 0 { diff --git a/backend/internal/servicehost/linux_test.go b/backend/internal/servicehost/linux_test.go index 5c76809..ff075f0 100644 --- a/backend/internal/servicehost/linux_test.go +++ b/backend/internal/servicehost/linux_test.go @@ -34,7 +34,23 @@ func TestRenderUnitFileIncludesExecutableConfigurationAndWorkDir(t *testing.T) { "WorkingDirectory=\"/opt/Scert data\"", "ExecStart=\"/opt/Scert/scert\" --config \"/opt/Scert data/scert.json\" serve", "Restart=on-failure", - "ProtectSystem=full", + "CapabilityBoundingSet=", + "AmbientCapabilities=", + "PrivateDevices=yes", + "ProtectSystem=strict", + "ProtectHostname=yes", + "ProtectClock=yes", + "ProtectKernelTunables=yes", + "ProtectKernelModules=yes", + "ProtectControlGroups=yes", + "ProtectKernelLogs=yes", + "LockPersonality=yes", + "MemoryDenyWriteExecute=yes", + "RestrictNamespaces=yes", + "RestrictRealtime=yes", + "RestrictSUIDSGID=yes", + "RemoveIPC=yes", + "SystemCallArchitectures=native", "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6", "ReadWritePaths=\"/var/lib/scert\" \"/var/log/scert\"", "[Install]", diff --git a/doc/Scert开发任务清单.md b/doc/Scert开发任务清单.md index 3ca3028..c1bfd5b 100644 --- a/doc/Scert开发任务清单.md +++ b/doc/Scert开发任务清单.md @@ -3243,4 +3243,32 @@ Linux Ubuntu 22.04 上的 `Scert-admin` 手动启停、无开机自启动、无 - `[!]` Linux systemd 实际安装、启停、开机启动和权限效果仍需在授权 Ubuntu 主机实机验收。 - `[!]` Windows Service 实际安装、ACL、开机启动和升级仍需在授权 Windows 主机实机验收。 - `[!]` 真实 DNS 服务商、Let’s Encrypt Production、远程 SSH 部署、Nginx 反向代理、生产 HTTPS、MySQL 和真实防火墙链路仍需目标环境验收。 -- `[!]` 工作区已有的 `desktop/desktop.exe`、`desktop/frontend/dist/index.html`、`dist/`、`backend/.patch*` 和 `backend/*.exe` 未删除、未纳入源码提交。 \ No newline at end of file + +## 八十六、动态 systemd 加固与 DNS 测试环境隔离复核(2026-08-31) + +### 86.1 本轮需求清单 + +- `[✓]` 动态 Linux systemd unit 与固定部署 unit 使用一致的最小权限和系统目录保护策略。 +- `[✓]` 动态 unit 增加能力集、设备、内核、命名空间、实时性、SUID 和系统调用架构限制。 +- `[✓]` DNS Provider 单元测试显式关闭 CNAME 跟随,避免测试环境 DNS 不可用时进入外部网络等待。 +- `[✓]` 保留生产环境默认 CNAME 委派行为,不通过测试配置改变运行时默认策略。 + +### 86.2 验证状态 + +- `[✓]` `go test -p 1 -count=1 -timeout=3m ./...` +- `[✓]` `go test -race -p 1 -count=1 -timeout=5m ./...` +- `[✓]` `go vet -p=1 ./...` +- `[✓]` `go mod verify` +- `[✓]` Linux amd64 `servicehost` 测试二进制交叉编译。 +- `[✓]` 网页端 `npm.cmd run build`。 +- `[✓]` 桌面端 Go `go test -p 1 -count=1 ./...`。 +- `[✓]` `git diff --check`。 +- `[~]` 本轮源码提交和远程推送待完成。 + +### 86.3 复审边界 + +- `[!]` Linux systemd unit 的实际安装、启停、开机启动和沙箱权限效果仍需授权 Ubuntu 主机实机验收。 +- `[!]` 当前未运行会覆盖用户保留桌面构建产物的桌面前端生产构建。 +- `[!]` 真实 DNS 服务商、Let’s Encrypt Production、远程 SSH 部署、Nginx 反向代理、生产 HTTPS、Windows Service、Windows ACL、MySQL 和真实防火墙链路仍需目标环境验收。 +- `[!]` 工作区已有的 `desktop/desktop.exe`、`desktop/frontend/dist/index.html`、`dist/`、`backend/.patch*` 和 `backend/*.exe` 未删除、未纳入本轮源码提交。 +- `[!]` 工作区已有的 `desktop/desktop.exe`、`desktop/frontend/dist/index.html`、`dist/`、`backend/.patch*` 和 `backend/*.exe` 未删除、未纳入源码提交。