feat: allow configuring account TLS and default UI endpoints (#376)
This commit is contained in:
parent
5a2bef2ac2
commit
dda0c50dec
@ -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{
|
||||
|
||||
@ -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: ""
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -79,6 +79,7 @@
|
||||
server:
|
||||
addr: ":8443"
|
||||
tls:
|
||||
enabled: true
|
||||
certFile: "/etc/ssl/certs/account.pem"
|
||||
keyFile: "/etc/ssl/private/account.key"
|
||||
clientCAFile: "" # (可选)配置客户端证书验证
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user