Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions docs/migrating-to-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -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, `<table>_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 |
Expand Down
187 changes: 47 additions & 140 deletions templates/infra/deployment.md
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion templates/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/template-quality.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading