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