github.com/kbehouse/nsc@v0.0.6/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 } 32 33 func NewNatsResolverConfigBuilder() *NatsResolverConfigBuilder { 34 cb := NatsResolverConfigBuilder{} 35 return &cb 36 } 37 38 func (cb *NatsResolverConfigBuilder) Add(rawClaim []byte) error { 39 token := string(rawClaim) 40 gc, err := jwt.DecodeGeneric(token) 41 if err != nil { 42 return err 43 } 44 switch gc.ClaimType() { 45 case jwt.OperatorClaim: 46 if claim, err := jwt.DecodeOperatorClaims(token); err != nil { 47 return err 48 } else { 49 cb.operator = token 50 cb.operatorName = claim.Name 51 } 52 case jwt.AccountClaim: 53 if claim, err := jwt.DecodeAccountClaims(token); err != nil { 54 return err 55 } else if claim.Subject == cb.sysAccountSubj { 56 cb.sysAccount = token 57 cb.sysAccountName = claim.Name 58 } 59 } 60 return nil 61 } 62 63 func (cb *NatsResolverConfigBuilder) SetOutputDir(fp string) error { 64 return errors.New("nats-resolver configurations don't support directory output") 65 } 66 67 func (cb *NatsResolverConfigBuilder) SetSystemAccount(id string) error { 68 cb.sysAccountSubj = id 69 return nil 70 } 71 72 const tmpl = `# Operator named %s 73 operator: %s 74 # System Account named %s 75 system_account: %s 76 77 # configuration of the nats based resolver 78 resolver { 79 type: full 80 # Directory in which the account jwt will be stored 81 dir: './jwt' 82 # In order to support jwt deletion, set to true 83 # If the resolver type is full delete will rename the jwt. 84 # This is to allow manual restoration in case of inadvertent deletion. 85 # To restore a jwt, remove the added suffix .delete and restart or send a reload signal. 86 # To free up storage you must manually delete files with the suffix .delete. 87 allow_delete: false 88 # Interval at which a nats-server with a nats based account resolver will compare 89 # it's state with one random nats based account resolver in the cluster and if needed, 90 # exchange jwt and converge on the same set of jwt. 91 interval: "2m" 92 # Timeout for lookup requests in case an account does not exist locally. 93 timeout: "1.9s" 94 } 95 96 # Preload the nats based resolver with the system account jwt. 97 # This is not necessary but avoids a bootstrapping system account. 98 # This only applies to the system account. Therefore other account jwt are not included here. 99 # To populate the resolver: 100 # 1) make sure that your operator has the account server URL pointing at your nats servers. 101 # The url must start with: "nats://" 102 # nsc edit operator --account-jwt-server-url nats://localhost:4222 103 # 2) push your accounts using: nsc push --all 104 # The argument to push -u is optional if your account server url is set as described. 105 # 3) to prune accounts use: nsc push --prune 106 # In order to enable prune you must set above allow_delete to true 107 # Later changes to the system account take precedence over the system account jwt listed here. 108 resolver_preload: { 109 %s: %s, 110 } 111 ` 112 113 func (cb *NatsResolverConfigBuilder) Generate() ([]byte, error) { 114 if cb.operator == "" { 115 return nil, errors.New("operator is not set") 116 } 117 if cb.sysAccountSubj == "" || cb.sysAccount == "" { 118 return nil, errors.New("system account is not set") 119 } 120 return []byte(fmt.Sprintf(tmpl, cb.operatorName, cb.operator, cb.sysAccountName, 121 cb.sysAccountSubj, cb.sysAccountSubj, cb.sysAccount)), nil 122 }