cleanup: address golangci 'funcorder' linter problems

The new 'funcorder' linter expects all public functions to be placed
before private functions of a struct. Many private functions needed
moving further down into their files.

Some files had many issues reported. To reduce the churn in those files,
they have been annotated with a `//nolint:funcorder` comment.

Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
Niels de Vos
2025-04-29 11:32:43 +02:00
committed by mergify[bot]
parent 0907f39d95
commit 0a22e3a186
29 changed files with 921 additions and 914 deletions

View File

@ -124,35 +124,6 @@ func initAWSMetadataKMS(args ProviderInitArgs) (EncryptionKMS, error) {
return kms, nil
}
func (kms *awsMetadataKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to Kubernetes to "+
"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case awsSecretAccessKey, awsAccessKey, awsSessionToken, awsCMK:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS "+
"provider %q: %s", kmsTypeAWSMetadata, k)
}
}
return config, nil
}
func (kms *awsMetadataKMS) Destroy() {
// Nothing to do.
}
@ -164,24 +135,6 @@ func (kms *awsMetadataKMS) RequiresDEKStore() DEKStoreType {
return DEKStoreMetadata
}
func (kms *awsMetadataKMS) getService() (*awsKMS.KMS, error) {
creds := awsCreds.NewStaticCredentials(kms.accessKey,
kms.secretAccessKey, kms.sessionToken)
sess, err := awsSession.NewSessionWithOptions(awsSession.Options{
SharedConfigState: awsSession.SharedConfigDisable,
Config: aws.Config{
Credentials: creds,
Region: aws.String(kms.region),
},
})
if err != nil {
return nil, fmt.Errorf("failed to create AWS session: %w", err)
}
return awsKMS.New(sess), nil
}
// EncryptDEK uses the Amazon KMS and the configured CMK to encrypt the DEK.
func (kms *awsMetadataKMS) EncryptDEK(ctx context.Context, volumeID, plainDEK string) (string, error) {
svc, err := kms.getService()
@ -230,3 +183,50 @@ func (kms *awsMetadataKMS) DecryptDEK(ctx context.Context, volumeID, encryptedDE
func (kms *awsMetadataKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
return "", ErrGetSecretUnsupported
}
func (kms *awsMetadataKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to Kubernetes to "+
"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case awsSecretAccessKey, awsAccessKey, awsSessionToken, awsCMK:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS "+
"provider %q: %s", kmsTypeAWSMetadata, k)
}
}
return config, nil
}
func (kms *awsMetadataKMS) getService() (*awsKMS.KMS, error) {
creds := awsCreds.NewStaticCredentials(kms.accessKey,
kms.secretAccessKey, kms.sessionToken)
sess, err := awsSession.NewSessionWithOptions(awsSession.Options{
SharedConfigState: awsSession.SharedConfigDisable,
Config: aws.Config{
Credentials: creds,
Region: aws.String(kms.region),
},
})
if err != nil {
return nil, fmt.Errorf("failed to create AWS session: %w", err)
}
return awsKMS.New(sess), nil
}

View File

@ -115,6 +115,49 @@ func initAWSSTSMetadataKMS(args ProviderInitArgs) (EncryptionKMS, error) {
return kms, nil
}
// EncryptDEK uses the Amazon KMS and the configured CMK to encrypt the DEK.
func (as *awsSTSMetadataKMS) EncryptDEK(ctx context.Context, _, plainDEK string) (string, error) {
svc, err := as.getServiceWithSTS()
if err != nil {
return "", fmt.Errorf("failed to get KMS service: %w", err)
}
result, err := svc.Encrypt(&awsKMS.EncryptInput{
KeyId: aws.String(as.cmk),
Plaintext: []byte(plainDEK),
})
if err != nil {
return "", fmt.Errorf("failed to encrypt DEK: %w", err)
}
// base64 encode the encrypted DEK, so that storing it should not have
// issues
return base64.StdEncoding.EncodeToString(result.CiphertextBlob), nil
}
// DecryptDEK uses the Amazon KMS and the configured CMK to decrypt the DEK.
func (as *awsSTSMetadataKMS) DecryptDEK(ctx context.Context, _, encryptedDEK string) (string, error) {
svc, err := as.getServiceWithSTS()
if err != nil {
return "", fmt.Errorf("failed to get KMS service: %w", err)
}
ciphertextBlob, err := base64.StdEncoding.DecodeString(encryptedDEK)
if err != nil {
return "", fmt.Errorf("failed to decode base64 cipher: %w",
err)
}
result, err := svc.Decrypt(&awsKMS.DecryptInput{
CiphertextBlob: ciphertextBlob,
})
if err != nil {
return "", fmt.Errorf("failed to decrypt DEK: %w", err)
}
return string(result.Plaintext), nil
}
// getSecrets returns required STS configuration options from the Kubernetes Secret.
func (as *awsSTSMetadataKMS) getSecrets() (map[string]string, error) {
c, err := k8s.NewK8sClient()
@ -191,46 +234,3 @@ func (as *awsSTSMetadataKMS) getServiceWithSTS() (*awsKMS.KMS, error) {
return awsKMS.New(sess), nil
}
// EncryptDEK uses the Amazon KMS and the configured CMK to encrypt the DEK.
func (as *awsSTSMetadataKMS) EncryptDEK(ctx context.Context, _, plainDEK string) (string, error) {
svc, err := as.getServiceWithSTS()
if err != nil {
return "", fmt.Errorf("failed to get KMS service: %w", err)
}
result, err := svc.Encrypt(&awsKMS.EncryptInput{
KeyId: aws.String(as.cmk),
Plaintext: []byte(plainDEK),
})
if err != nil {
return "", fmt.Errorf("failed to encrypt DEK: %w", err)
}
// base64 encode the encrypted DEK, so that storing it should not have
// issues
return base64.StdEncoding.EncodeToString(result.CiphertextBlob), nil
}
// DecryptDEK uses the Amazon KMS and the configured CMK to decrypt the DEK.
func (as *awsSTSMetadataKMS) DecryptDEK(ctx context.Context, _, encryptedDEK string) (string, error) {
svc, err := as.getServiceWithSTS()
if err != nil {
return "", fmt.Errorf("failed to get KMS service: %w", err)
}
ciphertextBlob, err := base64.StdEncoding.DecodeString(encryptedDEK)
if err != nil {
return "", fmt.Errorf("failed to decode base64 cipher: %w",
err)
}
result, err := svc.Decrypt(&awsKMS.DecryptInput{
CiphertextBlob: ciphertextBlob,
})
if err != nil {
return "", fmt.Errorf("failed to decrypt DEK: %w", err)
}
return string(result.Plaintext), nil
}

View File

@ -117,50 +117,6 @@ func (kms *azureKMS) Destroy() {
// Nothing to do.
}
func (kms *azureKMS) getService() (*azsecrets.Client, error) {
certs, key, err := azidentity.ParseCertificates([]byte(kms.clientCertificate), []byte{})
if err != nil {
return nil, fmt.Errorf("failed to parse Azure client certificate: %w", err)
}
creds, err := azidentity.NewClientCertificateCredential(kms.tenantID, kms.clientID, certs, key, nil)
if err != nil {
return nil, fmt.Errorf("failed to create Azure credentials: %w", err)
}
azClient, err := azsecrets.NewClient(kms.vaultURL, creds, nil)
if err != nil {
return nil, fmt.Errorf("failed to create Azure client: %w", err)
}
return azClient, nil
}
func (kms *azureKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to kubernetes to "+
"get secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case azureClientCertificate:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS provider %q: %s", kmsTypeAzure, k)
}
}
return config, nil
}
// FetchDEK returns passphrase from Azure key vault.
func (kms *azureKMS) FetchDEK(ctx context.Context, key string) (string, error) {
svc, err := kms.getService()
@ -208,3 +164,47 @@ func (kms *azureKMS) RemoveDEK(ctx context.Context, key string) error {
return nil
}
func (kms *azureKMS) getService() (*azsecrets.Client, error) {
certs, key, err := azidentity.ParseCertificates([]byte(kms.clientCertificate), []byte{})
if err != nil {
return nil, fmt.Errorf("failed to parse Azure client certificate: %w", err)
}
creds, err := azidentity.NewClientCertificateCredential(kms.tenantID, kms.clientID, certs, key, nil)
if err != nil {
return nil, fmt.Errorf("failed to create Azure credentials: %w", err)
}
azClient, err := azsecrets.NewClient(kms.vaultURL, creds, nil)
if err != nil {
return nil, fmt.Errorf("failed to create Azure client: %w", err)
}
return azClient, nil
}
func (kms *azureKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to kubernetes to "+
"get secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case azureClientCertificate:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS provider %q: %s", kmsTypeAzure, k)
}
}
return config, nil
}

View File

@ -147,35 +147,6 @@ func initKeyProtectKMS(args ProviderInitArgs) (EncryptionKMS, error) {
return kms, nil
}
func (kms *keyProtectKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to Kubernetes to "+
"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case keyProtectServiceAPIKey, KeyProtectCustomerRootKey, keyProtectSessionToken, keyProtectCRK:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS "+
"provider %q: %s", kmsTypeKeyProtectMetadata, k)
}
}
return config, nil
}
func (kms *keyProtectKMS) Destroy() {
// Nothing to do.
}
@ -184,25 +155,6 @@ func (kms *keyProtectKMS) RequiresDEKStore() DEKStoreType {
return DEKStoreMetadata
}
func (kms *keyProtectKMS) getService() error {
// Use your Service API Key and your KeyProtect Service Instance ID to create a ClientConfig
cc := kp.ClientConfig{
BaseURL: kms.baseURL,
TokenURL: kms.tokenURL,
APIKey: kms.serviceAPIKey,
InstanceID: kms.serviceInstanceID,
}
// Build a new client from the config
client, err := kp.New(cc, kp.DefaultTransport())
if err != nil {
return fmt.Errorf("failed to create keyprotect client: %w", err)
}
kms.client = client
return nil
}
// EncryptDEK uses the KeyProtect KMS and the configured CRK to encrypt the DEK.
func (kms *keyProtectKMS) EncryptDEK(ctx context.Context, volumeID, plainDEK string) (string, error) {
if err := kms.getService(); err != nil {
@ -246,3 +198,51 @@ func (kms *keyProtectKMS) DecryptDEK(ctx context.Context, volumeID, encryptedDEK
func (kms *keyProtectKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
return "", ErrGetSecretUnsupported
}
func (kms *keyProtectKMS) getSecrets() (map[string]interface{}, error) {
c, err := k8s.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("failed to connect to Kubernetes to "+
"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
}
secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
kms.secretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
kms.namespace, kms.secretName, err)
}
config := make(map[string]interface{})
for k, v := range secret.Data {
switch k {
case keyProtectServiceAPIKey, KeyProtectCustomerRootKey, keyProtectSessionToken, keyProtectCRK:
config[k] = string(v)
default:
return nil, fmt.Errorf("unsupported option for KMS "+
"provider %q: %s", kmsTypeKeyProtectMetadata, k)
}
}
return config, nil
}
func (kms *keyProtectKMS) getService() error {
// Use your Service API Key and your KeyProtect Service Instance ID to create a ClientConfig
cc := kp.ClientConfig{
BaseURL: kms.baseURL,
TokenURL: kms.tokenURL,
APIKey: kms.serviceAPIKey,
InstanceID: kms.serviceInstanceID,
}
// Build a new client from the config
client, err := kp.New(cc, kp.DefaultTransport())
if err != nil {
return fmt.Errorf("failed to create keyprotect client: %w", err)
}
kms.client = client
return nil
}

View File

@ -293,6 +293,10 @@ func (kms *kmipKMS) RequiresDEKStore() DEKStoreType {
return DEKStoreMetadata
}
func (kms *kmipKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
return "", ErrGetSecretUnsupported
}
// getSecrets returns required options from the Kubernetes Secret.
func (kms *kmipKMS) getSecrets() (map[string]string, error) {
c, err := k8s.NewK8sClient()
@ -500,10 +504,6 @@ func (kms *kmipKMS) verifyResponse(
return &batchItem, nil
}
func (kms *kmipKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
return "", ErrGetSecretUnsupported
}
// TODO: use the following structs from https://github.com/gemalto/kmip-go
// when https://github.com/ThalesGroup/kmip-go/issues/21 is resolved.
// refer: https://docs.oasis-open.org/kmip/spec/v1.4/kmip-spec-v1.4.html.

View File

@ -116,53 +116,6 @@ func initSecretsMetadataKMS(args ProviderInitArgs) (EncryptionKMS, error) {
return smKMS, nil
}
// fetchEncryptionPassphrase fetches encryptionPassphrase from user provided secret.
func (kms secretsMetadataKMS) fetchEncryptionPassphrase(
config map[string]interface{},
defaultNamespace string,
) (string, error) {
var (
secretName string
secretNamespace string
)
err := setConfigString(&secretName, config, metadataSecretNameKey)
if err != nil {
return "", err
}
err = setConfigString(&secretNamespace, config, metadataSecretNamespaceKey)
if err != nil {
if !errors.Is(err, errConfigOptionMissing) {
return "", err
}
// if 'secretNamespace' option is not specified, defaults to namespace in
// which PVC was created
secretNamespace = defaultNamespace
}
c, err := k8s.NewK8sClient()
if err != nil {
return "", fmt.Errorf("can not get Secret %s/%s, failed to "+
"connect to Kubernetes: %w", secretNamespace, secretName, err)
}
secret, err := c.CoreV1().Secrets(secretNamespace).Get(context.TODO(),
secretName, metav1.GetOptions{})
if err != nil {
return "", fmt.Errorf("failed to get Secret %s/%s: %w",
secretNamespace, secretName, err)
}
passphraseValue, ok := secret.Data[encryptionPassphraseKey]
if !ok {
return "", fmt.Errorf("missing %q in Secret %s/%s",
encryptionPassphraseKey, secretNamespace, secretName)
}
return string(passphraseValue), nil
}
// Destroy frees all used resources.
func (kms secretsMetadataKMS) Destroy() {
// nothing to do
@ -287,6 +240,53 @@ func (kms secretsMetadataKMS) GetSecret(ctx context.Context, volumeID string) (s
return kms.FetchDEK(ctx, volumeID)
}
// fetchEncryptionPassphrase fetches encryptionPassphrase from user provided secret.
func (kms secretsMetadataKMS) fetchEncryptionPassphrase(
config map[string]interface{},
defaultNamespace string,
) (string, error) {
var (
secretName string
secretNamespace string
)
err := setConfigString(&secretName, config, metadataSecretNameKey)
if err != nil {
return "", err
}
err = setConfigString(&secretNamespace, config, metadataSecretNamespaceKey)
if err != nil {
if !errors.Is(err, errConfigOptionMissing) {
return "", err
}
// if 'secretNamespace' option is not specified, defaults to namespace in
// which PVC was created
secretNamespace = defaultNamespace
}
c, err := k8s.NewK8sClient()
if err != nil {
return "", fmt.Errorf("can not get Secret %s/%s, failed to "+
"connect to Kubernetes: %w", secretNamespace, secretName, err)
}
secret, err := c.CoreV1().Secrets(secretNamespace).Get(context.TODO(),
secretName, metav1.GetOptions{})
if err != nil {
return "", fmt.Errorf("failed to get Secret %s/%s: %w",
secretNamespace, secretName, err)
}
passphraseValue, ok := secret.Data[encryptionPassphraseKey]
if !ok {
return "", fmt.Errorf("missing %q in Secret %s/%s",
encryptionPassphraseKey, secretNamespace, secretName)
}
return string(passphraseValue), nil
}
// generateCipher returns a AEAD cipher based on a passphrase and salt
// (volumeID). The cipher can then be used to encrypt/decrypt the DEK.
func generateCipher(passphrase, salt string) (cipher.AEAD, error) {

View File

@ -122,6 +122,19 @@ func setConfigString(option *string, config map[string]interface{}, key string)
return nil
}
// Destroy frees allocated resources. For a vaultConnection that means removing
// the created temporary files.
func (vc *vaultConnection) Destroy() {
if vc.vaultConfig != nil {
tmpFile, ok := vc.vaultConfig[api.EnvVaultCACert]
if ok {
// ignore error on failure to remove tmpfile (gosec complains)
//nolint:forcetypeassert,errcheck // ignore error on failure to remove tmpfile
_ = os.Remove(tmpFile.(string))
}
}
}
// initConnection sets VAULT_* environment variables in the vc.vaultConfig map,
// these settings will be used when connecting to the Vault service with
// vc.connectVault().
@ -298,19 +311,6 @@ func (vc *vaultConnection) connectVault() error {
return nil
}
// Destroy frees allocated resources. For a vaultConnection that means removing
// the created temporary files.
func (vc *vaultConnection) Destroy() {
if vc.vaultConfig != nil {
tmpFile, ok := vc.vaultConfig[api.EnvVaultCACert]
if ok {
// ignore error on failure to remove tmpfile (gosec complains)
//nolint:forcetypeassert,errcheck // ignore error on failure to remove tmpfile
_ = os.Remove(tmpFile.(string))
}
}
}
// getDeleteKeyContext creates a new KeyContext that has an optional value set
// to destroy the contents of secrets. This is configurable with the
// `vaultDestroyKeys` configuration parameter.

View File

@ -281,6 +281,54 @@ func initVaultTokensKMS(args ProviderInitArgs) (EncryptionKMS, error) {
return kms, nil
}
// FetchDEK returns passphrase from Vault. The passphrase is stored in a
// data.data.passphrase structure.
func (vtc *vaultTenantConnection) FetchDEK(ctx context.Context, key string) (string, error) {
// Since the second return variable loss.Version is not used, there it is ignored.
s, _, err := vtc.secrets.GetSecret(key, vtc.keyContext)
if err != nil {
return "", err
}
data, ok := s["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("failed parsing data for get passphrase request for %s", key)
}
passphrase, ok := data["passphrase"].(string)
if !ok {
return "", fmt.Errorf("failed parsing passphrase for get passphrase request for %s", key)
}
return passphrase, nil
}
// StoreDEK saves new passphrase in Vault.
func (vtc *vaultTenantConnection) StoreDEK(ctx context.Context, key, value string) error {
data := map[string]interface{}{
"data": map[string]string{
"passphrase": value,
},
}
// Since the first return variable loss.Version is not used, there it is ignored.
_, err := vtc.secrets.PutSecret(key, data, vtc.keyContext)
if err != nil {
return fmt.Errorf("saving passphrase at %s request to vault failed: %w", key, err)
}
return nil
}
// RemoveDEK deletes passphrase from Vault.
func (vtc *vaultTenantConnection) RemoveDEK(ctx context.Context, key string) error {
err := vtc.secrets.DeleteSecret(key, vtc.getDeleteKeyContext())
if err != nil {
return fmt.Errorf("delete passphrase at %s request to vault failed: %w", key, err)
}
return nil
}
func (kms *vaultTokensKMS) configureTenant(config map[string]interface{}, tenant string) error {
kms.Tenant = tenant
tenantConfig, found := fetchTenantConfig(config, tenant)
@ -461,54 +509,6 @@ func (vtc *vaultTenantConnection) getK8sClient() (*kubernetes.Clientset, error)
return vtc.client, nil
}
// FetchDEK returns passphrase from Vault. The passphrase is stored in a
// data.data.passphrase structure.
func (vtc *vaultTenantConnection) FetchDEK(ctx context.Context, key string) (string, error) {
// Since the second return variable loss.Version is not used, there it is ignored.
s, _, err := vtc.secrets.GetSecret(key, vtc.keyContext)
if err != nil {
return "", err
}
data, ok := s["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("failed parsing data for get passphrase request for %s", key)
}
passphrase, ok := data["passphrase"].(string)
if !ok {
return "", fmt.Errorf("failed parsing passphrase for get passphrase request for %s", key)
}
return passphrase, nil
}
// StoreDEK saves new passphrase in Vault.
func (vtc *vaultTenantConnection) StoreDEK(ctx context.Context, key, value string) error {
data := map[string]interface{}{
"data": map[string]string{
"passphrase": value,
},
}
// Since the first return variable loss.Version is not used, there it is ignored.
_, err := vtc.secrets.PutSecret(key, data, vtc.keyContext)
if err != nil {
return fmt.Errorf("saving passphrase at %s request to vault failed: %w", key, err)
}
return nil
}
// RemoveDEK deletes passphrase from Vault.
func (vtc *vaultTenantConnection) RemoveDEK(ctx context.Context, key string) error {
err := vtc.secrets.DeleteSecret(key, vtc.getDeleteKeyContext())
if err != nil {
return fmt.Errorf("delete passphrase at %s request to vault failed: %w", key, err)
}
return nil
}
func (kms *vaultTokensKMS) getToken() (string, error) {
c, err := kms.getK8sClient()
if err != nil {