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  }