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

[Fleet] Add experimental package verification (server side) #135570

Merged
merged 18 commits into from
Jul 7, 2022

Conversation

hop-dev
Copy link
Contributor

@hop-dev hop-dev commented Jun 30, 2022

Summary

Part of #133822.

Add package verification on package install. Verify a package signature if:

  • the feature flag is enabled packageVerification
  • the package has a .sig file in the registry (none will yet)
  • a local public key is configured at xpack.fleet.packageVerification.gpgKeyPath

Otherwise package verification status is always set to "unknown".

Summary of changes

  • Add new feature flag packageVerification, disabled by default
  • Add new fields to installation saved object (saved object migration to follow in separate PR)
    • verification_status - unknown | verified | unverified
    • verification_key_id - present if status is not unknown, they id of the key used to do verification.
  • Add new cache for storing archive verification status
  • When downloading archive, perform verification and cache result
  • Verify bundled packages when downloading them (but don't currently store the .sig file for future verification, so will still have unknown verification status)
  • Return 400 response code if package verification fails
  • If a package is installed with force: true then install will proceed even if verification fails

Testing steps

    1. Run the version of the EPR with package signatures locally:

docker run -p 8080:8080 docker.elastic.co/observability-ci/package-registry/distribution:PR-463

    1. set xpack.fleet.registryUrl: http://localhost:8080
    1. download local public key curl https://artifacts.elastic.co/GPG-KEY-elasticsearch -o /tmp/GPG-KEY-elasticsearch
    1. set xpack.fleet.packageVerification.gpgKeyPath: /tmp/GPG-KEY-elasticsearch
    1. Enable the feature by setting:
xpack.fleet.enableExperimental: 
    - packageVerification
    1. Optional - to test if verification fails, here is a GPG public key which isnt the elastic one:
      NOT_THE_ELASTIC_KEY.txt

Test scenarios:

  • if verification feature flag is enabled and:
    • verification is successful: Install should succeed,verification_key_id should be d27d666cd88e42b4 and verification_status should be verified
    • verification is not successful : (e.g by using a different public key supplied above) Install should not succeed, 400 response code returned,verification_key_id should be d27d666cd88e42b4 and verification_status should be unverified
    • no public key configured locally: (e.g by unsetting gpgKey config)Install should succeed,verification_key_id should not be set and verification_status should be unknown
    • missing .sig file: (e.g by connecting to the normal EPR) Install should succeed,verification_key_id should not be set and verification_status should be unknown
  • verification feature flag not enabled: Install should succeed,verification_key_id should not be set and verification_status should be unknown

Checklist

Delete any items that are not applicable to this PR.

@hop-dev hop-dev added release_note:skip Skip the PR/issue when compiling release notes Team:Fleet Team label for Observability Data Collection Fleet team v8.4.0 labels Jun 30, 2022
@hop-dev hop-dev self-assigned this Jun 30, 2022
@@ -60,6 +61,9 @@ const getHTTPResponseCode = (error: IngestManagerError): number => {
if (error instanceof PackageUnsupportedMediaTypeError) {
return 415; // Unsupported Media Type
}
if (error instanceof PackageFailedVerificationError) {
return 422; // Unprocessable Entity
Copy link
Contributor Author

@hop-dev hop-dev Jun 30, 2022

Choose a reason for hiding this comment

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

Not sure about this response code for when a package fails verification, I was also tempted by Forbidden or Bad Request

Copy link
Member

Choose a reason for hiding this comment

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

400 Bad Request seems most appropriate here. 422 is usually more applicable when creating/updating some resource and the request body fails some validation check in my experience.

@@ -5,7 +5,7 @@
* 2.0.
*/

import type { AssetParts, InstallSource } from '../../../../common/types';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

installSource was unused

if (verificationResult) {
savedObjectUpdate = {
...savedObjectUpdate,
verification_key_id: null, // unset any previous verification key id
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if this is a bit messy, if for example I install a packge and it is verified, then I reinstall it and it is "unknown", we need to unset the verification key ID, I've done this by nulling it.

Copy link
Member

Choose a reason for hiding this comment

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

This makes sense to me

@@ -256,32 +282,65 @@ function ensureContentType(archivePath: string) {
return contentType;
}

export async function ensureCachedArchiveInfo(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this function was unused

@hop-dev hop-dev requested a review from kpollich June 30, 2022 16:16
@hop-dev hop-dev marked this pull request as ready for review June 30, 2022 16:17
@hop-dev hop-dev requested review from a team as code owners June 30, 2022 16:17
@hop-dev hop-dev requested review from pzl and parkiino June 30, 2022 16:17
@elasticmachine
Copy link
Contributor

Pinging @elastic/fleet (Team:Fleet)

Copy link
Member

@pzl pzl left a comment

Choose a reason for hiding this comment

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

security_solution bits are 👌

@hop-dev hop-dev force-pushed the 133822-package-signature-verification branch from eb62b01 to e61cebd Compare July 4, 2022 10:56
const archiveEntryCache: Map<ArchiveEntry['path'], ArchiveEntry['buffer']> = new Map();
export const getArchiveEntry = (key: string) => archiveEntryCache.get(key);
export const setArchiveEntry = (key: string, value: Buffer) => archiveEntryCache.set(key, value);
export const hasArchiveEntry = (key: string) => archiveEntryCache.has(key);
export const clearArchiveEntries = () => archiveEntryCache.clear();
export const deleteArchiveEntry = (key: string) => archiveEntryCache.delete(key);

const verificationResultCache: Map<SharedKeyString, PackageVerificationResult> = new Map();
Copy link
Member

Choose a reason for hiding this comment

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

I am wondering if we should avoid this cache pattern at some point it's not going to scale (it's probably more problematic for archiveEntryCache) do we really need to cache things how often are computing the verification?

If we really need to cache it it's probably better to use an LRU cache with a max size

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into removing caching, unfortunately as we do not cache the full archive only the sub-files this wasn't possible. I agree that the way that we cache isn't great, I think changing the way we cache should be done as a seperate ticket which I have raised here: #135790

@hop-dev hop-dev force-pushed the 133822-package-signature-verification branch 2 times, most recently from 58ea0e8 to 4236cbb Compare July 6, 2022 19:41
Copy link
Member

@kpollich kpollich left a comment

Choose a reason for hiding this comment

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

Couple naming suggestions and one clarification around log level. Requested changes are nonblocking though, so marking as approved.

if (verificationResult) {
savedObjectUpdate = {
...savedObjectUpdate,
verification_key_id: null, // unset any previous verification key id
Copy link
Member

Choose a reason for hiding this comment

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

This makes sense to me

@hop-dev hop-dev force-pushed the 133822-package-signature-verification branch from 4236cbb to 36a17de Compare July 7, 2022 10:19
@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
fleet 1376 1379 +3

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 5.2MB 5.2MB +30.0B

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
fleet 111.3KB 111.3KB +23.0B

Saved Objects .kibana field count

Every field in each saved object type adds overhead to Elasticsearch. Kibana needs to keep the total field count below Elasticsearch's default limit of 1000 fields. Only specify field mappings for the fields you wish to search on or query. See https://www.elastic.co/guide/en/kibana/master/development-plugin-saved-objects.html#_mappings

id before after diff
epm-packages 20 22 +2
Unknown metric groups

API count

id before after diff
fleet 1507 1510 +3

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @hop-dev

Copy link
Contributor

@parkiino parkiino left a comment

Choose a reason for hiding this comment

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

onboarding-lifecycle-management team files look good to me

@hop-dev hop-dev merged commit dbc251e into elastic:main Jul 7, 2022
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Jul 7, 2022
@hop-dev hop-dev deleted the 133822-package-signature-verification branch July 7, 2022 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Fleet Team label for Observability Data Collection Fleet team v8.4.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants