diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b8b0b6..6cf5d719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,8 @@ Releases up to 2.63.0 are listed in orchestrator-neutral ([#2099]) - The data-modeling template asks for one naming convention per store and marks its relational rules ([#2100]) +- The deployment template keeps target-neutral rules and drops its per-target + product choices ([#2101]) ### Deprecated @@ -203,6 +205,7 @@ Releases up to 2.63.0 are listed in [#2098]: https://github.com/solid-ai-dev/solid-ai-templates/pull/2098 [#2099]: https://github.com/solid-ai-dev/solid-ai-templates/pull/2099 [#2100]: https://github.com/solid-ai-dev/solid-ai-templates/pull/2100 +[#2101]: https://github.com/solid-ai-dev/solid-ai-templates/pull/2101 ## [2.90.0] - 2026-09-12 diff --git a/docs/migrating-to-v3.md b/docs/migrating-to-v3.md index f82f5870..0d140300 100644 --- a/docs/migrating-to-v3.md +++ b/docs/migrating-to-v3.md @@ -61,6 +61,7 @@ receives nothing (ADR-051). | The eight-stage pipeline order, its push and tag triggers, the three-environment minimum, the post-publish deploy hook | `base-cicd` | removed; the gates, packaging once, DAST before production and artifact promotion remain | | Kubernetes: namespaces, two replicas per service, probes, PodDisruptionBudget, ConfigMap secrets | `base-containers` | removed; resources as code and the readiness gate remain, orchestrator-neutral | | Exact names: plural snake_case tables, `is_` booleans, `_id` keys, alphabetical junctions, `ix_` and `ux_` indexes | `base-data-modeling` | one convention per store, recorded in the context file; relational rules say so | +| Per-target product choices: managed CAs, `step-ca`, F5 and MetalLB, Route 53 and Consul, Harbor and Athens, Vault topologies | `base-deployment` | removed; each section keeps its ID and the rules that hold on any target | | The numbered-document check after concurrent merges, the first-CI-run rule for a check on its own change | `base-git` | this repository's playbook; the `check-heading-numbers` hook still ships | | The submodule update after a pin bump, the base64 bundle mask, the `.vscode` allowlist | `base-git` | removed; a neutral editor-settings rule remains | | Factory classmethods; `*-overlay.png` naming | `base-oop`, `base-measurement` | neutral rules remain | diff --git a/templates/infra/deployment.md b/templates/infra/deployment.md index c4bfea48..bb651fe7 100644 --- a/templates/infra/deployment.md +++ b/templates/infra/deployment.md @@ -1,172 +1,79 @@ # Base — Deployment [ID: base-deployment] -Cross-cutting deployment rules. Covers deployment targets, certificates, load -balancing, service discovery, registries, secrets, and network assumptions. -Applies to every service regardless of language or framework. +Deployment rules that hold on any target: certificates, load balancing, +service discovery, registries, secrets, and network assumptions. The +products and topology a team adopts belong in its own stack or platform +template. ## Deployment targets [ID: base-deployment-targets] -Declare the deployment target explicitly in every project's context file. -All other rules in this document are qualified by target. - -| Target | Description | -|--------|-------------| -| `cloud` | Public cloud (AWS, GCP, Azure) — managed services, external CA, public DNS | -| `hybrid` | On-premises + cloud — private CA for internal traffic, public CA for external | -| `offline` | Air-gapped — no internet access; all dependencies pre-mirrored internally | - -A project may support more than one target. List all that apply and note -which sections of configuration differ per target. +- Declare each deployment target in the project's context file: cloud, + hybrid, offline (air-gapped), or another the project names +- Note which configuration differs per target ## Certificates and PKI [ID: base-deployment-certs] -**Cloud:** -- Use a managed CA: AWS ACM, GCP Certificate Manager, or Let's Encrypt via - ACME — do not manage certificates manually -- Automate renewal — never set a manual expiry reminder as the sole safeguard -- Terminate TLS at the load balancer or ingress; internal service-to-service - traffic may use mTLS via a service mesh - -**Hybrid:** -- Run an internal CA (Smallstep `step-ca`, HashiCorp Vault PKI, or CFSSL) - for all internal services -- Use a public CA (Let's Encrypt, ACM) for externally reachable endpoints only -- Distribute the internal root CA cert to all nodes via configuration - management — never distribute it manually -- Automate internal certificate rotation; treat certificates expiring without - renewal as an incident - -**Offline:** -- Internal CA is the only CA — no ACME against public endpoints -- Run an internal ACME server (Smallstep `step-ca` supports this) so services - can renew certificates automatically without internet access -- Pre-distribute the root CA cert in the base OS image or via configuration - management before first deployment -- Certificate revocation via internal CRL or OCSP responder — no external OCSP +- Automate certificate issuance and renewal — never rely on a manual expiry + reminder alone +- Treat a certificate expiring without renewal as an incident +- Distribute every trusted root certificate through configuration + management or the base image, never by hand +- Renew certificates and check revocation against endpoints the target can + reach; an offline target uses internal ones only ## Load balancing and reverse proxy [ID: base-deployment-lb] -**Cloud:** -- Use the cloud provider's managed load balancer (AWS ALB/NLB, GCP Load - Balancing, Azure Application Gateway) -- Prefer application-layer (L7) load balancing for HTTP services — enables - path-based routing, header inspection, and health checks -- Do not run a self-managed reverse proxy in front of a managed LB unless - there is a specific requirement (e.g. custom WAF rules) - -**Hybrid:** -- External traffic: managed cloud LB or hardware appliance (F5, Citrix ADC) - at the network boundary -- Internal traffic: software reverse proxy (NGINX, HAProxy, Traefik) or - service mesh (Istio, Linkerd) for east-west routing -- Ensure the internal LB is aware of both on-prem and cloud service endpoints - -**Offline:** -- Software load balancer only: HAProxy, NGINX, or Traefik — all run fully - offline with static or service-discovery-driven configuration -- Hardware appliances: F5 BIG-IP, Citrix ADC — common in government and - defence networks; configure via local management plane, not cloud APIs -- Kubernetes bare-metal: use MetalLB for `LoadBalancer` service type; - configure address pools from the local IP range +- Route public ingress through a load balancer or reverse proxy that + health-checks its backends; never make an instance directly + internet-routable +- Prefer application-layer (L7) load balancing for HTTP services — it + enables path-based routing, header inspection, and health checks ## Service discovery and DNS [ID: base-deployment-dns] -**Cloud:** -- Use the cloud provider's DNS service (Route 53, Cloud DNS, Azure DNS) -- Use cloud-native service discovery where available (AWS Cloud Map, - Kubernetes CoreDNS) -- Services should resolve each other by DNS name — never hardcode IPs - -**Hybrid:** -- Internal DNS: BIND or CoreDNS — authoritative for all internal zones -- Split-horizon DNS: internal zones resolve to private IPs; public zones - resolve to public IPs -- Dynamic service registration: Consul or etcd, integrated with DNS via - Consul DNS or CoreDNS plugins - -**Offline:** -- Internal DNS is the only DNS — no public resolver fallback -- All hostnames must resolve within the internal DNS zone before deployment -- Dynamic service discovery: Consul or etcd running on internal infrastructure -- NTP: sync all nodes from an internal time server — clock skew causes - certificate validation failures and distributed system bugs +- Resolve services by DNS name or service discovery — never hardcode IPs +- Confirm every hostname a service needs resolves on its target before + deployment +- Sync every node's clock from a time source the target can reach — clock + skew breaks certificate validation and distributed systems ## Container and artifact registries [ID: base-deployment-registries] -**Cloud:** -- Use a managed registry: AWS ECR, GCP Artifact Registry, GitHub Container - Registry, or Docker Hub (private) -- Enforce image signing and scan all images for vulnerabilities before - promotion to production - -**Hybrid:** -- Internal registry (Harbor, JFrog Artifactory, Sonatype Nexus) proxies and - caches images from public registries -- Air-gapped segments pull from the internal registry only — no direct - internet access from those segments -- Mirror required base images and dependencies into the internal registry - as part of the build pipeline - -**Offline:** -- All images and packages must be mirrored before the system is air-gapped: - - Container images → Harbor, Artifactory, or Nexus - - Go modules → Athens module proxy - - Python packages → devpi or Artifactory PyPI proxy - - npm packages → Verdaccio or Artifactory npm proxy -- Set `GOPROXY`, `PIP_INDEX_URL`, and `.npmrc` to point to internal mirrors - in all build environments -- Scan and approve all dependencies at the boundary before mirroring — - treat the mirror as a trusted internal supply chain artefact +- Sign every image and scan it for vulnerabilities before promotion to + production +- Mirror every image and package into an internal registry where the + target cannot reach public ones, and point every build environment at + the mirror +- Scan and approve each dependency before mirroring it — the mirror is a + trusted supply chain ## Secrets management [ID: base-deployment-secrets] -**Cloud:** -- Use the cloud provider's secrets service (AWS Secrets Manager, GCP Secret - Manager, Azure Key Vault) or HashiCorp Vault with a cloud backend -- Never pass secrets as environment variables baked into images — inject at - runtime via the secrets service or a Kubernetes `Secret` mounted as a volume +- Inject secrets at runtime from a secrets service; never bake them into an + image - Rotate secrets automatically; alert on rotation failures - -**Hybrid:** -- HashiCorp Vault with a replicated backend spanning on-prem and cloud, or - separate Vault clusters with cross-cluster replication -- Services authenticate to Vault using platform identity (IAM role, K8s - service account) — no static Vault tokens in configuration files - -**Offline:** -- HashiCorp Vault (runs fully offline), CyberArk, or a hardware HSM -- Vault unsealing must not depend on an external KMS — use Shamir secret - sharing with a defined key custodian process, or an internal HSM for - auto-unseal -- Establish a documented break-glass procedure for Vault recovery +- Authenticate services to the secrets service by platform identity — no + static tokens in configuration files +- Keep the secrets service's unseal and recovery free of anything the + target cannot reach, and document a break-glass procedure ## Network assumptions [ID: base-deployment-network] -Document network assumptions explicitly in the project context file. -Do not rely on implicit network access that may not exist in all targets. - -**Cloud:** -- Outbound internet access available unless restricted by VPC policy -- Public ingress via load balancer; services are not directly internet-routable -- Assume DNS, NTP, and package registries are reachable - -**Hybrid:** -- Define which network segments have internet access and which do not -- Services crossing the boundary must go through a defined ingress/egress point -- Firewall rules must be documented and version-controlled alongside the service - -**Offline:** -- No outbound internet access — any code that calls an external URL will fail -- Audit all dependencies for hidden external calls (telemetry, update checks, - licence validation) — disable or patch before deployment -- All required endpoints (DNS, NTP, registry, CA, OCSP) must be reachable - within the internal network before the service starts -- Document the full list of required internal endpoints in the project README +- Document network assumptions in the project's context file: which + segments reach the internet, and the internal endpoints a service needs + (DNS, NTP, registry, CA, OCSP) +- Route traffic that crosses a network boundary through a defined ingress + or egress point +- Keep firewall rules in version control beside the service +- Audit dependencies for hidden external calls (telemetry, update checks, + licence validation) on a target without outbound internet, and disable + them before deployment +- Make every required endpoint reachable before the service starts diff --git a/templates/manifest.yaml b/templates/manifest.yaml index cd6d88ac..6691cdd4 100644 --- a/templates/manifest.yaml +++ b/templates/manifest.yaml @@ -56,7 +56,7 @@ base: description: Env vars, secrets, fail-fast validation - id: base-deployment file: templates/infra/deployment.md - description: Deployment targets (cloud/hybrid/offline), certs, LB, registries, secrets + description: Deployment targets, certs, load balancing, DNS, registries, secrets, network - id: base-data-quality file: templates/data/data-quality.md description: Data sourcing, completeness, freshness, research, scoring — data-heavy projects diff --git a/tests/baselines/template-quality.txt b/tests/baselines/template-quality.txt index 89e0dec3..6679eeec 100644 --- a/tests/baselines/template-quality.txt +++ b/tests/baselines/template-quality.txt @@ -40,6 +40,6 @@ templates/frontend/static-site.md 84.2 templates/frontend/ux.md 94.3 templates/infra/cicd.md 95.7 templates/infra/containers.md 95.2 -templates/infra/deployment.md 95.4 +templates/infra/deployment.md 99.4 templates/security/devsecops.md 100.0 templates/security/security.md 96.1