Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/INTEGRATING_AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ Note that a Package version. Can be:
- A digest (`@sha256:...`)
- Both tag and digest (`:v1.0.0@sha256:...`), when both are specified the digest takes precedence.

The package in the OCI repository must follow a specific [structure](./oci_repository.md#package-structure).

**Accessing Package Contents:**

After installation, the package directory path is available via the reserved variable `${nr-sub:packages.<package-id>.dir}`, where `<package-id>` is the key used in the packages map.
Expand Down
122 changes: 120 additions & 2 deletions docs/oci_repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,92 @@ Package references are constructed from three components:

This data is taken from the Packages section of the [AgentType configuration](./INTEGRATING_AGENTS.md).

## Package structure

The packaged agent must comply with the [OCI image spec](https://github.com/opencontainers/image-spec). In short, that means
that a manifest or index file must exist. Besides, Agent Control expects specific values for some fields.

* `artifactType` must take one of the following values:

- `application/vnd.newrelic.agent.v1+tar`
- `application/vnd.newrelic.agent.v1+zip`

* `config` must be set to empty as per the [empty descriptor guidance](https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/manifest.md#guidance-for-an-empty-descriptor)

* `annotations` must contain
- `com.newrelic.artifact.type` with value `binary` or `agent-type`

Manifest example:

```json
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.newrelic.agent.v1+tar",
"config": {
"mediaType": "application/vnd.oci.empty.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2
},
"layers": [
{
"mediaType": "application/vnd.newrelic.agent.v1+tar",
"digest": "sha256:d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26",
"size": 12,
"annotations": {
"org.opencontainers.image.title": "agent-control",
"org.opencontainers.image.version": "2.4.1-rc1",
"com.newrelic.artifact.type": "binary"
}
}
],
"annotations": {
"org.opencontainers.image.created": "2023-08-03T00:21:51Z"
}
}
```

Index example

```json
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:82677ba32d1276debe264d14ec5f7b1c61e2a9acbc8c6a6dff779d7133ec8487",
"size": 617,
"platform": {
"architecture": "amd64",
"os": "linux"
},
"artifactType": "application/vnd.newrelic.agent.v1+tar"
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:5a16021a5101f7ae0583cddae44ea715ad2cfd618b61b8982de1b847958260da",
"size": 617,
"platform": {
"architecture": "arm64",
"os": "linux"
},
"artifactType": "application/vnd.newrelic.agent.v1+tar"
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:13e6d06647bbaf4f44d4c29bb57e1078c9919da92e2aee3443c122c24b86d3cb",
"size": 502,
"platform": {
"architecture": "amd64",
"os": "windows"
},
"artifactType": "application/vnd.newrelic.agent.v1+zip"
}
]
}
```

## Package Installation Process

When an agent needs to install or update a package, the package manager leverages the following paths:
Expand Down Expand Up @@ -55,10 +141,42 @@ Currently, there is no installation step or script execution, just extraction.
We expect to support installation scripts in the future. TODO

## Signature Verification
TODO @danielorihuela

Agent Control assumes the signature in the repository is in [Simple Signing format](https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md#payloads) and it's been created with the [external tool process](https://docs.sigstore.dev/cosign/signing/signing_with_containers/#sign-and-upload-a-generated-payload-in-another-format-from-another-tool).

> [!NOTE]
> NewRelic uses a private repository. It doesn't need extra-services like [Rekor](https://docs.sigstore.dev/logging/overview/) or [Fulcio](https://docs.sigstore.dev/certificate_authority/overview/). That's the reason why Agent Control uses the external tool process instead of `cosign sign`.

As a result of the "external tool process", the OCI repository will contain two packages. One for the agent and one for the signature. The signature package contains, among other things, the payload that was signed (in json format) and it's signature in base64. Inside the payload, we find the hash of the signed agent package. This is enough to verify the signature, as we will see in a moment.

Verification Flow:

1. AC receives an order to download a package and it's data
2. Downloads the signature package
3. Verifies the signature is correct (the base64 signature "matches" the payload)
4. Get artifact hash from payload
5. Download artifact from hash (never the tag)
6. Check downloaded artifact hash value is equal to the hash in the payload

## Key Rotation

We hid an important detail in the [Signature Verification section](./oci_repository.md#signature-verification), to make it easier to understand. Agent Control **ALWAYS** downloads the public key when verifying a signature/ This avoids the problem of using a revoked key while the cache isn't updated.

That's great, but what happens during a key rotation? It depends on the specific use case. Agent Control always tries to verify the signature with every single public key published for that package. Avoiding downtimes. There are a couple of edge cases in which we can't do nothing. The user has to wait for the signature or disable signature verification.

* The first key was published
* All keys were revoked

## Garbage collection
TODO not implemented yet

Agent Control stores in the system the two latest installed versions of each agent. Any other version of the package is removed from the system.
You can think of it like a FIFO with size 2.

Example:

1. User installs infra agent version 1.0.0 (system stores infra 1.0.0)
2. User installs infra agent version 3.0.0 (system stores infra 1.0.0 and 3.0.0)
3. User installs infra agent version 2.0.0 (system stores infra 2.0.0 and 3.0.0)

## Agent Types Management
TODO not implemented yet
Expand Down
Loading