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

Add Tink signing backend #645

Merged
merged 1 commit into from
Jun 28, 2022
Merged

Conversation

haydentherapper
Copy link
Contributor

@haydentherapper haydentherapper commented Jun 14, 2022

Summary

This adds support for using encrypted Tink keysets to load a signer.
There are two main benefits from this work: We can leverage this instead
of KMS if we need to support a higher QPS, and Tink keysets use strong
secure defaults. Keysets can be encrypted with AESGCM, do not rely on a
KDF, cannot be brute-forced, and access to the key can be audited
through cloud audit logs.

Tink does not provide a method to extract the signing key from the
keyset intentionally, so I wrote a helper library to reach into the key
handle proto to construct a crypto.Signer.

Signed-off-by: Hayden Blauzvern [email protected]

Ticket Link

Fixes #646

Release Note

Added Tink signing backend for signing certificates with a local encrypted Tink keyset

@codecov-commenter
Copy link

codecov-commenter commented Jun 14, 2022

Codecov Report

Merging #645 (4302340) into main (ce8d2fb) will decrease coverage by 0.17%.
The diff coverage is 63.46%.

@@            Coverage Diff             @@
##             main     #645      +/-   ##
==========================================
- Coverage   62.02%   61.85%   -0.18%     
==========================================
  Files          29       30       +1     
  Lines        1646     1717      +71     
==========================================
+ Hits         1021     1062      +41     
- Misses        552      571      +19     
- Partials       73       84      +11     
Impacted Files Coverage Δ
pkg/ca/fileca/fileca.go 48.48% <ø> (ø)
pkg/ca/googleca/v1/googleca.go 52.25% <0.00%> (ø)
pkg/ca/tinkca/tinkca.go 37.93% <37.93%> (ø)
pkg/ca/tinkca/signer.go 57.14% <57.14%> (ø)
pkg/ca/baseca/baseca.go 56.09% <66.66%> (ø)
pkg/ca/common.go 85.93% <85.93%> (ø)
pkg/ca/ephemeralca/ephemeral.go 70.73% <100.00%> (+0.73%) ⬆️
pkg/ca/extensions.go 100.00% <100.00%> (ø)
pkg/ca/fileca/load.go 58.62% <100.00%> (-10.35%) ⬇️
pkg/ca/kmsca/kmsca.go 53.57% <100.00%> (ø)
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ce8d2fb...4302340. Read the comment docs.

@dlorenc
Copy link
Member

dlorenc commented Jun 15, 2022

We can leverage this instead of KMS if we need to support a higher QPS, and Tink keysets use strong secure defaults. Keysets can be encrypted with AESGCM, do not rely on a KDF, cannot be brute-forced, and access to the key can be audited through cloud audit logs.

I'm not sure I follow this part - are we saying that we'd be storing an encrypted private key locally, then decrypting that private key to use for signing? The encryption/decryption would happen in KMS, but then the signing would happen with an in-memory key?

@haydentherapper
Copy link
Contributor Author

Yep! It's similar to the file CA implementation, but instead of a password-protected signing key, it's a KMS-encrypted signing key. All signing would happen with an in-memory key. There's only one call to KMS, just to decrypt the key (unlike the current implementation which signs all certs with a KMS key)

Here's the end to end flow:

  • One-time, create a Tink keyset to be used for signing, and encrypt it with a KMS key. Also create a CA certificate using the Tink keyset's public key
  • Configure the CA with the encrypted Tink keyset, the CA chain, and the KMS key
  • On startup, the CA will use the KMS key to decrypt the Tink keyset. Once decrypted, it can be used to sign certificates

@dlorenc
Copy link
Member

dlorenc commented Jun 15, 2022

Ah ok, thanks. Makes sense. The part that threw me off was around auditing access to the key - I guess it's technically correct that we can audit decryptions of the key, but if it were to leak we don't have any magic there.

@haydentherapper
Copy link
Contributor Author

Yea, if the key leaked from memory somehow, there's nothing that can be done, but at rest, if the encrypted key is compromised, it should be infeasible to decrypt it without the KMS key/service account credentials.

@haydentherapper haydentherapper marked this pull request as ready for review June 20, 2022 21:21
@haydentherapper
Copy link
Contributor Author

haydentherapper commented Jun 20, 2022

Tested with:

./tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://projects/project/locations/us-west1/keyRings/test-ring-local/cryptoKeys/test-key

(reverse-i-search)`go run ': go run cmd/fetch_ca_cert/fetch_ca_cert.go   --tink-kms-resource="gcp-kms://projects/project/locations/us-west1/keyRings/test-ring-local/cryptoKeys/test-key" --tink-keyset-path="../tinkey/enc-keyset.cfg" --gcp-ca-parent="projects/project/locations/us-west1/caPools/fulcio-test" --output="chain.crt.pem"

edit docker-compose to add necessary flags

test with curl

@haydentherapper
Copy link
Contributor Author

@bobcallaway @dlorenc Bumping PR, thanks! Just a note, the only untested function is tinkca.GetPrimaryKey since it fetches a key from a remote KMS and the library doesn't support fakes.

bobcallaway
bobcallaway previously approved these changes Jun 28, 2022
Copy link
Member

@bobcallaway bobcallaway left a comment

Choose a reason for hiding this comment

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

lgtm, thanks!

pkg/ca/tinkca/signer.go Outdated Show resolved Hide resolved
pkg/ca/tinkca/signer.go Outdated Show resolved Hide resolved
This adds support for using encrypted Tink keysets to load a signer.
There are two main benefits from this work: We can leverage this instead
of KMS if we need to support a higher QPS, and Tink keysets use strong
secure defaults. Keysets can be encrypted with AESGCM, do not rely on a
KDF, cannot be brute-forced, and access to the key can be audited
through cloud audit logs.

Tink does not provide a method to extract the signing key from the
keyset intentionally, so I wrote a helper library to reach into the key
handle proto to construct a crypto.Signer.

Signed-off-by: Hayden Blauzvern <[email protected]>
@haydentherapper haydentherapper merged commit fac62ed into sigstore:main Jun 28, 2022
@haydentherapper haydentherapper deleted the tink branch June 28, 2022 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Tink signing backend for local signing
4 participants