Developed and written by Maximiliano Pizarro - Specialist Solution Architect at Red Hat LATAM
π Quick Start Recommendation
For the best experience, we recommend forking this repository to your own GitHub organization or user account. This allows you to:
- Customize configurations without affecting the original repository
- Set up your own GitOps workflows with ArgoCD pointing to your fork
- Modify cluster-specific settings (like domain names) in your own repository
- Maintain your own version control and deployment pipeline
After forking, update the repository references in applicationset-instance.yaml to point to your fork.
π TL;DR
- Requirements: OpenShift 4.20+ with cluster-admin privileges
- Minimal step: Install the OpenShift GitOps operator
- Then:
oc apply -f applicationset-instance.yamlto instantiate the demo applications - Outcome: ArgoCD (OpenShift GitOps) will detect and manage the resources declared in this repository
π Overview
This repository contains a comprehensive demo of Connectivity Link using a GitOps workflow. It demonstrates how applications and infrastructure are declared as Kubernetes/Helm manifests and managed with ArgoCD (OpenShift GitOps). The demo includes:
- Service Mesh: Istio-based service mesh for traffic management and security
- API Gateway: Kubernetes Gateway API implementation with Istio
- Authentication: Keycloak for identity and access management
- Authorization: Kuadrant/Authorino for OIDC-based API protection
- Application Stack: NeuralBank demo application (frontend, backend, database)
- Developer Hub: Red Hat Developer Hub (Backstage) integration
Key Components
- Connectivity Link: A set of configurations and examples demonstrating connectivity between components (services, gateways, and authentication) within an OpenShift cluster in a GitOps context
- OpenShift GitOps (ArgoCD): Used as the GitOps controller to reconcile the declared state in this repository with the cluster
- Service Mesh Operator: Manages the Istio service mesh control plane and data plane
- RHCL Operator: Red Hat Connectivity Link operator for managing connectivity policies and OIDC authentication
βοΈ Important Requirements
- OpenShift version: 4.20+ (this demo and manifests are validated against this version)
- Permissions: cluster-admin privileges are required to:
- Install the OpenShift GitOps operator
- Allow the ApplicationSet/instance to create/manage cluster-scoped objects
- Install and configure service mesh operators
- Set up RBAC for ArgoCD to manage resources across namespaces
π§ Configuration: Pre-configure DNS with ApplicationSets
β οΈ Important: Instead of manually updating cluster domain references, you can pre-configure the DNS hostnames directly in the ApplicationSet definitions. This approach uses Kustomize patches and Helm parameters to dynamically inject your cluster domain values at deployment time.
Finding Your Cluster Domain
First, find your OpenShift clusterβs base domain:
oc get ingress.config/cluster -o jsonpath='{.spec.domain}'
Or check your clusterβs console URL - it typically follows the pattern: console-openshift-console.apps.<your-cluster-domain>
Option 1: ApplicationSet with Kustomize Patches (Recommended)
This approach uses Kustomize patches to update DNS hostnames in Keycloak, Routes, and OIDC policies. Update the keycloak_host and app_host values in the generator elements:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: connectivity-infra-plain
namespace: openshift-gitops
spec:
goTemplate: true
generators:
- list:
elements:
- name: namespaces
namespace: openshift-gitops
path: namespaces
sync_wave: "1"
- name: operators
namespace: openshift-gitops
path: operators
sync_wave: "2"
- name: developer-hub
namespace: developer-hub
path: developer-hub
sync_wave: "2"
- name: servicemeshoperator3
namespace: openshift-operators
path: servicemeshoperator3
sync_wave: "3"
- name: rhcl-operator
namespace: openshift-operators
path: rhcl-operator
sync_wave: "3"
template:
metadata:
name: ''
spec:
project: default
source:
repoURL: 'https://gitlab.com/maximilianoPizarro/connectivity-link.git'
targetRevision: main
path: ''
destination:
server: 'https://kubernetes.default.svc'
namespace: ''
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: connectivity-infra-rhbk
namespace: openshift-gitops
spec:
goTemplate: true
generators:
- list:
elements:
- name: rhbk
namespace: rhbk-operator
path: rhbk
sync_wave: "2"
keycloak_host: rhbk.apps.cluster-24p6f.24p6f.sandbox2386.opentlc.com
app_host: neuralbank.apps.cluster-24p6f.24p6f.sandbox2386.opentlc.com
template:
metadata:
name: ''
spec:
project: default
source:
repoURL: 'https://gitlab.com/maximilianoPizarro/connectivity-link.git'
targetRevision: main
path: ''
kustomize:
patches:
- target:
group: k8s.keycloak.org
kind: Keycloak
name: rhbk
patch: |-
- op: replace
path: /spec/hostname/hostname
value: ""
- target:
group: k8s.keycloak.org
kind: KeycloakRealmImport
name: neuralbank-full-import
patch: |-
- op: replace
path: /spec/realm/clients/0/redirectUris/0
value: "https:///*"
- target:
group: route.openshift.io
kind: Route
name: neuralbank-external-route
patch: |-
- op: replace
path: /spec/host
value: ""
- target:
group: extensions.kuadrant.io
kind: OIDCPolicy
name: neuralbank-oidc
patch: |-
- op: replace
path: /spec/provider/issuerURL
value: "https:///realms/neuralbank"
- op: replace
path: /spec/provider/authorizationEndpoint
value: "https:///realms/neuralbank/protocol/openid-connect/auth"
- op: replace
path: /spec/provider/tokenEndpoint
value: "https:///realms/neuralbank/protocol/openid-connect/token"
- op: replace
path: /spec/provider/redirectURI
value: "https:///auth/callback"
destination:
server: 'https://kubernetes.default.svc'
namespace: ''
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
Key Configuration Points:
keycloak_host: Update this value with your Keycloak hostname (e.g.,rhbk.apps.<your-cluster-domain>)app_host: Update this value with your application hostname (e.g.,neuralbank.apps.<your-cluster-domain>)- The Kustomize patches automatically update all DNS references in Keycloak, Routes, and OIDC policies
Option 2: ApplicationSet with Helm Parameters
For Helm-based deployments, use Helm parameters to inject DNS values. Update the keycloak_host and app_host values in the generator:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: connectivity-apps-helm-internal
namespace: openshift-gitops
spec:
goTemplate: true
generators:
- list:
elements:
- name: neuralbank-stack
namespace: neuralbank-stack
path: neuralbank-stack
sync_wave: "5"
keycloak_host: rhbk.apps.cluster-24p6f.24p6f.sandbox2386.opentlc.com
app_host: neuralbank.apps.cluster-24p6f.24p6f.sandbox2386.opentlc.com
template:
metadata:
name: ''
spec:
project: default
source:
repoURL: 'https://gitlab.com/maximilianoPizarro/connectivity-link.git'
targetRevision: main
path: ''
helm:
parameters:
- name: "keycloak.issuerUrl"
value: "https:///realms/neuralbank"
- name: "keycloak.redirectUri"
value: "https:///auth/callback"
- name: "keycloak.authorizationEndpoint"
value: "https:///realms/neuralbank/protocol/openid-connect/auth"
- name: "keycloak.tokenEndpoint"
value: "https:///realms/neuralbank/protocol/openid-connect/token"
- name: "keycloak.postLogoutRedirectUri"
value: "https://"
destination:
server: 'https://kubernetes.default.svc'
namespace: ''
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
Key Configuration Points:
keycloak_host: Update this value with your Keycloak hostnameapp_host: Update this value with your application hostname- Helm parameters automatically inject DNS values into the Helm chart values
Option 3: External Helm Chart ApplicationSet
For external Helm charts, configure the chart repository and version:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: connectivity-apps-helm-external
namespace: openshift-gitops
spec:
goTemplate: true
generators:
- list:
elements:
- name: workshop-pipelines
namespace: workshop-pipelines
helmRepoURL: 'https://maximilianopizarro.github.io/workshop-pipelines/'
chart: workshop-pipelines
chartVersion: "0.1.6"
sync_wave: "5"
template:
metadata:
name: ''
spec:
project: default
source:
repoURL: ''
targetRevision: ''
chart: ''
destination:
server: 'https://kubernetes.default.svc'
namespace: ''
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
Benefits of Pre-configuring DNS
- No manual file editing: DNS values are configured once in the ApplicationSet
- GitOps-friendly: All configuration is version-controlled in the ApplicationSet manifests
- Dynamic updates: Change DNS values by updating the ApplicationSet and ArgoCD will sync automatically
- Environment-specific: Use different ApplicationSets for different environments (dev, staging, prod)
π Getting Started
Step 1: Install OpenShift GitOps Operator
Install the OpenShift GitOps Operator (via OperatorHub in the OpenShift console or via OLM). This is the only manual step required before applying the manifests in this demo.
- Console method: Operators β OperatorHub β search for βOpenShift GitOpsβ β Install
- CLI alternative: Use
octo install the operator with OLM if you have an appropriate catalog/package available
Step 2: Configure DNS in ApplicationSets (Required)
Before proceeding, pre-configure your cluster domain in the ApplicationSet definitions as described in the Configuration section above. Update the keycloak_host and app_host values in the ApplicationSet generators to match your OpenShift cluster domain.
Step 3: Create ApplicationSet Instance
Create the ApplicationSet / ArgoCD instance using the top-level manifest:
oc apply -f applicationset-instance.yaml
applicationset-instance.yamlcreates/instantiates the applications defined in this repo and points them to this repository for ArgoCD to reconcile- After applying, open the OpenShift GitOps (ArgoCD) console to view status and sync applications if needed
Step 4: Configure Keycloak Client Settings (Manual)
After Keycloak is deployed and the realm is imported, you need to manually configure the client settings in the Red Hat Build of Keycloak console. This step is required for proper OIDC authentication flow.
Access Keycloak Console:
- Navigate to the Keycloak route in OpenShift (typically
rhbk.apps.<your-cluster-domain>) - Log in with the admin credentials (configured in
rhbk/keycloak-initial-admin.yaml) - Select the
neuralbankrealm
Configure Client Settings:
For the neuralbank client (or neuralbank-frontend if using that client):
- Navigate to Clients β Select your client (e.g.,
neuralbank) - Enable Client Authentication:
- Set Client authentication to ON (this makes it a confidential client)
- Ensure
publicClientis set tofalsein the configuration
- Enable Direct Access Grants:
- Enable Direct access grants (allows Resource Owner Password Credentials grant type)
- Configure PKCE:
- Set Proof Key for Code Exchange Code Challenge Method to S256
- This enables PKCE (RFC 7636) for enhanced security in authorization code flows
Generate Client Secret:
After enabling client authentication, you need to generate and retrieve the client secret:
- Go to the Credentials tab of your client
- Copy the Client secret value
- Update the
clientSecretfield inrhcl-operator/oidc-policy.yamlwith this value - Commit and push the change to your repository for ArgoCD to sync
Note: The client secret is required for the OIDC Policy to authenticate with Keycloak. Without it, the OIDC authentication flow will fail.
Step 5: Create OpenShift Route for Gateway (Manual)
The Gateway API Gateway resource (neuralbank-gateway) needs an OpenShift Route to expose it externally. This step must be done manually from the OpenShift console or CLI.
Option 1: Using OpenShift Console
- Navigate to Networking β Routes in the
istio-systemnamespace - Click Create Route
- Configure the route:
- Name:
neuralbank-external-route(or your preferred name) - Hostname:
neuralbank.apps.<your-cluster-domain>(or use a wildcard*.apps.<your-cluster-domain>) - Service: Select
neuralbank-gateway-istioservice - Target Port: Select
http(port 8080) - TLS Termination: Edge
- Insecure Traffic: Redirect
- Name:
Option 2: Using CLI
You can also create the route using oc:
oc create route edge neuralbank-external-route \
--service=neuralbank-gateway-istio \
--hostname=neuralbank.apps.<your-cluster-domain> \
--port=http \
--namespace=istio-system
For Wildcard Route:
If you want to use a wildcard route to access both frontend and backend through the same hostname:
oc create route edge neuralbank-external-route \
--service=neuralbank-gateway-istio \
--hostname="*.apps.<your-cluster-domain>" \
--port=http \
--namespace=istio-system
Note: The wildcard route allows you to access the application using any subdomain under apps.<your-cluster-domain>, which is useful for development and testing. The Gateway and HTTPRoute resources will handle the actual routing based on the hostnames specified in the HTTPRoute manifests.
π Repository Structure
Top-Level Files
applicationset-instance.yamlβ ArgoCD ApplicationSet/instance manifest that ties multiple applications togetherupdate-cluster-domain.shβ Bash script to automatically update cluster domain references (legacy method; recommended: use ApplicationSets with Kustomize patches as described in Configuration)
Developer Hub (developer-hub/)
Red Hat Developer Hub (Backstage) configuration and manifests:
developer-hub/README.mdβ Developer Hub app configuration and notesdeveloper-hub/app-config.yamlβ Backstage application configurationdeveloper-hub/backstage.yamlβ Backstage Kubernetes deployment manifestdeveloper-hub/dynamic-plugins.yamlβ Dynamic plugin configurationdeveloper-hub/kustomization.yamlβ Kustomize overlay for developer-hubdeveloper-hub/ols-embeddings.yamlβ Embeddings/ML integration configurationdeveloper-hub/rcsconfig-onprem.yamlβ RCS on-premises configurationdeveloper-hub/rcsconfig.yamlβ RCS cloud configurationdeveloper-hub/rhdh-rbac-policy.yamlβ RBAC policy for Developer Hubdeveloper-hub/rolebinding.yamlβ RoleBinding for the app namespacedeveloper-hub/secret-secrets-rhdh.yamlβ Secrets manifest for Developer Hub
NeuralBank Stack (neuralbank-stack/)
Helm chart for the NeuralBank demo application (frontend, backend, database, and proxy):
neuralbank-stack/Chart.yamlβ Helm chart metadataneuralbank-stack/values.yamlβ Helm chart default values (includes Keycloak and API configuration)neuralbank-stack/templates/β Kubernetes manifest templates:backend.yamlβ Backend service deploymentdb-deployment.yamlβ PostgreSQL database deploymentdb-resources.yamlβ Database persistent volume and servicefrontend.yamlβ Frontend application deploymentneuralbank-config.yamlβ ConfigMap with runtime configuration (Keycloak URLs, API endpoints)proxy.yamlβ Nginx reverse proxy/gateway configurationroute.yamlβ OpenShift Route for external accesssa-default.yamlβ Service account definitionsrolebinding.yamlβ RBAC bindingsscc-rolebinding.yamlβ Security context constraints
Operators (operators/)
Helm charts for operators used in the demo:
operators/Chart.yamlβ Helm chart metadataoperators/helm-values.yamlβ Operator configuration valuesoperators/templates/β Operator subscription and configuration manifests:rhbk.yamlβ Red Hat Build of Keycloak operator subscriptionrhcl-operator.yamlβ Red Hat Connectivity Link operator subscriptionrhdh.yamlβ Red Hat Developer Hub operator subscriptionservicemeshoperator3.yamlβ Service Mesh Operator (Istio) subscriptionsubscriptions.yamlβ Operator subscription definitions
operators/tests/β Helm chart tests
Red Hat Build of Keycloak (rhbk/)
Keycloak and related secrets/realm setup used for authentication in the demo:
rhbk/keycloak-backstage-realm.yamlβ Backstage realm configuration for Keycloakrhbk/keycloak-db-secret.yamlβ Database credentials secret for Keycloakrhbk/keycloak-initial-admin.yamlβ Initial admin credentials for Keycloakrhbk/keycloak.yamlβ Keycloak operator CR that deploys Keycloak (demo configuration)rhbk/postgres.yamlβ PostgreSQL database for Keycloakrhbk/kustomization.yamlβ Kustomize configurationrhbk/rolebinding.yamlβ RBAC bindings for Keycloak namespace
RHCL Operator (rhcl-operator/)
Red Hat Connectivity Link operator configurations for API gateway, OIDC authentication, and authorization policies:
rhcl-operator/kustomization.yamlβ Kustomize configuration for RHCL resourcesrhcl-operator/kuadrant.yamlβ Kuadrant CR (manages Authorino for OIDC authentication)rhcl-operator/oidc-policy.yamlβ OIDCPolicy CR defining OIDC authentication flow (issuer, client credentials, endpoints)rhcl-operator/neuralbank-route.yamlβ Kubernetes Gateway API HTTPRoute resources:neuralbank-api-routeβ Routes/apiand/qpaths to backend serviceneuralbank-root-routeβ Routes root path and static assets to frontend service
rhcl-operator/neuralbank-oidc-callback.yamlβ HTTPRoute for OIDC callback endpoint (/auth/callback)rhcl-operator/keycloak-authpolicy.yamlβ AuthPolicy CR for advanced authentication rules and token handlingrhcl-operator/rolebinding.yamlβ RBAC bindings for ArgoCD to manage RHCL resources
Key Features:
- OIDC-based authentication using Keycloak as the identity provider
- API protection with Authorino (via Kuadrant)
- Gateway API HTTPRoute definitions for traffic routing
- Token-based authorization with cookie and header support
HTTPRoute Resources
The HTTPRoute resources define how traffic is routed from the Gateway to backend services. These routes use the Kubernetes Gateway API standard and are managed by the Istio Gateway implementation.
Structure:
parentRefs: References the Gateway resource (neuralbank-gatewayinistio-systemnamespace) that will handle the traffichostnames: Specifies the hostname(s) that this route will match (must match the OpenShift Route hostname)rules: Defines path-based routing rules:matches: Path patterns to match (e.g.,/api,/q,/)backendRefs: Kubernetes Service to route matched traffic to
Example HTTPRoute (neuralbank-api-route):
spec:
parentRefs:
- name: neuralbank-gateway
namespace: istio-system
hostnames:
- "neuralbank.apps.<your-cluster-domain>"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: neuralbank-backend-svc
port: 8080
This route matches requests to /api/* and /q/* and forwards them to the neuralbank-backend-svc service on port 8080.
OIDC Policy Configuration
The OIDCPolicy resource configures OIDC authentication for protected routes. It integrates with Authorino (via Kuadrant) to enforce authentication at the gateway level.
Key Configuration Fields:
provider.issuerURL: The Keycloak realm issuer URL- Format:
https://<keycloak-host>/realms/<realm-name> - Example:
https://rhbk.apps.<your-cluster-domain>/realms/neuralbank
- Format:
provider.clientID: The Keycloak client ID (must match the client configured in Keycloak)- Example:
neuralbank
- Example:
provider.clientSecret: β οΈ IMPORTANT β The client secret generated from Keycloak console- This must be obtained from Keycloak after enabling client authentication
- Steps to get the secret:
- Log into Keycloak console
- Navigate to your realm β Clients β Select your client
- Go to the Credentials tab
- Copy the Client secret value
- Update the
clientSecretfield inoidc-policy.yaml
- Security Note: Consider using a Kubernetes Secret to store the client secret instead of hardcoding it in the YAML file
provider.authorizationEndpoint: Keycloak authorization endpoint- Format:
https://<keycloak-host>/realms/<realm-name>/protocol/openid-connect/auth
- Format:
provider.redirectURI: OAuth callback URL (must match a redirect URI configured in Keycloak client)- Example:
https://neuralbank.apps.<your-cluster-domain>/auth/callback
- Example:
provider.tokenEndpoint: Keycloak token endpoint- Format:
https://<keycloak-host>/realms/<realm-name>/protocol/openid-connect/token
- Format:
targetRef: References the HTTPRoute resource that should be protected by this OIDC policy- Example:
neuralbank-api-route(protects the/apiand/qendpoints)
- Example:
auth.tokenSource: Defines where to look for the authentication tokenauthorizationHeader: Token inAuthorization: Bearer <token>headercookie: Token stored in a cookie (e.g.,jwtcookie)
Example OIDC Policy:
spec:
provider:
issuerURL: "https://rhbk.apps.<your-cluster-domain>/realms/neuralbank"
clientID: neuralbank
clientSecret: "<your-client-secret-from-keycloak>" # β οΈ Update this!
authorizationEndpoint: "https://rhbk.apps.<your-cluster-domain>/realms/neuralbank/protocol/openid-connect/auth"
redirectURI: "https://neuralbank.apps.<your-cluster-domain>/auth/callback"
tokenEndpoint: "https://rhbk.apps.<your-cluster-domain>/realms/neuralbank/protocol/openid-connect/token"
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: neuralbank-api-route
auth:
tokenSource:
authorizationHeader:
prefix: Bearer
name: Authorization
cookie:
name: jwt
Important Notes:
- The
clientSecretmust be updated after generating it from the Keycloak console (see Step 4) - The
redirectURImust exactly match one of the redirect URIs configured in the Keycloak client - The
hostnamesin HTTPRoute resources must match the hostname used in the OpenShift Route - All URLs (issuer, endpoints) must use HTTPS and match your clusterβs domain configuration
Service Mesh Operator 3 (servicemeshoperator3/)
Service Mesh Operator (Istio) configurations for service mesh control plane and gateway:
servicemeshoperator3/kustomization.yamlβ Kustomize configuration for service mesh resourcesservicemeshoperator3/smcp-controlplane.yamlβ Service Mesh Control Plane (SMCP) configuration:IstioCR β Istio control plane deployment (version v1.27.3)IstioCNICR β Istio CNI plugin configuration- ClusterRole/ClusterRoleBinding β RBAC for ArgoCD to manage Istio resources
servicemeshoperator3/gateway.yamlβ Kubernetes Gateway API Gateway resource:neuralbank-gatewayβ Gateway with HTTP (8080) and HTTPS (443) listeners- Role/RoleBinding β RBAC for ArgoCD to manage Gateway resources in istio-system namespace
servicemeshoperator3/gateway-route.yamlβ Example HTTPRoute for gateway (commented out by default)
Key Features:
- Istio service mesh control plane management
- Kubernetes Gateway API implementation
- Multi-protocol support (HTTP/HTTPS)
- Cross-namespace route support
Namespaces (namespaces/)
namespaces/namespaces.yamlβ Kubernetes namespace definitions for the demo
π Notes
- The demo configuration uses a Keycloak operator CR (
rhbk/keycloak.yaml) to bootstrap an instance and wire it to a PostgreSQL database - Everything in this repository is intended to be applied via a GitOps controller (ArgoCD), so changes to these files represent the desired cluster state
- The service mesh and gateway configurations work together to provide:
- Traffic management and routing
- mTLS between services
- OIDC authentication at the gateway level
- API protection with fine-grained authorization policies
ποΈ Architecture Diagrams
The Application Solution without Auth π:
The Application Solution with Auth π powered by Red Hat Build of Keycloak & Authorino:
π Benefits of Cloud Native Integration with Kuadrant
Integrating with a cloud native strategy and the Kuadrant project brings significant advantages to modern application deployment and security. The simplicity of this approach is remarkable: by adding just a few manifest files with the appropriate configuration, you can transform your applicationβs security posture. GitOps plays a crucial role in orchestrating these changes in a clean environment within seconds, enabling a true Zero Trust architecture implementation.
The power of this solution lies in its declarative natureβyou define the desired state through Kubernetes manifests, and the GitOps workflow ensures that state is achieved and maintained automatically. This approach eliminates manual configuration errors, provides complete audit trails through Git history, and enables rapid deployment across multiple environments with consistency. The Zero Trust model is enforced at every layer: authentication through Keycloak, authorization via Authorino, rate limiting for API protection, and service mesh policies for inter-service communication. With Connectivity Link and Kuadrant, youβre establishing a comprehensive security framework that scales with your infrastructure, creating a robust foundation for modern, secure microservices architectures.
π’ Share This Content
If you found this guide helpful, please share it with your network! Help others discover how to implement Zero Trust security with Connectivity Link and GitOps.
Thank you for sharing! Your support helps the community grow and learn together.