github.com/influxdata/influxdb/v2@v2.7.6/secret/storage.go (about)

     1  package secret
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"errors"
     7  
     8  	"github.com/influxdata/influxdb/v2"
     9  	"github.com/influxdata/influxdb/v2/kit/platform"
    10  	errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors"
    11  	"github.com/influxdata/influxdb/v2/kv"
    12  )
    13  
    14  var secretBucket = []byte("secretsv1")
    15  
    16  // Storage is a store translation layer between the data storage unit and the
    17  // service layer.
    18  type Storage struct {
    19  	store kv.Store
    20  }
    21  
    22  // NewStore creates a new storage system
    23  func NewStore(s kv.Store) (*Storage, error) {
    24  	return &Storage{s}, nil
    25  }
    26  
    27  func (s *Storage) View(ctx context.Context, fn func(kv.Tx) error) error {
    28  	return s.store.View(ctx, fn)
    29  }
    30  
    31  func (s *Storage) Update(ctx context.Context, fn func(kv.Tx) error) error {
    32  	return s.store.Update(ctx, fn)
    33  }
    34  
    35  // GetSecret Returns the value of a secret
    36  func (s *Storage) GetSecret(ctx context.Context, tx kv.Tx, orgID platform.ID, k string) (string, error) {
    37  	key, err := encodeSecretKey(orgID, k)
    38  	if err != nil {
    39  		return "", err
    40  	}
    41  
    42  	b, err := tx.Bucket(secretBucket)
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  
    47  	val, err := b.Get(key)
    48  	if kv.IsNotFound(err) {
    49  		return "", &errors2.Error{
    50  			Code: errors2.ENotFound,
    51  			Msg:  influxdb.ErrSecretNotFound,
    52  		}
    53  	}
    54  
    55  	if err != nil {
    56  		return "", err
    57  	}
    58  
    59  	v, err := decodeSecretValue(val)
    60  	if err != nil {
    61  		return "", err
    62  	}
    63  
    64  	return v, nil
    65  }
    66  
    67  // ListSecrets returns a list of secret keys
    68  func (s *Storage) ListSecret(ctx context.Context, tx kv.Tx, orgID platform.ID) ([]string, error) {
    69  	b, err := tx.Bucket(secretBucket)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	prefix, err := orgID.Encode()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	cur, err := b.ForwardCursor(prefix, kv.WithCursorPrefix(prefix))
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	keys := []string{}
    85  
    86  	err = kv.WalkCursor(ctx, cur, func(k, v []byte) (bool, error) {
    87  		id, key, err := decodeSecretKey(k)
    88  		if err != nil {
    89  			return false, err
    90  		}
    91  
    92  		if id != orgID {
    93  			// We've reached the end of the keyspace for the provided orgID
    94  			return false, nil
    95  		}
    96  
    97  		keys = append(keys, key)
    98  
    99  		return true, nil
   100  	})
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	return keys, nil
   106  }
   107  
   108  // PutSecret sets a secret in the db.
   109  func (s *Storage) PutSecret(ctx context.Context, tx kv.Tx, orgID platform.ID, k, v string) error {
   110  	key, err := encodeSecretKey(orgID, k)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	val := encodeSecretValue(v)
   116  
   117  	b, err := tx.Bucket(secretBucket)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	if err := b.Put(key, val); err != nil {
   123  		return err
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // DeleteSecret removes a secret for the db
   130  func (s *Storage) DeleteSecret(ctx context.Context, tx kv.Tx, orgID platform.ID, k string) error {
   131  	key, err := encodeSecretKey(orgID, k)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	b, err := tx.Bucket(secretBucket)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	return b.Delete(key)
   142  }
   143  
   144  func encodeSecretKey(orgID platform.ID, k string) ([]byte, error) {
   145  	buf, err := orgID.Encode()
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	key := make([]byte, 0, platform.IDLength+len(k))
   151  	key = append(key, buf...)
   152  	key = append(key, k...)
   153  
   154  	return key, nil
   155  }
   156  
   157  func decodeSecretKey(key []byte) (platform.ID, string, error) {
   158  	if len(key) < platform.IDLength {
   159  		// This should not happen.
   160  		return platform.InvalidID(), "", errors.New("provided key is too short to contain an ID (please report this error)")
   161  	}
   162  
   163  	var id platform.ID
   164  	if err := id.Decode(key[:platform.IDLength]); err != nil {
   165  		return platform.InvalidID(), "", err
   166  	}
   167  
   168  	k := string(key[platform.IDLength:])
   169  
   170  	return id, k, nil
   171  }
   172  
   173  func decodeSecretValue(val []byte) (string, error) {
   174  	// store the secret value base64 encoded so that it's marginally better than plaintext
   175  	v, err := base64.StdEncoding.DecodeString(string(val))
   176  	if err != nil {
   177  		return "", err
   178  	}
   179  
   180  	return string(v), nil
   181  }
   182  
   183  func encodeSecretValue(v string) []byte {
   184  	val := make([]byte, base64.StdEncoding.EncodedLen(len(v)))
   185  	base64.StdEncoding.Encode(val, []byte(v))
   186  	return val
   187  }