mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-16 11:04:42 -07:00
Merge pull request #1862 from nats-io/varz-jwt
[added] field to varz output containing the operator jwt
This commit is contained in:
@@ -32,34 +32,39 @@ const jwtPrefix = "eyJ"
|
||||
|
||||
// ReadOperatorJWT will read a jwt file for an operator claim. This can be a decorated file.
|
||||
func ReadOperatorJWT(jwtfile string) (*jwt.OperatorClaims, error) {
|
||||
_, claim, err := readOperatorJWT(jwtfile)
|
||||
return claim, err
|
||||
}
|
||||
|
||||
func readOperatorJWT(jwtfile string) (string, *jwt.OperatorClaims, error) {
|
||||
contents, err := ioutil.ReadFile(jwtfile)
|
||||
if err != nil {
|
||||
// Check to see if the JWT has been inlined.
|
||||
if !strings.HasPrefix(jwtfile, jwtPrefix) {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
// We may have an inline jwt here.
|
||||
contents = []byte(jwtfile)
|
||||
}
|
||||
defer wipeSlice(contents)
|
||||
|
||||
var claim string
|
||||
var theJWT string
|
||||
items := nscDecoratedRe.FindAllSubmatch(contents, -1)
|
||||
if len(items) == 0 {
|
||||
claim = string(contents)
|
||||
theJWT = string(contents)
|
||||
} else {
|
||||
// First result should be the JWT.
|
||||
// We copy here so that if the file contained a seed file too we wipe appropriately.
|
||||
raw := items[0][1]
|
||||
tmp := make([]byte, len(raw))
|
||||
copy(tmp, raw)
|
||||
claim = string(tmp)
|
||||
theJWT = string(tmp)
|
||||
}
|
||||
opc, err := jwt.DecodeOperatorClaims(claim)
|
||||
opc, err := jwt.DecodeOperatorClaims(theJWT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
return opc, nil
|
||||
return theJWT, opc, nil
|
||||
}
|
||||
|
||||
// Just wipe slice with 'x', for clearing contents of nkey seed file.
|
||||
|
||||
@@ -992,59 +992,61 @@ func (s *Server) HandleStacksz(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Varz will output server information on the monitoring port at /varz.
|
||||
type Varz struct {
|
||||
ID string `json:"server_id"`
|
||||
Name string `json:"server_name"`
|
||||
Version string `json:"version"`
|
||||
Proto int `json:"proto"`
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
GoVersion string `json:"go"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
AuthRequired bool `json:"auth_required,omitempty"`
|
||||
TLSRequired bool `json:"tls_required,omitempty"`
|
||||
TLSVerify bool `json:"tls_verify,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
ClientConnectURLs []string `json:"connect_urls,omitempty"`
|
||||
WSConnectURLs []string `json:"ws_connect_urls,omitempty"`
|
||||
MaxConn int `json:"max_connections"`
|
||||
MaxSubs int `json:"max_subscriptions,omitempty"`
|
||||
PingInterval time.Duration `json:"ping_interval"`
|
||||
MaxPingsOut int `json:"ping_max"`
|
||||
HTTPHost string `json:"http_host"`
|
||||
HTTPPort int `json:"http_port"`
|
||||
HTTPBasePath string `json:"http_base_path"`
|
||||
HTTPSPort int `json:"https_port"`
|
||||
AuthTimeout float64 `json:"auth_timeout"`
|
||||
MaxControlLine int32 `json:"max_control_line"`
|
||||
MaxPayload int `json:"max_payload"`
|
||||
MaxPending int64 `json:"max_pending"`
|
||||
Cluster ClusterOptsVarz `json:"cluster,omitempty"`
|
||||
Gateway GatewayOptsVarz `json:"gateway,omitempty"`
|
||||
LeafNode LeafNodeOptsVarz `json:"leaf,omitempty"`
|
||||
JetStream JetStreamVarz `json:"jetstream,omitempty"`
|
||||
TLSTimeout float64 `json:"tls_timeout"`
|
||||
WriteDeadline time.Duration `json:"write_deadline"`
|
||||
Start time.Time `json:"start"`
|
||||
Now time.Time `json:"now"`
|
||||
Uptime string `json:"uptime"`
|
||||
Mem int64 `json:"mem"`
|
||||
Cores int `json:"cores"`
|
||||
MaxProcs int `json:"gomaxprocs"`
|
||||
CPU float64 `json:"cpu"`
|
||||
Connections int `json:"connections"`
|
||||
TotalConnections uint64 `json:"total_connections"`
|
||||
Routes int `json:"routes"`
|
||||
Remotes int `json:"remotes"`
|
||||
Leafs int `json:"leafnodes"`
|
||||
InMsgs int64 `json:"in_msgs"`
|
||||
OutMsgs int64 `json:"out_msgs"`
|
||||
InBytes int64 `json:"in_bytes"`
|
||||
OutBytes int64 `json:"out_bytes"`
|
||||
SlowConsumers int64 `json:"slow_consumers"`
|
||||
Subscriptions uint32 `json:"subscriptions"`
|
||||
HTTPReqStats map[string]uint64 `json:"http_req_stats"`
|
||||
ConfigLoadTime time.Time `json:"config_load_time"`
|
||||
Tags jwt.TagList `json:"tags,omitempty"`
|
||||
ID string `json:"server_id"`
|
||||
Name string `json:"server_name"`
|
||||
Version string `json:"version"`
|
||||
Proto int `json:"proto"`
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
GoVersion string `json:"go"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
AuthRequired bool `json:"auth_required,omitempty"`
|
||||
TLSRequired bool `json:"tls_required,omitempty"`
|
||||
TLSVerify bool `json:"tls_verify,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
ClientConnectURLs []string `json:"connect_urls,omitempty"`
|
||||
WSConnectURLs []string `json:"ws_connect_urls,omitempty"`
|
||||
MaxConn int `json:"max_connections"`
|
||||
MaxSubs int `json:"max_subscriptions,omitempty"`
|
||||
PingInterval time.Duration `json:"ping_interval"`
|
||||
MaxPingsOut int `json:"ping_max"`
|
||||
HTTPHost string `json:"http_host"`
|
||||
HTTPPort int `json:"http_port"`
|
||||
HTTPBasePath string `json:"http_base_path"`
|
||||
HTTPSPort int `json:"https_port"`
|
||||
AuthTimeout float64 `json:"auth_timeout"`
|
||||
MaxControlLine int32 `json:"max_control_line"`
|
||||
MaxPayload int `json:"max_payload"`
|
||||
MaxPending int64 `json:"max_pending"`
|
||||
Cluster ClusterOptsVarz `json:"cluster,omitempty"`
|
||||
Gateway GatewayOptsVarz `json:"gateway,omitempty"`
|
||||
LeafNode LeafNodeOptsVarz `json:"leaf,omitempty"`
|
||||
JetStream JetStreamVarz `json:"jetstream,omitempty"`
|
||||
TLSTimeout float64 `json:"tls_timeout"`
|
||||
WriteDeadline time.Duration `json:"write_deadline"`
|
||||
Start time.Time `json:"start"`
|
||||
Now time.Time `json:"now"`
|
||||
Uptime string `json:"uptime"`
|
||||
Mem int64 `json:"mem"`
|
||||
Cores int `json:"cores"`
|
||||
MaxProcs int `json:"gomaxprocs"`
|
||||
CPU float64 `json:"cpu"`
|
||||
Connections int `json:"connections"`
|
||||
TotalConnections uint64 `json:"total_connections"`
|
||||
Routes int `json:"routes"`
|
||||
Remotes int `json:"remotes"`
|
||||
Leafs int `json:"leafnodes"`
|
||||
InMsgs int64 `json:"in_msgs"`
|
||||
OutMsgs int64 `json:"out_msgs"`
|
||||
InBytes int64 `json:"in_bytes"`
|
||||
OutBytes int64 `json:"out_bytes"`
|
||||
SlowConsumers int64 `json:"slow_consumers"`
|
||||
Subscriptions uint32 `json:"subscriptions"`
|
||||
HTTPReqStats map[string]uint64 `json:"http_req_stats"`
|
||||
ConfigLoadTime time.Time `json:"config_load_time"`
|
||||
Tags jwt.TagList `json:"tags,omitempty"`
|
||||
TrustedOperatorsJwt []string `json:"trusted_operators_jwt,omitempty"`
|
||||
TrustedOperatorsClaim []*jwt.OperatorClaims `json:"trusted_operators_claim,omitempty"`
|
||||
}
|
||||
|
||||
// JetStreamVarz contains basic runtime information about jetstream
|
||||
@@ -1251,11 +1253,13 @@ func (s *Server) createVarz(pcpu float64, rss int64) *Varz {
|
||||
TLSVerify: leafTlsVerify,
|
||||
Remotes: []RemoteLeafOptsVarz{},
|
||||
},
|
||||
Start: s.start,
|
||||
MaxSubs: opts.MaxSubs,
|
||||
Cores: numCores,
|
||||
MaxProcs: maxProcs,
|
||||
Tags: opts.Tags,
|
||||
Start: s.start,
|
||||
MaxSubs: opts.MaxSubs,
|
||||
Cores: numCores,
|
||||
MaxProcs: maxProcs,
|
||||
Tags: opts.Tags,
|
||||
TrustedOperatorsJwt: opts.operatorJWT,
|
||||
TrustedOperatorsClaim: opts.TrustedOperators,
|
||||
}
|
||||
if len(opts.Routes) > 0 {
|
||||
varz.Cluster.URLs = urlsToStrings(opts.Routes)
|
||||
@@ -1281,7 +1285,6 @@ func (s *Server) createVarz(pcpu float64, rss int64) *Varz {
|
||||
}
|
||||
varz.LeafNode.Remotes = rlna
|
||||
}
|
||||
|
||||
if s.js != nil {
|
||||
s.js.mu.RLock()
|
||||
varz.JetStream = JetStreamVarz{
|
||||
|
||||
@@ -3495,6 +3495,43 @@ func pollLeafz(t *testing.T, s *Server, mode int, url string, opts *LeafzOptions
|
||||
return l
|
||||
}
|
||||
|
||||
func TestMonitorOpJWT(t *testing.T) {
|
||||
content := `
|
||||
listen: "127.0.0.1:-1"
|
||||
http: "127.0.0.1:-1"
|
||||
operator = "../test/configs/nkeys/op.jwt"
|
||||
resolver = MEMORY
|
||||
`
|
||||
conf := createConfFile(t, []byte(content))
|
||||
defer os.Remove(conf)
|
||||
sa, _ := RunServerWithConfig(conf)
|
||||
defer sa.Shutdown()
|
||||
|
||||
theJWT, err := ioutil.ReadFile("../test/configs/nkeys/op.jwt")
|
||||
require_NoError(t, err)
|
||||
theJWT = []byte(strings.Split(string(theJWT), "\n")[1])
|
||||
claim, err := jwt.DecodeOperatorClaims(string(theJWT))
|
||||
require_NoError(t, err)
|
||||
|
||||
pollURL := fmt.Sprintf("http://127.0.0.1:%d/varz", sa.MonitorAddr().Port)
|
||||
for pollMode := 1; pollMode < 2; pollMode++ {
|
||||
l := pollVarz(t, sa, pollMode, pollURL, nil)
|
||||
|
||||
if len(l.TrustedOperatorsJwt) != 1 {
|
||||
t.Fatalf("Expected one operator jwt")
|
||||
}
|
||||
if len(l.TrustedOperatorsClaim) != 1 {
|
||||
t.Fatalf("Expected one operator claim")
|
||||
}
|
||||
if l.TrustedOperatorsJwt[0] != string(theJWT) {
|
||||
t.Fatalf("Expected operator to be identical to configuration")
|
||||
}
|
||||
if !reflect.DeepEqual(l.TrustedOperatorsClaim[0], claim) {
|
||||
t.Fatal("claims need to be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonitorLeafz(t *testing.T) {
|
||||
content := `
|
||||
listen: "127.0.0.1:-1"
|
||||
|
||||
@@ -238,7 +238,6 @@ type Options struct {
|
||||
TrustedOperators []*jwt.OperatorClaims `json:"-"`
|
||||
AccountResolver AccountResolver `json:"-"`
|
||||
AccountResolverTLSConfig *tls.Config `json:"-"`
|
||||
resolverPreloads map[string]string
|
||||
|
||||
CustomClientAuthentication Authentication `json:"-"`
|
||||
CustomRouterAuthentication Authentication `json:"-"`
|
||||
@@ -265,6 +264,10 @@ type Options struct {
|
||||
inConfig map[string]bool
|
||||
inCmdLine map[string]bool
|
||||
|
||||
// private fields for operator mode
|
||||
operatorJWT []string
|
||||
resolverPreloads map[string]string
|
||||
|
||||
// private fields, used for testing
|
||||
gatewaysSolicitDelay time.Duration
|
||||
routeProto int
|
||||
@@ -862,12 +865,13 @@ func (o *Options) processConfigFileLine(k string, v interface{}, errors *[]error
|
||||
// Assume for now these are file names, but they can also be the JWT itself inline.
|
||||
o.TrustedOperators = make([]*jwt.OperatorClaims, 0, len(opFiles))
|
||||
for _, fname := range opFiles {
|
||||
opc, err := ReadOperatorJWT(fname)
|
||||
theJWT, opc, err := readOperatorJWT(fname)
|
||||
if err != nil {
|
||||
err := &configErr{tk, fmt.Sprintf("error parsing operator JWT: %v", err)}
|
||||
*errors = append(*errors, err)
|
||||
continue
|
||||
}
|
||||
o.operatorJWT = append(o.operatorJWT, theJWT)
|
||||
o.TrustedOperators = append(o.TrustedOperators, opc)
|
||||
}
|
||||
if len(o.TrustedOperators) == 1 {
|
||||
|
||||
Reference in New Issue
Block a user