node_mtls.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package service
  2. import (
  3. "crypto/tls"
  4. "crypto/x509"
  5. "encoding/pem"
  6. "strings"
  7. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  8. "github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
  9. )
  10. // NodeMtlsCaCert returns the PEM of this panel's node-auth CA certificate (the
  11. // public half) to copy into a node's mTLS trust setting, minting the CA and the
  12. // master client cert on first call so the panel is ready to present a client
  13. // certificate to mtls nodes.
  14. func (s *NodeService) NodeMtlsCaCert() (string, error) {
  15. settings := SettingService{}
  16. ca, err := settings.EnsureNodeMtlsCA()
  17. if err != nil {
  18. return "", err
  19. }
  20. if _, err := settings.EnsureMasterClientCert(); err != nil {
  21. return "", err
  22. }
  23. return string(ca.CertPEM), nil
  24. }
  25. // ReloadMasterMtlsClient validates the master credential currently stored by
  26. // the panel and drops cached mTLS connection pools. This makes an intentional
  27. // out-of-process credential rotation take effect without restarting x-ui (and
  28. // therefore without stopping the xray child process in the same service).
  29. func (s *NodeService) ReloadMasterMtlsClient() error {
  30. stored, err := (&SettingService{}).LoadMasterClientCert()
  31. if err != nil {
  32. return err
  33. }
  34. if _, err := tls.X509KeyPair(stored.CertPEM, stored.KeyPEM); err != nil {
  35. return err
  36. }
  37. runtime.InvalidateMasterClientConnections()
  38. return nil
  39. }
  40. // SetNodeMtlsTrustCA stores the CA certificate this panel trusts for incoming
  41. // node-API client certificates. An empty value clears it (mTLS off). A
  42. // non-empty value must be a PEM certificate (fail closed). Takes effect on the
  43. // next panel restart, when the listener's ClientCAs is rebuilt.
  44. func (s *NodeService) SetNodeMtlsTrustCA(caPem string) error {
  45. caPem = strings.TrimSpace(caPem)
  46. if caPem != "" {
  47. block, _ := pem.Decode([]byte(caPem))
  48. if block == nil || block.Type != "CERTIFICATE" {
  49. return common.NewError("trust CA must be a PEM-encoded certificate")
  50. }
  51. if _, err := x509.ParseCertificate(block.Bytes); err != nil {
  52. return common.NewError("invalid trust CA certificate: " + err.Error())
  53. }
  54. }
  55. return (&SettingService{}).setString(settingNodeMtlsClientCA, caPem)
  56. }