feat: allow configuring account TLS and default UI endpoints (#376)

This commit is contained in:
shenlan 2025-10-02 16:55:03 +08:00 committed by GitHub
parent 5a2bef2ac2
commit dda0c50dec
7 changed files with 52 additions and 15 deletions

View File

@ -5,6 +5,7 @@ import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"log/slog"
"net"
"net/http"
@ -94,11 +95,24 @@ var rootCmd = &cobra.Command{
keyFile := strings.TrimSpace(tlsSettings.KeyFile)
clientCAFile := strings.TrimSpace(tlsSettings.ClientCAFile)
useTLS := certFile != "" && keyFile != ""
useTLS := tlsSettings.IsEnabled()
var tlsConfig *tls.Config
if useTLS {
tlsConfig = &tls.Config{MinVersion: tls.VersionTLS12}
if certFile == "" || keyFile == "" {
return fmt.Errorf("tls is enabled but certFile (%q) or keyFile (%q) is empty", certFile, keyFile)
}
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return fmt.Errorf("failed to load tls certificate: %w", err)
}
tlsConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
}
if clientCAFile != "" {
caBytes, err := os.ReadFile(clientCAFile)
if err != nil {
@ -111,8 +125,13 @@ var rootCmd = &cobra.Command{
tlsConfig.ClientCAs = pool
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
} else if clientCAFile != "" {
logger.Warn("client CA configured but TLS certificates are missing; ignoring", "clientCAFile", clientCAFile)
} else {
if certFile != "" || keyFile != "" {
logger.Info("TLS disabled; certificate paths will be ignored", "certFile", certFile, "keyFile", keyFile)
}
if clientCAFile != "" {
logger.Warn("client CA configured but TLS is disabled; ignoring", "clientCAFile", clientCAFile)
}
}
srv := &http.Server{

View File

@ -6,6 +6,7 @@ server:
readTimeout: 15s
writeTimeout: 15s
tls:
enabled: true
certFile: "/etc/ssl/svc.plus.pem"
keyFile: "/etc/ssl/svc.plus.rsa.key"
clientCAFile: ""

View File

@ -4,6 +4,7 @@ import (
"errors"
"os"
"path/filepath"
"strings"
"time"
"gopkg.in/yaml.v3"
@ -26,18 +27,29 @@ type Config struct {
// Server defines HTTP server configuration.
type Server struct {
Addr string `yaml:"addr"`
ReadTimeout time.Duration `yaml:"readTimeout"`
WriteTimeout time.Duration `yaml:"writeTimeout"`
TLS TLS `yaml:"tls"`
Addr string `yaml:"addr"`
ReadTimeout time.Duration `yaml:"readTimeout"`
WriteTimeout time.Duration `yaml:"writeTimeout"`
TLS TLS `yaml:"tls"`
}
// TLS describes TLS configuration for the server listener.
type TLS struct {
CertFile string `yaml:"certFile"`
KeyFile string `yaml:"keyFile"`
ClientCAFile string `yaml:"clientCAFile"`
RedirectHTTP bool `yaml:"redirectHttp"`
Enabled *bool `yaml:"enabled"`
CertFile string `yaml:"certFile"`
KeyFile string `yaml:"keyFile"`
ClientCAFile string `yaml:"clientCAFile"`
RedirectHTTP bool `yaml:"redirectHttp"`
}
// IsEnabled reports whether TLS should be enabled for the server listener. When the
// configuration explicitly sets the Enabled field it is respected. Otherwise TLS is
// considered enabled only if both the certificate and key paths are non-empty.
func (t TLS) IsEnabled() bool {
if t.Enabled != nil {
return *t.Enabled
}
return strings.TrimSpace(t.CertFile) != "" && strings.TrimSpace(t.KeyFile) != ""
}
// Store defines persistence configuration for the account service.

View File

@ -27,6 +27,7 @@ server:
readTimeout: 15s # 读取超时
writeTimeout: 15s # 写入超时
tls: # 启用 HTTPS 时的证书配置
enabled: true # 显式启用/关闭 TLS为空时仍根据证书路径推断
certFile: "/etc/ssl/certs/account.pem"
keyFile: "/etc/ssl/private/account.key"
clientCAFile: "" # (可选)双向 TLS CA
@ -42,7 +43,7 @@ session:
ttl: 24h # 登录会话有效期
```
**TLS 提示**:当 `certFile` 和 `keyFile` 都非空时,`accountsvc` 会调用 `ListenAndServeTLS` 启动 HTTPS。如果同时希望保留 80 端口,可将 `redirectHttp` 置为 `true`,服务会开启一个额外的明文监听,将请求 301 重定向到 HTTPS。
**TLS 提示**:当 `tls.enabled` 显式为 `true` 时或 `certFile``keyFile` 均提供时,`accountsvc` 会调用 `ListenAndServeTLS` 启动 HTTPS。需要在开发环境暂时关闭 TLS可将 `tls.enabled` 设为 `false`,此时服务会忽略证书路径并仅监听 HTTP。如果同时希望保留 80 端口,可将 `redirectHttp` 置为 `true`,服务会开启一个额外的明文监听,将请求 301 重定向到 HTTPS。
**MFA 相关接口**:账号服务在 `/api/auth/mfa/*` 下提供 MFA 绑定与验证接口,默认无需额外配置即可使用,但生产环境建议将 `server.tls` 打开,确保 MFA 秘钥与 TOTP 码在传输过程中被加密。MFA 挑战 token 默认 10 分钟过期,服务器会接受 ±1 个 30 秒窗口的 TOTP 漂移,因此务必启用 NTP 等时间同步手段,避免合法验证码因时钟偏差被拒绝。
@ -73,6 +74,7 @@ server:
readTimeout: 15s
writeTimeout: 15s
tls:
enabled: true
certFile: "/etc/ssl/certs/account.pem"
keyFile: "/etc/ssl/private/account.key"
redirectHttp: true

View File

@ -79,6 +79,7 @@
server:
addr: ":8443"
tls:
enabled: true
certFile: "/etc/ssl/certs/account.pem"
keyFile: "/etc/ssl/private/account.key"
clientCAFile: "" # (可选)配置客户端证书验证

View File

@ -53,9 +53,10 @@ export default function LoginContent({ children }: LoginContentProps) {
[],
)
const accountServiceBaseUrl = (process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || 'https://127.0.0.1:8443').replace(/\/$/, '')
const githubAuthUrl = process.env.NEXT_PUBLIC_GITHUB_AUTH_URL || '/api/auth/github'
const wechatAuthUrl = process.env.NEXT_PUBLIC_WECHAT_AUTH_URL || '/api/auth/wechat'
const loginUrl = process.env.NEXT_PUBLIC_LOGIN_URL || '/api/auth/login'
const loginUrl = process.env.NEXT_PUBLIC_LOGIN_URL || `${accountServiceBaseUrl}/api/auth/login`
const socialButtonsDisabled = true

View File

@ -22,9 +22,10 @@ export default function RegisterContent() {
const searchParams = useSearchParams()
const router = useRouter()
const accountServiceBaseUrl = (process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || 'https://127.0.0.1:8443').replace(/\/$/, '')
const githubAuthUrl = process.env.NEXT_PUBLIC_GITHUB_AUTH_URL || '/api/auth/github'
const wechatAuthUrl = process.env.NEXT_PUBLIC_WECHAT_AUTH_URL || '/api/auth/wechat'
const registerUrl = process.env.NEXT_PUBLIC_REGISTER_URL || '/api/auth/register'
const registerUrl = process.env.NEXT_PUBLIC_REGISTER_URL || `${accountServiceBaseUrl}/api/auth/register`
const isSocialAuthVisible = false
useEffect(() => {