diff --git a/.github/workflows/release-ocm-components.yml b/.github/workflows/release-ocm-components.yml index 003d0e8..63cc220 100644 --- a/.github/workflows/release-ocm-components.yml +++ b/.github/workflows/release-ocm-components.yml @@ -18,6 +18,8 @@ jobs: - ./cloudnative-pg - ./keycloak - ./ocm-demo + - ./solution-arsenal + - ./solution-arsenal-discovery steps: - name: Checkout repository uses: actions/checkout@v6 diff --git a/README.md b/README.md index a9d206b..27aec22 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,29 @@ helm install artifact-conduit artifact-conduit/arc-0.1.0.tgz \ **Note**: Artifact Conduit is an early-stage project (356+ commits, 8 contributors) not yet recommended for production without thorough testing. It provides a declarative way to transfer artifacts across security boundaries with automated scanning and policy compliance. +### Solution Arsenal + +OCM-based Application Catalog and Fleet Rollout Manager + +- **Status**: Early Stage (pre-release, active development) +- **License**: Apache 2.0 +- **Configurations**: + - Minimal (single instance, development / evaluation) + - Production (3 replicas each, leader election, metrics enabled) +- **Documentation**: [solution-arsenal/README.md](solution-arsenal/README.md) + +### Solution Arsenal Discovery + +Standalone OCI Registry Scanner for OCM Packages + +- **Status**: Early Stage (pre-release, active development) +- **License**: Apache 2.0 +- **Configurations**: + - Minimal (single instance, scan-only mode, no webhook) + - Production (2 replicas, webhook listener enabled, anti-affinity) +- **Documentation**: [solution-arsenal-discovery/README.md](solution-arsenal-discovery/README.md) + + ### ocm-demo (v0.1.0) Minimal example component used to demonstrate OCM packaging, transfer, and runtime image localization. diff --git a/solution-arsenal-discovery/README.md b/solution-arsenal-discovery/README.md new file mode 100644 index 0000000..e392249 --- /dev/null +++ b/solution-arsenal-discovery/README.md @@ -0,0 +1,47 @@ +# Solution Arsenal Discovery (SolAr Discovery) OCM Component + +This directory contains the OCM (Open Component Model) packaging for [SolAr Discovery](https://github.com/opendefensecloud/solution-arsenal), a standalone OCI registry scanner that discovers OCM packages and populates the Solution Arsenal catalog. + +## Component structure + +``` +solution-arsenal-discovery/ +├── component-constructor.yaml # OCM component descriptor +├── minimal-values.yaml # Helm values: single-instance dev/test profile +├── production-values.yaml # Helm values: HA production profile +``` + +## Prerequisites + +### Required +- **Kubernetes** +- **Helm** + + +## Quick start + +### 1. Build the CTF archive + +Run from the `solution-arsenal-discovery/` directory of this repo: + +```bash +ocm add componentversion --version 0.1.0 --create --file ./ctf component-constructor.yaml +``` + +### 2. Transfer to a registry + +```bash +# Public registry (replace with your org) +ocm transfer ctf --copy-local-resources ./ctf ghcr.io/your-org + +# Local registry for testing +ocm transfer ctf --copy-local-resources ./ctf localhost:5001 +``` + +The `--copy-local-resources` flag rewrites the image references inside the component to point to the target registry. The RGD picks up these rewritten references at runtime so images are pulled from the correct location. + +## Resources + +- [Solution Arsenal repository](https://github.com/opendefensecloud/solution-arsenal) +- [SolAr documentation](https://solar.opendefense.cloud) +- [OCM specification](https://ocm.software) diff --git a/solution-arsenal-discovery/component-constructor.yaml b/solution-arsenal-discovery/component-constructor.yaml new file mode 100644 index 0000000..4f75f64 --- /dev/null +++ b/solution-arsenal-discovery/component-constructor.yaml @@ -0,0 +1,45 @@ +components: + - name: opendefense.cloud/solution-arsenal-discovery + provider: + name: opendefense.cloud + labels: + - name: app.kubernetes.io/name + value: solution-arsenal-discovery + - name: app.kubernetes.io/component + value: registry-scanner + - name: app.kubernetes.io/part-of + value: solution-arsenal + resources: + # SolutionArsenal Discovery Helm Chart + - name: solution-arsenal-discovery-chart + type: helmChart + version: v0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/charts/solar-discovery:0.1.1 + + # Solar Discovery Container Image + - name: solution-arsenal-discovery-image + type: ociImage + version: v0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/solar-discovery:0.1.1 + + # Minimal Configuration (single instance, scan-only mode) + - name: solution-arsenal-discovery-minimal-config + type: yaml + relation: local + input: + type: file + path: minimal-values.yaml + + # Production Configuration (2 replicas, webhook enabled, anti-affinity) + - name: solution-arsenal-discovery-production-config + type: yaml + relation: local + input: + type: file + path: production-values.yaml diff --git a/solution-arsenal-discovery/minimal-values.yaml b/solution-arsenal-discovery/minimal-values.yaml new file mode 100644 index 0000000..32077cb --- /dev/null +++ b/solution-arsenal-discovery/minimal-values.yaml @@ -0,0 +1,48 @@ +# Minimal SolutionArsenal Discovery Configuration +# Single-instance setup suitable for: +# - Development environments +# - Testing and evaluation +# - Resource-constrained environments (kind, minikube) +# - Scan-only mode (no webhook required) + +image: + repository: ghcr.io/opendefensecloud/solar-discovery + tag: latest + pullPolicy: IfNotPresent + +replicaCount: 1 + +# No registries configured by default — add your registries here +# registries: +# - name: my-registry +# hostname: registry.example.com +# scanInterval: 24h +# credentials: +# username: ${REGISTRY_USERNAME} +# password: ${REGISTRY_PASSWORD} + +# Namespace where discovered Component/ComponentVersion resources are created +namespace: "" + +# Webhook service enabled but no ingress — webhook can be added later +service: + enabled: true + type: ClusterIP + port: 8080 + +# Minimal resource requests +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + +# CA bundle disabled for minimal setup +caBundle: + enabled: false + +# RBAC enabled +rbac: + create: true diff --git a/solution-arsenal-discovery/production-values.yaml b/solution-arsenal-discovery/production-values.yaml new file mode 100644 index 0000000..17aa28e --- /dev/null +++ b/solution-arsenal-discovery/production-values.yaml @@ -0,0 +1,71 @@ +# Production SolutionArsenal Discovery Configuration +# Highly-available setup suitable for: +# - Production environments +# - Environments with private registries requiring TLS trust + +image: + repository: ghcr.io/opendefensecloud/solar-discovery + tag: latest + pullPolicy: IfNotPresent + +replicaCount: 2 + +# Configure registries to scan — use envFrom to inject credentials from Secrets +# registries: +# - name: internal-registry +# hostname: registry.internal.example.com +# scanInterval: 12h +# credentials: +# username: ${REGISTRY_USERNAME} +# password: ${REGISTRY_PASSWORD} +# webhookPath: events +# flavor: zot + +# Namespace where discovered Component/ComponentVersion resources are created +namespace: "" + +# Webhook service for event-driven registry notifications +service: + enabled: true + type: ClusterIP + port: 8080 + +# Production resource limits +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + +# Spread replicas across nodes for resilience +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - solar-discovery + topologyKey: kubernetes.io/hostname + +# CA bundle for private registry TLS trust +# Point to a ConfigMap containing your CA certificates +# (e.g., produced by trust-manager's root-bundle) +caBundle: + enabled: true + configMapName: registry-ca-bundle + key: trust-bundle.pem + +# Inject registry credentials from a Secret +# envFrom: +# - secretRef: +# name: registry-credentials + +# RBAC enabled +rbac: + create: true \ No newline at end of file diff --git a/solution-arsenal/README.md b/solution-arsenal/README.md new file mode 100644 index 0000000..ae931d2 --- /dev/null +++ b/solution-arsenal/README.md @@ -0,0 +1,47 @@ +# Solution Arsenal (SolAr) OCM Component + +This directory contains the OCM (Open Component Model) packaging for [Solution Arsenal (SolAr)](https://github.com/opendefensecloud/solution-arsenal), an application catalog and fleet rollout manager. + +## Component structure + +``` +solution-arsenal/ +├── component-constructor.yaml # OCM component descriptor +├── minimal-values.yaml # Helm values: single-instance dev/test profile +├── production-values.yaml # Helm values: HA production profile +``` + +## Prerequisites + +### Required +- **Kubernetes** +- **Helm** +- **cert-manager** + +## Quick start + +### 1. Build the CTF archive + +Run from the `solution-arsenal/` directory of this repo: + +```bash +ocm add componentversion --version 0.1.0 --create --file ./ctf component-constructor.yaml +``` + +### 2. Transfer to a registry + +```bash +# Public registry (replace with your org) +ocm transfer ctf --copy-local-resources ./ctf ghcr.io/your-org + +# Local registry for testing +ocm transfer ctf --copy-local-resources ./ctf localhost:5001 +``` + +The `--copy-local-resources` flag rewrites the image references inside the component to point to the target registry. The RGD picks up these rewritten references at runtime so images are pulled from the correct location. + +## Resources + +- [Solution Arsenal repository](https://github.com/opendefensecloud/solution-arsenal) +- [SolAr documentation](https://solar.opendefense.cloud) +- [OCM specification](https://ocm.software) diff --git a/solution-arsenal/component-constructor.yaml b/solution-arsenal/component-constructor.yaml new file mode 100644 index 0000000..db97415 --- /dev/null +++ b/solution-arsenal/component-constructor.yaml @@ -0,0 +1,72 @@ +components: + - name: opendefense.cloud/solution-arsenal + provider: + name: opendefense.cloud + labels: + - name: app.kubernetes.io/name + value: solution-arsenal + - name: app.kubernetes.io/component + value: solution-catalog + - name: app.kubernetes.io/part-of + value: solution-arsenal + resources: + # SolutionArsenal Helm Chart + - name: solution-arsenal-chart + type: helmChart + version: v0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/charts/solar:0.1.1 + + # API Server Container Image + - name: solution-arsenal-apiserver-image + type: ociImage + version: v0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/solar-apiserver:0.1.1 + + # Controller Manager Container Image + - name: solution-arsenal-controller-manager-image + type: ociImage + version: v0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/solar-controller-manager:0.1.1 + + # Renderer Container Image + - name: solution-arsenal-renderer-image + type: ociImage + version: 0.1.1 + relation: external + access: + type: ociArtifact + imageReference: ghcr.io/opendefensecloud/solar-renderer:0.1.1 + + # etcd Container Image + - name: etcd-image + type: ociImage + version: v3.6.10 + relation: external + access: + type: ociArtifact + imageReference: quay.io/coreos/etcd:v3.6.10 + + # Minimal Configuration (single instance, development) + - name: solution-arsenal-minimal-config + type: yaml + relation: local + input: + type: file + path: minimal-values.yaml + + # Production Configuration (HA with replicas, metrics enabled) + - name: solution-arsenal-production-config + type: yaml + relation: local + input: + type: file + path: production-values.yaml diff --git a/solution-arsenal/minimal-values.yaml b/solution-arsenal/minimal-values.yaml new file mode 100644 index 0000000..9e77b46 --- /dev/null +++ b/solution-arsenal/minimal-values.yaml @@ -0,0 +1,100 @@ +# Minimal SolutionArsenal Configuration +# Single-instance setup suitable for: +# - Development environments +# - Testing and evaluation +# - Resource-constrained environments (kind, minikube) +# - Non-HA scenarios + +# API Server - single instance, minimal resources +apiserver: + enabled: true + replicaCount: 1 + + image: + repository: ghcr.io/opendefensecloud/solar-apiserver + tag: latest + pullPolicy: IfNotPresent + + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + + service: + type: ClusterIP + port: 443 + +# Renderer - minimal resources +renderer: + image: + repository: ghcr.io/opendefensecloud/solar-renderer + tag: latest + +# Controller Manager - single instance, leader election disabled +controller: + enabled: true + replicaCount: 1 + + image: + repository: ghcr.io/opendefensecloud/solar-controller-manager + tag: latest + pullPolicy: IfNotPresent + + args: + healthProbeBindAddress: ":8081" + metricsBindAddress: "0" + metricsSecure: true + enableHTTP2: false + leaderElect: false + + metrics: + enabled: false + + resources: + limits: + cpu: 300m + memory: 128Mi + requests: + cpu: 100m + memory: 64Mi + +# etcd - single instance, minimal storage +etcd: + enabled: true + replicaCount: 1 + + image: + repository: quay.io/coreos/etcd + tag: v3.6.10 + pullPolicy: IfNotPresent + + persistence: + enabled: true + size: 1Gi + storageClass: "" + + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 10m + memory: 64Mi + +# cert-manager integration - self-signed issuer +certManager: + enabled: true + issuer: + create: true + kind: Issuer + selfSigned: true + certificate: + duration: 2160h # 90 days + renewBefore: 720h # 30 days + +# RBAC enabled +rbac: + create: true diff --git a/solution-arsenal/production-values.yaml b/solution-arsenal/production-values.yaml new file mode 100644 index 0000000..fe9ebe5 --- /dev/null +++ b/solution-arsenal/production-values.yaml @@ -0,0 +1,176 @@ +# Production SolutionArsenal Configuration +# Highly-available setup suitable for: +# - Production environments +# - Mission-critical workloads +# - Enterprise deployments + +# API Server - 3 replicas, HA with anti-affinity +apiserver: + enabled: true + replicaCount: 3 + + image: + repository: ghcr.io/opendefensecloud/solar-apiserver + tag: latest + pullPolicy: IfNotPresent + + resources: + limits: + cpu: 1000m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + + service: + type: ClusterIP + port: 443 + + # Spread replicas across nodes + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - solar + - key: app.kubernetes.io/component + operator: In + values: + - apiserver + topologyKey: kubernetes.io/hostname + +# Renderer - production resources +renderer: + image: + repository: ghcr.io/opendefensecloud/solar-renderer + tag: latest + +# Controller Manager - 3 replicas, leader election enabled +controller: + enabled: true + replicaCount: 3 + + image: + repository: ghcr.io/opendefensecloud/solar-controller-manager + tag: latest + pullPolicy: IfNotPresent + + args: + healthProbeBindAddress: ":8081" + metricsBindAddress: ":8443" + metricsSecure: true + enableHTTP2: false + leaderElect: true + + # Enable metrics for production monitoring + metrics: + enabled: true + service: + type: ClusterIP + port: 8443 + certManager: + enabled: true + serviceMonitor: + enabled: true + interval: 30s + scrapeTimeout: 10s + additionalLabels: + release: prometheus + + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 200m + memory: 128Mi + + # Spread replicas across nodes + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - solar + - key: app.kubernetes.io/component + operator: In + values: + - controller-manager + topologyKey: kubernetes.io/hostname + +# etcd - 3 replicas, production storage +etcd: + enabled: true + replicaCount: 3 + + image: + repository: quay.io/coreos/etcd + tag: v3.6.10 + pullPolicy: IfNotPresent + + persistence: + enabled: true + size: 20Gi + # storageClass: "fast-ssd" # Uncomment and set to your high-performance storage class + storageClass: "" + + resources: + limits: + cpu: 1000m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + + # Spread replicas across nodes + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - solar + - key: app.kubernetes.io/component + operator: In + values: + - etcd + topologyKey: kubernetes.io/hostname + +# cert-manager integration - ClusterIssuer for production +certManager: + enabled: true + issuer: + create: true + kind: ClusterIssuer + selfSigned: true + # Alternative: Use CA issuer if you have an internal CA + # ca: + # enabled: true + # secretName: "ca-key-pair" + # Alternative: Use Let's Encrypt ACME for public certificates + # acme: + # enabled: true + # server: "https://acme-v02.api.letsencrypt.org/directory" + # email: "admin@example.com" + # privateKeySecretRef: "letsencrypt-production" + certificate: + duration: 8760h # 1 year + renewBefore: 2160h # 90 days + +# RBAC enabled +rbac: + create: true