Compare commits

..

1 Commits

Author SHA1 Message Date
Andrew Stoltz
eae7b4ed7a infra(cx2-5): DNS auth/NetPol substrate, air-gap landing, arm64 ARC runner + tenant landing manifests
- fc-dns: add OnePasswordItem CRD for DNS API keys + NetworkPolicy for Phase 0 auth hardening; bump dns-web image tag
- fc-landing: rewrite landing HTML to remove CDN dependencies (air-gap safe); add preview.html standalone preview
- github-runner: add TOOLCACHE_ARCH to install-ruby-toolcache.sh for arm64 support; add Dockerfile.arm64 for arm64 ARC runner image
- docs/gx10-tenant-landing: per-user Deployment+IngressRoute manifests (andrew/dustin/erik/fit/matt) + CUTOVER-RUNBOOK.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 11:53:26 -05:00
260 changed files with 18336 additions and 35185 deletions

View File

@@ -101,7 +101,7 @@ curl -sk -X DELETE https://dns.iamworkin.lan/api/v1/servers/<serverId>/zones/iam
- **StatefulSet PVC drift**: `volumeClaimTemplates` needs explicit `volumeMode: Filesystem` or ArgoCD SSA self-heals forever. See memory `feedback_argocd_statefulset_pvc_drift.md`.
- **IngressRoute namespace split**: this RKE2 Traefik install does not allow cross-namespace service refs. Keep the `IngressRoute`, backend `Service`, and TLS secret in the same namespace; if one host is shared across namespaces, duplicate the `Certificate` and move the route next to the destination service.
- **Public read-only hosts**: if a public host fronts a service that also exposes admin writes internally, add a Traefik route match like `Host(...) && (Method(GET) || Method(HEAD))` on the public edge instead of trusting the app to reject unsafe methods.
- **Public read-write allowlist hosts**: if a public host accepts a tightly bounded write surface (e.g. bootstrap-JWT POST), pin the allowlist as `(Method(GET) || Method(HEAD) || Method(POST) || Method(OPTIONS))`. PUT/PATCH/DELETE must still 404 at the route. Internal UpdateCenter hosts (`updatecenter.iamworkin.lan` / `updates.iamworkin.lan`) are the canonical example. Public UpdateCenter delivery hosts (`update.flowercore.io` / `updates.flowercore.io`) stay GET/HEAD-only and share-link gated until an explicit operator decision changes that posture.
- **Public read-write allowlist hosts**: if a public host accepts a tightly bounded write surface (e.g. bootstrap-JWT POST), pin the allowlist as `(Method(GET) || Method(HEAD) || Method(POST) || Method(OPTIONS))`. PUT/PATCH/DELETE must still 404 at the route. Track A's `updatecenter.iamworkin.lan` / `updates.iamworkin.lan` are the canonical example. The lint test enforces this invariant.
- **Traefik VIP netpols**: when a `NetworkPolicy` allows `10.0.56.200`, also allow the post-DNAT backend ports (`8443` for TLS plus `8080` or `8000` for HTTP) or Calico will drop the rewritten flow.
- **Auth-safe probes**: services behind API-key or global auth middleware should prefer `tcpSocket` probes unless `/health` is explicitly exempted before the middleware runs.
- **ArgoCD must use internal Gitea URL**: `http://gitea-clusterip.gitea.svc.cluster.local:3000/bluejay/bluejay-infra.git`, not the external HTTPS URL (step-ca cert isn't trusted by ArgoCD). The `ApplicationSet` and any hand-created `Application` must both use the internal URL.

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"name": "aistation-web-tls",
"namespace": "fc-aistation"
},
"spec": {
"dnsNames": [
"aistation.iamworkin.lan"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "step-ca-acme"
},
"secretName": "aistation-web-tls"
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:5000",
"AiStation__Appliance__FallbackEdition": "gx10",
"FLOWERCORE_AISTATION_EDITION": "gx10",
"FlowerCore__AgentZero__Enabled": "false",
"FlowerCore__DataDirectory": "/data",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/aistation.db",
"FlowerCore__Database__Provider": "Sqlite",
"FlowerCore__Editions__ProfileDirectory": "/app/editions",
"FlowerCore__Ollama__BaseUrl": "http://10.0.57.201:11434",
"FlowerCore__Operator__Enabled": "true",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.AiStation"
},
"kind": "ConfigMap",
"metadata": {
"labels": {
"app.kubernetes.io/name": "aistation-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "aistation-web-config",
"namespace": "fc-aistation"
}
}

View File

@@ -1,120 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "aistation-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "aistation-web",
"namespace": "fc-aistation"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "aistation-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-06-16T14:00:18-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5000",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "aistation-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "aistation-web-config"
}
}
],
"image": "localhost/fc-aistation-web:v20260619-aistation-eb9d513",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "aistation-web",
"ports": [
{
"containerPort": 5000,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/healthz",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"nodeSelector": {
"kubernetes.io/arch": "arm64"
},
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "aistation-web-data"
}
}
]
}
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "aistation-web",
"namespace": "fc-aistation"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`aistation.iamworkin.lan`)",
"services": [
{
"name": "aistation-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "aistation-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "aistation-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "aistation-web",
"namespace": "fc-aistation"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 5000
}
],
"selector": {
"app.kubernetes.io/name": "aistation-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,61 +0,0 @@
# FlowerCore Apple MDM on GX10
This directory deploys the NanoHUB `v0.2.0` substrate for Apple MDM protocol
traffic at `https://mdm.iamworkin.lan`.
## Runtime
- Namespace: `fc-apple-mdm`
- Image: `localhost/fc-apple-mdm-nanohub:v0.2.0-20260617`
- Upstream digest: `ghcr.io/micromdm/nanohub:latest@sha256:e36a50db2dc3d2bf736645e58712f622c04b05b28487390981905ef4d0be5fbd`
- Persistent state: `fc-apple-mdm-data` on `local-path`, mounted at `/var/lib/nanohub`
- File backend DSN: `/var/lib/nanohub/db`
- Required secret: `Secret/fc-apple-mdm-runtime`, key `NANOHUB_API_KEY`
- Optional later bridge secret: `NANOHUB_WEBHOOK_URL`
- Required CA mount: `ConfigMap/fc-apple-mdm-root-ca`, key `root_ca.crt`
- SCEP backend: noc1 systemd service `step-ca-apple-mdm-scep`, forwarded through
selectorless `Service/fc-apple-mdm-scep` and `EndpointSlice/fc-apple-mdm-scep-noc1`
to `10.0.56.10:9080`
NanoHUB API authentication is HTTP Basic with username `nanohub` and password
from `NANOHUB_API_KEY`.
## Public Surface
The Traefik route intentionally exposes only:
- `/version`
- `/mdm`
- `/checkin`
- `/scep`
NanoHUB APIs under `/api/v1/*` stay cluster-internal for MDM-N1. The
DeviceManagement bridge can use the ClusterIP service directly once its NanoHUB
client lane lands.
SCEP is backed by the dedicated Apple-MDM-specific RSA step-ca hierarchy on
noc1, not by the IAmWorkin ACME CA. The live profile URL is:
```text
https://mdm.iamworkin.lan/scep/apple-mdm-scep
```
Do not point `APPLE_MDM_SCEP_URL` at a placeholder URL or at the ECDSA
IAmWorkin ACME CA; Smallstep SCEP requires an RSA intermediate/decrypter path.
## Deployment Notes
1. Create or refresh the runtime Kubernetes Secret from the 1Password item
`FlowerCore Apple MDM Runtime` before sync. GX10 does not yet depend on the
1Password operator for this workload.
2. Import `localhost/fc-apple-mdm-nanohub:v0.2.0-20260617` into GX10 containerd
before ArgoCD syncs. The deployment uses `imagePullPolicy: Never`.
3. Ensure `mdm.iamworkin.lan` resolves to the GX10 Traefik VIP `10.0.56.200`
before cert-manager requests `Certificate/fc-apple-mdm-tls`.
4. Prove `https://mdm.iamworkin.lan/version` after ArgoCD converges.
5. Prove SCEP CA publication with
`curl -sk -o /dev/null -w '%{http_code} %{size_download}\n' 'https://mdm.iamworkin.lan/scep/apple-mdm-scep?operation=GetCACert'`.
This lane does not create an APNs MDM push certificate, enrollment profile,
managed Wi-Fi payload, managed app install, or supervised iPad enrollment. Those
remain MDM-N2 through MDM-N8.

View File

@@ -1,378 +0,0 @@
# FlowerCore Apple MDM NanoHUB workload for the GX10 cluster.
# Secret values are copied into Kubernetes Secrets out of band until the
# 1Password operator exists on GX10; never commit secret data here.
---
apiVersion: v1
kind: Namespace
metadata:
name: fc-apple-mdm
labels:
app.kubernetes.io/part-of: flowercore
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fc-apple-mdm-root-ca
namespace: fc-apple-mdm
data:
root_ca.crt: |
-----BEGIN CERTIFICATE-----
MIIBxDCCAWqgAwIBAgIRAPY357G6ow6zMAL5+4bS2kkwCgYIKoZIzj0EAwIwQDEa
MBgGA1UEChMRSUFtV29ya2luIEFDTUUgQ0ExIjAgBgNVBAMTGUlBbVdvcmtpbiBB
Q01FIENBIFJvb3QgQ0EwHhcNMjYwMzA4MTgwNzExWhcNMzYwMzA1MTgwNzExWjBA
MRowGAYDVQQKExFJQW1Xb3JraW4gQUNNRSBDQTEiMCAGA1UEAxMZSUFtV29ya2lu
IEFDTUUgQ0EgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ2n04X1
JZo5Zdq/i1Idv8+fqwZyAzBh7whbqj0SWsJL8UWRabCMqYCs7+dXO0xRSzqkwFDL
x+vooOai8RgRNhajRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/
AgEBMB0GA1UdDgQWBBRnuPPQR6iM/H6vOluiU3Sygayz8jAKBggqhkjOPQQDAgNI
ADBFAiEArQK9dYPGmAZsdYnjziuFVVE5NKZUcceYvGfGC+tLXUsCIAudF2zJrCRq
3mK50ZZET/fwTkJwiEF4824mjP8p1CKM
-----END CERTIFICATE-----
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fc-apple-mdm-data
namespace: fc-apple-mdm
labels:
app: fc-apple-mdm
app.kubernetes.io/name: fc-apple-mdm
app.kubernetes.io/part-of: flowercore
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: fc-apple-mdm
namespace: fc-apple-mdm
labels:
app: fc-apple-mdm
app.kubernetes.io/name: fc-apple-mdm
app.kubernetes.io/component: mdm
app.kubernetes.io/part-of: flowercore
spec:
replicas: 1
revisionHistoryLimit: 3
strategy:
type: Recreate
selector:
matchLabels:
app: fc-apple-mdm
template:
metadata:
labels:
app: fc-apple-mdm
app.kubernetes.io/name: fc-apple-mdm
app.kubernetes.io/component: mdm
app.kubernetes.io/part-of: flowercore
annotations:
fc.flowercore.io/healthz-anon: "true"
fc.flowercore.io/probe-path: "/version"
flowercore.io/audit-trace-id: "apple-mdm-nanohub-runtime-trace"
flowercore.io/root-ca-sha256: "a9120c88fa3ec735d790aa4cfeb61ac2946730338969015bebaccc08fe10535e"
prometheus.io/scrape: "false"
spec:
enableServiceLinks: false
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
fsGroup: 1654
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
containers:
- name: nanohub
image: localhost/fc-apple-mdm-nanohub:v0.2.0-20260617
imagePullPolicy: Never
ports:
- name: http
containerPort: 9004
protocol: TCP
env:
- name: HOME
value: "/var/lib/nanohub"
- name: NANOHUB_LISTEN
value: ":9004"
- name: NANOHUB_STORAGE
value: "file"
- name: NANOHUB_STORAGE_DSN
value: "/var/lib/nanohub/db"
- name: NANOHUB_CHECKIN
value: "true"
- name: NANOHUB_CA
value: "/etc/nanohub/ca/root_ca.crt"
- name: NANOHUB_API_KEY
valueFrom:
secretKeyRef:
name: fc-apple-mdm-runtime
key: NANOHUB_API_KEY
- name: NANOHUB_WEBHOOK_URL
valueFrom:
secretKeyRef:
name: fc-apple-mdm-runtime
key: NANOHUB_WEBHOOK_URL
optional: true
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
startupProbe:
httpGet:
path: /version
port: 9004
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
readinessProbe:
httpGet:
path: /version
port: 9004
periodSeconds: 10
failureThreshold: 3
livenessProbe:
tcpSocket:
port: 9004
initialDelaySeconds: 30
periodSeconds: 30
failureThreshold: 3
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: data
mountPath: /var/lib/nanohub
- name: tmp
mountPath: /tmp
- name: root-ca
mountPath: /etc/nanohub/ca
readOnly: true
volumes:
- name: data
persistentVolumeClaim:
claimName: fc-apple-mdm-data
- name: tmp
emptyDir: {}
- name: root-ca
configMap:
name: fc-apple-mdm-root-ca
items:
- key: root_ca.crt
path: root_ca.crt
---
apiVersion: v1
kind: Service
metadata:
name: fc-apple-mdm
namespace: fc-apple-mdm
labels:
app: fc-apple-mdm
app.kubernetes.io/name: fc-apple-mdm
app.kubernetes.io/part-of: flowercore
spec:
type: ClusterIP
selector:
app: fc-apple-mdm
ports:
- name: http
port: 80
targetPort: 9004
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: fc-apple-mdm-scep
namespace: fc-apple-mdm
labels:
app: fc-apple-mdm-scep
app.kubernetes.io/name: fc-apple-mdm-scep
app.kubernetes.io/part-of: flowercore
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 9080
protocol: TCP
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: fc-apple-mdm-scep-noc1
namespace: fc-apple-mdm
labels:
kubernetes.io/service-name: fc-apple-mdm-scep
app.kubernetes.io/name: fc-apple-mdm-scep
app.kubernetes.io/part-of: flowercore
addressType: IPv4
endpoints:
- addresses:
- 10.0.56.10
conditions:
ready: true
ports:
- name: http
port: 9080
protocol: TCP
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: fc-apple-mdm-tls
namespace: fc-apple-mdm
annotations:
flowercore.io/dns-preflight: "mdm.iamworkin.lan must resolve to 10.0.56.200 before ACME sync"
spec:
secretName: fc-apple-mdm-tls
issuerRef:
name: step-ca-acme
kind: ClusterIssuer
dnsNames:
- mdm.iamworkin.lan
duration: 720h
renewBefore: 240h
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: fc-apple-mdm
namespace: fc-apple-mdm
spec:
entryPoints:
- websecure
routes:
- match: Host(`mdm.iamworkin.lan`) && PathPrefix(`/scep`)
kind: Rule
services:
- name: fc-apple-mdm-scep
port: 80
- match: Host(`mdm.iamworkin.lan`) && (PathPrefix(`/mdm`) || PathPrefix(`/checkin`) || PathPrefix(`/version`))
kind: Rule
services:
- name: fc-apple-mdm
port: 80
tls:
secretName: fc-apple-mdm-tls
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-apple-mdm-default-deny
namespace: fc-apple-mdm
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-apple-mdm-netpol
namespace: fc-apple-mdm
spec:
podSelector:
matchLabels:
app: fc-apple-mdm
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
ports:
- port: 9004
protocol: TCP
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-devicemgmt
ports:
- port: 9004
protocol: TCP
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- port: 443
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-devicemgmt
ports:
- port: 80
protocol: TCP
- port: 8080
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-apple-mdm-acme-http-solver-allow
namespace: fc-apple-mdm
spec:
podSelector:
matchLabels:
acme.cert-manager.io/http01-solver: "true"
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
ports:
- port: 8089
protocol: TCP
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

View File

@@ -1,6 +0,0 @@
# ArgoCD discovers apps-gx10/* directories on the GX10 GitOps branch.
# This kustomization is for local previews and single-app validation.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- fc-apple-mdm.yaml

View File

@@ -1,54 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"ChatOptions__BehaviorRuleEngine__FallbackOllamaBaseUrl": "http://10.0.57.201:11434",
"ChatOptions__BehaviorRuleEngine__ModelName": "gemma3:4b",
"ChatOptions__BehaviorRuleEngine__OllamaBaseUrl": "http://10.0.57.201:11434",
"FlowerCore__AI__DefaultModelName": "gemma3:12b",
"FlowerCore__AI__Helpdesk__SentimentEscalation__Enabled": "true",
"FlowerCore__AI__IrcBridge__AllowActionExecution": "false",
"FlowerCore__AI__IrcBridge__DefaultProfileSlug": "it-helpdesk",
"FlowerCore__AI__IrcBridge__Enabled": "true",
"FlowerCore__AI__IrcBridge__MentionProfileSlug": "it-helpdesk",
"FlowerCore__AI__IrcBridge__MentionReactiveMode": "mentions-only",
"FlowerCore__AI__Memory__EmbeddingModel": "nomic-embed-text",
"FlowerCore__AI__Memory__EnableSharedIndexingBackfill": "true",
"FlowerCore__AI__Memory__SharedIndexingDatabasePath": "/data/chat-memory-index.db",
"FlowerCore__AI__Memory__UseOllamaEmbeddings": "true",
"FlowerCore__AI__Memory__UseSharedIndexingAdapter": "true",
"FlowerCore__AI__OllamaBaseUrl": "http://10.0.57.201:11434",
"FlowerCore__AI__Skills__Intranet__IntranetBaseUrl": "http://intranet-web.intranet.svc.cluster.local",
"FlowerCore__AI__Skills__Intranet__PublicBaseUrl": "https://intranet.iamworkin.lan",
"FlowerCore__AI__Skills__Intranet__SearchBaseUrl": "https://intranet.iamworkin.lan",
"FlowerCore__AI__Skills__Library__LibraryApiUrl": "http://library-web.fc-library.svc.cluster.local",
"FlowerCore__AI__Skills__Print__PrintMcpBaseUrl": "http://10.0.57.16:5200",
"FlowerCore__AI__Skills__Retail__RetailApiUrl": "http://retail-web.fc-retail.svc.cluster.local",
"FlowerCore__AI__Voice__OutputRoot": "/data/audio",
"FlowerCore__AI__Voice__Piper__Host": "10.0.57.17",
"FlowerCore__AI__Voice__Piper__Port": "10400",
"FlowerCore__AI__Voice__RetentionDays": "30",
"FlowerCore__Anthropic__BaseUrl": "https://api.anthropic.com",
"FlowerCore__Anthropic__CheapModel": "claude-haiku-4-5-20251001",
"FlowerCore__Anthropic__DeepModel": "claude-opus-4-7",
"FlowerCore__Anthropic__DefaultModel": "claude-sonnet-4-6",
"FlowerCore__Anthropic__Enabled": "false",
"FlowerCore__Auth__Enabled": "false",
"FlowerCore__Auth__Oidc__Audience": "chat",
"FlowerCore__Auth__Oidc__Authority": "https://id.iamworkin.lan/application/o/chat/",
"FlowerCore__Auth__Oidc__ClientId": "chat",
"FlowerCore__Auth__Oidc__Enabled": "true",
"FlowerCore__Budget__ResponseCacheEnabled": "true",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/chat.db",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.Chat"
},
"kind": "ConfigMap",
"metadata": {
"name": "chat-web-config",
"namespace": "fc-chat"
}
}

View File

@@ -1,187 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "chat-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "chat-web",
"namespace": "fc-chat"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "chat-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/healthz",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "chat-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "FlowerCore__Auth__Oidc__Authority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "chat-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "chat-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "chat-oidc-client",
"optional": true
}
}
}
],
"envFrom": [
{
"configMapRef": {
"name": "chat-web-config"
}
},
{
"secretRef": {
"name": "chat-web-secret",
"optional": true
}
}
],
"image": "localhost/fc-chat-web:v20260621-rum2-ace701d-db838f5",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "chat-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "temp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "chat-web-data"
}
},
{
"emptyDir": {},
"name": "temp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "chat-web-public",
"namespace": "fc-chat"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`chat.flowercore.io`) && (Path(`/`) || Path(`/chat`) || PathPrefix(`/_blazor`) || PathPrefix(`/_framework`) || PathPrefix(`/_content`) || PathPrefix(`/avatars`) || PathPrefix(`/css`) || PathPrefix(`/js`) || PathPrefix(`/favicon`) || PathPrefix(`/chathub`)) && (Method(`GET`) || Method(`HEAD`) || Method(`POST`) || Method(`OPTIONS`))",
"priority": 100,
"services": [
{
"name": "chat-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "cf-origin-flowercore-io"
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "chat-web",
"namespace": "fc-chat"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`chat.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "chat-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "chat-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "chat-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "chat-web",
"namespace": "fc-chat"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "chat-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"name": "remotedesktop-tls",
"namespace": "fc-desktop"
},
"spec": {
"dnsNames": [
"desktop.iamworkin.lan"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "step-ca-acme"
},
"secretName": "remotedesktop-tls"
}
}

View File

@@ -1,93 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "remotedesktop-operator",
"app.kubernetes.io/part-of": "flowercore-remotedesktop"
},
"name": "remotedesktop-operator",
"namespace": "fc-desktop"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "remotedesktop-operator"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"labels": {
"app.kubernetes.io/name": "remotedesktop-operator",
"app.kubernetes.io/part-of": "flowercore-remotedesktop"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "RemoteDesktop__WebUrl",
"value": "http://remotedesktop-web.fc-desktop.svc.cluster.local.:8080"
}
],
"image": "localhost/fc-remotedesktop-operator:gx10-v1",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": "http",
"scheme": "HTTP"
},
"initialDelaySeconds": 15,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "operator",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": "http",
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"periodSeconds": 15,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"serviceAccount": "remotedesktop-operator",
"serviceAccountName": "remotedesktop-operator",
"terminationGracePeriodSeconds": 30
}
}
}
}

View File

@@ -1,331 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "remotedesktop-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "remotedesktop-web",
"namespace": "fc-desktop"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "remotedesktop-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"labels": {
"app.kubernetes.io/name": "remotedesktop-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"initContainers": [
{
"command": [
"sh",
"-c",
"chown -R 1654:1654 /app/data"
],
"image": "localhost/fc-remotedesktop-web:v20260621-rd-lsio-3d510aa",
"imagePullPolicy": "IfNotPresent",
"name": "fix-data-permissions",
"resources": {
"limits": {
"cpu": "100m",
"memory": "128Mi"
},
"requests": {
"cpu": "10m",
"memory": "32Mi"
}
},
"securityContext": {
"runAsGroup": 0,
"runAsUser": 0
},
"volumeMounts": [
{
"mountPath": "/app/data",
"name": "data"
}
]
}
],
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:8080"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "FlowerCore__Database__ConnectionStrings__Sqlite",
"value": "Data Source=/app/data/remotedesktop.db"
},
{
"name": "RemoteDesktop__Mode",
"value": "Remote"
},
{
"name": "RemoteDesktop__EnableApiDocs",
"value": "true"
},
{
"name": "RemoteDesktop__PoolWarmupEnabled",
"value": "false"
},
{
"name": "RemoteDesktop__PoolWarmupIntervalSeconds",
"value": "60"
},
{
"name": "RemoteDesktop__OrphanReconciler__Enabled",
"value": "true"
},
{
"name": "RemoteDesktop__OrphanReconciler__IntervalSeconds",
"value": "300"
},
{
"name": "RemoteDesktop__OrphanReconciler__GraceSeconds",
"value": "600"
},
{
"name": "RemoteDesktop__Audit__Enabled",
"value": "true"
},
{
"name": "RemoteDesktop__Audit__DualWrite",
"value": "true"
},
{
"name": "RemoteDesktop__UserVolumeClaimInitializer",
"value": "KubernetesExec"
},
{
"name": "RemoteDesktop__KubernetesNamespace",
"value": "fc-desktop"
},
{
"name": "RemoteDesktop__GuacamoleUrl",
"value": "http://guacamole.guacamole.svc.cluster.local.:8080/guacamole"
},
{
"name": "RemoteDesktop__GuacamolePublicUrl",
"value": "https://desktop.iamworkin.lan/guacamole"
},
{
"name": "RemoteDesktop__GuacamoleAdminUser",
"value": "guacadmin"
},
{
"name": "RemoteDesktop__GuacamoleJsonSecretKey",
"valueFrom": {
"secretKeyRef": {
"key": "password",
"name": "remotedesktop-guacamole-json-auth"
}
}
},
{
"name": "RemoteDesktop__TraefikClusterIp",
"value": "10.43.234.103"
},
{
"name": "RemoteDesktop__TraefikHostAliases__0",
"value": "chat.iamworkin.lan"
},
{
"name": "RemoteDesktop__TraefikHostAliases__1",
"value": "desktop.iamworkin.lan"
},
{
"name": "RemoteDesktop__TraefikHostAliases__2",
"value": "gitea.iamworkin.lan"
},
{
"name": "RemoteDesktop__TraefikHostAliases__3",
"value": "intranet.iamworkin.lan"
},
{
"name": "RemoteDesktop__TraefikHostAliases__4",
"value": "print.iamworkin.lan"
},
{
"name": "RemoteDesktop__TraefikHostAliases__5",
"value": "selenium.iamworkin.lan"
},
{
"name": "RemoteDesktop__NfsServer",
"value": "10.0.58.3"
},
{
"name": "RemoteDesktop__NfsBasePath",
"value": "/volume1/kubernetes/remotedesktop/users"
},
{
"name": "RemoteDesktop__SessionRecordingBasePath",
"value": "/var/lib/guacamole/recordings"
},
{
"name": "RemoteDesktop__MaxSessionsPerUser",
"value": "3"
},
{
"name": "FlowerCore__Auth__Oidc__Authority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "remotedesktop-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "remotedesktop-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "remotedesktop-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Enabled",
"value": "false"
},
{
"name": "FlowerCore__Auth__Oidc__Enabled",
"value": "false"
}
],
"envFrom": [
{
"secretRef": {
"name": "remotedesktop-secrets",
"optional": true
}
}
],
"image": "localhost/fc-remotedesktop-web:v20260621-rd-lsio-3d510aa",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 15,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"startupProbe": {
"failureThreshold": 60,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/app/data",
"name": "data"
},
{
"mountPath": "/var/lib/guacamole/recordings",
"name": "recordings",
"readOnly": true,
"subPath": "guacamole/recordings"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"serviceAccount": "remotedesktop-web",
"serviceAccountName": "remotedesktop-web",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "remotedesktop-data"
}
},
{
"name": "recordings",
"nfs": {
"path": "/volume1/kubernetes",
"server": "10.0.58.3"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "remotedesktop-web",
"namespace": "fc-desktop"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`desktop.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "remotedesktop-web",
"port": 8080
}
]
}
],
"tls": {
"secretName": "remotedesktop-tls"
}
}
}

View File

@@ -1,24 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "remotedesktop-web",
"namespace": "fc-desktop"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 8080,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "remotedesktop-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,8 +0,0 @@
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "remotedesktop-operator",
"namespace": "fc-desktop"
}
}

View File

@@ -1,8 +0,0 @@
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "remotedesktop-web",
"namespace": "fc-desktop"
}
}

View File

@@ -1,67 +0,0 @@
# FlowerCore DeviceManagement on GX10
This adopted GX10 app hosts `FlowerCore.DeviceManagement.Web` at
`https://devices.iamworkin.lan`. Agent-only REST/SignalR callbacks can use
`https://devices-agent.iamworkin.lan`, which is a separate Traefik router that
requires a TLS client certificate and forwards the presented certificate to the
app. Traefik v3.6 currently forwards raw base64 DER in
`X-Forwarded-Tls-Client-Cert`; the app also accepts URL-escaped PEM for
compatibility with older/alternate Traefik shapes.
## Apple MDM Runtime Contract
Apple MDM is enabled in NanoHUB mode, but enrollment remains unavailable until
the runtime secret contains real Apple-side material. Do not use placeholder
values to clear readiness checks.
`Secret/fc-devicemgmt-runtime` supports these Apple MDM keys:
| Key | Purpose |
| --- | --- |
| `DEVICE_MANAGEMENT_OPERATOR_API_KEY` | Required operator API key for authenticated REST/MCP write operations, including Android command queueing. |
| `DEVICE_MANAGEMENT_ADMIN_API_KEY` | Required admin API key for privileged DeviceManagement operations. |
| `DEVICE_MANAGEMENT_AGENT_API_KEY` | Required scoped agent credential for REST agent callbacks when TLS terminates before Kestrel; maps to `Auth:AgentApiKey` and `FlowerCore:Auth:AgentApiKey`. |
| `DEVICE_MANAGEMENT_ENROLLMENT_CA_CERTIFICATE_PEM` | Optional persistent enrollment CA certificate PEM; maps to `FlowerCore:DeviceManagement:EnrollmentCertificateAuthorityCertificatePem`. Live on GX10 for the agent client-cert chain currently trusted by Traefik. |
| `DEVICE_MANAGEMENT_ENROLLMENT_CA_PRIVATE_KEY_PEM` | Optional private key PEM matching the persistent enrollment CA certificate; maps to `FlowerCore:DeviceManagement:EnrollmentCertificateAuthorityPrivateKeyPem`. |
| `NANOHUB_API_KEY` | NanoHUB API password for HTTP Basic user `nanohub`. |
| `APPLE_MDM_APNS_TOPIC` | MDM APNs topic returned after uploading the Apple MDM push certificate to NanoHUB/NanoMDM. |
| `APPLE_MDM_SCEP_URL` | Live SCEP URL included in the enrollment profile. |
| `APPLE_MDM_SCEP_CHALLENGE` | SCEP challenge shared with the SCEP provisioner. |
| `APPLE_MDM_PROFILE_SIGNING_CERTIFICATE_PEM` | PEM certificate used to CMS-sign `.mobileconfig` profiles. |
| `APPLE_MDM_PROFILE_SIGNING_PRIVATE_KEY_PEM` | PEM private key matching the profile-signing certificate. |
| `APPLE_MDM_REQUIRE_MANAGED_WIFI_PAYLOAD` | Set to `true` only when Wi-Fi payload delivery should gate enrollment readiness. |
| `APPLE_MDM_MANAGED_WIFI_SSID` | Managed Wi-Fi SSID for the iPad profile. |
| `APPLE_MDM_MANAGED_WIFI_PASSWORD` | Managed Wi-Fi password when the network is not open. |
Non-secret profile constants stay in GitOps: NanoHUB base URL, MDM server URL,
check-in URL, organization/display names, the HTTPS trust anchor certificate,
managed Wi-Fi encryption type, auto-join, and MAC-randomization disablement.
DeviceManagement auth is enabled on GX10. The deployment maps
`DEVICE_MANAGEMENT_OPERATOR_API_KEY` to both `Auth__ApiKey` and
`FlowerCore__Auth__ApiKey`; the unprefixed key keeps the MCP API key post-config
path aligned with REST auth. Agent heartbeat, inventory, command poll, app-catalog,
and command-result callbacks use the agent-specific authorization boundary: the
server validates a direct device client certificate when Kestrel receives one,
validates Traefik-forwarded client certificates only on
`devices-agent.iamworkin.lan`, and also accepts only the scoped
`DEVICE_MANAGEMENT_AGENT_API_KEY` via `Authorization: Bearer` or
`X-Agent-Api-Key` as the fallback path. Operator write endpoints must use
`X-Api-Key`.
The agent-only Traefik route uses `RequireAndVerifyClientCert` with
`Secret/devicemgmt-agent-client-ca`, derived from the persistent
DeviceManagement enrollment CA. The application still matches the forwarded
client certificate thumbprint to the enrolled device record, but unauthenticated
clients are now rejected during TLS before reaching the agent REST route.
## Readiness Check
After changing the runtime secret and letting the pod roll, verify:
```bash
curl -sk https://devices.iamworkin.lan/api/v1/apple-mdm/enrollment-profile/status
```
Configurator enrollment must wait until this status reports `available=true`
and an empty `missingRequirements` array.

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"name": "fc-devicemgmt-agent-tls",
"namespace": "fc-devicemgmt"
},
"spec": {
"dnsNames": [
"devices-agent.iamworkin.lan"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "step-ca-acme"
},
"secretName": "fc-devicemgmt-agent-tls"
}
}

View File

@@ -1,183 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "fc-devicemgmt-operator",
"app.kubernetes.io/component": "operator",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-operator",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-devicemgmt-operator",
"namespace": "fc-devicemgmt"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app": "fc-devicemgmt-operator"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"annotations": {
"flowercore.io/audit-trace-id": "runtime-activity-trace",
"prometheus.io/path": "/metrics",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app": "fc-devicemgmt-operator",
"app.kubernetes.io/component": "operator",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-operator",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",
"value": "false"
},
{
"name": "POD_NAME",
"valueFrom": {
"fieldRef": {
"apiVersion": "v1",
"fieldPath": "metadata.name"
}
}
},
{
"name": "POD_NAMESPACE",
"valueFrom": {
"fieldRef": {
"apiVersion": "v1",
"fieldPath": "metadata.namespace"
}
}
},
{
"name": "FLOWERCORE_KUBERNETES_OWNER_DEPLOYMENT",
"value": "fc-devicemgmt-operator"
},
{
"name": "FlowerCore__Service__Name",
"value": "FlowerCore.DeviceManagement.Operator"
},
{
"name": "FlowerCore__DeviceManagement__DefaultTenantId",
"value": "system"
}
],
"image": "localhost/fc-devicemgmt-operator:gx10-v1",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 20,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"name": "operator",
"ports": [
{
"containerPort": 8080,
"name": "metrics",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 5,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "50m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"serviceAccount": "fc-devicemgmt-operator",
"serviceAccountName": "fc-devicemgmt-operator",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,450 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "fc-devicemgmt-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-devicemgmt-web",
"namespace": "fc-devicemgmt"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app": "fc-devicemgmt-web"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": 0,
"maxUnavailable": 1
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/healthz",
"flowercore.io/audit-trace-id": "runtime-activity-trace",
"kubectl.kubernetes.io/restartedAt": "2026-05-20T11:29:46-05:00",
"operator.1password.io/last-restarted": "2026-05-20T16:29:03Z",
"prometheus.io/path": "/metrics",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app": "fc-devicemgmt-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:8080"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",
"value": "false"
},
{
"name": "HOME",
"value": "/data"
},
{
"name": "FlowerCore__Service__Name",
"value": "FlowerCore.DeviceManagement.Web"
},
{
"name": "FlowerCore__DeviceManagement__DefaultTenantId",
"value": "system"
},
{
"name": "FlowerCore__Database__Provider",
"value": "Sqlite"
},
{
"name": "FlowerCore__Database__ConnectionStrings__Sqlite",
"value": "Data Source=/data/devicemgmt.db"
},
{
"name": "FlowerCore__Database__Password",
"valueFrom": {
"secretKeyRef": {
"key": "DB-Password",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__Auth__Enabled",
"value": "true"
},
{
"name": "Auth__ApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_OPERATOR_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__Auth__ApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_OPERATOR_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "Auth__AdminApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_ADMIN_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__Auth__AdminApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_ADMIN_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "Auth__AgentApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_AGENT_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__Auth__AgentApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_AGENT_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__DeviceManagement__EnrollmentCertificateAuthorityCertificatePem",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_ENROLLMENT_CA_CERTIFICATE_PEM",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__EnrollmentCertificateAuthorityPrivateKeyPem",
"valueFrom": {
"secretKeyRef": {
"key": "DEVICE_MANAGEMENT_ENROLLMENT_CA_PRIVATE_KEY_PEM",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AgentMtls__ForwardedCertificateHosts__0",
"value": "devices-agent.iamworkin.lan"
},
{
"name": "FlowerCore__DeviceManagement__AgentMtls__ForwardedCertificateHeader",
"value": "X-Forwarded-Tls-Client-Cert"
},
{
"name": "FlowerCore__EventBus__Redis__Configuration",
"value": "redis.fc-redis.svc:6379"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__Enabled",
"value": "true"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__GatewayMode",
"value": "nanohub"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__NanoHubBaseUrl",
"value": "http://fc-apple-mdm.fc-apple-mdm.svc"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__NanoHubApiUserName",
"value": "nanohub"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__NanoHubNanoMdmApiPath",
"value": "/api/v1/nanomdm/"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__EnrollmentProfileDownloadUrl",
"value": "https://devices.iamworkin.lan/api/v1/apple-mdm/enrollment-profile.mobileconfig"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__MdmServerUrl",
"value": "https://mdm.iamworkin.lan/mdm"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__MdmCheckInUrl",
"value": "https://mdm.iamworkin.lan/checkin"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__Organization",
"value": "FlowerCore"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__EnrollmentDisplayName",
"value": "FlowerCore Apple MDM"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ScepName",
"value": "FlowerCore Apple MDM Device Identity"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__TrustAnchorDisplayName",
"value": "IAmWorkin ACME CA Root CA"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__TrustAnchorCertificatePem",
"value": "-----BEGIN CERTIFICATE-----\nMIIBxDCCAWqgAwIBAgIRAPY357G6ow6zMAL5+4bS2kkwCgYIKoZIzj0EAwIwQDEa\nMBgGA1UEChMRSUFtV29ya2luIEFDTUUgQ0ExIjAgBgNVBAMTGUlBbVdvcmtpbiBB\nQ01FIENBIFJvb3QgQ0EwHhcNMjYwMzA4MTgwNzExWhcNMzYwMzA1MTgwNzExWjBA\nMRowGAYDVQQKExFJQW1Xb3JraW4gQUNNRSBDQTEiMCAGA1UEAxMZSUFtV29ya2lu\nIEFDTUUgQ0EgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ2n04X1\nJZo5Zdq/i1Idv8+fqwZyAzBh7whbqj0SWsJL8UWRabCMqYCs7+dXO0xRSzqkwFDL\nx+vooOai8RgRNhajRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/\nAgEBMB0GA1UdDgQWBBRnuPPQR6iM/H6vOluiU3Sygayz8jAKBggqhkjOPQQDAgNI\nADBFAiEArQK9dYPGmAZsdYnjziuFVVE5NKZUcceYvGfGC+tLXUsCIAudF2zJrCRq\n3mK50ZZET/fwTkJwiEF4824mjP8p1CKM\n-----END CERTIFICATE-----"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__NanoHubApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "NANOHUB_API_KEY",
"name": "fc-devicemgmt-runtime"
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ApnsTopic",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_APNS_TOPIC",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ScepUrl",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_SCEP_URL",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ScepChallenge",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_SCEP_CHALLENGE",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ProfileSigningCertificatePem",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_PROFILE_SIGNING_CERTIFICATE_PEM",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ProfileSigningPrivateKeyPem",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_PROFILE_SIGNING_PRIVATE_KEY_PEM",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__RequireManagedWifiPayload",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_REQUIRE_MANAGED_WIFI_PAYLOAD",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ManagedWifiSsid",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_MANAGED_WIFI_SSID",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ManagedWifiPassword",
"valueFrom": {
"secretKeyRef": {
"key": "APPLE_MDM_MANAGED_WIFI_PASSWORD",
"name": "fc-devicemgmt-runtime",
"optional": true
}
}
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ManagedWifiEncryptionType",
"value": "WPA2"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ManagedWifiAutoJoin",
"value": "true"
},
{
"name": "FlowerCore__DeviceManagement__AppleMdm__ManagedWifiDisableAssociationMacRandomization",
"value": "true"
}
],
"image": "localhost/fc-devicemgmt-web:v20260621-bootstraptrust-df7d826",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"name": "web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "1",
"memory": "768Mi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"startupProbe": {
"failureThreshold": 30,
"initialDelaySeconds": 5,
"periodSeconds": 5,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "fc-devicemgmt-web-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,38 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "devicemgmt-agent-mtls",
"namespace": "fc-devicemgmt"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`devices-agent.iamworkin.lan`)",
"middlewares": [
{
"name": "devicemgmt-agent-pass-client-cert",
"namespace": "fc-devicemgmt"
}
],
"services": [
{
"name": "fc-devicemgmt-web",
"port": 80
}
]
}
],
"tls": {
"options": {
"name": "devicemgmt-agent-mtls",
"namespace": "fc-devicemgmt"
},
"secretName": "fc-devicemgmt-agent-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "devicemgmt",
"namespace": "fc-devicemgmt"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`devices.iamworkin.lan`)",
"services": [
{
"name": "fc-devicemgmt-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "fc-devicemgmt-web-tls"
}
}
}

View File

@@ -1,13 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "Middleware",
"metadata": {
"name": "devicemgmt-agent-pass-client-cert",
"namespace": "fc-devicemgmt"
},
"spec": {
"passTLSClientCert": {
"pem": true
}
}
}

View File

@@ -1,20 +0,0 @@
{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "devicemgmt-agent-client-ca",
"namespace": "fc-devicemgmt",
"labels": {
"app.kubernetes.io/name": "fc-devicemgmt-web",
"app.kubernetes.io/component": "agent-mtls",
"app.kubernetes.io/part-of": "flowercore",
"app.kubernetes.io/managed-by": "argocd",
"flowercore.io/tenant-id": "system",
"flowercore.io/created-by": "bluejay-infra"
}
},
"type": "Opaque",
"data": {
"ca.crt": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUYyRENDQThDZ0F3SUJBZ0lVRTFhTVFrRXFmMzJMaVpwTHdudEd6NSsrWnBRd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2NqRUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQW9NQ2tac2IzZGxja052Y21VeEdqQVlCZ05WQkFzTQpFVVJsZG1salpTQk5ZVzVoWjJWdFpXNTBNVEl3TUFZRFZRUUREQ2xHYkc5M1pYSkRiM0psSUVSbGRtbGpaVTFoCmJtRm5aVzFsYm5RZ1JXNXliMnhzYldWdWRDQkRRVEFlRncweU5qQTJNVGt4TWpBM01UWmFGdzB6TmpBMk1UWXgKTWpBM01UWmFNSEl4Q3pBSkJnTlZCQVlUQWxWVE1STXdFUVlEVlFRS0RBcEdiRzkzWlhKRGIzSmxNUm93R0FZRApWUVFMREJGRVpYWnBZMlVnVFdGdVlXZGxiV1Z1ZERFeU1EQUdBMVVFQXd3cFJteHZkMlZ5UTI5eVpTQkVaWFpwClkyVk5ZVzVoWjJWdFpXNTBJRVZ1Y205c2JHMWxiblFnUTBFd2dnSWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUMKRHdBd2dnSUtBb0lDQVFDNGJLdWxXODV1alBFUmhGa2JZUmtDdHBmdWIrbnVvaHlPaW5lbWRXRERhQUpYQkVPVAoxNlUwc1dFODc0RmdCYzN3elYzQ0FUc3BZMW9VcGRyUUliQUZzWkN2VGZHSlhydmtJZm1yR0tmbGhZMHdZTTRKCm9OUFM2K1hYRlFWZVpzc3AwUnk1YWdLM3dUdE1uTFNuUkhzNm5VWnhIa2s1MzdaNER5NTAvT0xma2dYWnFyRm0KNStLaVJocHNTRytuUm12VmsrSW5yUmg1WS9HeENGN1ZWY2FJcStJRXVxZTIzc3ZMck8vZmJnb3k5MWlBMi9NUApWRWRuUFZ1cnAreFdONkswckZLZmE0QmU4RVhpRXZLK20reUttMEZTUEZ6ZFBON0xFWWhnRVJwYkp0S3RNQXJaCnVJc2FmeVl6M0c1REtBdllodlRyN3VCVnFOK1JQREtuWXNtcmdMcTQ0bXpESjkxcEMzckxOM0lHbXlVbloyZmwKWUc1UFIyNDBFOENOTVo0aHV1b3FZT3puYjJRUndPb1pmbG9rZDBISnJwVm4yUjNIVEpCL3ZacFMxbVlyNUMyTApBdTk2aHdvd0QvR1FlNzlyekRpa1lDempiQTFEZHFkeHZUb3g3Y1lRRUgzVUFZMEFGenpyUm5ISWRGYVgvZ2pyCm5GQy9od2RtQ3VZbm5KQ1Rpb3kzcVJjUFBPTTc4UzJrcGNJdy9MdjYrMDNlNFRUWjI2UVZIV3BQaUtNeHZiVjYKbk4xUUJBNGRjVUZtdzZXWFBIa0pFNnVVcHl5bEI1RzlmNkh6Rkt2TDhOZHNXRjA4WUc5SHc5d1lJTnpzbll3YQpDWkZJUmttenpQVERQZUZUUjUweVErWVRYY2FwZUpsWHQ4VjJRdzlQd0tWL0Rsa09QVE5YYkxDOTN3SURBUUFCCm8yWXdaREFkQmdOVkhRNEVGZ1FVcWgyOVpvUU9aNXRLY05hOEJjUnJISUthTHlnd0h3WURWUjBqQkJnd0ZvQVUKcWgyOVpvUU9aNXRLY05hOEJjUnJISUthTHlnd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQU9CZ05WSFE4QgpBZjhFQkFNQ0FRWXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnSUJBS1dsbStkQ1BLZ2lDVUFrL3Zlb1RCV1dxMWFxClhJOC81WG9DQ2owU3Q0ZHdhbXdHVUxhU0J0cnZhNFRJMkY0UmpBU25uRmFIMkhlY3laWm5CZW4wZHUrUitDMzEKdmZkVHIrVEQ4QUlpQkEyZm13L1hvTkJwTEsrKzBNL2xoNjJ3ai80KzBlVGVJSHg4TENDazRxUWxUYUlrNld3bgpuK0JSL2F3ZGhRM2RMZzAvM1kzL2V2Q3FQS1B1OTQrc1d5YkpuMlNUb2l1Y1RhL0ZvbnBIWjdZSU9SM3N4b1JwClh1V2JyS3ZUMGFmL1pVeXVpeTJFd0Y1dGU4N25BMkp5OGVsdzFTeGMrM0RiYlc3M3JJMFhZTGxHa0M1NWhBeFUKa2ZYSE5EaXNvV1BoN1pBV09lVFk0OElPZGgvb1IraW9mbkdiYkFvekh0ZmtYOXdUN3V2RlpYS0xTbHM1SEg4dQpZcDRwazdZam9kdmFTbys5SDhua3lYOGxYNmI2RCs0Mi9xTkVVN1UxYjQrdHcxQ0QyVmlRRUFpMHdLbHgzRFZVCnluMm13Zk9SZjQzT1hVUjIzZHh2UXhEWDR0RUNKUVpxTWxJaFZsRmN4TWN6dzRNcTZiTVZTaVB0ZzZtcml0eEsKOUUrb3JsRnNQRm9GdlphSTlzVGUxQWpkZWlUbjhxdUgyUFZqZ3lEa2E0bmt1UG1JS0FIbDVWSWZtWnVjTndTaApxMVE0REo5OFVCQStlTkpuZ1RBYVlXY1BIa2R4U0xKV3EwVzU1NGFrZUZaUW5qYXg3NFZoQWtxdExEZlhnNWw1ClNUeTcxRDNDNnl4SUpyVmZzV1JLS3dDY2dOOWpWR2dNMHBXMVNRaGZmRDdwK1hNRHZxRDNiejQ5S09XM0VGVzAKcG9vaGY3UGl5eU9TYVh3UgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
}
}

View File

@@ -1,33 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app": "fc-devicemgmt-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-devicemgmt-web",
"namespace": "fc-devicemgmt"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app": "fc-devicemgmt-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,16 +0,0 @@
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"labels": {
"app.kubernetes.io/component": "operator",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-devicemgmt-operator",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-devicemgmt-operator",
"namespace": "fc-devicemgmt"
}
}

View File

@@ -1,16 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "TLSOption",
"metadata": {
"name": "devicemgmt-agent-mtls",
"namespace": "fc-devicemgmt"
},
"spec": {
"clientAuth": {
"clientAuthType": "RequireAndVerifyClientCert",
"secretNames": [
"devicemgmt-agent-client-ca"
]
}
}
}

View File

@@ -1,265 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "fc-distribution",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "fc-distribution",
"namespace": "fc-distribution"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "fc-distribution"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"flowercore.io/healthz-auth-policy": "allow-anonymous",
"prometheus.io/path": "/metrics",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "fc-distribution",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:8080"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",
"value": "false"
},
{
"name": "FlowerCore__Auth__Enabled",
"value": "true"
},
{
"name": "FlowerCore__Auth__Oidc__Enabled",
"value": "true"
},
{
"name": "FlowerCore__Auth__Oidc__Authority",
"value": "https://id.iamworkin.lan/application/o/distribution/"
},
{
"name": "FlowerCore__Auth__Oidc__Audience",
"value": "distribution"
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"value": "distribution"
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "distribution-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Database__Provider",
"value": "Sqlite"
},
{
"name": "FlowerCore__Database__ConnectionStrings__Sqlite",
"value": "Data Source=/data/distribution.db"
},
{
"name": "FlowerCore__Distribution__Blobs__Root",
"value": "/blobs"
},
{
"name": "FlowerCore__Distribution__Signing__EditionCerts__kiosk-standard__CertPath",
"value": "/signing/kiosk-standard/chain.pem"
},
{
"name": "FlowerCore__Distribution__Signing__EditionCerts__kiosk-standard__KeyPath",
"value": "/signing/kiosk-standard/private-key.pem"
},
{
"name": "FlowerCore__Distribution__Signing__EditionCerts__aistation-field__CertPath",
"value": "/signing/aistation-field/chain.pem"
},
{
"name": "FlowerCore__Distribution__Signing__EditionCerts__aistation-field__KeyPath",
"value": "/signing/aistation-field/private-key.pem"
},
{
"name": "FlowerCore__Distribution__EntitlementPublic__PublicEditions__0",
"value": "*"
}
],
"image": "localhost/fc-distribution:v20260619-distribution-592ad75",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"name": "web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"startupProbe": {
"failureThreshold": 30,
"httpGet": {
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"periodSeconds": 5,
"successThreshold": 1,
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "sqlite",
"subPath": "distribution/data"
},
{
"mountPath": "/blobs",
"name": "blobs",
"subPath": "distribution/blobs"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
},
{
"mountPath": "/signing/kiosk-standard",
"name": "kiosk-standard",
"readOnly": true
},
{
"mountPath": "/signing/aistation-field",
"name": "aistation-field",
"readOnly": true
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsNonRoot": true
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "sqlite",
"nfs": {
"path": "/volume1/kubernetes",
"server": "10.0.58.3"
}
},
{
"name": "blobs",
"nfs": {
"path": "/volume1/kubernetes",
"server": "10.0.58.3"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
},
{
"name": "kiosk-standard",
"secret": {
"defaultMode": 256,
"secretName": "edition-kiosk-standard"
}
},
{
"name": "aistation-field",
"secret": {
"defaultMode": 256,
"secretName": "edition-aistation-field"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "fc-distribution-public",
"namespace": "fc-distribution"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`dist.flowercore.io`) && (Method(`GET`) || Method(`HEAD`))",
"priority": 100,
"services": [
{
"name": "fc-distribution",
"port": 80
}
]
}
],
"tls": {
"secretName": "cf-origin-flowercore-io"
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "fc-distribution",
"namespace": "fc-distribution"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`dist.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "fc-distribution",
"port": 80
}
]
}
],
"tls": {
"secretName": "fc-distribution-tls-secret"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "fc-distribution",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "fc-distribution",
"namespace": "fc-distribution"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "fc-distribution"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"Dms__AutoMessageDaemon__PollIntervalMinutes": "5",
"Dms__Weather__CacheFilePath": "/data/noaa-cache.json",
"Dms__Weather__State": "MN",
"FlowerCore__Auth__AcceptLegacyApiKey": "true",
"FlowerCore__Auth__AcceptLegacyJwt": "false",
"FlowerCore__Auth__Provider": "Oidc",
"FlowerCore__Auth__RoleClaimType": "fc:roles",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/dms.db",
"FlowerCore__Database__Provider": "Sqlite",
"FlowerCore__Tenant__DefaultTenantHosts__0": "dms.iamworkin.lan",
"FlowerCore__Tenant__JwtClaimsEnabled": "false",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.DMS",
"Security__AllowedOrigins__0": "https://dms.iamworkin.lan"
},
"kind": "ConfigMap",
"metadata": {
"name": "dms-web-config",
"namespace": "fc-dms"
}
}

View File

@@ -1,178 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "dms-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "dms-web",
"namespace": "fc-dms"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "dms-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-06-12T16:05:19-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "dms-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "Kestrel__Endpoints__Http__Url",
"value": "http://+:8080"
},
{
"name": "Kestrel__Endpoints__Http__Protocols",
"value": "Http1"
},
{
"name": "Kestrel__Endpoints__Grpc__Url",
"value": "http://+:8081"
},
{
"name": "Kestrel__Endpoints__Grpc__Protocols",
"value": "Http2"
},
{
"name": "FlowerCore__Auth__OidcClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "dms-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__OidcClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "dms-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__OidcAuthority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "dms-oidc-client",
"optional": true
}
}
}
],
"envFrom": [
{
"configMapRef": {
"name": "dms-web-config"
}
},
{
"secretRef": {
"name": "dms-web-secrets"
}
}
],
"image": "localhost/fc-dms-web:v20260621-rum3-316cb2d",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 180,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "dms-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
},
{
"containerPort": 8081,
"name": "grpc",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 18,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "dms-web-data"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "dms-web",
"namespace": "fc-dms"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`dms.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "dms-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "dms-web-tls"
}
}
}

View File

@@ -1,34 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "dms-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "dms-web",
"namespace": "fc-dms"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
},
{
"name": "grpc",
"port": 8081,
"protocol": "TCP",
"targetPort": 8081
}
],
"selector": {
"app.kubernetes.io/name": "dms-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,542 +0,0 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: fc-dns
labels:
app.kubernetes.io/part-of: flowercore
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dns-web-data
namespace: fc-dns
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: ConfigMap
metadata:
name: dns-web-config
namespace: fc-dns
data:
appsettings.Production.json: |
{
"FlowerCore": {
"Auth": {
"Enabled": true,
"Oidc": {
"Enabled": true,
"Audience": "dns",
"RequireHttpsMetadata": true
}
},
"Database": {
"Provider": "Sqlite",
"ConnectionStrings": {
"Sqlite": "Data Source=/data/dns.db"
}
},
"Tenant": {
"DefaultTenantId": "default",
"JwtClaimsEnabled": true,
"DefaultTenantHosts": [
"dns.iamworkin.lan"
]
},
"Audit": {
"HashChain": {
"BridgeSensitivity": {
"Distribution": "Warn"
}
}
},
"Dns": {
"RateLimits": {
"PermitLimit": 60,
"WindowSeconds": 60,
"QueueLimit": 0
}
}
}
}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: dns-web
namespace: fc-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dns-web
rules:
- apiGroups:
- ""
resources:
- namespaces
- pods
- services
- secrets
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- cert-manager.io
resources:
- certificates
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dns-web
subjects:
- kind: ServiceAccount
name: dns-web
namespace: fc-dns
roleRef:
kind: ClusterRole
name: dns-web
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-web
namespace: fc-dns
labels:
app: dns-web
app.kubernetes.io/name: dns-web
app.kubernetes.io/part-of: flowercore
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: dns-web
template:
metadata:
labels:
app: dns-web
app.kubernetes.io/name: dns-web
app.kubernetes.io/part-of: flowercore
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "5320"
prometheus.io/path: "/metrics/prometheus"
flowercore.io/source-sha: "0cdea666a09dea526fb701d06c2ce17b90664a0f"
spec:
serviceAccountName: dns-web
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
fsGroup: 1654
fsGroupChangePolicy: OnRootMismatch
containers:
- name: dns-web
image: localhost/fc-dns-web:v20260620-dns-sec5-93f96c6
imagePullPolicy: Never
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
ports:
- containerPort: 5320
name: http
env:
- name: ASPNETCORE_URLS
value: http://+:5320
- name: ASPNETCORE_ENVIRONMENT
value: Production
- name: FlowerCore__Dns__Providers__PfSenseUnbound__FallbackPassword
valueFrom:
secretKeyRef:
name: pfsense-admin
key: password
- name: FlowerCore__Auth__Oidc__Authority
valueFrom:
secretKeyRef:
name: dns-oidc-client
key: issuer_url
optional: true
- name: FlowerCore__Auth__Oidc__ClientId
valueFrom:
secretKeyRef:
name: dns-oidc-client
key: client_id
optional: true
- name: FlowerCore__Auth__Oidc__ClientSecret
valueFrom:
secretKeyRef:
name: dns-oidc-client
key: client_secret
optional: true
- name: FlowerCore__Auth__ApiKey
valueFrom:
secretKeyRef:
name: dns-api-keys
key: api_key
optional: true
- name: FlowerCore__Mcp__ApiKey__Key
valueFrom:
secretKeyRef:
name: dns-api-keys
key: api_key
optional: true
- name: FlowerCore__Mcp__ServiceName
value: flowercore.dns
- name: FlowerCore__Auth__Enabled
value: "true"
- name: FlowerCore__Auth__Oidc__Enabled
value: "true"
- name: FlowerCore__Auth__Oidc__Audience
value: dns
volumeMounts:
- name: data
mountPath: /data
- name: tmp
mountPath: /tmp
- name: logs
mountPath: /app/logs
- name: config
mountPath: /app/appsettings.Production.json
subPath: appsettings.Production.json
readOnly: true
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 300m
memory: 384Mi
readinessProbe:
httpGet:
path: /healthz
port: 5320
initialDelaySeconds: 10
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 5320
initialDelaySeconds: 20
periodSeconds: 30
volumes:
- name: data
persistentVolumeClaim:
claimName: dns-web-data
- name: tmp
emptyDir: {}
- name: logs
emptyDir: {}
- name: config
configMap:
name: dns-web-config
---
apiVersion: v1
kind: Service
metadata:
name: dns-web
namespace: fc-dns
spec:
selector:
app: dns-web
ports:
- port: 5320
targetPort: 5320
name: http
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dns-web-ingress-isolation
namespace: fc-dns
spec:
podSelector:
matchLabels:
app: dns-web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-dns
- ipBlock:
cidr: 10.42.0.0/16
- ipBlock:
cidr: 10.0.56.0/24
- ipBlock:
cidr: 10.0.57.0/24
- ipBlock:
cidr: 10.0.58.0/24
- ipBlock:
cidr: 10.0.68.0/27
ports:
- port: 5320
protocol: TCP
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dns-web-cert
namespace: fc-dns
spec:
secretName: dns-web-tls
issuerRef:
name: step-ca-acme
kind: ClusterIssuer
dnsNames:
- dns.iamworkin.lan
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: dns-web
namespace: fc-dns
spec:
entryPoints:
- websecure
routes:
- match: Host(`dns.iamworkin.lan`)
kind: Rule
priority: 100
services:
- name: dns-web
port: 5320
tls:
secretName: dns-web-tls
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: dns-acme-webhook
namespace: fc-dns
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-acme-webhook
namespace: fc-dns
labels:
app: dns-acme-webhook
app.kubernetes.io/name: dns-acme-webhook
app.kubernetes.io/part-of: flowercore
spec:
replicas: 1
selector:
matchLabels:
app: dns-acme-webhook
template:
metadata:
labels:
app: dns-acme-webhook
app.kubernetes.io/name: dns-acme-webhook
app.kubernetes.io/part-of: flowercore
annotations:
flowercore.io/source-sha: "0cdea666a09dea526fb701d06c2ce17b90664a0f"
spec:
serviceAccountName: dns-acme-webhook
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
fsGroup: 1654
fsGroupChangePolicy: OnRootMismatch
containers:
- name: dns-acme-webhook
image: localhost/fc-dns-acme-webhook:v20260617-sec5-0cdea66
imagePullPolicy: Never
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
ports:
- containerPort: 9443
name: https
env:
- name: ASPNETCORE_URLS
value: https://+:9443
- name: ASPNETCORE_ENVIRONMENT
value: Production
- name: Kestrel__Certificates__Default__Path
value: /tls/tls.crt
- name: Kestrel__Certificates__Default__KeyPath
value: /tls/tls.key
- name: FlowerCore__Dns__AcmeWebhook__ServiceBaseUrl
value: http://dns-web:5320
- name: FlowerCore__Dns__AcmeWebhook__ApiKey
valueFrom:
secretKeyRef:
name: dns-api-keys
key: api_key
optional: true
- name: FlowerCore__Dns__AcmeWebhook__GroupName
value: acme.flowercore.io
- name: FlowerCore__Dns__AcmeWebhook__SolverName
value: flowercore-dns
- name: FlowerCore__Dns__AcmeWebhook__Version
value: v1alpha1
volumeMounts:
- name: tls
mountPath: /tls
readOnly: true
- name: tmp
mountPath: /tmp
- name: logs
mountPath: /app/logs
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
readinessProbe:
httpGet:
scheme: HTTPS
path: /readyz
port: https
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
initialDelaySeconds: 10
periodSeconds: 20
timeoutSeconds: 5
volumes:
- name: tls
secret:
secretName: dns-acme-webhook-tls
- name: tmp
emptyDir: {}
- name: logs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: dns-acme-webhook
namespace: fc-dns
spec:
selector:
app: dns-acme-webhook
ports:
- port: 443
targetPort: https
name: https
type: ClusterIP
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: dns-acme-webhook-selfsigned
namespace: fc-dns
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dns-acme-webhook-ca
namespace: fc-dns
spec:
secretName: dns-acme-webhook-ca
duration: 43800h
issuerRef:
name: dns-acme-webhook-selfsigned
commonName: ca.dns-acme-webhook.fc-dns
isCA: true
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: dns-acme-webhook-ca-issuer
namespace: fc-dns
spec:
ca:
secretName: dns-acme-webhook-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dns-acme-webhook-serving-cert
namespace: fc-dns
spec:
secretName: dns-acme-webhook-tls
duration: 8760h
issuerRef:
name: dns-acme-webhook-ca-issuer
dnsNames:
- dns-acme-webhook
- dns-acme-webhook.fc-dns
- dns-acme-webhook.fc-dns.svc
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.acme.flowercore.io
annotations:
cert-manager.io/inject-ca-from: fc-dns/dns-acme-webhook-serving-cert
spec:
group: acme.flowercore.io
groupPriorityMinimum: 1000
service:
name: dns-acme-webhook
namespace: fc-dns
version: v1alpha1
versionPriority: 15
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dns-acme-webhook-solver
rules:
- apiGroups:
- acme.flowercore.io
resources:
- flowercore-dns
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dns-acme-webhook-solver
subjects:
- kind: ServiceAccount
name: cert-manager
namespace: cert-manager
roleRef:
kind: ClusterRole
name: dns-acme-webhook-solver
apiGroup: rbac.authorization.k8s.io

View File

@@ -1,358 +0,0 @@
# FlowerCore MCP Gateway for the GX10 cluster.
# Secret values are copied into Kubernetes Secrets out of band until the
# 1Password operator exists on GX10; never commit secret data here.
---
apiVersion: v1
kind: Namespace
metadata:
name: fc-gateway
labels:
app.kubernetes.io/part-of: flowercore
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: fc-gateway
namespace: fc-gateway
labels:
app.kubernetes.io/name: fc-gateway
app.kubernetes.io/part-of: flowercore
spec:
replicas: 1
revisionHistoryLimit: 3
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: fc-gateway
template:
metadata:
labels:
app.kubernetes.io/name: fc-gateway
app.kubernetes.io/part-of: flowercore
annotations:
fc.flowercore.io/healthz-anon: "true"
fc.flowercore.io/probe-path: "/healthz"
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics/prometheus"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
fsGroup: 1654
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: localhost/fc-gateway:v20260621-chrome-9c860bb
imagePullPolicy: Never
ports:
- containerPort: 8080
name: http
env:
- name: ASPNETCORE_URLS
value: "http://+:8080"
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
- name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
value: "false"
- name: FlowerCore__Mcp__ApiKey__Key
valueFrom:
secretKeyRef:
name: gateway-mcp-keys
key: credential
- name: FlowerCore__Mcp__Gateway__Embedding__BaseUrl
value: "http://fc-llm-bridge.fc-llm-bridge.svc:8080/v1"
- name: FlowerCore__Mcp__Gateway__Embedding__Model
value: "fc:embedding"
- name: FlowerCore__Mcp__Gateway__Embedding__Mode
value: "openai"
- name: FlowerCore__Mcp__Gateway__Embedding__ApiKey
valueFrom:
secretKeyRef:
name: fc-llm-bridge-api-keys
key: agent-zero-k8s
optional: true
- name: GW_BACKEND_fc_mysql_KEY
valueFrom:
secretKeyRef:
name: mysql-mcp-keys
key: credential
optional: true
- name: GW_BACKEND_fc_php_KEY
valueFrom:
secretKeyRef:
name: php-mcp-keys
key: credential
optional: true
- name: GW_BACKEND_fc_telephony_KEY
valueFrom:
secretKeyRef:
name: telephony-mcp-keys
key: credential
optional: true
- name: GW_BACKEND_fc_chat_KEY
valueFrom:
secretKeyRef:
name: chat-mcp-keys
key: credential
optional: true
- name: GW_BACKEND_fc_dms_KEY
valueFrom:
secretKeyRef:
name: dms-mcp-keys
key: credential
optional: true
- name: GW_BACKEND_fc_knowledge_KEY
valueFrom:
secretKeyRef:
name: knowledge-mcp-tokens
key: password
optional: true
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 384Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: logs
mountPath: /home/app/logs
securityContext:
runAsNonRoot: true
runAsUser: 1654
runAsGroup: 1654
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
startupProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
readinessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
volumes:
- name: tmp
emptyDir: {}
- name: logs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: fc-gateway
namespace: fc-gateway
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: fc-gateway
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: fc-gateway-tls
namespace: fc-gateway
spec:
secretName: fc-gateway-tls
issuerRef:
name: step-ca-acme
kind: ClusterIssuer
dnsNames:
- gateway.iamworkin.lan
duration: 720h
renewBefore: 240h
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: fc-gateway
namespace: fc-gateway
spec:
entryPoints:
- websecure
routes:
- match: Host(`gateway.iamworkin.lan`)
kind: Rule
services:
- name: fc-gateway
port: 80
tls:
secretName: fc-gateway-tls
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-gateway-default-deny
namespace: fc-gateway
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-gateway-netpol
namespace: fc-gateway
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: fc-gateway
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: agent-zero
ports:
- port: 8080
protocol: TCP
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
ports:
- port: 8080
protocol: TCP
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- port: 8080
protocol: TCP
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-llm-bridge
ports:
- port: 8080
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-mysql
ports:
- port: 5300
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-php
ports:
- port: 5400
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: telephony
ports:
- port: 5100
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-chat
ports:
- port: 80
protocol: TCP
- port: 8080
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-dms
ports:
- port: 80
protocol: TCP
- port: 8080
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: knowledge
ports:
- port: 80
protocol: TCP
- port: 8080
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fc-gateway-acme-http-solver-allow
namespace: fc-gateway
spec:
podSelector:
matchLabels:
acme.cert-manager.io/http01-solver: "true"
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
ports:
- port: 8089
protocol: TCP
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

View File

@@ -1,20 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:5000",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/library.db",
"FlowerCore__Database__Provider": "Sqlite",
"FlowerCore__Library__BaseUrl": "https://library.iamworkin.lan",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.Library",
"PrintService__BaseUrl": "http://print.iamworkin.lan:5200"
},
"kind": "ConfigMap",
"metadata": {
"name": "library-web-config",
"namespace": "fc-library"
}
}

View File

@@ -1,119 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "library-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "library-web",
"namespace": "fc-library"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "library-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/health",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5000",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "library-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "library-web-config"
}
}
],
"image": "localhost/fc-library-web:v20260619-library-0e027cc",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "library-web",
"ports": [
{
"containerPort": 5000,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "library-web-data"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "library-web",
"namespace": "fc-library"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`library.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "library-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "library-web-tls"
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "library-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "library-web",
"namespace": "fc-library"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 5000
}
],
"selector": {
"app.kubernetes.io/name": "library-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,292 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "fc-llm-bridge",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "fc-llm-bridge",
"namespace": "fc-llm-bridge"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "fc-llm-bridge"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/healthz",
"kubectl.kubernetes.io/restartedAt": "2026-06-14T15:12:25-05:00",
"prometheus.io/path": "/metrics",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "fc-llm-bridge",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:8080"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",
"value": "false"
},
{
"name": "FlowerCore__LlmBridge__SqliteConnectionString",
"value": "Data Source=/data/llm-bridge.db"
},
{
"name": "FlowerCore__LlmBridge__DefaultTenantId",
"value": "default"
},
{
"name": "FlowerCore__LlmBridge__DefaultAppName",
"value": "agent-zero"
},
{
"name": "FlowerCore__LlmBridge__UtilModel",
"value": "qwen2.5:1.5b"
},
{
"name": "FlowerCore__LlmBridge__EmbedModel",
"value": "nomic-embed-text"
},
{
"name": "FlowerCore__LlmBridge__ApiKeys__agent-zero-ws",
"valueFrom": {
"secretKeyRef": {
"key": "agent-zero-ws",
"name": "fc-llm-bridge-api-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__LlmBridge__ApiKeys__agent-zero-k8s",
"valueFrom": {
"secretKeyRef": {
"key": "agent-zero-k8s",
"name": "fc-llm-bridge-api-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__LlmBridge__ApiKeys__spare-1",
"valueFrom": {
"secretKeyRef": {
"key": "spare-1",
"name": "fc-llm-bridge-api-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__LlmBridge__ApiKeys__spare-2",
"valueFrom": {
"secretKeyRef": {
"key": "spare-2",
"name": "fc-llm-bridge-api-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__Chat__OllamaBaseUrl",
"value": "http://10.0.56.14:30976"
},
{
"name": "FlowerCore__Chat__HttpTimeout",
"value": "00:05:00"
},
{
"name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Balanced__Provider",
"value": "Ollama"
},
{
"name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Balanced__Model",
"value": "qwen2.5:14b"
},
{
"name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Cheap__Provider",
"value": "Ollama"
},
{
"name": "FlowerCore__Chat__ModelRouter__DefaultRoutes__Cheap__Model",
"value": "qwen2.5:7b"
},
{
"name": "FlowerCore__Chat__Anthropic__Enabled",
"value": "true"
},
{
"name": "FlowerCore__Chat__Anthropic__ApiKey",
"valueFrom": {
"secretKeyRef": {
"key": "password",
"name": "anthropic-api-key"
}
}
},
{
"name": "FlowerCore__Chat__Anthropic__OrganizationId",
"valueFrom": {
"secretKeyRef": {
"key": "organization_id",
"name": "anthropic-api-key",
"optional": true
}
}
},
{
"name": "FlowerCore__Chat__Anthropic__BaseUrl",
"value": "https://api.anthropic.com"
},
{
"name": "FlowerCore__Chat__Anthropic__DefaultModel",
"value": "claude-sonnet-4-6"
},
{
"name": "FlowerCore__Chat__Anthropic__AnthropicVersion",
"value": "2023-06-01"
},
{
"name": "FlowerCore__Chat__Anthropic__Timeout",
"value": "00:05:00"
}
],
"image": "localhost/fc-llm-bridge:v20260621-rum2-ace701d-f2b7d3e",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 15,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"name": "web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 5,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "1",
"memory": "768Mi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/data",
"name": "app-data"
}
]
}
],
"dnsConfig": {
"nameservers": [
"10.43.0.10"
],
"options": [
{
"name": "ndots",
"value": "2"
}
],
"searches": [
"fc-llm-bridge.svc.cluster.local",
"svc.cluster.local",
"cluster.local"
]
},
"dnsPolicy": "None",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "fc-llm-bridge-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "app-data"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "fc-llm-bridge",
"namespace": "fc-llm-bridge"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`fc-llm-bridge.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "fc-llm-bridge",
"port": 8080
}
]
}
],
"tls": {
"secretName": "fc-llm-bridge-tls"
}
}
}

View File

@@ -1,25 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {},
"name": "fc-llm-bridge",
"namespace": "fc-llm-bridge"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 8080,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "fc-llm-bridge"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,11 +0,0 @@
{
"apiVersion": "v1",
"data": {
"appsettings.Production.json": "{\n \"DatabaseProvider\": \"Sqlite\",\n \"ConnectionStrings\": {\n \"Sqlite\": \"Data Source=/data/media.db\"\n },\n \"FlowerCore\": {\n \"Auth\": {\n \"Enabled\": true,\n \"Oidc\": {\n \"Authority\": \"https://id.iamworkin.lan/application/o/media/\",\n \"ClientId\": \"media\",\n \"ClientSecret\": \"\",\n \"Audience\": \"media\",\n \"RequireHttpsMetadata\": true\n }\n },\n \"Tenant\": {\n \"JwtClaimsEnabled\": false,\n \"DefaultTenantHosts\": [ \"media.iamworkin.lan\" ]\n }\n },\n \"Media\": {\n \"LibraryRoot\": \"/media/library\",\n \"Sources\": [\n {\n \"Name\": \"BlueJayNAS Video\",\n \"Driver\": \"Nfs\",\n \"MountedPath\": \"/media/library\",\n \"RemotePath\": \"nfs://10.0.58.3/volume1/video\",\n \"IsEnabled\": true,\n \"IsDefault\": true,\n \"Notes\": \"Synology NFS media share mounted read-only inside the cluster.\"\n }\n ],\n \"GeneratedRoot\": \"/data/generated\",\n \"TranscodeRoot\": \"/data/transcodes\",\n \"InboxPath\": \"/media/inbox\",\n \"InboxScanIntervalMinutes\": 5,\n \"ScanOnStartup\": false,\n \"ComputeChecksums\": false,\n \"FfmpegCommand\": \"ffmpeg\",\n \"FfprobeCommand\": \"ffprobe\",\n \"Hls\": {\n \"MaxConcurrentJobs\": 1\n },\n \"DefaultViewerName\": \"BlueJay\",\n \"Dlna\": {\n \"IsEnabled\": true,\n \"MulticastAddress\": \"239.255.255.250\",\n \"Port\": 1900,\n \"DiscoveryTimeoutSeconds\": 2,\n \"DescriptionFetchTimeoutSeconds\": 2,\n \"MaxResponsesPerSearchTarget\": 32,\n \"SearchTargets\": [\n \"urn:schemas-upnp-org:device:MediaRenderer:1\",\n \"urn:schemas-upnp-org:device:MediaServer:1\"\n ]\n }\n }\n}\n"
},
"kind": "ConfigMap",
"metadata": {
"name": "fc-media-config",
"namespace": "fc-media"
}
}

View File

@@ -1,273 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "fc-media-web",
"app.kubernetes.io/name": "fc-media-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "fc-media-web",
"namespace": "fc-media"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "fc-media-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"flowercore.io/healthz-auth-policy": "allow-anonymous",
"kubectl.kubernetes.io/restartedAt": "2026-04-05T14:14:28-05:00",
"prometheus.io/path": "/metrics",
"prometheus.io/port": "5200",
"prometheus.io/scrape": "true"
},
"labels": {
"app": "fc-media-web",
"app.kubernetes.io/name": "fc-media-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "ASPNETCORE_URLS",
"value": "http://+:5200"
},
{
"name": "FlowerCore__Auth__Enabled",
"value": "true"
},
{
"name": "FlowerCore__Auth__Oidc__Enabled",
"value": "true"
},
{
"name": "FlowerCore__Auth__Oidc__Audience",
"value": "media"
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "media-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "media-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__Authority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "media-oidc-client",
"optional": true
}
}
}
],
"image": "localhost/fc-media-web:v20260620-media-chrome-e05b9c1",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"httpHeaders": [
{
"name": "X-Forwarded-Proto",
"value": "https"
}
],
"path": "/healthz",
"port": 5200,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "fc-media-web",
"ports": [
{
"containerPort": 5200,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"httpHeaders": [
{
"name": "X-Forwarded-Proto",
"value": "https"
}
],
"path": "/healthz",
"port": 5200,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "4",
"memory": "4Gi"
},
"requests": {
"cpu": "500m",
"memory": "1Gi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"startupProbe": {
"failureThreshold": 18,
"httpGet": {
"httpHeaders": [
{
"name": "X-Forwarded-Proto",
"value": "https"
}
],
"path": "/healthz",
"port": 5200,
"scheme": "HTTP"
},
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/app/appsettings.Production.json",
"name": "config",
"readOnly": true,
"subPath": "appsettings.Production.json"
},
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/data/transcodes",
"name": "transcodes"
},
{
"mountPath": "/media/library",
"name": "media-library",
"readOnly": true
},
{
"mountPath": "/media/inbox",
"name": "media-inbox"
},
{
"mountPath": "/tmp",
"name": "temp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"configMap": {
"defaultMode": 420,
"name": "fc-media-config"
},
"name": "config"
},
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "fc-media-data"
}
},
{
"name": "transcodes",
"nfs": {
"path": "/volume1/kubernetes/fc-media-transcodes",
"server": "10.0.58.3"
}
},
{
"name": "media-inbox",
"nfs": {
"path": "/volume1/kubernetes/fc-media-inbox",
"server": "10.0.58.3"
}
},
{
"name": "media-library",
"nfs": {
"path": "/volume1/video",
"readOnly": true,
"server": "10.0.58.3"
}
},
{
"emptyDir": {},
"name": "temp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "fc-media-web",
"namespace": "fc-media"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`media.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "fc-media-web",
"port": 5200
}
]
}
],
"tls": {
"secretName": "fc-media-tls"
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app": "fc-media-web",
"app.kubernetes.io/name": "fc-media-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "fc-media-web",
"namespace": "fc-media"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 5200,
"protocol": "TCP",
"targetPort": 5200
}
],
"selector": {
"app": "fc-media-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:5000",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/menuboard.db",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.MenuBoard",
"Security__AllowedOrigins__0": "https://menuboard.iamworkin.lan"
},
"kind": "ConfigMap",
"metadata": {
"name": "menuboard-web-config",
"namespace": "fc-menuboard"
}
}

View File

@@ -1,143 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "menuboard-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "menuboard-web",
"namespace": "fc-menuboard"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "menuboard-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5000",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "menuboard-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "menuboard-web-config"
}
},
{
"secretRef": {
"name": "menuboard-web-secrets"
}
}
],
"image": "localhost/fc-menuboard-web:v20260620-menuboard-chrome-b36eb7a",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "menuboard-web",
"ports": [
{
"containerPort": 5000,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "temp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "menuboard-web-data"
}
},
{
"emptyDir": {},
"name": "temp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "menuboard-web",
"namespace": "fc-menuboard"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`menuboard.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "menuboard-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "menuboard-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "menuboard-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "menuboard-web",
"namespace": "fc-menuboard"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 5000
}
],
"selector": {
"app.kubernetes.io/name": "menuboard-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/messageboard.db",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.MessageBoard",
"Security__AllowedOrigins__0": "https://messageboard.iamworkin.lan"
},
"kind": "ConfigMap",
"metadata": {
"name": "messageboard-web-config",
"namespace": "fc-messageboard"
}
}

View File

@@ -1,149 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "messageboard-web"
},
"name": "messageboard-web",
"namespace": "fc-messageboard"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "messageboard-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/health",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app": "messageboard-web"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "messageboard-web-config"
}
},
{
"secretRef": {
"name": "messageboard-web-secrets",
"optional": true
}
}
],
"image": "localhost/fc-messageboard-web:v20260620-messageboard-chrome-e652648",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 10,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 5
},
"name": "messageboard-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/app/logs",
"name": "logs"
},
{
"mountPath": "/tmp",
"name": "tmp"
}
],
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
}
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "messageboard-web-data"
}
},
{
"name": "logs",
"emptyDir": {}
},
{
"name": "tmp",
"emptyDir": {}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "messageboard-web",
"namespace": "fc-messageboard"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`messageboard.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "messageboard-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "messageboard-web-tls"
}
}
}

View File

@@ -1,25 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {},
"name": "messageboard-web",
"namespace": "fc-messageboard"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app": "messageboard-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,11 +0,0 @@
{
"apiVersion": "v1",
"data": {
"appsettings.Production.json": "{\n \"MySqlManager\": {\n \"CrdNamespace\": \"fc-tenant-default\",\n \"MySqlImage\": \"iwrk-nexus.iamworkin.lan:8444/iwrk-ubuntu-mysql:master\",\n \"PhpMyAdminImage\": \"phpmyadmin/phpmyadmin:latest\",\n \"PhpMyAdminDomain\": \"iamworkin.lan\",\n \"Advisor\": {\n \"DefaultPreset\": \"medium\",\n \"AutoDetectPreset\": true,\n \"MaxAutoPreset\": \"medium\",\n \"PresetOverride\": null\n }\n },\n \"ContainerBackend\": {\n \"Default\": \"Kubernetes\"\n },\n \"FlowerCore\": {\n \"Auth\": {\n \"Provider\": \"Oidc\",\n \"Enabled\": false,\n \"Oidc\": {\n \"Enabled\": true,\n \"Authority\": \"https://id.iamworkin.lan/application/o/mysql/\",\n \"Audience\": \"mysql\",\n \"ClientId\": \"mysql\",\n \"ClientSecret\": \"\"\n }\n },\n \"Tenant\": {\n \"JwtClaimsEnabled\": false,\n \"TenantClaimType\": \"fc:tenant\",\n \"ActorIdClaimType\": \"flowercore_actor_id\"\n },\n \"Database\": {\n \"Provider\": \"Sqlite\",\n \"ConnectionStrings\": {\n \"Sqlite\": \"Data Source=/data/mysql-manager.db\"\n }\n }\n }\n}\n"
},
"kind": "ConfigMap",
"metadata": {
"name": "mysql-web-config",
"namespace": "fc-mysql"
}
}

View File

@@ -1,220 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "flowercore",
"app.kubernetes.io/name": "mysql-web"
},
"name": "mysql-web",
"namespace": "fc-mysql"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "mysql-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-04-17T19:52:14-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5300",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "mysql-web"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "FlowerCore__Auth__Enabled",
"value": "false"
},
{
"name": "FlowerCore__Mcp__ApiKey__Key",
"valueFrom": {
"secretKeyRef": {
"key": "credential",
"name": "mysql-mcp-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__Authority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "mysql-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "mysql-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "mysql-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__Audience",
"value": "mysql"
}
],
"image": "localhost/fc-mysql-web:v20260618-hm4-tenant-84dc65c",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/metrics/prometheus",
"port": 5300,
"scheme": "HTTP"
},
"initialDelaySeconds": 20,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "mysql-web",
"ports": [
{
"containerPort": 5300,
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/metrics/prometheus",
"port": 5300,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
},
{
"mountPath": "/app/appsettings.Production.json",
"name": "config",
"readOnly": true,
"subPath": "appsettings.Production.json"
}
]
}
],
"dnsConfig": {
"nameservers": [
"10.43.0.10"
],
"options": [
{
"name": "ndots",
"value": "2"
}
],
"searches": [
"fc-mysql.svc.cluster.local",
"svc.cluster.local",
"cluster.local"
]
},
"dnsPolicy": "None",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"serviceAccount": "mysql-web",
"serviceAccountName": "mysql-web",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "mysql-web-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
},
{
"configMap": {
"defaultMode": 420,
"name": "mysql-web-config"
},
"name": "config"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "mysql-web",
"namespace": "fc-mysql"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`mysql.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "mysql-web",
"port": 5300
}
]
}
],
"tls": {
"secretName": "mysql-web-tls"
}
}
}

View File

@@ -1,23 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "mysql-web",
"namespace": "fc-mysql"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"port": 5300,
"protocol": "TCP",
"targetPort": 5300
}
],
"selector": {
"app.kubernetes.io/name": "mysql-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,8 +0,0 @@
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "mysql-web",
"namespace": "fc-mysql"
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"name": "fc-network-web-tls",
"namespace": "fc-network"
},
"spec": {
"dnsNames": [
"network.iamworkin.lan"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "step-ca-acme"
},
"secretName": "fc-network-web-tls"
}
}

View File

@@ -1,210 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "fc-network-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-network-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-network-web",
"namespace": "fc-network"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app": "fc-network-web"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": 0,
"maxUnavailable": 1
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/healthz",
"flowercore.io/audit-trace-id": "runtime-activity-trace",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5340",
"prometheus.io/scrape": "true"
},
"labels": {
"app": "fc-network-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-network-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:5340"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",
"value": "false"
},
{
"name": "HOME",
"value": "/data"
},
{
"name": "FlowerCore__Auth__Enabled",
"value": "false"
},
{
"name": "FlowerCore__Database__Provider",
"value": "Sqlite"
},
{
"name": "FlowerCore__Database__ConnectionStrings__Sqlite",
"value": "Data Source=/data/network.db"
},
{
"name": "FlowerCore__Network__SnapshotStore__RootDirectory",
"value": "/data/snapshots"
},
{
"name": "FlowerCore__Network__SnapshotStore__UseGitHistory",
"value": "true"
},
{
"name": "FlowerCore__Network__IntendedModel__FilePath",
"value": "/data/intended.json"
}
],
"image": "localhost/fc-network-web:v20260621-network-chrome-1375ad7",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5340,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "web",
"ports": [
{
"containerPort": 5340,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5340,
"scheme": "HTTP"
},
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "50m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"startupProbe": {
"failureThreshold": 30,
"httpGet": {
"path": "/healthz",
"port": 5340,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"periodSeconds": 5,
"successThreshold": 1,
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "fc-network-web-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "fc-network-web",
"namespace": "fc-network"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`network.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "fc-network-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "fc-network-web-tls"
}
}
}

View File

@@ -1,33 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app": "fc-network-web",
"app.kubernetes.io/component": "web",
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "fc-network-web",
"app.kubernetes.io/part-of": "flowercore",
"flowercore.io/created-by": "bluejay-infra",
"flowercore.io/tenant-id": "system"
},
"name": "fc-network-web",
"namespace": "fc-network"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 5340
}
],
"selector": {
"app": "fc-network-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"name": "php-web-tls",
"namespace": "fc-php"
},
"spec": {
"dnsNames": [
"php.iamworkin.lan"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "step-ca-acme"
},
"secretName": "php-web-tls"
}
}

View File

@@ -1,11 +0,0 @@
{
"apiVersion": "v1",
"data": {
"appsettings.Production.json": "{\"PhpManager\":{\"Namespace\":\"fc-php\",\"Slowlog\":{\"Path\":\"/var/log/apache2/php-fpm-slow.log\",\"Sidecar\":{\"Enabled\":true,\"Image\":\"\"}},\"PoolConfig\":{\"StartServers\":null,\"MinSpareServers\":null,\"MaxSpareServers\":null,\"ProcessIdleTimeoutSeconds\":10,\"RequestTerminateTimeoutSeconds\":30},\"Certificates\":{\"TlsInspector\":{\"LogGracefulDegradeWarnings\":false}},\"Backups\":{\"StoragePath\":\"/data/backups\"},\"Ingress\":{\"DefaultMiddlewares\":[{\"Name\":\"php-tenant-rate-limit\",\"Namespace\":\"fc-php\"},{\"Name\":\"php-tenant-secure-headers\",\"Namespace\":\"fc-php\"}],\"TlsOption\":{\"Name\":\"php-tenant-tls13\",\"Namespace\":\"fc-php\"},\"Waf\":{\"Enabled\":true,\"Image\":\"owasp/modsecurity-crs:4.25-nginx-alpine-lts@sha256:88b59911549723e71beabf3b4aa47bbd31b00e79401f442e65ddfc430ae46343\",\"AllowedMethods\":\"GET HEAD POST OPTIONS DELETE\"}}},\"ApplicationArchives\":{\"WordPressCoreUrl\":\"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/wordpress/latest.tar.gz\",\"WordPressProxySourceUrl\":\"https://wordpress.org/latest.tar.gz\",\"WordPressLocalArchivePath\":\"/data/application-archives/latest.tar.gz\",\"MyBbCoreUrl\":\"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/mybb/latest.zip\",\"MyBbProxySourceUrl\":\"https://mybb.com/download/\",\"MyBbLocalArchivePath\":\"/data/application-archives/mybb-latest.zip\",\"MediaWikiCoreUrl\":\"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/mediawiki/latest.tar.gz\",\"MediaWikiProxySourceUrl\":\"https://releases.wikimedia.org/mediawiki/1.45/mediawiki-1.45.3.tar.gz\",\"MediaWikiLocalArchivePath\":\"/data/application-archives/mediawiki-latest.tar.gz\",\"DrupalCoreUrl\":\"http://php-web.fc-php.svc.cluster.local.:5400/api/v1/application-archives/drupal/latest.tar.gz\",\"DrupalProxySourceUrl\":\"https://ftp.drupal.org/files/projects/drupal-11.3.8.tar.gz\",\"DrupalLocalArchivePath\":\"/data/application-archives/drupal-latest.tar.gz\",\"BypassUpstreamTls\":true},\"ContainerBackend\":{\"Default\":\"Kubernetes\"},\"FlowerCore\":{\"Auth\":{\"Provider\":\"Oidc\",\"Enabled\":false,\"Oidc\":{\"Enabled\":true,\"Authority\":\"https://id.iamworkin.lan/application/o/php/\",\"Audience\":\"php\",\"ClientId\":\"php\",\"ClientSecret\":\"\"},\"Impersonation\":{\"Enabled\":false,\"DebugMode\":false}},\"Tenant\":{\"StrictMode\":false,\"JwtClaimsEnabled\":false,\"TenantClaimType\":\"fc:tenant\",\"ActorIdClaimType\":\"flowercore_actor_id\"},\"Account\":{\"AppId\":\"php\",\"DefaultTenantId\":\"default\",\"Impersonation\":{\"Enabled\":false,\"StrictMode\":false,\"TechSupportRoles\":[\"tech-support\"],\"Targets\":[]}},\"Hosting\":{\"AutoDns\":{\"Enabled\":true,\"DnsManagerBaseUrl\":\"https://dns.iamworkin.lan/\",\"ZoneName\":\"iamworkin.lan\",\"RecordType\":\"A\",\"TargetAddress\":\"10.0.57.202\",\"Ttl\":300,\"BypassTls\":true}},\"Database\":{\"Provider\":\"Sqlite\",\"ConnectionStrings\":{\"Sqlite\":\"Data Source=/data/php-manager.db\"}}}}"
},
"kind": "ConfigMap",
"metadata": {
"name": "php-web-config",
"namespace": "fc-php"
}
}

View File

@@ -1,186 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "flowercore",
"app.kubernetes.io/name": "php-waf"
},
"name": "php-waf",
"namespace": "fc-php"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "php-waf"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"labels": {
"app.kubernetes.io/name": "php-waf"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "BACKEND",
"value": "http://php-web.fc-php.svc.cluster.local:5400"
},
{
"name": "SERVER_NAME",
"value": "php.iamworkin.lan"
},
{
"name": "PORT",
"value": "8080"
},
{
"name": "PROXY_PRESERVE_HOST",
"value": "on"
},
{
"name": "PROXY_TIMEOUT",
"value": "60s"
},
{
"name": "MODSEC_RULE_ENGINE",
"value": "On"
},
{
"name": "MODSEC_AUDIT_ENGINE",
"value": "RelevantOnly"
},
{
"name": "MODSEC_AUDIT_LOG",
"value": "/dev/stdout"
},
{
"name": "MODSEC_AUDIT_LOG_TYPE",
"value": "Serial"
},
{
"name": "ALLOWED_METHODS",
"value": "GET HEAD POST OPTIONS DELETE"
},
{
"name": "LOGLEVEL",
"value": "warn"
},
{
"name": "ERRORLOG",
"value": "/dev/stderr"
},
{
"name": "ACCESSLOG",
"value": "/dev/stdout"
},
{
"name": "BLOCKING_PARANOIA",
"value": "1"
},
{
"name": "DETECTION_PARANOIA",
"value": "1"
},
{
"name": "ANOMALY_INBOUND",
"value": "5"
},
{
"name": "ANOMALY_OUTBOUND",
"value": "4"
}
],
"image": "owasp/modsecurity-crs:4.25-nginx-alpine-lts@sha256:88b59911549723e71beabf3b4aa47bbd31b00e79401f442e65ddfc430ae46343",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"httpHeaders": [
{
"name": "Host",
"value": "php.iamworkin.lan"
}
],
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 20,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 2
},
"name": "php-waf",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"httpHeaders": [
{
"name": "Host",
"value": "php.iamworkin.lan"
}
],
"path": "/healthz",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 2
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"enableServiceLinks": false,
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 101,
"runAsGroup": 101,
"runAsNonRoot": true,
"runAsUser": 101
},
"serviceAccount": "php-web",
"serviceAccountName": "php-web",
"terminationGracePeriodSeconds": 30
}
}
}
}

View File

@@ -1,219 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "flowercore",
"app.kubernetes.io/name": "php-web"
},
"name": "php-web",
"namespace": "fc-php"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "php-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-06-19T00:00:00-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5400",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "php-web"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "FlowerCore__Auth__Enabled",
"value": "false"
},
{
"name": "FlowerCore__Mcp__ApiKey__Key",
"valueFrom": {
"secretKeyRef": {
"key": "credential",
"name": "php-mcp-keys",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__Authority",
"valueFrom": {
"secretKeyRef": {
"key": "issuer_url",
"name": "php-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientId",
"valueFrom": {
"secretKeyRef": {
"key": "client_id",
"name": "php-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__ClientSecret",
"valueFrom": {
"secretKeyRef": {
"key": "client_secret",
"name": "php-oidc-client",
"optional": true
}
}
},
{
"name": "FlowerCore__Auth__Oidc__Audience",
"value": "php"
}
],
"image": "localhost/fc-php-web:v20260619-whc4-generated-waf-147f02a",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/metrics/prometheus",
"port": 5400,
"scheme": "HTTP"
},
"initialDelaySeconds": 20,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "php-web",
"ports": [
{
"containerPort": 5400,
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/metrics/prometheus",
"port": 5400,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
},
{
"mountPath": "/app/appsettings.Production.json",
"name": "config",
"readOnly": true,
"subPath": "appsettings.Production.json"
}
]
}
],
"dnsConfig": {
"nameservers": [
"10.43.0.10"
],
"options": [
{
"name": "ndots",
"value": "2"
}
],
"searches": [
"fc-php.svc.cluster.local",
"svc.cluster.local",
"cluster.local"
]
},
"dnsPolicy": "None",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"serviceAccount": "php-web",
"serviceAccountName": "php-web",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "php-web-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
},
{
"configMap": {
"defaultMode": 420,
"name": "php-web-config"
},
"name": "config"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "php-web",
"namespace": "fc-php"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`php.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "php-waf",
"port": 8080
}
]
}
],
"tls": {
"secretName": "php-web-tls"
}
}
}

View File

@@ -1,15 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "Middleware",
"metadata": {
"name": "php-tenant-rate-limit",
"namespace": "fc-php"
},
"spec": {
"rateLimit": {
"average": 120,
"burst": 240,
"period": "1m"
}
}
}

View File

@@ -1,18 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "Middleware",
"metadata": {
"name": "php-tenant-secure-headers",
"namespace": "fc-php"
},
"spec": {
"headers": {
"contentTypeNosniff": true,
"browserXssFilter": true,
"referrerPolicy": "strict-origin-when-cross-origin",
"stsSeconds": 31536000,
"stsIncludeSubdomains": true,
"stsPreload": false
}
}
}

View File

@@ -1,24 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "php-waf",
"namespace": "fc-php"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 8080,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "php-waf"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,23 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "php-web",
"namespace": "fc-php"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"port": 5400,
"protocol": "TCP",
"targetPort": 5400
}
],
"selector": {
"app.kubernetes.io/name": "php-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,8 +0,0 @@
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "php-web",
"namespace": "fc-php"
}
}

View File

@@ -1,11 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "TLSOption",
"metadata": {
"name": "php-tenant-tls13",
"namespace": "fc-php"
},
"spec": {
"minVersion": "VersionTLS13"
}
}

View File

@@ -1,22 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/presentations.db",
"FlowerCore__Database__Provider": "Sqlite",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.Presentations",
"PresentationStorage__HtmlBundlesRelativePath": "uploads/html-bundles",
"PresentationStorage__ImportsRelativePath": "uploads/imports",
"PresentationStorage__SlidesRelativePath": "uploads/slides",
"Security__AllowedOrigins__0": "https://presentations.iamworkin.lan"
},
"kind": "ConfigMap",
"metadata": {
"name": "presentations-web-config",
"namespace": "fc-presentations"
}
}

View File

@@ -1,161 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "presentations-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "presentations-web",
"namespace": "fc-presentations"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "presentations-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-04-23T14:47:39-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "presentations-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "presentations-web-config"
}
},
{
"secretRef": {
"name": "presentations-web-secrets"
}
}
],
"image": "localhost/fc-presentations:v20260619-presentations-a67ef22",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "presentations-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data",
"subPath": "data"
},
{
"mountPath": "/home/app/wwwroot/uploads",
"name": "data",
"subPath": "uploads"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"initContainers": [
{
"command": [
"/bin/sh",
"-lc",
"set -eu\nmkdir -p /mnt/pvc/data /mnt/pvc/uploads\n\nfor file in presentations.db presentations.db-shm presentations.db-wal; do\n if [ -f \"/mnt/pvc/${file}\" ] && [ ! -f \"/mnt/pvc/data/${file}\" ]; then\n mv \"/mnt/pvc/${file}\" \"/mnt/pvc/data/${file}\"\n fi\ndone\n\nif [ -d /mnt/pvc/dp-keys ] && [ ! -d /mnt/pvc/data/dp-keys ]; then\n mv /mnt/pvc/dp-keys /mnt/pvc/data/dp-keys\nfi\n\nfor directory in imports slides html-bundles; do\n if [ -d \"/mnt/pvc/${directory}\" ] && [ ! -d \"/mnt/pvc/uploads/${directory}\" ]; then\n mv \"/mnt/pvc/${directory}\" \"/mnt/pvc/uploads/${directory}\"\n fi\ndone\n\nmkdir -p \\\n /mnt/pvc/data/dp-keys \\\n /mnt/pvc/uploads/imports \\\n /mnt/pvc/uploads/slides \\\n /mnt/pvc/uploads/html-bundles\n"
],
"image": "localhost/fc-presentations:v20260619-presentations-a67ef22",
"imagePullPolicy": "Never",
"name": "storage-init",
"resources": {
"limits": {
"cpu": "250m",
"memory": "256Mi"
},
"requests": {
"cpu": "25m",
"memory": "64Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/mnt/pvc",
"name": "data"
}
]
}
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "presentations-web-data"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "presentations-web",
"namespace": "fc-presentations"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`presentations.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "presentations-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "presentations-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "presentations-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "presentations-web",
"namespace": "fc-presentations"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "presentations-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,20 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:5000",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/retail.db",
"FlowerCore__Database__Provider": "Sqlite",
"FlowerCore__Retail__BaseUrl": "https://retail.iamworkin.lan",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.Retail",
"PrintService__BaseUrl": "http://print.iamworkin.lan:5200"
},
"kind": "ConfigMap",
"metadata": {
"name": "retail-web-config",
"namespace": "fc-retail"
}
}

View File

@@ -1,120 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "retail-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "retail-web",
"namespace": "fc-retail"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 3,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "retail-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"fc.flowercore.io/healthz-anon": "true",
"fc.flowercore.io/probe-path": "/healthz",
"kubectl.kubernetes.io/restartedAt": "2026-06-02T01:34:08-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "5000",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "retail-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "retail-web-config"
}
}
],
"image": "localhost/fc-retail-web:v20260619-retail-faae9db",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "retail-web",
"ports": [
{
"containerPort": 5000,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/health",
"port": 5000,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "256Mi"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "retail-web-data"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "retail-web",
"namespace": "fc-retail"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`retail.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "retail-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "retail-web-tls"
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/managed-by": "argocd",
"app.kubernetes.io/name": "retail-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "retail-web",
"namespace": "fc-retail"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 5000
}
],
"selector": {
"app.kubernetes.io/name": "retail-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,21 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"Auth__ApiKey": "change-me",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/scoreboard.db",
"FlowerCore__Database__Provider": "Sqlite",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.Scoreboard",
"Security__AllowedOrigins__0": "https://scoreboard.iamworkin.lan",
"Security__ApiKey": "change-me"
},
"kind": "ConfigMap",
"metadata": {
"name": "scoreboard-web-config",
"namespace": "fc-scoreboard"
}
}

View File

@@ -1,132 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "scoreboard-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "scoreboard-web",
"namespace": "fc-scoreboard"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "scoreboard-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-06-12T16:43:22-05:00",
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "scoreboard-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "scoreboard-web-config"
}
}
],
"image": "localhost/fc-scoreboard-web:v20260620-scoreboard-vr-5df3f9a",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 5
},
"name": "scoreboard-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 5
},
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"initContainers": [
{
"command": [
"/bin/sh",
"-c",
"chown -R 1654:1654 /data && chmod -R u+rwX,g+rwX /data"
],
"image": "localhost/fc-scoreboard-web:v20260620-scoreboard-vr-5df3f9a",
"imagePullPolicy": "Never",
"name": "scoreboard-data-permissions",
"resources": {},
"securityContext": {
"runAsGroup": 0,
"runAsUser": 0
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
}
]
}
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch"
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "scoreboard-web-data"
}
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "scoreboard-web",
"namespace": "fc-scoreboard"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`scoreboard.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "scoreboard-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "scoreboard-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "scoreboard-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "scoreboard-web",
"namespace": "fc-scoreboard"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "scoreboard-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,19 +0,0 @@
{
"apiVersion": "v1",
"data": {
"ASPNETCORE_ENVIRONMENT": "Production",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"ASPNETCORE_URLS": "http://+:8080",
"FlowerCore__Database__ConnectionStrings__Sqlite": "Data Source=/data/segmentdisplay.db",
"FlowerCore__Database__Provider": "Sqlite",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.monitoring.svc.cluster.local:4317",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_SERVICE_NAME": "FlowerCore.SegmentDisplay",
"Security__AllowedOrigins__0": "https://segmentdisplay.iamworkin.lan"
},
"kind": "ConfigMap",
"metadata": {
"name": "segmentdisplay-web-config",
"namespace": "fc-segmentdisplay"
}
}

View File

@@ -1,147 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app.kubernetes.io/name": "segmentdisplay-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "segmentdisplay-web",
"namespace": "fc-segmentdisplay"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/name": "segmentdisplay-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"prometheus.io/path": "/metrics/prometheus",
"prometheus.io/port": "8080",
"prometheus.io/scrape": "true"
},
"labels": {
"app.kubernetes.io/name": "segmentdisplay-web",
"app.kubernetes.io/part-of": "flowercore"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "segmentdisplay-web-config"
}
},
{
"secretRef": {
"name": "segmentdisplay-web-secrets",
"optional": true
}
}
],
"image": "localhost/fc-segmentdisplay-web:v20260621-segmentdisplay-chrome-f059aa2",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 5
},
"name": "segmentdisplay-web",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 5
},
"resources": {},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "segmentdisplay-web-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "segmentdisplay-web",
"namespace": "fc-segmentdisplay"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`segmentdisplay.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "segmentdisplay-web",
"port": 80
}
]
}
],
"tls": {
"secretName": "segmentdisplay-web-tls"
}
}
}

View File

@@ -1,28 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app.kubernetes.io/name": "segmentdisplay-web",
"app.kubernetes.io/part-of": "flowercore"
},
"name": "segmentdisplay-web",
"namespace": "fc-segmentdisplay"
},
"spec": {
"internalTrafficPolicy": "Cluster",
"ports": [
{
"name": "http",
"port": 80,
"protocol": "TCP",
"targetPort": 8080
}
],
"selector": {
"app.kubernetes.io/name": "segmentdisplay-web"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
}

View File

@@ -1,151 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "signage-replay-web"
},
"name": "signage-replay-web",
"namespace": "fc-signage"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "signage-replay-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-05-04T13:50:05-05:00"
},
"labels": {
"app": "signage-replay-web"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:5280"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "ReplayFederation__Signage__Enabled",
"value": "true"
},
{
"name": "ReplayFederation__Signage__BaseUrl",
"value": "http://signage-web.fc-signage.svc.cluster.local.:5190"
},
{
"name": "ReplayFederation__Dms__Enabled",
"value": "true"
},
{
"name": "ReplayFederation__Dms__BaseUrl",
"value": "http://dms-web.fc-dms.svc.cluster.local.:8081"
}
],
"image": "localhost/fc-signage-replay-web:v20260619-signage-replay-4da0983",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5280,
"scheme": "HTTP"
},
"initialDelaySeconds": 20,
"periodSeconds": 20,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "signage-replay-web",
"ports": [
{
"containerPort": 5280,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5280,
"scheme": "HTTP"
},
"initialDelaySeconds": 10,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "256Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/home/app/logs",
"name": "logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,230 +0,0 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "signage-web"
},
"name": "signage-web",
"namespace": "fc-signage"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "signage-web"
}
},
"strategy": {
"type": "Recreate"
},
"template": {
"metadata": {
"annotations": {
"kubectl.kubernetes.io/restartedAt": "2026-05-04T13:50:05-05:00"
},
"labels": {
"app": "signage-web"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "ASPNETCORE_URLS",
"value": "http://+:5190"
},
{
"name": "ASPNETCORE_ENVIRONMENT",
"value": "Production"
},
{
"name": "TrafficSignal__RelayBridge__Enabled",
"value": "true"
},
{
"name": "TrafficSignal__RelayBridge__BaseUrl",
"value": "http://pirelay.iamworkin.lan:5100"
},
{
"name": "DatabaseProvider",
"value": "Sqlite"
},
{
"name": "ConnectionStrings__DefaultConnection",
"value": "Data Source=/data/signage.db"
},
{
"name": "Serilog__MinimumLevel__Default",
"value": "Information"
},
{
"name": "Serilog__WriteTo__0__Name",
"value": "Console"
},
{
"name": "Kestrel__Endpoints__Http__Url",
"value": "http://+:5190"
},
{
"name": "Kestrel__Endpoints__Grpc__Url",
"value": "http://+:5191"
},
{
"name": "FlowerCore__DefaultTenantId",
"value": "default"
},
{
"name": "FlowerCore__Signage__Announcements__AudibleEnabled",
"value": "true"
},
{
"name": "FlowerCore__Signage__Announcements__DefaultVoiceName",
"value": "en_US-amy-low"
},
{
"name": "FlowerCore__Signage__Announcements__Piper__Host",
"value": "10.0.57.17"
},
{
"name": "FlowerCore__Signage__Announcements__Piper__Port",
"value": "10400"
},
{
"name": "FlowerCore__Signage__Announcements__Piper__TimeoutSeconds",
"value": "120"
}
],
"image": "localhost/fc-signage-web:v20260620-signage-sec5-5ee8f74",
"imagePullPolicy": "Never",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5190,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 30,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "signage-web",
"ports": [
{
"containerPort": 5190,
"name": "http",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/healthz",
"port": 5190,
"scheme": "HTTP"
},
"initialDelaySeconds": 15,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "10m",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"readOnlyRootFilesystem": true
},
"startupProbe": {
"failureThreshold": 30,
"periodSeconds": 5,
"successThreshold": 1,
"tcpSocket": {
"port": 5190
},
"timeoutSeconds": 1
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/data",
"name": "data"
},
{
"mountPath": "/app/data",
"name": "data"
},
{
"mountPath": "/app/Cache",
"name": "data"
},
{
"mountPath": "/app/storage",
"name": "data"
},
{
"mountPath": "/app/wwwroot/uploads",
"name": "data"
},
{
"mountPath": "/tmp",
"name": "tmp"
},
{
"mountPath": "/app/logs",
"name": "logs"
},
{
"mountPath": "/app/wwwroot/announcement-audio",
"name": "data"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1654,
"runAsGroup": 1654,
"runAsNonRoot": true,
"runAsUser": 1654
},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "data",
"persistentVolumeClaim": {
"claimName": "signage-data"
}
},
{
"emptyDir": {},
"name": "tmp"
},
{
"emptyDir": {},
"name": "logs"
}
]
}
}
}
}

View File

@@ -1,29 +0,0 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "IngressRoute",
"metadata": {
"name": "signage-replay-web",
"namespace": "fc-signage"
},
"spec": {
"entryPoints": [
"websecure"
],
"routes": [
{
"kind": "Rule",
"match": "Host(`replay.iamworkin.lan`)",
"priority": 100,
"services": [
{
"name": "signage-replay-web",
"port": 5280
}
]
}
],
"tls": {
"secretName": "signage-replay-web-tls"
}
}
}

Some files were not shown because too many files have changed in this diff Show More