mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	Add warnings to crl rebuilds, allowing notifying operator of empty issuer equivalency sets (#20253)
* Add infrastructure for warnings on CRL rebuilds Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add warning on issuer missing KU for CRL Signing When an entire issuer equivalency class is missing CRL signing usage (but otherwise has key material present), we should add a warning so operators can either correct this issuer or create an equivalent version with KU specified. Resolves: https://github.com/hashicorp/vault/issues/20137 Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add tests for issuer warnings Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add changelog entry Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Fix return order of CRL builders Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
		| @@ -600,16 +600,32 @@ func (b *backend) periodicFunc(ctx context.Context, request *logical.Request) er | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Then attempt to rebuild the CRLs if required. | 		// Then attempt to rebuild the CRLs if required. | ||||||
| 		if err := b.crlBuilder.rebuildIfForced(sc); err != nil { | 		warnings, err := b.crlBuilder.rebuildIfForced(sc) | ||||||
|  | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | 		if len(warnings) > 0 { | ||||||
|  | 			msg := "During rebuild of complete CRL, got the following warnings:" | ||||||
|  | 			for index, warning := range warnings { | ||||||
|  | 				msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 			} | ||||||
|  | 			b.Logger().Warn(msg) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// If a delta CRL was rebuilt above as part of the complete CRL rebuild, | 		// If a delta CRL was rebuilt above as part of the complete CRL rebuild, | ||||||
| 		// this will be a no-op. However, if we do need to rebuild delta CRLs, | 		// this will be a no-op. However, if we do need to rebuild delta CRLs, | ||||||
| 		// this would cause us to do so. | 		// this would cause us to do so. | ||||||
| 		if err := b.crlBuilder.rebuildDeltaCRLsIfForced(sc, false); err != nil { | 		warnings, err = b.crlBuilder.rebuildDeltaCRLsIfForced(sc, false) | ||||||
|  | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | 		if len(warnings) > 0 { | ||||||
|  | 			msg := "During rebuild of delta CRL, got the following warnings:" | ||||||
|  | 			for index, warning := range warnings { | ||||||
|  | 				msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 			} | ||||||
|  | 			b.Logger().Warn(msg) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -177,9 +177,17 @@ func fetchCertBySerial(sc *storageContext, prefix, serial string) (*logical.Stor | |||||||
| 		legacyPath = "revoked/" + colonSerial | 		legacyPath = "revoked/" + colonSerial | ||||||
| 		path = "revoked/" + hyphenSerial | 		path = "revoked/" + hyphenSerial | ||||||
| 	case serial == legacyCRLPath || serial == deltaCRLPath || serial == unifiedCRLPath || serial == unifiedDeltaCRLPath: | 	case serial == legacyCRLPath || serial == deltaCRLPath || serial == unifiedCRLPath || serial == unifiedDeltaCRLPath: | ||||||
| 		if err = sc.Backend.crlBuilder.rebuildIfForced(sc); err != nil { | 		warnings, err := sc.Backend.crlBuilder.rebuildIfForced(sc) | ||||||
|  | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | 		if len(warnings) > 0 { | ||||||
|  | 			msg := "During rebuild of CRL for cert fetch, got the following warnings:" | ||||||
|  | 			for index, warning := range warnings { | ||||||
|  | 				msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 			} | ||||||
|  | 			sc.Backend.Logger().Warn(msg) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		unified := serial == unifiedCRLPath || serial == unifiedDeltaCRLPath | 		unified := serial == unifiedCRLPath || serial == unifiedDeltaCRLPath | ||||||
| 		path, err = sc.resolveIssuerCRLPath(defaultRef, unified) | 		path, err = sc.resolveIssuerCRLPath(defaultRef, unified) | ||||||
|   | |||||||
| @@ -415,15 +415,18 @@ func TestCrlRebuilder(t *testing.T) { | |||||||
| 	cb := newCRLBuilder(true /* can rebuild and write CRLs */) | 	cb := newCRLBuilder(true /* can rebuild and write CRLs */) | ||||||
|  |  | ||||||
| 	// Force an initial build | 	// Force an initial build | ||||||
| 	err = cb.rebuild(sc, true) | 	warnings, err := cb.rebuild(sc, true) | ||||||
| 	require.NoError(t, err, "Failed to rebuild CRL") | 	require.NoError(t, err, "Failed to rebuild CRL") | ||||||
|  | 	require.Empty(t, warnings, "unexpectedly got warnings rebuilding CRL") | ||||||
|  |  | ||||||
| 	resp := requestCrlFromBackend(t, s, b) | 	resp := requestCrlFromBackend(t, s, b) | ||||||
| 	crl1 := parseCrlPemBytes(t, resp.Data["http_raw_body"].([]byte)) | 	crl1 := parseCrlPemBytes(t, resp.Data["http_raw_body"].([]byte)) | ||||||
|  |  | ||||||
| 	// We shouldn't rebuild within this call. | 	// We shouldn't rebuild within this call. | ||||||
| 	err = cb.rebuildIfForced(sc) | 	warnings, err = cb.rebuildIfForced(sc) | ||||||
| 	require.NoError(t, err, "Failed to rebuild if forced CRL") | 	require.NoError(t, err, "Failed to rebuild if forced CRL") | ||||||
|  | 	require.Empty(t, warnings, "unexpectedly got warnings rebuilding CRL") | ||||||
|  |  | ||||||
| 	resp = requestCrlFromBackend(t, s, b) | 	resp = requestCrlFromBackend(t, s, b) | ||||||
| 	crl2 := parseCrlPemBytes(t, resp.Data["http_raw_body"].([]byte)) | 	crl2 := parseCrlPemBytes(t, resp.Data["http_raw_body"].([]byte)) | ||||||
| 	require.Equal(t, crl1.ThisUpdate, crl2.ThisUpdate, "According to the update field, we rebuilt the CRL") | 	require.Equal(t, crl1.ThisUpdate, crl2.ThisUpdate, "According to the update field, we rebuilt the CRL") | ||||||
| @@ -439,8 +442,9 @@ func TestCrlRebuilder(t *testing.T) { | |||||||
|  |  | ||||||
| 	// This should rebuild the CRL | 	// This should rebuild the CRL | ||||||
| 	cb.requestRebuildIfActiveNode(b) | 	cb.requestRebuildIfActiveNode(b) | ||||||
| 	err = cb.rebuildIfForced(sc) | 	warnings, err = cb.rebuildIfForced(sc) | ||||||
| 	require.NoError(t, err, "Failed to rebuild if forced CRL") | 	require.NoError(t, err, "Failed to rebuild if forced CRL") | ||||||
|  | 	require.Empty(t, warnings, "unexpectedly got warnings rebuilding CRL") | ||||||
| 	resp = requestCrlFromBackend(t, s, b) | 	resp = requestCrlFromBackend(t, s, b) | ||||||
| 	schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("crl/pem"), logical.ReadOperation), resp, true) | 	schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("crl/pem"), logical.ReadOperation), resp, true) | ||||||
|  |  | ||||||
| @@ -1325,3 +1329,106 @@ func requestCrlFromBackend(t *testing.T, s logical.Storage, b *backend) *logical | |||||||
| 	require.False(t, resp.IsError(), "crl error response: %v", resp) | 	require.False(t, resp.IsError(), "crl error response: %v", resp) | ||||||
| 	return resp | 	return resp | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestCRLWarningsEmptyKeyUsage(t *testing.T) { | ||||||
|  | 	t.Parallel() | ||||||
|  |  | ||||||
|  | 	b, s := CreateBackendWithStorage(t) | ||||||
|  |  | ||||||
|  | 	// Generated using OpenSSL with a configuration lacking KeyUsage on | ||||||
|  | 	// the CA certificate. | ||||||
|  | 	cert := `-----BEGIN CERTIFICATE----- | ||||||
|  | MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhyb290 | ||||||
|  | LW9sZDAeFw0yMDAxMDEwMTAxMDFaFw0yMTAxMDEwMTAxMDFaMBMxETAPBgNVBAMM | ||||||
|  | CHJvb3Qtb2xkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzqhSZxAL | ||||||
|  | PwFhCIPL1jFPq6jxp1wFgo6YNSfVI13gfaGIjfErxsQUbosmlEuTeOc50zXXN3kb | ||||||
|  | SDufy5Yi1OeSkFZRdJ78zdKzsEDIVR1ukUngVsSrt05gdNMJlh8XOPbcrJo78jYG | ||||||
|  | lRgtkkFSc/wCu+ue6JqkfKrbUY/G9WK0UM8ppHm1Ux67ZGoypyEgaqqxKHBRC4Yl | ||||||
|  | D+lAs1vP4C6cavqdUMKgAPTKmMBzlbpCuYPLHSzWh9Com3WQSqCbrlo3uH5RT3V9 | ||||||
|  | 5Gjuk3mMUhY1l6fRL7wG3f+4x+DS+ICQNT0o4lnMxpIsiTh0cEHUFgY7G0iHWYPj | ||||||
|  | CIN8UDhpZIpoCQIDAQABo2UwYzAdBgNVHQ4EFgQUJlHk3PN7pfC22FGxAb0rWgQt | ||||||
|  | L4cwHwYDVR0jBBgwFoAUJlHk3PN7pfC22FGxAb0rWgQtL4cwDAYDVR0TBAUwAwEB | ||||||
|  | /zATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAcaU0FbXb | ||||||
|  | FfXluBrjKfOzVKz+kvQ1CVv3xe3MBkS6wvqybBjJCFChnqCPxEe57BdSbBXNU5LZ | ||||||
|  | zCR/OqYas4Csv9+msSn9BI2FSMAmfMDTsp5/6iIQJqlJx9L8a7bjzVMGX6QJm/3x | ||||||
|  | S/EgGsMETAgewQXeu4jhI6StgJ2V/4Ofe498hYw4LAiBapJmkU/nHezWodNBZJ7h | ||||||
|  | LcLOzVj0Hu5MZplGBgJFgRqBCVVkqXA0q7tORuhNzYtNdJFpv3pZIhvVFFu3HUPf | ||||||
|  | wYQPhLye5WNtosz5xKe8X0Q9qp8g6azMTk+5Qe7u1d8MYAA2AIlGuKUvPHRruOmN | ||||||
|  | NC+gQnS7AK1lCw== | ||||||
|  | -----END CERTIFICATE-----` | ||||||
|  | 	privKey := `-----BEGIN PRIVATE KEY----- | ||||||
|  | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOqFJnEAs/AWEI | ||||||
|  | g8vWMU+rqPGnXAWCjpg1J9UjXeB9oYiN8SvGxBRuiyaUS5N45znTNdc3eRtIO5/L | ||||||
|  | liLU55KQVlF0nvzN0rOwQMhVHW6RSeBWxKu3TmB00wmWHxc49tysmjvyNgaVGC2S | ||||||
|  | QVJz/AK7657omqR8qttRj8b1YrRQzymkebVTHrtkajKnISBqqrEocFELhiUP6UCz | ||||||
|  | W8/gLpxq+p1QwqAA9MqYwHOVukK5g8sdLNaH0KibdZBKoJuuWje4flFPdX3kaO6T | ||||||
|  | eYxSFjWXp9EvvAbd/7jH4NL4gJA1PSjiWczGkiyJOHRwQdQWBjsbSIdZg+MIg3xQ | ||||||
|  | OGlkimgJAgMBAAECggEABKmCdmXDwy+eR0ll41aoc/hzPzHRxADAiU51Pf+DrYHj | ||||||
|  | 6UPcF3db+KR2Adl0ocEhqlSoHs3CIk6KC9c+wOvagBwaaVWe4WvT9vF3M4he8rMm | ||||||
|  | dv6n2xJPFcOfDz5zUSssjk5KdOvoGRv7BzYnDIvOafvmUVwPwuo92Wizddy8saf4 | ||||||
|  | Xuea0Cupz1PELPKkbXcAqb+TzbAZrwdPj1Y7vTe/KGE4+aoDqCW/sFB1E0UsMGlt | ||||||
|  | /yfGwFP48b7kdkqSpcEQW5H8+WL3TfqRcolCD9To4vo2J+1Po0S/8qPNRvkNQDDX | ||||||
|  | AypHtrXFBOWHpJgXT4rKyH+ZGJchrCRDblt9s/sNQwKBgQD7NytvYET3pWemYiX+ | ||||||
|  | MB9uc6cPuMFONvlzjA9T6dbOSi/HLaeDoW027aMUZqb7QeaQCoWcUwh13dI2SZq0 | ||||||
|  | 5+l9hei4JkWjoDhbWmPe7zDuQr3UMl0CSk3egz3BSHkjAhRAuUxK0QLKGB23zWxz | ||||||
|  | k8mUWYZaZRA39C6aqMt/jbJjDwKBgQDSl+eO+DjpwPzrjPSphpF4xYo4XDje9ovK | ||||||
|  | 9q4KTHye7Flc3cMCX3WZBmzdt0zbqu6gWZjJH0XbWX/+SkJBGh77XWD0FeQnU7Vk | ||||||
|  | ipoeb8zTsCVxD9EytQuXti3cqBgClcCMvLKgLOJIcNYTnygojwg3t+jboQqbtV7p | ||||||
|  | VpQfAC6jZwKBgQCxJ46x1CnOmg4l/0DbqAQCV/yP0bI//fSbz0Ff459fimF3DHL9 | ||||||
|  | GHF0MtC2Kk3HEgoNud3PB58Hv43mSrGWsZSuuCgM9LBXWz1i7rNPG05eNyK26W09 | ||||||
|  | mDihmduK2hjS3zx5CDMM76gP7EHIxEyelLGqtBdS18JAMypKVo5rPPl3cQKBgQCG | ||||||
|  | ueXLImQOr4dfDntLpSqV0BLAQcekZKhEPZJURmCHr37wGXNzpixurJyjL2w9MFqf | ||||||
|  | PRKwwJAJZ3Wp8kn2qkZd23x2Szb+LeBjJQS6Kh4o44zgixTz0r1K3qLygptxs+pO | ||||||
|  | Xz4LmQte+skKHo0rfW3tb3vKXnmR6fOBZgE23//2SwKBgHck44hoE1Ex2gDEfIq1 | ||||||
|  | 04OBoS1cpuc9ge4uHEmv+8uANjzwlsYf8hY1qae513MGixRBOkxcI5xX/fYPQV9F | ||||||
|  | t3Jfh8QX85JjnGntuXuraYZJMUjpwXr3QHPx0jpvAM3Au5j6qD3biC9Vrwq9Chkg | ||||||
|  | hbiiPARizZA/Tsna/9ox1qDT | ||||||
|  | -----END PRIVATE KEY-----` | ||||||
|  | 	resp, err := CBWrite(b, s, "issuers/import/bundle", map[string]interface{}{ | ||||||
|  | 		"pem_bundle": cert + "\n" + privKey, | ||||||
|  | 	}) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	require.NotNil(t, resp) | ||||||
|  | 	require.NotEmpty(t, resp.Warnings) | ||||||
|  | 	originalWarnings := resp.Warnings | ||||||
|  |  | ||||||
|  | 	resp, err = CBRead(b, s, "crl/rotate") | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	require.NotNil(t, resp) | ||||||
|  | 	require.NotEmpty(t, resp.Warnings) | ||||||
|  |  | ||||||
|  | 	// All CRL-specific warnings should've already occurred earlier on the | ||||||
|  | 	// import's CRL rebuild. | ||||||
|  | 	for _, warning := range resp.Warnings { | ||||||
|  | 		require.Contains(t, originalWarnings, warning) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Deleting the issuer and key should remove the warning. | ||||||
|  | 	_, err = CBDelete(b, s, "root") | ||||||
|  | 	require.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	resp, err = CBRead(b, s, "crl/rotate") | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	require.NotNil(t, resp) | ||||||
|  | 	require.Empty(t, resp.Warnings) | ||||||
|  |  | ||||||
|  | 	// Adding back just the cert shouldn't cause CRL rebuild warnings. | ||||||
|  | 	resp, err = CBWrite(b, s, "issuers/import/bundle", map[string]interface{}{ | ||||||
|  | 		"pem_bundle": cert, | ||||||
|  | 	}) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	require.NotNil(t, resp) | ||||||
|  | 	require.NotNil(t, resp.Data) | ||||||
|  | 	require.NotNil(t, resp.Data["mapping"]) | ||||||
|  | 	require.NotEmpty(t, resp.Data["mapping"]) | ||||||
|  | 	require.Equal(t, len(resp.Data["mapping"].(map[string]string)), 1) | ||||||
|  | 	for key, value := range resp.Data["mapping"].(map[string]string) { | ||||||
|  | 		require.NotEmpty(t, key) | ||||||
|  | 		require.Empty(t, value) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err = CBRead(b, s, "crl/rotate") | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 	require.NotNil(t, resp) | ||||||
|  | 	require.Empty(t, resp.Warnings) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -301,16 +301,16 @@ func (cb *crlBuilder) flushCRLBuildTimeInvalidation(sc *storageContext) error { | |||||||
|  |  | ||||||
| // rebuildIfForced is to be called by readers or periodic functions that might need to trigger | // rebuildIfForced is to be called by readers or periodic functions that might need to trigger | ||||||
| // a refresh of the CRL before the read occurs. | // a refresh of the CRL before the read occurs. | ||||||
| func (cb *crlBuilder) rebuildIfForced(sc *storageContext) error { | func (cb *crlBuilder) rebuildIfForced(sc *storageContext) ([]string, error) { | ||||||
| 	if cb.forceRebuild.Load() { | 	if cb.forceRebuild.Load() { | ||||||
| 		return cb._doRebuild(sc, true, _enforceForceFlag) | 		return cb._doRebuild(sc, true, _enforceForceFlag) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // rebuild is to be called by various write apis that know the CRL is to be updated and can be now. | // rebuild is to be called by various write apis that know the CRL is to be updated and can be now. | ||||||
| func (cb *crlBuilder) rebuild(sc *storageContext, forceNew bool) error { | func (cb *crlBuilder) rebuild(sc *storageContext, forceNew bool) ([]string, error) { | ||||||
| 	return cb._doRebuild(sc, forceNew, _ignoreForceFlag) | 	return cb._doRebuild(sc, forceNew, _ignoreForceFlag) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -329,7 +329,7 @@ func (cb *crlBuilder) requestRebuildIfActiveNode(b *backend) { | |||||||
| 	cb.forceRebuild.Store(true) | 	cb.forceRebuild.Store(true) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cb *crlBuilder) _doRebuild(sc *storageContext, forceNew bool, ignoreForceFlag bool) error { | func (cb *crlBuilder) _doRebuild(sc *storageContext, forceNew bool, ignoreForceFlag bool) ([]string, error) { | ||||||
| 	cb._builder.Lock() | 	cb._builder.Lock() | ||||||
| 	defer cb._builder.Unlock() | 	defer cb._builder.Unlock() | ||||||
| 	// Re-read the lock in case someone beat us to the punch between the previous load op. | 	// Re-read the lock in case someone beat us to the punch between the previous load op. | ||||||
| @@ -346,7 +346,7 @@ func (cb *crlBuilder) _doRebuild(sc *storageContext, forceNew bool, ignoreForceF | |||||||
| 		return buildCRLs(sc, myForceNew) | 		return buildCRLs(sc, myForceNew) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cb *crlBuilder) _getPresentDeltaWALForClearing(sc *storageContext, path string) ([]string, error) { | func (cb *crlBuilder) _getPresentDeltaWALForClearing(sc *storageContext, path string) ([]string, error) { | ||||||
| @@ -415,7 +415,7 @@ func (cb *crlBuilder) clearUnifiedDeltaWAL(sc *storageContext, walSerials []stri | |||||||
| 	return cb._clearDeltaWAL(sc, walSerials, unifiedDeltaWALPrefix) | 	return cb._clearDeltaWAL(sc, walSerials, unifiedDeltaWALPrefix) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cb *crlBuilder) rebuildDeltaCRLsIfForced(sc *storageContext, override bool) error { | func (cb *crlBuilder) rebuildDeltaCRLsIfForced(sc *storageContext, override bool) ([]string, error) { | ||||||
| 	// Delta CRLs use the same expiry duration as the complete CRL. Because | 	// Delta CRLs use the same expiry duration as the complete CRL. Because | ||||||
| 	// we always rebuild the complete CRL and then the delta CRL, we can | 	// we always rebuild the complete CRL and then the delta CRL, we can | ||||||
| 	// be assured that the delta CRL always expires after a complete CRL, | 	// be assured that the delta CRL always expires after a complete CRL, | ||||||
| @@ -427,18 +427,18 @@ func (cb *crlBuilder) rebuildDeltaCRLsIfForced(sc *storageContext, override bool | |||||||
| 	// within our time window for updating it. | 	// within our time window for updating it. | ||||||
| 	cfg, err := cb.getConfigWithUpdate(sc) | 	cfg, err := cb.getConfigWithUpdate(sc) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !cfg.EnableDelta { | 	if !cfg.EnableDelta { | ||||||
| 		// We explicitly do not update the last check time here, as we | 		// We explicitly do not update the last check time here, as we | ||||||
| 		// want to persist the last rebuild window if it hasn't been set. | 		// want to persist the last rebuild window if it hasn't been set. | ||||||
| 		return nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	deltaRebuildDuration, err := time.ParseDuration(cfg.DeltaRebuildInterval) | 	deltaRebuildDuration, err := time.ParseDuration(cfg.DeltaRebuildInterval) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Acquire CRL building locks before we get too much further. | 	// Acquire CRL building locks before we get too much further. | ||||||
| @@ -454,7 +454,7 @@ func (cb *crlBuilder) rebuildDeltaCRLsIfForced(sc *storageContext, override bool | |||||||
| 		// If we're still before the time of our next rebuild check, we can | 		// If we're still before the time of our next rebuild check, we can | ||||||
| 		// safely return here even if we have certs. We'll wait for a bit, | 		// safely return here even if we have certs. We'll wait for a bit, | ||||||
| 		// retrigger this check, and then do the rebuild. | 		// retrigger this check, and then do the rebuild. | ||||||
| 		return nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Update our check time. If we bail out below (due to storage errors | 	// Update our check time. If we bail out below (due to storage errors | ||||||
| @@ -465,16 +465,16 @@ func (cb *crlBuilder) rebuildDeltaCRLsIfForced(sc *storageContext, override bool | |||||||
|  |  | ||||||
| 	rebuildLocal, err := cb._shouldRebuildLocalCRLs(sc, override) | 	rebuildLocal, err := cb._shouldRebuildLocalCRLs(sc, override) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, fmt.Errorf("error determining if local CRLs should be rebuilt: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	rebuildUnified, err := cb._shouldRebuildUnifiedCRLs(sc, override) | 	rebuildUnified, err := cb._shouldRebuildUnifiedCRLs(sc, override) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, fmt.Errorf("error determining if unified CRLs should be rebuilt: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !rebuildLocal && !rebuildUnified { | 	if !rebuildLocal && !rebuildUnified { | ||||||
| 		return nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Finally, we must've needed to do the rebuild. Execute! | 	// Finally, we must've needed to do the rebuild. Execute! | ||||||
| @@ -601,14 +601,14 @@ func (cb *crlBuilder) _shouldRebuildUnifiedCRLs(sc *storageContext, override boo | |||||||
| 	return shouldRebuild, nil | 	return shouldRebuild, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cb *crlBuilder) rebuildDeltaCRLs(sc *storageContext, forceNew bool) error { | func (cb *crlBuilder) rebuildDeltaCRLs(sc *storageContext, forceNew bool) ([]string, error) { | ||||||
| 	cb._builder.Lock() | 	cb._builder.Lock() | ||||||
| 	defer cb._builder.Unlock() | 	defer cb._builder.Unlock() | ||||||
|  |  | ||||||
| 	return cb.rebuildDeltaCRLsHoldingLock(sc, forceNew) | 	return cb.rebuildDeltaCRLsHoldingLock(sc, forceNew) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cb *crlBuilder) rebuildDeltaCRLsHoldingLock(sc *storageContext, forceNew bool) error { | func (cb *crlBuilder) rebuildDeltaCRLsHoldingLock(sc *storageContext, forceNew bool) ([]string, error) { | ||||||
| 	return buildAnyCRLs(sc, forceNew, true /* building delta */) | 	return buildAnyCRLs(sc, forceNew, true /* building delta */) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1064,7 +1064,7 @@ func revokeCert(sc *storageContext, config *crlConfig, cert *x509.Certificate) ( | |||||||
| 		// already rebuilt the full CRL so the Delta WAL will be cleared | 		// already rebuilt the full CRL so the Delta WAL will be cleared | ||||||
| 		// afterwards. Writing an entry only to immediately remove it | 		// afterwards. Writing an entry only to immediately remove it | ||||||
| 		// isn't necessary. | 		// isn't necessary. | ||||||
| 		crlErr := sc.Backend.crlBuilder.rebuild(sc, false) | 		warnings, crlErr := sc.Backend.crlBuilder.rebuild(sc, false) | ||||||
| 		if crlErr != nil { | 		if crlErr != nil { | ||||||
| 			switch crlErr.(type) { | 			switch crlErr.(type) { | ||||||
| 			case errutil.UserError: | 			case errutil.UserError: | ||||||
| @@ -1073,6 +1073,9 @@ func revokeCert(sc *storageContext, config *crlConfig, cert *x509.Certificate) ( | |||||||
| 				return nil, fmt.Errorf("error encountered during CRL building: %w", crlErr) | 				return nil, fmt.Errorf("error encountered during CRL building: %w", crlErr) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		for index, warning := range warnings { | ||||||
|  | 			resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 		} | ||||||
| 	} else if config.EnableDelta { | 	} else if config.EnableDelta { | ||||||
| 		if err := writeRevocationDeltaWALs(sc, config, resp, failedWritingUnifiedCRL, hyphenSerial, colonSerial); err != nil { | 		if err := writeRevocationDeltaWALs(sc, config, resp, failedWritingUnifiedCRL, hyphenSerial, colonSerial); err != nil { | ||||||
| 			return nil, fmt.Errorf("failed to write WAL entries for Delta CRLs: %w", err) | 			return nil, fmt.Errorf("failed to write WAL entries for Delta CRLs: %w", err) | ||||||
| @@ -1165,11 +1168,11 @@ func writeSpecificRevocationDeltaWALs(sc *storageContext, hyphenSerial string, c | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func buildCRLs(sc *storageContext, forceNew bool) error { | func buildCRLs(sc *storageContext, forceNew bool) ([]string, error) { | ||||||
| 	return buildAnyCRLs(sc, forceNew, false) | 	return buildAnyCRLs(sc, forceNew, false) | ||||||
| } | } | ||||||
|  |  | ||||||
| func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) ([]string, error) { | ||||||
| 	// In order to build all CRLs, we need knowledge of all issuers. Any two | 	// In order to build all CRLs, we need knowledge of all issuers. Any two | ||||||
| 	// issuers with the same keys _and_ subject should have the same CRL since | 	// issuers with the same keys _and_ subject should have the same CRL since | ||||||
| 	// they're functionally equivalent. | 	// they're functionally equivalent. | ||||||
| @@ -1204,7 +1207,7 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 	// buildCRL. | 	// buildCRL. | ||||||
| 	globalCRLConfig, err := sc.Backend.crlBuilder.getConfigWithUpdate(sc) | 	globalCRLConfig, err := sc.Backend.crlBuilder.getConfigWithUpdate(sc) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error building CRL: while updating config: %w", err) | 		return nil, fmt.Errorf("error building CRL: while updating config: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if globalCRLConfig.Disable && !forceNew { | 	if globalCRLConfig.Disable && !forceNew { | ||||||
| @@ -1216,13 +1219,13 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 		// So, since tidy can now associate issuers on revocation entries, we | 		// So, since tidy can now associate issuers on revocation entries, we | ||||||
| 		// can skip the rest of this function and exit early without updating | 		// can skip the rest of this function and exit early without updating | ||||||
| 		// anything. | 		// anything. | ||||||
| 		return nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !sc.Backend.useLegacyBundleCaStorage() { | 	if !sc.Backend.useLegacyBundleCaStorage() { | ||||||
| 		issuers, err = sc.listIssuers() | 		issuers, err = sc.listIssuers() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("error building CRL: while listing issuers: %w", err) | 			return nil, fmt.Errorf("error building CRL: while listing issuers: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		// Here, we hard-code the legacy issuer entry instead of using the | 		// Here, we hard-code the legacy issuer entry instead of using the | ||||||
| @@ -1236,13 +1239,13 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 		// Users should upgrade symmetrically, rather than attempting | 		// Users should upgrade symmetrically, rather than attempting | ||||||
| 		// backward compatibility for new features across disparate versions. | 		// backward compatibility for new features across disparate versions. | ||||||
| 		if isDelta { | 		if isDelta { | ||||||
| 			return nil | 			return []string{"refusing to rebuild delta CRL with legacy bundle; finish migrating to newer issuer storage layout"}, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	issuersConfig, err := sc.getIssuersConfig() | 	issuersConfig, err := sc.getIssuersConfig() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error building CRLs: while getting the default config: %w", err) | 		return nil, fmt.Errorf("error building CRLs: while getting the default config: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// We map issuerID->entry for fast lookup and also issuerID->Cert for | 	// We map issuerID->entry for fast lookup and also issuerID->Cert for | ||||||
| @@ -1259,7 +1262,7 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 		// legacy path is automatically ignored. | 		// legacy path is automatically ignored. | ||||||
| 		thisEntry, _, err := sc.fetchCertBundleByIssuerId(issuer, false) | 		thisEntry, _, err := sc.fetchCertBundleByIssuerId(issuer, false) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("error building CRLs: unable to fetch specified issuer (%v): %w", issuer, err) | 			return nil, fmt.Errorf("error building CRLs: unable to fetch specified issuer (%v): %w", issuer, err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if len(thisEntry.KeyID) == 0 { | 		if len(thisEntry.KeyID) == 0 { | ||||||
| @@ -1284,7 +1287,7 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
|  |  | ||||||
| 		thisCert, err := thisEntry.GetCertificate() | 		thisCert, err := thisEntry.GetCertificate() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("error building CRLs: unable to parse issuer (%v)'s certificate: %w", issuer, err) | 			return nil, fmt.Errorf("error building CRLs: unable to parse issuer (%v)'s certificate: %w", issuer, err) | ||||||
| 		} | 		} | ||||||
| 		issuerIDCertMap[issuer] = thisCert | 		issuerIDCertMap[issuer] = thisCert | ||||||
|  |  | ||||||
| @@ -1299,19 +1302,27 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 	// Now we do two calls: building the cluster-local CRL, and potentially | 	// Now we do two calls: building the cluster-local CRL, and potentially | ||||||
| 	// building the global CRL if we're on the active node of the performance | 	// building the global CRL if we're on the active node of the performance | ||||||
| 	// primary. | 	// primary. | ||||||
| 	currLocalDeltaSerials, err := buildAnyLocalCRLs(sc, issuersConfig, globalCRLConfig, | 	currLocalDeltaSerials, localWarnings, err := buildAnyLocalCRLs(sc, issuersConfig, globalCRLConfig, | ||||||
| 		issuers, issuerIDEntryMap, | 		issuers, issuerIDEntryMap, | ||||||
| 		issuerIDCertMap, keySubjectIssuersMap, | 		issuerIDCertMap, keySubjectIssuersMap, | ||||||
| 		wasLegacy, forceNew, isDelta) | 		wasLegacy, forceNew, isDelta) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	currUnifiedDeltaSerials, err := buildAnyUnifiedCRLs(sc, issuersConfig, globalCRLConfig, | 	currUnifiedDeltaSerials, unifiedWarnings, err := buildAnyUnifiedCRLs(sc, issuersConfig, globalCRLConfig, | ||||||
| 		issuers, issuerIDEntryMap, | 		issuers, issuerIDEntryMap, | ||||||
| 		issuerIDCertMap, keySubjectIssuersMap, | 		issuerIDCertMap, keySubjectIssuersMap, | ||||||
| 		wasLegacy, forceNew, isDelta) | 		wasLegacy, forceNew, isDelta) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var warnings []string | ||||||
|  | 	for _, warning := range localWarnings { | ||||||
|  | 		warnings = append(warnings, fmt.Sprintf("warning from local CRL rebuild: %v", warning)) | ||||||
|  | 	} | ||||||
|  | 	for _, warning := range unifiedWarnings { | ||||||
|  | 		warnings = append(warnings, fmt.Sprintf("warning from unified CRL rebuild: %v", warning)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Finally, we decide if we need to rebuild the Delta CRLs again, for both | 	// Finally, we decide if we need to rebuild the Delta CRLs again, for both | ||||||
| @@ -1320,17 +1331,21 @@ func buildAnyCRLs(sc *storageContext, forceNew bool, isDelta bool) error { | |||||||
| 		// After we've confirmed the primary CRLs have built OK, go ahead and | 		// After we've confirmed the primary CRLs have built OK, go ahead and | ||||||
| 		// clear the delta CRL WAL and rebuild it. | 		// clear the delta CRL WAL and rebuild it. | ||||||
| 		if err := sc.Backend.crlBuilder.clearLocalDeltaWAL(sc, currLocalDeltaSerials); err != nil { | 		if err := sc.Backend.crlBuilder.clearLocalDeltaWAL(sc, currLocalDeltaSerials); err != nil { | ||||||
| 			return fmt.Errorf("error building CRLs: unable to clear Delta WAL: %w", err) | 			return nil, fmt.Errorf("error building CRLs: unable to clear Delta WAL: %w", err) | ||||||
| 		} | 		} | ||||||
| 		if err := sc.Backend.crlBuilder.clearUnifiedDeltaWAL(sc, currUnifiedDeltaSerials); err != nil { | 		if err := sc.Backend.crlBuilder.clearUnifiedDeltaWAL(sc, currUnifiedDeltaSerials); err != nil { | ||||||
| 			return fmt.Errorf("error building CRLs: unable to clear Delta WAL: %w", err) | 			return nil, fmt.Errorf("error building CRLs: unable to clear Delta WAL: %w", err) | ||||||
| 		} | 		} | ||||||
| 		if err := sc.Backend.crlBuilder.rebuildDeltaCRLsHoldingLock(sc, forceNew); err != nil { | 		deltaWarnings, err := sc.Backend.crlBuilder.rebuildDeltaCRLsHoldingLock(sc, forceNew) | ||||||
| 			return fmt.Errorf("error building CRLs: unable to rebuild empty Delta WAL: %w", err) | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("error building CRLs: unable to rebuild empty Delta WAL: %w", err) | ||||||
|  | 		} | ||||||
|  | 		for _, warning := range deltaWarnings { | ||||||
|  | 			warnings = append(warnings, fmt.Sprintf("warning from delta CRL rebuild: %v", warning)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return warnings, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getLastWALSerial(sc *storageContext, path string) (string, error) { | func getLastWALSerial(sc *storageContext, path string) (string, error) { | ||||||
| @@ -1363,8 +1378,9 @@ func buildAnyLocalCRLs( | |||||||
| 	wasLegacy bool, | 	wasLegacy bool, | ||||||
| 	forceNew bool, | 	forceNew bool, | ||||||
| 	isDelta bool, | 	isDelta bool, | ||||||
| ) ([]string, error) { | ) ([]string, []string, error) { | ||||||
| 	var err error | 	var err error | ||||||
|  | 	var warnings []string | ||||||
|  |  | ||||||
| 	// Before we load cert entries, we want to store the last seen delta WAL | 	// Before we load cert entries, we want to store the last seen delta WAL | ||||||
| 	// serial number. The subsequent List will have at LEAST that certificate | 	// serial number. The subsequent List will have at LEAST that certificate | ||||||
| @@ -1375,7 +1391,7 @@ func buildAnyLocalCRLs( | |||||||
| 	if isDelta { | 	if isDelta { | ||||||
| 		lastDeltaSerial, err = getLastWALSerial(sc, localDeltaWALLastRevokedSerial) | 		lastDeltaSerial, err = getLastWALSerial(sc, localDeltaWALLastRevokedSerial) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1386,7 +1402,7 @@ func buildAnyLocalCRLs( | |||||||
| 	if !isDelta { | 	if !isDelta { | ||||||
| 		currDeltaCerts, err = sc.Backend.crlBuilder.getPresentLocalDeltaWALForClearing(sc) | 		currDeltaCerts, err = sc.Backend.crlBuilder.getPresentLocalDeltaWALForClearing(sc) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to get present delta WAL entries for removal: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to get present delta WAL entries for removal: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1401,7 +1417,7 @@ func buildAnyLocalCRLs( | |||||||
| 		// a separate pool for those. | 		// a separate pool for those. | ||||||
| 		unassignedCerts, revokedCertsMap, err = getLocalRevokedCertEntries(sc, issuerIDCertMap, isDelta) | 		unassignedCerts, revokedCertsMap, err = getLocalRevokedCertEntries(sc, issuerIDCertMap, isDelta) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to get revoked certificate entries: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to get revoked certificate entries: %w", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if !isDelta { | 		if !isDelta { | ||||||
| @@ -1414,7 +1430,7 @@ func buildAnyLocalCRLs( | |||||||
| 			// duplicate this serial number on the delta, hence the above | 			// duplicate this serial number on the delta, hence the above | ||||||
| 			// guard for isDelta. | 			// guard for isDelta. | ||||||
| 			if err := augmentWithRevokedIssuers(issuerIDEntryMap, issuerIDCertMap, revokedCertsMap); err != nil { | 			if err := augmentWithRevokedIssuers(issuerIDEntryMap, issuerIDCertMap, revokedCertsMap); err != nil { | ||||||
| 				return nil, fmt.Errorf("error building CRLs: unable to parse revoked issuers: %w", err) | 				return nil, nil, fmt.Errorf("error building CRLs: unable to parse revoked issuers: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -1423,21 +1439,25 @@ func buildAnyLocalCRLs( | |||||||
| 	// CRLs. | 	// CRLs. | ||||||
| 	internalCRLConfig, err := sc.getLocalCRLConfig() | 	internalCRLConfig, err := sc.getLocalCRLConfig() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("error building CRLs: unable to fetch cluster-local CRL configuration: %w", err) | 		return nil, nil, fmt.Errorf("error building CRLs: unable to fetch cluster-local CRL configuration: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := buildAnyCRLsWithCerts(sc, issuersConfig, globalCRLConfig, internalCRLConfig, | 	rebuildWarnings, err := buildAnyCRLsWithCerts(sc, issuersConfig, globalCRLConfig, internalCRLConfig, | ||||||
| 		issuers, issuerIDEntryMap, keySubjectIssuersMap, | 		issuers, issuerIDEntryMap, keySubjectIssuersMap, | ||||||
| 		unassignedCerts, revokedCertsMap, | 		unassignedCerts, revokedCertsMap, | ||||||
| 		forceNew, false /* isUnified */, isDelta); err != nil { | 		forceNew, false /* isUnified */, isDelta) | ||||||
| 		return nil, fmt.Errorf("error building CRLs: %w", err) | 	if err != nil { | ||||||
|  | 		return nil, nil, fmt.Errorf("error building CRLs: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if len(rebuildWarnings) > 0 { | ||||||
|  | 		warnings = append(warnings, rebuildWarnings...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Finally, persist our potentially updated local CRL config. Only do this | 	// Finally, persist our potentially updated local CRL config. Only do this | ||||||
| 	// if we didn't have a legacy CRL bundle. | 	// if we didn't have a legacy CRL bundle. | ||||||
| 	if !wasLegacy { | 	if !wasLegacy { | ||||||
| 		if err := sc.setLocalCRLConfig(internalCRLConfig); err != nil { | 		if err := sc.setLocalCRLConfig(internalCRLConfig); err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to persist updated cluster-local CRL config: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to persist updated cluster-local CRL config: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1453,17 +1473,17 @@ func buildAnyLocalCRLs( | |||||||
|  |  | ||||||
| 			lastDeltaBuildEntry, err := logical.StorageEntryJSON(localDeltaWALLastBuildSerial, deltaInfo) | 			lastDeltaBuildEntry, err := logical.StorageEntryJSON(localDeltaWALLastBuildSerial, deltaInfo) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("error creating last delta CRL rebuild serial entry: %w", err) | 				return nil, nil, fmt.Errorf("error creating last delta CRL rebuild serial entry: %w", err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			err = sc.Storage.Put(sc.Context, lastDeltaBuildEntry) | 			err = sc.Storage.Put(sc.Context, lastDeltaBuildEntry) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("error persisting last delta CRL rebuild info: %w", err) | 				return nil, nil, fmt.Errorf("error persisting last delta CRL rebuild info: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return currDeltaCerts, nil | 	return currDeltaCerts, warnings, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func buildAnyUnifiedCRLs( | func buildAnyUnifiedCRLs( | ||||||
| @@ -1477,19 +1497,20 @@ func buildAnyUnifiedCRLs( | |||||||
| 	wasLegacy bool, | 	wasLegacy bool, | ||||||
| 	forceNew bool, | 	forceNew bool, | ||||||
| 	isDelta bool, | 	isDelta bool, | ||||||
| ) ([]string, error) { | ) ([]string, []string, error) { | ||||||
| 	var err error | 	var err error | ||||||
|  | 	var warnings []string | ||||||
|  |  | ||||||
| 	// Unified CRL can only be built by the main cluster. | 	// Unified CRL can only be built by the main cluster. | ||||||
| 	b := sc.Backend | 	b := sc.Backend | ||||||
| 	if b.System().ReplicationState().HasState(consts.ReplicationDRSecondary|consts.ReplicationPerformanceStandby) || | 	if b.System().ReplicationState().HasState(consts.ReplicationDRSecondary|consts.ReplicationPerformanceStandby) || | ||||||
| 		(!b.System().LocalMount() && b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary)) { | 		(!b.System().LocalMount() && b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary)) { | ||||||
| 		return nil, nil | 		return nil, nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Unified CRL should only be built if enabled. | 	// Unified CRL should only be built if enabled. | ||||||
| 	if !globalCRLConfig.UnifiedCRL && !forceNew { | 	if !globalCRLConfig.UnifiedCRL && !forceNew { | ||||||
| 		return nil, nil | 		return nil, nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Before we load cert entries, we want to store the last seen delta WAL | 	// Before we load cert entries, we want to store the last seen delta WAL | ||||||
| @@ -1503,14 +1524,14 @@ func buildAnyUnifiedCRLs( | |||||||
| 	if isDelta { | 	if isDelta { | ||||||
| 		clusters, err := sc.Storage.List(sc.Context, unifiedDeltaWALPrefix) | 		clusters, err := sc.Storage.List(sc.Context, unifiedDeltaWALPrefix) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error listing clusters for unified delta WAL building: %w", err) | 			return nil, nil, fmt.Errorf("error listing clusters for unified delta WAL building: %w", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for index, cluster := range clusters { | 		for index, cluster := range clusters { | ||||||
| 			path := unifiedDeltaWALPrefix + cluster + deltaWALLastRevokedSerialName | 			path := unifiedDeltaWALPrefix + cluster + deltaWALLastRevokedSerialName | ||||||
| 			serial, err := getLastWALSerial(sc, path) | 			serial, err := getLastWALSerial(sc, path) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("error getting last written Delta WAL serial for cluster (%v / %v): %w", index, cluster, err) | 				return nil, nil, fmt.Errorf("error getting last written Delta WAL serial for cluster (%v / %v): %w", index, cluster, err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			lastDeltaSerial[cluster] = serial | 			lastDeltaSerial[cluster] = serial | ||||||
| @@ -1524,7 +1545,7 @@ func buildAnyUnifiedCRLs( | |||||||
| 	if !isDelta { | 	if !isDelta { | ||||||
| 		currDeltaCerts, err = sc.Backend.crlBuilder.getPresentUnifiedDeltaWALForClearing(sc) | 		currDeltaCerts, err = sc.Backend.crlBuilder.getPresentUnifiedDeltaWALForClearing(sc) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to get present delta WAL entries for removal: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to get present delta WAL entries for removal: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1539,7 +1560,7 @@ func buildAnyUnifiedCRLs( | |||||||
| 		// a separate pool for those. | 		// a separate pool for those. | ||||||
| 		unassignedCerts, revokedCertsMap, err = getUnifiedRevokedCertEntries(sc, issuerIDCertMap, isDelta) | 		unassignedCerts, revokedCertsMap, err = getUnifiedRevokedCertEntries(sc, issuerIDCertMap, isDelta) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to get revoked certificate entries: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to get revoked certificate entries: %w", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if !isDelta { | 		if !isDelta { | ||||||
| @@ -1552,7 +1573,7 @@ func buildAnyUnifiedCRLs( | |||||||
| 			// duplicate this serial number on the delta, hence the above | 			// duplicate this serial number on the delta, hence the above | ||||||
| 			// guard for isDelta. | 			// guard for isDelta. | ||||||
| 			if err := augmentWithRevokedIssuers(issuerIDEntryMap, issuerIDCertMap, revokedCertsMap); err != nil { | 			if err := augmentWithRevokedIssuers(issuerIDEntryMap, issuerIDCertMap, revokedCertsMap); err != nil { | ||||||
| 				return nil, fmt.Errorf("error building CRLs: unable to parse revoked issuers: %w", err) | 				return nil, nil, fmt.Errorf("error building CRLs: unable to parse revoked issuers: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -1561,21 +1582,25 @@ func buildAnyUnifiedCRLs( | |||||||
| 	// CRLs. | 	// CRLs. | ||||||
| 	internalCRLConfig, err := sc.getUnifiedCRLConfig() | 	internalCRLConfig, err := sc.getUnifiedCRLConfig() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("error building CRLs: unable to fetch cluster-local CRL configuration: %w", err) | 		return nil, nil, fmt.Errorf("error building CRLs: unable to fetch cluster-local CRL configuration: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := buildAnyCRLsWithCerts(sc, issuersConfig, globalCRLConfig, internalCRLConfig, | 	rebuildWarnings, err := buildAnyCRLsWithCerts(sc, issuersConfig, globalCRLConfig, internalCRLConfig, | ||||||
| 		issuers, issuerIDEntryMap, keySubjectIssuersMap, | 		issuers, issuerIDEntryMap, keySubjectIssuersMap, | ||||||
| 		unassignedCerts, revokedCertsMap, | 		unassignedCerts, revokedCertsMap, | ||||||
| 		forceNew, true /* isUnified */, isDelta); err != nil { | 		forceNew, true /* isUnified */, isDelta) | ||||||
| 		return nil, fmt.Errorf("error building CRLs: %w", err) | 	if err != nil { | ||||||
|  | 		return nil, nil, fmt.Errorf("error building CRLs: %w", err) | ||||||
|  | 	} | ||||||
|  | 	if len(rebuildWarnings) > 0 { | ||||||
|  | 		warnings = append(warnings, rebuildWarnings...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Finally, persist our potentially updated local CRL config. Only do this | 	// Finally, persist our potentially updated local CRL config. Only do this | ||||||
| 	// if we didn't have a legacy CRL bundle. | 	// if we didn't have a legacy CRL bundle. | ||||||
| 	if !wasLegacy { | 	if !wasLegacy { | ||||||
| 		if err := sc.setUnifiedCRLConfig(internalCRLConfig); err != nil { | 		if err := sc.setUnifiedCRLConfig(internalCRLConfig); err != nil { | ||||||
| 			return nil, fmt.Errorf("error building CRLs: unable to persist updated cluster-local CRL config: %w", err) | 			return nil, nil, fmt.Errorf("error building CRLs: unable to persist updated cluster-local CRL config: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1599,17 +1624,17 @@ func buildAnyUnifiedCRLs( | |||||||
| 			deltaInfo := lastDeltaInfo{Serial: serial} | 			deltaInfo := lastDeltaInfo{Serial: serial} | ||||||
| 			lastDeltaBuildEntry, err := logical.StorageEntryJSON(path, deltaInfo) | 			lastDeltaBuildEntry, err := logical.StorageEntryJSON(path, deltaInfo) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("error creating last delta CRL rebuild serial entry: %w", err) | 				return nil, nil, fmt.Errorf("error creating last delta CRL rebuild serial entry: %w", err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			err = sc.Storage.Put(sc.Context, lastDeltaBuildEntry) | 			err = sc.Storage.Put(sc.Context, lastDeltaBuildEntry) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, fmt.Errorf("error persisting last delta CRL rebuild info: %w", err) | 				return nil, nil, fmt.Errorf("error persisting last delta CRL rebuild info: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return currDeltaCerts, nil | 	return currDeltaCerts, warnings, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func buildAnyCRLsWithCerts( | func buildAnyCRLsWithCerts( | ||||||
| @@ -1625,9 +1650,10 @@ func buildAnyCRLsWithCerts( | |||||||
| 	forceNew bool, | 	forceNew bool, | ||||||
| 	isUnified bool, | 	isUnified bool, | ||||||
| 	isDelta bool, | 	isDelta bool, | ||||||
| ) error { | ) ([]string, error) { | ||||||
| 	// Now we can call buildCRL once, on an arbitrary/representative issuer | 	// Now we can call buildCRL once, on an arbitrary/representative issuer | ||||||
| 	// from each of these (keyID, subject) sets. | 	// from each of these (keyID, subject) sets. | ||||||
|  | 	var warnings []string | ||||||
| 	for _, subjectIssuersMap := range keySubjectIssuersMap { | 	for _, subjectIssuersMap := range keySubjectIssuersMap { | ||||||
| 		for _, issuersSet := range subjectIssuersMap { | 		for _, issuersSet := range subjectIssuersMap { | ||||||
| 			if len(issuersSet) == 0 { | 			if len(issuersSet) == 0 { | ||||||
| @@ -1675,7 +1701,7 @@ func buildAnyCRLsWithCerts( | |||||||
| 				// Finally, check our crlIdentifier. | 				// Finally, check our crlIdentifier. | ||||||
| 				if thisCRLId, ok := internalCRLConfig.IssuerIDCRLMap[issuerId]; ok && len(thisCRLId) > 0 { | 				if thisCRLId, ok := internalCRLConfig.IssuerIDCRLMap[issuerId]; ok && len(thisCRLId) > 0 { | ||||||
| 					if len(crlIdentifier) > 0 && crlIdentifier != thisCRLId { | 					if len(crlIdentifier) > 0 && crlIdentifier != thisCRLId { | ||||||
| 						return fmt.Errorf("error building CRLs: two issuers with same keys/subjects (%v vs %v) have different internal CRL IDs: %v vs %v", issuerId, crlIdIssuer, thisCRLId, crlIdentifier) | 						return nil, fmt.Errorf("error building CRLs: two issuers with same keys/subjects (%v vs %v) have different internal CRL IDs: %v vs %v", issuerId, crlIdIssuer, thisCRLId, crlIdentifier) | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					crlIdentifier = thisCRLId | 					crlIdentifier = thisCRLId | ||||||
| @@ -1687,6 +1713,24 @@ func buildAnyCRLsWithCerts( | |||||||
| 				// Skip this set for the time being; while we have valid | 				// Skip this set for the time being; while we have valid | ||||||
| 				// issuers and associated keys, this occurred because we lack | 				// issuers and associated keys, this occurred because we lack | ||||||
| 				// crl-signing usage on all issuers in this set. | 				// crl-signing usage on all issuers in this set. | ||||||
|  | 				// | ||||||
|  | 				// But, tell the user about this, so they can either correct | ||||||
|  | 				// this by reissuing the CA certificate or adding an equivalent | ||||||
|  | 				// version with KU bits if the CA cert lacks KU altogether. | ||||||
|  | 				// | ||||||
|  | 				// See also: https://github.com/hashicorp/vault/issues/20137 | ||||||
|  | 				warning := "Issuer equivalency set with associated keys lacked an issuer with CRL Signing KeyUsage; refusing to rebuild CRL for this group of issuers: " | ||||||
|  | 				var issuers []string | ||||||
|  | 				for _, issuerId := range issuersSet { | ||||||
|  | 					issuers = append(issuers, issuerId.String()) | ||||||
|  | 				} | ||||||
|  | 				warning += strings.Join(issuers, ",") | ||||||
|  |  | ||||||
|  | 				// We only need this warning once. :-) | ||||||
|  | 				if !isUnified && !isDelta { | ||||||
|  | 					warnings = append(warnings, warning) | ||||||
|  | 				} | ||||||
|  |  | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -1727,7 +1771,7 @@ func buildAnyCRLsWithCerts( | |||||||
| 			// Lastly, build the CRL. | 			// Lastly, build the CRL. | ||||||
| 			nextUpdate, err := buildCRL(sc, globalCRLConfig, forceNew, representative, revokedCerts, crlIdentifier, crlNumber, isUnified, isDelta, lastCompleteNumber) | 			nextUpdate, err := buildCRL(sc, globalCRLConfig, forceNew, representative, revokedCerts, crlIdentifier, crlNumber, isUnified, isDelta, lastCompleteNumber) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return fmt.Errorf("error building CRLs: unable to build CRL for issuer (%v): %w", representative, err) | 				return nil, fmt.Errorf("error building CRLs: unable to build CRL for issuer (%v): %w", representative, err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			internalCRLConfig.CRLExpirationMap[crlIdentifier] = *nextUpdate | 			internalCRLConfig.CRLExpirationMap[crlIdentifier] = *nextUpdate | ||||||
| @@ -1776,13 +1820,13 @@ func buildAnyCRLsWithCerts( | |||||||
|  |  | ||||||
| 		if !stillHaveIssuerForID { | 		if !stillHaveIssuerForID { | ||||||
| 			if err := sc.Storage.Delete(sc.Context, "crls/"+crlId.String()); err != nil { | 			if err := sc.Storage.Delete(sc.Context, "crls/"+crlId.String()); err != nil { | ||||||
| 				return fmt.Errorf("error building CRLs: unable to clean up deleted issuers' CRL: %w", err) | 				return nil, fmt.Errorf("error building CRLs: unable to clean up deleted issuers' CRL: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// All good :-) | 	// All good :-) | ||||||
| 	return nil | 	return warnings, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func isRevInfoIssuerValid(revInfo *revocationInfo, issuerIDCertMap map[issuerID]*x509.Certificate) bool { | func isRevInfoIssuerValid(revInfo *revocationInfo, issuerIDCertMap map[issuerID]*x509.Certificate) bool { | ||||||
|   | |||||||
| @@ -421,6 +421,8 @@ func (b *backend) pathCRLWrite(ctx context.Context, req *logical.Request, d *fra | |||||||
| 	b.crlBuilder.markConfigDirty() | 	b.crlBuilder.markConfigDirty() | ||||||
| 	b.crlBuilder.reloadConfigIfRequired(sc) | 	b.crlBuilder.reloadConfigIfRequired(sc) | ||||||
|  |  | ||||||
|  | 	resp := genResponseFromCrlConfig(config) | ||||||
|  |  | ||||||
| 	// Note this only affects/happens on the main cluster node, if you need to | 	// Note this only affects/happens on the main cluster node, if you need to | ||||||
| 	// notify something based on a configuration change on all server types | 	// notify something based on a configuration change on all server types | ||||||
| 	// have a look at crlBuilder::reloadConfigIfRequired | 	// have a look at crlBuilder::reloadConfigIfRequired | ||||||
| @@ -429,7 +431,7 @@ func (b *backend) pathCRLWrite(ctx context.Context, req *logical.Request, d *fra | |||||||
| 		// auto-rebuild and we aren't now or equivalently, we changed our | 		// auto-rebuild and we aren't now or equivalently, we changed our | ||||||
| 		// mind about delta CRLs and need a new complete one or equivalently, | 		// mind about delta CRLs and need a new complete one or equivalently, | ||||||
| 		// we changed our mind about unified CRLs), rotate the CRLs. | 		// we changed our mind about unified CRLs), rotate the CRLs. | ||||||
| 		crlErr := b.crlBuilder.rebuild(sc, true) | 		warnings, crlErr := b.crlBuilder.rebuild(sc, true) | ||||||
| 		if crlErr != nil { | 		if crlErr != nil { | ||||||
| 			switch crlErr.(type) { | 			switch crlErr.(type) { | ||||||
| 			case errutil.UserError: | 			case errutil.UserError: | ||||||
| @@ -438,9 +440,12 @@ func (b *backend) pathCRLWrite(ctx context.Context, req *logical.Request, d *fra | |||||||
| 				return nil, fmt.Errorf("error encountered during CRL building: %w", crlErr) | 				return nil, fmt.Errorf("error encountered during CRL building: %w", crlErr) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		for index, warning := range warnings { | ||||||
|  | 			resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return genResponseFromCrlConfig(config), nil | 	return resp, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func genResponseFromCrlConfig(config *crlConfig) *logical.Response { | func genResponseFromCrlConfig(config *crlConfig) *logical.Response { | ||||||
|   | |||||||
| @@ -1192,9 +1192,20 @@ func (b *backend) pathGetIssuerCRL(ctx context.Context, req *logical.Request, da | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	sc := b.makeStorageContext(ctx, req.Storage) | 	sc := b.makeStorageContext(ctx, req.Storage) | ||||||
| 	if err := b.crlBuilder.rebuildIfForced(sc); err != nil { | 	warnings, err := b.crlBuilder.rebuildIfForced(sc) | ||||||
|  | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	if len(warnings) > 0 { | ||||||
|  | 		// Since this is a fetch of a specific CRL, this most likely comes | ||||||
|  | 		// from an automated system of some sort; these warnings would be | ||||||
|  | 		// ignored and likely meaningless. Log them instead. | ||||||
|  | 		msg := "During rebuild of CRL on issuer CRL fetch, got the following warnings:" | ||||||
|  | 		for index, warning := range warnings { | ||||||
|  | 			msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 		} | ||||||
|  | 		b.Logger().Warn(msg) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var certificate []byte | 	var certificate []byte | ||||||
| 	var contentType string | 	var contentType string | ||||||
|   | |||||||
| @@ -388,7 +388,7 @@ func (b *backend) pathImportIssuers(ctx context.Context, req *logical.Request, d | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(createdIssuers) > 0 { | 	if len(createdIssuers) > 0 { | ||||||
| 		err := b.crlBuilder.rebuild(sc, true) | 		warnings, err := b.crlBuilder.rebuild(sc, true) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			// Before returning, check if the error message includes the | 			// Before returning, check if the error message includes the | ||||||
| 			// string "PSS". If so, it indicates we might've wanted to modify | 			// string "PSS". If so, it indicates we might've wanted to modify | ||||||
| @@ -403,6 +403,9 @@ func (b *backend) pathImportIssuers(ctx context.Context, req *logical.Request, d | |||||||
|  |  | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | 		for index, warning := range warnings { | ||||||
|  | 			response.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var issuersWithKeys []string | 		var issuersWithKeys []string | ||||||
| 		for _, issuer := range createdIssuers { | 		for _, issuer := range createdIssuers { | ||||||
| @@ -709,7 +712,7 @@ func (b *backend) pathRevokeIssuer(ctx context.Context, req *logical.Request, da | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Rebuild the CRL to include the newly revoked issuer. | 	// Rebuild the CRL to include the newly revoked issuer. | ||||||
| 	crlErr := b.crlBuilder.rebuild(sc, false) | 	warnings, crlErr := b.crlBuilder.rebuild(sc, false) | ||||||
| 	if crlErr != nil { | 	if crlErr != nil { | ||||||
| 		switch crlErr.(type) { | 		switch crlErr.(type) { | ||||||
| 		case errutil.UserError: | 		case errutil.UserError: | ||||||
| @@ -725,6 +728,9 @@ func (b *backend) pathRevokeIssuer(ctx context.Context, req *logical.Request, da | |||||||
| 		// Impossible. | 		// Impossible. | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	for index, warning := range warnings { | ||||||
|  | 		response.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// For sanity, we'll add a warning message here if there's no other | 	// For sanity, we'll add a warning message here if there's no other | ||||||
| 	// issuer which verifies this issuer. | 	// issuer which verifies this issuer. | ||||||
|   | |||||||
| @@ -651,7 +651,7 @@ func (b *backend) pathRotateCRLRead(ctx context.Context, req *logical.Request, _ | |||||||
| 	defer b.revokeStorageLock.RUnlock() | 	defer b.revokeStorageLock.RUnlock() | ||||||
|  |  | ||||||
| 	sc := b.makeStorageContext(ctx, req.Storage) | 	sc := b.makeStorageContext(ctx, req.Storage) | ||||||
| 	crlErr := b.crlBuilder.rebuild(sc, false) | 	warnings, crlErr := b.crlBuilder.rebuild(sc, false) | ||||||
| 	if crlErr != nil { | 	if crlErr != nil { | ||||||
| 		switch crlErr.(type) { | 		switch crlErr.(type) { | ||||||
| 		case errutil.UserError: | 		case errutil.UserError: | ||||||
| @@ -661,11 +661,17 @@ func (b *backend) pathRotateCRLRead(ctx context.Context, req *logical.Request, _ | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &logical.Response{ | 	resp := &logical.Response{ | ||||||
| 		Data: map[string]interface{}{ | 		Data: map[string]interface{}{ | ||||||
| 			"success": true, | 			"success": true, | ||||||
| 		}, | 		}, | ||||||
| 	}, nil | 	} | ||||||
|  |  | ||||||
|  | 	for index, warning := range warnings { | ||||||
|  | 		resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return resp, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *backend) pathRotateDeltaCRLRead(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) { | func (b *backend) pathRotateDeltaCRLRead(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) { | ||||||
| @@ -678,7 +684,7 @@ func (b *backend) pathRotateDeltaCRLRead(ctx context.Context, req *logical.Reque | |||||||
|  |  | ||||||
| 	isEnabled := cfg.EnableDelta | 	isEnabled := cfg.EnableDelta | ||||||
|  |  | ||||||
| 	crlErr := b.crlBuilder.rebuildDeltaCRLsIfForced(sc, true) | 	warnings, crlErr := b.crlBuilder.rebuildDeltaCRLsIfForced(sc, true) | ||||||
| 	if crlErr != nil { | 	if crlErr != nil { | ||||||
| 		switch crlErr.(type) { | 		switch crlErr.(type) { | ||||||
| 		case errutil.UserError: | 		case errutil.UserError: | ||||||
| @@ -697,6 +703,9 @@ func (b *backend) pathRotateDeltaCRLRead(ctx context.Context, req *logical.Reque | |||||||
| 	if !isEnabled { | 	if !isEnabled { | ||||||
| 		resp.AddWarning("requested rebuild of delta CRL when delta CRL is not enabled; this is a no-op") | 		resp.AddWarning("requested rebuild of delta CRL when delta CRL is not enabled; this is a no-op") | ||||||
| 	} | 	} | ||||||
|  | 	for index, warning := range warnings { | ||||||
|  | 		resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return resp, nil | 	return resp, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -297,10 +297,13 @@ func (b *backend) pathCAGenerateRoot(ctx context.Context, req *logical.Request, | |||||||
| 	b.ifCountEnabledIncrementTotalCertificatesCount(certsCounted, key) | 	b.ifCountEnabledIncrementTotalCertificatesCount(certsCounted, key) | ||||||
|  |  | ||||||
| 	// Build a fresh CRL | 	// Build a fresh CRL | ||||||
| 	err = b.crlBuilder.rebuild(sc, true) | 	warnings, err = b.crlBuilder.rebuild(sc, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	for index, warning := range warnings { | ||||||
|  | 		resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if parsedBundle.Certificate.MaxPathLen == 0 { | 	if parsedBundle.Certificate.MaxPathLen == 0 { | ||||||
| 		resp.AddWarning("Max path length of the generated certificate is zero. This certificate cannot be used to issue intermediate CA certificates.") | 		resp.AddWarning("Max path length of the generated certificate is zero. This certificate cannot be used to issue intermediate CA certificates.") | ||||||
|   | |||||||
| @@ -977,9 +977,17 @@ func (b *backend) doTidyRevocationStore(ctx context.Context, req *logical.Reques | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if !config.AutoRebuild { | 		if !config.AutoRebuild { | ||||||
| 			if err := b.crlBuilder.rebuild(sc, false); err != nil { | 			warnings, err := b.crlBuilder.rebuild(sc, false) | ||||||
|  | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
|  | 			if len(warnings) > 0 { | ||||||
|  | 				msg := "During rebuild of CRL for tidy, got the following warnings:" | ||||||
|  | 				for index, warning := range warnings { | ||||||
|  | 					msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 				} | ||||||
|  | 				b.Logger().Warn(msg) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1081,9 +1089,17 @@ func (b *backend) doTidyExpiredIssuers(ctx context.Context, req *logical.Request | |||||||
| 		b.revokeStorageLock.Lock() | 		b.revokeStorageLock.Lock() | ||||||
| 		defer b.revokeStorageLock.Unlock() | 		defer b.revokeStorageLock.Unlock() | ||||||
|  |  | ||||||
| 		if err := b.crlBuilder.rebuild(sc, false); err != nil { | 		warnings, err := b.crlBuilder.rebuild(sc, false) | ||||||
|  | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | 		if len(warnings) > 0 { | ||||||
|  | 			msg := "During rebuild of CRL for tidy, got the following warnings:" | ||||||
|  | 			for index, warning := range warnings { | ||||||
|  | 				msg = fmt.Sprintf("%v\n %d. %v", msg, index+1, warning) | ||||||
|  | 			} | ||||||
|  | 			b.Logger().Warn(msg) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								changelog/20253.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/20253.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:improvement | ||||||
|  | secrets/pki: Add warning when issuer lacks KeyUsage during CRL rebuilds; expose in logs and on rotation. | ||||||
|  | ``` | ||||||
		Reference in New Issue
	
	Block a user
	 Alexander Scheel
					Alexander Scheel