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

Verify bundle signature is valid and is not modified #9209

Merged
merged 2 commits into from
Feb 1, 2025

Conversation

panktishah26
Copy link
Member

@panktishah26 panktishah26 commented Jan 29, 2025

Issue #, if available:
#6793

Description of changes:
Validate the EKS-A bundle has not been modified by verifying the signature in the bundle annotation. We sign the bundle by adding signature annotation on the bundle field. To verify the bundle, we have used ecdsa.VerifyASN1 method to support air gapped environment scenario. The validation is only added for controller for now.

Testing (if applicable):

Documentation added/planned (if applicable):

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@eks-distro-bot eks-distro-bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jan 29, 2025
@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from e17bb84 to 486d237 Compare January 29, 2025 19:16
@@ -62,13 +62,4 @@ const (

// KMS key alias
KmsKey = "arn:aws:kms:us-west-2:857151390494:alias/signingEKSABundlesKey"

Copy link
Member Author

Choose a reason for hiding this comment

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

I have moved these constants to eks-anywhere constants package since these are used for both signing and verification purpose and to keep a single source of truth.

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 486d237 to 4c86845 Compare January 29, 2025 19:45
@eks-distro-bot eks-distro-bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 29, 2025
Copy link

codecov bot commented Jan 29, 2025

Codecov Report

Attention: Patch coverage is 74.60317% with 32 lines in your changes missing coverage. Please review.

Project coverage is 72.38%. Comparing base (5583d64) to head (fe12c2c).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/signature/manifest.go 68.47% 20 Missing and 9 partials ⚠️
pkg/validations/extendedversion.go 80.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #9209    +/-   ##
========================================
  Coverage   72.37%   72.38%            
========================================
  Files         585      587     +2     
  Lines       45710    45836   +126     
========================================
+ Hits        33084    33178    +94     
- Misses      10888    10910    +22     
- Partials     1738     1748    +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 4c86845 to 4b17c77 Compare January 29, 2025 20:33
)

// ValidateExtendedK8sVersionSupport validates all the validations needed for the support of extended kubernetes support.
func ValidateExtendedK8sVersionSupport(_ context.Context, _ *anywherev1.Cluster, bundle *v1alpha1.Bundles, _ kubernetes.Client) error {
Copy link
Member Author

Choose a reason for hiding this comment

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

I am not using context, cluster and client field in this PR but I will need those for further extended support related validations.

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 4b17c77 to 8506072 Compare January 29, 2025 21:41
// fields depending on your signing requirements.
Excludes = "LnNwZWMudmVyc2lvbnNCdW5kbGVzW10uYm9vdHN0cmFwCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmJvdHRsZXJvY2tldEhvc3RDb250YWluZXJzCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNlcnRNYW5hZ2VyCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNpbGl1bQouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5jbG91ZFN0YWNrCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNsdXN0ZXJBUEkKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uY29udHJvbFBsYW5lCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmRvY2tlcgouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5la3NhCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmV0Y2RhZG1Cb290c3RyYXAKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uZXRjZGFkbUNvbnRyb2xsZXIKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uZmx1eAouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5oYXByb3h5Ci5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmtpbmRuZXRkCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLm51dGFuaXgKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10ucGFja2FnZUNvbnRyb2xsZXIKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uc25vdwouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS50aW5rZXJiZWxsCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLnVwZ3JhZGVyCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLnZTcGhlcmU="
// KMSPublicKey to verify bundle signature.
KMSPublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFZU/Z6VVMU9HioT7rGkPdJg3frC2xyQZhWFIrz5HeZEfeQ2nAdnJMLrs2Qr3V9xVrJrHA54wnIHDoPGbEhojqg=="
Copy link
Member

Choose a reason for hiding this comment

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

from where did this value come? how is it produced?

Copy link
Member Author

@panktishah26 panktishah26 Jan 29, 2025

Choose a reason for hiding this comment

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

This is the public key of the KMS key that we use to sign the bundle.

Copy link
Member

Choose a reason for hiding this comment

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

I know public keys are meant to be public, but should we be putting this out in the open?

Copy link
Member

Choose a reason for hiding this comment

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

https://github.com/aws/eks-anywhere-packages/blob/main/charts/eks-anywhere-packages/values.yaml#L93

We have it in our packages repo too for verifying package bundle signature in the webhook.


pubparsed, err := x509.ParsePKIXPublicKey(pubdecoded)
if err != nil {
return false, digest, yml, fmt.Errorf("unable parse the public key (not PKIX): %v", err)
Copy link
Member

Choose a reason for hiding this comment

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

might think about this: %v -> %w.

"Wrap an error to expose it to callers. Do not wrap an error when doing so would expose implementation details."
reference: https://go.dev/blog/go1.13-errors#wrapping-errors-with-w

if !valid {
return fmt.Errorf("signature on the bundle is invalid, error: %v, digest: %s", err, base64.StdEncoding.EncodeToString(digest[:]))
}
logger.Info("Signature on the bundle is valid.")
Copy link
Member

Choose a reason for hiding this comment

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

i recommend not logging in a function in a package like this. I recommend letting consumers/callers of the function do the logging. Also, this this looks like a global logger. Where is it even defined?

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree, I added it as a part of my debugging and forgot to remove. I have removed this log.

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 8506072 to b67e52f Compare January 29, 2025 23:20
func validateExtendedK8sVersionSupport(ctx context.Context, client client.Client, cluster *anywherev1.Cluster) error {
bundle, err := c.BundlesForCluster(ctx, clientutil.NewKubeClient(client), cluster)
if err != nil {
return fmt.Errorf("failed to get bundle for cluster: %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.

We generally want to avoid saying error or failed again right?

Suggested change
return fmt.Errorf("failed to get bundle for cluster: %w", err)
return fmt.Errorf("getting bundle for cluster: %w", err)

// Excludes is a base64-encoded, newline-delimited list of JSON/YAML paths to remove
// from the Bundles manifest prior to computing the digest. You can add or remove
// fields depending on your signing requirements.
Excludes = "LnNwZWMudmVyc2lvbnNCdW5kbGVzW10uYm9vdHN0cmFwCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmJvdHRsZXJvY2tldEhvc3RDb250YWluZXJzCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNlcnRNYW5hZ2VyCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNpbGl1bQouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5jbG91ZFN0YWNrCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmNsdXN0ZXJBUEkKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uY29udHJvbFBsYW5lCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmRvY2tlcgouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5la3NhCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmV0Y2RhZG1Cb290c3RyYXAKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uZXRjZGFkbUNvbnRyb2xsZXIKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uZmx1eAouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS5oYXByb3h5Ci5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLmtpbmRuZXRkCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLm51dGFuaXgKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10ucGFja2FnZUNvbnRyb2xsZXIKLnNwZWMudmVyc2lvbnNCdW5kbGVzW10uc25vdwouc3BlYy52ZXJzaW9uc0J1bmRsZXNbXS50aW5rZXJiZWxsCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLnVwZ3JhZGVyCi5zcGVjLnZlcnNpb25zQnVuZGxlc1tdLnZTcGhlcmU="
Copy link
Member

Choose a reason for hiding this comment

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

How did we determine what to remove here?

Copy link
Member

Choose a reason for hiding this comment

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

https://quip-amazon.com/cUORAQaTboBZ/Extended-Kubernetes-version-support-for-EKS-Anywhere#temp:C:ceKc799977659fd44e0916fb1899

We are only concerned with the tampering of the above fields for extended support. In the future, if we need to include more fields in the bundle signature for particular usecase, it can be easily added by removing it from the Excludes annotation here.


pubdecoded, err := base64.StdEncoding.DecodeString(pubKey)
if err != nil {
return false, fmt.Errorf("unable to decode the public key (not base 64): %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.

Yea these should be phrased as such right?

Suggested change
return false, fmt.Errorf("unable to decode the public key (not base 64): %w", err)
return false, fmt.Errorf("decoding the public key as string: %w", err)

// Marshal Bundles object to YAML
yamlBytes, err := yaml.Marshal(bundle)
if err != nil {
return zero, nil, fmt.Errorf("marshalling bundle to YAML: %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.

Yea this is a right error message

@@ -389,6 +389,10 @@ func (r *ClusterReconciler) preClusterProviderReconcile(ctx context.Context, log
return controller.Result{}, err
}

if err := validateExtendedK8sVersionSupport(ctx, r.client, cluster); err != nil {
Copy link
Member

@vivek-koppuru vivek-koppuru Jan 30, 2025

Choose a reason for hiding this comment

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

Are we planning to update the cluster status in any way, or this will just be reflected as an error in the controller logs?

Copy link
Member Author

@panktishah26 panktishah26 Jan 31, 2025

Choose a reason for hiding this comment

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

I have updated the status fields with error.

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 83cf0f2 to 97804a2 Compare January 31, 2025 00:41
@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch from 97804a2 to 7cdc7cb Compare January 31, 2025 00:43
@panktishah26
Copy link
Member Author

/test eks-anywhere-release-tooling-test-presubmit

@panktishah26 panktishah26 force-pushed the extended-k8s-bundle-validation branch 3 times, most recently from fb5465a to da9a9dd Compare January 31, 2025 20:46
BundleNotFoundReason FailureReasonType = "BundleNotFoundForCluster"

// K8sVersionNotSupportedReason reports that validation for supporting extended kubernetes version failed.
K8sVersionNotSupportedReason FailureReasonType = "ExtendedKubernetesVersionNotSupported"
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
K8sVersionNotSupportedReason FailureReasonType = "ExtendedKubernetesVersionNotSupported"
ExtendedK8sVersionSupportNotSupportedReason FailureReasonType = "ExtendedKubernetesVersionSupportNotSupported"

@@ -0,0 +1,338 @@
package signature
Copy link
Member

Choose a reason for hiding this comment

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

Can you rename this file to fix spelling?

@sp1999
Copy link
Member

sp1999 commented Jan 31, 2025

/lgtm

@eks-distro-bot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

Approval requirements bypassed by manually added approval.

This pull-request has been approved by:

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

@panktishah26 panktishah26 merged commit 26f5eab into aws:main Feb 1, 2025
13 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved lgtm size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants