An Argo CD Config Management Plugin (CMP) for verified manifest delivery from OCI blob archives.
Blob CMP integrates with the Meigma Blob system to provide cryptographically verified manifest delivery to Argo CD. The plugin verifies blob archives against configurable policies (Sigstore signatures and/or SLSA provenance) before extracting Kubernetes manifests.
- Sigstore verification: Verify keyless signatures from GitHub Actions and other OIDC providers
- SLSA provenance: Validate SLSA build provenance attestations
- Flexible policy configuration: Per-application inline policies or centralized policy management
- Combined verification: Require multiple verification types (e.g., both Sigstore AND SLSA)
- Caching: Built-in caching for tag-to-digest resolution and verified archives
Use blob-action to push Kubernetes manifests to an OCI registry with optional Sigstore signing:
- name: Push manifests
id: push
uses: meigma/blob-action@v1
with:
action: push
ref: ghcr.io/${{ github.repository }}/manifests:${{ github.sha }}
path: ./manifests
sign: "true" # Enable Sigstore keyless signing
- name: Generate SLSA attestation
uses: actions/attest-build-provenance@v2
with:
subject-name: ghcr.io/${{ github.repository }}/manifests
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: trueSee the integration test workflow for a complete working example.
The policy ConfigMap configures verification requirements and caching:
kubectl apply -f deploy/policy-configmap.yamlEdit the ConfigMap to configure your verification policies before applying.
The plugin configuration is baked into the Docker image, so this step is only needed if you want to customize the plugin parameters:
kubectl apply -f deploy/configmap.yamlAdd the CMP sidecar container to the repo-server deployment:
kubectl patch deployment argocd-repo-server -n argocd --patch-file deploy/patch-repo-server.yamlOr use kubectl edit to add the sidecar container manually. See the Argo CD CMP documentation for details.
Note: The plugin is named blob-cmp with version v1.0. When referencing it in Applications, use the combined name blob-cmp-v1.0.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
source:
repoURL: https://github.com/placeholder/repo
path: .
plugin:
name: blob-cmp-v1.0
parameters:
- name: blob-ref
string: "ghcr.io/myorg/manifests:v1.2.3"
- name: policy
string: |
type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/repo/.github/workflows/release.yaml@refs/heads/main"
destination:
server: https://kubernetes.default.svc
namespace: my-appVerify keyless signatures:
type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/repo/.github/workflows/release.yaml@refs/heads/main"Verify SLSA provenance:
type: slsa
slsa:
repository: "myorg/repo"
branches: ["main"]
tags: ["v*"]Require both Sigstore AND SLSA:
type: all
policies:
- type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/repo/.github/workflows/release.yaml@refs/heads/main"
- type: slsa
slsa:
repository: "myorg/repo"
branches: ["main"]Require Sigstore OR SLSA:
type: any
policies:
- type: sigstore
sigstore:
issuer: "https://issuer1"
subject: "https://subject1"
- type: sigstore
sigstore:
issuer: "https://issuer2"
subject: "https://subject2"Skip verification (for internal registries):
type: noneFor environments where inline policies are not desired, configure policies centrally in /etc/blob-cmp/policy.yaml:
apiVersion: blob-cmp.meigma.io/v1alpha1
kind: PolicyConfig
# Enable caching for improved performance
cache:
enabled: true
directory: /tmp/blob-cache
refTTL: 5m # How long to cache tag->digest mappings
# Set to false to reject inline policies
allowInlinePolicy: true
defaults:
requireVerification: true
patterns: ["*.yaml", "*.yml", "*.json"]
policies:
default:
type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/configs/.github/workflows/*"
repositories:
- match: "ghcr.io/myorg/prod-*"
policy:
type: all
policies:
- type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/prod-configs/.github/workflows/release.yaml@refs/heads/main"
- type: slsa
slsa:
repository: "myorg/prod-configs"
branches: ["main"]
- match: "internal.registry.io/*"
policy:
type: noneapiVersion: argoproj.io/v1alpha1
kind: Application
spec:
source:
plugin:
name: blob-cmp-v1.0
parameters:
- name: blob-ref
string: "ghcr.io/myorg/manifests:v1.2.3"
# No policy parameter - uses central config lookup| Parameter | Required | Description |
|---|---|---|
blob-ref |
Yes | OCI reference to blob archive (e.g., ghcr.io/org/repo:tag) |
policy |
No | Inline policy YAML. Overrides central config if set. |
patterns |
No | Glob patterns for manifest files (default: *.yaml, *.yml, *.json) |
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Verification failed (policy violation) |
| 2 | Configuration error |
| 3 | Network/registry error |
| 4 | Invalid archive format |
The integration test workflow demonstrates a complete end-to-end setup:
- Push manifests to GHCR with Sigstore signing using
blob-action - Generate SLSA attestation using
actions/attest-build-provenance - Deploy Argo CD with the CMP sidecar in a Kind cluster
- Create an Application that pulls and verifies the manifests
- Verify deployment succeeds with verified manifests
- Negative test confirms unsigned images are rejected
The workflow configures a policy requiring both Sigstore AND SLSA verification:
policies:
repositories:
- match: "ghcr.io/myorg/*"
policy:
type: all
policies:
- type: sigstore
sigstore:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/repo/.github/workflows/release.yml@refs/heads/main"
- type: slsa
slsa:
repository: "myorg/repo"# Build binary
make build
# Run tests
make test
# Build Docker image
make docker VERSION=v1.0.0Licensed under either of Apache License, Version 2.0 or MIT license at your option.