-
Notifications
You must be signed in to change notification settings - Fork 0
feat(deploy): add hardened Kubernetes reference deployment #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
f68c85d
1877894
d687825
8a7aa4d
1e127ec
7879fb8
31b623a
d4750c0
3f8a282
6b4fc61
95ef5b4
07c0dc3
e46d188
4dfaa3d
774d886
0d54610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| name: Kubernetes Reference Quality | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - develop | ||
| push: | ||
| branches: | ||
| - develop | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: kubernetes-reference-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| kubernetes-reference: | ||
| name: Hardened reference deployment contract | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - name: Checkout exact candidate | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| persist-credentials: false | ||
| - name: Prove exact candidate checkout | ||
| env: | ||
| EXPECTED_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| run: test "$(git rev-parse HEAD)" = "${EXPECTED_SHA}" | ||
| - name: Set up Node.js LTS | ||
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | ||
| with: | ||
| node-version: "24" | ||
| check-latest: false | ||
| - name: Exercise hardened Kubernetes reference contract | ||
| run: node --test tests/kubernetes-reference.test.mjs | ||
| - name: Validate repository contracts | ||
| run: npm run validate | ||
| - name: Prove clean checkout | ||
| run: | | ||
| git diff --exit-code | ||
| test -z "$(git status --porcelain)" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,3 +105,7 @@ The foundation starts as a monorepo with separately deployable services. Each se | |
| ## Security posture | ||
|
|
||
| Access is tenant-, actor-, purpose-, resource-, and lifetime-scoped. High-impact decisions require preview, explicit human confirmation, versioned evidence, immutable decision records, and attributable audit events. LLM outputs are draft evidence only. | ||
|
|
||
| ## Kubernetes reference deployment boundary | ||
|
|
||
| The active deployment lane carries the provider-neutral People API reference at `infrastructure/kubernetes/people-api-reference.json`. It is an architecture example for extracting the People API behind the same published API/data-ownership boundary; it does not authorize a release and does not make Kubernetes part of protected-branch runtime truth until this lane is integrated. The manifest keeps the image non-runnable until an immutable digest from an integrated protected revision is supplied, preserves Restricted Pod Security Admission and default-deny network isolation, and requires environment-specific node-CIDR, DNS, PostgreSQL, admission and CNI validation. No Kubernetes object may introduce direct cross-service application-table access or weaken Orgmetra's service-owned schema boundary. | ||
|
Comment on lines
+109
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Architecture update invalidates repository manifest After this architecture update, manifest.json retains the previous digest, byte count, and line count. Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Kubernetes reference deployment — primary-source doctoring | ||
|
|
||
| **Evidence state:** active-PR design evidence. These sources inform the Orgmetra-owned reference deployment; they do not constitute Kubernetes certification, cloud-provider compatibility, SOC 2 evidence by themselves, or release authorization. | ||
|
|
||
| ## APA 7 references | ||
|
|
||
| Kubernetes Authors. (n.d.). *Configure liveness, readiness and startup probes*. Kubernetes. Retrieved August 22, 2026, from https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | ||
|
|
||
| Kubernetes Authors. (n.d.). *Network policies*. Kubernetes. Retrieved August 22, 2026, from https://kubernetes.io/docs/concepts/services-networking/network-policies/ | ||
|
|
||
| Kubernetes Authors. (n.d.). *Pod Security Admission*. Kubernetes. Retrieved August 31, 2026, from https://kubernetes.io/docs/concepts/security/pod-security-admission/ | ||
|
|
||
| Kubernetes Authors. (n.d.). *Pod security standards*. Kubernetes. Retrieved August 22, 2026, from https://kubernetes.io/docs/concepts/security/pod-security-standards/ | ||
|
|
||
| Kubernetes Authors. (n.d.). *Specifying a disruption budget for your application*. Kubernetes. Retrieved August 22, 2026, from https://kubernetes.io/docs/tasks/run-application/configure-pdb/ | ||
|
|
||
| ## Design consequences recorded from the primary documentation | ||
|
|
||
| - **Probe roles stay separate.** Startup probes delay takeover by liveness/readiness while a process starts; liveness is for restart decisions; readiness controls whether a pod receives service traffic. Orgmetra therefore keeps `/health` dependency-free and uses `/ready` for owned PostgreSQL readiness rather than making database reachability a liveness condition. | ||
| - **Restricted pod intent is explicit and versioned.** The reference declares Restricted Pod Security Admission labels and a pod/container security context that avoids host namespaces, privileged mode and privilege escalation, runs non-root, uses `RuntimeDefault` seccomp and drops Linux capabilities. Kubernetes defines a per-mode `*-version` label; if version is not pinned, the admission controller uses `latest`. Orgmetra therefore pins `enforce`, `audit`, and `warn` to `v1.37` so the authored policy contract does not silently change when the control plane advances. A target on a different minor requires an explicit re-baseline and re-pin, not deletion of the version labels. | ||
| - **Network isolation starts deny-by-default.** A NetworkPolicy selecting all pods with both `Ingress` and `Egress` policy types establishes the namespace baseline. Required application and DNS flows are then explicit exceptions. Cluster networking must actually enforce NetworkPolicy before this is treated as isolation evidence. | ||
| - **PDB evidence is bounded.** `maxUnavailable: 1` applies to a controller-managed replicated Deployment and limits voluntary evictions; it is not evidence against involuntary node, process or dependency failures. | ||
|
|
||
| ## Out of scope for this evidence set | ||
|
|
||
| This doctoring file does not select a managed Kubernetes vendor, CNI, ingress controller, service mesh, cloud load balancer, registry, PostgreSQL provider or image signer. Those choices must be bound to their own current primary documentation and target-environment acceptance evidence before release. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Kubernetes reference deployment traceability | ||
|
|
||
| ## State legend | ||
|
|
||
| - **Protected-main truth:** accepted on `develop@9e3e4847510e1e612b48474ba42b177b8ed824df`. | ||
| - **Active PR:** implemented only on `feat/kubernetes-reference-deployment` until merged. | ||
| - **Dependency-active PR:** same-repository capability required for a runnable release but not copied into this branch. | ||
| - **Planned:** deliberately outside this bounded slice. | ||
|
|
||
| ## Requirement → evidence map | ||
|
|
||
| | Requirement | State | Executable / review evidence | | ||
| | --- | --- | --- | | ||
| | Provider-neutral Kubernetes reference is absent on protected main and cannot be mistaken for shipped deployment truth | Protected-main truth | Foundation implementation plan Task 10 plus initial RED exact head `18778945f2bdb9d6f42cebd7a3c71c18dad36352` | | ||
| | Reference uses immutable image identity rather than a mutable tag | Active PR | `infrastructure/kubernetes/people-api-reference.json`; sentinel requires digest resolution before apply; `tests/kubernetes-reference.test.mjs` | | ||
| | Pod uses Restricted-intent security context and no automatic API token | Active PR | Namespace labels, ServiceAccount, Deployment security contexts and adversarial manifest assertions | | ||
| | Pod Security Admission behavior is deterministic rather than implicitly drifting with `latest` | Active PR | `enforce-version`, `audit-version`, and `warn-version` are pinned to `v1.37`; `tests/kubernetes-reference.test.mjs`; exact RED head `6b4fc614b57ec09172b6d029a9ea07d2203ad42e`, run `33344167879`, job `99345037244` | | ||
| | Startup/liveness and readiness are not conflated | Active PR + dependency-active PR | Reference sends startup/liveness to `/health` and readiness to `/ready`; People API probe implementation is owned by PR #74 and must be integrated into the selected release image before this manifest can be runnable | | ||
| | Namespace traffic is deny-by-default | Active PR | `orgmetra-default-deny` plus exact People API ingress/PostgreSQL/DNS exceptions; network-policy assertions | | ||
| | Managed PostgreSQL adaptation cannot silently broaden egress | Active PR | `infrastructure/kubernetes/README.md` requires provider-approved exact private-network adaptation while preserving default deny | | ||
| | Voluntary disruption and rollout are bounded | Active PR | two replicas, `maxUnavailable: 0` rolling update, PDB `maxUnavailable: 1`, topology-spread preference | | ||
| | Target cluster validates object schemas/admission before deployment | Active PR | documented `kubectl apply --dry-run=server ...` precondition; actual target-cluster dry-run remains environment-specific release evidence | | ||
| | Release candidate has reproducible source/SBOM/provenance evidence | Dependency-active PR | PR #78; this branch does not duplicate its builder or evidence | | ||
| | Image/container build, signed attestation and verified deployable digest exist | Planned | must be produced from one accepted integrated protected head; sentinel intentionally keeps this reference non-runnable until then | | ||
| | Production metrics, ingress/TLS, secrets delivery, autoscaling and environment-specific SLOs are accepted | Planned | separate deployment/operability slices; not claimed here | | ||
|
|
||
| ## RED → repair evidence | ||
|
|
||
| The initial exact RED head `18778945f2bdb9d6f42cebd7a3c71c18dad36352` materialized Kubernetes Reference Quality run `32564001046`, job `97009809481`. The job proved exact checkout of that SHA and failed in the first contract step because `infrastructure/kubernetes/people-api-reference.json` and `infrastructure/kubernetes/README.md` did not exist. Six deployment-contract tests failed with `ENOENT`; repository validation and clean-checkout proof were therefore correctly skipped rather than treated as passing evidence. | ||
|
|
||
| A second acquisition-grade regression at exact head `6b4fc614b57ec09172b6d029a9ea07d2203ad42e` materialized run `33344167879`, job `99345037244`, proved exact checkout, and produced eight passing tests plus one intentional failure because `pod-security.kubernetes.io/enforce-version` was absent (`undefined` versus expected `v1.37`). The repair pins all three Pod Security Admission modes (`enforce`, `audit`, `warn`) to the authored Kubernetes minor and documents deliberate re-baselining for a target cluster on a different minor. | ||
|
|
||
| The repair adds only Orgmetra-owned reference-deployment artifacts and supporting evidence. It does not mutate a dedicated-writer CWL dependency, add cross-service SQL, publish an image, create cluster resources, or claim that a target cluster has accepted the objects. | ||
|
|
||
| ## Release boundary | ||
|
|
||
| A release operator must replace the image sentinel only with a verified digest from the same exact integrated protected revision that contains the required People API probe implementation and passes all applicable build, security, provenance, review, migration, rollback/recovery and target-environment checks together. The checked-in reference itself is therefore buyer-readable deployment intent, not release authorization. |
|
devin-ai-integration[bot] marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # Orgmetra Kubernetes reference deployment | ||
|
|
||
| This directory contains a provider-neutral **reference**, not a release artifact. Applying it does not authorize a release, does not certify a cluster, and does not replace environment-specific threat modelling or change approval. | ||
|
|
||
| ## Release precondition: immutable image identity | ||
|
|
||
| `people-api-reference.json` deliberately contains a non-runnable image sentinel. Before any server-side apply or rollout, replace it with an Orgmetra People API image qualified by a **verified 64-character lowercase SHA-256 image digest**: | ||
|
|
||
| ```text | ||
| ghcr.io/contextualwisdomlab/orgmetra-people-api@sha256:<64-lowercase-hex> | ||
| ``` | ||
|
|
||
| The digest must be resolved from the same integrated protected source revision that passed the applicable build, security, SBOM, provenance, migration, recovery, review and release-authorization gates. A mutable tag is not an acceptable substitute. The current repository reference does not publish such an image and therefore must remain non-runnable until that evidence exists. | ||
|
|
||
| The probe paths also assume the selected image contains the governed People API `/health` and `/ready` contracts. Do not deploy a protected revision that predates those endpoints merely to satisfy the manifest shape. | ||
|
|
||
| ## Pod hardening | ||
|
|
||
| The `orgmetra-system` namespace declares `pod-security.kubernetes.io/enforce=restricted` and matching `audit`/`warn` Restricted Pod Security Admission labels. It pins the policy contract with `pod-security.kubernetes.io/enforce-version=v1.37`, `pod-security.kubernetes.io/audit-version=v1.37`, and `pod-security.kubernetes.io/warn-version=v1.37`. The explicit version labels are deliberate: an omitted version uses the admission controller's `latest` policy, which can change the effective Restricted contract after a Kubernetes upgrade. The People API pod is non-root, uses `RuntimeDefault` seccomp, disables service-account token automount, privilege escalation, privileged mode and host namespaces, drops every Linux capability, and uses a read-only root filesystem. Because the root filesystem is read-only, the pod declares a dedicated `tmp-scratch` `emptyDir` mounted at `/tmp`; do not remove it and do not replace it with a `hostPath`. | ||
|
|
||
| Cluster operators must verify that admission controls actually enforce the intended Restricted profile. A target cluster whose supported policy minor differs from `v1.37` must not make the reference deployable by deleting or weakening the version labels. Re-baseline the policy deliberately against that cluster's authoritative Kubernetes documentation, update the pinned minor and regression evidence together, and prove the resulting objects with server-side dry-run before release. If the environment injects sidecars or init containers, those injected containers must independently satisfy the same effective policy. | ||
|
|
||
| ## Liveness and readiness | ||
|
|
||
| - startup and liveness use `GET /health`, which is process-liveness only; | ||
| - readiness uses `GET /ready`, which checks the People API's owned PostgreSQL dependency; | ||
| - dependency failure removes a pod from service traffic rather than making liveness depend on PostgreSQL. | ||
|
|
||
| The timing values are bounded reference defaults, not universal tuning values. Validate them against measured startup and dependency-recovery behaviour before production use. | ||
|
|
||
| ## Network isolation | ||
|
|
||
| The namespace starts from default-deny ingress and egress. The People API policy then permits only: | ||
|
|
||
| 1. TCP/8080 ingress from same-namespace pods explicitly labelled `orgmetra.cwl/people-api-client=true`; | ||
| 2. TCP/8080 ingress from the kubelet probe source range, modelled by the RFC 5737 TEST-NET-1 placeholder `192.0.2.0/24`. **Replace that `ipBlock.cidr` with the exact node CIDR your cluster's kubelet probes originate from** (or the documented per-node ranges); without it, a default-deny CNI drops HTTP health probes and every pod fails liveness; | ||
| 3. TCP/5432 egress to same-namespace pods labelled `app.kubernetes.io/name=orgmetra-postgres`; | ||
| 4. DNS to kube-system pods labelled `k8s-app=kube-dns` over UDP/TCP 53. | ||
|
|
||
| A **NetworkPolicy-capable CNI** is required. If the selected cluster networking implementation does not enforce Kubernetes NetworkPolicy, do not claim that this reference provides network isolation. | ||
|
|
||
| The checked-in PostgreSQL rule models an in-cluster owned database. For **managed PostgreSQL**, replace the database egress rule with the provider-approved private-network policy for the exact database endpoints while preserving default-deny semantics. Do not broaden egress to `0.0.0.0/0` as a convenience workaround. Likewise, adapt the DNS selector only to the cluster's authoritative DNS implementation and keep that exception narrowly scoped. | ||
|
|
||
| Keyverse, Naruon and other dedicated-writer CWL services are intentionally absent from this egress policy. Add a foreign-service network path only when a published adapter/API contract and environment-specific authorization design require it; never add cross-service application-table access. | ||
|
|
||
| ## Availability boundary | ||
|
|
||
| The reference uses two replicas, a rolling update with `maxUnavailable: 0`, and a PodDisruptionBudget with `maxUnavailable: 1`. The PDB constrains voluntary disruption only; it does not protect against node failure or application failure. A topology-spread preference reduces accidental same-node concentration but does not claim multi-zone disaster tolerance. | ||
|
|
||
| ## Pre-deployment verification | ||
|
|
||
| Do not apply the reference unchanged. After resolving the exact image digest and cluster-specific database/DNS networking, validate the candidate against the target API server: | ||
|
|
||
| ```bash | ||
| kubectl apply --dry-run=server -f infrastructure/kubernetes/people-api-reference.json | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Fresh-cluster validation always fails Without Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
| ``` | ||
|
|
||
| Then verify, at minimum, the target cluster's admission policy, NetworkPolicy enforcement, available resource quotas, image-pull authorization, probe behaviour, disruption semantics, PostgreSQL connectivity, migration compatibility, rollback/recovery procedure and immutable release evidence. A successful dry-run is necessary evidence for the target cluster but is not sufficient release authorization. | ||
Uh oh!
There was an error while loading. Please reload this page.