Skip to content

Commit

Permalink
mod: support enabled status for kmp keys/certs
Browse files Browse the repository at this point in the history
Signed-off-by: Joshua Duffney <[email protected]>
  • Loading branch information
duffney committed Oct 22, 2024
1 parent 75ed5ba commit de24cc1
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
66 changes: 49 additions & 17 deletions pkg/keymanagementprovider/azurekeyvault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)
}

Expand All @@ -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
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions pkg/keymanagementprovider/azurekeyvault/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions pkg/keymanagementprovider/azurekeyvault/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down
1 change: 1 addition & 0 deletions pkg/keymanagementprovider/keymanagementprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type KeyManagementProviderStatus map[string]interface{}
type KMPMapKey struct {
Name string
Version string
Enabled string
}

type PublicKey struct {
Expand Down

0 comments on commit de24cc1

Please sign in to comment.