diff --git a/.github/config/wordlist.txt b/.github/config/wordlist.txt index 0f3f415d1..46effe5a5 100644 --- a/.github/config/wordlist.txt +++ b/.github/config/wordlist.txt @@ -459,11 +459,20 @@ diataxis callouts shortcode shortcodes +href +dockerconfigjson +rhel +misattributed +whitespace +hsms +helloworld +centos wsl auditable hasmermaid -XDG +xdg subpaths -IAM +iam +ocirepository pullable descriptor's diff --git a/content/docs/concepts/components.md b/content/docs/concepts/components.md index c1dcbb3b0..bf42038a2 100644 --- a/content/docs/concepts/components.md +++ b/content/docs/concepts/components.md @@ -2,7 +2,7 @@ title : "OCM Components" description: "Learn about OCM components and their elements." icon: "๐Ÿ”ฉ" -weight: 41 +weight: 1 toc: true --- diff --git a/content/docs/concepts/coordinates.md b/content/docs/concepts/coordinates.md index 7efd7b206..d550f0ff9 100644 --- a/content/docs/concepts/coordinates.md +++ b/content/docs/concepts/coordinates.md @@ -2,7 +2,7 @@ title : "OCM Coordinates" description: "Discover how OCM components and artifacts are identified." icon: "๐Ÿงญ" -weight: 42 +weight: 2 toc: true --- diff --git a/content/docs/concepts/credential-system.md b/content/docs/concepts/credential-system.md index d44cf3c12..60ba881cc 100644 --- a/content/docs/concepts/credential-system.md +++ b/content/docs/concepts/credential-system.md @@ -2,7 +2,7 @@ title: "Credential System" description: "Why OCM manages credentials centrally and how its resolution model works." icon: "๐Ÿ”‘" -weight: 43 +weight: 6 toc: true --- @@ -77,7 +77,7 @@ flowchart TB subgraph repos ["Repositories (fallback)"] direction TB - docker["DockerConfig/v1
~/.docker/config.json"] + docker["DockerConfig/v1
$HOME/.docker/config.json"] end ``` @@ -91,3 +91,7 @@ To see resolution in action, try the [Understand Credential Resolution]({{< relr - [Tutorial: Credential Resolution]({{< relref "/docs/tutorials/credential-resolution.md" >}}) โ€” Learn how OCM picks the right credentials by experimenting with a config - [How-To: Configure Credentials for Multiple Registries]({{< relref "/docs/how-to/configure-multiple-credentials.md" >}}) โ€” Quick task-oriented setup - [Tutorial: Credentials for OCM Controllers]({{< relref "/docs/tutorials/configure-credentials-for-controllers.md" >}}) โ€” How to provide credentials in Kubernetes environments + +## Related Documentation + +- [Reference: Consumer Identities]({{< relref "/docs/reference/credential-consumer-identities.md" >}}) โ€” Complete list of identity types, attributes, and credential properties diff --git a/content/docs/concepts/ocm-controllers.md b/content/docs/concepts/ocm-controllers.md index a57219ba8..22b9f7107 100644 --- a/content/docs/concepts/ocm-controllers.md +++ b/content/docs/concepts/ocm-controllers.md @@ -2,7 +2,7 @@ title: OCM Controllers description: "Learn about the OCM controllers and their capabilities." icon: "๐Ÿ" -weight: 43 +weight: 3 toc: true --- diff --git a/content/docs/concepts/resolvers.md b/content/docs/concepts/resolvers.md index 6b29d9e2f..db80b22ae 100644 --- a/content/docs/concepts/resolvers.md +++ b/content/docs/concepts/resolvers.md @@ -2,7 +2,7 @@ title: "Resolvers" description: "Learn how OCM resolvers map component name patterns to repositories for recursive resolution." icon: "๐Ÿ”" -weight: 44 +weight: 7 toc: true --- diff --git a/content/docs/concepts/signing-and-verification-concept.md b/content/docs/concepts/signing-and-verification-concept.md new file mode 100644 index 000000000..e815a0c2f --- /dev/null +++ b/content/docs/concepts/signing-and-verification-concept.md @@ -0,0 +1,261 @@ +--- +title: "Signing and Verification" +description: "Understanding how OCM ensures component integrity and authenticity through cryptographic signatures." +weight: 5 +toc: true +--- + +OCM uses cryptographic signatures to guarantee that component versions are authentic (created by a trusted party) and have not been tampered with during storage or transfer. + +## Why Sign Components? + +Software supply chains involve multiple stages: development, build, packaging, distribution, and deployment. At each stage, components could potentially be: + +- **Modified** โ€” malicious actors could inject code or alter resources +- **Replaced** โ€” components could be swapped for compromised versions +- **Misattributed** โ€” components could falsely claim to come from a trusted source + +Signing addresses these risks by creating a cryptographic proof of: + +1. **Integrity**: The component has not changed since it was signed +2. **Authenticity**: The signature was created by someone with access to the private key +3. **Provenance**: The signer cannot deny having signed the component + +## How OCM Signing Works + +```mermaid +flowchart TB + subgraph sign ["Sign (Producer)"] + direction TB + A[Component Version] --> B[Normalize & Hash] + B --> C[Sign with Private Key] + C --> D["Signature embedded in CV"] + end + + sign --> T["Transfer Component Version"] + + T --> verify + + subgraph verify ["Verify (Consumer)"] + direction TB + E[Component Version] --> F[Extract Signature] + E --> G[Normalize & Hash] + F --> H[Verify with Public Key] + G --> H + H --> I{Valid?} + I -->|Yes| VALID["โœ“ Trusted"] + I -->|No| INVALID["โœ— Rejected"] + end +``` + +### Normalization and Digest Calculation + +OCM uses a two-layer approach to ensure consistent and reproducible digests: + +#### Component Descriptor Normalization + +Before hashing, the component descriptor is normalized into a canonical form, eliminating any ambiguities +that could cause the same logical descriptor to produce different digests. The default normalization +algorithm ([`jsonNormalisation/v4alpha1`](https://github.com/open-component-model/ocm-spec/blob/main/doc/04-extensions/04-algorithms/component-descriptor-normalization-algorithms.md#normalization-algorithms)) defines exactly how this canonical form is derived, ensuring +identical component descriptors always yield the same digest. + +#### Artifact Digest Normalization + +Each artifact's digest is calculated using a type-specific normalization algorithm: + +| Artifact Type | Algorithm | Description | +|---------------|-----------|-------------| +| OCI artifact | `ociArtifactDigest/v1` | Digest of the OCI manifest (used for container images, Helm charts, and other OCI-native content) | +| Generic blob | `genericBlobDigest/v1` | Direct hash of blob content (used for executables, blueprints, and other non-OCI content) | + +This allows OCM to use the most appropriate digest mechanism for each artifact type. +OCI artifacts use their manifest digest rather than re-hashing the blob, +improving performance and ensuring consistency with OCI registry behavior. Generic blobs are hashed directly. + +#### Recursive Component References + +When a component references other components, their digests are calculated recursively and embedded: + +```yaml +references: + - componentName: ocm.software/helper + name: helper + version: 1.0.0 + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: 01c211f5c9cfd7c40e5b84d66a2fb7d19cb0... +``` + +This creates a **complete integrity chain** โ€” verifying the root component automatically verifies all transitive dependencies. + +### What Gets Signed? + +OCM signs a **digest** of the component descriptor, which includes: + +- Component metadata (name, version, provider) +- Resource declarations with their digests +- Source references +- Component references + +The signature does **not** cover the raw resource content directly โ€” instead, it covers the **digests** of those resources as recorded in the component descriptor. Crucially, the `access` field (which describes *where* a resource is stored) is **excluded** from the signed digest by the normalization process. This is a key design principle: + +- **Location-independent integrity** โ€” a component version can be transferred to a different registry (changing all `access` references) without invalidating its signature. The digest remains stable because it depends only on *what* the artifacts contain, not *where* they are stored. +- Any change to resource content changes its digest, invalidating the signature. +- Signature verification is fast (no need to re-hash large binaries). + +This separation of content identity from storage location is what enables secure delivery across environments: a producer signs a component version once, and consumers can verify it after any number of transfers โ€” even into air-gapped environments with completely different registries. + +The following example shows a signed component descriptor. Notice that each resource has both an `access` field (storage location) and a `digest` field (content hash). Only the `digest` is included in the signature โ€” the `access` can change freely during transfers: + +{{< details "Example Signed Component Descriptor" >}} +```yaml +component: + name: github.com/acme.org/helloworld + version: 1.0.0 + provider: acme.org + resources: + - name: mylocalfile + type: blob + version: 1.0.0 + relation: local + access: # NOT included in signature + type: localBlob + localReference: sha256:70a257... + mediaType: text/plain; charset=utf-8 + digest: # Included in signature + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 70a2577d7b649574cbbba99a2f2ebdf27904a4abf80c9729923ee67ea8d2d9d8 + - name: image + type: ociImage + version: 1.0.0 + relation: external + access: # NOT included in signature + type: ociArtifact + imageReference: ghcr.io/stefanprodan/podinfo:6.9.1@sha256:262578cd... + digest: # Included in signature + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 262578cde928d5c9eba3bce079976444f624c13ed0afb741d90d5423877496cb +signatures: + - name: default + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad + signature: + algorithm: RSASSA-PSS + mediaType: application/vnd.ocm.signature.rsa.pss + value: 7feb449229c6ffe368144995432befd1505d2d29... +``` +{{< /details >}} + +### Signature Storage + +Signatures are stored as part of the component version: + +```yaml +signatures: + - name: acme-release-signing + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: abc123... + signature: + algorithm: RSASSA-PSS + mediaType: application/vnd.ocm.signature.rsa + value: +``` + +A component version can have **multiple signatures** from different parties, enabling: + +- Separation of build and release signing +- Multiple approval workflows +- Cross-organizational trust chains + +## Supported Signing Algorithms + +OCM currently only supports RSA-based signing algorithms: + +| Algorithm | Type | Characteristics | +|----------------------|------|-----------------| +| RSASSA-PSS (default) | Asymmetric | Probabilistic, stronger security guarantees, recommended for new implementations | +| RSA-PKCS#1 v1.5 | Asymmetric | Deterministic, widely supported, compatible with legacy systems | + +To override the default signing algorithm or encoding policy, see the --signer-spec flag in the [CLI reference]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}). +The signer spec file configures only the algorithm and encoding policy โ€” credentials are always resolved separately via the [`.ocmconfig`]({{< relref "configure-multiple-credentials.md" >}}) file. + +For key management, OCM uses PEM-encoded key files configured in the `.ocmconfig`: + +- **Private keys**: Used by producers to sign component versions +- **Public keys**: Distributed to consumers for verification + +See [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}) for creating RSA key pairs. + +{{< callout context="tip" title="Upcoming Sigstore Support" icon="outline/bulb" >}} +We are planning to add support for [Sigstore](https://www.sigstore.dev/) and Cosign as an additional signing mechanism. +This will enable keyless signing workflows and improved supply chain security. Stay tuned for updates. +{{< /callout >}} + +### Signature Encoding Policies + +The `signatureEncodingPolicy` in the [signer spec]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}) controls how the **signature output** is serialized and stored. It does **not** affect the format of key input files, which are always PEM-encoded. + +| Policy | Signature Format | Media Type | Certificate Chain | Verification Requires | +|--------|-----------------|------------|-------------------|-----------------------| +| **Plain** (default) | Hex-encoded raw bytes | `application/vnd.ocm.signature.rsa.pss` | Not embedded | Externally supplied public key | +| **PEM** (experimental) | PEM `SIGNATURE` block + `CERTIFICATE` blocks | `application/x-pem-file` | Embedded in signature | Valid certificate chain in signature | + +#### Plain Encoding (Default) + +The raw RSA signature bytes are hex-encoded and stored directly. This is the most compact representation. Verification always requires the public key to be provided separately via `.ocmconfig` credentials. + +Example signature in a component descriptor: + +```yaml +signature: + algorithm: RSASSA-PSS + mediaType: application/vnd.ocm.signature.rsa.pss + value: d1ea6e0cd850c8dbd0d20cd39b9c7954... +``` + +#### PEM Encoding (Experimental) + +The signature is wrapped in a PEM block of type `SIGNATURE`, optionally followed by the signer's X.509 certificate chain. This makes the signature **self-contained**: verifiers can extract and validate the public key from the embedded chain without needing a separately distributed key. + +Example of a PEM-encoded signature value: + +```text +-----BEGIN SIGNATURE----- +Signature Algorithm: RSASSA-PSS + +-----END SIGNATURE----- +-----BEGIN CERTIFICATE----- + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- + +-----END CERTIFICATE----- +``` + +{{< callout context="caution" title="PEM encoding is experimental" icon="outline/alert-triangle" >}} +This encoding policy may change or be deprecated in future versions. For production use, prefer the default Plain encoding. +{{< /callout >}} + +{{< callout context="note" title="Key files vs. signature encoding" icon="outline/info-circle" >}} +A common source of confusion: "PEM" in `signatureEncodingPolicy` refers to the **signature output** format, not the key input format. Input keys are **always** PEM-encoded files (e.g. `-----BEGIN RSA PRIVATE KEY-----`), regardless of which encoding policy is selected. + +When using PEM encoding for signing, the credential referenced by `public_key_pem` / `public_key_pem_file` must contain **X.509 certificates** (not bare public keys), because the certificate chain is embedded into the signature for self-contained verification. +{{< /callout >}} + +## Next Steps + +- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Step-by-step creating RSA key pairs. +- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification +- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Step-by-step signing instructions +- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Step-by-step verification instructions + +## Related Documentation + +- [Concept: Component Versions]({{< relref "components.md" >}}) - Understanding component structure diff --git a/content/docs/concepts/transfer-concept.md b/content/docs/concepts/transfer-concept.md index 22397ad27..46a3e35b9 100644 --- a/content/docs/concepts/transfer-concept.md +++ b/content/docs/concepts/transfer-concept.md @@ -1,7 +1,7 @@ --- title: "Transfer and Transport" description: "Understand how OCM moves component versions between repositories while preserving identity, integrity, and signatures." -weight: 44 +weight: 4 toc: true hasMermaid: true --- diff --git a/content/docs/how-to/air-gap-transfer.md b/content/docs/how-to/air-gap-transfer.md index 72e1797b9..7e36f7f60 100644 --- a/content/docs/how-to/air-gap-transfer.md +++ b/content/docs/how-to/air-gap-transfer.md @@ -1,7 +1,7 @@ --- -title: "Transfer Components Across an Air Gap" +title: "Transfer Components across an Air Gap" description: "Transfer a signed OCM component version into an air-gapped registry via a CTF archive." -weight: 10 +weight: 1 toc: true --- @@ -9,13 +9,11 @@ toc: true Transfer a signed component version from a source registry into an air-gapped target registry using a CTF archive as the transport medium. An air-gapped environment is a network that is physically isolated from untrusted networks such as the public internet. -{{< callout context="note" title="You will end up with" >}} +## You'll end up with - A verified, signed component version available in your air-gapped registry - All resource artifacts (container images, Helm charts) copied into the target registry -{{< /callout >}} - **Estimated time:** ~10 minutes ## Prerequisites diff --git a/content/docs/how-to/configure-credentials-ocm-controllers.md b/content/docs/how-to/configure-credentials-ocm-controllers.md new file mode 100644 index 000000000..2b38d88b4 --- /dev/null +++ b/content/docs/how-to/configure-credentials-ocm-controllers.md @@ -0,0 +1,318 @@ +--- +title: "Configure Credentials for OCM Controllers" +description: "Configure authentication for OCM Controllers to access private OCM repositories." +weight: 2 +toc: true +--- + +## Goal + +Configure credentials to allow OCM Controllers to access OCM components stored in private OCI registries. + +## You will end up with + +- A Kubernetes secret containing registry credentials +- OCM Controller resources configured to use these credentials +- Verified access to private OCM repositories + +**Estimated time:** ~5 minutes + +## Prerequisites + +- [Controller environment]({{< relref "setup-controller-environment.md" >}}) set up (OCM Controllers, kro and Flux in a Kubernetes cluster) +- [OCM CLI]({{< relref "ocm-cli-installation.md" >}}) installed +- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) installed +- Credentials for your private OCI registry (username and password, Docker config file, or OCM CLI config file) +- The registry URL where your OCM components are stored + +{{< callout context="caution" title="Security Warning" icon="outline/alert-triangle" >}} +Kubernetes secrets are only base64-encoded, not encrypted. +Ensure proper RBAC policies to restrict access to secrets containing credentials. +{{< /callout >}} + +## Configure and propagate credentials for OCM resources + +{{< steps >}} +{{< step >}} + +### Create a Kubernetes secret with credentials + +Choose one of two methods to create the secret: + +{{< tabs "credential-methods" >}} +{{< tab "OCM Config (.ocmconfig)" >}} + +Use this method if you already use the OCM CLI and have an `.ocmconfig` file configured with credentials. +[Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) helps with creating this file. + +#### Create the secret from your existing `.ocmconfig` file + +Point the command to your existing `.ocmconfig` file. The secret key must be named `.ocmconfig` (with the dot). +The `--from-file` command automatically uses the filename as the key. + +```bash +kubectl create secret generic ocm-secret --from-file= +``` + +
+You should see this output + +```text +secret/ocm-secret created +``` +
+ +{{< /tab >}} + +{{< tab "Docker Config (dockerconfigjson)" >}} + +#### Option A: From existing Docker config file + +```bash +kubectl create secret docker-registry ocm-secret --from-file= +``` + +
+You should see this output + +```text +secret/ocm-secret created +``` +
+ +#### Option B: Create from command line + +```bash +kubectl create secret docker-registry ocm-secret \ + --docker-username= \ + --docker-password= \ + --docker-server= +``` + +
+You should see this output + +```text +secret/ocm-secret created +``` +
+ +{{< /tab >}} +{{< /tabs >}} +{{< /step >}} + +{{< step >}} + +### Reference the secret in OCM Controller resources + +Add the `spec.ocmConfig` field to your OCM Controller resources to use the credentials. +Create a `repository.yaml` with a `Repository` resource. +Replace `` with your actual namespace in the registry URL. + +```yaml +apiVersion: delivery.ocm.software/v1alpha1 +kind: Repository +metadata: + name: my-repository +spec: + repositorySpec: + baseUrl: ghcr.io/ + type: OCIRegistry + interval: 1m + ocmConfig: + - kind: Secret + name: ocm-secret +``` + +Apply the resource: + +```bash +kubectl apply -f repository.yaml +``` + +
+You should see this output + +```text +repository.delivery.ocm.software/my-repository created +``` +
+
+ +Verify the resource is ready and can access your registry (due to the complex status field of OCM resources, to show the status, we need to use `custom-columns`) + +```shell +kubectl get repository my-repository -o 'custom-columns=NAME:.metadata.name,READY:.status.conditions[0].message,AGE:.metadata.creationTimestamp' +``` + +
+You should see this output + +```text +NAME READY AGE +my-repository Successfully reconciled OCM repository 2026-02-25T15:45:49Z +``` +
+ +{{< /step >}} + +{{< step >}} + +### Propagate credentials to dependent resources (optional) + +OCM Controller resources can inherit credentials from referenced resources, reducing duplication. +Create a `component.yaml` with a component referencing the OCM config from the `Repository` resource you just created. +Specify the component reference to an existing component in your registry. + +```yaml +apiVersion: delivery.ocm.software/v1alpha1 +kind: Component +metadata: + name: my-component +spec: + component: /my-component + repositoryRef: + name: my-repository + semver: 1.0.0 + interval: 1m + ocmConfig: + - kind: Repository + apiVersion: delivery.ocm.software/v1alpha1 + name: my-repository +``` + +The `Component` resource inherits credentials from the `Repository` resource named `my-repository`. + +Apply the resource: + +```shell +kubectl apply -f component.yaml +``` + +
+You should see this output + +```text +component.delivery.ocm.software/my-component created +``` +
+
+ +Verify the resource is ready and can access your registry (due to the complex status field of OCM resources, to show the status, we need to use `custom-columns`) + +```shell +kubectl get component my-component -o 'custom-columns=NAME:.metadata.name,READY:.status.conditions[0].message,AGE:.metadata.creationTimestamp' +``` + +
+You should see this output + +```text +NAME READY AGE +my-component Applied version 1.0.0 2026-02-25T15:49:58Z +``` +
+ +### Credential propagation + +- Credentials are propagated by default when referencing other OCM Controller resources +- You must still specify the `ocmConfig` field on each resource that needs credentials +- Credentials are not automatically inherited across all resources in the cluster + +{{< /step >}} + +{{< /steps >}} + +## Advanced: Prevent credential propagation + +To prevent a resource from propagating its credentials to dependent resources, set the `policy` to `DoNotPropagate`: + +```yaml +apiVersion: delivery.ocm.software/v1alpha1 +kind: Component +metadata: + name: my-component +spec: + component: /my-component + repositoryRef: + name: my-repository + semver: 1.0.0 + interval: 1m + ocmConfig: + - kind: Repository + apiVersion: delivery.ocm.software/v1alpha1 + name: my-repository + policy: DoNotPropagate +``` + +## Troubleshooting + +### Symptom: "failed to list versions: response status code 401: unauthorized" + +**Cause:** The credentials are incorrect, missing, or the secret is not referenced in the resource. + +**Fix:** + +1. Verify the secret exists: + ```bash + kubectl get secret ocm-secret + ``` + +2. Check the secret contains the correct credentials: + ```bash + kubectl get secret ocm-secret -o yaml + ``` + +3. Ensure the `ocmConfig` field references the correct secret name in your resource. + +### Symptom: "failed to read OCM config: key .ocmconfig not found in secret" + +**Cause:** When using the OCM config method, the secret key must be named `.ocmconfig`. + +**Fix:** + +Recreate the secret with the correct key name, e.g., referencing an `.ocmconfig` file in the same folder: + +```bash +kubectl delete secret ocm-secret +kubectl create secret generic ocm-secret --from-file=./.ocmconfig +``` + +The filename in `--from-file` must be `.ocmconfig` (with the dot). + +### Symptom: "Component shows `Not Ready` with credential errors" + +**Cause:** The `ocmConfig` is not specified or references a non-existent resource. + +**Fix:** + +Add the `ocmConfig` field to your Component resource: + +```yaml +spec: + # ...existing configuration... + ocmConfig: + - kind: Repository + apiVersion: delivery.ocm.software/v1alpha1 + name: my-repository +``` + +Or reference the secret directly: + +```yaml +spec: + # ...existing configuration... + ocmConfig: + - kind: Secret + name: ocm-secret +``` + +## Next Steps + +- [Tutorial: Deploy a Helm Chart]({{< relref "deploy-helm-chart.md" >}}) - Use the OCM Controllers to deploy applications from component versions +- [How-To: Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) - Configure credentials for multiple registries in an `.ocmconfig` file + +## Related documentation + +- [Concept: OCM Controllers]({{< relref "ocm-controllers.md" >}}) +- [Concept: Credential System]({{< relref "credential-system.md" >}}) diff --git a/content/docs/how-to/configure-multiple-credentials.md b/content/docs/how-to/configure-multiple-credentials.md index 70a6900fc..07db6ef6e 100644 --- a/content/docs/how-to/configure-multiple-credentials.md +++ b/content/docs/how-to/configure-multiple-credentials.md @@ -2,7 +2,7 @@ title: "Configure Credentials for Multiple Registries" description: "Set up OCM credentials to authenticate against multiple OCI registries with explicit entries and Docker config fallback." icon: "๐Ÿ”‘" -weight: 45 +weight: 3 toc: true --- @@ -10,17 +10,15 @@ toc: true Configure OCM to authenticate against multiple OCI registries โ€” pinning explicit credentials for specific registries while using Docker config as a catch-all fallback. -{{< callout context="note" >}} -**You will end up with** +## You'll end up with - An OCM config file that resolves credentials automatically for every `ocm` command - Explicit control over specific registry paths with Docker config covering the rest -{{< /callout >}} ## Prerequisites - [OCM CLI]({{< relref "/docs/getting-started/ocm-cli-installation.md" >}}) installed -- Docker CLI installed and `docker login` run for any registries you want as fallback (creates `~/.docker/config.json`) +- Docker CLI installed and `docker login` run for any registries you want as fallback (creates `$HOME/.docker/config.json`) ## Steps @@ -29,7 +27,7 @@ Configure OCM to authenticate against multiple OCI registries โ€” pinning explic {{< step >}} **Identity by hostname only** -Create `~/.ocmconfig` with an identity that matches **any path** on a hostname: +Create `$HOME/.ocmconfig` with an identity that matches **any path** on a hostname: ```yaml type: generic.config.ocm.software/v1 @@ -122,10 +120,10 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" # Fallback for unmatched registries + dockerConfigFile: "$HOME/.docker/config.json" # Fallback for unmatched registries ``` -**Identity:** Derived from the `auths` section in Docker config file (`~/.docker/config.json`) +**Identity:** Derived from the `auths` section in Docker config file (`$HOME/.docker/config.json`) **Matches:** Any registry with credentials in Docker config that wasn't matched by a consumer **Differs from steps 1-3:** This is a **repository** (not a consumer). OCM checks all consumers first, then falls back to repositories. Use this for registries you authenticate with `docker login`. {{< /step >}} @@ -174,7 +172,7 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" + dockerConfigFile: "$HOME/.docker/config.json" ``` **Resolution order** (see [Credential Resolution Tutorial]({{< relref "/docs/tutorials/credential-resolution.md" >}}) for details): diff --git a/content/docs/how-to/configure-signing-credentials.md b/content/docs/how-to/configure-signing-credentials.md new file mode 100644 index 000000000..e57e30121 --- /dev/null +++ b/content/docs/how-to/configure-signing-credentials.md @@ -0,0 +1,192 @@ +--- +title: "Configure Credentials for Signing" +description: "Configure OCM signing and verification keys using .ocmconfig or signer specification files." +icon: "๐Ÿ”‘" +weight: 4 +toc: true +--- + +Set up credential configuration so OCM can find your signing keys when signing or verifying component versions. + +## You'll end up with + +- A configured `.ocmconfig` file that OCM uses to locate your signing keys +- Ability to sign and verify component versions without specifying key paths manually + +**Estimated time:** ~3 minutes + +## Prerequisites + +- [OCM CLI installed]({{< relref "docs/getting-started/ocm-cli-installation.md" >}}) +- [RSA key pair generated]({{< relref "generate-signing-keys.md" >}}) +- A component version to test your configuration (we'll use `github.com/acme.org/helloworld:1.0.0` from the [getting started guide]({{< relref "create-component-version.md" >}})) in this guide, but you can use any component version you have. + +## Steps + +{{< steps >}} +{{< step >}} + +## Create your .ocmconfig file (optional) + +Create `$HOME/.ocmconfig` if it doesn't exist: + +```bash +touch $HOME/.ocmconfig +``` + +{{< /step >}} + +{{< step >}} + +## Add the signing credential configuration to your .ocmconfig + +Copy the following YAML into your `.ocmconfig` file. + +We use the key pair you created in the [How-To: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}). +If you already have a key pair that is located in a different location, simply update the file paths accordingly. + +All three identity attributes (`type`, `algorithm`, `signature`) are required for credential matching. +See the [Consumer Identities Reference]({{< relref "docs/reference/credential-consumer-identities.md" >}}) for details. + +```yaml +type: generic.config.ocm.software/v1 +configurations: + - type: credentials.config.ocm.software + consumers: + - identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: default + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /tmp/keys/private-key.pem + public_key_pem_file: /tmp/keys/public-key.pem +``` + +**Key paths:** + +- `private_key_pem_file` - Required for **signing** operations +- `public_key_pem_file` - Required for **verification** operations + +{{< /step >}} + +{{< step >}} + +## Test the configuration + +```bash +ocm sign cv --dry-run /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 +``` + +If configured correctly, the dry run completes without "no private key found" errors. + +{{< details "Expected output" >}} + +```text +time=2026-03-12T17:05:46.428+01:00 level=INFO msg="no signer spec file provided, using default" algorithm=RSASSA-PSS encodingPolicy=Plain +digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad +name: default +signature: + algorithm: RSASSA-PSS + mediaType: application/vnd.ocm.signature.rsa.pss + value: 0cb48e5867575151fca94e995fc03c6df734163aed8fbee46231c9b36e59956d51df60263d8cd58e3de7662b2fbc3c4f800107d96b4fc27e7a16807388f7e5a73d2269290c0f367d0eb92d930b485054911c10e22ed1fe6c5bfab441f1af28d8deec4df8d67ca5a54fa4495510e2fff809fe8162f875d6b91a6bc1d29e7466f113a9d9d23f16956588a5792e4c7553a8ceb6f8c630aa6090aceb83e763734c33902d4697beadc65a6bc4761e6221ec49a6882bd46c87a14c5a5c24c70bf95880d0a43b176a5bf6200837ce344abff360e13f07db35290b3e1e3639a0fdc87252542965ea95231444807564c718734ccf10a5dbbb58a8b11f7df418002e6bebfa + +time=2026-03-12T17:05:46.437+01:00 level=INFO msg="dry run: signature not persisted" +``` + +{{< /details >}} +{{< /step >}} + +{{< /steps >}} + +### Configure multiple signing identities + +For different environments (e.g., dev and prod) you can create different key pairs and +add multiple consumer blocks to your `.ocmconfig` with different `signature` names: + +```yaml +type: generic.config.ocm.software/v1 +configurations: + - type: credentials.config.ocm.software + consumers: + - identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: dev + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /tmp/keys/dev/private-key.pem + public_key_pem_file: /tmp/keys/dev/public-key.pem + - identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: prod + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /tmp/keys/prod/private-key.pem + public_key_pem_file: /tmp/keys/prod/public-key.pem +``` + +Specify the signature name when signing: + +```bash +ocm sign cv --signature dev /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 +ocm sign cv --signature prod /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 +``` + +## Identity Attributes Reference + +The consumer identity for RSA signing/verification supports these attributes: + +| Attribute | Required | Description | +|-------------|----------|-----------------------------------------------------| +| `type` | Yes | Must be `RSA/v1alpha1` | +| `algorithm` | Yes | `RSASSA-PSS` (default) or `RSASSA-PKCS1-V1_5`. Required for credential matching โ€” the lookup always includes this field. | +| `signature` | Yes | Logical name for this key configuration (default: `default`). Must match the `--signature` CLI flag. | + +## Troubleshooting + +### Symptom: "no private key found" + +**Cause:** OCM cannot find a matching consumer entry in `.ocmconfig`. + +**Fix:** Ensure: + +- The file path `private_key_pem_file` is correct and the file exists +- The `algorithm` attribute is present in the identity (e.g. `algorithm: RSASSA-PSS`). See [Consumer Identities Reference]({{< relref "docs/reference/credential-consumer-identities.md" >}}). +- The `signature` name matches what you're using (or is `default` if not specified) +- The file is valid YAML with correct indentation + +### Symptom: "permission denied" reading key file + +**Cause:** Key file has restrictive permissions. + +**Fix:** Ensure your user can read the key file: + +```bash +chmod 600 /tmp/keys/private-key.pem +ls -la /tmp/keys/private-key.pem +``` + +## CLI Reference + +| Command | Description | +|--------------------------------------------------------------------------|-------------| +| [`ocm sign cv --dry-run`]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}) | Test signing configuration | +| [`ocm verify cv`]({{< relref "/docs/reference/ocm-cli/ocm_verify_component-version.md" >}}) | Test verification configuration | + +## Next Steps + +- [How-to: Sign Component Versions]({{< relref "sign-component-version.md" >}}) - Sign components with your configured credentials +- [How-to: Verify Component Versions]({{< relref "verify-component-version.md" >}}) - Verify signatures using public keys + +## Related Documentation + +- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Create the key pair needed for this configuration +- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) - Understand how OCM signing works diff --git a/content/docs/how-to/download-resources-from-component-versions.md b/content/docs/how-to/download-resources-from-component-versions.md index 866571cba..10e61fb67 100644 --- a/content/docs/how-to/download-resources-from-component-versions.md +++ b/content/docs/how-to/download-resources-from-component-versions.md @@ -2,12 +2,14 @@ title: "Download Resources from Component Versions" description: "Extract resources from OCM component versions to your local filesystem." icon: "๐Ÿ“ฅ" -weight: 10 +weight: 5 toc: true --- -This guide shows you how to download resources from a component version using the OCM CLI. -You'll learn how to fetch specific resources, optionally transform them to their native format, +## Goal + +Download resources from a component version using the OCM CLI. +Learn how to fetch specific resources, optionally transform them to their native format, and save them to your local filesystem. ## You'll end up with @@ -15,9 +17,7 @@ and save them to your local filesystem. - A resource file downloaded from a component version - Optionally a resource transformed to its native format (e.g., Helm chart `.tgz`) -## Estimated time - -~5 minutes +**Estimated time:** ~5 minutes ## How it works diff --git a/content/docs/how-to/generate-signing-keys.md b/content/docs/how-to/generate-signing-keys.md new file mode 100644 index 000000000..a5b270d16 --- /dev/null +++ b/content/docs/how-to/generate-signing-keys.md @@ -0,0 +1,119 @@ +--- +title: "Generate Signing Keys" +description: "Create an RSA key pair for signing and verifying OCM component versions." +weight: 10 +toc: true +--- + +## Goal + +Generate an RSA key pair that can be used to sign and verify OCM component versions. + +## You'll end up with + +- A private key file for signing component versions +- A public key file for sharing with consumers who need to verify signatures + +**Estimated time:** ~2 minutes + +## Prerequisites + +- [OpenSSL](https://openssl-library.org) installed on your system (typically pre-installed on Linux/macOS) + +## Generate an RSA key pair + +To be able to use the keys across all How-to guides, we'll create them in your home directory (`$HOME`). + +{{< steps >}} + +{{< step >}} + +### Generate the private key + +Create a folder `/tmp/keys` and create a 4096-bit RSA private key in it: + +```bash +mkdir /tmp/keys && cd /tmp/keys +openssl genpkey -algorithm RSA -out private-key.pem -pkeyopt rsa_keygen_bits:4096 +``` + +Verify the private key file was created: + +```bash +ls -la /tmp/keys +``` + +> โš ๏ธ **Keep your private key secure!** โš ๏ธ +> Anyone with access to this file can sign components as you. +> Store it in a secure location and never commit it to version control. + +{{< /step >}} + +{{< step >}} + +### Extract the public key + +Derive the public key from your private key: + +```bash +openssl rsa -in private-key.pem -pubout -out public-key.pem +``` + +This creates `public-key.pem` which you can safely share with others. + +{{< /step >}} + +{{< step >}} + +### Verify the keys were created + +```bash +ls -la *.pem +``` + +You should see both files: + +```text +-rw------- 1 user group 3272 Jan 15 10:00 private-key.pem +-rw-r--r-- 1 user group 800 Jan 15 10:00 public-key.pem +``` + +{{< /step >}} + +{{< /steps >}} + +## Key management tips + +| Key | Who has it | Purpose | +|-----|------------|---------| +| **Private key** | Only you (the signer) | Sign component versions | +| **Public key** | Anyone who needs to verify | Verify signatures | + +- Use different key pairs for different environments (dev, staging, production) +- Document which public key corresponds to which signing identity +- Consider key rotation policies for long-lived projects + +## Troubleshooting + +### Symptom: "command not found: openssl" + +**Fix:** Install OpenSSL: + +- macOS: `brew install openssl` +- Ubuntu/Debian: `sudo apt-get install openssl` +- RHEL/CentOS: `sudo dnf install openssl` + +### Symptom: Permission denied when creating files + +**Fix:** Ensure you have write permissions in the current directory, or specify a full path where you have access. + +## Next steps + +- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification +- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Use your private key to sign components +- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Share your public key and verify signatures + +## Related documentation + +- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) - Understand how OCM signing and verification works +- [Tutorial: Sign Your First Component]({{< relref "signing-and-verification.md" >}}) - A hands-on tutorial for signing components end-to-end diff --git a/content/docs/how-to/legacy-credential-compatibility.md b/content/docs/how-to/legacy-credential-compatibility.md index 0e263d3fa..72c38c25b 100644 --- a/content/docs/how-to/legacy-credential-compatibility.md +++ b/content/docs/how-to/legacy-credential-compatibility.md @@ -2,7 +2,7 @@ title: "Migrate Legacy Credentials" description: "Update your legacy OCM credential configuration to work with the new OCM." icon: "๐Ÿ”‘" -weight: 46 +weight: 6 toc: true --- @@ -21,7 +21,7 @@ Migrate an existing legacy OCM `.ocmconfig` file so it works with the new OCM. ## Steps -Suppose you have the following legacy config in `~/.ocmconfig`: +Suppose you have the following legacy config in `$HOME/.ocmconfig`: ```yaml type: generic.config.ocm.software/v1 @@ -40,7 +40,7 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" + dockerConfigFile: "$HOME/.docker/config.json" ``` The following steps walk you through each change needed to make this config work with the new OCM. @@ -100,7 +100,7 @@ The following parts of your legacy config work unchanged in the new OCM: - `Credentials/v1` type and `properties` field - `DockerConfig/v1` repository entries - `dockerConfigFile` and `dockerConfig` fields -- Config file locations (`~/.ocmconfig`, `$OCM_CONFIG`) +- Config file locations (`$HOME/.ocmconfig`, `$OCM_CONFIG`) Your migrated config now looks like this: @@ -121,7 +121,7 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" + dockerConfigFile: "$HOME/.docker/config.json" ``` {{< /step >}} diff --git a/content/docs/how-to/migrate-from-deprecated-resolvers.md b/content/docs/how-to/migrate-from-deprecated-resolvers.md index e5ec5b3ba..ba4d1d47c 100644 --- a/content/docs/how-to/migrate-from-deprecated-resolvers.md +++ b/content/docs/how-to/migrate-from-deprecated-resolvers.md @@ -29,7 +29,7 @@ against component names, which is simpler and more efficient. ## Steps -Suppose you have the following legacy resolver config in `~/.ocmconfig`: +Suppose you have the following legacy resolver config in `$HOME/.ocmconfig`: ```yaml type: generic.config.ocm.software/v1 diff --git a/content/docs/how-to/resolve-components-from-multiple-repositories.md b/content/docs/how-to/resolve-components-from-multiple-repositories.md index f85d8f8a0..068142652 100644 --- a/content/docs/how-to/resolve-components-from-multiple-repositories.md +++ b/content/docs/how-to/resolve-components-from-multiple-repositories.md @@ -1,7 +1,7 @@ --- -title: "Resolving Components Across Multiple Registries" +title: "Resolving Components across Multiple Registries" description: "Configure resolvers to recursively resolve component references distributed across multiple OCI registries." -weight: 10 +weight: 7 toc: true --- @@ -36,7 +36,7 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" + dockerConfigFile: "$HOME/.docker/config.json" - type: resolvers.config.ocm.software/v1alpha1 resolvers: - repository: diff --git a/content/docs/how-to/sign-component-version.md b/content/docs/how-to/sign-component-version.md new file mode 100644 index 000000000..27471852e --- /dev/null +++ b/content/docs/how-to/sign-component-version.md @@ -0,0 +1,143 @@ +--- +title: "Sign Component Versions" +description: "Cryptographically sign a component version to establish authenticity and enable verification." +icon: "๐Ÿ”" +weight: 8 +toc: true +--- + +## Goal + +Sign a component version to certify its authenticity and enable downstream verification. + +## You'll end up with + +- A component version with a cryptographic signature attached + +**Estimated time:** ~3 minutes + +## Prerequisites + +- [OCM CLI installed]({{< relref "ocm-cli-installation.md" >}}) +- [Signing credentials configured]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) +- A component version in a CTF archive or OCI registry (we'll use `github.com/acme.org/helloworld:1.0.0` from the [getting started guide]({{< relref "create-component-version.md" >}})) in this guide, but you can use any component version you have. + +## Steps + +{{< steps >}} + +{{< step >}} + +### Sign the component version + +Run the sign command against your component: + +{{< tabs >}} +{{< tab "Local CTF Archive" >}} + +```bash +ocm sign cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 +``` +{{< /tab >}} +{{< tab "Remote OCI Registry" >}} + +```bash +ocm sign cv ghcr.io///github.com/acme.org/helloworld:1.0.0 +``` +{{< /tab >}} +{{< /tabs >}} + +{{< details "Expected output from signing" >}} + +```text +time=2026-03-12T21:45:16.517+01:00 level=INFO msg="no signer spec file provided, using default" algorithm=RSASSA-PSS encodingPolicy=Plain +digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad +name: default +signature: + algorithm: RSASSA-PSS + mediaType: application/vnd.ocm.signature.rsa.pss + value: d1ea6e0cd850c8dbd0d20cd39b9c79547005e56a3df08974543e8a8b2f4ce17784d473a9397928432dfac1cefbf9c74087d3f0432275d692025b65d4feca6acabd6ed2cb495f77026a699f3e5009515d6b845cd698c210718a0788dbb08c4a345dae6c64a39c652edc1ede71ff2c7b0d4315351abede51c136d680b478a0ae9ae1a88916b289c59a8d263a8ad2223386f76104356b060caf8643405646bf106811cddbf7df1cdc7ba2a8323a1803d76238a9cd5bf700752ce4d9666acdb361f55d4fbda99ff794cf6d743f56a3d974441e708a4455686d5aefe1d22bc068c2e91acd18492af8624c0e6ef62afac0e176abd1db581ec12871281ad26f996c64d8ec164e9b9100f19d37491d2c13464f40c51ca8e0521e17578df4d8a89deb141c0fe7f4833ddee19ebffe292a065cf1a428860280905826469f1d44fed54c8654b94b32d19a798d6e40518fb53988f23a6266c968706d5276c1dc2664085337d169d1375413b75b86fc379bda3c1abab27c646502850eb27d88bdad4400d08ec1ca8dfe98806dff2bfd24cc1f50bd74fd632a881b99f72cf5ef7b20df910da663410b7021afffd5bd983805d461d27585225c933d52a2bea3a438c65a494b03d17fc9421fc02dff7d5bc36782fa5e9d1314bd5bfc291fed341fad084e3a5bb5da895fdaa00d6947c66e8cf0ed671ec44591c5fb84898e3263190c13d511380ad5 + +time=2026-03-12T21:45:16.532+01:00 level=INFO msg="signed successfully" name=default digest=91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad hashAlgorithm=SHA-256 normalisationAlgorithm=jsonNormalisation/v4alpha1 +``` +{{< /details >}} +{{< /step >}} + +{{< step >}} + +### Use a named signature (optional) + +If you have multiple signing configurations in your `.ocmconfig`, +use `--signature` flag to specify which one to use. +Without the flag, OCM uses the configuration named `default`. In this example, we'll use a configuration named `prod`: + +```bash +ocm sign cv --signature prod ghcr.io///github.com/acme.org/helloworld:1.0.0 +``` + +{{< /step >}} + +{{< step >}} + +### Verify the signature was added + +Check that the signature is present in the component descriptor: + +```bash +ocm get cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml +``` + +Look for the `signatures` section in the output: + +```yaml +signatures: + - name: default + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: jsonNormalisation/v4alpha1 + value: 91dd197... + signature: + algorithm: RSASSA-PSS + value: d1ea6e0... +``` + +{{< /step >}} +{{< /steps >}} + +## Troubleshooting + +### Symptom: "no private key found" + +**Cause:** OCM cannot find a matching signing configuration in `.ocmconfig`. + +**Fix:** Ensure your `.ocmconfig` has a consumer entry with matching `signature` name: + +- Without `--signature` flag: must have `signature: default` +- With `--signature prod`: must have `signature: prod` + +See [Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) guide. + +### Symptom: "signature already exists" + +**Cause:** The component version already has a signature with this name. + +**Fix:** Use a different signature name with `--signature newname`, or remove the existing signature first. + +### Symptom: Permission denied on registry + +**Cause:** Missing write access to the OCI registry. + +**Fix:** Ensure you're `.ocmconfig` file is configure with credentials for the registry. +See [How-To: Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) for details. + +## Next Steps + +- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) โ€” Verify signatures using public keys + +## Related Documentation + +- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) โ€” Understand how OCM signing works +- [Tutorial: Sign and Verify Components]({{< relref "signing-and-verification.md" >}}) โ€” End-to-end signing workflow diff --git a/content/docs/how-to/verify-component-version.md b/content/docs/how-to/verify-component-version.md new file mode 100644 index 000000000..b8f763d40 --- /dev/null +++ b/content/docs/how-to/verify-component-version.md @@ -0,0 +1,138 @@ +--- +title: "Verify Component Versions" +description: "Validate component version signatures to ensure authenticity and integrity." +icon: "๐Ÿ”" +weight: 9 +toc: true +--- + +## You'll end up with + +- Confidence that a component version is authentic and hasn't been tampered with + +**Estimated time:** ~3 minutes + +## Prerequisites + +- [OCM CLI installed]({{< relref "ocm-cli-installation.md" >}}) +- [Verification credentials configured]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) with the public key +- A signed component version to verify + +## Steps + +{{< steps >}} + +{{< step >}} + +### Verify the component version + +Run the verify command against your signed component: + +```bash +ocm verify cv //: +``` + +**Local CTF Archive:** + +```bash +ocm verify cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 +``` + +**Remote OCI Registry:** + +```bash +ocm verify cv ghcr.io/myorg/components//github.com/acme.org/helloworld:1.0.0 +``` + +
+Expected output + +```text +time=2025-11-19T15:58:22.431+01:00 level=INFO msg="verifying signature" name=default +time=2025-11-19T15:58:22.435+01:00 level=INFO msg="signature verification completed" name=default duration=4.287541ms +time=2025-11-19T15:58:22.435+01:00 level=INFO msg="SIGNATURE VERIFICATION SUCCESSFUL" +``` + +
+ +The command exits with status code `0` on success. + +{{< /step >}} + +{{< step >}} + +### Verify a specific signature (optional) + +If the component has multiple signatures, specify which one to verify: + +```bash +ocm verify cv --signature prod ghcr.io/myorg/components//github.com/acme.org/helloworld:1.0.0 +``` + +> ๐Ÿ‘‰ Without the `--signature` flag, OCM uses the configuration named `default`. + +{{< /step >}} + +{{< step >}} + +### List available signatures (optional) + +View all signatures in a component version: + +```bash +ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 10 signatures: +``` + +{{< /step >}} + +{{< /steps >}} + +## Troubleshooting + +### Symptom: "signature verification failed" + +**Cause:** Public key doesn't match the signing private key, or the component was modified after signing. + +**Fix:** Ensure you're using the correct public key that corresponds to the private key used for signing: + +```bash +# Check which signature names exist +ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 3 "signatures:" + +# Verify with the correct signature name +ocm verify cv --signature ./transport-archive//github.com/acme.org/helloworld:1.0.0 +``` + +### Symptom: "no public key found" + +**Cause:** OCM cannot find a matching verification configuration in `.ocmconfig`. + +**Fix:** Ensure your `.ocmconfig` has a consumer entry with the matching `signature` name and `public_key_pem_file` path. + +See [Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}). + +### Symptom: "invalid key format" + +**Cause:** The public key file is not in PEM format. + +**Fix:** Verify the key starts with `-----BEGIN PUBLIC KEY-----`: + +```bash +head -n 1 $HOME/.ocm/keys/public.pem +``` + +## CLI Reference + +| Command | Description | +|---------|-------------| +| [`ocm verify componentversions`]({{< relref "docs/reference/ocm-cli/ocm_verify_component-version.md" >}}) | Verify a component version signature | +| [`ocm get componentversions`]({{< relref "docs/reference/ocm-cli/ocm_get_component-version.md" >}}) | View component with signatures | + +## Next Steps + +- [How-to: Sign Component Versions]({{< relref "sign-component-version.md" >}}) - Add signatures to your components +- [Tutorial: Signing and Verification]({{< relref "signing-and-verification.md" >}}) - Learn how to sign and verify components in a complete tutorial + +## Related Documentation + +- [Concept: Signing and Verification]({{< relref "docs/concepts/signing-and-verification-concept.md" >}}) - Understand how OCM signing works diff --git a/content/docs/reference/_index.md b/content/docs/reference/_index.md index 1ed82f145..c1717de52 100644 --- a/content/docs/reference/_index.md +++ b/content/docs/reference/_index.md @@ -2,7 +2,7 @@ title: Reference description: "Browse reference documentation for the OCM CLI and OCM controllers." icon: "๐Ÿ’พ" -weight: +weight: 60 toc: true sidebar: collapsed: true diff --git a/content/docs/reference/credential-consumer-identities.md b/content/docs/reference/credential-consumer-identities.md new file mode 100644 index 000000000..7a3b2e3cd --- /dev/null +++ b/content/docs/reference/credential-consumer-identities.md @@ -0,0 +1,251 @@ +--- +title: "Credential Consumer Identities" +description: "Complete reference for OCM credential consumer identity types, their attributes, and credential properties." +icon: "๐Ÿ”‘" +weight: 2 +toc: true +--- + +This page is the technical reference for credential consumer identities โ€” the key-value maps OCM uses to look up credentials for a given operation. For a high-level introduction, see [Credential System]({{< relref "docs/concepts/credential-system.md" >}}). + +## Overview + +Every time OCM needs credentials (accessing a registry, signing a component version), it constructs a **lookup identity** โ€” a map of string attributes describing what it needs credentials for. The credential system then searches configured consumers for a matching entry. + +A consumer entry in `.ocmconfig` looks like this: + +```yaml +type: generic.config.ocm.software/v1 +configurations: + - type: credentials.config.ocm.software + consumers: + - identity: + type: + # ... type-specific attributes + credentials: + - type: Credentials/v1 + properties: + # ... key-value credential properties +``` + +OCM currently defines two consumer identity types: + +| Identity Type | Used For | +|---|---| +| [`OCIRepository`](#ocirepository) | Authenticating against OCI registries | +| [`RSA/v1alpha1`](#rsav1alpha1) | Providing signing and verification keys | + +--- + +## OCIRepository + +Used when OCM accesses an OCI registry โ€” pushing, pulling, or resolving component versions and resources. + +### Identity Attributes + +| Attribute | Required | Description | +|---|---|---| +| `type` | Yes | Must be `OCIRepository` | +| `hostname` | Yes | Registry hostname (e.g. `ghcr.io`, `registry.example.com`) | +| `path` | No | Repository path. Supports glob patterns (`*` matches one path segment). If omitted, matches any path on the hostname. | +| `scheme` | No | URL scheme (`https`, `http`, `oci`). If omitted, matches any scheme. If set, must match exactly. | +| `port` | No | Port number as string. Default ports are applied when `scheme` is set: `https` and `oci` default to `443`, `http` defaults to `80`. | + +### Credential Properties + +| Property | Description | +|---|---| +| `username` | Registry username | +| `password` | Registry password or token | + +### Matching Behavior + +Matching runs three chained checks โ€” all must pass: + +1. **Path matcher** โ€” compares `path` using `path.Match` (glob). `*` matches one segment, not across `/`. If the configured entry has no `path`, any request path is accepted. +2. **URL matcher** โ€” compares `scheme`, `hostname`, and `port`. Applies default ports when a scheme is present (`https` โ†’ `443`, `http` โ†’ `80`). +3. **Equality matcher** โ€” all remaining attributes (like `type`) must be exactly equal. + +For detailed matching examples and edge cases, see [Tutorial: Understand Credential Resolution]({{< relref "docs/tutorials/credential-resolution.md" >}}). + +### Examples + +**Hostname only** โ€” matches all paths on `ghcr.io`: + +```yaml +- identity: + type: OCIRepository + hostname: ghcr.io + credentials: + - type: Credentials/v1 + properties: + username: my-user + password: ghp_token +``` + +**Hostname + path glob** โ€” matches any single-segment path under `my-org/`: + +```yaml +- identity: + type: OCIRepository + hostname: ghcr.io + path: my-org/* + credentials: + - type: Credentials/v1 + properties: + username: org-user + password: ghp_org_token +``` + +**Hostname + scheme + port** โ€” matches only HTTPS on a custom port: + +```yaml +- identity: + type: OCIRepository + hostname: registry.internal + scheme: https + port: "8443" + credentials: + - type: Credentials/v1 + properties: + username: internal-user + password: internal_pass +``` + +--- + +## RSA/v1alpha1 + +Used when OCM signs or verifies component versions with RSA keys. + +### Identity Attributes + +| Attribute | Required | Description | +|---|---|---| +| `type` | Yes | Must be `RSA/v1alpha1` | +| `algorithm` | Yes | Signing algorithm. Must be `RSASSA-PSS` (recommended) or `RSASSA-PKCS1-V1_5`. | +| `signature` | Yes | Logical signature name (e.g. `default`). Must match the `--signature` flag used with `ocm sign cv`. Defaults to `default` if not specified on the CLI. | + +{{< callout context="caution" >}} +**All three attributes are required.** When OCM looks up signing credentials, it always constructs a lookup identity with `type`, `algorithm`, and `signature`. If your consumer entry omits `algorithm`, the credential system will not find a match โ€” even though the signing algorithm defaults to `RSASSA-PSS` internally. + +If you are unsure which algorithm to use, specify `algorithm: RSASSA-PSS`. +{{< /callout >}} + +### Credential Properties + +| Property | Used For | Description | +|---|---|---| +| `private_key_pem` | Signing | Inline PEM-encoded private key | +| `private_key_pem_file` | Signing | Path to PEM-encoded private key file | +| `public_key_pem` | Verification | Inline PEM-encoded public key | +| `public_key_pem_file` | Verification | Path to PEM-encoded public key file | + +You can specify both `private_key_pem_file` and `public_key_pem_file` in the same entry to use it for both signing and verification. + +### Matching Behavior + +Unlike OCI identities, RSA signing identities use **strict equality matching** โ€” every attribute in the lookup identity must be present in the configured consumer identity with the exact same value. There is no glob or subset matching. + +### Examples + +**Signing and verification with default settings:** + +```yaml +- identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: default + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /path/to/private-key.pem + public_key_pem_file: /path/to/public-key.pem +``` + +**Multiple signature identities** (e.g. dev and prod): + +```yaml +- identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: dev + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /path/to/dev/private-key.pem + public_key_pem_file: /path/to/dev/public-key.pem +- identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: prod + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /path/to/prod/private-key.pem + public_key_pem_file: /path/to/prod/public-key.pem +``` + +Sign with a specific identity: + +```bash +ocm sign cv --signature dev +ocm sign cv --signature prod +``` + +**Using PKCS#1 v1.5 algorithm:** + +```yaml +- identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PKCS1-V1_5 + signature: legacy + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /path/to/private-key.pem +``` + +--- + +## Complete Configuration Example + +A single `.ocmconfig` combining registry credentials (with Docker fallback) and signing credentials: + +```yaml +type: generic.config.ocm.software/v1 +configurations: + - type: credentials.config.ocm.software + consumers: + # OCI registry โ€” hostname catch-all + - identity: + type: OCIRepository + hostname: ghcr.io + credentials: + - type: Credentials/v1 + properties: + username: my-user + password: ghp_token + # RSA signing โ€” default signature + - identity: + type: RSA/v1alpha1 + algorithm: RSASSA-PSS + signature: default + credentials: + - type: Credentials/v1 + properties: + private_key_pem_file: /path/to/private-key.pem + public_key_pem_file: /path/to/public-key.pem + # Docker config fallback for registries not matched above + repositories: + - repository: + type: DockerConfig/v1 + dockerConfigFile: "$HOME/.docker/config.json" +``` + +## Related Documentation + +- [Concept: Credential System]({{< relref "docs/concepts/credential-system.md" >}}) โ€” How the credential system works +- [Tutorial: Understand Credential Resolution]({{< relref "docs/tutorials/credential-resolution.md" >}}) โ€” Step-by-step matching examples for OCI registries +- [How-To: Configure Credentials for Multiple Registries]({{< relref "docs/how-to/configure-multiple-credentials.md" >}}) โ€” Task-oriented registry credential setup +- [How-To: Configure Credentials for Signing]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) โ€” Task-oriented signing credential setup diff --git a/content/docs/reference/resolver-configuration.md b/content/docs/reference/resolver-configuration.md index 9dc7f2a64..8a41a1b4e 100644 --- a/content/docs/reference/resolver-configuration.md +++ b/content/docs/reference/resolver-configuration.md @@ -2,7 +2,7 @@ title: "Resolver Configuration" description: "Complete reference for OCM resolver configuration: schema, repository types, and component name patterns." icon: "๐Ÿ”" -weight: 10 +weight: 1 toc: true --- diff --git a/content/docs/tutorials/configure-resolvers.md b/content/docs/tutorials/configure-resolvers.md index 3414ac794..3bc79d852 100644 --- a/content/docs/tutorials/configure-resolvers.md +++ b/content/docs/tutorials/configure-resolvers.md @@ -85,7 +85,7 @@ configurations: repositories: - repository: type: DockerConfig/v1 - dockerConfigFile: "~/.docker/config.json" + dockerConfigFile: "$HOME/.docker/config.json" ``` For more information about the OCM configuration file, diff --git a/content/docs/tutorials/credential-resolution.md b/content/docs/tutorials/credential-resolution.md index 992d79cd3..4737da3b4 100644 --- a/content/docs/tutorials/credential-resolution.md +++ b/content/docs/tutorials/credential-resolution.md @@ -10,6 +10,8 @@ toc: true Every time OCM accesses a registry, it resolves credentials automatically. This tutorial walks you through how that resolution works โ€” given a config, which credentials does OCM pick for each request, and why? +This tutorial focuses on OCI registry credentials. For signing credential identities (`RSA/v1alpha1`), see the [Consumer Identities Reference]({{< relref "/docs/reference/credential-consumer-identities.md" >}}). + For the full concept, see [Credential System]({{< relref "/docs/concepts/credential-system.md" >}}). **Estimated time:** ~10 minutes @@ -350,3 +352,4 @@ Then retry the OCM command. ## Related Documentation - [Concept: Credential System]({{< relref "/docs/concepts/credential-system.md" >}}) - Learn how the credential system automatically finds the right credentials for each operation +- [Reference: Consumer Identities]({{< relref "/docs/reference/credential-consumer-identities.md" >}}) โ€” Complete reference for all identity types (OCI registries and RSA signing) diff --git a/content/docs/tutorials/signing-and-verification.md b/content/docs/tutorials/signing-and-verification.md index 6e029d7f0..72a6e152f 100644 --- a/content/docs/tutorials/signing-and-verification.md +++ b/content/docs/tutorials/signing-and-verification.md @@ -1,231 +1,145 @@ --- -title: "Signing and Verification" -description: "Complete guide to cryptographic signing and verification in OCM." +title: "Sign and Verify Components" +description: "Learn to cryptographically sign a component version and verify its authenticity." icon: "โœ๏ธ" -weight: 60 +weight: 55 toc: true --- -## Overview - -The Open Component Model provides cryptographic signing and verification capabilities -to establish **provenance** and **authenticity** of component versions. -This guide covers the complete signing and verification workflow, from key pair generation to trust model selection. - -**This guide is for users who want to:** - -- Understand how OCM handles component signing and verification -- Learn about supported signature types -- See step-by-step signing and verification examples -- Plan multi-environment workflows with dedicated signing profiles (dev/staging/prod) -- Understand how signer specifications and encoding policies complement `.ocmconfig` - -## Signing and Verification Workflow - -### High-Level Process - -A side-by-side comparison makes it clear how both flows mirror the same normalization and hashing steps while differing only in credential handling. - -### Workflow Comparison - -| Step | Signing Flow | Verification Flow | -| --- | --- | --- | -| 1 | Resolve signing credentials from `.ocmconfig` or signer spec | Resolve signature by name and load public key/certificate (config, CLI flag, or embedded PEM) | -| 2 | Normalize component descriptor (selected algorithm) | Normalize component descriptor with the same algorithm | -| 3 | Hash normalized descriptor (selected hash) | Hash normalized descriptor and compare against signature digest | -| 4 | Produce signature, store it with descriptor metadata | Verify signature (and certificate chain if PEM) | - -### What Gets Signed? - -OCM signs the **component descriptor**, which contains: - -- Component metadata (name, version, provider) -- Resources (artifacts like container images, Helm charts) -- Sources (references to source code) -- References to other components -- **Resource digests** (cryptographic hashes of artifacts) - -**Important:** OCM does **not** sign the artifacts themselves, but rather their digests in the component descriptor. This provides: - -- โœ… Efficient verification (no external dependencies) -- โœ… Tamper detection (any change to artifacts invalidates the signature) -- โœ… Provenance (signature proves who created/released the component version) - -## Key Pair Generation (Optional) - -> **Already have RSA key pairs?** Skip to [Configuring Keys in an .ocmconfig File](#configuring-keys-in-an-ocmconfig-file). - -This section covers general RSA key pair generation and management. If you already have suitable RSA keys (self-signed or CA-signed), you can use them directly with OCM and skip to the configuration section. - -### Choose Your Approach - -Before generating keys, decide which approach fits your needs: - -| Your Situation | Recommended Approach | -| --- | --- | -| Local development or testing | **Self-Signed Keys** | -| Production environment | **CA-Signed Keys** | -| Enterprise/Multi-organization | **CA-Signed Keys** | -| Compliance requirements | **CA-Signed Keys** | - -### Self-Signed vs. CA-Signed +In this tutorial, you'll sign a component version with a private key and verify it with the corresponding public key. +By the end, you'll understand the complete signing and verification workflow that ensures component authenticity and integrity. + +## What You'll Learn + +- Create an RSA key pair for signing and verification +- Sign component version in a CTF archive +- Hands-on experience verifying the signature + +**Estimated time:** ~15 minutes + +## Scenario + +You're a software engineer who has built a `helloworld` component and packaged it as an OCM component version. Before distributing it to your team, you need to sign it so consumers can verify that: + +1. **The component is authentic** โ€” it comes from you, not an imposter +2. **The component has integrity** โ€” it hasn't been tampered with since signing + +## How It Works + +```mermaid +flowchart LR + subgraph sign ["Sign (You)"] + direction TB + A[Component Version] --> C[Sign with Private Key] + C --> D[Signed Component Version] + end + + D --> T["Share Component"] + + T --> verify + + subgraph verify ["Verify (Consumer)"] + direction TB + E[Signed Component Version] --> H[Verify with Public Key] + H --> I{Valid?} + I -->|Yes| VALID["โœ“ Trusted"] + I -->|No| INVALID["โœ— Rejected"] + end + + style VALID fill:#dcfce7,color:#166534 + style INVALID fill:#fee2e2,color:#991b1b +``` -**Self-Signed Keys:** +The producer signs the component version with a private key, creating a signed component. Consumers verify the signature using the corresponding public key to ensure authenticity and integrity. -- Simple to create (no external CA required) -- Full control over key lifecycle -- Trust based on explicit key distribution -- Public key must be manually distributed to verifiers +## Prerequisites -**CA-Signed Certificates:** +- [OCM CLI installed]({{< relref "docs/getting-started/ocm-cli-installation.md" >}}) +- A component version to sign (we'll create one if you don't have one) -- Requires Certificate Authority (CA) -- Certificate chain validates against trusted root CAs -- Trust leverages existing PKI -- Automatic trust propagation via certificate validation +## Steps -## Key Pair Generation +{{< steps >}} -OCM supports **RSA** signatures with two algorithms: +{{< step >}} -- **RSASSA-PSS** - Default and recommended -- **RSASSA-PKCS1v15** - Legacy support +### Create a sample component (if needed) -### Directory Structure Setup +If you already have a component version in a CTF archive, +e.g, by following our [Create a Component Version]({{< relref "create-component-version.md" >}}) guide, skip to the next step. -First, create a consistent directory structure for your keys. This guide uses the following convention: +Create a simple helloworld component: ```bash -# Create a directory for your OCM keys -mkdir -p ~/.ocm/keys - -# Recommended structure: -# ~/.ocm/keys/ -# โ”œโ”€โ”€ dev/ # Development keys -# โ”œโ”€โ”€ staging/ # Staging keys -# โ””โ”€โ”€ prod/ # Production keys -``` +# Create a directory for the tutorial +mkdir -p /tmp/ocm-signing-tutorial && cd /tmp/ocm-signing-tutorial -Throughout this guide, we'll use this structure and reference files with their full paths. +# Create a basic `component-constructor.yaml` without any resources: +cat > component-constructor.yaml << 'EOF' +components: +- name: github.com/acme.org/helloworld + version: 1.0.0 + provider: + name: acme.org +EOF -### Self-Signed Keys (Development) +# Create component version in a CTF archive located at ./transport-archive +ocm add cv -Self-signed keys are ideal for development, testing, and environments without PKI infrastructure. - -#### Generate Development Keys +``` -```bash -# Create directory for development keys -mkdir -p ~/.ocm/keys/dev +You should see that the component version was created successfully. -# Generate private key (4096 bits recommended) -openssl genrsa -out ~/.ocm/keys/dev/private.pem 4096 +
+Expected output -# Extract public key -openssl rsa -in ~/.ocm/keys/dev/private.pem -pubout -out ~/.ocm/keys/dev/public.pem - -# Set secure permissions -chmod 600 ~/.ocm/keys/dev/private.pem -chmod 644 ~/.ocm/keys/dev/public.pem +```text + COMPONENT โ”‚ VERSION โ”‚ PROVIDER +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + github.com/acme.org/helloworld โ”‚ 1.0.0 โ”‚ acme.org ``` -**Files created:** - -- `~/.ocm/keys/dev/private.pem` - Private key (4096 bits) -- `~/.ocm/keys/dev/public.pem` - Public key +
+{{< /step >}} -### CA-Signed Keys (Production) +{{< step >}} -CA-signed certificates provide a trust chain that can be validated against a certificate authority. -They are recommended for production environments, enterprise deployments, -and scenarios requiring PKI integration or compliance. +### Generate an RSA key pair -#### Generate Production Keys with CSR +Create a directory for your keys and generate a 4096-bit RSA key pair: ```bash -# Create directory for production keys -mkdir -p ~/.ocm/keys/prod +# Create a directory for the generated keys +mkdir keys # Generate private key -openssl genrsa -out ~/.ocm/keys/prod/private.pem 4096 - -# Create certificate signing request (CSR) -openssl req -new -key ~/.ocm/keys/prod/private.pem \ - -out ~/.ocm/keys/prod/request.csr \ - -subj "/C=US/O=MyOrg/OU=Engineering/CN=OCM Production Signer" +openssl genpkey -algorithm RSA -out ./keys/private-key.pem -pkeyopt rsa_keygen_bits:4096 -# Set secure permissions -chmod 600 ~/.ocm/keys/prod/private.pem -chmod 644 ~/.ocm/keys/prod/request.csr +# Extract public key +openssl rsa -in ./keys/private-key.pem -pubout -out ./keys/public-key.pem -# Send request.csr to your CA and save the response -# After receiving from CA, save as: -# ~/.ocm/keys/prod/certificate.pem -# ~/.ocm/keys/prod/ca-chain.pem (if provided) +# Secure the private key +chmod 600 ./keys/private-key.pem ``` -**Files created:** - -- `~/.ocm/keys/prod/private.pem` - Private key (4096 bits) -- `~/.ocm/keys/prod/request.csr` - Certificate signing request (send to CA) - -**Files received from CA:** - -- `~/.ocm/keys/prod/certificate.pem` - Signed certificate -- `~/.ocm/keys/prod/ca-chain.pem` - CA certificate chain (optional but recommended) - -#### Create Certificate with Chain - -If you receive individual certificates, combine them into a chain: +Verify both files exist: ```bash -# Combine leaf certificate with intermediate and root CA certificates -cat ~/.ocm/keys/prod/certificate.pem \ - ~/.ocm/keys/prod/intermediate-ca.pem \ - ~/.ocm/keys/prod/root-ca.pem \ - > ~/.ocm/keys/prod/cert-chain.pem - -chmod 644 ~/.ocm/keys/prod/cert-chain.pem +ls -la ./keys/*.pem ``` -## Configuring Keys in an .ocmconfig File - -OCM uses its credential system to resolve signing and verification keys. -The keys are configured as credentials for a special consumer type: `RSA/v1alpha1`. - -> **Using your own keys?** Simply reference your existing key file paths in the configuration examples below instead of the `~/.ocm/keys/` paths shown here. - -All examples below use the **exact file paths** from the key generation section above. - -> **Tip:** Add the entries below to your `.ocmconfig`. If the file is present in your home directory (`~/.ocmconfig`), the OCM CLI will use it automatically. Only provide `--config ` when you want to reference a different configuration file. - -### Basic Signing Configuration (Development) - -Using the development keys we created earlier: - -```yaml -type: generic.config.ocm.software/v1 -configurations: - - type: credentials.config.ocm.software - consumers: - - identity: - type: RSA/v1alpha1 - algorithm: RSASSA-PSS - signature: default - credentials: - - type: Credentials/v1 - properties: - private_key_pem_file: ~/.ocm/keys/dev/private.pem -``` +> โš ๏ธ **Keep your private key secure!** โš ๏ธ +> Never commit it to version control or share it. -**Note:** This references `~/.ocm/keys/dev/private.pem` which we created with the OpenSSL command in the previous section. +For more details, see [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}). +{{< /step >}} -> **Alternative:** Keys can also be embedded inline using `private_key_pem` property. -> The inline format uses a multi-line YAML string with the PEM block. +{{< step >}} -### Basic Verification Configuration (Development) +### Configure signing credentials -Using the public key we generated earlier: +Create or update your `$HOME/.ocmconfig` file and copy the content below to it, to tell OCM where to find your keys. +A detailed How-To guide is available here: [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}). ```yaml type: generic.config.ocm.software/v1 @@ -239,538 +153,140 @@ configurations: credentials: - type: Credentials/v1 properties: - public_key_pem_file: ~/.ocm/keys/dev/public.pem -``` - -**Note:** This configuration references `~/.ocm/keys/dev/public.pem` which was extracted from the private key using OpenSSL. - -### Identity Attributes Explained - -The consumer identity for RSA signing/verification supports these attributes: - -| Attribute | Required | Description | -|-------------|----------|------------------------------------------------------------------| -| `type` | Yes | Must be `RSA/v1alpha1` | -| `algorithm` | No | `RSASSA-PSS` (default) or `RSASSA-PKCS1V15` (legacy) | -| `signature` | No | Name/label for this signature configuration (default: `default`) | - -The `signature` attribute is particularly useful for multi-environment setups. - -## Multi-Environment Configuration - -> **Optional (advanced):** Skip this section if you operate a single environment. You can continue with [Signer Specifications](#signer-specifications) without missing any required setup. - -In many organizations, you'll want different signing keys for different environments or purposes. - -For multiple environments, generate separate keys using the same process: - -- **Development:** Self-signed keys (see [Self-Signed Keys](#self-signed-keys-development) section) -- **Staging:** Self-signed keys in `~/.ocm/keys/staging/` (same process) -- **Production:** CA-signed keys (see [CA-Signed Keys](#ca-signed-keys-production) section) - -### Combined Configuration Example - -This example shows a complete `.ocmconfig` with signing and verification keys for all environments: - -```yaml -type: generic.config.ocm.software/v1 -configurations: - - type: credentials.config.ocm.software - consumers: - # Development environment - - identity: - type: RSA/v1alpha1 - algorithm: RSASSA-PSS - signature: dev - credentials: - - type: Credentials/v1 - properties: - private_key_pem_file: ~/.ocm/keys/dev/private.pem - public_key_pem_file: ~/.ocm/keys/dev/public.pem - - # Staging environment - - identity: - type: RSA/v1alpha1 - algorithm: RSASSA-PSS - signature: staging - credentials: - - type: Credentials/v1 - properties: - private_key_pem_file: ~/.ocm/keys/staging/private.pem - public_key_pem_file: ~/.ocm/keys/staging/public.pem - - # Production environment (CA-signed with certificate chain) - - identity: - type: RSA/v1alpha1 - algorithm: RSASSA-PSS - signature: prod - credentials: - - type: Credentials/v1 - properties: - private_key_pem_file: ~/.ocm/keys/prod/private.pem - public_key_pem_file: ~/.ocm/keys/prod/cert-chain.pem + private_key_pem_file: /tmp/ocm-signing-tutorial/keys/private-key.pem + public_key_pem_file: /tmp/ocm-signing-tutorial/keys/public-key.pem ``` -**Notes:** +> ๐Ÿ‘‰ The `signature: default` name is used when you don't specify `--signature` on the command line. -- Each environment has both private and public keys -- Production uses the certificate chain for verification -- The same configuration works for both signing and verification +For more details, see [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}). +{{< /step >}} -### Usage Examples +{{< step >}} -**Signing:** - -```bash -# Sign with development key -ocm sign cv --signature dev ghcr.io/myorg/component:1.0.0 - -# Sign with staging key -ocm sign cv --signature staging ghcr.io/myorg/component:1.0.0 - -# Sign with production key -ocm sign cv --signature prod ghcr.io/myorg/component:1.0.0 -``` +### Sign the component version -**Verification:** +Sign your component with the private key: ```bash -# Verify with development key -ocm verify cv --signature dev ghcr.io/myorg/component:1.0.0 - -# Verify with staging key -ocm verify cv --signature staging ghcr.io/myorg/component:1.0.0 - -# Verify with production key -ocm verify cv --signature prod ghcr.io/myorg/component:1.0.0 +ocm sign cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 ``` -### Verification-Only Configuration +
+Expected output -If you only need to verify signatures (e.g., on CI/CD runners or deployment systems), you can omit the private keys: - -```yaml -type: generic.config.ocm.software/v1 -configurations: - - type: credentials.config.ocm.software - consumers: - - identity: - type: RSA/v1alpha1 - signature: prod - credentials: - - type: Credentials/v1 - properties: - # Only public key needed for verification - public_key_pem_file: ~/.ocm/keys/prod/cert-chain.pem +```text +time=... level=INFO msg="signing component version" name=default +time=... level=INFO msg="signature added" name=default ``` -**Note:** This configuration contains only the public key. Verification works, but signing operations will fail (as intended for read-only environments). - -## Signer Specifications +
-> **Optional (advanced):** If you do not need per-command overrides or CI-friendly specs, skip ahead to [Signature Encoding Policies](#signature-encoding-policies). Core functionality continues there. - -The `--signer-spec` flag provides fine-grained control over the signing process via a YAML configuration file. - -### When to Use Signer Specs - -Use signer specifications when you need: - -- โœ… Command-specific signing config -- โœ… CI/CD pipeline integration -- โœ… Explicit control over signing parameters -- โœ… Different encoding policies -- โœ… Temporary or one-off signing operations - -**Signer specs vs. .ocmconfig:** - -| Aspect | Signer Spec File | .ocmconfig | -|---------------------|--------------------------|--------------------------| -| Scope | Command-specific | Global configuration | -| Portability | Easy to version control | User/machine-specific | -| Use case | CI/CD, explicit control | Local development | -| Key distribution | Embedded or referenced | Centralized config | - -### Signer Spec File Format - -A signer specification file contains only signing configuration, **not** the signature name (which is provided via `--signature` flag). - -```yaml -type: RSA/v1alpha1 -signatureAlgorithm: RSASSA-PSS # or RSASSA-PKCS1V15 -signatureEncodingPolicy: Plain # or PEM - -# Option 1: Reference external file (preferred) -privateKeyPEMFile: ~/.ocm/keys/dev/private.pem - -# Option 2: Inline private key -# privateKeyPEM: | -# -----BEGIN PRIVATE KEY----- -# ... -# -----END PRIVATE KEY----- -``` - -**Note:** The **signature name** is specified via the `--signature` flag when running the command, not in this file. - -### Default Signer Spec Behavior - -If `--signer-spec` is **not** provided, OCM uses defaults: - -```yaml -type: RSA/v1alpha1 -signatureAlgorithm: RSASSA-PSS -signatureEncodingPolicy: Plain -# Private key resolved from .ocmconfig -``` - -This means: - -- Algorithm: RSASSA-PSS -- Encoding: Plain (raw signature bytes) -- Key: Retrieved from `.ocmconfig` config file - -### Example: Using Signer Spec in CI/CD - -**signer-config.yaml:** - -```yaml -type: RSA/v1alpha1 -signatureAlgorithm: RSASSA-PSS -signatureEncodingPolicy: Plain -privateKeyPEMFile: /secrets/signing-key.pem -``` - -**CI/CD pipeline:** +Verify the signature was added: ```bash -# Inject private key into CI/CD secrets -echo "$SIGNING_PRIVATE_KEY" > /secrets/signing-key.pem -chmod 600 /secrets/signing-key.pem - -# Sign component version -ocm sign cv \ - --signer-spec ./signer-config.yaml \ - --signature release \ - ghcr.io/myorg/component:${VERSION} +ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 10 signatures: ``` -## Signature Encoding Policies - -> **Optional (advanced):** Readers who only work with the default signing setup can skip directly to [Signing Component Versions](#signing-component-versions). The sections below cover advanced storage and trust scenarios. +You should see a `signatures:` section with your signature. +{{< /step >}} -OCM supports two encoding policies that affect how signatures are stored and verified. +{{< step >}} -### Plain Encoding (Default) +### Verify the signature -Stores only the raw signature bytes. Compact but requires the public key to be provided separately (via `.ocmconfig` or `--public-key` flag). - -**Configuration:** - -```yaml -type: RSA/v1alpha1 -signatureEncodingPolicy: Plain -``` - -Suitable for self-signed keys and scenarios where public keys are distributed through `.ocmconfig`. - -### PEM Encoding - -Embeds the certificate chain directly in the signature, enabling verification against the system trust store without requiring public keys in `.ocmconfig`. - -**Configuration:** - -```yaml -type: RSA/v1alpha1 -signatureEncodingPolicy: PEM -``` - -**How it works:** - -1. Creates a PEM block containing the signature -2. Appends the signer's certificate chain -3. During verification, validates the chain against the system trust store -4. Extracts the public key from the validated certificate - -**Requirements:** - -- Signature name must match the config -- Certificate chain must be included in the signature -- System trust store must contain the root CA, or root CA must be provided in `.ocmconfig` - -Suitable for enterprise PKI integration and scenarios requiring automated trust validation. - -## Signing Component Versions - -### Basic Signing - -```sh -# Sign with default signature name and configuration -ocm sign cv ghcr.io/myorg/component:1.0.0 - -# Sign with custom signature name -ocm sign cv --signature release ghcr.io/myorg/component:1.0.0 -``` - -### Advanced Signing Options - -```sh -# Use specific signer specification -ocm sign cv \ - --signer-spec ./config/prod-signer.yaml \ - --signature prod-release \ - ghcr.io/myorg/component:1.0.0 - -# Dry run (compute signature without storing) -ocm sign cv \ - --signature test \ - --dry-run \ - ghcr.io/myorg/component:1.0.0 - -# Force overwrite existing signature -ocm sign cv \ - --signature release \ - --force \ - ghcr.io/myorg/component:1.0.0 - -# Custom normalization and hash algorithms -ocm sign cv \ - --normalisation jsonNormalisation/v4alpha1 \ - --hash SHA512 \ - --signature release \ - ghcr.io/myorg/component:1.0.0 -``` - -### Common Signing Flags - -| Flag | Description | Default | -|-------------------|------------------------------------------|---------------| -| `--signature` | Name of the signature | `default` | -| `--signer-spec` | Path to signer specification file | (uses config) | -| `--force` | Overwrite existing signature | `false` | -| `--dry-run` | Compute signature without storing | `false` | - -For complete flag reference, see `ocm sign cv --help`. - -## Verifying Component Versions - -### Basic Verification - -```sh -# Verify default signature -ocm verify cv ghcr.io/myorg/component:1.0.0 - -# Verify specific signature -ocm verify cv --signature release ghcr.io/myorg/component:1.0.0 -``` +Now verify the signature using the public key: -### Verification with External Public Key - -```sh -# Provide public key via command line -ocm verify cv \ - --public-key ./keys/public.pem \ - --signature release \ - ghcr.io/myorg/component:1.0.0 +```bash +ocm verify cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 ``` -### Verification Process - -1. **Fetch component version** from repository -2. **Locate signature** by name in component descriptor -3. **Resolve public key** from: - - `.ocmconfig` credential system, OR - - `--public-key` flag, OR - - Certificate chain in signature (PEM encoding only) -4. **Normalize component descriptor** using specified algorithm -5. **Hash normalized descriptor** -6. **Verify signature** using public key -7. **Validate certificate chain** (PEM encoding only) - -### Verification Success Criteria - -For verification to succeed: - -- โœ… Signature exists with specified name -- โœ… Public key can be resolved -- โœ… Signature cryptographically valid -- โœ… Component descriptor unchanged since signing -- โœ… Certificate chain valid (PEM encoding only) -- โœ… Certificate DN matches signature name (PEM encoding only) - -## Trust Models +
+Expected output -OCM supports multiple trust models depending on your security requirements. - -### 1. Key Pinning (Self-Signed) - -Specific public keys configured in `.ocmconfig`. Trust is based on exact key match without certificate validation. - -**Trust chain:** - -```code -Component Signature โ†’ Public Key in .ocmconfig โ†’ Trust +```text +time=2026-03-12T22:06:37.357+01:00 level=INFO msg="no verifier specification file given, using default RSASSA-PSS" +time=2026-03-12T22:06:37.357+01:00 level=INFO msg="verifying signature" name=default +time=2026-03-12T22:06:37.358+01:00 level=INFO msg="signature verification completed" name=default duration=798.25ยตs +time=2026-03-12T22:06:37.358+01:00 level=INFO msg="SIGNATURE VERIFICATION SUCCESSFUL" ``` -Simple setup with full control, suitable for small teams and development environments. - -### 2. System Trust Store (CA-Signed, PEM Encoding) - -Certificate chain embedded in signature and validated against system trust store or distributed root CA. No manual public key distribution needed. - -**Trust chain:** +
-```code -Component Signature โ†’ Embedded Cert Chain โ†’ System Trust Store โ†’ Root CA โ†’ Trust -``` +> โœ… **Success!** โœ… +> The component version is verified as authentic and unmodified. -Suitable for automatic trust propagation in enterprise PKI infrastructure. +{{< /step >}} +{{< /steps >}} -## Complete Configuration Examples +## What You've Learned -### Example 1: Development Setup (Self-Signed) +Congratulations! You've successfully: -**Prerequisites:** Generate self-signed keys (see "Self-Signed Keys" section): +- โœ… Generated an RSA key pair for signing and verification +- โœ… Configured OCM to use your keys via `.ocmconfig` +- โœ… Signed a component version with your private key +- โœ… Verified the signature using the public key +- โœ… Understood how signatures detect tampering -```bash -mkdir -p ~/.ocm/keys/dev -openssl genrsa -out ~/.ocm/keys/dev/private.pem 4096 -openssl rsa -in ~/.ocm/keys/dev/private.pem -pubout -out ~/.ocm/keys/dev/public.pem -chmod 600 ~/.ocm/keys/dev/private.pem -chmod 644 ~/.ocm/keys/dev/public.pem -``` +## Best Practices for Production -**.ocmconfig:** +Now that you understand the workflow, here are key practices for production environments: -```yaml -type: generic.config.ocm.software/v1 -configurations: - - type: credentials.config.ocm.software - consumers: - - identity: - type: RSA/v1alpha1 - signature: dev - credentials: - - type: Credentials/v1 - properties: - private_key_pem_file: ~/.ocm/keys/dev/private.pem - public_key_pem_file: ~/.ocm/keys/dev/public.pem -``` +- **Protect private keys** โ€” Use hardware security modules (HSMs) or secrets managers instead of local PEM files +- **Rotate keys periodically** โ€” Have a key rotation strategy; OCM supports multiple signatures to ease transitions +- **Sign at the right time** โ€” Sign after all resources are finalized; re-signing is possible but creates audit complexity +- **Distribute public keys securely** โ€” Document how consumers should obtain and verify public keys +- **Verify before deployment** โ€” Make signature verification a mandatory step in your deployment pipeline -**Usage:** +## Check Your Understanding -```bash -# Sign -ocm sign cv --signature dev ghcr.io/myorg/component:1.0.0 +{{< details "Why does OCM sign the component descriptor instead of the artifacts directly?" >}} +OCM signs the component descriptor because it contains **digests** (cryptographic hashes) of all resources. +This approach is: -# Verify -ocm verify cv --signature dev ghcr.io/myorg/component:1.0.0 -``` +- **Efficient**: Verification doesn't require downloading large artifacts +- **Complete**: Any change to any resource changes its digest, invalidating the signature +- **Portable**: The descriptor can be verified independently of artifact storage -### Example 2: Enterprise Production Setup (CA-Signed, PEM Encoding) +{{< /details >}} -**Prerequisites:** Use CA-signed production keys (see "CA-Signed Keys" section). +{{< details "What's the difference between the private and public key?" >}} -**Key differences from Development:** +- **Private key**: Used to create signatures. Keep it secret โ€” anyone with this key can sign components as you. +- **Public key**: Used to verify signatures. Share it freely with anyone who needs to verify your components. -- Uses `signatureEncodingPolicy: PEM` -- Certificate chain embedded in signature -- Validates against system trust store -- Minimal `.ocmconfig` needed for verification +{{< /details >}} -**Signer specification (~/prod-signer.yaml):** +{{< details "Can a component have multiple signatures?" >}} +Yes! A component version can have multiple signatures from different parties. This enables: -```yaml -type: RSA/v1alpha1 -signatureAlgorithm: RSASSA-PSS -signatureEncodingPolicy: PEM -privateKeyPEMFile: ~/.ocm/keys/prod/private.pem -``` +- Different signing identities (dev, staging, prod) +- Multiple approval workflows +- Cross-organizational trust chains -**Sign:** +Use `--signature ` to specify which signature to create or verify. +{{< /details >}} -```bash -ocm sign cv --signer-spec ~/prod-signer.yaml --signature prod ghcr.io/myorg/component:1.0.0 -``` +## Cleanup -**Verify:** +Remove the tutorial artifacts: ```bash -# Certificate chain validated automatically from signature -ocm verify cv --signature prod ghcr.io/myorg/component:1.0.0 +rm -rf $HOME/ocm-signing-tutorial +# Optionally remove keys: rm -rf $HOME/.ocm/keys +# Optionally remove config: rm $HOME/.ocmconfig ``` -## Troubleshooting - -### Signature Verification Fails - -**Error:** "signature verification failed" - -**Common causes:** - -1. Wrong public key configured -2. Component version modified after signing -3. Signature name mismatch -4. Certificate chain invalid (PEM encoding) - -**Solutions:** - -- Verify public key matches private key: `openssl rsa -in private.pem -pubout` -- Check signature name: `ocm get cv -o yaml ghcr.io/myorg/component:1.0.0` -- Verify certificate chain: `openssl verify -CAfile ca-chain.pem certificate.pem` - -### Private Key Not Found - -**Error:** "could not resolve credentials for identity" - -**Solutions:** - -- Check `.ocmconfig` path and syntax -- Verify file paths in `private_key_pem_file` -- Ensure `signature` attribute matches between config and command - -### Certificate Chain Validation Fails (PEM) - -**Error:** "certificate validation failed" - -**Solutions:** - -- Ensure system trust store includes required root CAs -- Provide root CA in `.ocmconfig`: `public_key_pem_file: ./ca-root.pem` -- Verify certificate DN matches signature name -- Check certificate expiry: `openssl x509 -in cert.pem -noout -dates` - -### Signature Already Exists - -**Error:** "signature 'name' already exists" - -**Solutions:** - -- Use `--force` to overwrite: `ocm sign cv ... --force` -- Use a different signature name: `--signature name-v2` -- Remove old signature first (manual descriptor editing) - -## Summary - -OCM's signing and verification system provides: - -- โœ… **Flexible trust models** - From simple key pinning to enterprise PKI -- โœ… **Multiple algorithms** - RSASSA-PSS (recommended) and PKCS1v15 -- โœ… **Encoding options** - Plain (compact) and PEM (with cert chains) -- โœ… **Multi-environment support** - Separate keys for dev, staging, prod -- โœ… **Signer specifications** - Fine-grained control over signing process -- โœ… **Credential integration** - Unified with OCM credential system - -**Choosing the right approach:** +## Next Steps -| Scenario | Recommended Approach | -| --- | --- | -| Local development | Self-signed, Plain encoding | -| Small team | Self-signed, key pinning | -| Medium organization | CA-signed, Plain, certificate pinning | -| Enterprise | CA-signed, PEM, system trust store | -| Compliance-driven | CA-signed, PEM, HSM integration | +- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Step-by-step creating RSA key pairs. +- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification +- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Step-by-step signing instructions +- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Step-by-step verification instructions ## Related Documentation -- [OCM Credentials]({{< relref "/docs/concepts/credential-system.md" >}}) - How OCM resolves credentials for registries and services -- [OCM CLI Reference]({{< relref "docs/reference/ocm-cli/_index.md" >}}) - Complete command-line options +- [Concept: Signing and Verification]({{< relref "docs/concepts/signing-and-verification-concept.md" >}}) - Understand the theory behind OCM signing +- [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}) - Detailed key generation guide +- [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) - Multi-environment and advanced configurations