Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kmsv2: KDF based nonce extension #118828

Merged
merged 1 commit into from
Jul 21, 2023

Conversation

enj
Copy link
Member

@enj enj commented Jun 23, 2023

Fixes #118831

/kind feature
/kind api-change
/sig auth
/triage accepted
/milestone v1.28

Changed how KMS v2 encryption at rest can generate data encryption keys.
When you enable the `KMSv2KDF` feature gate (off by default), KMS v2 uses a key derivation function to generate single use data encryption keys from a secret seed combined with some random data.  This eliminates the need for a counter based nonce while avoiding nonce collision concerns associated with AES-GCM's 12 byte nonce.
TODO link PR to update docs

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Jun 23, 2023
@k8s-ci-robot k8s-ci-robot added this to the v1.28 milestone Jun 23, 2023
@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. kind/feature Categorizes issue or PR as related to a new feature. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API sig/auth Categorizes an issue or PR as relevant to SIG Auth. triage/accepted Indicates an issue or PR is ready to be actively worked on. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. area/apiserver area/test sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/testing Categorizes an issue or PR as relevant to SIG Testing. labels Jun 23, 2023
@enj
Copy link
Member Author

enj commented Jun 23, 2023

/uncc alculquicondor caesarxuchao

@enj
Copy link
Member Author

enj commented Jun 23, 2023

/cc @nilekhc

@zelenushechka
Copy link
Member

Hey, I'm Anhelina from the Bug Triage Release team 1.28 👋. I wanted to let you know that Code Freeze is coming up on 01:00 UTC Wednesday 19th July 2023 / 18:00 PDT Tuesday 18th July 2023, Please make sure that this PR is submitted before the deadline. We are currently in Week 7, and the Code Freeze will be in effect by Week 9.
Do let me know if I can be of any help :)

@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jun 27, 2023
@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from 3b9fcbc to 19f6d89 Compare June 30, 2023 15:38
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 30, 2023
@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from 19f6d89 to 9259498 Compare June 30, 2023 21:54
@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 15, 2023
@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from d97b074 to f8cdfbc Compare July 18, 2023 21:44
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 18, 2023
@enj
Copy link
Member Author

enj commented Jul 18, 2023

/retest

@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from f8cdfbc to 6c1ee9a Compare July 18, 2023 23:26
// generateKey generates a random key using system randomness.
func generateKey(length int) (key []byte, err error) {
// GenerateKey generates a random key using system randomness.
func GenerateKey(length int) (key []byte, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is almost certainly fine to panic if rand.Read returns an error. On systems with getrandom (linux after 2014), it won't error after system entropy is initialized:

https://cs.opensource.google/go/go/+/refs/tags/go1.20.6:src/crypto/rand/rand_getrandom.go;l=36-38;drc=338a81741a9aecba1a80014eced5cb2d3852d8eb

Also maybe GetRandomBytes would be a better name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can do in a follow up - internally this sets metrics right now so would need to split this up to have a GetRandomBytes func.

// Because this mode requires a generated IV and IV reuse is a known weakness of AES-GCM, keys
// must be rotated before a birthday attack becomes feasible. NIST SP 800-38D
// (http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) recommends using the same
// key with random 96-bit nonces (the default nonce length) no more than 2^32 times, and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for fun, here's the calc. Birthday bound approximation is:

          N^2    (2^n)^2     2^(2n)
p(N;M) ~= ─── == ─────── == ───────
          2*M     2*2^m     2^(m+1)

M is size of set, m=log2(M) (i.e. m is bit size of nonce)
N is number of items chosen uniform randomly from the set, n=log2(N)
p(N;M) is probability of a collision given N draws from set of size M

SP 800-38D requires that “the probability that the authenticated encryption function ever will be invoked with the same IV and the same key on two (or more) distinct sets of input data shall be no greater than 2-32”.


     2^(2n)     1
    ─────── <= ────
    2^(m+1)    2^32

2^(2n)*2^32 <= 2^(m+1)

  2^(2n+32) <= 2^(m+1)

      2n+32 <= m+1

               m-31
          n <= ────
                2

Then for AES-GCM with nonce size of 96 bits

n <= (96-31)/2
n <= 32.5

Which is where 2^32 comes from. Also, limiting probability of collision 2^-32 is a very high standard.

// In regard to KMSv2, organization standards or compliance policies around rotation may require
// that the seed be rotated at some interval. This can be implemented externally by rotating
// the key encryption key via a key ID change.
func NewKDFExtendedNonceGCMTransformerFromSeed(seed []byte) (value.Transformer, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func NewKDFExtendedNonceGCMTransformerFromSeed(seed []byte) (value.Transformer, error) {
func NewHKDFExtendedNonceGCMTransformer(key []byte) (value.Transformer, error) {

two nits:

  • Add H to KDF so the scheme is called HKDFExtendendNonceGCM.
  • The seed is the key for this scheme. While it happens to seed a KDF as part of the internal key schedule, that's an implemenation detail. It may be less confusing to just call it key (i.e. you better keep it secret!).

Comment on lines +96 to +99
info := make([]byte, infoSizeExtendedNonceGCM)
if err := randomNonce(info); err != nil {
return nil, fmt.Errorf("failed to generate info for KDF: %w", err)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not: just call GetKey(infoSizeExtendedNonceGCM) especially if you rename it to GetRandomBytes

// NewKDFExtendedNonceGCMTransformerFromSeed is the same as NewGCMTransformer but trades storage,
// memory and CPU to work around the limitations of AES-GCM's 12 byte nonce size. The input seed
// is assumed to be a cryptographically strong slice of MinSeedSizeExtendedNonceGCM+ random bytes.
// Unlike NewGCMTransformer, this function is immune to the birthday attack because a new key is generated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found some relevant info on this https://words.filippo.io/dispatches/xaes-256-gcm-11/ (From Fillipo published a couple days ago), and linked from that: https://soatok.blog/2022/12/21/extending-the-aes-gcm-nonce-without-nightmare-fuel/

@liggitt liggitt added this to In progress in API Reviews Jul 20, 2023
@liggitt liggitt moved this from In progress to Changes requested in API Reviews Jul 20, 2023
@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from 2b0ce20 to 256ef44 Compare July 21, 2023 14:18
@liggitt
Copy link
Member

liggitt commented Jul 21, 2023

lgtm/approve for the proto API update (@mikedanese can weigh in on enum names, or we can tweak the text names in the future without changing the wire serialization)

I didn't review the implementation, will leave that review to mike

@enj
Copy link
Member Author

enj commented Jul 21, 2023

/retest

#119493

EncryptedDEKSourceType encryptedDEKSourceType = 5;
}

enum EncryptedDEKSourceType {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I might drop the "Encrypted" prefix. This describes a property of the unencyrpted DEKSource, it shows up in code around the unencrypted key, etc... encryptedDEKSourceType sounds fine as the field name, I'd just drop it from the enum type name.

block, err := aes.NewCipher(key)
if err != nil {
return nil, err
func (t *envelopeTransformer) addTransformerForDecryption(cacheKey []byte, key []byte, useSeed bool) (value.Read, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should pass in the EncryptedDEKSourceType and switch vs useSeed. That would be the factoring e.g. once we support three types.

transformer, newKey, err := aestransformer.NewGCMTransformerWithUniqueKeyUnsafe()
// GenerateTransformer generates a new transformer and encrypts the DEK/seed using the envelope service.
// It returns the transformer, the encrypted DEK/seed, cache key and error.
func GenerateTransformer(ctx context.Context, uid string, envelopeService kmsservice.Service, useSeed bool) (value.Transformer, *kmstypes.EncryptedObject, []byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same re useSeed.

@mikedanese
Copy link
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jul 21, 2023
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 76ef461ead1e01091ddece09448388dad9551bfe

@enj enj force-pushed the enj/f/kms_v2_hkdf_expand branch from 256ef44 to bf49c72 Compare July 21, 2023 19:26
@liggitt
Copy link
Member

liggitt commented Jul 21, 2023

/approve

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: enj, liggitt

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 21, 2023
@k8s-ci-robot
Copy link
Contributor

@enj: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-kubernetes-e2e-gce-cos-alpha-features bf49c72 link false /test pull-kubernetes-e2e-gce-cos-alpha-features

Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@k8s-ci-robot k8s-ci-robot merged commit 773a6b1 into kubernetes:master Jul 21, 2023
15 of 16 checks passed
@sftim
Copy link
Contributor

sftim commented Jul 25, 2023

Changelog suggestion:

Changed KMS API encryption can generate data encryption keys.
When you enable the `KMSv2KDF` feature gate (off by default), KMS v2 uses a key derivation function to generate single use data encryption keys from a secret seed combined with some random data.  This eliminates the need for a counter based nonce while avoiding nonce collision concerns associated with AES-GCM's 12 byte nonce.

BTW, is there a docs PR to cover this change?

@liggitt liggitt moved this from Changes requested to API review completed, 1.28 in API Reviews Aug 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/apiserver area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Status: API review completed, 1.28
Archived in project
Status: Done
Archived in project
Development

Successfully merging this pull request may close these issues.

kmsv2: fix limitations caused by counter based nonce
9 participants