-
Notifications
You must be signed in to change notification settings - Fork 40
Feat: AIAC Event Broker + Keycloak SPI listener (phase 2, PR 2) #754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
dd31fa4
9041072
ad90b0a
eb85ee3
371ac40
b565000
e4601e8
f17aee4
092853d
0905561
425a8b1
9266f60
bee62e6
20a71eb
37bd3d0
4efbe29
9401264
aa2411e
b85f514
f1c7366
58f225e
9d3a36e
1c8372e
199da88
c92cb89
432a884
087d19b
8013618
316c8f7
3b05cdb
2639f81
f1e6ae4
677d103
591b433
091c0bf
24e855e
e2d37eb
bc5fdcf
2233b70
113bcf9
ba30155
cf5bf7d
9f79b42
37223c8
b55011f
1c3e319
89374fe
010215f
21bd3f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,8 @@ This guide covers the full AIAC deployment in the `aiac-system` namespace. | |
| |---|---|---| | ||
| | `pdp-interface-deployment.yaml` | Rossoctl Interface Pod (IdP Configuration Service + PDP Policy Writer **Phase 1 rego-file mock** `aiac-pdp-policy-opa`) + 2 ClusterIP Services | 7071, 7072 | | ||
| | `policy-model-store-statefulset.yaml` | Policy Model Store StatefulSet + 1 Gi PVC + headless Service + ClusterIP Service | 7074 | | ||
| | `agent-deployment.yaml` | Agent Pod Deployment (AIAC Agent) + ClusterIP Service | 7070 | | ||
| | `event-broker-deployment.yaml` | NATS JetStream Event Broker Deployment + ClusterIP Service | 4222 | | ||
| | `agent-deployment.yaml` | Agent Pod Deployment (`aiac-init` init container + AIAC Agent) + ClusterIP Service | 7070 | | ||
|
|
||
| ## Prerequisites | ||
|
|
||
|
|
@@ -37,11 +38,13 @@ docker build -f aiac/src/aiac/pdp/service/policy/opa/Dockerfile \ | |
| docker build -f aiac/src/aiac/policy/model_store/service/Dockerfile \ | ||
| -t localhost/aiac-policy-model-store:local aiac/src/ | ||
|
|
||
| # AIAC Agent | ||
| # AIAC Agent (also used as the aiac-init init container, via a command override) — context: aiac/src/ | ||
| docker build -f aiac/src/aiac/agent/controller/Dockerfile \ | ||
| -t localhost/aiac-agent:local aiac/src/ | ||
| ``` | ||
|
|
||
| The Event Broker uses the stock `nats:latest` image — no build step. | ||
|
|
||
| ## 2 — Load images into the cluster | ||
|
|
||
| **Kind (local development)** | ||
|
|
@@ -53,15 +56,26 @@ kind load docker-image localhost/aiac-policy-model-store:local --name <clust | |
| kind load docker-image localhost/aiac-agent:local --name <cluster-name> | ||
| ``` | ||
|
|
||
| For a fully air-gapped Kind cluster (no outbound network access), also pull and load the | ||
| NATS image; `event-broker-deployment.yaml` uses `imagePullPolicy: IfNotPresent`, so a | ||
| networked cluster can skip this and pull it directly: | ||
|
|
||
| ```bash | ||
| docker pull nats:latest | ||
| kind load docker-image nats:latest --name <cluster-name> | ||
| ``` | ||
|
|
||
| **Remote registry** — tag, push, then update the `image:` fields in the manifests to match. | ||
|
|
||
| > **Note:** the manifests set `imagePullPolicy: Never` because images are side-loaded | ||
| > into a local Kind cluster (dev only). For a real cluster that pulls from a registry, | ||
| > change these to `imagePullPolicy: IfNotPresent` (or `Always`). | ||
| ## 3 — Create the secrets | ||
|
|
||
| ## 3 — Create the admin secret | ||
| Two Secrets must exist in `aiac-system` before applying the manifests. Create the namespace first, then both secrets. | ||
|
|
||
| The Interface Pod requires a `keycloak-admin-secret` Secret. Create it once per cluster before applying the manifests: | ||
| ```bash | ||
| kubectl create namespace aiac-system | ||
| ``` | ||
|
|
||
| **`keycloak-admin-secret`** — required by the Interface Pod: | ||
|
|
||
| ```bash | ||
| kubectl create secret generic keycloak-admin-secret \ | ||
|
|
@@ -114,10 +128,13 @@ Edit the `aiac-pdp-config` ConfigMap in `pdp-interface-deployment.yaml` to match | |
| | `AIAC_PDP_POLICY_URL` | `http://aiac-pdp-policy-service:7072` | Agent | | ||
| | `AIAC_POLICY_MODEL_STORE_URL` | `http://aiac-policy-model-store-service:7074` | Agent | | ||
| | `SERVICEPOLICY_DB_PATH` | `/data/policy_model.db` | Policy Model Store | | ||
| | `NATS_URL` | `nats://aiac-event-broker-service:4222` | Agent — **added in Phase 2** (Event Broker, issue 4.19) | | ||
| | `NATS_URL` | `nats://aiac-event-broker-service:4222` | Agent, `aiac-init` — Event Broker ClusterIP address | | ||
| | `AIAC_RAG_INGEST_URL` | `http://aiac-rag-service:7073` | Init container — **added in Phase 3** (RAG Pod, issue 4.20) | | ||
| | `AIAC_CHROMADB_URL` | `http://aiac-rag-service:8000` | Agent — **added in Phase 3** (RAG Pod, issue 4.20) | | ||
|
|
||
| `aiac-init` treats `AIAC_RAG_INGEST_URL` as optional and skips the RAG Ingest health check | ||
| when it is unset (the current phase has no RAG pod deployed yet). | ||
|
|
||
| ## 5 — Deploy | ||
|
|
||
| Apply in dependency order: | ||
|
|
@@ -126,17 +143,21 @@ Apply in dependency order: | |
| # 1. Interface Pod — creates the namespace, ConfigMap, Secret, and ClusterIP Services | ||
| kubectl apply -f aiac/k8s/pdp-interface-deployment.yaml | ||
|
|
||
| # 2. Policy Model Store — needs the aiac-system namespace | ||
| # 2. Event Broker — NATS JetStream, no dependencies | ||
| kubectl apply -f aiac/k8s/event-broker-deployment.yaml | ||
|
|
||
| # 3. Policy Model Store — needs the aiac-system namespace | ||
| kubectl apply -f aiac/k8s/policy-model-store-statefulset.yaml | ||
|
|
||
| # 3. Agent — depends on the Interface Pod + Policy Model Store already being healthy | ||
| # 4. Agent — aiac-init waits for NATS + Interface Pod + Policy Model Store to be healthy | ||
| kubectl apply -f aiac/k8s/agent-deployment.yaml | ||
|
Comment on lines
+152
to
153
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift Match the documented startup gate to
🤖 Prompt for AI Agents |
||
| ``` | ||
|
|
||
| Wait for all pods to be ready: | ||
|
|
||
| ```bash | ||
| kubectl wait deployment/aiac-interface -n aiac-system --for=condition=Available --timeout=120s | ||
| kubectl wait deployment/aiac-event-broker -n aiac-system --for=condition=Available --timeout=120s | ||
| kubectl wait statefulset/aiac-policy-model-store -n aiac-system --for=jsonpath='{.status.readyReplicas}'=1 --timeout=120s | ||
| kubectl wait deployment/aiac-agent -n aiac-system --for=condition=Available --timeout=120s | ||
| ``` | ||
|
|
@@ -166,9 +187,29 @@ kubectl port-forward svc/aiac-agent-service 7070:7070 -n aiac-system & | |
| curl http://localhost:7070/health | ||
| # {"status":"ok"} | ||
|
|
||
| #cleanup all the tunnels that were opended to the cluster | ||
| pkill -f "port-forward" | ||
|
Comment on lines
+190
to
191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Limit cleanup to tunnels created by this guide.
🤖 Prompt for AI Agents |
||
| ``` | ||
|
|
||
| ### NATS Event Broker — end-to-end check | ||
|
|
||
| Requires the [`nats` CLI](https://github.com/nats-io/natscli). | ||
|
|
||
| ```bash | ||
| kubectl port-forward svc/aiac-event-broker-service 4222:4222 -n aiac-system & | ||
| nats context save aiac --server nats://localhost:4222 | ||
| nats context select aiac | ||
|
|
||
| # Publish a test service-onboarding event (use a real IdP client UUID to see it | ||
| # processed end to end; any string will demonstrate delivery either way): | ||
| nats pub aiac.apply.service.<test-uuid> '{"id":"<test-uuid>"}' | ||
|
Comment on lines
+198
to
+205
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Wait for the NATS port-forward before publishing. The guide starts 🤖 Prompt for AI Agents |
||
|
|
||
| # Confirm the Agent processed and acked it (no redelivery): | ||
| kubectl logs deployment/aiac-agent -n aiac-system -c aiac-agent --tail=50 | ||
|
|
||
| pkill -f "port-forward.*4222" | ||
| ``` | ||
|
|
||
| Run the IdP data smoke test: | ||
|
|
||
| ```bash | ||
|
|
@@ -181,9 +222,10 @@ pkill -f "port-forward.*7071" | |
| ## Redeploying after a code change | ||
|
|
||
| ```bash | ||
| # Rebuild the changed image, e.g. IdP Configuration Service: | ||
| # Rebuild the changed image, e.g. IdP Configuration Service (context: the service dir): | ||
| docker build -f aiac/src/aiac/idp/service/configuration/keycloak/Dockerfile \ | ||
| -t localhost/aiac-pdp-config:local aiac/src/ | ||
| -t localhost/aiac-pdp-config:local \ | ||
| aiac/src/aiac/idp/service/configuration/keycloak/ | ||
| kind load docker-image localhost/aiac-pdp-config:local --name <cluster-name> | ||
|
|
||
| # Restart the affected deployment: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| apiVersion: apps/v1 | ||
| kind: Deployment | ||
| metadata: | ||
| name: aiac-event-broker | ||
| namespace: aiac-system | ||
| spec: | ||
| replicas: 1 | ||
| selector: | ||
| matchLabels: | ||
| app: aiac-event-broker | ||
| template: | ||
| metadata: | ||
| labels: | ||
| app: aiac-event-broker | ||
| spec: | ||
| containers: | ||
| - name: nats | ||
| image: nats:2.14-alpine | ||
| imagePullPolicy: IfNotPresent | ||
| args: ["-js", "-sd", "/data/jetstream"] | ||
| ports: | ||
| - containerPort: 4222 | ||
| volumeMounts: | ||
| - name: jetstream-data | ||
| mountPath: /data/jetstream | ||
| volumes: | ||
| - name: jetstream-data | ||
| emptyDir: {} | ||
|
Comment on lines
+16
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Set the required Pod and container security contexts. The manifest does not declare the required non-root UID/GID, seccomp profile, privilege-escalation restriction, read-only root filesystem, capability drop, or writable As per coding guidelines, “Apply the pod-security baseline: 🤖 Prompt for AI AgentsSource: Coding guidelines
Comment on lines
+17
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Add probes and resource requests and limits. The Event Broker has no readiness probe, liveness probe, CPU request, memory request, CPU limit, or memory limit. The Agent init flow depends on this broker. Add probes and resource settings so Kubernetes can remove an unready endpoint, recover an unhealthy broker, and reserve broker capacity. Kubernetes uses readiness and liveness probes for these actions, and schedules Pods using resource requests. (kubernetes.io) As per coding guidelines, “Core workloads must provide both readiness and liveness probes and define CPU and memory requests and limits.” 🤖 Prompt for AI AgentsSource: Coding guidelines
Comment on lines
+24
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Use persistent storage for JetStream data.
🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| --- | ||
| apiVersion: v1 | ||
| kind: Service | ||
| metadata: | ||
| name: aiac-event-broker-service | ||
| namespace: aiac-system | ||
| spec: | ||
| selector: | ||
| app: aiac-event-broker | ||
| ports: | ||
| - name: nats | ||
| port: 4222 | ||
| targetPort: 4222 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| target/ | ||
| .idea/ | ||
| .vscode/ | ||
| .git/ | ||
| .gitignore | ||
| *.iml | ||
| README.md | ||
| Makefile |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # Maven build output — regenerated by `mvn package`, never committed. | ||
| target/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # syntax=docker/dockerfile:1.7 | ||
|
|
||
| ARG KEYCLOAK_IMAGE=quay.io/keycloak/keycloak:26.6.3 | ||
|
|
||
| # Stage 1: build the SPI JAR (shaded — bundles jnats, since it isn't on Keycloak's classpath). | ||
| FROM maven:3.9-eclipse-temurin-17 AS jar-builder | ||
| WORKDIR /build | ||
| COPY pom.xml . | ||
| COPY src ./src | ||
| RUN --mount=type=cache,target=/root/.m2 mvn -B -DskipTests package | ||
|
|
||
| # Stage 2: drop the JAR into Keycloak and run `kc.sh build` so the augmented server is baked | ||
| # into the final image (no per-pod build at startup). | ||
| FROM ${KEYCLOAK_IMAGE} AS keycloak-builder | ||
| COPY --from=jar-builder /build/target/aiac-event-listener-*.jar /opt/keycloak/providers/ | ||
| RUN /opt/keycloak/bin/kc.sh build | ||
|
|
||
| # Stage 3: final runtime image — copy the augmented Keycloak from stage 2. | ||
| FROM ${KEYCLOAK_IMAGE} | ||
| COPY --from=keycloak-builder /opt/keycloak/ /opt/keycloak/ | ||
| ENTRYPOINT ["/opt/keycloak/bin/kc.sh"] | ||
| CMD ["start"] | ||
|
Comment on lines
+19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Run the final image as UID 10001. Create the As per coding guidelines, “Run all AIAC service containers as non-root UID 10001 by creating the 🤖 Prompt for AI AgentsSources: Coding guidelines, Learnings |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| SPI_VERSION := 0.1.0 | ||
| KEYCLOAK_VERSION := 26.6.3 | ||
|
|
||
| JAR := target/aiac-event-listener-$(SPI_VERSION).jar | ||
|
|
||
| REGISTRY ?= ghcr.io/rossoctl/cortex | ||
| IMAGE ?= aiac-keycloak-event-listener | ||
| IMAGE_TAG ?= $(SPI_VERSION)-kc$(KEYCLOAK_VERSION) | ||
| IMAGE_REF := $(REGISTRY)/$(IMAGE):$(IMAGE_TAG) | ||
|
|
||
| # Auto-detect if the 'docker' client is using a Podman backend. | ||
| IS_PODMAN_DETECT := $(shell docker info 2>/dev/null | grep -q "/var/lib/containers/storage" && echo "true") | ||
| ifeq ($(DOCKER_IS_PODMAN),) | ||
| DOCKER_IS_PODMAN := $(IS_PODMAN_DETECT) | ||
| endif | ||
|
|
||
| PLATFORMS ?= linux/amd64,linux/arm64 | ||
|
|
||
| HOST_ARCH := $(shell uname -m) | ||
| ifeq ($(HOST_ARCH),x86_64) | ||
| HOST_PLATFORM := linux/amd64 | ||
| else ifeq ($(HOST_ARCH),aarch64) | ||
| HOST_PLATFORM := linux/arm64 | ||
| else ifeq ($(HOST_ARCH),arm64) | ||
| HOST_PLATFORM := linux/arm64 | ||
| else | ||
| HOST_PLATFORM := linux/amd64 | ||
| endif | ||
|
|
||
| .PHONY: all package test clean image push install-info | ||
|
|
||
| all: package | ||
|
|
||
| package: $(JAR) | ||
|
|
||
| $(JAR): | ||
| mvn package | ||
|
|
||
| test: | ||
| mvn test | ||
|
|
||
| clean: | ||
| mvn clean | ||
|
|
||
| image: | ||
| @if [ "$(DOCKER_IS_PODMAN)" = "true" ]; then \ | ||
| echo "Info: Podman backend detected."; \ | ||
| fi | ||
| docker buildx build \ | ||
| --platform $(PLATFORMS) \ | ||
| --build-arg KEYCLOAK_IMAGE=quay.io/keycloak/keycloak:$(KEYCLOAK_VERSION) \ | ||
| -t $(IMAGE_REF) . | ||
| docker buildx build \ | ||
| --platform $(HOST_PLATFORM) \ | ||
| --build-arg KEYCLOAK_IMAGE=quay.io/keycloak/keycloak:$(KEYCLOAK_VERSION) \ | ||
| -t $(IMAGE_REF) --load . | ||
| @echo "Built $(IMAGE_REF) for $(PLATFORMS) (loaded $(HOST_PLATFORM) locally)" | ||
|
|
||
| push: | ||
| docker buildx build \ | ||
| --platform $(PLATFORMS) \ | ||
| --build-arg KEYCLOAK_IMAGE=quay.io/keycloak/keycloak:$(KEYCLOAK_VERSION) \ | ||
| -t $(IMAGE_REF) --push . | ||
| @echo "Pushed $(IMAGE_REF) for $(PLATFORMS)" | ||
|
|
||
| install-info: | ||
| @echo "JAR-only install:" | ||
| @echo " Copy $(JAR) into your Keycloak/RHBK providers directory, then run:" | ||
| @echo " kc.sh build" | ||
| @echo " and restart Keycloak." | ||
| @echo | ||
| @echo "Custom image install:" | ||
| @echo " make push # builds and pushes $(IMAGE_REF)" | ||
| @echo " Override the Keycloak image in your Helm values / Operator CR to: $(IMAGE_REF)" | ||
| @echo " (this repo does not manage that Helm chart — see README.md)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Use one NATS image tag in the guide and manifest.
aiac/k8s/event-broker-deployment.yamldeploysnats:2.14-alpine, but these lines document and loadnats:latest. In an air-gapped Kind cluster, the loaded image does not satisfy the manifest, so the broker can enterImagePullBackOff. Update the guide tonats:2.14-alpine, or change the manifest and all commands together.Also applies to: 59-65
🤖 Prompt for AI Agents