From de24cc11447bc7226450aed5c1a46942a622d776 Mon Sep 17 00:00:00 2001 From: Joshua Duffney Date: Thu, 17 Oct 2024 12:03:54 -0500 Subject: [PATCH] mod: support enabled status for kmp keys/certs Signed-off-by: Joshua Duffney --- .../azurekeyvault/provider.go | 66 ++++++++++++++----- .../azurekeyvault/provider_test.go | 5 +- .../azurekeyvault/types/types.go | 2 + .../keymanagementprovider.go | 1 + 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/pkg/keymanagementprovider/azurekeyvault/provider.go b/pkg/keymanagementprovider/azurekeyvault/provider.go index da885af90..b47c1dfa8 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider.go @@ -141,22 +141,44 @@ func (s *akvKMProvider) GetCertificates(ctx context.Context) (map[keymanagementp logger.GetLogger(ctx, logOpt).Debugf("fetching secret from key vault, certName %v, keyvault %v", keyVaultCert.Name, s.vaultURI) // fetch the object from Key Vault - // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details - startTime := time.Now() - secretBundle, err := s.kvClient.GetSecret(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) + certBundle, err := s.kvClient.GetCertificate(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) if err != nil { - return nil, nil, fmt.Errorf("failed to get secret objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) + return nil, nil, fmt.Errorf("failed to get certificate objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) } - certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.Name) - if err != nil { - return nil, nil, fmt.Errorf("failed to get certificates from secret bundle:%w", err) + //TODO: can I replace else with a continue? + if !*certBundle.Attributes.Enabled { + fmt.Printf("debug: certificate %s version %s is disabled.", keyVaultCert.Name, keyVaultCert.Version) + + isEnabled := "false" + startTime := time.Now() + lastRefreshed := startTime.Format(time.RFC3339) + + metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultCert.Name) + certProperty := getStatusProperty(keyVaultCert.Name, keyVaultCert.Version, isEnabled, lastRefreshed) + certsStatus = append(certsStatus, certProperty) + certMapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version, Enabled: isEnabled} + certsMap[certMapKey] = []*x509.Certificate{} // empty cert chain + } else { + // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details + isEnabled := "true" + startTime := time.Now() + secretBundle, err := s.kvClient.GetSecret(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) + if err != nil { + return nil, nil, fmt.Errorf("failed to get secret objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) + } + + certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.Name, isEnabled) + if err != nil { + return nil, nil, fmt.Errorf("failed to get certificates from secret bundle:%w", err) + } + + metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultCert.Name) + certsStatus = append(certsStatus, certProperty...) + certMapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version, Enabled: isEnabled} + certsMap[certMapKey] = certResult } - metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultCert.Name) - certsStatus = append(certsStatus, certProperty...) - certMapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version} - certsMap[certMapKey] = certResult } return certsMap, getStatusMap(certsStatus, types.CertificatesStatus), nil @@ -178,7 +200,16 @@ func (s *akvKMProvider) GetKeys(ctx context.Context) (map[keymanagementprovider. } if keyBundle.Attributes != nil && keyBundle.Attributes.Enabled != nil && !*keyBundle.Attributes.Enabled { - return nil, nil, fmt.Errorf("key %s version %s is disabled. please re-enable in azure key vault or remove reference to this key", keyVaultKey.Name, keyVaultKey.Version) + isEnabled := "false" + startTime := time.Now() + lastRefreshed := startTime.Format(time.RFC3339) + + keysMap[keymanagementprovider.KMPMapKey{Name: keyVaultKey.Name, Version: keyVaultKey.Version}] = nil + metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultKey.Name) + properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, isEnabled, lastRefreshed) + keysStatus = append(keysStatus, properties) + + continue } publicKey, err := getKeyFromKeyBundle(keyBundle) @@ -187,7 +218,7 @@ func (s *akvKMProvider) GetKeys(ctx context.Context) (map[keymanagementprovider. } keysMap[keymanagementprovider.KMPMapKey{Name: keyVaultKey.Name, Version: keyVaultKey.Version}] = publicKey metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultKey.Name) - properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, time.Now().Format(time.RFC3339)) + properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, "true", time.Now().Format(time.RFC3339)) keysStatus = append(keysStatus, properties) } @@ -205,11 +236,12 @@ func getStatusMap(statusMap []map[string]string, contentType string) keymanageme return status } -// return a status object that consist of the cert/key name, version and last refreshed time -func getStatusProperty(name, version, lastRefreshed string) map[string]string { +// return a status object that consist of the cert/key name, version, enabled and last refreshed time +func getStatusProperty(name, version, enabled, lastRefreshed string) map[string]string { properties := map[string]string{} properties[types.StatusName] = name properties[types.StatusVersion] = version + properties[types.StatusEnabled] = enabled properties[types.StatusLastRefreshed] = lastRefreshed return properties } @@ -244,7 +276,7 @@ func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientI // Parse the secret bundle and return an array of certificates // In a certificate chain scenario, all certificates from root to leaf will be returned -func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName string) ([]*x509.Certificate, []map[string]string, error) { +func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName, enabled string) ([]*x509.Certificate, []map[string]string, error) { if secretBundle.ContentType == nil || secretBundle.Value == nil || secretBundle.ID == nil { return nil, nil, re.ErrorCodeCertInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "found invalid secret bundle for certificate %s, contentType, value, and id must not be nil", re.HideStackTrace) } @@ -297,7 +329,7 @@ func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, } for _, cert := range decodedCerts { results = append(results, cert) - certProperty := getStatusProperty(certName, version, lastRefreshed) + certProperty := getStatusProperty(certName, version, enabled, lastRefreshed) certsStatus = append(certsStatus, certProperty) } default: diff --git a/pkg/keymanagementprovider/azurekeyvault/provider_test.go b/pkg/keymanagementprovider/azurekeyvault/provider_test.go index 676a43892..dd98541d4 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider_test.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider_test.go @@ -288,8 +288,9 @@ func TestGetStatusProperty(t *testing.T) { timeNow := time.Now().String() certName := "certName" certVersion := "versionABC" + isEnabled := "true" - status := getStatusProperty(certName, certVersion, timeNow) + status := getStatusProperty(certName, certVersion, isEnabled, timeNow) assert.Equal(t, certName, status[types.StatusName]) assert.Equal(t, timeNow, status[types.StatusLastRefreshed]) assert.Equal(t, certVersion, status[types.StatusVersion]) @@ -349,7 +350,7 @@ func TestGetCertsFromSecretBundle(t *testing.T) { ContentType: &cases[i].contentType, } - certs, status, err := getCertsFromSecretBundle(context.Background(), testdata, "certName") + certs, status, err := getCertsFromSecretBundle(context.Background(), testdata, "certName", "true") if tc.expectedErr { assert.NotNil(t, err) assert.Nil(t, certs) diff --git a/pkg/keymanagementprovider/azurekeyvault/types/types.go b/pkg/keymanagementprovider/azurekeyvault/types/types.go index 5cde59583..e51650dab 100644 --- a/pkg/keymanagementprovider/azurekeyvault/types/types.go +++ b/pkg/keymanagementprovider/azurekeyvault/types/types.go @@ -25,6 +25,8 @@ const ( StatusName = "Name" // Certificate version string for the certificate status property StatusVersion = "Version" + // Enabled string for the certificate status property + StatusEnabled = "Enabled" // Last refreshed string for the certificate status property StatusLastRefreshed = "LastRefreshed" ) diff --git a/pkg/keymanagementprovider/keymanagementprovider.go b/pkg/keymanagementprovider/keymanagementprovider.go index 584f50828..5cc2505fe 100644 --- a/pkg/keymanagementprovider/keymanagementprovider.go +++ b/pkg/keymanagementprovider/keymanagementprovider.go @@ -41,6 +41,7 @@ type KeyManagementProviderStatus map[string]interface{} type KMPMapKey struct { Name string Version string + Enabled string } type PublicKey struct {