-
Notifications
You must be signed in to change notification settings - Fork 42
/
natsresolverconfigbuilder.go
150 lines (134 loc) · 4.53 KB
/
natsresolverconfigbuilder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Copyright 2018-2020 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"errors"
"fmt"
"github.com/nats-io/jwt/v2"
)
type NatsResolverConfigBuilder struct {
operator string
operatorName string
sysAccountSubj string
sysAccount string
sysAccountName string
cache bool
}
func NewNatsResolverConfigBuilder(cache bool) *NatsResolverConfigBuilder {
cb := NatsResolverConfigBuilder{cache: cache}
return &cb
}
func (cb *NatsResolverConfigBuilder) Add(rawClaim []byte) error {
token := string(rawClaim)
gc, err := jwt.DecodeGeneric(token)
if err != nil {
return err
}
switch gc.ClaimType() {
case jwt.OperatorClaim:
if claim, err := jwt.DecodeOperatorClaims(token); err != nil {
return err
} else {
cb.operator = token
cb.operatorName = claim.Name
}
case jwt.AccountClaim:
if claim, err := jwt.DecodeAccountClaims(token); err != nil {
return err
} else if claim.Subject == cb.sysAccountSubj {
cb.sysAccount = token
cb.sysAccountName = claim.Name
}
}
return nil
}
func (cb *NatsResolverConfigBuilder) SetOutputDir(fp string) error {
return errors.New("nats-resolver configurations don't support directory output")
}
func (cb *NatsResolverConfigBuilder) SetSystemAccount(id string) error {
cb.sysAccountSubj = id
return nil
}
const tmplPreLoad = `
# Preload the nats based resolver with the system account jwt.
# This is not necessary but avoids a bootstrapping system account.
# This only applies to the system account. Therefore other account jwt are not included here.
# To populate the resolver:
# 1) make sure that your operator has the account server URL pointing at your nats servers.
# The url must start with: "nats://"
# nsc edit operator --account-jwt-server-url nats://localhost:4222
# 2) push your accounts using: nsc push --all
# The argument to push -u is optional if your account server url is set as described.
# 3) to prune accounts use: nsc push --prune
# In order to enable prune you must set above allow_delete to true
# Later changes to the system account take precedence over the system account jwt listed here.
resolver_preload: {
%s: %s,
}
`
const tmplFull = `# Operator named %s
operator: %s
# System Account named %s
system_account: %s
# configuration of the nats based resolver
resolver {
type: full
# Directory in which the account jwt will be stored
dir: './jwt'
# In order to support jwt deletion, set to true
# If the resolver type is full delete will rename the jwt.
# This is to allow manual restoration in case of inadvertent deletion.
# To restore a jwt, remove the added suffix .delete and restart or send a reload signal.
# To free up storage you must manually delete files with the suffix .delete.
allow_delete: false
# Interval at which a nats-server with a nats based account resolver will compare
# it's state with one random nats based account resolver in the cluster and if needed,
# exchange jwt and converge on the same set of jwt.
interval: "2m"
# Timeout for lookup requests in case an account does not exist locally.
timeout: "1.9s"
}
%s
`
const tmplCache = `# Operator named %s
operator: %s
# System Account named %s
system_account: %s
# configuration of the nats based cache resolver
resolver {
type: cache
# Directory in which the account jwt will be stored
dir: './jwt'
# ttl after which the file will be removed from the cache. Set to a large value in order to disable.
ttl: "1h"
# Timeout for lookup requests in case an account does not exist locally.
timeout: "1.9s"
}
%s
`
func (cb *NatsResolverConfigBuilder) Generate() ([]byte, error) {
if cb.operator == "" {
return nil, errors.New("operator is not set")
}
if cb.sysAccountSubj == "" || cb.sysAccount == "" {
return nil, errors.New("system account is not set")
}
tmpl := tmplFull
if cb.cache {
tmpl = tmplCache
}
return []byte(fmt.Sprintf(tmpl, cb.operatorName, cb.operator, cb.sysAccountName, cb.sysAccountSubj,
fmt.Sprintf(tmplPreLoad, cb.sysAccountSubj, cb.sysAccount))), nil
}