github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/secrets/store.go (about)

     1  package secrets
     2  
     3  import (
     4  	"fmt"
     5  
     6  	api_v1 "k8s.io/api/core/v1"
     7  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     8  )
     9  
    10  // SecretReference holds a reference to a secret stored on the file system.
    11  type SecretReference struct {
    12  	Secret *api_v1.Secret
    13  	Path   string
    14  	Error  error
    15  }
    16  
    17  // SecretFileManager manages secrets on the file system.
    18  type SecretFileManager interface {
    19  	AddOrUpdateSecret(secret *api_v1.Secret) string
    20  	DeleteSecret(key string)
    21  }
    22  
    23  // SecretStore stores secrets that the Ingress Controller uses.
    24  type SecretStore interface {
    25  	AddOrUpdateSecret(secret *api_v1.Secret)
    26  	DeleteSecret(key string)
    27  	GetSecret(key string) *SecretReference
    28  }
    29  
    30  // LocalSecretStore implements SecretStore interface.
    31  // It validates the secrets and manages them on the file system (via SecretFileManager).
    32  type LocalSecretStore struct {
    33  	secrets map[string]*SecretReference
    34  	manager SecretFileManager
    35  }
    36  
    37  // NewLocalSecretStore creates a new LocalSecretStore.
    38  func NewLocalSecretStore(manager SecretFileManager) *LocalSecretStore {
    39  	return &LocalSecretStore{
    40  		secrets: make(map[string]*SecretReference),
    41  		manager: manager,
    42  	}
    43  }
    44  
    45  // AddOrUpdateSecret adds or updates a secret.
    46  // The secret will only be updated on the file system if it is valid and if it is already on the file system.
    47  // If the secret becomes invalid, it will be removed from the filesystem.
    48  func (s *LocalSecretStore) AddOrUpdateSecret(secret *api_v1.Secret) {
    49  	secretRef, exists := s.secrets[getResourceKey(&secret.ObjectMeta)]
    50  	if !exists {
    51  		secretRef = &SecretReference{Secret: secret}
    52  	} else {
    53  		secretRef.Secret = secret
    54  	}
    55  
    56  	secretRef.Error = ValidateSecret(secret)
    57  
    58  	if secretRef.Path != "" {
    59  		if secretRef.Error != nil {
    60  			s.manager.DeleteSecret(getResourceKey(&secret.ObjectMeta))
    61  			secretRef.Path = ""
    62  		} else {
    63  			secretRef.Path = s.manager.AddOrUpdateSecret(secret)
    64  		}
    65  	}
    66  
    67  	s.secrets[getResourceKey(&secret.ObjectMeta)] = secretRef
    68  }
    69  
    70  // DeleteSecret deletes a secret.
    71  func (s *LocalSecretStore) DeleteSecret(key string) {
    72  	storedSecret, exists := s.secrets[key]
    73  	if !exists {
    74  		return
    75  	}
    76  
    77  	delete(s.secrets, key)
    78  
    79  	if storedSecret.Path == "" {
    80  		return
    81  	}
    82  
    83  	s.manager.DeleteSecret(key)
    84  }
    85  
    86  // GetSecret returns a SecretReference.
    87  // If the secret doesn't exist, is of an unsupported type, or invalid, the Error field will include an error.
    88  // If the secret is valid but isn't present on the file system, the secret will be written to the file system.
    89  func (s *LocalSecretStore) GetSecret(key string) *SecretReference {
    90  	secretRef, exists := s.secrets[key]
    91  	if !exists {
    92  		return &SecretReference{
    93  			Error: fmt.Errorf("secret doesn't exist or of an unsupported type"),
    94  		}
    95  	}
    96  
    97  	if secretRef.Error == nil && secretRef.Path == "" {
    98  		secretRef.Path = s.manager.AddOrUpdateSecret(secretRef.Secret)
    99  	}
   100  
   101  	return secretRef
   102  }
   103  
   104  func getResourceKey(meta *metav1.ObjectMeta) string {
   105  	return fmt.Sprintf("%s/%s", meta.Namespace, meta.Name)
   106  }
   107  
   108  // FakeSecretStore is a fake implementation of SecretStore.
   109  type FakeSecretStore struct {
   110  	secrets map[string]*SecretReference
   111  }
   112  
   113  // NewFakeSecretsStore creates a new FakeSecretStore.
   114  func NewFakeSecretsStore(secrets map[string]*SecretReference) *FakeSecretStore {
   115  	return &FakeSecretStore{
   116  		secrets: secrets,
   117  	}
   118  }
   119  
   120  // NewEmptyFakeSecretsStore creates a new empty FakeSecretStore.
   121  func NewEmptyFakeSecretsStore() *FakeSecretStore {
   122  	return &FakeSecretStore{
   123  		secrets: make(map[string]*SecretReference),
   124  	}
   125  }
   126  
   127  // AddOrUpdateSecret is a fake implementation of AddOrUpdateSecret.
   128  func (s *FakeSecretStore) AddOrUpdateSecret(secret *api_v1.Secret) {
   129  	secretRef, exists := s.secrets[getResourceKey(&secret.ObjectMeta)]
   130  	if !exists {
   131  		secretRef = &SecretReference{Secret: secret}
   132  	} else {
   133  		secretRef.Secret = secret
   134  	}
   135  	s.secrets[getResourceKey(&secret.ObjectMeta)] = secretRef
   136  }
   137  
   138  // DeleteSecret is a fake implementation of DeleteSecret.
   139  func (s *FakeSecretStore) DeleteSecret(key string) {
   140  }
   141  
   142  // GetSecret is a fake implementation of GetSecret.
   143  func (s *FakeSecretStore) GetSecret(key string) *SecretReference {
   144  	secretRef, exists := s.secrets[key]
   145  	if !exists {
   146  		return &SecretReference{
   147  			Error: fmt.Errorf("secret doesn't exist"),
   148  		}
   149  	}
   150  
   151  	return secretRef
   152  }