Skip to content

Commit 4ccf702

Browse files
committed
feat: add OpenShift overlay with AuthBridge configs, SCC, and Istio shared trust
Add a kustomize overlay (config/openshift) that composes the base operator deployment with OpenShift-specific resources: AuthBridge sidecar configuration: - authbridge-runtime-config ConfigMap (JWT validation, token exchange) - envoy-config ConfigMap (inbound/outbound listeners with ext_proc) - spiffe-helper-config ConfigMap (SVID and JWT SVID file output) Security: - kagenti-authbridge SCC allowing CSI volumes (csi.spiffe.io) - ClusterRole and ClusterRoleBinding for SCC delegation - Runtime SCC RoleBinding creation per agent namespace Istio shared trust (cert-manager): - Self-signed root CA ClusterIssuer and Certificate - Intermediate CA Certificates for istio-system and openshift-ingress Operator wiring: - Makefile targets: deploy-openshift, undeploy-openshift, manifests-openshift - POD_NAMESPACE env injection via manager webhook patch - Dynamic ClusterDefaultsNamespace resolved from operator pod namespace Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>
1 parent f68d4b2 commit 4ccf702

15 files changed

Lines changed: 513 additions & 2 deletions

kagenti-operator/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
193193
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} .
194194
- $(CONTAINER_TOOL) buildx rm kagenti-operator-builder
195195

196+
.PHONY: manifests-openshift
197+
manifests-openshift: manifests kustomize ## Build OpenShift standalone kustomize overlay manifests.
198+
$(KUSTOMIZE) build config/openshift
199+
196200
.PHONY: build-installer
197201
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
198202
mkdir -p dist
@@ -229,10 +233,19 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in
229233
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
230234
$(KUSTOMIZE) build config/default | $(KUBECTL) apply --server-side -f -
231235

236+
.PHONY: deploy-openshift
237+
deploy-openshift: manifests kustomize ## Deploy controller with OpenShift extras (istio-trust, authbridge, SCC).
238+
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
239+
$(KUSTOMIZE) build config/openshift | $(KUBECTL) apply --server-side -f -
240+
232241
.PHONY: undeploy
233242
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
234243
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
235244

245+
.PHONY: undeploy-openshift
246+
undeploy-openshift: kustomize ## Undeploy controller with OpenShift extras. Call with ignore-not-found=true to ignore resource not found errors.
247+
$(KUSTOMIZE) build config/openshift | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
248+
236249
.PHONY: chart
237250
chart: manifests kustomize
238251
cd config/manager && $(KUSTOMIZE) edit set image controller=$(shell echo ${IMG} | sed 's/\(:.*\)v/\1/')

kagenti-operator/cmd/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ func main() {
365365
}
366366
}
367367

368+
// ========================================
369+
// Operator namespace resolution
370+
// ========================================
371+
controller.SetClusterDefaultsNamespace(getOperatorNamespace())
372+
368373
if !requireA2ASignature && !enableVerifiedFetch {
369374
setupLog.Info("WARNING: Neither --require-a2a-signature nor --enable-verified-fetch is set. " +
370375
"Identity binding requires at least one trust mechanism to function. " +
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# AuthBridge runtime configuration template.
2+
# The operator copies this to agent namespaces via ensureNamespaceConfigMaps.
3+
apiVersion: v1
4+
kind: ConfigMap
5+
metadata:
6+
name: authbridge-runtime-config
7+
namespace: kagenti-operator-system
8+
labels:
9+
app.kubernetes.io/name: kagenti-operator
10+
app.kubernetes.io/component: authbridge
11+
app.kubernetes.io/managed-by: kustomize
12+
data:
13+
config.yaml: |
14+
spiffe: {}
15+
pipeline:
16+
inbound:
17+
plugins:
18+
- name: jwt-validation
19+
config:
20+
issuer: "http://keycloak.localtest.me:8080/realms/kagenti"
21+
keycloak_url: "http://keycloak-service.keycloak.svc:8080"
22+
keycloak_realm: "kagenti"
23+
outbound:
24+
plugins:
25+
- name: token-exchange
26+
config:
27+
keycloak_url: "http://keycloak-service.keycloak.svc:8080"
28+
keycloak_realm: "kagenti"
29+
default_policy: "passthrough"
30+
identity:
31+
type: "client-secret"
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Envoy proxy configuration template for envoy-sidecar mode.
2+
# The operator copies this to agent namespaces via ensureNamespaceConfigMaps.
3+
apiVersion: v1
4+
kind: ConfigMap
5+
metadata:
6+
name: envoy-config
7+
namespace: kagenti-operator-system
8+
labels:
9+
app.kubernetes.io/name: kagenti-operator
10+
app.kubernetes.io/component: authbridge
11+
app.kubernetes.io/managed-by: kustomize
12+
data:
13+
envoy.yaml: |
14+
admin:
15+
address:
16+
socket_address:
17+
protocol: TCP
18+
address: 127.0.0.1
19+
port_value: 9901
20+
21+
static_resources:
22+
listeners:
23+
- name: outbound_listener
24+
address:
25+
socket_address:
26+
protocol: TCP
27+
address: 0.0.0.0
28+
port_value: 15123
29+
listener_filters:
30+
- name: envoy.filters.listener.original_dst
31+
typed_config:
32+
"@type": type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst
33+
- name: envoy.filters.listener.tls_inspector
34+
typed_config:
35+
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
36+
filter_chains:
37+
- filter_chain_match:
38+
transport_protocol: tls
39+
filters:
40+
- name: envoy.filters.network.tcp_proxy
41+
typed_config:
42+
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
43+
stat_prefix: outbound_tls_passthrough
44+
cluster: original_destination
45+
- filter_chain_match:
46+
transport_protocol: raw_buffer
47+
filters:
48+
- name: envoy.filters.network.http_connection_manager
49+
typed_config:
50+
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
51+
stat_prefix: outbound_http
52+
codec_type: AUTO
53+
route_config:
54+
name: outbound_routes
55+
virtual_hosts:
56+
- name: catch_all
57+
domains: ["*"]
58+
routes:
59+
- match:
60+
prefix: "/"
61+
route:
62+
cluster: original_destination
63+
timeout: 300s
64+
http_filters:
65+
- name: envoy.filters.http.ext_proc
66+
typed_config:
67+
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
68+
grpc_service:
69+
envoy_grpc:
70+
cluster_name: ext_proc_cluster
71+
timeout: 300s
72+
allow_mode_override: true
73+
processing_mode:
74+
request_header_mode: SEND
75+
response_header_mode: SEND
76+
request_body_mode: NONE
77+
response_body_mode: NONE
78+
- name: envoy.filters.http.router
79+
typed_config:
80+
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
81+
82+
- name: inbound_listener
83+
address:
84+
socket_address:
85+
protocol: TCP
86+
address: 0.0.0.0
87+
port_value: 15124
88+
listener_filters:
89+
- name: envoy.filters.listener.original_dst
90+
typed_config:
91+
"@type": type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst
92+
filter_chains:
93+
- filters:
94+
- name: envoy.filters.network.http_connection_manager
95+
typed_config:
96+
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
97+
stat_prefix: inbound_http
98+
codec_type: AUTO
99+
route_config:
100+
name: inbound_routes
101+
virtual_hosts:
102+
- name: local_app
103+
domains: ["*"]
104+
routes:
105+
- match:
106+
prefix: "/"
107+
route:
108+
cluster: original_destination
109+
timeout: 300s
110+
http_filters:
111+
- name: envoy.filters.http.lua
112+
typed_config:
113+
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
114+
inline_code: |
115+
function envoy_on_request(request_handle)
116+
request_handle:headers():add("x-authbridge-direction", "inbound")
117+
end
118+
- name: envoy.filters.http.ext_proc
119+
typed_config:
120+
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
121+
grpc_service:
122+
envoy_grpc:
123+
cluster_name: ext_proc_cluster
124+
timeout: 300s
125+
allow_mode_override: true
126+
processing_mode:
127+
request_header_mode: SEND
128+
response_header_mode: SEND
129+
request_body_mode: NONE
130+
response_body_mode: NONE
131+
- name: envoy.filters.http.router
132+
typed_config:
133+
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
134+
135+
clusters:
136+
- name: original_destination
137+
connect_timeout: 30s
138+
type: ORIGINAL_DST
139+
lb_policy: CLUSTER_PROVIDED
140+
original_dst_lb_config:
141+
use_http_header: false
142+
143+
- name: ext_proc_cluster
144+
connect_timeout: 5s
145+
type: STATIC
146+
lb_policy: ROUND_ROBIN
147+
http2_protocol_options: {}
148+
load_assignment:
149+
cluster_name: ext_proc_cluster
150+
endpoints:
151+
- lb_endpoints:
152+
- endpoint:
153+
address:
154+
socket_address:
155+
address: 127.0.0.1
156+
port_value: 9090
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resources:
2+
- authbridge-runtime-config.yaml
3+
- envoy-config.yaml
4+
- spiffe-helper-config.yaml
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPIFFE helper configuration template.
2+
# The operator copies this to agent namespaces via ensureNamespaceConfigMaps.
3+
apiVersion: v1
4+
kind: ConfigMap
5+
metadata:
6+
name: spiffe-helper-config
7+
namespace: kagenti-operator-system
8+
labels:
9+
app.kubernetes.io/name: kagenti-operator
10+
app.kubernetes.io/component: authbridge
11+
app.kubernetes.io/managed-by: kustomize
12+
data:
13+
helper.conf: |
14+
agent_address = "/spiffe-workload-api/spire-agent.sock"
15+
cmd = ""
16+
cmd_args = ""
17+
svid_file_name = "/opt/svid.pem"
18+
svid_key_file_name = "/opt/svid_key.pem"
19+
svid_bundle_file_name = "/opt/svid_bundle.pem"
20+
cert_file_mode = 0644
21+
key_file_mode = 0640
22+
jwt_svids = [{jwt_audience="http://keycloak.localtest.me:8080/realms/kagenti", jwt_svid_file_name="/opt/jwt_svid.token"}]
23+
jwt_svid_file_mode = 0644
24+
include_federated_domains = true

kagenti-operator/config/default/manager_webhook_patch.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ spec:
1212
- containerPort: 9443
1313
name: webhook-server
1414
protocol: TCP
15+
env:
16+
- name: POD_NAMESPACE
17+
valueFrom:
18+
fieldRef:
19+
fieldPath: metadata.namespace
1520
volumeMounts:
1621
- mountPath: /tmp/k8s-webhook-server/serving-certs
1722
name: cert
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# cert-manager Certificates for multi-mesh Istio shared trust.
2+
# Root CA in cert-manager namespace, intermediate CAs per Istio control plane.
3+
---
4+
apiVersion: cert-manager.io/v1
5+
kind: Certificate
6+
metadata:
7+
name: istio-mesh-root-ca
8+
namespace: cert-manager
9+
labels:
10+
app.kubernetes.io/name: kagenti-operator
11+
app.kubernetes.io/component: shared-trust
12+
app.kubernetes.io/managed-by: kustomize
13+
spec:
14+
isCA: true
15+
commonName: istio-mesh-root-ca
16+
duration: 87600h
17+
renewBefore: 720h
18+
secretName: istio-mesh-root-ca-secret
19+
privateKey:
20+
algorithm: RSA
21+
size: 4096
22+
issuerRef:
23+
name: istio-mesh-root-selfsigned
24+
kind: ClusterIssuer
25+
---
26+
apiVersion: cert-manager.io/v1
27+
kind: Certificate
28+
metadata:
29+
name: istio-cacerts-default
30+
namespace: istio-system
31+
labels:
32+
app.kubernetes.io/name: kagenti-operator
33+
app.kubernetes.io/component: shared-trust
34+
app.kubernetes.io/managed-by: kustomize
35+
spec:
36+
isCA: true
37+
commonName: istio-ca-default
38+
duration: 8760h
39+
renewBefore: 720h
40+
secretName: istio-cacerts-default-cert
41+
privateKey:
42+
algorithm: RSA
43+
size: 2048
44+
issuerRef:
45+
name: istio-mesh-ca
46+
kind: ClusterIssuer
47+
---
48+
apiVersion: cert-manager.io/v1
49+
kind: Certificate
50+
metadata:
51+
name: istio-cacerts-openshift-gateway
52+
namespace: openshift-ingress
53+
labels:
54+
app.kubernetes.io/name: kagenti-operator
55+
app.kubernetes.io/component: shared-trust
56+
app.kubernetes.io/managed-by: kustomize
57+
spec:
58+
isCA: true
59+
commonName: istio-ca-openshift-gateway
60+
duration: 8760h
61+
renewBefore: 720h
62+
secretName: istio-cacerts-og-cert
63+
privateKey:
64+
algorithm: RSA
65+
size: 2048
66+
issuerRef:
67+
name: istio-mesh-ca
68+
kind: ClusterIssuer
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# ClusterIssuers for multi-mesh Istio shared trust via cert-manager.
2+
---
3+
apiVersion: cert-manager.io/v1
4+
kind: ClusterIssuer
5+
metadata:
6+
name: istio-mesh-root-selfsigned
7+
labels:
8+
app.kubernetes.io/name: kagenti-operator
9+
app.kubernetes.io/component: shared-trust
10+
app.kubernetes.io/managed-by: kustomize
11+
spec:
12+
selfSigned: {}
13+
---
14+
apiVersion: cert-manager.io/v1
15+
kind: ClusterIssuer
16+
metadata:
17+
name: istio-mesh-ca
18+
labels:
19+
app.kubernetes.io/name: kagenti-operator
20+
app.kubernetes.io/component: shared-trust
21+
app.kubernetes.io/managed-by: kustomize
22+
spec:
23+
ca:
24+
secretName: istio-mesh-root-ca-secret
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
resources:
2+
- cluster-issuers.yaml
3+
- certificates.yaml

0 commit comments

Comments
 (0)