go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers-sdk/v1/vault/keyring/keyring.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package keyring
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  
    10  	"github.com/99designs/keyring"
    11  	"github.com/rs/zerolog/log"
    12  	"go.mondoo.com/cnquery/providers-sdk/v1/vault"
    13  )
    14  
    15  var notImplemented = errors.New("not implemented")
    16  
    17  func New(serviceName string) *Vault {
    18  	return &Vault{
    19  		ServiceName: serviceName,
    20  		fileDir:     "~/.mondoo/",
    21  		filePasswordFunc: func(s string) (string, error) {
    22  			// TODO: this only applies to cases where we have no real keychain available
    23  			return "", errors.New("file-fallback is not supported")
    24  		},
    25  		// by default we do not allow a fallback to encrypted keys
    26  		allowedBackends: []keyring.BackendType{
    27  			// Windows
    28  			keyring.WinCredBackend,
    29  			// macOS
    30  			keyring.KeychainBackend,
    31  			// Linux
    32  			keyring.SecretServiceBackend,
    33  			keyring.KWalletBackend,
    34  			// General
    35  			keyring.PassBackend,
    36  		},
    37  	}
    38  }
    39  
    40  func NewEncryptedFile(path string, serviceName string, password string) *Vault {
    41  	return &Vault{
    42  		ServiceName: serviceName,
    43  		fileDir:     path,
    44  		filePasswordFunc: func(s string) (string, error) {
    45  			return password, nil
    46  		},
    47  		allowedBackends: []keyring.BackendType{
    48  			keyring.FileBackend,
    49  		},
    50  	}
    51  }
    52  
    53  func NewLinuxKernelKeyring(serviceName string) *Vault {
    54  	return &Vault{
    55  		ServiceName: serviceName,
    56  		allowedBackends: []keyring.BackendType{
    57  			keyring.KeyCtlBackend,
    58  		},
    59  		keyctlscope: "user",
    60  	}
    61  }
    62  
    63  type Vault struct {
    64  	ServiceName      string
    65  	allowedBackends  []keyring.BackendType
    66  	fileDir          string
    67  	filePasswordFunc func(s string) (string, error)
    68  	keyctlscope      string
    69  }
    70  
    71  func (v *Vault) About(context.Context, *vault.Empty) (*vault.VaultInfo, error) {
    72  	return &vault.VaultInfo{Name: "Keyring Vault: " + v.ServiceName}, nil
    73  }
    74  
    75  func (v *Vault) open() (keyring.Keyring, error) {
    76  	return keyring.Open(keyring.Config{
    77  		ServiceName:      v.ServiceName,
    78  		AllowedBackends:  v.allowedBackends,
    79  		FileDir:          v.fileDir,
    80  		FilePasswordFunc: v.filePasswordFunc,
    81  		KeyCtlScope:      v.keyctlscope,
    82  	})
    83  }
    84  
    85  func (v *Vault) Set(ctx context.Context, cred *vault.Secret) (*vault.SecretID, error) {
    86  	ring, err := v.open()
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	if cred.Encoding != vault.SecretEncoding_encoding_json && cred.Encoding != vault.SecretEncoding_encoding_undefined {
    92  		return nil, errors.New("only json encoding is supported")
    93  	}
    94  
    95  	// TODO: store data as json encoding
    96  	err = ring.Set(keyring.Item{
    97  		Key:   cred.Key,
    98  		Label: cred.Label,
    99  		Data:  cred.Data,
   100  	})
   101  
   102  	return &vault.SecretID{
   103  		Key: cred.Key,
   104  	}, err
   105  }
   106  
   107  func (v *Vault) Get(ctx context.Context, id *vault.SecretID) (*vault.Secret, error) {
   108  	if id == nil {
   109  		return nil, errors.New("id cannot be nil")
   110  	}
   111  	log.Debug().Str("id", id.Key).Msg("get secret from keyring")
   112  	ring, err := v.open()
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	i, err := ring.Get(id.Key)
   118  	if err != nil {
   119  		log.Debug().Err(err).Msg("could not retrieve secret from keyring")
   120  		return nil, vault.NotFoundError
   121  	}
   122  
   123  	return &vault.Secret{
   124  		Key:      i.Key,
   125  		Label:    i.Label,
   126  		Data:     i.Data,
   127  		Encoding: vault.SecretEncoding_encoding_json,
   128  	}, nil
   129  }