Merge pull request #116877 from enj/enj/i/validate_encrypt_resp_early

kmsv2: validate encrypt response at DEK generation time
This commit is contained in:
Kubernetes Prow Robot 2023-03-24 15:18:03 -07:00 committed by GitHub
commit f393e7da7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 8 deletions

View File

@ -81,9 +81,10 @@ func (t *testEnvelopeService) Encrypt(data []byte) ([]byte, error) {
// testKMSv2EnvelopeService is a mock kmsv2 envelope service which can be used to simulate remote Envelope v2 services
// for testing of the envelope transformer with other transformers.
type testKMSv2EnvelopeService struct {
err error
keyID string
encryptCalls int
err error
keyID string
encryptCalls int
encryptAnnotations map[string][]byte
}
func (t *testKMSv2EnvelopeService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
@ -99,8 +100,9 @@ func (t *testKMSv2EnvelopeService) Encrypt(ctx context.Context, uid string, data
return nil, t.err
}
return &kmsservice.EncryptResponse{
Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)),
KeyID: t.keyID,
Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)),
KeyID: t.keyID,
Annotations: t.encryptAnnotations,
}, nil
}
@ -123,17 +125,17 @@ func newMockErrorEnvelopeService(endpoint string, timeout time.Duration) (envelo
// The factory method to create mock envelope kmsv2 service.
func newMockEnvelopeKMSv2Service(ctx context.Context, endpoint, providerName string, timeout time.Duration) (kmsservice.Service, error) {
return &testKMSv2EnvelopeService{nil, "1", 0}, nil
return &testKMSv2EnvelopeService{nil, "1", 0, nil}, nil
}
// The factory method to create mock envelope kmsv2 service which always returns error.
func newMockErrorEnvelopeKMSv2Service(endpoint string, timeout time.Duration) (kmsservice.Service, error) {
return &testKMSv2EnvelopeService{errors.New("test"), "1", 0}, nil
return &testKMSv2EnvelopeService{errors.New("test"), "1", 0, nil}, nil
}
// The factory method to create mock envelope kmsv2 service that always returns invalid keyID.
func newMockInvalidKeyIDEnvelopeKMSv2Service(ctx context.Context, endpoint string, timeout time.Duration, keyID string) (kmsservice.Service, error) {
return &testKMSv2EnvelopeService{nil, keyID, 0}, nil
return &testKMSv2EnvelopeService{nil, keyID, 0, nil}, nil
}
func TestLegacyConfig(t *testing.T) {
@ -1758,6 +1760,39 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) {
`errState=<nil>, errGen=failed to encrypt DEK, error: broken, statusKeyID="5", ` +
`encryptKeyID="", stateKeyID="4", expirationTimestamp=` + now.Add(7*time.Minute).Format(time.RFC3339),
},
{
name: "invalid service response, no previous state",
service: &testKMSv2EnvelopeService{keyID: "1", encryptAnnotations: map[string][]byte{"panda": nil}},
state: envelopekmsv2.State{},
statusKeyID: "1",
wantState: envelopekmsv2.State{},
wantEncryptCalls: 1,
wantLogs: []string{
`"encrypting content using envelope service" uid="panda"`,
},
wantErr: `failed to rotate DEK uid="panda", ` +
`errState=got unexpected nil transformer, errGen=failed to validate annotations: annotations: Invalid value: "panda": ` +
`should be a domain with at least two segments separated by dots, statusKeyID="1", ` +
`encryptKeyID="", stateKeyID="", expirationTimestamp=` + (time.Time{}).Format(time.RFC3339),
},
{
name: "invalid service response, with previous state",
service: &testKMSv2EnvelopeService{keyID: "3", encryptAnnotations: map[string][]byte{"panda": nil}},
state: validState("2", now),
statusKeyID: "3",
wantState: envelopekmsv2.State{
KeyID: "2",
ExpirationTimestamp: now,
},
wantEncryptCalls: 1,
wantLogs: []string{
`"encrypting content using envelope service" uid="panda"`,
},
wantErr: `failed to rotate DEK uid="panda", ` +
`errState=<nil>, errGen=failed to validate annotations: annotations: Invalid value: "panda": ` +
`should be a domain with at least two segments separated by dots, statusKeyID="3", ` +
`encryptKeyID="", stateKeyID="2", expirationTimestamp=` + now.Format(time.RFC3339),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -278,6 +278,15 @@ func GenerateTransformer(ctx context.Context, uid string, envelopeService kmsser
return nil, nil, nil, fmt.Errorf("failed to encrypt DEK, error: %w", err)
}
if err := validateEncryptedObject(&kmstypes.EncryptedObject{
KeyID: resp.KeyID,
EncryptedDEK: resp.Ciphertext,
EncryptedData: []byte{0}, // any non-empty value to pass validation
Annotations: resp.Annotations,
}); err != nil {
return nil, nil, nil, err
}
cacheKey, err := generateCacheKey(resp.Ciphertext, resp.KeyID, resp.Annotations)
if err != nil {
return nil, nil, nil, err