mirror of
https://github.com/kerberos-io/deployment.git
synced 2026-11-05 20:10:26 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5485f454b3 | ||
|
|
7d5574f90e | ||
|
|
ebd5fffd8b | ||
|
|
eaa6bd0367 | ||
|
|
21536ed1b0 | ||
|
|
711ace1f15 | ||
|
|
4d5d7e3c18 | ||
|
|
c643012993 | ||
|
|
913706fe3f | ||
|
|
d41b425035 | ||
|
|
718fdbe302 |
@@ -99,8 +99,9 @@ jobs:
|
||||
id: install-hub
|
||||
run: |
|
||||
helm repo add kerberos https://charts.kerberos.io
|
||||
bash scripts/check-hub-runtime.sh
|
||||
kubectl create namespace kerberos-hub
|
||||
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
sleep 10
|
||||
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
|
||||
kubectl get pods -A -o wide
|
||||
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
run: |
|
||||
helm repo add kerberos https://charts.kerberos.io
|
||||
kubectl create namespace kerberos-hub
|
||||
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
sleep 10
|
||||
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
|
||||
kubectl get pods -A -o wide
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Validate Kustomize and Garage on kind
|
||||
name: Validate Kustomize, Garage and Factory on kind
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -45,6 +45,28 @@ jobs:
|
||||
bash scripts/install-garage.sh
|
||||
test "$credential_hash" = "$(kubectl -n garage get secret garage-credentials -o jsonpath='{.data}' | sha256sum)"
|
||||
bash scripts/check-garage.sh --restart
|
||||
- name: Install legacy Factory and upgrade the actual base
|
||||
run: |
|
||||
kubectl apply -f base/namespaces/kerberos-factory.yaml
|
||||
kubectl apply -f base/factory/kerberos-factory-clusterrole.yaml
|
||||
kubectl create --dry-run=client -n kerberos-factory -f base/factory/kerberos-factory-deployment.yaml -o json |
|
||||
jq '
|
||||
del(.spec.template.spec.securityContext, .spec.template.spec.volumes) |
|
||||
.spec.template.spec.containers[0] |= (
|
||||
.image = "ghcr.io/uug-ai/factory:v2.0.11" |
|
||||
.ports = [{"containerPort":80,"protocol":"TCP"}] |
|
||||
del(.securityContext, .volumeMounts, .startupProbe, .readinessProbe, .livenessProbe) |
|
||||
.env |= map(
|
||||
if .name == "K8S_PROXY" then .value = "http://localhost:80"
|
||||
elif .name == "PORT" then .value = "80"
|
||||
else . end))' |
|
||||
kubectl apply -n kerberos-factory -f -
|
||||
kubectl create --dry-run=client -n kerberos-factory -f base/factory/kerberos-factory-service.yaml -o json |
|
||||
jq '.spec.ports[0].targetPort = 80' |
|
||||
kubectl apply -n kerberos-factory -f -
|
||||
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
|
||||
kubectl apply -k base/factory
|
||||
bash scripts/check-factory.sh
|
||||
- name: Collect deployment diagnostics
|
||||
if: failure()
|
||||
run: bash scripts/diagnose-deployment.sh
|
||||
|
||||
@@ -90,8 +90,9 @@ jobs:
|
||||
id: install-hub
|
||||
run: |
|
||||
helm repo add kerberos https://charts.kerberos.io
|
||||
bash scripts/check-hub-runtime.sh
|
||||
kubectl create namespace kerberos-hub
|
||||
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
|
||||
sleep 10
|
||||
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
|
||||
kubectl get pods -A -o wide
|
||||
|
||||
@@ -10,14 +10,20 @@ The ecosystem offers flexible installation options, supporting deployment in hyb
|
||||
|
||||
- [Agent](https://learn.uug.ai/docs/agent/)
|
||||
- [Factory](https://learn.uug.ai/docs/factory/)
|
||||
- [Vault](https://github.com/kerberos-io/vault)
|
||||
- [Hub](https://github.com/kerberos-io/hub)
|
||||
- [Vault](https://learn.uug.ai/docs/vault/)
|
||||
- [Hub](https://learn.uug.ai/docs/hub/)
|
||||
|
||||
## Continuous deployment
|
||||
|
||||
[<img src="https://github.com/kerberos-io/deployment/workflows/Deploy%20on%20Microk8s/badge.svg"/>](https://github.com/kerberos-io/deployment/actions/workflows/microk8s.yaml) [<img src="https://github.com/kerberos-io/deployment/workflows/Deploy%20on%20Kubernetes/badge.svg"/>](https://github.com/kerberos-io/deployment/actions/workflows/kind.yaml)
|
||||
[](https://github.com/uug-ai/deployment/actions/workflows/kind.yaml)
|
||||
[](https://github.com/uug-ai/deployment/actions/workflows/k3d.yaml)
|
||||
[](https://github.com/uug-ai/deployment/actions/workflows/microk8s.yaml)
|
||||
[](https://github.com/uug-ai/deployment/actions/workflows/kustomize.yaml)
|
||||
|
||||
This repository continuously tests the ecosystem deployment using GitHub Actions across various platforms. Refer to the badges for an overview of the operating systems and Kubernetes distributions we are deploying to. We welcome suggestions for additional automations to consider.
|
||||
These badges show the latest status of each GitHub Actions workflow on `main`.
|
||||
Select a badge to view its runs and platform-specific results. The deployment
|
||||
workflows continuously test the ecosystem across kind, k3d, and MicroK8s; the
|
||||
Kustomize workflow validates the Kustomize, Garage, and Factory setup.
|
||||
|
||||
Kubernetes examples and CI now use **Garage S3** for local object storage.
|
||||
See the [Garage setup guide](./base/garage/README.md) for generated credentials,
|
||||
@@ -32,20 +38,10 @@ example on fork PRs), CI emits a warning and skips delivery without masking
|
||||
deployment failures. Configured webhook delivery errors still fail the step.
|
||||
Failed deployment jobs collect pod events and bounded logs for diagnosis.
|
||||
|
||||
### Hardened Hub frontend
|
||||
### Security
|
||||
|
||||
The promoted frontend image requires Hub chart **0.170.0 or newer**, which
|
||||
provides port `8080`, non-root/read-only runtime settings and a writable `/tmp`
|
||||
mount. Both primary and demo frontends use these settings; Admin remains on its
|
||||
legacy image and port `80`. Keep `global.imageRegistry` empty for the supplied
|
||||
fully qualified `ghcr.io` image names. Service ports remain `80` and the frontend
|
||||
NodePort remains `32080`, targeting the container port named `http`.
|
||||
|
||||
Run `bash scripts/check-hub-runtime.sh` to check the published chart with these
|
||||
values before installation, or pass a local chart path as the first argument.
|
||||
When adding custom branding mounts, preserve the chart's `frontend-tmp` volume
|
||||
and `/tmp` mount. Existing deployments may require the explicit
|
||||
[HTTP port migration](https://github.com/kerberos-io/helm-charts/blob/main/charts/hub/README.md#recovering-a-duplicate-http-port-during-upgrades).
|
||||
We harden our container images and check our solutions for known CVEs. See the
|
||||
[Secure repository](https://github.com/uug-ai/secure) for our security work.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
||||
+44
-3
@@ -15,7 +15,7 @@ deploy, configure and observe Agents (one Deployment + Service per camera).
|
||||
|
||||
| File | Kind | Purpose |
|
||||
| ---- | ---- | ------- |
|
||||
| [`kerberos-factory-deployment.yaml`](./kerberos-factory-deployment.yaml) | `Deployment` | The Factory web app/API (`uugai/factory`), container port `80`. |
|
||||
| [`kerberos-factory-deployment.yaml`](./kerberos-factory-deployment.yaml) | `Deployment` | Hardened `ghcr.io/uug-ai/factory:v2.0.13`, pinned to its verified multi-architecture digest, container port `8080`. |
|
||||
| [`kerberos-factory-service.yaml`](./kerberos-factory-service.yaml) | `Service` | Exposes Factory on `NodePort` **30079** (a `LoadBalancer` variant is included, commented out). |
|
||||
| [`kerberos-factory-clusterrole.yaml`](./kerberos-factory-clusterrole.yaml) | `ClusterRole` + `ClusterRoleBinding` | Grants the `default` ServiceAccount in `kerberos-factory` the API access Factory needs to manage Agents. |
|
||||
|
||||
@@ -50,7 +50,47 @@ Other relevant environment variables:
|
||||
| `KERBEROS_AGENT_IMAGE` | `kerberos/agent:latest` | Image used when Factory creates an Agent. |
|
||||
| `KERBEROS_AGENT_MEMORY_LIMIT` | `256Mi` | Default memory limit for created Agents. |
|
||||
| `NAMESPACE` | `kerberos-factory` | Namespace Factory schedules Agents into. |
|
||||
| `K8S_PROXY` | `http://localhost:80` | Internal proxy address Factory calls for the `/kubernetes` API. |
|
||||
| `PORT` | `8080` | Unprivileged HTTP listener used by the hardened image. |
|
||||
| `K8S_PROXY` | `http://localhost:8080` | Internal proxy address Factory calls for the `/kubernetes` API. |
|
||||
|
||||
## Hardened runtime and upgrades
|
||||
|
||||
The image runs as UID/GID `65532:65532`, with a read-only root filesystem,
|
||||
all Linux capabilities dropped, privilege escalation disabled and the
|
||||
`RuntimeDefault` seccomp profile. The UI login named `root` is independent
|
||||
of the container's operating-system user.
|
||||
|
||||
Two disk-backed `emptyDir` volumes are writable:
|
||||
|
||||
- `/home/factory/config` receives missing seed configuration files.
|
||||
- `/tmp` is scratch space, including multipart uploads.
|
||||
|
||||
The pod's `fsGroup: 65532` makes these volumes writable without a root
|
||||
init container. They survive a container restart but are replaced with the
|
||||
pod. In this base's `configmap` mode, the global configuration is restored
|
||||
from the existing Kubernetes ConfigMap on startup; existing global/template
|
||||
ConfigMaps are not overwritten by image defaults. Keep the existing
|
||||
ServiceAccount token and RBAC: Factory manages Agents through the Kubernetes
|
||||
API even though its process is non-root.
|
||||
|
||||
Apply the Deployment and Service together when upgrading from a legacy
|
||||
port-80 image. The external Service port `80` and NodePort `30079` are unchanged;
|
||||
the Service now targets the named `http` port on container port `8080`.
|
||||
Startup, readiness and liveness probes use `/healthz`; this endpoint checks
|
||||
the HTTP process, not all downstream Kubernetes dependencies.
|
||||
|
||||
Back up any legacy configuration stored only in the old container before
|
||||
replacing its pod. For `FACTORY_CONFIGURATION=json`, replace the config
|
||||
`emptyDir` with a writable PVC and preserve its existing JSON files before
|
||||
upgrading. A PVC must support access by UID/GID `65532`; storage backends that
|
||||
do not honor `fsGroup` need matching permissions provisioned separately.
|
||||
|
||||
CI upgrades the last legacy release (`v2.0.11`) to these actual base manifests
|
||||
on kind. It checks the restricted runtime, Service routing, UI/login,
|
||||
ConfigMap bootstrap, saving settings and persistence after pod replacement.
|
||||
The [smoke test](../../scripts/check-factory.sh) changes settings and restarts
|
||||
Factory, so it refuses non-CI invocation and is intended only for disposable
|
||||
test clusters.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -122,7 +162,8 @@ supports other stores via `FACTORY_CONFIGURATION`:
|
||||
- `configmap` *(default here)* — config in ConfigMaps, no MongoDB.
|
||||
- `secret` — same as `configmap` but sensitive values are kept in Kubernetes Secrets
|
||||
(add `secrets` to the ClusterRole resources for this mode).
|
||||
- `json` — config in local JSON files on the pod, no MongoDB.
|
||||
- `json` — config in local JSON files, no MongoDB. Use a PVC at
|
||||
`/home/factory/config`; the default `emptyDir` is not durable across pods.
|
||||
- `mongodb` — legacy behaviour: Factory and Agents read config from MongoDB. For this
|
||||
you also need a reachable MongoDB and the corresponding `MONGODB_*` environment
|
||||
variables (e.g. via a `mongodb` ConfigMap mounted with `envFrom`).
|
||||
|
||||
@@ -18,9 +18,21 @@ spec:
|
||||
labels:
|
||||
app: factory
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 65532
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: factory
|
||||
image: ghcr.io/uug-ai/factory:v2.0.4
|
||||
image: ghcr.io/uug-ai/factory:v2.0.13@sha256:ade073660d911ca66d75b2abc298f1ddcbfbfe43aeed44e60fc1984b49b73d95
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
runAsGroup: 65532
|
||||
readOnlyRootFilesystem: true
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
@@ -29,8 +41,36 @@ spec:
|
||||
memory: 128Mi
|
||||
cpu: 100m
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
failureThreshold: 30
|
||||
periodSeconds: 2
|
||||
timeoutSeconds: 2
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 2
|
||||
volumeMounts:
|
||||
- name: factory-config
|
||||
mountPath: /home/factory/config
|
||||
- name: factory-tmp
|
||||
mountPath: /tmp
|
||||
env:
|
||||
- name: PORT
|
||||
value: "8080"
|
||||
- name: GIN_MODE
|
||||
value: release
|
||||
- name: KERBEROS_LOGIN_USERNAME
|
||||
@@ -55,5 +95,9 @@ spec:
|
||||
- name: FACTORY_ENVIRONMENT
|
||||
value: "kubernetes"
|
||||
- name: K8S_PROXY
|
||||
value: http://localhost:80
|
||||
|
||||
value: http://localhost:8080
|
||||
volumes:
|
||||
- name: factory-config
|
||||
emptyDir: {}
|
||||
- name: factory-tmp
|
||||
emptyDir: {}
|
||||
|
||||
@@ -10,7 +10,7 @@ spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
targetPort: http
|
||||
nodePort: 30079 # You can specify a port in the range 30000-32767 or let Kubernetes assign one automatically
|
||||
name: frontend
|
||||
protocol: TCP
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
# type: LoadBalancer
|
||||
# ports:
|
||||
# - port: 80
|
||||
# targetPort: 80
|
||||
# targetPort: http
|
||||
# name: frontend
|
||||
# protocol: TCP
|
||||
# selector:
|
||||
|
||||
@@ -155,6 +155,8 @@ kerberoshub:
|
||||
memory: 100Mi
|
||||
cpu: 100m
|
||||
api:
|
||||
# Chart 0.170.1 supplies non-root security contexts and writable /tmp.
|
||||
# Retain hub-api-tmp when overriding the chart's volume/mount lists.
|
||||
repository: ghcr.io/uug-ai/hub-api
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.11.31"
|
||||
|
||||
@@ -36,7 +36,7 @@ helmCharts:
|
||||
releaseName: hub
|
||||
namespace: kerberos-hub
|
||||
repo: https://charts.kerberos.io
|
||||
version: 0.84.0
|
||||
version: 0.170.1
|
||||
valuesFile: ../../base/hub/kerberos-hub-values.yaml
|
||||
valuesInline:
|
||||
license: "L/+FAwEBB2xpY2Vuc2UB/4YAAQIBB1BheWxvYWQBCgABCVNpZ25hdHVyZQEKAAAA/gMw/4YB/gEl/8wQACxnaXRodWIuY29tL3V1Zy1haS9odWItbGljZW5zZS9tb2RlbHMuTGljZW5zZf+BAwEBB0xpY2Vuc2UB/4IAAQwBAklkAf+EAAEDS2V5AQwAAQdDb21wYW55AQwAAQdFeHBUaW1lAQQAAQREYXlzAQQAAQdDYW1lcmFzAQQAAQVTaXRlcwEEAAEGVmF1bHRzAQQAAQpNZWRpYUxpbWl0AQQAAQlQZXJwZXR1YWwBAgABBkFjdGl2ZQECAAEJSXBBZGRyZXNzAQwAAAAY/4MBAQEIT2JqZWN0SUQB/4QAAQYBGAAAPf+COgEMAAAAAAAAAAAAAAAAAg9nZW5lcmljLWxpY2Vuc2UB+AJl6LAHsRMYAfoB0alKIAABEAEUARQDAQAB/gIAFlQqo9yJj1a3OH1+5iGjCPcz9VtrRuGfz/iuQEFohbCfSiZGAdHh16gEc59Z2kPaey+eJcwY0BQsBoipW7SwFRmcHkrWLuxt+Yzi2kvwmL4TN0quWqM4xxBzH1sejS6kZpPm7bw11JBsBuaNOYMbl5lgpPCFajWUH6GzfmuQlptNQKosocacI/9PaaqEUUM0ALjDZNSqqFwZPPsFh9WTeaHGbRbmwQRMPFDgaPCxiHnCCUagbvuVZeOQbKaR5gPTUfPQY/L4mrN9QnMxdzwUJgqm7FbTH4UhoZn6EEzNGTN6DbHhpx8lezzCRW8dzMNuK8R1igiORV5gdWOPzBMZlTgodIZRD07e8iAo2XqT/BWcqaJXutdqXltaiJKshh2QzStdv2WZUynVTguYIQJyBNhrXEkewKZA0UftcSemDPkCmp6VovMMveV4X3Cpzkm7ZHtE7j39At/kpuqY/icTEzRWYuQqEDtqXMVar84VOpgVhxeNrrqZniLq8o3ezRdwy0BJG5xT9cuMxq13ZB3Am9iqTSjx2mh5VZZeB33GjLVAtLscj8NoKWy7BThchXB9xwoiy2RLO8nE+EI8wPbg+ajb2Ta7AFyxHgJJU6cea+zEpiBMARwjPKqk2nn02xdfdqMzQ+E9e115sIqhotBM5RI7uBIf8DDwT93HLsJZRBAA"
|
||||
|
||||
@@ -26,7 +26,7 @@ helmCharts:
|
||||
releaseName: hub
|
||||
namespace: kerberos-hub
|
||||
repo: https://charts.kerberos.io
|
||||
version: 0.170.0
|
||||
version: 0.170.1
|
||||
valuesFile: ../../base/hub/kerberos-hub-values.yaml
|
||||
valuesInline:
|
||||
mqtt:
|
||||
|
||||
@@ -8,7 +8,7 @@ helmCharts:
|
||||
releaseName: hub
|
||||
namespace: kerberos-hub
|
||||
repo: https://charts.kerberos.io
|
||||
version: 0.170.0
|
||||
version: 0.170.1
|
||||
valuesFile: ../../base/hub/kerberos-hub-values.yaml
|
||||
valuesInline:
|
||||
kerberoshub:
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${CI:-false}" != true ]]; then
|
||||
echo "This smoke test changes Factory settings and restarts its pod. Run it only in a disposable CI cluster (CI=true)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temporary="$(mktemp -d)"
|
||||
pid=""
|
||||
stop_forward() {
|
||||
if [[ -n "$pid" ]]; then
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill "$pid"
|
||||
wait "$pid" || [[ "$?" == 143 ]]
|
||||
fi
|
||||
pid=""
|
||||
fi
|
||||
}
|
||||
cleanup() {
|
||||
stop_forward
|
||||
rm -f "$temporary/port-forward.log" "$temporary/login.json" "$temporary/config.json" "$temporary/saved.json" "$temporary/index.html"
|
||||
rmdir "$temporary"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
|
||||
kubectl -n kerberos-factory get deployment factory -o json | jq -e '
|
||||
.spec.template.spec as $pod |
|
||||
$pod.securityContext.fsGroup == 65532 and
|
||||
$pod.securityContext.seccompProfile.type == "RuntimeDefault" and
|
||||
($pod.containers[] | select(.name == "factory") |
|
||||
.securityContext.runAsNonRoot == true and
|
||||
.securityContext.runAsUser == 65532 and .securityContext.runAsGroup == 65532 and
|
||||
.securityContext.readOnlyRootFilesystem == true and
|
||||
.securityContext.allowPrivilegeEscalation == false and
|
||||
.securityContext.capabilities.drop == ["ALL"] and
|
||||
.ports == [{"name":"http","containerPort":8080,"protocol":"TCP"}] and
|
||||
any(.volumeMounts[]; .mountPath == "/home/factory/config") and
|
||||
any(.volumeMounts[]; .mountPath == "/tmp") and
|
||||
.startupProbe.httpGet.path == "/healthz" and
|
||||
.readinessProbe.httpGet.port == "http" and
|
||||
.livenessProbe.httpGet.port == "http")'
|
||||
kubectl -n kerberos-factory get service factory-nodeport -o json |
|
||||
jq -e '.spec.ports | any(.port == 80 and .targetPort == "http" and .nodePort == 30079)'
|
||||
kubectl -n kerberos-factory get configmap agent-global-config agent-template-config
|
||||
kubectl -n kerberos-factory exec deployment/factory -- /app/main healthcheck
|
||||
|
||||
forward() {
|
||||
kubectl -n kerberos-factory port-forward service/factory-nodeport 13979:80 > "$temporary/port-forward.log" 2>&1 &
|
||||
pid=$!
|
||||
for attempt in {1..30}; do
|
||||
if curl --fail --silent http://127.0.0.1:13979/healthz >/dev/null; then return; fi
|
||||
if ! kill -0 "$pid" 2>/dev/null; then break; fi
|
||||
sleep 1
|
||||
done
|
||||
cat "$temporary/port-forward.log" >&2
|
||||
echo "Factory Service port-forward did not become healthy." >&2
|
||||
exit 1
|
||||
}
|
||||
login() {
|
||||
curl --fail --silent --show-error -H 'Content-Type: application/json' \
|
||||
-d '{"username":"root","password":"kerberos"}' \
|
||||
http://127.0.0.1:13979/api/login > "$temporary/login.json"
|
||||
token="$(jq -er '.token | select(length > 0)' "$temporary/login.json")"
|
||||
if [[ "${GITHUB_ACTIONS:-false}" == true ]]; then echo "::add-mask::$token"; fi
|
||||
}
|
||||
forward
|
||||
curl --fail --silent --show-error http://127.0.0.1:13979/ > "$temporary/index.html"
|
||||
grep -qi '<html' "$temporary/index.html"
|
||||
test "$(curl --silent --output /dev/null --write-out '%{http_code}' http://127.0.0.1:13979/api/config)" = 401
|
||||
login
|
||||
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
|
||||
http://127.0.0.1:13979/api/config > "$temporary/config.json"
|
||||
jq -e '.data.type == "global"' "$temporary/config.json"
|
||||
jq '.data | .timezone = (if .timezone == "UTC" then "Etc/GMT+1" else "UTC" end)' \
|
||||
"$temporary/config.json" > "$temporary/saved.json"
|
||||
timezone="$(jq -r '.timezone' "$temporary/saved.json")"
|
||||
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
|
||||
-H 'Content-Type: application/json' --data-binary "@$temporary/saved.json" \
|
||||
http://127.0.0.1:13979/api/config | jq -e --arg timezone "$timezone" '.data.timezone == $timezone'
|
||||
kubectl -n kerberos-factory get configmap agent-global-config -o json |
|
||||
jq -e --arg timezone "$timezone" '.data["_source.json"] | fromjson | .timezone == $timezone'
|
||||
|
||||
pod_uid() {
|
||||
kubectl -n kerberos-factory get pods -l app=factory -o json |
|
||||
jq -er '[.items[] | select(.metadata.deletionTimestamp == null)][0].metadata.uid'
|
||||
}
|
||||
old_pod="$(pod_uid)"
|
||||
stop_forward
|
||||
kubectl -n kerberos-factory rollout restart deployment/factory
|
||||
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
|
||||
test "$old_pod" != "$(pod_uid)"
|
||||
forward
|
||||
login
|
||||
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
|
||||
http://127.0.0.1:13979/api/config | jq -e --arg timezone "$timezone" '.data.timezone == $timezone'
|
||||
kubectl -n kerberos-factory exec deployment/factory -- /app/main healthcheck
|
||||
echo "Factory passed: restricted runtime, Service routing, UI/auth/config, ConfigMap bootstrap and persisted settings after pod replacement."
|
||||
@@ -3,6 +3,8 @@ set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CHART="${1:-kerberos/hub}"
|
||||
version=()
|
||||
if [[ "$CHART" == kerberos/hub ]]; then version=(--version 0.170.1); fi
|
||||
|
||||
assert_contains() {
|
||||
if ! grep -Eq -- "$2" <<< "$1"; then
|
||||
@@ -19,7 +21,7 @@ nodeport="$(awk '
|
||||
assert_contains "$nodeport" 'targetPort: http$'
|
||||
assert_contains "$nodeport" 'nodePort: 32080'
|
||||
|
||||
rendered="$(helm template hub "$CHART" --values "$ROOT/base/hub/kerberos-hub-values.yaml" \
|
||||
rendered="$(helm template hub "$CHART" "${version[@]}" --values "$ROOT/base/hub/kerberos-hub-values.yaml" \
|
||||
--set mode=ui --set kerberoshub.frontend.demoEnabled=true)"
|
||||
if grep -q 'image: "docker.io/ghcr.io/' <<< "$rendered"; then
|
||||
echo "Fully qualified GHCR image was prefixed with docker.io" >&2
|
||||
@@ -41,4 +43,20 @@ for name in hub-frontend hub-frontend-demo; do
|
||||
assert_contains "$deployment" 'image: "ghcr.io/uug-ai/hub-frontend:v1.19.28"$'
|
||||
echo "OK: $name uses the promoted image and matching hardened runtime"
|
||||
done
|
||||
api="$(awk '
|
||||
function emit() { if (deployment && matched) printf "%s", block }
|
||||
/^---$/ { emit(); block=""; deployment=0; matched=0 }
|
||||
{ block=block $0 "\n" }
|
||||
/^kind: Deployment$/ { deployment=1 }
|
||||
/^ name: hub-api$/ { matched=1 }
|
||||
END { emit() }
|
||||
' <<< "$rendered")"
|
||||
for setting in 'runAsNonRoot: true' 'runAsUser: 65532' 'runAsGroup: 65532' \
|
||||
'fsGroup: 65532' 'readOnlyRootFilesystem: true' 'allowPrivilegeEscalation: false' \
|
||||
'type: RuntimeDefault' 'drop:' '- ALL' 'name: hub-api-tmp' \
|
||||
'emptyDir: \{\}' 'mountPath: /tmp'; do
|
||||
assert_contains "$api" "^[[:space:]]*(- )?$setting$"
|
||||
done
|
||||
assert_contains "$api" 'image: "ghcr.io/uug-ai/hub-api:v1.11.31"$'
|
||||
echo "OK: hub-api uses the promoted image, hardened security and writable scratch"
|
||||
echo "Deployment Hub runtime preflight passed."
|
||||
|
||||
@@ -3,7 +3,7 @@ set -uo pipefail
|
||||
|
||||
kubectl get pods,pvc -A -o wide
|
||||
kubectl get events -A --sort-by=.lastTimestamp
|
||||
for namespace in garage mongodb rabbitmq vernemq kerberos-vault kerberos-agent kerberos-hub; do
|
||||
for namespace in garage mongodb rabbitmq vernemq kerberos-vault kerberos-agent kerberos-hub kerberos-factory; do
|
||||
if ! pods="$(kubectl -n "$namespace" get pods -o name)"; then
|
||||
echo "::warning::Could not list pods in $namespace."
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user