From 74f5e05980deff8f7355d9d9125795ad4e52e6f5 Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Fri, 2 Dec 2022 00:00:00 -0500 Subject: [PATCH] Migrating citrix charts to automated process --- ...itrix-adc-istio-ingress-gateway-1.11.0.tgz | Bin ...itrix-adc-istio-ingress-gateway-1.11.1.tgz | Bin ...itrix-adc-istio-ingress-gateway-1.14.0.tgz | Bin 0 -> 17659 bytes ...trix-adc-istio-ingress-gateway-1.2.100.tgz | Bin ...trix-cpx-istio-sidecar-injector-1.11.0.tgz | Bin ...trix-cpx-istio-sidecar-injector-1.11.1.tgz | Bin ...trix-cpx-istio-sidecar-injector-1.14.1.tgz | Bin 0 -> 14833 bytes ...ix-cpx-with-ingress-controller-1.27.15.tgz | Bin 0 -> 34018 bytes ...x-cpx-with-ingress-controller-1.8.2800.tgz | Bin .../citrix-ingress-controller-1.19.600.tgz | Bin .../citrix-ingress-controller-1.27.15.tgz | Bin 0 -> 33453 bytes .../citrix-multicluster-gateway.yaml | 40 - .../Chart.yaml | 9 +- .../README.md | 156 +- .../app-readme.md | 0 .../questions.yml | 0 .../templates/_helpers.tpl | 0 .../citrix-adc-ingressgateway-deployment.yaml | 100 +- .../citrix-multicluster-gateway.yaml | 46 + .../templates/ingressgateway-service.yaml | 0 .../templates/metrics-exporter-service.yaml | 1 + .../values.yaml | 24 +- .../.helmignore | 22 + .../Chart.yaml | 21 + .../README.md | 294 ++ .../app-readme.md | 0 .../create-certs-for-cpx-istio-chart.sh | 127 + .../questions.yml | 0 .../templates/_helpers.tpl | 20 + .../cpx-sidecar-injector-configmap.yaml | 263 ++ ...x-sidecar-injector-deployment-service.yaml | 114 + .../cpx-sidecar-injector-istioConfigMap.yaml | 16 + .../cpx-sidecar-injector-serviceaccount.yaml | 48 + .../templates/cpx-sidecar-networkpolicy.yaml | 15 + .../templates/mutatingwebhook.yaml | 57 + .../values.yaml | 77 + .../Chart.yaml | 21 + .../README.md | 572 ++++ .../app-readme.md | 0 .../questions.yml | 0 .../templates/NOTES.txt | 14 + .../templates/_helpers.tpl | 97 + .../templates/cic_crds.yaml | 2515 +++++++++++++++++ .../templates/citrix-k8s-cpx-ingress.yaml | 414 +++ .../templates/configmap.yaml | 71 + .../templates/ingressclass.yaml | 18 + .../templates/rbac.yaml | 89 + .../values.yaml | 221 ++ .../citrix-ingress-controller/Chart.yaml | 20 + .../citrix-ingress-controller/README.md | 492 ++++ .../citrix-ingress-controller}/app-readme.md | 0 .../citrix-ingress-controller}/questions.yml | 0 .../templates/NOTES.txt | 15 + .../templates/_helpers.tpl | 94 + .../templates/cic_crds.yaml | 2515 +++++++++++++++++ .../templates/citrix-k8s-ingress.yaml | 260 ++ .../templates/configmap.yaml | 60 + .../templates/ingressclass.yaml | 18 + .../templates/rbac.yaml | 89 + .../citrix-ingress-controller/values.yaml | 177 ++ index.yaml | 113 +- .../generated-changes/patch/Chart.yaml.patch | 24 - .../generated-changes/patch/values.yaml.patch | 11 - .../package.yaml | 4 - .../generated-changes/patch/Chart.yaml.patch | 24 - .../generated-changes/patch/README.md.patch | 11 - .../package.yaml | 4 - .../generated-changes/patch/Chart.yaml.patch | 9 - .../generated-changes/patch/README.md.patch | 11 - .../package.yaml | 2 - .../generated-changes/patch/Chart.yaml.patch | 16 - .../citrix-ingress-controller/package.yaml | 2 - .../overlay/app-readme.md | 0 .../overlay/questions.yml | 0 .../upstream.yaml | 4 + .../overlay/app-readme.md | 28 + .../overlay/questions.yml | 291 ++ .../upstream.yaml | 4 + .../overlay/app-readme.md | 5 + .../overlay/questions.yml | 211 ++ .../upstream.yaml | 4 + .../overlay/app-readme.md | 5 + .../overlay/questions.yml | 348 +++ .../citrix-ingress-controller/upstream.yaml | 4 + 84 files changed, 10089 insertions(+), 268 deletions(-) rename assets/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway-1.11.0.tgz (100%) rename assets/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway-1.11.1.tgz (100%) create mode 100644 assets/citrix/citrix-adc-istio-ingress-gateway-1.14.0.tgz rename assets/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway-1.2.100.tgz (100%) rename assets/{citrix-cpx-istio-sidecar-injector => citrix}/citrix-cpx-istio-sidecar-injector-1.11.0.tgz (100%) rename assets/{citrix-cpx-istio-sidecar-injector => citrix}/citrix-cpx-istio-sidecar-injector-1.11.1.tgz (100%) create mode 100644 assets/citrix/citrix-cpx-istio-sidecar-injector-1.14.1.tgz create mode 100644 assets/citrix/citrix-cpx-with-ingress-controller-1.27.15.tgz rename assets/{citrix-cpx-with-ingress-controller => citrix}/citrix-cpx-with-ingress-controller-1.8.2800.tgz (100%) rename assets/{citrix-ingress-controller => citrix}/citrix-ingress-controller-1.19.600.tgz (100%) create mode 100644 assets/citrix/citrix-ingress-controller-1.27.15.tgz delete mode 100644 charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/citrix-multicluster-gateway.yaml rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/Chart.yaml (75%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/README.md (82%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/app-readme.md (100%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/questions.yml (100%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/templates/_helpers.tpl (100%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml (84%) create mode 100644 charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-multicluster-gateway.yaml rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/templates/ingressgateway-service.yaml (100%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml (92%) rename charts/{citrix-adc-istio-ingress-gateway => citrix}/citrix-adc-istio-ingress-gateway/values.yaml (62%) create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/.helmignore create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/Chart.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/README.md rename {packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay => charts/citrix/citrix-cpx-istio-sidecar-injector}/app-readme.md (100%) create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/create-certs-for-cpx-istio-chart.sh rename {packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay => charts/citrix/citrix-cpx-istio-sidecar-injector}/questions.yml (100%) create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/_helpers.tpl create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-configmap.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-deployment-service.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-istioConfigMap.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-serviceaccount.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-networkpolicy.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/templates/mutatingwebhook.yaml create mode 100644 charts/citrix/citrix-cpx-istio-sidecar-injector/values.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/Chart.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/README.md rename {packages/citrix-cpx-with-ingress-controller/generated-changes/overlay => charts/citrix/citrix-cpx-with-ingress-controller}/app-readme.md (100%) rename {packages/citrix-cpx-with-ingress-controller/generated-changes/overlay => charts/citrix/citrix-cpx-with-ingress-controller}/questions.yml (100%) create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/NOTES.txt create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/_helpers.tpl create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/cic_crds.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/citrix-k8s-cpx-ingress.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/configmap.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/ingressclass.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/templates/rbac.yaml create mode 100644 charts/citrix/citrix-cpx-with-ingress-controller/values.yaml create mode 100644 charts/citrix/citrix-ingress-controller/Chart.yaml create mode 100644 charts/citrix/citrix-ingress-controller/README.md rename {packages/citrix-ingress-controller/generated-changes/overlay => charts/citrix/citrix-ingress-controller}/app-readme.md (100%) rename {packages/citrix-ingress-controller/generated-changes/overlay => charts/citrix/citrix-ingress-controller}/questions.yml (100%) create mode 100644 charts/citrix/citrix-ingress-controller/templates/NOTES.txt create mode 100644 charts/citrix/citrix-ingress-controller/templates/_helpers.tpl create mode 100644 charts/citrix/citrix-ingress-controller/templates/cic_crds.yaml create mode 100644 charts/citrix/citrix-ingress-controller/templates/citrix-k8s-ingress.yaml create mode 100644 charts/citrix/citrix-ingress-controller/templates/configmap.yaml create mode 100644 charts/citrix/citrix-ingress-controller/templates/ingressclass.yaml create mode 100644 charts/citrix/citrix-ingress-controller/templates/rbac.yaml create mode 100644 charts/citrix/citrix-ingress-controller/values.yaml delete mode 100644 packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/Chart.yaml.patch delete mode 100644 packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/values.yaml.patch delete mode 100644 packages/citrix-adc-istio-ingress-gateway/package.yaml delete mode 100644 packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/Chart.yaml.patch delete mode 100644 packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/README.md.patch delete mode 100644 packages/citrix-cpx-istio-sidecar-injector/package.yaml delete mode 100644 packages/citrix-cpx-with-ingress-controller/generated-changes/patch/Chart.yaml.patch delete mode 100644 packages/citrix-cpx-with-ingress-controller/generated-changes/patch/README.md.patch delete mode 100644 packages/citrix-cpx-with-ingress-controller/package.yaml delete mode 100644 packages/citrix-ingress-controller/generated-changes/patch/Chart.yaml.patch delete mode 100644 packages/citrix-ingress-controller/package.yaml rename packages/{citrix-adc-istio-ingress-gateway/generated-changes => citrix/citrix-adc-istio-ingress-gateway}/overlay/app-readme.md (100%) rename packages/{citrix-adc-istio-ingress-gateway/generated-changes => citrix/citrix-adc-istio-ingress-gateway}/overlay/questions.yml (100%) create mode 100644 packages/citrix/citrix-adc-istio-ingress-gateway/upstream.yaml create mode 100644 packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/app-readme.md create mode 100644 packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/questions.yml create mode 100644 packages/citrix/citrix-cpx-istio-sidecar-injector/upstream.yaml create mode 100644 packages/citrix/citrix-cpx-with-ingress-controller/overlay/app-readme.md create mode 100644 packages/citrix/citrix-cpx-with-ingress-controller/overlay/questions.yml create mode 100644 packages/citrix/citrix-cpx-with-ingress-controller/upstream.yaml create mode 100644 packages/citrix/citrix-ingress-controller/overlay/app-readme.md create mode 100644 packages/citrix/citrix-ingress-controller/overlay/questions.yml create mode 100644 packages/citrix/citrix-ingress-controller/upstream.yaml diff --git a/assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.0.tgz b/assets/citrix/citrix-adc-istio-ingress-gateway-1.11.0.tgz similarity index 100% rename from assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.0.tgz rename to assets/citrix/citrix-adc-istio-ingress-gateway-1.11.0.tgz diff --git a/assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.1.tgz b/assets/citrix/citrix-adc-istio-ingress-gateway-1.11.1.tgz similarity index 100% rename from assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.1.tgz rename to assets/citrix/citrix-adc-istio-ingress-gateway-1.11.1.tgz diff --git a/assets/citrix/citrix-adc-istio-ingress-gateway-1.14.0.tgz b/assets/citrix/citrix-adc-istio-ingress-gateway-1.14.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5386997f1e0b36e4c2af407db036ec5b0551f0d2 GIT binary patch literal 17659 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 X`TG24J^z0I00960;(t!z02BcL_B-#j literal 0 HcmV?d00001 diff --git a/assets/citrix/citrix-cpx-with-ingress-controller-1.27.15.tgz b/assets/citrix/citrix-cpx-with-ingress-controller-1.27.15.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b383760c6d17bb5cb61ae21bd312a9f21ad43f4a GIT binary patch literal 34018 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 Z|2+RZ|5SedZvX%Q|Nm*@M-~7u0{}uvew_dS literal 0 HcmV?d00001 diff --git a/assets/citrix-cpx-with-ingress-controller/citrix-cpx-with-ingress-controller-1.8.2800.tgz b/assets/citrix/citrix-cpx-with-ingress-controller-1.8.2800.tgz similarity index 100% rename from assets/citrix-cpx-with-ingress-controller/citrix-cpx-with-ingress-controller-1.8.2800.tgz rename to assets/citrix/citrix-cpx-with-ingress-controller-1.8.2800.tgz diff --git a/assets/citrix-ingress-controller/citrix-ingress-controller-1.19.600.tgz b/assets/citrix/citrix-ingress-controller-1.19.600.tgz similarity index 100% rename from assets/citrix-ingress-controller/citrix-ingress-controller-1.19.600.tgz rename to assets/citrix/citrix-ingress-controller-1.19.600.tgz diff --git a/assets/citrix/citrix-ingress-controller-1.27.15.tgz b/assets/citrix/citrix-ingress-controller-1.27.15.tgz new file mode 100644 index 0000000000000000000000000000000000000000..40469e58b6ff191bc272aad690aaaee36207cba8 GIT binary patch literal 33453 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.16.0-0' catalog.cattle.io/release-name: citrix-adc-istio-ingress-gateway apiVersion: v2 -appVersion: 1.11.0 +appVersion: 1.14.0 description: A Helm chart for Citrix ADC as Ingress Gateway installation in Istio Service Mesh on Kubernetes platform home: https://www.citrix.com -icon: https://raw.githubusercontent.com/citrix/citrix-xds-adaptor/master/docs/media/Citrix_Logo_Trademark.png +icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png kubeVersion: '>=v1.16.0-0' maintainers: - email: dhiraj.gedam@citrix.com name: dheerajng - email: subash.dangol@citrix.com name: subashd -- email: ajeeta.shaket@citrix.com - name: ajeetas name: citrix-adc-istio-ingress-gateway sources: - https://github.com/citrix/citrix-xds-adaptor -version: 1.11.1 +version: 1.14.0 diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/README.md b/charts/citrix/citrix-adc-istio-ingress-gateway/README.md similarity index 82% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/README.md rename to charts/citrix/citrix-adc-istio-ingress-gateway/README.md index f845a434f..aefb0c33b 100644 --- a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/README.md +++ b/charts/citrix/citrix-adc-istio-ingress-gateway/README.md @@ -3,6 +3,7 @@ Citrix Application Delivery Controller (ADC) can be deployed as an Istio Ingress Gateway to control the ingress traffic to Istio service mesh. # Table of Contents + 1. [TL; DR;](#tldr) 2. [Introduction](#introduction) 3. [Deploy Citrix ADC VPX or MPX as an Ingress Gateway](#deploy-citrix-adc-vpx-or-mpx-as-an-ingress-gateway) @@ -21,10 +22,9 @@ Citrix Application Delivery Controller (ADC) can be deployed as an Istio Ingress 16. [Citrix ADC VPX/MPX Certificate Verification](#citrix-adc-vpx-or-mpx-certificate-verification) 17. [Configuration Parameters](#configuration-parameters) - ## TL; DR; -### To deploy Citrix ADC VPX or MPX as an Ingress Gateway: +### To deploy Citrix ADC VPX or MPX as an Ingress Gateway kubectl create secret generic nslogin --from-literal=username= --from-literal=password= -n citrix-system @@ -32,15 +32,12 @@ Citrix Application Delivery Controller (ADC) can be deployed as an Istio Ingress helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set ingressGateway.netscalerUrl=https://[:port] --set ingressGateway.vserverIP= --set secretName=nslogin - - -### To deploy Citrix ADC CPX as an Ingress Gateway: +### To deploy Citrix ADC CPX as an Ingress Gateway helm repo add citrix https://citrix.github.io/citrix-helm-charts/ helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set citrixCPX=true - ## Introduction This chart deploys Citrix ADC VPX, MPX, or CPX as an Ingress Gateway in the Istio service mesh using the Helm package manager. For detailed information on different deployment options, see [Deployment Architecture](https://github.com/citrix/citrix-istio-adaptor/blob/master/docs/istio-integration/architecture.md). @@ -51,7 +48,9 @@ Below table provides info about recommended Citrix xDS-Adaptor version to be use | Citrix xDS-Adaptor version | Istio version | |----------------------------|---------------| -| quay.io/citrix/citrix-xds-adaptor:0.9.9 | Istio v1.10+ | +| quay.io/citrix/citrix-xds-adaptor:0.10.3 | Istio v1.14+ | +| quay.io/citrix/citrix-xds-adaptor:0.10.1 | Istio v1.12 to Istio v1.13 | +| quay.io/citrix/citrix-xds-adaptor:0.9.9 | Istio v1.10 to Istio v1.11 | | quay.io/citrix/citrix-xds-adaptor:0.9.8 | Istio v1.8 to Istio v1.9 | | quay.io/citrix/citrix-xds-adaptor:0.9.5 | Istio v1.6 | @@ -78,7 +77,6 @@ The following prerequisites are required for deploying Citrix ADC as an Ingress kubectl create secret generic nslogin --from-literal=username= --from-literal=password= -n citrix-system - - **Create system user account for xDS-adaptor in Citrix ADC:** The Citrix ADC appliance needs to have system user account (non-default) with certain privileges so that `xDS-adaptor` can configure the Citrix ADC VPX or MPX appliance. Follow the instructions to create the system user account on Citrix ADC. @@ -91,25 +89,24 @@ The following prerequisites are required for deploying Citrix ADC as an Ingress The `xDS-adaptor` configures the Citrix ADC using a system user account of the Citrix ADC. The system user account should have certain privileges so that the xDS-adaptor has permissions configure the following on the Citrix ADC: - - Add, Delete, or View Content Switching (CS) virtual server - - Configure CS policies and actions - - Configure Load Balancing (LB) virtual server - - Configure Service groups - - Cofigure SSl certkeys - - Configure routes - - Configure user monitors - - Add system file (for uploading SSL certkeys from Kubernetes) - - Configure Virtual IP address (VIP) - - Check the status of the Citrix ADC appliance - - Add, Delete or view authentication virtual server, policy, authaction - - Add, Delete or view Policy - - Add, Delete or view Responder policy, action, param - - Add, Delete or view Rewrite policy, action, param - - Add, Delete or view analytics profile - - Add, Delete or view DNS name server - - Add, Delete or view network netprofile - - Add, Delete or view Traffic Management Commands(sessionaction, session policy, sessionparameter) - + - Add, Delete, or View Content Switching (CS) virtual server + - Configure CS policies and actions + - Configure Load Balancing (LB) virtual server + - Configure Service groups + - Cofigure SSl certkeys + - Configure routes + - Configure user monitors + - Add system file (for uploading SSL certkeys from Kubernetes) + - Configure Virtual IP address (VIP) + - Check the status of the Citrix ADC appliance + - Add, Delete or view authentication virtual server, policy, authaction + - Add, Delete or view Policy + - Add, Delete or view Responder policy, action, param + - Add, Delete or view Rewrite policy, action, param + - Add, Delete or view analytics profile + - Add, Delete or view DNS name server + - Add, Delete or view network netprofile + - Add, Delete or view Traffic Management Commands(sessionaction, session policy, sessionparameter) > **Note:** > @@ -117,12 +114,12 @@ The following prerequisites are required for deploying Citrix ADC as an Ingress To create the system user account, do the following: - 1. Log on to the Citrix ADC appliance. Perform the following: - 1. Use an SSH client, such as PuTTy, to open an SSH connection to the Citrix ADC appliance. + 1. Log on to the Citrix ADC appliance. Perform the following: + 1. Use an SSH client, such as PuTTy, to open an SSH connection to the Citrix ADC appliance. - 2. Log on to the appliance by using the administrator credentials. + 2. Log on to the appliance by using the administrator credentials. - 2. Create the system user account using the following command: + 2. Create the system user account using the following command: ``` add system user @@ -134,13 +131,13 @@ The following prerequisites are required for deploying Citrix ADC as an Ingress add system user cxa mypassword ``` - 3. Create a policy to provide required permissions to the system user account. Use the following command: + 3. Create a policy to provide required permissions to the system user account. Use the following command: ``` add cmdpolicy cxa-policy ALLOW "((^\S+\s+cs\s+\S+)|(^\S+\s+lb\s+\S+)|(^\S+\s+service\s+\S+)|(^\S+\s+servicegroup\s+\S+)|(^stat\s+system)|(^show\s+ha)|(^\S+\s+ssl\s+certKey)|(^\S+\s+ssl)|(^\S+\s+route)|(^\S+\s+monitor)|(^show\s+ns\s+ip)|(^\S+\s+system\s+file)|)|(^\S+\s+aaa\s+\S+)|(^\S+\s+aaa\s+\S+\s+.*)|(^\S+\s+authentication\s+\S+)|(^\S+\s+authentication\s+\S+\s+.*)|(^\S+\s+policy\s+\S+)|(^\S+\s+policy\s+\S+\s+.*)|(^\S+\s+rewrite\s+\S+)|(^\S+\s+rewrite\s+\S+\s+.*)|(^\S+\s+analytics\s+\S+)|(^\S+\s+analytics\s+\S+\s+.*)|(^\S+\s+dns\s+\S+)|(^\S+\s+dns\s+\S+\s+.*)|(^\S+\s+netProfile)|(^\S+\s+netProfile\s+.*)|(^\S+\s+tm\s+\S+)|(^\S+\s+tm\s+\S+\s+.*)" ``` - 4. Bind the policy to the system user account using the following command: + 4. Bind the policy to the system user account using the following command: ``` bind system user cxa cxa-policy 0 @@ -154,7 +151,6 @@ Create a secret for ADM username and password - **Important Note:** For deploying Citrix ADC VPX or MPX as ingress gateway, you should establish the connectivity between Citrix ADC VPX or MPX and cluster nodes. This connectivity can be established by configuring routes on Citrix ADC as mentioned [here](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/network/staticrouting.md) or by deploying [Citrix Node Controller](https://github.com/citrix/citrix-k8s-node-controller). - ## Deploy Citrix ADC VPX or MPX as an Ingress Gateway To deploy Citrix ADC VPX or MPX as an Ingress Gateway in the Istio service mesh, do the following step. In this example, release name is specified as `citrix-adc-istio-ingress-gateway` and namespace as `citrix-system`. @@ -173,10 +169,10 @@ Create a secret for ADM username and password helm install my-release citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES,citrixCPX=true - ## Deploy Citrix ADC as an Ingress Gateway in multi cluster Istio Service mesh To deploy **Citrix ADC VPX/MPX as an Ingress Gateway** in multi cluster Istio Service mesh, carry out below steps. + ``` helm repo add citrix https://citrix.github.io/citrix-helm-charts/ @@ -184,6 +180,7 @@ helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-ga ``` To deploy **Citrix ADC CPX as an Ingress Gateway** in multi cluster Istio Service mesh, carry out below steps. + ``` helm repo add citrix https://citrix.github.io/citrix-helm-charts/ @@ -230,10 +227,10 @@ To deploy Citrix ADC CPX with secret volume, do the following step: ## Segregating traffic with multiple Ingress Gateways -You can deploy multiple Citrix ADC Ingress Gateway devices and segregate traffic to various deployments in the Istio service mesh. This can be achieved with *custom labels*. By default, Citrix ADC Ingress Gateway service comes up with the `app: citrix-ingressgateway` label. This label is used as a selector while deploying the Ingress Gateway or virtual service resources. If you want to deploy Ingress Gateway with the custom label, you can do it using the `ingressGateway.label` option in the Helm chart. +You can deploy multiple Citrix ADC Ingress Gateway devices and segregate traffic to various deployments in the Istio service mesh. This can be achieved with _custom labels_. By default, Citrix ADC Ingress Gateway service comes up with the `app: citrix-ingressgateway` label. This label is used as a selector while deploying the Ingress Gateway or virtual service resources. If you want to deploy Ingress Gateway with the custom label, you can do it using the `ingressGateway.label` option in the Helm chart. To deploy Citrix ADC CPX Ingress Gateway with the label `my_custom_ingressgateway`, do the following step: - + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ helm install my-release citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES,citrixCPX=true,ingressGateway.lightWeightCPX=NO,ingressGateway.label=my_custom_ingressgateway @@ -256,7 +253,6 @@ When Citrix ADC CPX is deployed as Ingress Gateway, Metrics Exporter runs along To deploy Citrix ADC as Ingress Gateway without Metrics Exporter, set the value of `metricExporter.required` as false. - kubectl create secret generic nslogin --from-literal=username= --from-literal=password= -n citrix-system helm repo add citrix https://citrix.github.io/citrix-helm-charts/ @@ -288,23 +284,25 @@ In this example, a service running on TCP port 5000 is exposed using port 10000 ## Generate Certificate for Ingress Gateway -Citrix Ingress gateway needs TLS certificate-key pair for establishing secure communication channel with backend applications. Earlier these certificates were issued by Istio Citadel and bundled in Kubernetes secret. Certificate was loaded in the application pod by doing volume mount of secret. Now `xDS-Adaptor` can generate its own certificate and get it signed by the Istio Citadel (Istiod). This eliminates the need of secret and associated [risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks). +Citrix Ingress gateway needs TLS certificate-key pair for establishing secure communication channel with backend applications. Earlier these certificates were issued by Istio Citadel and bundled in Kubernetes secret. Certificate was loaded in the application pod by doing volume mount of secret. Now `xDS-Adaptor` can generate its own certificate and get it signed by the Istio Citadel (Istiod). This eliminates the need of secret and associated [risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks). -xDS-Adaptor needs to be provided with details Certificate Authority (CA) for successful signing of Certificate Signing Request (CSR). By default, CA is `istiod.istio-system.svc` which accepts CSRs on port 15012. +xDS-Adaptor needs to be provided with details Certificate Authority (CA) for successful signing of Certificate Signing Request (CSR). By default, CA is `istiod.istio-system.svc` which accepts CSRs on port 15012. To skip this process, don't provide any value (empty string) to `certProvider.caAddr`. + ``` helm repo add citrix https://citrix.github.io/citrix-helm-charts/ helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set citrixCPX=true --set certProvider.caAddr="" ``` + ### Configure Third Party Service Account Tokens -In order to generate certificate for application workload, xDS-Adaptor needs to send valid service account token along with Certificate Signing Request (CSR) to the Istio control plane (Citadel CA). Istio control plane authenticates the xDS-Adaptor using this JWT. +In order to generate certificate for application workload, xDS-Adaptor needs to send valid service account token along with Certificate Signing Request (CSR) to the Istio control plane (Citadel CA). Istio control plane authenticates the xDS-Adaptor using this JWT. Kubernetes supports two forms of these tokens: -* Third party tokens, which have a scoped audience and expiration. -* First party tokens, which have no expiration and are mounted into all pods. - +- Third party tokens, which have a scoped audience and expiration. +- First party tokens, which have no expiration and are mounted into all pods. + If Kubernetes cluster is installed with third party tokens, then the same information needs to be provided for automatic sidecar injection by passing `--set certProvider.jwtPolicy="third-party-jwt"`. By default, it is `first-party-jwt`. ``` @@ -334,29 +332,31 @@ To determine if your cluster supports third party tokens, look for the TokenRequ ``` ## **Citrix ADC CPX License Provisioning** + By default, CPX runs with 20 Mbps bandwidth called as [CPX Express](https://www.citrix.com/en-in/products/citrix-adc/cpx-express.html) however for better performance and production deployment customer needs licensed CPX instances. [Citrix ADM](https://www.citrix.com/en-in/products/citrix-application-delivery-management/) is used to check out licenses for Citrix ADC CPX. **Bandwidth based licensing** For provisioning licensing on Citrix ADC CPX, it is mandatory to provide License Server information to CPX. This can be done by setting **ADMSettings.licenseServerIP** as License Server IP. In addition to this, **ADMSettings.bandWidthLicense** needs to be set true and desired bandwidth capacity in Mbps should be set **ADMSettings.bandWidth**. For example, to set 2Gbps as bandwidth capacity, below command can be used. - helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set ADMSettings.licenseServerIP=,ADMSettings.bandWidthLicense=True --set ADMSettings.bandWidth=2000 --set citrixCPX=true ## **Service Graph configuration** + Citrix ADM Service graph is an observability tool that allows user to analyse service to service communication. The service graph is generated by ADM post collection of transactional data from registered Citrix ADC instances. More details about it can be found [here](https://docs.citrix.com/en-us/citrix-application-delivery-management-service/application-analytics-and-management/service-graph.html). Citrix ADC needs to be provided with ADM details for registration and data export. This section lists the steps needed to deploy Citrix ADC and register it with ADM. **Deploy Citrix ADC CPX as ingress gateway** + 1. Create secret using Citrix ADM Agent credentials, which will be used by Citrix ADC as CPX to communicate with Citrix ADM Agent: - kubectl create secret generic admlogin --from-literal=username= --from-literal=password= + kubectl create secret generic admlogin --from-literal=username= --from-literal=password= 2. Deploy Citrix ADC CPX as ingress gateway using helm command with `ADM` details: - helm install citrix-adc-istio-ingress-gateway citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set citrixCPX=true --set ADMSettings.ADMIP= - + helm install citrix-adc-istio-ingress-gateway citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set citrixCPX=true --set ADMSettings.ADMIP= > **Note:** > If container agent is being used here for Citrix ADM, specify `serviceIP` of container agent in the `ADMSettings.ADMIP` parameter. @@ -364,32 +364,30 @@ For example, to set 2Gbps as bandwidth capacity, below command can be used. **Deploy Citrix ADC VPX/MPX as ingress gateway** Deploy Citrix ADC VPX/MPX as ingress gateway using helm command and set analytics settings on Citrix ADC VPX/MPX for sending transaction metrics to Citrix ADM - - helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set ingressGateway.netscalerUrl=https://[:port] --set ingressGateway.vserverIP= --set secretName=nslogin + + helm install citrix-adc-istio-ingress-gateway citrix/citrix-adc-istio-ingress-gateway --namespace citrix-system --set ingressGateway.EULA=YES --set ingressGateway.netscalerUrl=https://[:port] --set ingressGateway.vserverIP= --set secretName=nslogin Add the following configurations in Citrix ADC VPX/MPX - en ns mode ulfd + en ns mode ulfd - en ns feature appflow + en ns feature appflow - add appflow collector logproxy_lstreamd -IPAddress -port 5557 -Transport logstream + add appflow collector logproxy_lstreamd -IPAddress -port 5557 -Transport logstream - set appflow param -templateRefresh 3600 -httpUrl ENABLED -httpCookie ENABLED -httpReferer ENABLED -httpMethod ENABLED -httpHost ENABLED -httpUserAgent ENABLED -httpContentType ENABLED -httpAuthorization ENABLED -httpVia ENABLED -httpXForwardedFor ENABLED -httpLocation ENABLED -httpSetCookie ENABLED -httpSetCookie2 ENABLED -httpDomain ENABLED -httpQueryWithUrl ENABLED metrics ENABLED -events ENABLED -auditlogs ENABLED + set appflow param -templateRefresh 3600 -httpUrl ENABLED -httpCookie ENABLED -httpReferer ENABLED -httpMethod ENABLED -httpHost ENABLED -httpUserAgent ENABLED -httpContentType ENABLED -httpAuthorization ENABLED -httpVia ENABLED -httpXForwardedFor ENABLED -httpLocation ENABLED -httpSetCookie ENABLED -httpSetCookie2 ENABLED -httpDomain ENABLED -httpQueryWithUrl ENABLED metrics ENABLED -events ENABLED -auditlogs ENABLED - add appflow action logproxy_lstreamd -collectors logproxy_lstreamd + add appflow action logproxy_lstreamd -collectors logproxy_lstreamd - add appflow policy logproxy_policy true logproxy_lstreamd + add appflow policy logproxy_policy true logproxy_lstreamd - bind appflow global logproxy_policy 10 END -type REQ_DEFAULT + bind appflow global logproxy_policy 10 END -type REQ_DEFAULT - bind appflow global logproxy_policy 10 END -type OTHERTCP_REQ_DEFAULT + bind appflow global logproxy_policy 10 END -type OTHERTCP_REQ_DEFAULT - > **Note:** > If container agent is being used here for Citrix ADM, specify `PodIP` of container agent in above manual config. - ## Citrix ADC as Ingress Gateway: a sample deployment A sample deployment of Citrix ADC as an Ingress gateway for the Bookinfo application is provided [here](https://github.com/citrix/citrix-helm-charts/tree/master/examples/citrix-adc-in-istio). @@ -422,28 +420,34 @@ To deploy Citrix ADC VPX or MPX with Citrix ADC certificate verification, do the The following table lists the configurable parameters in the Helm chart and their default values. - | Parameter | Description | Default | Optional/Mandatory | |--------------------------------|-------------------------------|---------------------------|---------------------------| | `citrixCPX` | Citrix ADC CPX | FALSE | Mandatory for Citrix ADC CPX | -| `xDSAdaptor.image` | Image of the Citrix xDS adaptor container (Refer compatibility matrix) |quay.io/citrix/citrix-xds-adaptor:0.9.9 | Mandatory| +| `xDSAdaptor.imageRegistry` | Image registry of the Citrix xDS adaptor container(Refer compatibility matrix) | `quay.io` | Mandatory | +| `xDSAdaptor.imageRepository` | Image repository of the Citrix xDS adaptor container(Refer compatibility matrix) | `citrix/citrix-xds-adaptor` | Mandatory | +| `xDSAdaptor.imageTag` | Image tag of the Citrix xDS adaptor container(Refer compatibility matrix) | `0.10.3` | Mandatory | | `xDSAdaptor.imagePullPolicy` | Image pull policy for xDS adaptor | IfNotPresent | Optional| | `xDSAdaptor.secureConnect` | If this value is set to true, xDS-adaptor establishes secure gRPC channel with Istio Pilot | TRUE | Optional| | `xDSAdaptor.logLevel` | Log level to be set for xDS-adaptor log messages. Possible values: TRACE (most verbose), DEBUG, INFO, WARN, ERROR (least verbose) | DEBUG | Optional| | `xDSAdaptor.jsonLog` | Set this argument to true if log messages are required in JSON format | false | Optional| +| `xDSAdaptor.defaultSSLListenerOn443` | Create SSL vserver by default for LDS resource for 0.0.0.0 and port 443. If set to false, TCP vserver will be created in absence of TLSContext in tcp_proxy filter | true | Optional | | `coe.coeURL` | Name of [Citrix Observability Exporter](https://github.com/citrix/citrix-observability-exporter) Service in the form of "." | null | Optional| | `coe.coeTracing` | Use COE to send appflow transactions to Zipkin endpoint. If it is set to true, ADM servicegraph (if configured) can be impacted. | false | Optional| -| `ADMSettings.ADMIP ` | Citrix Application Delivery Management (ADM) IP address | null | Mandatory for Citrix ADC CPX | -| `ADMSettings.licenseServerIP ` | Citrix License Server IP address | null | Optional | +| `ADMSettings.ADMIP` | Citrix Application Delivery Management (ADM) IP address | null | Mandatory for Citrix ADC CPX | +| `ADMSettings.licenseServerIP` | Citrix License Server IP address | null | Optional | | `ADMSettings.licenseServerPort` | Citrix ADM port if a non-default port is used | 27000 | Optional| -| `ADMSettings.bandWidth` | Desired bandwidth capacity to be set for Citrix ADC CPX in Mbps | null | Optional | +| `ADMSettings.bandWidth` | Desired bandwidth capacity to be set for Citrix ADC CPX in Mbps | 1000 | Optional | | `ADMSettings.bandWidthLicense` | To specify bandwidth based licensing | false | Optional | +| `ADMSettings.licenseEdition`| License edition that can be Standard, Platinum and Enterprise . By default, Platinum is selected | PLATINUM | optional | +| `ADMSettings.analyticsServerPort` | Port used for Analytics in ADM. Required to plot ServiceGraph. | 5557 | Optional| | `ingressGateway.netscalerUrl` | URL or IP address of the Citrix ADC which Istio-adaptor configures (Mandatory if citrixCPX=false)| null |Mandatory for Citrix ADC MPX or VPX| | `ingressGateway.vserverIP` | Virtual server IP address on Citrix ADC (Mandatory if citrixCPX=false) | null | Mandatory for Citrix ADC MPX or VPX| -| `ingressGateway.adcServerName ` | Citrix ADC ServerName used in the Citrix ADC certificate | null | Optional | -| `ingressGateway.image` | Image of Citrix ADC CPX designated to run as Ingress Gateway |quay.io/citrix/citrix-k8s-cpx-ingress:13.0-83.27 | Mandatory for Citrix ADC CPX | +| `ingressGateway.adcServerName` | Citrix ADC ServerName used in the Citrix ADC certificate | null | Optional | +| `ingressGateway.imageRegistry` | Image registry of Citrix ADC CPX designated to run as Ingress Gateway | `quay.io` | Mandatory for Citrix ADC CPX | +| `ingressGateway.imageRepository` | Image repository of Citrix ADC CPX designated to run as Ingress Gateway | `citrix/citrix-k8s-cpx-ingress` | Mandatory for Citrix ADC CPX | +| `ingressGateway.imageTag` | Image tag of Citrix ADC CPX designated to run as Ingress Gateway | `13.1-30.52` | Mandatory for Citrix ADC CPX | | `ingressGateway.imagePullPolicy` | Image pull policy | IfNotPresent | Optional| -| `ingressGateway.EULA` | End User License Agreement(EULA) terms and conditions. If yes, then user agrees to EULA terms and conditions. | NO | Mandatory for Citrix ADC CPX +| `ingressGateway.EULA` | End User License Agreement(EULA) terms and conditions. If yes, then user agrees to EULA terms and conditions. | NO | Mandatory for Citrix ADC CPX | `ingressGateway.mgmtHttpPort` | Management port of the Citrix ADC CPX | 9080 | Optional| | `ingressGateway.mgmtHttpsPort` | Secure management port of Citrix ADC CPX | 9443 | Optional| | `ingressGateway.httpNodePort` | Port on host machine which is used to expose HTTP port (80) of Citrix ADC CPX | 30180 |Optional| @@ -451,19 +455,23 @@ The following table lists the configurable parameters in the Helm chart and thei | `ingressGateway.nodePortRequired` | Set this argument if servicetype to be NodePort of Citrix ADC CPX | false |Optional| | `ingressGateway.secretVolume` | A map of user defined volumes to be mounted using Kubernetes secrets | null |Optional| | `ingressGateway.label` | Custom label for the Ingress Gateway service | citrix-ingressgateway |Optional| -| `ingressGateway.netProfile ` | Network profile name used by [CNC](https://github.com/citrix/citrix-k8s-node-controller) to configure Citrix ADC VPX or MPX which is deployed as Ingress Gateway | null | Optional| -| `ingressGateway.multiClusterIngress ` | Flag indicating if Citrix ADC is acting as Ingress gateway to multi cluster Istio mesh installation. Possible values: true/false | false | Optional| -| `ingressGateway.multiClusterListenerPort ` | Port opened on Citrix ADC to enable inter-cluster service to service (E-W) communication | 15443 | Optional| -| `ingressGateway.multiClusterListenerNodePort ` | Nodeport for multiClusterListenerPort in case of Citrix ADC CPX acting as Ingress gateway | 32443 | Optional| -| `ingressGateway.multiClusterSvcDomain ` | Domain suffix of remote service (deployed in other cluster) used in E-W communication | global | Optional| +| `ingressGateway.netProfile` | Network profile name used by [CNC](https://github.com/citrix/citrix-k8s-node-controller) to configure Citrix ADC VPX or MPX which is deployed as Ingress Gateway | null | Optional| +| `ingressGateway.multiClusterIngress` | Flag indicating if Citrix ADC is acting as Ingress gateway to multi cluster Istio mesh installation. Possible values: true/false | false | Optional| +| `ingressGateway.multiClusterListenerPort` | Port opened on Citrix ADC to enable inter-cluster service to service (E-W) communication | 15443 | Optional| +| `ingressGateway.multiClusterListenerNodePort` | Nodeport for multiClusterListenerPort in case of Citrix ADC CPX acting as Ingress gateway | 32443 | Optional| +| `ingressGateway.multiClusterSvcDomain` | Domain suffix of remote service (deployed in other cluster) used in E-W communication | global | Optional| +| `ingressGateway.cpxLicenseAggregator` | IP/FQDN of the CPX License Aggregator if it is being used to license the CPX. | null | Optional| | `ingressGateway.tcpPort` | For exposing multiple TCP ingress | null |Optional| +| `ingressGateway.enableLabelsFeature` | If this variable is true, Istio's [subset](https://istio.io/latest/docs/reference/config/networking/destination-rule/#Subset) of the service and some metadata of the service such as servicename, namespace etc will be stored in the Citrix ADC that might be used for analytics purpose. | FALSE |Optional| | `istioPilot.name` | Name of the Istio Pilot service | istiod |Optional| | `istioPilot.namespace` | Namespace where Istio Pilot is running | istio-system |Optional| | `istioPilot.secureGrpcPort` | Secure GRPC port where Istiod (Istio Pilot) is listening (default setting) | 15012 |Optional| | `istioPilot.insecureGrpcPort` | Insecure GRPC port where Istiod (Istio Pilot) is listening | 15010 |Optional| | `istioPilot.SAN` | Subject alternative name for Istiod (Istio Pilot) which is the secure production identity framework for everyone (SPIFFE) ID of Istio Pilot | null |Optional| | `metricExporter.required` | Metrics exporter for Citrix ADC | TRUE |Optional| -| `metricExporter.image` | Image of the Citrix ADC Metrics Exporter | quay.io/citrix/citrix-adc-metrics-exporter:1.4.9 |Optional| +| `metricExporter.imageRegistry` | Image registry of the Citrix ADC Metrics Exporter | `quay.io` | Optional | +| `metricExporter.imageRepository` | Image repository of the Citrix ADC Metrics Exporter | `citrix/citrix-adc-metrics-exporter` | Optional | +| `metricExporter.imageTag` | Image tag of the Citrix ADC Metrics Exporter | `1.4.9` | Optional | | `metricExporter.port` | Port over which Citrix ADC Metrics Exporter collects metrics of Citrix ADC. | 8888 |Optional| | `metricExporter.secure` | Enables collecting metrics over TLS | YES |Optional| | `metricExporter.logLevel` | Level of logging in Citrix ADC Metrics Exporter. Possible values are: DEBUG, INFO, WARNING, ERROR, CRITICAL | ERROR |Optional| diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/app-readme.md b/charts/citrix/citrix-adc-istio-ingress-gateway/app-readme.md similarity index 100% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/app-readme.md rename to charts/citrix/citrix-adc-istio-ingress-gateway/app-readme.md diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/questions.yml b/charts/citrix/citrix-adc-istio-ingress-gateway/questions.yml similarity index 100% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/questions.yml rename to charts/citrix/citrix-adc-istio-ingress-gateway/questions.yml diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/_helpers.tpl b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/_helpers.tpl similarity index 100% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/_helpers.tpl rename to charts/citrix/citrix-adc-istio-ingress-gateway/templates/_helpers.tpl diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml similarity index 84% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml rename to charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml index 53af158f1..8d80e572e 100644 --- a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml +++ b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-adc-ingressgateway-deployment.yaml @@ -17,6 +17,8 @@ spec: labels: app: {{ .Values.ingressGateway.label | default "citrix-ingressgateway" }} citrix.com/no.sidecar: "true" + adc: "citrix" + deployment: "cpx-ingressgateway" # This label is useful in ServiceGraph annotations: scheduler.alpha.kubernetes.io/critical-pod: "" prometheus.io/port: "{{ .Values.metricExporter.port }}" @@ -31,6 +33,15 @@ spec: secret: optional: true secretName: "citrix-ingressgateway-ca-certs" # IMPORTANT: This secret MUST BE created before deploying gateway and ingress-gateway + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations {{- range .Values.ingressGateway.secretVolumes }} - name: {{ .name }} secret: @@ -64,7 +75,7 @@ spec: containers: {{- if eq .Values.metricExporter.required true }} - name: exporter - image: {{ .Values.metricExporter.image }} + image: {{ tpl .Values.metricExporter.image . }} imagePullPolicy: IfNotPresent args: - "--target-nsip=127.0.0.1" @@ -81,7 +92,7 @@ spec: name: cpx-pwd {{- end }} - name: istio-adaptor - image: {{ .Values.xDSAdaptor.image }} + image: {{ tpl .Values.xDSAdaptor.image . }} imagePullPolicy: {{ .Values.xDSAdaptor.imagePullPolicy }} args: - -ads-server @@ -107,7 +118,10 @@ spec: - -citrix-adm - {{ .Values.ADMSettings.ADMIP }} {{- end }} -{{- if .Values.ADMSettings.licenseServerIP }} +{{- if .Values.ingressGateway.cpxLicenseAggregator }} + - -citrix-license-server + - {{ .Values.ingressGateway.cpxLicenseAggregator }} +{{- else if .Values.ADMSettings.licenseServerIP }} - -citrix-license-server - {{ .Values.ADMSettings.licenseServerIP }} {{- end }} @@ -170,7 +184,14 @@ spec: {{- if eq .Values.xDSAdaptor.jsonLog true }} - name: JSONLOG value: "TRUE" + {{- end }} + - name: ENABLE_LABELS_FEATURE + value: {{ .Values.ingressGateway.enableLabelsFeature | quote }} +{{- if eq .Values.xDSAdaptor.defaultSSLListenerOn443 true }} + - name: DEFAULT_SSL_LISTENER_ON_443 + value: "TRUE" +{{- end }} securityContext: readOnlyRootFilesystem: true runAsGroup: 32024 @@ -193,13 +214,15 @@ spec: - mountPath: /etc/istio/ingressgateway-ca-certs # Make sure that Gateway definition has this path mentioned in server.tls section for MUTUAL TLS name: citrix-ingressgateway-ca-certs readOnly: true + - mountPath: /etc/podinfo + name: podinfo {{- range .Values.ingressGateway.secretVolumes }} - name: {{ .name }} mountPath: {{ .mountPath | quote }} readOnly: true {{- end }} - name: citrix-ingressgateway - image: "{{ .Values.ingressGateway.image }}" + image: "{{ tpl .Values.ingressGateway.image . }}" imagePullPolicy: {{ .Values.ingressGateway.imagePullPolicy }} securityContext: privileged: true @@ -223,6 +246,23 @@ spec: - mountPath: /var/deviceinfo name: cpx-pwd env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +{{- if .Values.ingressGateway.cpxLicenseAggregator }} + - name: "CLA" + value: "{{ .Values.ingressGateway.cpxLicenseAggregator }}" +{{- else if .Values.ADMSettings.licenseServerIP }} + - name: "LS_IP" + value: {{ .Values.ADMSettings.licenseServerIP }} + - name: "LS_PORT" + value: "{{ .Values.ADMSettings.licenseServerPort }}" +{{- end }} - name: "EULA" value: "{{ .Values.ingressGateway.EULA }}" {{- if .Values.metricExporter.required }} @@ -233,40 +273,44 @@ spec: value: "{{ .Values.ingressGateway.mgmtHttpPort }}" - name: "MGMT_HTTPS_PORT" value: "{{ .Values.ingressGateway.mgmtHttpsPort }}" +{{- if .Values.ingressGateway.lightWeightCPX }} - name: "NS_CPX_LITE" - value: "{{ .Values.ingressGateway.lightWeightCPX }}" + value: "1" +{{- end }} {{- if or .Values.coe.coeURL .Values.ADMSettings.ADMIP }} - name: "NS_ENABLE_NEWNSLOG" value: "1" {{- end }} - name: "KUBERNETES_TASK_ID" value: "" - - name: "LS_IP" - value: {{ .Values.ADMSettings.licenseServerIP | default "" }} - - name: "LS_PORT" - value: "{{ .Values.ADMSettings.licenseServerPort}}" {{- if .Values.ADMSettings.ADMIP }} - name: "NS_MGMT_SERVER" - value: {{ .Values.ADMSettings.ADMIP }} + value: {{ .Values.ADMSettings.ADMIP | quote }} - name: "NS_HTTP_PORT" value: {{ .Values.ingressGateway.mgmtHttpPort | quote }} - name: "NS_HTTPS_PORT" value: {{ .Values.ingressGateway.mgmtHttpsPort | quote }} + - name: "ANALYTICS_SERVER" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "ANALYTICS_SERVER_PORT" + value: {{ .Values.ADMSettings.analyticsServerPort | quote }} {{- end }} - name: "LOGSTREAM_COLLECTOR_IP" - value: {{ .Values.ADMSettings.ADMIP | default ""}} -#To povision bandwidth based licensing to Citrix ADC CPX from ADM, needs bandwidth -{{- if and ( .Values.ADMSettings.licenseServerIP ) (eq .Values.ADMSettings.bandWidthLicense true) }} + value: {{ .Values.ADMSettings.ADMIP | default "" | quote }} +#Need to set env var BANDWIDTH in order to provide Bandwidth license to Citrix ADC CPX from ADM or CPX License Aggregator +{{- if and ( or ( .Values.ADMSettings.licenseServerIP ) ( .Values.ingressGateway.cpxLicenseAggregator ) ) ( eq .Values.ADMSettings.bandWidthLicense true ) }} - name: "BANDWIDTH" - value: {{ required "Mention bandwidth for bandwidth based licensing" .Values.ADMSettings.bandWidth | quote }} + value: {{ .Values.ADMSettings.bandWidth | quote }} {{- end }} #for multiple-PE support, need to set CPX_CORES -{{- if .Values.ADMSettings.licenseServerIP }} -{{- if or (eq .Values.ADMSettings.vCPULicense true) (eq .Values.ADMSettings.bandWidthLicense true) }} +{{- if or .Values.ADMSettings.licenseServerIP .Values.ingressGateway.cpxLicenseAggregator }} +{{- if or ( eq .Values.ADMSettings.vCPULicense true ) ( eq .Values.ADMSettings.bandWidthLicense true ) }} - name: "CPX_CORES" value: {{ .Values.ADMSettings.cpxCores | default 1 | quote }} {{- end }} {{- end }} + - name: "EDITION" + value: {{ .Values.ADMSettings.licenseEdition | quote }} {{- if or (.Values.ADMSettings.ADMIP) (.Values.ADMSettings.licenseServerIP) }} - name: NS_MGMT_USER valueFrom: @@ -298,6 +342,7 @@ spec: labels: app: {{ .Values.ingressGateway.label | default "citrix-ingressgateway" }} citrix.com/no.sidecar: "true" + adc: "citrix" annotations: scheduler.alpha.kubernetes.io/critical-pod: "" prometheus.io/port: "{{ .Values.metricExporter.port }}" @@ -306,7 +351,7 @@ spec: containers: {{- if eq .Values.metricExporter.required true }} - name: exporter - image: {{ .Values.metricExporter.image }} + image: {{ tpl .Values.metricExporter.image . }} imagePullPolicy: {{ .Values.metricExporter.imagePullPolicy }} args: - "--target-nsip={{- include "exporter_nsip" . -}}" @@ -321,7 +366,7 @@ spec: readOnly: true {{- end }} - name: istio-adaptor - image: {{ .Values.xDSAdaptor.image }} + image: {{ tpl .Values.xDSAdaptor.image . }} imagePullPolicy: {{ .Values.xDSAdaptor.imagePullPolicy }} env: - name: POD_NAME @@ -379,6 +424,12 @@ spec: - name: JSONLOG value: "TRUE" {{- end }} + - name: ENABLE_LABELS_FEATURE + value: "FALSE" +{{- if eq .Values.xDSAdaptor.defaultSSLListenerOn443 true }} + - name: DEFAULT_SSL_LISTENER_ON_443 + value: "TRUE" +{{- end }} - name: NS_USER valueFrom: secretKeyRef: @@ -452,6 +503,8 @@ spec: - mountPath: /etc/istio/ingressgateway-ca-certs # Make sure that Gateway definition has this path mentioned in server.tls section for MUTUAL TLS name: citrix-ingressgateway-ca-certs readOnly: true + - mountPath: /etc/podinfo + name: podinfo {{- range .Values.ingressGateway.secretVolumes }} - name: {{ .name }} mountPath: {{ .mountPath | quote }} @@ -482,7 +535,16 @@ spec: - name: citrix-ingressgateway-ca-certs secret: optional: true - secretName: "citrix-ingressgateway-ca-certs" # IMPORTANT: This secret MUST BE created before deploying gateway and ingress-gateway + secretName: "citrix-ingressgateway-ca-certs" # IMPORTANT: This secret MUST BE created before deploying gateway and ingress-gateway + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations {{- range .Values.ingressGateway.secretVolumes }} - name: {{ .name }} secret: diff --git a/charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-multicluster-gateway.yaml b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-multicluster-gateway.yaml new file mode 100644 index 000000000..ae40331fe --- /dev/null +++ b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/citrix-multicluster-gateway.yaml @@ -0,0 +1,46 @@ +{{- if eq .Values.ingressGateway.multiClusterIngress true }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + annotations: + labels: + app: {{ .Values.ingressGateway.label | default "citrix-ingressgateway" }} +{{- if eq .Values.citrixCPX true }} + deployment: "cpx-ingressgateway" # This label is useful in ServiceGraph +{{- end }} + name: citrix-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} +spec: + selector: + app: {{ .Values.ingressGateway.label | default "citrix-ingressgateway" }} + servers: + - port: + name: tls-mc-port + number: {{ .Values.ingressGateway.multiClusterListenerPort }} + protocol: tls + tls: + mode: PASSTHROUGH + hosts: + - {{ printf "'*.%s'" .Values.ingressGateway.multiClusterSvcDomain }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: citrix-multicluster-ingressgateway +spec: + hosts: + - {{ printf "'*.%s'" .Values.ingressGateway.multiClusterSvcDomain }} + gateways: + - citrix-multicluster-ingressgateway + tls: + - match: + - port: {{ .Values.ingressGateway.multiClusterListenerPort }} + sniHosts: + - {{ printf "'*.%s'" .Values.ingressGateway.multiClusterSvcDomain }} + route: + - destination: + host: {{ template "generate-name" (list . (dict "suffixname" "citrix-ingress-svc")) }} + port: + number: {{ .Values.ingressGateway.multiClusterListenerPort }} +--- +{{- end }} \ No newline at end of file diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/ingressgateway-service.yaml b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/ingressgateway-service.yaml similarity index 100% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/ingressgateway-service.yaml rename to charts/citrix/citrix-adc-istio-ingress-gateway/templates/ingressgateway-service.yaml diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml similarity index 92% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml rename to charts/citrix/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml index b63096938..4448ad191 100644 --- a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml +++ b/charts/citrix/citrix-adc-istio-ingress-gateway/templates/metrics-exporter-service.yaml @@ -3,6 +3,7 @@ kind: Service apiVersion: v1 metadata: name: {{ template "generate-name" (list . (dict "suffixname" "citrix-exporter-svc")) }} + namespace: {{ .Release.Namespace }} annotations: labels: service-type: citrix-adc-monitor diff --git a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/values.yaml b/charts/citrix/citrix-adc-istio-ingress-gateway/values.yaml similarity index 62% rename from charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/values.yaml rename to charts/citrix/citrix-adc-istio-ingress-gateway/values.yaml index f6a6d0051..123e6d481 100644 --- a/charts/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway/values.yaml +++ b/charts/citrix/citrix-adc-istio-ingress-gateway/values.yaml @@ -10,19 +10,26 @@ coe: metricExporter: required: true - image: quay.io/citrix/citrix-adc-metrics-exporter:1.4.9 + imageRegistry: quay.io + imageRepository: citrix/citrix-adc-metrics-exporter + imageTag: 1.4.9 + image: "{{ .Values.metricExporter.imageRegistry }}/{{ .Values.metricExporter.imageRepository }}:{{ .Values.metricExporter.imageTag }}" port: 8888 secure: "YES" logLevel: ERROR imagePullPolicy: IfNotPresent xDSAdaptor: - image: quay.io/citrix/citrix-xds-adaptor:0.9.9 + imageRegistry: quay.io + imageRepository: citrix/citrix-xds-adaptor + imageTag: 0.10.3 + image: "{{ .Values.xDSAdaptor.imageRegistry }}/{{ .Values.xDSAdaptor.imageRepository }}:{{ .Values.xDSAdaptor.imageTag }}" imagePullPolicy: IfNotPresent proxyType: router secureConnect: true logLevel: DEBUG jsonLog: false + defaultSSLListenerOn443: true istioPilot: name: istiod @@ -41,14 +48,17 @@ certProvider: ingressGateway: netscalerUrl: null - image: quay.io/citrix/citrix-k8s-cpx-ingress:13.0-83.27 + imageRegistry: quay.io + imageRepository: citrix/citrix-k8s-cpx-ingress + imageTag: 13.1-30.52 + image: "{{ .Values.ingressGateway.imageRegistry }}/{{ .Values.ingressGateway.imageRepository }}:{{ .Values.ingressGateway.imageTag }}" imagePullPolicy: IfNotPresent EULA: NO mgmtHttpPort: 10080 mgmtHttpsPort: 10443 httpNodePort: 30180 httpsNodePort: 31443 - nodePortRequired: true + nodePortRequired: false lightWeightCPX: 1 secretVolumes: #licenseServerIP: this value will be taken from ADMSettings.ADMIP @@ -61,14 +71,18 @@ ingressGateway: multiClusterListenerPort: 15443 multiClusterListenerNodePort: 32443 multiClusterSvcDomain: global + cpxLicenseAggregator: + enableLabelsFeature: FALSE ADMSettings: ADMIP: licenseServerIP: licenseServerPort: 27000 bandWidthLicense: false - bandWidth: + bandWidth: 1000 #Bandwidth should be given in Mbps vCPULicense: false cpxCores: + analyticsServerPort: 5557 + licenseEdition: PLATINUM secretName: nslogin diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/.helmignore b/charts/citrix/citrix-cpx-istio-sidecar-injector/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/Chart.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/Chart.yaml new file mode 100644 index 000000000..1952382c6 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/Chart.yaml @@ -0,0 +1,21 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Cpx Istio Sidecar Injector + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-cpx-istio-sidecar-injector +apiVersion: v2 +appVersion: 1.14.1 +description: A Helm chart to deploy resources which install Citrix ADC CPX in Istio + Service Mesh as sidecar in application pod +home: https://www.citrix.com +icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png +kubeVersion: '>=v1.16.0-0' +maintainers: +- email: dhiraj.gedam@citrix.com + name: dheerajng +- email: subash.dangol@citrix.com + name: subashd +name: citrix-cpx-istio-sidecar-injector +sources: +- https://github.com/citrix/citrix-xds-adaptor +version: 1.14.1 diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/README.md b/charts/citrix/citrix-cpx-istio-sidecar-injector/README.md new file mode 100644 index 000000000..62ee974e3 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/README.md @@ -0,0 +1,294 @@ +# Deploy Citrix ADC CPX as a sidecar in Istio environment using Helm charts + +Citrix ADC CPX can be deployed as a sidecar proxy in an application pod in the Istio service mesh. + + +# Table of Contents +1. [TL; DR;](#tldr) +2. [Introduction](#introduction) +3. [Deploy Sidecar Injector for Citrix ADC CPX using Helm chart](#deploy-sidecar-injector-for-citrix-adc-cpx-using-helm-chart) +4. [Observability using Citrix Observability Exporter](#observability-using-coe) +5. [Citrix ADC CPX License Provisioning](#citrix-adc-cpx-license-provisioning) +6. [Service Graph configuration](#configuration-for-servicegraph) +7. [Generate Certificate for Application](#generate-certificate-for-application) +8. [Limitations](#limitations) +9. [Clean Up](#clean-up) +10. [Configuration Parameters](#configuration-parameters) + + +## TL; DR; + + kubectl create namespace citrix-system + + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES + + +## Introduction + +Citrix ADC CPX can act as a sidecar proxy to an application container in Istio. You can inject the Citrix ADC CPX manually or automatically using the [Istio sidecar injector](https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/). Automatic sidecar injection requires resources including a Kubernetes [mutating webhook admission](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) controller, and a service. Using this Helm chart, you can create resources required for automatically deploying Citrix ADC CPX as a sidecar proxy. + +In Istio servicemesh, the namespace must be labelled before applying the deployment yaml for [automatic sidecar injection](https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#automatic-sidecar-injection). Once the namespace is labelled, sidecars (envoy or CPX) will be injected while creating pods. +- For CPX, namespace must be labelled `cpx-injection=enabled` +- For Envoy, namespace must be labelled `istio-injection=enabled` + +__Note: If a namespace is labelled with both `istio-injection` and `cpx-injection`, Envoy injection takes a priority! Citrix CPX won't be injected on top of the already injected Envoy sidecar. For using Citrix ADC as sidecar, ensure that `istio-injection` label is removed from the namespace.__ + +For detailed information on different deployment options, see [Deployment Architecture](https://github.com/citrix/citrix-istio-adaptor/blob/master/docs/istio-integration/architecture.md). + +### Compatibility Matrix between Citrix xDS-adaptor and Istio version + +Below table provides info about recommended Citrix xDS-Adaptor version to be used for various Istio versions. + +| Citrix xDS-Adaptor version | Istio version | +|----------------------------|---------------| +| quay.io/citrix/citrix-xds-adaptor:0.10.3 | Istio v1.14+ | +| quay.io/citrix/citrix-xds-adaptor:0.10.1 | Istio v1.12 to Istio v1.13 | +| quay.io/citrix/citrix-xds-adaptor:0.9.9 | Istio v1.10 to Istio v1.11 | +| quay.io/citrix/citrix-xds-adaptor:0.9.8 | Istio v1.8 to Istio v1.9 | +| quay.io/citrix/citrix-xds-adaptor:0.9.5 | Istio v1.6 | + +### Prerequisites + +The following prerequisites are required for deploying Citrix ADC as a sidecar to an application pod. + +- Ensure that **Istio version 1.8 onwards** is installed +- Ensure that Helm with version 3.x is installed. Follow this [step](https://github.com/citrix/citrix-helm-charts/blob/master/Helm_Installation_version_3.md) to install the same. +- Ensure that your cluster Kubernetes version should be 1.16 onwards and the `admissionregistration.k8s.io/v1`, `admissionregistration.k8s.io/v1beta1` API is enabled + +You can verify the API by using the following command: + + kubectl api-versions | grep admissionregistration.k8s.io/v1 + +The following output indicates that the API is enabled: + + admissionregistration.k8s.io/v1 + admissionregistration.k8s.io/v1beta1 + +- Create namespace `citrix-system` + + kubectl create namespace citrix-system + +- **Registration of Citrix ADC CPX in ADM** + +Create a secret containing ADM username and password in each application namespace. + + kubectl create secret generic admlogin --from-literal=username= --from-literal=password= -n citrix-system + +## Deploy Sidecar Injector for Citrix ADC CPX using Helm chart + +**Before you Begin** + +To deploy resources for automatic installation of Citrix ADC CPX as a sidecar in Istio, perform the following step. In this example, release name is specified as `cpx-sidecar-injector` and namespace is used as `citrix-system`. + + + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES + +This step installs a mutating webhook and a service resource to application pods in the namespace labeled as `cpx-injection=enabled`. + +*"Note:" The `cpx-injection=enabled` label is mandatory for injecting sidecars.* + +An example to deploy application along with Citrix ADC CPX sidecar is provided [here](https://github.com/citrix/citrix-helm-charts/tree/master/examples/citrix-adc-in-istio). + + +# Observability using Citrix Observability Exporter + +### Pre-requisites + +1. Citrix Observability Exporter (COE) should be deployed in the cluster. + +2. Citrix ADC CPX should be running with versions 13.0-48+ or 12.1-56+. + +Citrix ADC CPXes serving East West traffic send its metrics and transaction data to COE which has a support for Prometheus and Zipkin. + +Metrics data can be visualized in Prometheus dashboard. + +Zipkin enables users to analyze tracing for East-West service to service communication. + +*Note*: Istio should be [installed](https://istio.io/docs/tasks/observability/distributed-tracing/zipkin/#before-you-begin) with Zipkin as tracing endpoint. + +``` +helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + +helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES,coe.coeURL=. +``` + +By default, COE is primarily used for Prometheus integration. Servicegraph and tracing is handled by Citrix ADM appliance. To enable Zipkin tracing, set argument `coe.coeTracing=true` in helm command. Default value of coeTracing is set to false. + +``` +helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + +helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES,coe.coeURL=.,coe.coeTracing=true + +``` + +For example, if COE is deployed as `coe` in `citrix-system` namespace, then below helm command will deploy sidecar injector webhook which will be deploying Citrix ADC CPX sidecar proxies in application pods, and these sidecar proxies will be configured to establish communication channels with COE. + +``` +helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + +helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES,coe.coeURL=coe.citrix-system +``` + +*Important*: Apply below mentioned annotations on COE deployment so that Prometheus can scrape data from COE. +``` + prometheus.io/scrape: "true" + prometheus.io/port: "5563" # Prometheus port +``` +## **Citrix ADC CPX License Provisioning** +By default, CPX runs with 20 Mbps bandwidth called as [CPX Express](https://www.citrix.com/en-in/products/citrix-adc/cpx-express.html) however for better performance and production deployment customer needs licensed CPX instances. [Citrix ADM](https://www.citrix.com/en-in/products/citrix-application-delivery-management/) is used to check out licenses for Citrix ADC CPX. + +**Bandwidth based licensing** +For provisioning licensing on Citrix ADC CPX, it is mandatory to provide License Server information to CPX. This can be done by setting **ADMSettings.licenseServerIP** as License Server IP. In addition to this, **ADMSettings.bandWidthLicense** needs to be set true and desired bandwidth capacity in Mbps should be set **ADMSettings.bandWidth**. +For example, to set 2Gbps as bandwidth capacity, below command can be used. + +``` +helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + +helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES --set ADMSettings.licenseServerIP=,ADMSettings.bandWidthLicense=True --set ADMSettings.bandWidth=2000 + +``` + +## **Service Graph configuration** + Citrix ADM Service graph is an observability tool that allows user to analyse service to service communication. The service graph is generated by ADM post collection of transactional data from registered Citrix ADC instances. More details about it can be found [here](https://docs.citrix.com/en-us/citrix-application-delivery-management-service/application-analytics-and-management/service-graph.html). + Citrix ADC needs to be provided with ADM details for registration and data export. This section lists the steps needed to deploy Citrix ADC and register it with ADM. + + 1. Create secret using Citrix ADM Agent credentials, which will be used by Citrix ADC as CPX to communicate with Citrix ADM Agent: + + kubectl create secret generic admlogin --from-literal=username= --from-literal=password= + + 2. Deploy Citrix ADC CPX sidecar injector using helm command with `ADM` details: + + helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES --set ADMSettings.ADMIP= + +> **Note:** +> If container agent is being used here for Citrix ADM, specify `serviceIP` of container agent in the `ADMSettings.ADMIP` parameter. + +## Generate Certificate for Application + +Application needs TLS certificate-key pair for establishing secure communication channel with other applications. Earlier these certificates were issued by Istio Citadel and bundled in Kubernetes secret. Certificate was loaded in the application pod by doing volume mount of secret. Now `xDS-Adaptor` can generate its own certificate and get it signed by the Istio Citadel (Istiod). This eliminates the need of secret and associated [risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks). + +xDS-Adaptor needs to be provided with details Certificate Authority (CA) for successful signing of Certificate Signing Request (CSR). By default, CA is `istiod.istio-system.svc` which accepts CSRs on port 15012. +To skip this process, don't provide any value (empty string) to `certProvider.caAddr`. +``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES --set certProvider.caAddr="" +``` + +### Configure Third Party Service Account Tokens + +In order to generate certificate for application workload, xDS-Adaptor needs to send valid service account token along with Certificate Signing Request (CSR) to the Istio control plane (Citadel CA). Istio control plane authenticates the xDS-Adaptor using this JWT. +Kubernetes supports two forms of these tokens: + +* Third party tokens, which have a scoped audience and expiration. +* First party tokens, which have no expiration and are mounted into all pods. + + If Kubernetes cluster is installed with third party tokens, then the same information needs to be provided for automatic sidecar injection by passing `--set certProvider.jwtPolicy="third-party-jwt"`. By default, it is `first-party-jwt`. + +``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES --set certProvider.caAddr="istiod.istio-system.svc" --set certProvider.jwtPolicy="third-party-jwt" + +``` + +To determine if your cluster supports third party tokens, look for the TokenRequest API using below command. If there is no output, then it is `first-party-jwt`. In case of `third-party-jwt`, output will be like below. + +``` +# kubectl get --raw /api/v1 | jq '.resources[] | select(.name | index("serviceaccounts/token"))' + +{ + "name": "serviceaccounts/token", + "singularName": "", + "namespaced": true, + "group": "authentication.k8s.io", + "version": "v1", + "kind": "TokenRequest", + "verbs": [ + "create" + ] +} + +``` + +## Limitations + +Citrix ADC CPX occupies certain ports for internal usage. This makes application service running on one of these restricted ports incompatible with the Citrix ADC CPX. +The list of ports is mentioned below. Citrix is working on delisting some of the major ports from the given list, and same shall be available in future releases. + +#### Restricted Ports + +| Sr No |Port Number| +|-------|-----------| +| 1 | 80 | +| 2 | 3010 | +| 3 | 5555 | +| 4 | 8080 | + +## Clean Up + +To delete the resources created for automatic injection with the release name `cpx-sidecar-injector`, perform the following step. + + helm delete cpx-sidecar-injector + +## Configuration parameters + +The following table lists the configurable parameters and their default values in the Helm chart. + + +| Parameter | Description | Default | +|--------------------------------|-------------------------------|---------------------------| +| `xDSAdaptor.imageRegistry` | Image registry of the Citrix xDS adaptor container | `quay.io` | +| `xDSAdaptor.imageRepository` | Image repository of the Citrix xDS adaptor container | `citrix/citrix-xds-adaptor` | +| `xDSAdaptor.imageTag` | Image tag of the Citrix xDS adaptor container | `0.10.3` | +| `xDSAdaptor.imagePullPolicy` | Image pull policy for xDS-adaptor | IfNotPresent | +| `xDSAdaptor.secureConnect` | If this value is set to true, xDS-adaptor establishes secure gRPC channel with Istio Pilot | TRUE | +| `xDSAdaptor.logLevel` | Log level to be set for xDS-adaptor log messages. Possible values: TRACE (most verbose), DEBUG, INFO, WARN, ERROR (least verbose) | DEBUG | Optional| +| `xDSAdaptor.jsonLog` | Set this argument to true if log messages are required in JSON format | false | Optional| +| `xDSAdaptor.defaultSSLListenerOn443` | Create SSL vserver by default for LDS resource for 0.0.0.0 and port 443. If set to false, TCP vserver will be created in absence of TLSContext in tcp_proxy filter | true | Optional | +| `coe.coeURL` | Name of [Citrix Observability Exporter](https://github.com/citrix/citrix-observability-exporter) Service in the form of _servicename.namespace_ | NIL | Optional| +| `coe.coeTracing` | Use COE to send appflow transactions to Zipkin endpoint. If it is set to true, ADM servicegraph (if configured) can be impacted. | false | Optional| +| `ADMSettings.ADMIP` | Provide the Citrix Application Delivery Management (ADM) IP address | NIL | +| `ADMSettings.licenseServerIP` | Citrix License Server IP address | NIL | Optional | +| `ADMSettings.licenseServerPort` | Citrix ADM port if a non-default port is used | 27000 | +| `ADMSettings.bandWidth` | Desired bandwidth capacity to be set for Citrix ADC CPX in Mbps | 1000 | Optional | +| `ADMSettings.analyticsServerPort` | Port used for Analytics in ADM. Required to plot ServiceGraph. | 5557 | Optional | +| `ADMSettings.licenseEdition`| License edition that can be Standard, Platinum and Enterprise . By default, Platinum is selected | PLATINUM | optional | +| `istioPilot.name` | Name of the Istio Pilot service | istio-pilot | Mandatory | +| `istioPilot.namespace` | Namespace where Istio Pilot is running | istio-system | +| `istioPilot.secureGrpcPort` | Secure GRPC port where Istio Pilot is listening (Default setting) | 15011 | +| `istioPilot.insecureGrpcPort` | Insecure GRPC port where Istio Pilot is listening | 15010 | +| `istioPilot.proxyType` | Type of Citrix ADC associated with the xDS-adaptor. Possible values are: sidecar and router. | sidecar| +| `istioPilot.SAN` | Subject alternative name for Istio Pilot which is the Secure Production Identity Framework For Everyone (SPIFFE) ID of Istio Pilot. | NIL | +| `cpxProxy.netscalerUrl` | URL or IP address of the Citrix ADC which will be configured by Istio-adaptor. | http://127.0.0.1 | +| `cpxProxy.imageRegistry` | Image registry of Citrix ADC CPX designated to run as sidecar proxy | `quay.io` | +| `cpxProxy.imageRepository` | Image repository of Citrix ADC CPX designated to run as sidecar proxy | `citrix/citrix-k8s-cpx-ingress` | +| `cpxProxy.imageTag` | Image tag of Citrix ADC CPX designated to run as sidecar proxy | `13.1-30.52` | +| `cpxProxy.imagePullPolicy` | Image pull policy for Citrix ADC | IfNotPresent | +| `cpxProxy.EULA` | End User License Agreement(EULA) terms and conditions. If yes, then user agrees to EULA terms and conditions. | NO | +| `cpxProxy.cpxSidecarMode` | Environment variable for Citrix ADC CPX. It indicates that Citrix ADC CPX is running as sidecar mode or not. | YES | +| `cpxProxy.cpxDisableProbe` | Environment variable for Citrix ADC CPX. It indicates that Citrix ADC CPX will disable probing dynamic services. It should be enabled for multicluster setup. | YES | +| `cpxProxy.cpxLicenseAggregator` | IP/FQDN of the CPX License Aggregator if it is being used to license the CPX. | Null | optional | +| `cpxProxy.enableLabelsFeature` | If this variable is true, Istio's [subset](https://istio.io/latest/docs/reference/config/networking/destination-rule/#Subset) of the service and some metadata of the service such as servicename, namespace etc will be stored in the Citrix ADC that might be used for analytics purpose. | FALSE |Optional| +| `sidecarWebHook.webhookImageRegistry` | Image registry of sidecarWebHook. Mutating webhook associated with the sidecar injector. It invokes a service `cpx-sidecar-injector` to inject sidecar proxies in the application pod. | `quay.io` | +| `sidecarWebHook.webhookImageRepository` | Image repository of sidecarWebHook. Mutating webhook associated with the sidecar injector. It invokes a service `cpx-sidecar-injector` to inject sidecar proxies in the application pod. | `citrix/cpx-istio-sidecar-injector` | +| `sidecarWebHook.webhookImageTag` | Image tag of sidecarWebHook. Mutating webhook associated with the sidecar injector. It invokes a service `cpx-sidecar-injector` to inject sidecar proxies in the application pod. | `1.3.0` | +| `sidecarWebHook.imagePullPolicy` | Image pull policy |IfNotPresent| +| `sidecarCertsGenerator.imageRegistry` | Image registry of sidecarCertsGenerator. Certificate genrator image associated with sidecar injector. This image generates certificate and key needed for CPX sidecar injection. | `quay.io` | +| `sidecarCertsGenerator.imageRepository` | Image repository of sidecarCertsGenerator. Certificate genrator image associated with sidecar injector. This image generates certificate and key needed for CPX sidecar injection. | `citrix/cpx-sidecar-injector-certgen` | +| `sidecarCertsGenerator.imageTag` | Image tag of sidecarCertsGenerator. Certificate genrator image associated with sidecar injector. This image generates certificate and key needed for CPX sidecar injection. | `1.2.0` | +| `sidecarCertsGenerator.imagePullPolicy` | Image pull policy |IfNotPresent| +| `webhook.injectionLabelName` | Label of namespace where automatic Citrix ADC CPX sidecar injection is required. | cpx-injection | +| `certProvider.caAddr` | Certificate Authority (CA) address issuing certificate to application | istiod.istio-system.svc | Optional | +| `certProvider.caPort` | Certificate Authority (CA) port issuing certificate to application | 15012 | Optional | +| `certProvider.trustDomain` | SPIFFE Trust Domain | cluster.local | Optional | +| `certProvider.certTTLinHours` | Validity of certificate generated by xds-adaptor and signed by Istiod (Istio Citadel) in hours. Default is 30 days validity | 720 | Optional | +| `certProvider.clusterId` | clusterId is the ID of the cluster where Istiod CA instance resides (default Kubernetes). It can be different value on some cloud platforms or in multicluster environments. For example, in Anthos servicemesh, it might be of the format of `cn--`. In multiCluster environments, it is the value of global.multiCluster.clusterName provided during servicemesh control plane installation | Kubernetes | Optional | +| `certProvider.jwtPolicy` | Service Account token type. Kubernetes platform supports First party tokens and Third party tokens. | first-party-jwt | Optional | +| `certProvider.jwtPolicy` | Service Account token type. Kubernetes platform supports First party tokens and Third party tokens. Usually public cloud based Kubernetes has third-party-jwt | Null | Optional | + +**Note:** You can use the `values.yaml` file packaged in the chart. This file contains the default configuration values for the chart. diff --git a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay/app-readme.md b/charts/citrix/citrix-cpx-istio-sidecar-injector/app-readme.md similarity index 100% rename from packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay/app-readme.md rename to charts/citrix/citrix-cpx-istio-sidecar-injector/app-readme.md diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/create-certs-for-cpx-istio-chart.sh b/charts/citrix/citrix-cpx-istio-sidecar-injector/create-certs-for-cpx-istio-chart.sh new file mode 100644 index 000000000..ed5d58a4e --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/create-certs-for-cpx-istio-chart.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +set -e + +usage() { + cat <> ${certdir}/csr.conf +[req] +req_extensions = v3_req +distinguished_name = req_distinguished_name +[req_distinguished_name] +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +subjectAltName = @alt_names +[alt_names] +DNS.1 = ${service} +DNS.2 = ${service}.${namespace} +DNS.3 = ${service}.${namespace}.svc +EOF + +openssl genrsa -out ${certdir}/key.pem 2048 +openssl req -new -key ${certdir}/key.pem -subj "/CN=${service}.${namespace}.svc" -out ${certdir}/server.csr -config ${certdir}/csr.conf + +# clean-up any previously created CSR for our service. Ignore errors if not present. +kubectl delete csr ${csrName} 2>/dev/null || true + +# create server cert/key CSR and send to k8s API +cat <&2 + exit 1 +fi +echo ${serverCert} | openssl base64 -d -A -out ${certdir}/cert.pem + + +# create the secret with CA cert and server cert/key +kubectl create secret generic ${secret} \ + --from-file=key.pem=${certdir}/key.pem \ + --from-file=cert.pem=${certdir}/cert.pem \ + --dry-run -o yaml | + kubectl -n ${namespace} apply -f - diff --git a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay/questions.yml b/charts/citrix/citrix-cpx-istio-sidecar-injector/questions.yml similarity index 100% rename from packages/citrix-cpx-istio-sidecar-injector/generated-changes/overlay/questions.yml rename to charts/citrix/citrix-cpx-istio-sidecar-injector/questions.yml diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/_helpers.tpl b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/_helpers.tpl new file mode 100644 index 000000000..964b92cd5 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/_helpers.tpl @@ -0,0 +1,20 @@ +{{/* Below function is used to identify default value of jwtPolicy if not provided. + * For on-prem Kubernetes v1.21+, it is third-party-jwt. Else first-party-jwt. + * Note: Don't just do "helm template" to generate yaml file. Else https://github.com/helm/helm/issues/7991 + * is possible. Use "helm template --validate" or "helm install --dry-run --debug". + * Note2: For cloud environments, semverCompare should be ideally done with "<1.21.x-x" as + * Kubernetes version is generally of the format v1.20.7-eks-xxxxxx. So, it fails the "v1.21.x" check but that's fine + * as in cloud environments third-party-jwt is enabled. +*/}} + +{{- define "jwtValue" -}} +{{- if .Values.certProvider.jwtPolicy -}} +{{- printf .Values.certProvider.jwtPolicy -}} +{{- else -}} +{{- if semverCompare "<1.21.x" .Capabilities.KubeVersion.Version -}} +{{- printf "first-party-jwt" -}} +{{- else -}} +{{- printf "third-party-jwt" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-configmap.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-configmap.yaml new file mode 100644 index 000000000..56d0279ce --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-configmap.yaml @@ -0,0 +1,263 @@ +# This configmap stores the sidecar proxy info and arguments needed +apiVersion: v1 +kind: ConfigMap +metadata: + name: cpx-istio-sidecar-injector + namespace: {{.Release.Namespace}} + labels: + app: cpx-sidecar-injector + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + istio: sidecar-injector +data: + config: |- + policy: enabled + # If user does *NOT* want to inject sidecar on some pods based on label, + # then mention such labels in 'neverInjectSelector' entry. + # Note: This is valid only when istio's sidecar-injector image is running. + neverInjectSelector: + - matchExpressions: + - {key: citrix.com/no.sidecar, operator: Exists} + # Here, if pod has a label citrix.com/no.sidecar, then sidecar won't be injected for that pod. + template: |- + containers: + - name: istio-adaptor + image: {{ tpl .Values.xDSAdaptor.image . }} + imagePullPolicy: {{ .Values.xDSAdaptor.imagePullPolicy }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: APPLICATION_NAME + valueFrom: + fieldRef: + fieldPath: metadata.labels['app'] + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.serviceAccountName +{{- if .Values.certProvider.caAddr }} + - name: CA_ADDR + value: {{ .Values.certProvider.caAddr }}:{{ .Values.certProvider.caPort}} #istiod.istio-system.svc:15012 + - name: TRUST_DOMAIN + value: {{ .Values.certProvider.trustDomain }} #cluster.local + - name: CLUSTER_ID + value: {{ .Values.certProvider.clusterId }} #Kubernetes + - name: CERT_TTL_IN_HOURS + value: {{ .Values.certProvider.certTTLinHours }} + - name: JWT_POLICY + value: {{ include "jwtValue" . | quote }} # third-party-jwt if Kubernetes cluster supports third-party tokens +{{- end }} + - name: NS_USER + value: nsroot + - name: NS_PASSWORD + value: nsroot +{{- if eq .Values.coe.coeTracing true }} + - name: COE_TRACING + value: "TRUE" +{{- end }} + - name: ENABLE_LABELS_FEATURE + value: {{ .Values.cpxProxy.enableLabelsFeature | quote }} +{{- if eq .Values.xDSAdaptor.defaultSSLListenerOn443 true }} + - name: DEFAULT_SSL_LISTENER_ON_443 + value: "TRUE" +{{- end }} + - name: LOGLEVEL + value: {{ .Values.xDSAdaptor.logLevel | default "DEBUG" | quote }} +{{- if eq .Values.xDSAdaptor.jsonLog true }} + - name: JSONLOG + value: "TRUE" +{{- end }} + args: + - -ads-server +{{- if eq .Values.xDSAdaptor.secureConnect true }} + - {{ .Values.istioPilot.name}}.{{.Values.istioPilot.namespace }}.svc:{{ .Values.istioPilot.secureGrpcPort }} # istiod.istio-system.svc:15012 +{{- else }} + - {{ .Values.istioPilot.name}}.{{.Values.istioPilot.namespace }}.svc:{{ .Values.istioPilot.insecureGrpcPort }} # istiod.istio-system.svc:15010 +{{- end }} + - -ads-secure-connect={{ .Values.xDSAdaptor.secureConnect}} + - -ads-server-SAN + - {{ .Values.istioPilot.SAN }} + - -istio-proxy-type + - {{ .Values.xDSAdaptor.proxyType | default "sidecar" | quote }} + - -citrix-adc + - "{{- .Values.cpxProxy.netscalerUrl }}:{{- .Values.cpxProxy.mgmtHttpPort | toString }}" + - -citrix-adc-password + - "/var/deviceinfo/random_id" +{{- if .Values.ADMSettings.ADMIP }} + - -citrix-adm + - {{ .Values.ADMSettings.ADMIP }} +{{- end }} +{{- if .Values.cpxProxy.cpxLicenseAggregator }} + - -citrix-license-server + - {{ .Values.cpxProxy.cpxLicenseAggregator }} +{{- else if .Values.ADMSettings.licenseServerIP }} + - -citrix-license-server + - {{ .Values.ADMSettings.licenseServerIP }} +{{- end }} +{{- if .Values.coe.coeURL }} + - -coe + - {{ .Values.coe.coeURL }} +{{- end }} + volumeMounts: + - mountPath: /var/deviceinfo + name: cpx-pwd +{{- $jwtpolicy := include "jwtValue" . }} +{{- if eq $jwtpolicy "third-party-jwt" }} + - mountPath: /var/run/secrets/tokens + name: istio-token +{{- end }} + - mountPath: /etc/nslogin + name: nslogin + readOnly: true + - name: certs + mountPath: /etc/certs + - name: istiod-ca-cert + mountPath: /etc/rootcert/ + - name: podinfo + mountPath: /etc/podinfo + securityContext: + readOnlyRootFilesystem: true + runAsGroup: 32024 + runAsUser: 32024 # UID of xds-adaptor container's user + runAsNonRoot: true + - name: cpx-proxy + image: {{ tpl .Values.cpxProxy.image . }} + imagePullPolicy: IfNotPresent + securityContext: + privileged: true + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +{{- if .Values.cpxProxy.cpxLicenseAggregator }} + - name: "CLA" + value: "{{ .Values.cpxProxy.cpxLicenseAggregator }}" +{{- else if .Values.ADMSettings.licenseServerIP }} + - name: "LS_IP" + value: {{ .Values.ADMSettings.licenseServerIP }} + - name: "LS_PORT" + value: {{ .Values.ADMSettings.licenseServerPort }} +{{- end}} + - name: "EULA" + value: "{{ .Values.cpxProxy.EULA }}" + - name: "CPX_SIDECAR_MODE" + value: {{ .Values.cpxProxy.cpxSidecarMode | quote }} + - name: "CPX_DISABLE_PROBE" + value: "{{ .Values.cpxProxy.cpxDisableProbe }}" + - name: "MGMT_HTTP_PORT" + value: {{ .Values.cpxProxy.mgmtHttpPort | quote }} + - name: "MGMT_HTTPS_PORT" + value: {{ .Values.cpxProxy.mgmtHttpsPort | quote }} + - name: "KUBERNETES_TASK_ID" + value: "" + - name: "NS_CPX_LITE" + value: 1 +{{- if or .Values.coe.coeURL .Values.ADMSettings.ADMIP }} + - name: "NS_ENABLE_NEWNSLOG" + value: 1 +{{- end }} +{{- if .Values.ADMSettings.ADMIP }} + - name: "NS_MGMT_SERVER" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "NS_HTTP_PORT" + value: {{ .Values.cpxProxy.mgmtHttpPort | quote }} + - name: "NS_HTTPS_PORT" + value: {{ .Values.cpxProxy.mgmtHttpsPort | quote }} + - name: "ANALYTICS_SERVER" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "ANALYTICS_SERVER_PORT" + value: {{.Values.ADMSettings.analyticsServerPort | quote }} +{{- end }} + - name: "LOGSTREAM_COLLECTOR_IP" + value: {{ .Values.ADMSettings.ADMIP | default "" | quote }} +{{- if and ( or ( .Values.ADMSettings.licenseServerIP ) ( .Values.cpxProxy.cpxLicenseAggregator ) ) ( eq .Values.ADMSettings.bandWidthLicense true ) }} + - name: "BANDWIDTH" #Need to set env var BANDWIDTH in order to provide Bandwidth license to Citrix ADC CPX from ADM or CPX License Aggregator + value: {{ .Values.ADMSettings.bandWidth | quote }} + - name: "EDITION" + value: {{ .Values.ADMSettings.licenseEdition | quote }} +{{- end }} +{{- if or (.Values.ADMSettings.ADMIP) (.Values.ADMSettings.licenseServerIP) }} + - name: NS_MGMT_USER + valueFrom: + secretKeyRef: + name: admlogin + key: username + - name: NS_MGMT_PASS + valueFrom: + secretKeyRef: + name: admlogin + key: password +{{- end }} + volumeMounts: + - mountPath: /cpx/conf/ + name: cpx-conf + - mountPath: /var/deviceinfo + name: cpx-pwd + - mountPath: /cpx/crash/ + name: cpx-crash + volumes: + - name: cpx-conf + emptyDir: {} + - name: cpx-pwd + emptyDir: {} + - name: cpx-crash + emptyDir: {} + - name: nslogin + secret: + optional: true + secretName: nslogin + - name: certs + emptyDir: {} +{{- $jwtpolicy := include "jwtValue" . }} +{{- if eq $jwtpolicy "third-party-jwt" }} + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: istio-ca + expirationSeconds: 43200 + path: istio-token +{{- end }} + - name: istiod-ca-cert + configMap: + defaultMode: 0777 + name: istio-ca-root-cert + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + values: |- + { + "global": { + "jwtPolicy": "third-party-jwt", + }, + "adcSelector": { + "adc": "citrix", + } + } +--- diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-deployment-service.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-deployment-service.yaml new file mode 100644 index 000000000..173660786 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-deployment-service.yaml @@ -0,0 +1,114 @@ +apiVersion: v1 +kind: Service +metadata: + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + istio: sidecar-injector + app: cpx-sidecar-injector +spec: + ports: + - port: 443 + selector: + istio: sidecar-injector + +--- +# Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecarInjectorWebhook + istio: sidecar-injector + app: cpx-sidecar-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app: cpx-sidecar-injector + istio: sidecar-injector + template: + metadata: + labels: + istio: sidecar-injector + app: cpx-sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + spec: + serviceAccountName: cpx-sidecar-injector-service-account + initContainers: + - name: sidecar-certs-generator + image: {{ tpl .Values.sidecarCertsGenerator.image . }} + imagePullPolicy: {{ .Values.sidecarCertsGenerator.imagePullPolicy }} + securityContext: + privileged: true + volumeMounts: + - name: certs + mountPath: /tmp + containers: + - name: sidecar-injector-webhook + image: {{ tpl .Values.sidecarWebHook.webhookImage . }} + imagePullPolicy: {{ .Values.sidecarWebHook.imagePullPolicy }} + securityContext: + privileged: true + args: + - --caCertFile=/etc/istio/certs/cert.pem + - --tlsCertFile=/etc/istio/certs/cert.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=10s + - --webhookConfigName=cpx-sidecar-injector + - --webhookName=cpx-sidecar-injector.citrix.io + - --objectWebhookName=object.cpx-sidecar-injector.citrix.io + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - cat + - /health + failureThreshold: 5 + initialDelaySeconds: 4 + periodSeconds: 10 + readinessProbe: + exec: + command: + - cat + - /health + failureThreshold: 5 + initialDelaySeconds: 4 + periodSeconds: 10 + initialDelaySeconds: 4 + resources: + requests: + cpu: 10m + + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + emptyDir: {} + - name: inject-config + configMap: + name: cpx-istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values +--- diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-istioConfigMap.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-istioConfigMap.yaml new file mode 100644 index 000000000..8d7e8f708 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-istioConfigMap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: {{ .Release.Namespace }} + labels: + app: cpx-sidecar-injector + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + istio: sidecar-injector +data: + mesh: |- + # Needed for injection of securityContext in PodSpec during auto-sidecar injection + sdsUdsPath: unix:/etc/istio/proxy/SDS + +--- diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-serviceaccount.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-serviceaccount.yaml new file mode 100644 index 000000000..161998c6c --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-injector-serviceaccount.yaml @@ -0,0 +1,48 @@ +# Serviceaccount +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cpx-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} + labels: + app: cpx-sidecar-injector + +--- +# ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cpx-sidecar-injector-istio-system + labels: + app: cpx-sidecar-injector +rules: +- apiGroups: ["*"] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] +- apiGroups: ["certificates.k8s.io"] + resources: ["certificatesigningrequests", "certificatesigningrequests/approval"] + verbs: ["get", "list", "create", "watch", "delete", "update"] +- apiGroups: ["certificates.k8s.io"] + resources: ["signers"] + resourceNames: ["kubernetes.io/legacy-unknown", "kubernetes.io/kubelet-serving"] + verbs: ["get", "list", "create", "watch", "delete", "update", "approve"] +--- +# ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cpx-sidecar-injector-admin-role-binding-istio-system + labels: + app: cpx-sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cpx-sidecar-injector-istio-system +subjects: + - kind: ServiceAccount + name: cpx-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-networkpolicy.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-networkpolicy.yaml new file mode 100644 index 000000000..83234a10d --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/cpx-sidecar-networkpolicy.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + app: cpx-sidecar-injector + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} +spec: + ingress: + - {} + podSelector: + matchLabels: + app: cpx-sidecar-injector + policyTypes: + - Ingress diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/mutatingwebhook.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/mutatingwebhook.yaml new file mode 100644 index 000000000..8924ec6e8 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/templates/mutatingwebhook.yaml @@ -0,0 +1,57 @@ +# Mutating wehbook is used to perform sidecar injection. +# It calls sidecar-injector-service when the label is matched. +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: cpx-sidecar-injector + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} +webhooks: + - name: cpx-sidecar-injector.citrix.io + admissionReviewVersions: + - v1 + clientConfig: + service: + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + scope: "*" + sideEffects: None + failurePolicy: Fail + namespaceSelector: + matchLabels: +{{- if .Values.webhook.injectionLabelName }} + {{ .Values.webhook.injectionLabelName }}: enabled +{{- else }} + cpx-injection: enabled +{{- end }} + - name: object.cpx-sidecar-injector.citrix.io + admissionReviewVersions: + - v1 + clientConfig: + service: + name: cpx-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + scope: "*" + sideEffects: None + failurePolicy: Fail + objectSelector: + matchLabels: + sidecar.citrix.io/inject: "true" +--- diff --git a/charts/citrix/citrix-cpx-istio-sidecar-injector/values.yaml b/charts/citrix/citrix-cpx-istio-sidecar-injector/values.yaml new file mode 100644 index 000000000..6840785a5 --- /dev/null +++ b/charts/citrix/citrix-cpx-istio-sidecar-injector/values.yaml @@ -0,0 +1,77 @@ +# Default values for cpx-istio. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +xDSAdaptor: + imageRegistry: quay.io + imageRepository: citrix/citrix-xds-adaptor + imageTag: 0.10.3 + image: "{{ .Values.xDSAdaptor.imageRegistry }}/{{ .Values.xDSAdaptor.imageRepository }}:{{ .Values.xDSAdaptor.imageTag }}" + imagePullPolicy: IfNotPresent + proxyType: sidecar + secureConnect: true + logLevel: DEBUG + jsonLog: false + defaultSSLListenerOn443: true + +coe: + coeURL: + coeTracing: false + +istioPilot: + name: istiod + namespace: istio-system + secureGrpcPort: 15012 + insecureGrpcPort: 15010 + SAN: #"spiffe://cluster.local/ns/istio-system/sa/istiod-service-account" + +certProvider: + caAddr: istiod.istio-system.svc + caPort: 15012 + trustDomain: cluster.local + certTTLinHours: 720 + clusterId: Kubernetes + jwtPolicy: #specify third-party-jwt if Kubernetes cluster supports third-party tokens + +cpxProxy: + netscalerUrl: "http://127.0.0.1" + imageRegistry: quay.io + imageRepository: citrix/citrix-k8s-cpx-ingress + imageTag: 13.1-30.52 + image: "{{ .Values.cpxProxy.imageRegistry }}/{{ .Values.cpxProxy.imageRepository }}:{{ .Values.cpxProxy.imageTag }}" + imagePullPolicy: IfNotPresent + EULA: NO + cpxSidecarMode: YES + mgmtHttpPort: 10080 + mgmtHttpsPort: 10443 + cpxDisableProbe: "YES" + cpxLicenseAggregator: + enableLabelsFeature: FALSE + #licenseServerIP: this value is taken from ADMSettings.ADMIP + +sidecarWebHook: + webhookImageRegistry: quay.io + webhookImageRepository: citrix/cpx-istio-sidecar-injector + webhookImageTag: 1.3.0 + webhookImage: "{{ .Values.sidecarWebHook.webhookImageRegistry }}/{{ .Values.sidecarWebHook.webhookImageRepository }}:{{ .Values.sidecarWebHook.webhookImageTag }}" + imagePullPolicy: IfNotPresent + +sidecarCertsGenerator: + imageRegistry: quay.io + imageRepository: citrix/cpx-sidecar-injector-certgen + imageTag: 1.2.0 + image: "{{ .Values.sidecarCertsGenerator.imageRegistry }}/{{ .Values.sidecarCertsGenerator.imageRepository }}:{{ .Values.sidecarCertsGenerator.imageTag }}" + imagePullPolicy: IfNotPresent + +ADMSettings: + ADMIP: + licenseServerIP: + licenseServerPort: 27000 + bandWidthLicense: false + bandWidth: 1000 + analyticsServerPort: 5557 + licenseEdition: PLATINUM + +webhook: + injectionLabelName: cpx-injection + diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/Chart.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/Chart.yaml new file mode 100644 index 000000000..f3982c2a7 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/Chart.yaml @@ -0,0 +1,21 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Cpx with Ingress Controller + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-cpx-with-ingress-controller +apiVersion: v2 +appVersion: 1.27.15 +description: A Helm chart for Citrix ADC CPX with Citrix ingress Controller running + as sidecar. +home: https://www.citrix.com +icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png +kubeVersion: '>=v1.16.0-0' +maintainers: +- email: priyanka.sharma@citrix.com + name: priyankash-citrix +- email: subash.dangol@citrix.com + name: subashd +name: citrix-cpx-with-ingress-controller +sources: +- https://github.com/citrix/citrix-k8s-ingress-controller +version: 1.27.15 diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/README.md b/charts/citrix/citrix-cpx-with-ingress-controller/README.md new file mode 100644 index 000000000..67d34a394 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/README.md @@ -0,0 +1,572 @@ +# Citrix ADC CPX with Citrix Ingress Controller running as sidecar. + +In a [Kubernetes](https://kubernetes.io/) or [OpenShift](https://www.openshift.com) cluster, you can deploy [Citrix ADC CPX](https://docs.citrix.com/en-us/citrix-adc-cpx) with Citrix ingress controller as a [sidecar](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/). The Citrix ADC CPX instance is used for load balancing the North-South traffic to the microservices in your cluster. And, the sidecar Citrix ingress controller configures the Citrix ADC CPX. + +## TL;DR; + +### For Kubernetes + ``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes + ``` + + To install Citrix Provided Custom Resource Definition(CRDs) along with Citrix Ingress Controller + ``` + helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,crds.install=true + ``` + +### For OpenShift + + ``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,openshift=true + ``` + + To install Citrix Provided Custom Resource Definition(CRDs) along with Citrix Ingress Controller + ``` + helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,openshift=true,crds.install=true + ``` + +> **Important:** +> +> The "license.accept" is a mandatory argument and should be set to "yes" to accept the terms of the Citrix license. + + +## Introduction +This Helm chart deploys a Citrix ADC CPX with Citrix ingress controller as a sidecar in the [Kubernetes](https://kubernetes.io/) or in the [Openshift](https://www.openshift.com) cluster using the [Helm](https://helm.sh/) package manager. + +### Prerequisites + +- The [Kubernetes](https://kubernetes.io/) version should be 1.16 and above if using Kubernetes environment. +- The [Openshift](https://www.openshift.com) version 4.8 or later if using OpenShift platform. +- The [Helm](https://helm.sh/) version 3.x or later. You can follow instruction given [here](https://github.com/citrix/citrix-helm-charts/blob/master/Helm_Installation_version_3.md) to install the same. +- You have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator), if you want to view the metrics of the Citrix ADC CPX collected by the [metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics). +- Registration of Citrix ADC CPX in ADM: You may want to register your CPX in ADM for licensing or to obtain [servicegraph](https://docs.citrix.com/en-us/citrix-application-delivery-management-service/application-analytics-and-management/service-graph.html). For this you will have to create a Kubernetes secret using ADM credentials and provide it while install the chart. Create a Kubernetes secret for the user name and password using the following command: + + ``` + kubectl create secret generic admlogin --from-literal=username= --from-literal=password= -n citrix-system + ``` + +## Installing the Chart +Add the Citrix Ingress Controller helm chart repository using command: + + ``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + ``` + +### For Kubernetes: +#### 1. Citrix ADC CPX with Citrix Ingress Controller running as side car. +To install the chart with the release name ``` my-release```: + + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,ingressClass[0]= + ``` + +> **Note:** +> +> By default the chart installs the recommended [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and role bindings. + +The command deploys Citrix ADC CPX with Citrix ingress controller as a sidecar on the Kubernetes cluster with the default configuration. The [configuration](#configuration) section lists the mandatory and optional parameters that you can configure during installation. + +#### 2. Citrix ADC CPX with Citrix Ingress Controller and Exporter running as side car. +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed as sidecar to the Citrix ADC CPX and collects metrics from the Citrix ADC CPX instance. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. +> **Note:** +> +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator). + +Use the following command for this: + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,ingressClass[0]=,exporter.required=true + ``` + +### For OpenShift: +Add the name of the service account created when the chart is deployed to the privileged Security Context Constraints of OpenShift: + + ``` + oc adm policy add-scc-to-user privileged system:serviceaccount:: + ``` + +#### 1. Citrix ADC CPX with Citrix Ingress Controller running as side car. +To install the chart with the release name, `my-release`, use the following command: + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,openshift=true + ``` + +#### 2. Citrix ADC CPX with Citrix Ingress Controller and Exporter running as side car. +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed as sidecar to the Citrix ADC CPX and collects metrics from the Citrix ADC CPX instance. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. +> **Note:** +> +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator). + +Use the following command for this: + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,openshift=true,exporter.required=true + ``` + +### Installed components + +The following components are installed: + +- [Citrix ADC CPX](https://docs.citrix.com/en-us/citrix-adc-cpx/netscaler-cpx.html) +- [Citrix ingress controller](https://github.com/citrix/citrix-k8s-ingress-controller) (if enabled) +- [Exporter](https://github.com/citrix/citrix-adc-metrics-exporter) (if enabled) + + +### Citrix ADC CPX Service Annotations: + + The parameter `serviceAnnotations` can be used to annotate CPX service while installing Citrix ADC CPX using this helm chart. + For example, if CPX is getting deployed in Azure and an Azure Internal Load Balancer is required before CPX then the annotation `service.beta.kubernetes.io/azure-load-balancer-internal:True` can be set in CPX service using Helm command: + + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,serviceAnnotations.service\\.beta\\.kubernetes\\.io/azure-load-balancer-internal=True + ``` + + or the same can be provided in [values.yaml](https://github.com/citrix/citrix-helm-charts/blob/master/citrix-cpx-with-ingress-controller/values.yaml): + + ``` + license: + accept: yes + serviceAnnotations: + service.beta.kubernetes.io/azure-load-balancer-internal: True + ``` + + which can be used to install Citrix ADC CPX using Helm command: + + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller -f values.yaml + ``` + + To know more about service annotations supported by Kubernetes on various platforms please see [this](https://kubernetes.io/docs/concepts/services-networking/service/). + +### Citrix ADC CPX Service Ports: + + By default, port 80 and 443 of CPX service will exposed when CPX is installed using this helm chart. If it is required to expose any other ports in CPX service then the parameter `servicePorts` can be used for it. + For example, if port 9999 is required to be exposed then below helm command can be used for installing Citrix ADC CPX: + + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,servicePorts[0].port=9999,servicePorts[0].protocol=TCP,servicePorts[0].name=https + ``` + + or the same can be provided in [values.yaml](https://github.com/citrix/citrix-helm-charts/blob/master/citrix-cpx-with-ingress-controller/values.yaml): + + ``` + license: + accept: yes + servicePorts: + - port: 9090 + protocol: TCP + name: https + ``` + + which can be used to install Citrix ADC using Helm command: + + ``` + helm install my-release citrix/citrix-cpx-with-ingress-controller -f values.yaml + ``` + +> **Note:** If `servicePorts` parameters is used, only ports provided in this parameter will be exposed in CPX service. +> If you want to expose default ports 80 or 443, then you will need to explicity mention these also in this parameter. + +### Configuration for ServiceGraph: + If Citrix ADC CPX need to send data to the Citrix ADM to bring up the servicegraph, then the below steps can be followed to install Citrix ADC CPX with ingress controller. Citrix ingress controller configures Citrix ADC CPX with the configuration required for servicegraph. + + 1. Create secret using Citrix ADC Agent credentials, which will be used by Citrix ADC CPX to communicate with Citrix ADM Agent: + + kubectl create secret generic admlogin --from-literal=username= --from-literal=password= + + 2. Deploy Citrix ADC CPX with Citrix ingress controller using helm command: + + helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,analyticsConfig.required=true,analyticsConfig.timeseries.metrics.enable=true,analyticsConfig.distributedTracing.enable=true,analyticsConfig.endpoint.server=,ADMSettings.ADMIP=,ADMSettings.loginSecret= + +> **Note:** +> If container agent is being used here for Citrix ADM, please provide `svcIP` of container agent in the `analyticsConfig.endpoint.server` parameter. + +## Citrix ADC CPX DaemonSet with Citrix Ingress Controller as sidecar for BGP Advertisement + + The previous section of deploying CPX as a Deployment requires a Tier-1 Loadbalancer such as Citrix VPX or cloud loadbalancers to route the traffic to CPX instances running in Kubernetes cluster, but you can also leverage BGP network fabric in your on-prem environemnt to route the traffic to CPX instances in a Kubernetes or Openshift cluster. you need to deploy CPX with Citrix Ingress Controller as Daemonset to advertise the ExternalIPs of the K8s services of type LoadBalancer to your BGP Fabric. Citrix ADC CPX establishes a BGP peering session with your network routers, and uses that peering session to advertise the IP addresses of external cluster services. If your routers have ECMP capability, the traffic is load-balanced to multiple CPX instances by the upstream router, which in turn load-balances to actual application pods. When you deploy the Citrix ADC CPX with this mode, Citrix ADC CPX adds iptables rules for each service of type LoadBalancer on Kubernetes nodes. The traffic destined to the external IP address is routed to Citrix ADC CPX pods. You can also set the 'ingressIP' variable to an IP Address to advertise the External IP address for Ingress resources. Refer [documentation](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/network/cpx-bgp-router.md) for complete details about BGP advertisement with CPX. + +### Download the chart +You can download the chart usimg `helm pull` command. +``` +helm repo add citrix https://citrix.github.io/citrix-helm-charts/ +helm pull citrix/citrix-cpx-with-ingress-controller +tar -zxvf citrix-cpx-with-ingress-controller-x.y.z.tgz +``` + +### Edit the BGP configuration in values.yaml +BGP configurations enables CPX to peer with neighbor routers for advertisting the routes for Service of Type LoadBalancer. Citrix Ingress Controllers uses static IPs given in Service YAML or using an IPAM controller to allocate an External IP address, and same is advertisted to the neighbour router with the Gateway as Node IP. An example BGP configurations is given below. + +``` +# BGP configurations: local AS, remote AS and remote address is mandatory to provide. +bgpSettings: + required: true + bgpConfig: + - bgpRouter: + # Local AS number for BGP advertisement + localAS: + neighbor: + # Address of the nighbor router for BGP advertisement + - address: xx.xx.xx.xx + # Remote AS number + remoteAS: + advertisementInterval: 10 + ASOriginationInterval: 10 +``` +If the cluster spawns across multiple networks, you can also specify the NodeSelector to give different neighbors for different Cluster Nodes as shown below. + +``` +bgpSettings: + required: true + bgpConfig: + - nodeSelector: datacenter=ds1 + bgpRouter: + localAS: + neighbor: + - address: xx.xx.xx.xx + remoteAS: + advertisementInterval: 10 + ASOriginationInterval: 10 + - nodeSelector: datacenter=ds2 + bgpRouter: + localAS: + neighbor: + - address: yy.yy.yy.yy + remoteAS: + advertisementInterval: 10 + ASOriginationInterval: 10 +``` + +### Deploy the chart +#### For Kubernetes: +#### 1. Citrix ADC CPX DaemonSet with Citrix Ingress Controller running as side car for BGP Advertisement. + + +To install the chart with the release name ``` my-release```: + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true + ``` +If you are running Citrix IPAM for auto allocation of IPs for Service of type LoadBalancer, you must enable the IPAM configurations in Citrix Ingress Controller as show below: + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ipam=true + ``` +If you are using ingress resources, you must set the `ingressIP` to a valid IP Address which will enable the BGP route advertisement for this IP when ingress resource is deployed. + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ingressIP= + ``` + +> **Note:** +> +> By default the chart installs the recommended [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and role bindings. + +The command deploys Citrix ADC CPX Daemonset with Citrix ingress controller as a sidecar on the Kubernetes cluster with the default configuration. The [configuration](#configuration) section lists the mandatory and optional parameters that you can configure during installation. + +#### 2. Citrix ADC CPX with Citrix Ingress Controller and Exporter running as side car for BGP Advertisement. +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed as sidecar to the Citrix ADC CPX and collects metrics from the Citrix ADC CPX instance. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. +> **Note:** +> +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator). + +Use the following command for this: + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,exporter.required=true + ``` +If you are running Citrix IPAM controller for auto allocation of IPs for Service of type LoadBalancer, you must enable the IPAM configurations in Citrix Ingress Controller as show below: + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ipam=true,exporter.required=true + ``` +If you are using ingress resources, you must set the `ingressIP` to a valid IP Address which will enable the BGP route advertisement for this IP when ingress resource is deployed. + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ingressIP=, exporter.required=true + ``` + +#### For OpenShift: +Add the name of the service account created when the chart is deployed to the privileged Security Context Constraints of OpenShift: + + ``` + oc adm policy add-scc-to-user privileged system:serviceaccount:: + ``` + +#### 1. Citrix ADC CPX DaemonSet with Citrix Ingress Controller running as side car for BGP Advertisement. +To install the chart with the release name, `my-release`, use the following command: + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,openshift=true + ``` +If you are running Citrix IPAM controller for auto allocation of IPs for Service of type LoadBalancer, you must enable the IPAM configurations in Citrix Ingress Controller as show below: + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ipam=true,openshift=true + ``` + + If you are using ingress or Route resources, you must set the `ingressIP` to a valid IP Address which will enable the BGP route advertisement for this IP when ingress resource is deployed. + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ingressIP=,openshift=true + ``` + +#### 2. Citrix ADC CPX with Citrix Ingress Controller and Exporter running as side car for BGP Advertisement. +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed as sidecar to the Citrix ADC CPX and collects metrics from the Citrix ADC CPX instance. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. +> **Note:** +> +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator). + +Use the following command for this: + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,openshift=true,openshift=true,exporter.required=true + ``` +If you are running Citrix IPAM controller for auto allocation of IPs for Service of type LoadBalancer, you must enable the IPAM configurations in Citrix Ingress Controller as show below: + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ipam=true,openshift=true,exporter.required=true + ``` + +If you are using ingress or Route resources, you must set the `ingressIP` to a valid IP Address which will enable the BGP route advertisement for this IP when ingress resource is deployed. + + ``` + helm install my-release ./citrix-cpx-with-ingress-controller --set license.accept=yes,cpxBgpRouter=true,ingressIP=,openshift=true,exporter.required=true + ``` + +## CRDs configuration + +CRDs can be installed/upgraded when we install/upgrade Citrix ADC CPX with Citrix ingress controller using `crds.install=true` parameter in Helm. If you do not want to install CRDs, then set the option `crds.install` to `false`. By default, CRDs too get deleted if you uninstall through Helm. This means, even the CustomResource objects created by the customer will get deleted. If you want to avoid this data loss set `crds.retainOnDelete` to `true`. + +> **Note:** +> Installing again may fail due to the presence of CRDs. Make sure that you back up all CustomResource objects and clean up CRDs before re-installing Citrix ADC CPX with Citrix ingress controller. + +There are a few examples of how to use these CRDs, which are placed in the folder: [Example-CRDs](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds). Refer to them and install as needed, using the following command: +```kubectl create -f ``` + +### Details of the supported CRDs: + +#### authpolicies CRD: + +Authentication policies are used to enforce access restrictions to resources hosted by an application or an API server. + +Citrix provides a Kubernetes CustomResourceDefinitions (CRDs) called the [Auth CRD](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/auth) that you can use with the Citrix ingress controller to define authentication policies on the ingress Citrix ADC. + +Example file: [auth_example.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/auth_example.yaml) + +#### continuousdeployments CRD for canary: + +Canary release is a technique to reduce the risk of introducing a new software version in production by first rolling out the change to a small subset of users. After user validation, the application is rolled out to the larger set of users. Citrix ADC-Integrated [Canary Deployment solution](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/canary) stitches together all components of continuous delivery (CD) and makes canary deployment easier for the application developers. + +#### httproutes and listeners CRDs for contentrouting: + +[Content Routing (CR)](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/contentrouting) is the execution of defined rules that determine the placement and configuration of network traffic between users and web applications, based on the content being sent. For example, a pattern in the URL or header fields of the request. + +Example files: [HTTPRoute_crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/HTTPRoute_crd.yaml), [Listener_crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/Listener_crd.yaml) + +#### ratelimits CRD: + +In a Kubernetes deployment, you can [rate limit the requests](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/ratelimit) to the resources on the back end server or services using rate limiting feature provided by the ingress Citrix ADC. + +Example files: [ratelimit-example1.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/ratelimit-example1.yaml), [ratelimit-example2.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/ratelimit-example2.yaml) + +#### vips CRD: + +Citrix provides a CustomResourceDefinitions (CRD) called [VIP](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/vip) for asynchronous communication between the IPAM controller and Citrix ingress controller. + +The IPAM controller is provided by Citrix for IP address management. It allocates IP address to the service from a defined IP address range. The Citrix ingress controller configures the IP address allocated to the service as virtual IP (VIP) in Citrix ADX VPX. And, the service is exposed using the IP address. + +When a new service is created, the Citrix ingress controller creates a CRD object for the service with an empty IP address field. The IPAM Controller listens to addition, deletion, or modification of the CRD and updates it with an IP address to the CRD. Once the CRD object is updated, the Citrix ingress controller automatically configures Citrix ADC-specfic configuration in the tier-1 Citrix ADC VPX. + +#### rewritepolicies CRD: + +In kubernetes environment, to deploy specific layer 7 policies to handle scenarios such as, redirecting HTTP traffic to a specific URL, blocking a set of IP addresses to mitigate DDoS attacks, imposing HTTP to HTTPS and so on, requires you to add appropriate libraries within the microservices and manually configure the policies. Instead, you can use the [Rewrite and Responder features](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/crd/rewrite-responder-policies-deployment.yaml) provided by the Ingress Citrix ADC device to deploy these policies. + +Example files: [target-url-rewrite.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/target-url-rewrite.yaml) + +#### wafs CRD: + +[WAF CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/waf.md) can be used to configure the web application firewall policies with the Citrix ingress controller on the Citrix ADC VPX, MPX, SDX, and CPX. The WAF CRD enables communication between the Citrix ingress controller and Citrix ADC for enforcing web application firewall policies. + +In a Kubernetes deployment, you can enforce a web application firewall policy to protect the server using the WAF CRD. For more information about web application firewall, see [Web application security](https://docs.citrix.com/en-us/citrix-adc/13/application-firewall/introduction/web-application-security.html). + +Example files: [wafhtmlxsssql.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/wafhtmlxsssql.yaml) + +#### CORS CRD: + +[CORS CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/cors.md) Cross-origin resource sharing (CORS) is a mechanism allows a web application running under one domain to securely access resources in another domain. You can configure CORS policies on Citrix ADC using Citrix ingress controller to allow one domain (the origin domain) to call APIs in another domain. For more information, see the [cross-origin resource sharing CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/cors.md) documentation. + +Example files: [cors-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/corspolicy-example.yaml) + +#### APPQOE CRD: + +[APPQOE CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/appqoe.md) When a Citrix ADC appliance receives an HTTP request and forwards it to a back-end server, sometimes there may be connection failures with the back-end server. You can configure the request-retry feature on Citrix ADC to forward the request to the next available server, instead of sending the reset to the client. Hence, the client saves round trip time when Citrix ADC initiates the same request to the next available service. +For more information, see the AppQoE support documentation. [Appqoe resource sharing CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/appqoe.md) documentation. + +Example files: [appqoe-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/appqoe_example.yaml) + +#### WILDCARDDNS CRD: + +[WILDCARDDNS CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/wildcarddns.md) Wildcard DNS domains are used to handle requests for nonexistent domains and subdomains. In a zone, use wildcard domains to redirect queries for all nonexistent domains or subdomains to a particular server, instead of creating a separate Resource Record (RR) for each domain. The most common use of a wildcard DNS domain is to create a zone that can be used to forward mail from the internet to some other mail system. +For more information, see the Wild card DNS domains support documentation. [Wildcard DNS Entry CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/wildcarddns.md) documentation. + +Example files: [wildcarddns-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/wildcarddns-example.yaml) + +## Citrix ADC CPX servicetype LoadBalancer +Citrix ADC CPX can be installed with service having servicetype LoadBalancer. Following arguments can be used in the `helm install` command for the same: + +``` +helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,serviceType.loadBalancer.enabled=True +``` + +## Citrix ADC CPX servicetype NodePort +Citrix ADC CPX can be installed with service having servicetype Nodeport. Following arguments can be used in the `helm install` command for the same: + +``` +helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,serviceType.nodePort.enabled=True +``` + +Additionally, `serviceType.nodePort.httpPort` and `serviceType.nodePort.httpsPort` arguments can be used to select the nodePort for the CPX service for HTTP and HTTPS ports. + +### Tolerations + +Taints are applied on cluster nodes whereas tolerations are applied on pods. Tolerations enable pods to be scheduled on node with matching taints. For more information see [Taints and Tolerations in Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + +Toleration can be applied to pod running Citrix ADC CPX and ingress controller containers using `tolerations` argument while deploying CPX+CIC using helm chart. This argument takes list of tolerations that user need to apply on the CPX+CIC pods. + +For example, following command can be used to apply toleration on the CPX+CIC pod: + +``` +helm install my-release citrix/citrix-cpx-with-ingress-controller --set license.accept=yes,tolerations[0].key=,tolerations[0].value=,tolerations[0].operator=,tolerations[0].effect= +``` + +Here tolerations[0].key, tolerations[0].value and tolerations[0].effect are the key, value and effect that was used while tainting the node. +Effect represents what should happen to the pod if the pod don't have any matching toleration. It can have values `NoSchedule`, `NoExecute` and `PreferNoSchedule`. +Operator represents the operation to be used for key and value comparison between taint and tolerations. It can have values `Exists` and `Equal`. The default value for operator is `Equal`. + +## Configuration +The following table lists the configurable parameters of the Citrix ADC CPX with Citrix ingress controller as side car chart and their default values. + +| Parameters | Mandatory or Optional | Default value | Description | +| ---------- | --------------------- | ------------- | ----------- | +| license.accept | Mandatory | no | Set `yes` to accept the Citrix ingress controller end user license agreement. | +| imageRegistry | Mandatory | `quay.io` | The Citrix ADC CPX image registry | +| imageRepository | Mandatory | `citrix/citrix-k8s-cpx-ingress` | The Citrix ADC CPX image repository | +| imageTag | Mandatory | `13.1-30.52` | The Citrix ADC CPX image tag | +| pullPolicy | Mandatory | IfNotPresent | The Citrix ADC CPX image pull policy. | +| daemonSet | Optional | False | Set this to true if Citrix ADC CPX needs to be deployed as DaemonSet. | +| cic.imageRegistry | Mandatory | `quay.io` | The Citrix ingress controller image registry | +| cic.imageRepository | Mandatory | `citrix/citrix-k8s-ingress-controller` | The Citrix ingress controller image repository | +| cic.imageTag | Mandatory | `1.27.15` | The Citrix ingress controller image tag | +| cic.pullPolicy | Mandatory | IfNotPresent | The Citrix ingress controller image pull policy. | +| cic.required | Mandatory | true | CIC to be run as sidecar with Citrix ADC CPX | +| cic.resources | Optional | {} | CPU/Memory resource requests/limits for Citrix Ingress Controller container | +| imagePullSecrets | Optional | N/A | Provide list of Kubernetes secrets to be used for pulling the images from a private Docker registry or repository. For more information on how to create this secret please see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). | +| nameOverride | Optional | N/A | String to partially override deployment fullname template with a string (will prepend the release name) | +| fullNameOverride | Optional | N/A | String to fully override deployment fullname template with a string | +| resources | Optional | {} | CPU/Memory resource requests/limits for Citrix CPX container | +| nitroReadTimeout | Optional | 20 | The nitro Read timeout in seconds, defaults to 20 | +| logLevel | Optional | DEBUG | The loglevel to control the logs generated by CIC. The supported loglevels are: CRITICAL, ERROR, WARNING, INFO, DEBUG and TRACE. For more information, see [Logging](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/configure/log-levels.md).| +| jsonLog | Optional | false | Set this argument to true if log messages are required in JSON format | +| nsConfigDnsRec | Optional | false | To enable/disable DNS address Record addition in ADC through Ingress | +| nsSvcLbDnsRec | Optional | false | To enable/disable DNS address Record addition in ADC through Type Load Balancer Service | +| nsDnsNameserver | Optional | N/A | To add DNS Nameservers in ADC | +| optimizeEndpointBinding | Optional | false | To enable/disable binding of backend endpoints to servicegroup in a single API-call. Recommended when endpoints(pods) per application are large in number. Applicable only for Citrix ADC Version >=13.0-45.7 | +| defaultSSLCertSecret | Optional | N/A | Provide Kubernetes secret name that needs to be used as a default non-SNI certificate in Citrix ADC. | +| nsHTTP2ServerSide | Optional | OFF | Set this argument to `ON` for enabling HTTP2 for Citrix ADC service group configurations. | +| cpxLicenseAggregator | Optional | N/A | IP/FQDN of the CPX License Aggregator if it is being used to license the CPX. | +| nsCookieVersion | Optional | 0 | Specify the persistence cookie version (0 or 1). | +| logProxy | Optional | N/A | Provide Elasticsearch or Kafka or Zipkin endpoint for Citrix observability exporter. | +| nsProtocol | Optional | http | Protocol http or https used for the communication between Citrix Ingress Controller and CPX | +| cpxBgpRouter | Optional | false| If set to true, this CPX is deployed as daemonset in BGP controller mode wherein BGP advertisements are done for attracting external traffic to Kubernetes clusters | +| replicaCount | Optional | 1 | Number of CPX-CIC pods to be deployed. With `cpxBgpRouter : true`, replicaCount is 1 since CPX will be deployed as DaemonSet | +| nsIP | Optional | 192.168.1.2 | NSIP used by CPX for internal communication when run in Host mode, i.e when cpxBgpRouter is set to true. A /24 internal network is created in this IP range which is used for internal communications withing the network namespace. | +| nsGateway | Optional | 192.168.1.1 | Gateway used by CPX for internal communication when run in Host mode, i.e when cpxBgpRouter is set to true. If not specified, first IP in the nsIP network is used as gateway. It must be in same network as nsIP | +| bgpPort | Optional | 179 | BGP port used by CPX for BGP advertisement if cpxBgpRouter is set to true| +| ingressIP | Optional | N/A | External IP address to be used by ingress resources if not overriden by ingress.com/frontend-ip annotation in Ingress resources. This is also advertised to external routers when pxBgpRouter is set to true| +| entityPrefix | Optional | k8s | The prefix for the resources on the Citrix ADC CPX. | +| ingressClass | Optional | N/A | If multiple ingress load balancers are used to load balance different ingress resources. You can use this parameter to specify Citrix ingress controller to configure Citrix ADC associated with specific ingress class. For more information on Ingress class, see [Ingress class support](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/configure/ingress-classes/). For Kubernetes version >= 1.19, this will create an IngressClass object with the name specified here | +| setAsDefaultIngressClass | Optional | False | Set the IngressClass object as default. New Ingresses without an "ingressClassName" field specified will be assigned the class specified in ingressClass. Applicable only for kubernetes versions >= 1.19 | +| updateIngressStatus | Optional | False | Set this argument if you want to update ingress status of the ingress resources exposed via CPX. This is only applicable if servicetype of CPX service is LoadBalancer. | +| disableAPIServerCertVerify | Optional | False | Set this parameter to True for disabling API Server certificate verification. | +| openshift | Optional | false | Set this argument if OpenShift environment is being used. | +| disableOpenshiftRoutes | false | By default Openshift routes are processed in openshift environment, this variable can be used to disable Ingress controller processing the openshift routes. | +| routeLabels | Optional | N/A | You can use this parameter to provide the route labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster. | +| namespaceLabels | Optional | N/A | You can use this parameter to provide the namespace labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster. | +| sslCertManagedByAWS | Optional | False | Set this argument if SSL certs used is managed by AWS while deploying Citrix ADC CPX in AWS. | +| nodeSelector.key | Optional | N/A | Node label key to be used for nodeSelector option for CPX-CIC deployment. | +| nodeSelector.value | Optional | N/A | Node label value to be used for nodeSelector option in CPX-CIC deployment. | +| podAnnotations | Optional | N/A | Map of annotations to add to the pods. | +| affinity | Optional | N/A | Affinity labels for pod assignment. | +| tolerations | Optional | N/A | Specify the tolerations for the CPX-CIC deployment. | +| serviceType.loadBalancer.enabled | Optional | False | Set this argument if you want servicetype of CPX service to be LoadBalancer. | +| serviceType.nodePort.enabled | Optional | False | Set this argument if you want servicetype of CPX service to be NodePort. | +| serviceType.nodePort.httpPort | Optional | N/A | Specify the HTTP nodeport to be used for NodePort CPX service. | +| serviceType.nodePort.httpsPort | Optional | N/A | Specify the HTTPS nodeport to be used for NodePort CPX service. | +| serviceAnnotations | Optional | N/A | Dictionary of annotations to be used in CPX service. Key in this dictionary is the name of the annotation and Value is the required value of that annotation. For example, [see this](#citrix-adc-cpx-service-annotations). | +| serviceSpec.externalTrafficPolicy | Optional | Cluster | Use this parameter to provide externalTrafficPolicy for CPX service of type LoadBalancer or NodePort. `serviceType.loadBalancer.enabled` or `serviceType.nodePort.enabled` should be set to `true` according to your use case for using this parameter. | +| serviceSpec.loadBalancerIP | Optional | N/A | Use this parameter to provide LoadBalancer IP to CPX service of type LoadBalancer. `serviceType.loadBalancer.enabled` should be set to `true` for using this parameter. | +| serviceSpec.loadBalancerSourceRanges | Optional | N/A | Provide the list of IP Address or range which should be allowed to access the Network Load Balancer. `serviceType.loadBalancer.enabled` should be set to `true` for using this parameter. For details, see [Network Load Balancer support on AWS](https://kubernetes.io/docs/concepts/services-networking/service/#aws-nlb-support). | +| servicePorts | Optional | N/A | List of port. Each element in this list is a dictionary that contains information about the port. For example, [see this](#citrix-adc-cpx-service-ports). | +| ADMSettings.licenseServerIP | Optional | N/A | Provide the Citrix Application Delivery Management (ADM) IP address to license Citrix ADC CPX. For more information, see [Licensing](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/licensing/). | +| ADMSettings.licenseServerPort | Optional | 27000 | Citrix ADM port if non-default port is used. | +| ADMSettings.ADMIP | Optional | N/A | Citrix Application Delivery Management (ADM) IP address. | +| ADMSettings.loginSecret | Optional | N/A | The secret key to login to the ADM. For information on how to create the secret keys, see [Prerequisites](#prerequistes). | +| ADMSettings.bandWidthLicense | Optional | False | Set to true if you want to use bandwidth based licensing for Citrix ADC CPX. | +| ADMSettings.bandWidth | Optional | 1000 | Desired bandwidth capacity to be set for Citrix ADC CPX in Mbps. | +| ADMSettings.vCPULicense | Optional | N/A | Set to true if you want to use vCPU based licensing for Citrix ADC CPX. | +| ADMSettings.licenseEdition| Optional | PLATINUM | License edition that can be Standard, Platinum and Enterprise . By default, Platinum is selected.| +| ADMSettings.cpxCores | Optional | 1 | Desired number of vCPU to be set for Citrix ADC CPX. | +| ADMSettings.analyticsServerPort | Optional | 5557 | Port used for Analytics by ADM. Required to plot ServiceGraph. | +| exporter.required | Optional | false | Use the argument if you want to run the [Exporter for Citrix ADC Stats](https://github.com/citrix/citrix-adc-metrics-exporter) along with Citrix ingress controller to pull metrics for the Citrix ADC CPX| +| exporter.imageRegistry | Optional | `quay.io` | The Exporter for Citrix ADC Stats image registry | +| exporter.imageRepository | Optional | `citrix/citrix-adc-metrics-exporter` | The Exporter for Citrix ADC Stats image repository | +| exporter.imageTag | Optional | `1.4.9` | The Exporter for Citrix ADC Stats image tag | +| exporter.pullPolicy | Optional | IfNotPresent | The Exporter for Citrix ADC Stats image pull policy. | +| exporter.resources | Optional | {} | CPU/Memory resource requests/limits for Metrics exporter container | +| exporter.ports.containerPort | Optional | 8888 | The Exporter for Citrix ADC Stats container port. | +| analyticsConfig.required | Mandatory | false | Set this to true if you want to configure Citrix ADC to send metrics and transaction records to analytics service. | +| analyticsConfig.distributedTracing.enable | Optional | false | Set this value to true to enable OpenTracing in Citrix ADC. | +| analyticsConfig.distributedTracing.samplingrate | Optional | 100 | Specifies the OpenTracing sampling rate in percentage. | +| analyticsConfig.endpoint.server | Optional | N/A | Set this value as the IP address or DNS address of the analytics server. | +| analyticsConfig.endpoint.service | Optional | N/A | Set this value as the IP address or service name with namespace of the analytics service deployed in Kuberenetes. Format: namespace/servicename| +| analyticsConfig.timeseries.port | Optional | 5563 | Specify the port used to expose analytics service for timeseries endpoint. | +| analyticsConfig.timeseries.metrics.enable | Optional | Set this value to true to enable sending metrics from Citrix ADC. | +| analyticsConfig.timeseries.metrics.mode | Optional | avro | Specifies the mode of metric endpoint. | +| analyticsConfig.timeseries.auditlogs.enable | Optional | false | Set this value to true to export audit log data from Citrix ADC. | +| analyticsConfig.timeseries.events.enable | Optional | false | Set this value to true to export events from the Citrix ADC. | +| analyticsConfig.transactions.enable | Optional | false | Set this value to true to export transactions from Citrix ADC. | +| analyticsConfig.transactions.port | Optional | 5557 | Specify the port used to expose analytics service for transaction endpoint. | +| crds.install | Optional | False | Unset this argument if you don't want to install CustomResourceDefinitions which are consumed by CIC. | +| crds.retainOnDelete | Optional | false | Set this argument if you want to retain CustomResourceDefinitions even after uninstalling CIC. This will avoid data-loss of Custom Resource Objects created before uninstallation. | +| bgpSettings.required | Optional | false | Set this argument if you want to enable BGP configurations for exposing service of Type Loadbalancer through BGP fabric| +| bgpSettings.bgpConfig | Optional| N/A| This represents BGP configurations in YAML format. For the description about individual fields, please refer the [documentation](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/network/cpx-bgp-router.md) | +| nsLbHashAlgo.required | Optional | false | Set this value to set the LB consistent hashing Algorithm | +| nsLbHashAlgo.hashFingers | Optional |256 | Specifies the number of fingers to be used for hashing algorithm. Possible values are from 1 to 1024, Default value is 256 | +| nsLbHashAlgo.hashAlgorithm | Optional | 'default' | Specifies the supported algorithm. Supported algorithms are "default", "jarh", "prac", Default value is 'default' | + +> **Note:** +> +> If Citrix ADM related information is not provided during installation, Citrix ADC CPX will come up with the default license. + +Alternatively, you can define a YAML file with the values for the parameters and pass the values while installing the chart. + +For example: + ``` + helm install citrix-cpx-with-ingress-controller citrix/citrix-cpx-with-ingress-controller -f values.yaml + ``` + +> **Tip:** +> +> The [values.yaml](https://github.com/citrix/citrix-helm-charts/blob/master/citrix-cpx-with-ingress-controller/values.yaml) contains the default values of the parameters. + +## Uninstalling the Chart +To uninstall/delete the ```my-release``` deployment: + ``` + helm delete my-release + ``` + +## Related documentation + +- [Citrix ADC CPX Documentation](https://docs.citrix.com/en-us/citrix-adc-cpx/12-1/cpx-architecture-and-traffic-flow.html) +- [Citrix ingress controller Documentation](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/) +- [Citrix ingress controller GitHub](https://github.com/citrix/citrix-k8s-ingress-controller) +- [BGP advertisement for External IPs with CPX](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/network/cpx-bgp-router.md) diff --git a/packages/citrix-cpx-with-ingress-controller/generated-changes/overlay/app-readme.md b/charts/citrix/citrix-cpx-with-ingress-controller/app-readme.md similarity index 100% rename from packages/citrix-cpx-with-ingress-controller/generated-changes/overlay/app-readme.md rename to charts/citrix/citrix-cpx-with-ingress-controller/app-readme.md diff --git a/packages/citrix-cpx-with-ingress-controller/generated-changes/overlay/questions.yml b/charts/citrix/citrix-cpx-with-ingress-controller/questions.yml similarity index 100% rename from packages/citrix-cpx-with-ingress-controller/generated-changes/overlay/questions.yml rename to charts/citrix/citrix-cpx-with-ingress-controller/questions.yml diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/NOTES.txt b/charts/citrix/citrix-cpx-with-ingress-controller/templates/NOTES.txt new file mode 100644 index 000000000..bccfdf69a --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/NOTES.txt @@ -0,0 +1,14 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get {{ .Release.Name }} + + +To delete : + helm delete {{ .Release.Name }} + diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/_helpers.tpl b/charts/citrix/citrix-cpx-with-ingress-controller/templates/_helpers.tpl new file mode 100644 index 000000000..92e636ce2 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/_helpers.tpl @@ -0,0 +1,97 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Analytics Server IP or DNS +*/}} +{{- define "analytics.server" -}} +{{- if .Values.analyticsConfig.endpoint.server -}} +{{- printf .Values.analyticsConfig.endpoint.server -}} +{{- else -}} +{{- printf "analytics.%s.svc.cluster.local" .Release.Namespace -}} +{{- end -}} +{{- end -}} + + +{{- define "citrix-cpx-ingress-controller.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "citrix-cpx-ingress-controller.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "cpxservice.fullname" -}} +{{- $name := default .Chart.Name "cpx-service" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "cpxexporter.fullname" -}} +{{- $name := default .Chart.Name "exporter" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "cpxservicemonitor.fullname" -}} +{{- $name := default .Chart.Name "citrix-adc-cpx-servicemonitor" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "cpxservicemonitorlabel" -}} +{{- $name := default .Chart.Name "citrix-adc-cpx-svcmon" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "cpxconfigmap.fullname" -}} +{{- $name := default .Chart.Name "cpx-cic-configmap" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "citrix-cpx-ingress-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "citrix-cpx-ingress-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "citrix-cpx-ingress-controller.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/cic_crds.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/templates/cic_crds.yaml new file mode 100644 index 000000000..6ff58466f --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/cic_crds.yaml @@ -0,0 +1,2515 @@ +{{- if .Values.crds.install }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: rewritepolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: rewritepolicy + plural: rewritepolicies + singular: rewritepolicy + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + rewrite-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to rewrite policy.' + type: array + items: + type: string + maxLength: 127 + goto-priority-expression: + description: 'Expression or other value specifying the next policy to be + evaluated if the current policy evaluates to TRUE. + Specify one of the following values: + * NEXT - Evaluate the policy with the next higher priority number. + * END - End policy evaluation. + Default value of goto-priority-expression: END' + type: string + maxLength: 1499 + logpackets: + type: object + description: 'Adds an audit message action. + The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + rewrite-policy: + type: object + properties: + rewrite-criteria: + description: 'Expression against which traffic is evaluated.' + type: string + maxLength: 1299 + default-action: + description: 'Action to perform if the result of policy evaluation is undefined (UNDEF). + An UNDEF event indicates an internal error condition.' + type: string + maxLength: 77 + enum: ['NOREWRITE', 'RESET', 'DROP'] + operation: + description: 'Type of user-defined rewrite action.' + type: string + enum: ["noop", "delete", "insert_http_header", "delete_http_header", + "corrupt_http_header", "insert_before", "insert_after", "replace", + "replace_http_res", "delete_all", "replace_all", "insert_before_all", + "insert_after_all", "clientless_vpn_encode", "clientless_vpn_encode_all", + "clientless_vpn_decode", "clientless_vpn_decode_all", "insert_sip_header", + "delete_sip_header", "corrupt_sip_header", "replace_sip_res", "replace_diameter_header_field", + "replace_dns_header_field", "replace_dns_answer_section"] + target: + description: 'Default syntax expression that specifies which part of the request or response to rewrite.' + type: string + maxLength: 1229 + modify-expression: + description: 'Default syntax expression that specifies the content to insert into the request + or response at the specified location, or that replaces the specified string.' + type: string + maxLength: 7991 + multiple-occurence-modify: + description: 'Search facility that is used to match multiple strings in the request or response.' + type: string + maxLength: 171 + additional-multiple-occurence-modify: + description: 'Specify additional criteria to refine the results of the search. + Always starts with the "extend(m,n)" operation, where "m" specifies number of bytes to the left of selected data + and "n" specifies number of bytes to the right of selected data. + You can use refineSearch only on body expressions, and only when rewrite-criteria is any one of this: + INSERT_BEFORE_ALL, INSERT_AFTER_ALL, REPLACE_ALL, and DELETE_ALL.' + type: string + maxLength: 1299 + direction: + description: 'Bind point to which to bind the policy.' + type: string + enum: ["REQUEST","RESPONSE"] + comment: + description: 'Any comments to preserve information about this rewrite policy.' + type: string + maxLength: 255 + required: [rewrite-criteria, operation, target, direction] + required: [rewrite-policy] + + responder-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to responder policy.' + type: array + items: + type: string + maxLength: 127 + goto-priority-expression: + description: 'Expression or other value specifying the next policy to be + evaluated if the current policy evaluates to TRUE. + Specify one of the following values: + * NEXT - Evaluate the policy with the next higher priority number. + * END - End policy evaluation. + Default value of goto-priority-expression: END' + type: string + maxLength: 1499 + logpackets: + type: object + description: 'Adds an audit message action. + The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", + "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + responder-policy: + type: object + properties: + redirect: + type: object + description: 'Use this option when you want to Redirect the request when request matches to policy.' + properties: + url: + description: 'URL on which you want to redirect the request.' + type: string + maxLength: 7991 + redirect-status-code: + description: 'HTTP response status code, for example 200, 302, 404, etc.' + type: integer + minimum: 100 + maximum: 599 + redirect-reason: + description: 'Expression specifying the reason for redirecting the request.' + type: string + maxLength: 7991 + required: [url] + respondwith: + type: object + description: 'Use this parameter when you want to respond to the request when request matches to policy.' + properties: + http-payload-string: + description: 'Expression that you want to sent as response to the request.' + type: string + maxLength: 7991 + required: [http-payload-string] + noop: + type: string + description: 'Use this option when you want to send the request to the protected server instead of + responding to it when request matches to policy.' + properties: + target: + description: 'Default syntax expression that specifies to perform noop operation on' + type: string + maxLength: 1229 + reset: + type: string + description: 'Use this option when you want to Reset the client connection by closing it when request matches to policy.' + properties: + drop: + type: string + description: 'Use this option when you want to drop the request without sending a response to the user when request matches to policy.' + properties: + respond-criteria: + description: 'Default syntax expression that the policy uses to determine whether to respond to the specified request.' + type: string + maxLength: 1299 + default-action: + description: 'Action to perform if the result of policy evaluation is undefined (UNDEF). + An UNDEF event indicates an internal error condition.' + type: string + maxLength: 77 + enum: ['NOOP', 'RESET', 'DROP'] + comment: + description: 'Any comments to preserve information about this responder policy.' + type: string + maxLength: 255 + required: [respond-criteria] + oneOf: [required: [redirect], required: [respondwith], required: [noop], required: [reset], required: [drop]] + required: [responder-policy] + + dataset: + type: array + items: + type: object + properties: + name: + description: 'Name of the dataset.' + type: string + maxLength: 32 + type: + description: 'Type of value to bind to the dataset.' + type: string + enum: ["ipv4", "number", "ipv6", "ulong", "double", "mac"] + comment: + description: 'Any comments to preserve information about this dataset.' + type: string + maxLength: 255 + values: + description: 'Value of the specified type that is associated with this dataset.' + type: array + items: + type: string + required: [name, type, values] + + patset: + type: array + items: + type: object + properties: + name: + description: 'Name of the Patset.' + type: string + maxLength: 32 + comment: + description: 'Any comments to preserve information about this patset.' + type: string + maxLength: 255 + values: + description: 'String of characters that constitutes a pattern and is associated with this patset.' + type: array + items: + type: string + required: [name, values] + + stringmap: + type: array + items: + type: object + properties: + name: + description: 'Name of the Stringmap.' + type: string + maxLength: 32 + comment: + description: 'Any comments to preserve information about this stringmap.' + type: string + maxLength: 255 + values: + description: 'List of (key,value) pairs to be bound to this string map.' + type: array + items: + type: object + properties: + key: + description: 'Character string constituting the key to be bound to this string map.' + type: string + maxLength: 2047 + value: + description: 'Character string constituting the value associated with the key.' + type: string + maxLength: 2047 + required: [name, values] + + httpcallout_policy: + type: array + items: + type: object + properties: + name: + description: 'httpcallout name' + type: string + maxLength: 32 + server_ip: + description: 'IP Address of the server(callout agent) to which the callout is sent.' + type: string + server_port: + description: 'Port of the server(callout agent) to which the callout is sent.' + type: integer + minimum: 1 + maximum: 65535 + http_method: + description: |+ + 'Method used in the HTTP request that this callout sends. + Default http method is GET' + type: string + enum: ['GET', 'POST'] + host_expr: + description: |+ + 'String expression to configure the Host header. Can contain a literal value + (for example, 10.101.10.11) or a derived value (for example, http.req.header("Host")). + The literal value can be an IP address or a fully qualified domain name. Mutually + exclusive with the full HTTP request expression.' + type: string + maxLength: 255 + url_stem_expr: + description: |+ + 'String expression for generating the URL stem. Can contain a literal string + (for example, "/mysite/index.html") or an expression that derives the value + (for example, http.req.url).' + type: string + maxLength: 8191 + headers: + type: array + description: |+ + 'One or more headers to insert into the HTTP request. Each header is represented by + name and expr, where expr is an expression that is evaluated at runtime to provide + the value for the named header. You can configure a maximum of eight headers for + an HTTP callout.' + items: + type: object + properties: + name: + description: 'header name' + type: string + expr: + description: 'header expression' + type: string + parameters: + type: array + description: |+ + 'One or more query parameters to insert into the HTTP request URL (for a GET request) + or into the request body (for a POST request). Each parameter is represented by + name and expr, where expr is an expression that is evaluated at run time to provide + the value for the named parameter (name=value). The parameter values are URL encoded.' + items: + type: object + properties: + name: + description: 'parameter name' + type: string + expr: + description: 'parameter expression' + type: string + body_expr: + description: |+ + 'An advanced string expression for generating the body of the request. + The expression can contain a literal string or an expression that derives + the value (for example, client.ip.src).' + type: string + full_req_expr: + description: |+ + 'Exact HTTP request, in the form of an expression, which the Citrix ADC sends + to the callout agent. The request expression is constrained by the feature + for which the callout is used. For example, an HTTP.RES expression cannot be + used in a request-time policy bank or in a TCP content switching policy bank.' + type: string + scheme: + description: |+ + 'Type of scheme for the callout server. + Default scheme is HTTP' + type: string + enum: ['HTTP', 'HTTPS'] + cache_for_secs: + description: |+ + 'Duration, in seconds, for which the callout response is cached. + The cached responses are stored in an integrated caching content + group named "calloutContentGroup". If no duration is configured, + the callout responses will not be cached unless normal caching + configuration is used to cache them. This parameter takes precedence over any + normal caching configuration that would otherwise apply to these responses.' + type: integer + minimum: 1 + maximum: 31536000 + return_type: + description: |+ + 'Type of data that the target callout agent returns in response to the callout + Available settings function as follows: + * TEXT - Treat the returned value as a text string. + * NUM - Treat the returned value as a number. + * BOOL - Treat the returned value as a Boolean value.' + type: string + enum: ['TEXT', 'NUM', 'BOOL'] + result_expr: + description: |+ + 'Expression that extracts the callout results from the response sent by the HTTP callout + agent. Must be a response based expression, that is, it must begin with HTTP.RES. The + operations in this expression must match the return type. For example, if you configure + a return type of TEXT, the result expression must be a text based expression. If the + return type is NUM, the result expression (resultExpr) must return a numeric value, + as in the following example: http.res.body(10000).length.' + type: string + maxLength: 8191 + comment: + description: 'Any comments to preserve information about this HTTP callout.' + type: string + maxLength: 255 + allOf: + - properties: + required: [name, server_ip, server_port] + - properties: + oneOf: + - properties: + required: [full_req_expr] + - properties: + anyOf: + - properties: + required: [http_method] + - properties: + required: [host_expr] + - properties: + required: [url_stem_expr] + - properties: + required: [headers] + - properties: + required: [parameters] + - properties: + required: [body_expr] + anyOf: [required: [rewrite-policies], required: [responder-policies]] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ratelimits.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: ratelimit + plural: ratelimits + singular: ratelimit + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the ratelimit policies are applied.' + type: array + items: + type: string + maxLength: 127 + selector_keys: + type: object + description: 'Traffic match criteria to which apply above rate-limit/throttling. All keys are applied as AND condition. If no keys are specified, rate-limit applies at service level' + properties: + basic: + type: object + description: "Basic traffic stream selection criteria to which to apply the ratelimit" + properties: + path: + type: array + description: "api resource path prefix match. e.g. /api/v1/products" + items: + type: string + method: + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header_name: + description: "HTTP header that identifies the unique API client for e.g. X-apikey" + type: string + per_client_ip: + description: "Setting this applies the throttling limit to each unique Client IP address accessing the API resource" + type: boolean + req_threshold: + description: 'Max requests per timeslice units to be allowed' + type: integer + timeslice: + description: 'Timeslice in miliseconds in multiple of 10. Defaults to 1000 miliseconds' + type: integer + limittype: + description: "Burst mode or smooth. Defaults to smooth limittype if not specified" + type: string + enum: ['BURSTY','SMOOTH'] + throttle_action: + type: string + enum: ['DROP', 'RESET','REDIRECT', 'RESPOND'] + description: "Drop will drop the requests exceeding limits, RESET will reset the client connection, Redirect will redirect to specified URL, respond will respond with 429 'Exceeded allowed rate of requests'" + redirect_url: + type: string + description: "Redirect-URL" + logpackets: + type: object + description: 'Adds an audit message action. The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + required: [req_threshold] +--- +#Sample CRD instance + +#apiVersion: citrix.com/v1 +#description: VIP for apache service +#kind: vip +#metadata: +# name: service-apache +# namespace: default +#spec: +# description: VIP for the apache Service +# ipaddress: 10.99.98.90 +# kind: service +# name: apache + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vips.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: vip + plural: vips + singular: vip + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .spec.ipaddress + name: VIP + type: string + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + ipaddress: + type: string + name: + type: string + kind: + type: string + enum: ["service", "ingress"] + description: + type: string + range-name: + type: string +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: authpolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: authpolicy + plural: authpolicies + singular: authpolicy + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: 'Current Status of the CRD' + jsonPath: .status.state + - name: Message + type: string + description: 'Status Message' + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: |+ + 'Name of the services for which the policies applied' + type: array + items: + type: string + maxLength: 63 + authentication_mechanism: + type: object + description: |+ + 'Authentication mechanism. Options: using forms or using request header. + Default is Authentication using request header, when no option is specified' + properties: + using_request_header: + description: |+ + 'Enable user authentication using request header. Use when the credentials + or api keys are passed in a header. For example, when using Basic, Digest, + Bearer authentication or api keys. + When authentication using forms is provided, this is set to OFF' + + type: string + using_forms: + type: object + description: 'Enables authentication using forms. Use with user/web authentication.' + properties: + authentication_host: + description: |+ + 'Fully qualified domain name (FQDN) for authentication. + This FQDN should be unique and should resolve to frontend IP of + ADC with Ingress/service type LoadBalancer (or) vip of Listener CRD' + type: string + maxLength: 255 + authentication_host_cert: + description: |+ + 'Name of the SSL certificate to be used with authentication_host. + This certificate is mandatory while using_forms' + type: object + properties: + tls_secret: + type: string + description: 'Name of the Kubernetes Secret of type tls referring to Certificate' + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + preconfigured: + type: string + maxLength: 63 + description: |+ + 'Preconfigured SSL certkey name on ADC with the + certificate and key already added on ADC' + oneOf: + - properties: + required: [tls_secret] + - properties: + required: [preconfigured] + ingress_name: + description: |+ + 'Ingress name for which the authentication using forms + is applicable.' + type: string + maxLength: 63 + lb_service_name: + description: |+ + 'Service of type LoadBalancer for which the authentication using forms + is applicable.' + type: string + maxLength: 63 + listener_name: + description: |+ + 'Listener CRD name for which the authentication using forms is applicable.' + type: string + maxLength: 63 + vip: + description: |+ + 'Frontend IP of ingress for which the authentication + using forms is applicable. This refers to frontend-ip provided + with Ingress. It is suggested to use vip, if more than one Ingress + resource use the same frontend-ip' + type: string + required: [authentication_host, authentication_host_cert] + oneOf: + - properties: + required: [ingress_name] + - properties: + required: [lb_service_name] + - properties: + required: [listener_name] + - properties: + required: [vip] + oneOf: + - properties: + using_request_header: + enum: ['ON'] + required: [using_request_header] + - properties: + required: [using_forms] + + authentication_providers: + description: |+ + 'Authentication Configuration for required authentication providers/schemes. + One or more of these can be created' + type: array + items: + description: 'Create config for a single authentication provider of a particular type' + type: object + properties: + name: + description: 'Name for this provider, has to be unique, referenced by authentication policies' + type: string + maxLength: 127 + + oauth: + description: 'Authentication provided by external oAuth provider' + type: object + properties: + issuer: + description: 'Identity of the server whose tokens are to be accepted' + type: string + maxLength: 127 + audience: + description: 'Audience for which token sent by Authorization server is applicable' + type: array + items: + type: string + maxLength: 127 + jwks_uri: + description: |+ + 'URL of the endpoint that contains JWKs (Json Web Key) for + JWT (Json Web Token) verification' + type: string + maxLength: 127 + introspect_url: + description: ' URL of the introspection server' + type: string + maxLength: 127 + client_credentials: + description: |+ + 'secrets object that contains Client Id and secret as known + to Introspection server' + type: string + maxLength: 253 + token_in_hdr: + description: |+ + 'custom header name where token is present, + default is Authorization header' + type: array + items: + type: string + maxLength: 127 + maxItems: 2 + token_in_param: + description: 'query parameter name where token is present' + type: array + items: + type: string + maxLength: 127 + maxItems: 2 + signature_algorithms: + description: 'list of allowed signature algorithms, by default HS256, RS256, RS512 are allowed' + type: array + items: + type: string + enum: ['HS256', 'RS256', 'RS512'] + claims_to_save: + description: 'list of claims to be saved, used to create authorization policies' + type: array + items: + type: string + maxLength: 127 + metadata_url: + description: 'URL used to get OAUTH/OIDC provider metadata' + type: string + maxLength: 255 + user_field: + description: |+ + 'Attribute in the token from which username should be extracted. + by default, ADC looks at email attribute for user id' + type: string + maxLength: 127 + default_group: + description: |+ + 'group assigned to the request if authentication succeeds, + this is in addition to any extracted groups from token' + type: string + maxLength: 63 + grant_type: + description: 'used to specify the type of flow to the token end point, defaults to CODE' + type: array + items: + type: string + enum: ['CODE','PASSWORD'] + pkce: + description: 'specify whether to enable Proof Key Code Exchange, defaults to ENABLED' + type: string + enum: ['ENABLED', 'DISABLED'] + token_ep_auth_method: + description: |+ + 'authentication method to be used with token end point, + defaults to client_secret_post' + type: string + enum: ['client_secret_post', 'client_secret_jwt'] + + anyOf: + - properties: + required : [jwks_uri] + - properties: + required : [introspect_url, client_credentials] + - properties: + required : [metadata_url] + + ldap: + description: 'LDAP authentication provider' + type: object + properties: + server_ip: + description: 'IP address assigned to the LDAP server' + type: string + server_name: + description: 'LDAP server name as a FQDN' + type: string + maxLength: 127 + server_port: + description: 'Port on which the LDAP server accepts connections. Default is 389' + type: integer + minimum: 1 + maximum: 65535 + base: + description: |+ + 'Base (node) from which to start LDAP searches. If the LDAP server is + running locally, the default value of base is dc=netscaler, dc=com' + type: string + maxLength: 127 + server_login_credentials: + description: |+ + 'Kubernetes secret object providing credentials to login to LDAP server, + The secret data should have username and password' + type: string + login_name: + description: |+ + 'LDAP login name attribute. The Citrix ADC uses the LDAP login name + to query external LDAP servers or Active Directories' + type: string + maxLength: 127 + security_type: + description: |+ + 'Type of security used for communications between the Citrix ADC + and the LDAP server. Default is TLS' + type: string + enum: ['PLAINTEXT', 'TLS', 'SSL'] + validate_server_cert: + description: 'Validate LDAP Server certs. Default is NO' + type: string + enum: ['YES', 'NO'] + hostname: + description: |+ + 'Hostname for the LDAP server. If validate_server_cert is ON, + this must be the host name on the certificate from the LDAP + A hostname mismatch will cause a connection failure' + type: string + maxLength: 127 + sub_attribute_name: + description: 'LDAP group sub-attribute name. Used for group extraction from the LDAP server.' + type: string + maxLength: 31 + group_attribute_name: + description: 'LDAP group attribute name. Used for group extraction on the LDAP server.' + type: string + maxLength: 31 + search_filter: + description: |+ + 'String to be combined with the default LDAP user search string to form the + search value. For example, if the search filter "vpnallowed=true" is combined + with the LDAP login name "samaccount" and the user-supplied username is "bob", + the result is the LDAP search string ""(&(vpnallowed=true)(samaccount=bob)"" + (Be sure to enclose the search string in two sets of double quotation marks)' + type: string + maxLength: 255 + auth_timeout: + description: |+ + 'Number of seconds the Citrix ADC waits for a response from the server + Default is 3' + type: integer + minimum: 1 + maximum: 4294967295 + password_change: + description: 'Allow password change requests. Default is DISABLED' + type: string + enum: ['ENABLED', 'DISABLED'] + attributes_to_save: + description: |+ + 'List of attribute names separated by comma which needs to be fetched + from LDAP server and stored as key-value pair for the session on ADC' + type: string + maxLength: 2047 + oneOf: + - properties: + required: [server_ip] + - properties: + required: [server_name] + + saml: + description: |+ + 'SAML authentication provider. + Currently SAML is supported only with authentication mechanism using forms' + type: object + properties: + metadata_url: + description: 'URL is used for obtaining saml metadata.' + type: string + maxLength: 255 + metadata_refresh_interval: + description: |+ + 'Interval in minutes for fetching metadata from specified metadata URL. + Default is 36000' + type: integer + minimum: 1 + maximum: 4294967295 + signing_cert: + description: 'SSL certificate to sign requests from SP to IDP' + type: object + properties: + tls_secret: + type: string + description: 'Name of the Kubernetes Secret of type tls referring to Certificate' + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + preconfigured: + type: string + maxLength: 63 + description: |+ + 'Preconfigured SSL certkey name on ADC with the + certificate and key already added on ADC' + oneOf: + - properties: + required: [tls_secret] + - properties: + required: [preconfigured] + audience: + description: 'Audience for which assertion sent by IdP is applicable' + type: string + maxLength: 127 + issuer_name: + description: 'The name to be used in requests sent from SP to IDP to identify citrix ADC' + type: string + maxLength: 63 + binding: + description: 'Specifies the transport mechanism of saml message. Default is POST' + type: string + enum: ['REDIRECT', 'POST', 'ARTIFACT'] + artifact_resolution_service_url: + description: 'URL of the Artifact Resolution Service on IdP' + type: string + maxLength: 255 + logout_binding: + description: 'Specifies the transport mechanism of saml logout. Default is POST' + type: string + enum: ['REDIRECT', 'POST'] + reject_unsigned_assertion: + description: |+ + 'Reject unsigned SAML assertions. ON, rejects assertion without signature. + STRICT ensure that both Response and Assertion are signed. Default is ON' + type: string + enum: ['ON', 'OFF', 'STRICT'] + user_field: + description: 'SAML user ID, as given in the SAML assertion' + type: string + maxLength: 63 + default_authentication_group: + description: |+ + 'This is the default group that is chosen when the authentication + succeeds in addition to extracted groups' + type: string + maxLength: 63 + skew_time: + description: |+ + 'Allowed clock skew in number of minutes on an incoming assertion. + Default is 5' + type: integer + minimum: 1 + attributes_to_save: + description: |+ + 'List of attribute names separated by comma which needs to be extracted + and stored as key-value pair for the session on ADC' + type: string + maxLength: 2047 + required: + - metadata_url + + basic_local_db: + type: object + description: |+ + 'Basic HTTP authentication supported by ADC, user data in local DB of ADC. + Users needs to be added on ADC' + properties: + use_local_auth: + description: 'Use ADC authentication' + type: string + enum: ['YES'] + + required: + - name + + authentication_policies: + description: 'Authentication policies' + type: array + items: + type: object + description: 'Authentication policy' + properties: + resource: + type: object + description: 'endpoint/resource selection criteria' + properties: + path: + description: 'api resource path e.g. /products. ' + type: array + items: + type: string + maxLength: 511 + method: + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + required: + - path + expression: + description: 'ADC syntax expression for authentication' + type: string + maxLength: 1229 + provider: + description: 'name of the authentication provider for the policy, empty if no authentication required' + type: array + items: + type: string + maxLength: 127 + maxItems: 1 + oneOf: + - required: [resource, provider] + - required: [expression, provider] + + authorization_policies: + description: 'Authorization policies' + type: array + items: + type: object + description: 'Authorization policy' + properties: + resource: + type: object + description: 'endpoint/resource selection criteria' + properties: + path: + description: 'api resource path e.g. /products. ' + type: array + items: + type: string + maxLength: 511 + method: + description: ' http method' + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + claims: + description: 'authorization scopes required for selected resource saved as claims or attributes' + type: array + items: + type: object + properties: + name: + description: 'name of the claim/attribute to check' + type: string + maxLength: 127 + values: + description: 'list of claim values required for the request' + type: array + items: + type: string + maxLength: 127 + minItems: 1 + required: + - name + - values + required: + - claims + expression: + description: 'ADC syntax expression for authorization' + type: string + maxLength: 1229 + oneOf: + - required: [resource] + - required: [expression] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: listeners.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + version: null + names: + kind: Listener + plural: listeners + singular: listener + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + required: [spec] + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + required: [protocol] + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + protocol: + type: string + enum: ["https", "http"] + description: "Protocol for this listener" + vip: + type: string + description: "VIP address, Optional for CPX, required for Tier-1 deployments" + secondaryVips: + type: array + description: "An array of Secondary VIPs. All the VIPs will be part of an ipset" + minItems: 1 + items: + type: string + redirectPort: + type: integer + minimum: 1 + maximum: 65535 + description: "Port from which http traffic should be redirected to https" + port: + type: integer + minimum: 1 + maximum: 65535 + certificates: + type: array + description: "certificates attached to the endpoints - Not applicable for HTTP" + minItems: 1 + items: + type: object + properties: + preconfigured: + type: string + description: "Preconfigured Certificate name on ADC " + secret: + type: object + description: "Kuberentes secret object" + required: [name] + properties: + name: + type: string + description: "name of the Kubernetes Secret object where Cert is located" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + namespace: + type: string + description: "Namespace of the kubernetes secret object; Default is same namespace where the Listener object is located" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + default: + type: boolean + description: "Only one of the certificate can be marked as default which will be presented if none of the cert matches with the hostname" + oneOf: + - required: ["preconfigured"] + - required: ["secret"] + policies: + type: object + description: "Policies attached to the Listener" + properties: + httpprofile: + type: object + description: "HTTP profile configurations for the Listener, HTTP level configurations" + properties: + preconfigured: + type: string + description: "Preconfigured or Built-in HTTP profile name" + config: + type: object + description: "HTTP profile configuration for the listener. For individual fields, refer:https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ns/nshttpprofile/nshttpprofile/ Name field is auto populated" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + tcpprofile: + type: object + description: "TCP level configurations, uses ns tcpprofile of citrix ADC" + properties: + preconfigured: + description: "Preconfigured or Built-in TCP profile name" + type: string + config: + type: object + description: "TCPprofile configurations for the listener. For individual fields refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ns/nstcpprofile/ ; Name field is auto populated" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + csvserverConfig: + type: object + description: "CS Vserver configuration for the listener" + additionalProperties: + type: string + sslprofile: + type: object + description: "SSL profile configuration" + properties: + preconfigured: + type: string + description: "SSL profile which is preconfigured in ADC. Ciphers bound to the profile is not overriden" + config: + description: "Citrix ADC frontend SSL profile configurations. Refer:https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ssl/sslprofile/ for all configurations; Name field is auto generated" + type: object + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + sslciphers: + type: array + description: "List of ciphers to be bound to the ssl profile for the listener. Priority is as per the order in the list. A cipher suite, predefined cipher group or User created cipher group can be mentioned" + minItems: 1 + items: + type: string + description: "Cipher suite, cipher group name" + analyticsprofile: + type: object + description: "Analytics profile configuration" + properties: + preconfigured: + type: array + description: "Preconfigured Analytics profile that needs to be bound to the vserver" + minItems: 1 + items: + type: string + description: "Name of the analytics profile preconfigured that will be bound to the Vserver" + config: + type: array + description: "An array of analytics to be enabled" + minItems: 1 + items: + type: object + description: "Anlytics to be enabled" + required: ['type'] + properties: + type: + description: "Analytics profile to be enabled, you can enable one or more of the webinsight, tcpinsight, securityinsight, videoinsight, hdxinsight, gatewayinsight, timeseries, lsninsight, botinsight " + type: string + enum: ["webinsight", "tcpinsight", "securityinsight", "videoinsight", "hdxinsight", "gatewayinsight", "timeseries", "lsninsight", "botinsight"] + parameters: + type: object + description: "Additional parameters for analytics profile. Please refer:https://developer-docs.citrix.com/projects/citrix-adc-nitro-api-reference/en/latest/configuration/analytics/analyticsprofile/" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + routes: + type: array + description: "List of route objects attached to the listener" + minItems: 1 + items: + type: object + properties: + name: + type: string + description: "Name of the HTTPRoute object" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + namespace: + type: string + description: "Namespace of the HTTPRoute object" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + labelSelector: + description: "Labels key value pair, if the route carries the same labels, it is automatically attached" + type: object + additionalProperties: + type: string + oneOf: + - required: [name, namespace] + - required: [labelSelector] + defaultAction: + type: object + description: "Default action for the listener: One of Backend or Redirect" + properties: + backend: + type: object + oneOf: + - required: [kube] + properties: + kube: + type: object + required: [service, port] + properties: + service: + description: "Name of the backend service" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + port: + description: "Service port" + type: integer + minimum: 1 + maximum: 65535 + namespace: + description: "Service namespace" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + backendConfig: + description: "General backend service options" + type: object + properties: + secure_backend: + description: "Use Secure communications to the backends" + type: boolean + lbConfig: + description: "Citrix ADC LB vserver configurations for the backend. Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/load-balancing/lbvserver/lbvserver/ for all configurations" + type: object + additionalProperties: + type: string + servicegroupConfig: + description: "Citrix ADC service group configurations for the backend; Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/basic/servicegroup/servicegroup/ for all configurations" + type: object + additionalProperties: + type: string + redirect: + type: object + oneOf: + - required: [targetExpression] + - required: [hostRedirect] + - required: [httpsRedirect] + properties: + httpsRedirect: + description: "Change the scheme from http to https keeping URL intact" + type: boolean + hostRedirect: + description: "Host name specified is used for redirection with URL intact" + type: string + targetExpression: + description: "A target can be specified using Citrix ADC policy expression" + type: string + responseCode: + description: "Default response code is 302, which can be customised using this attribute" + type: integer + minimum: 100 + maximum: 599 + oneOf: + - required: ["backend"] + - required: ["redirect"] + subresources: + # status enables the status subresource. + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: httproutes.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + version: null + names: + kind: HTTPRoute + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + required: [rules] + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + hostname: + type: array + description: "List of domain names that share the same route, default is '*'" + minItems: 1 + items: + type: string + description: "Domain name" + rules: + type: array + description: "List Content routing rules with an action defined" + minItems: 1 + items: + type: object + required: [name, action] + properties: + name: + type: string + description: "A name to represent the rule, this is used as an identifier in content routing policy name in ADC" + minLength: 1 + maxLength: 20 + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + match: + type: array + description: "List of rules with same action" + minItems: 1 + items: + type: object + anyOf: + - required: [path] + - required: [headers] + - required: [cookies] + - required: [queryParams] + - required: [method] + - required: [policyExpression] + properties: + path: + type: object + description: "URL Path based content routing" + properties: + prefix: + type: string + description: "URL path matches the prefix expression" + exact: + type: string + description: "URL Path must match exact path" + regex: + type: string + description: "PCRE based regex expression for path matching" + headers: + type: array + description: "List of header for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Header details for content routing, Check for existence of a header or header name-value match" + properties: + headerName: + type: object + description: "Header name based content routing, Here existence of header is used for routing" + properties: + exact: + type: string + description: "Header Name - treated as exact must exist" + contains: + type: string + description: "Header Name - A header must exist that contain the string the name" + regex: + type: string + description: "header Name - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e header name must not exist" + oneOf: + - required: [exact] + - required: [contains] + - required: [regex] + headerValue: + type: object + description: "Header Name and Value based match" + properties: + name: + type: string + description: "Header name that must match the value" + exact: + type: string + description: "Header value - treated as exact" + contains: + type: string + description: "Header value - treated as contains" + regex: + type: string + description: "header value - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e header if present must not match the value" + oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + queryParams: + type: array + description: "List of Query parameters for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Query parameters Name and Value based match" + properties: + name: + type: string + description: "Query name that must match the value. If no value is specified, matches with any value" + exact: + type: string + description: "Query value - Exact match" + contains: + type: string + description: "Query value - value must have the string(substring)" + regex: + type: string + description: "Query value - Value must match this regex patterm" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e query if present must not match the value" + anyOf: + - required: [name] + - oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + cookies: + type: array + description: "List of Cookie params for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Cookie based routing" + properties: + name: + type: string + description: "cookie name that must match the value. If no value specified, it matches with any value" + exact: + type: string + description: "cookie value - treated as exact" + contains: + type: string + description: "cookie value - treated as substring" + regex: + type: string + description: "cookie value - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e cookie if present must not match the value" + anyOf: + - required: [name] + - oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + method: + type: string + description: "HTTP method for content routing eg: POST, PUT, DELETE etc" + policyExpression: + type: string + description: "Citrix ADC policy expressions; refer: https://docs.citrix.com/en-us/netscaler/media/expression-prefix.pdf" + action: + type: object + description: "Action for the matched rule" + properties: + backend: + type: object + oneOf: + - required: [kube] + properties: + kube: + type: object + required: [service, port] + properties: + service: + description: "Name of the backend service" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + port: + description: "Service port" + type: integer + minimum: 1 + maximum: 65535 + backendConfig: + type: object + description: "General backend service options" + properties: + secureBackend: + description: "Use Secure communications to the backends" + type: boolean + lbConfig: + description: "Citrix ADC LB vserver configurations for the backend. Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/load-balancing/lbvserver/lbvserver/ for all configurations" + type: object + additionalProperties: + type: string + servicegroupConfig: + description: "Citrix ADC service group configurations for the backend; Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/basic/servicegroup/servicegroup/ for all configurations" + type: object + additionalProperties: + type: string + redirect: + type: object + oneOf: + - required: [targetExpression] + - required: [hostRedirect] + - required: [httpsRedirect] + properties: + httpsRedirect: + description: "Change the scheme from http to https keeping URL intact" + type: boolean + hostRedirect: + description: "Host name specified is used for redirection with URL intact" + type: string + targetExpression: + description: "A target can be specified using Citrix ADC policy expression" + type: string + responseCode: + description: "Default response code is 302, which can be customised using this attribute" + type: integer + minimum: 100 + maximum: 599 + oneOf: + - required: ["backend"] + - required: ["redirect"] + subresources: + # status enables the status subresource. + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: continuousdeployments.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: continuousdeployment + plural: continuousdeployments + singular: continuousdeployment + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + cronSpec: + type: integer + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: wafs.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: waf + plural: wafs + singular: waf + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the waf policies are applied.' + type: array + items: + type: string + maxLength: 127 + application_type: + description: 'Type of applications to protect' + type: array + items: + type: string + enum: ['HTML', 'JSON', 'XML'] + signatures: + description: 'Location of external signature file' + type: string + redirect_url: + description: 'When a URL is blocked/down, redirect_url represents the alternate URL where the client requests should be sent.' + type: string + html_error_object: + description: 'Location of customized error page to respond when html or common violation are hit' + type: string + xml_error_object: + description: 'Location of customized error page to respond when xml violations are hit' + type: string + json_error_object: + description: 'Location of customized error page to respond when json violations are hit' + type: string + ip_reputation: + type: object + x-kubernetes-preserve-unknown-fields: true + description: 'Enabling IP reputation feature' + target: + description: 'To control what traffic to be inspected by Web Application Firewall. If you do not provide the target, everything will be inspected by default' + type: object + properties: + path: + type: array + description: "List of http urls to inspect" + items: + type: string + description: "URL path" + method: + type: array + description: "List of http methods to inspect" + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header: + type: array + description: "List of http headers to inspect" + items: + type: string + description: "header name" + security_checks: + description: 'To enable/disable application firewall security checks' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + settings: + description: 'To fine tune application firewall security checks default settings' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + relaxations: + description: 'Section which contains relaxation rules for known traffic and false positives' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + enforcements: + description: 'Section which contains enforcement or restriction rules' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bots.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: bot + plural: bots + singular: bot + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the bot policies are applied.' + type: array + items: + type: string + maxLength: 127 + signatures: + description: 'Location of external bot signature file' + type: string + redirect_url: + description: 'url to redirect when bot violation is hit' + type: string + target: + description: 'To control what traffic to be inspected by BOT. If you do not provide the target, everything will be inspected by default' + type: object + properties: + path: + type: array + description: "List of http urls to inspect" + items: + type: string + description: "URL path" + method: + type: array + description: "List of http methods to inspect" + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header: + type: array + description: "List of http headers to inspect" + items: + type: string + description: "header name" + security_checks: + description: 'To enable/disable bot ecurity checks' + type: object + properties: + allow_list: + type: string + enum: ['ON', 'OFF'] + block_list: + type: string + enum: ['ON', 'OFF'] + device_fingerprint: + type: object + x-kubernetes-preserve-unknown-fields: true + reputation: + type: string + enum: ['ON', 'OFF'] + ratelimit: + type: string + enum: ['ON', 'OFF'] + tps: + type: string + enum: ['ON', 'OFF'] + trap: + type: object + x-kubernetes-preserve-unknown-fields: true + bindings: + description: 'Section which contains binding rules for bot security checks' + type: object + properties: + allow_list: + type: array + items: + type: object + properties: + subnet: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + expression: + type: object + x-kubernetes-preserve-unknown-fields: true + + block_list: + type: array + items: + type: object + properties: + subnet: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + expression: + type: object + x-kubernetes-preserve-unknown-fields: true + ratelimit: + type: array + items: + type: object + properties: + url: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + cookie: + type: object + x-kubernetes-preserve-unknown-fields: true + reputation: + type: object + x-kubernetes-preserve-unknown-fields: true + captcha: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + tps: + type: object + properties: + geolocation: + type: object + x-kubernetes-preserve-unknown-fields: true + host: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + trapinsertion: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: apigatewaypolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: apigatewaypolicy + plural: apigatewaypolicies + singular: apigatewaypolicy + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + api_definition: + type: object + properties: + repository: + type: string + branch: + type: string + oas_secret_ref: + type: string + files: + type: array + items: + type: string + maxLength: 127 + api_proxy: + type: object + properties: + ipaddress: + type: string + port: + type: integer + protocol: + type: string + secret: + type: string + policies: + type: array + items: + type: object + properties: + name: + type: string + selector: + type: array + items: + type: object + properties: + tags: + type: array + items: + type: string + api: + type: string + method: + type: array + items: + type: string + maxLength: 127 + upstream: + type: object + properties: + service: + type: string + port: + type: integer + policy_bindings: + type: object + properties: + ratelimit: + type: object + properties: + name: + type: string + waf: + type: object + properties: + name: + type: string + rewritepolicy: + type: object + properties: + name: + type: string + bot: + type: object + properties: + name: + type: string + aaa: + type: array + items: + type: object + properties: + crd_name: + type: string + mappings: + type: array + items: + type: object + properties: + petstore_auth: + type: string + api_key: + type: string +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: corspolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: corspolicy + plural: corspolicies + singular: corspolicy + shortNames: + - cp + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: 'Current Status of the CRD' + jsonPath: .status.state + - name: Message + type: string + description: 'Status Message' + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'The list of Kubernetes services to which you want to apply the cors policies.' + type: array + items: + type: string + maxLength: 63 + allow_origin: + description: 'Represents list of allowed origins, it is used to screen the “origin” in the cors pre flight request' + type: array + items: + type: string + maxLength: 2083 + allow_methods: + description: 'Indicates which methods are supported by the response’s URL for the purposes of the CORS protocol. This variable will be used to set Access-Control-Allow-Methods in the pre-flight cors response.' + type: array + items: + type: string + maxLength: 127 + allow_headers: + description: 'Indicates which headers are supported by the response’s URL for the purposes of the CORS protocol. This variable will be used to set Access-Control-Allow-Headers in the pre-flight cors response.' + type: array + items: + type: string + maxLength: 127 + max_age: + description: 'Indicates the number of seconds (5 by default) the information provided by the `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` headers can be cached. This variable will be used to set Access-Control-Max-Age in the pre-flight cors response.' + type: integer + allow_credentials: + description: 'Indicates whether the response can be shared when the request’s credentials mode is "include". This variable will be set to Access-Control-Allow-Credentials in the rewrite action.' + type: boolean + required: [servicenames, allow_origin, allow_methods, allow_headers] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: appqoepolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: appqoepolicy + plural: appqoepolicies + singular: appqoepolicy + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + appqoe-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to appqoe policy.' + type: array + items: + type: string + maxLength: 127 + appqoe-policy: + type: object + properties: + operation-retry: + type: object + properties: + on-reset: + description: "To set Retry on Connection Reset or Not" + type: string + enum: ['YES','NO'] + on-timeout: + description: "Time in milliseconds for retry" + type: integer + minimum: 30 + maximum: 2000 + number-of-retries: + description: "To set number of retries" + type: integer + minimum: 1 + maximum: 7 + required: [operation-retry] + appqoe-criteria: + description: 'Expression against which traffic is evaluated.' + type: string + maxLength: 1299 + direction: + description: 'Bind point to which to bind the policy.' + type: string + enum: ["REQUEST","RESPONSE"] + required: [appqoe-criteria, operation-retry] + required: [appqoe-policy] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: wildcarddnsentries.citrix.com +spec: + group: citrix.com + names: + kind: wildcarddnsentry + plural: wildcarddnsentries + singular: wildcarddnsentry + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: Current Status of the CRD + jsonPath: .status.state + - name: Message + type: string + description: Status Message + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + zone: + type: object + description: DNS configuration for a zone + properties: + domain: + type: string + description: Domain name + dnsaddrec: + type: object + description: DNS Address record + properties: + domain-ip: + type: string + description: IPv4 addresses to assign to the domain name + ttl: + type: integer + description: >- + TTL is the time for which the record must be cached + by DNS proxies + dnsaaaarec: + type: object + description: DNS AAAA record + properties: + domain-ip: + type: string + description: IPv6 addresses to assign to the domain name + ttl: + type: integer + description: >- + TTL is the time for which the record must be cached + by DNS proxies + soarec: + type: object + description: SOA record + properties: + origin-server: + type: string + description: Origin server domain + contact: + type: string + description: Admin contact + serial: + type: integer + description: >- + The secondary server uses this parameter to + determine whether it requires a zone transfer from + the primary server. + refresh: + type: integer + description: >- + Time, in seconds, for which a secondary server must + wait between successive checks on the value of the + serial number. + retry: + type: integer + description: >- + Time, in seconds, between retries if a secondary server's + attempt to contact the primary server for a zone refresh fails. + expire: + type: integer + description: >- + Time, in seconds, after which the zone data on a secondary + nameserver can no longer be considered authoritative because + all refresh and retry attempts made during the period have failed." + nsrec: + type: object + description: Name server record + properties: + nameserver: + type: string + description: Host name of the name server to add to the domain. + ttl: + type: integer + description: >- + Time to Live (TTL), in seconds, for the record. TTL + is the time for which the record must be cached by + DNS proxies. The specified TTL is applied to all the + resource records that are of the same record type + and belong to the specified domain name +--- +{{- end }} diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/citrix-k8s-cpx-ingress.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/templates/citrix-k8s-cpx-ingress.yaml new file mode 100644 index 000000000..8af1c96e6 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/citrix-k8s-cpx-ingress.yaml @@ -0,0 +1,414 @@ +apiVersion: apps/v1 +{{- if or .Values.cpxBgpRouter .Values.daemonSet }} +kind: DaemonSet +{{- else }} +kind: Deployment +{{- end }} +metadata: + name: {{ include "citrix-cpx-ingress-controller.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: + app: {{ include "citrix-cpx-ingress-controller.fullname" . }} +{{- if not ( or .Values.cpxBgpRouter .Values.daemonSet ) }} + replicas: {{ .Values.replicaCount }} +{{- end }} + template: + metadata: + name: {{ include "citrix-cpx-ingress-controller.fullname" . }} + labels: + app: {{ include "citrix-cpx-ingress-controller.fullname" . }} + adc: "citrix" +{{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} +{{- end }} + spec: + serviceAccountName: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} +{{- if .Values.cpxBgpRouter }} + hostNetwork: true +{{- end }} + containers: + - name: cpx-ingress + image: "{{ tpl .Values.image . }}" + imagePullPolicy: {{ .Values.pullPolicy }} + tty: true + securityContext: + privileged: true + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace +{{- if .Values.cpxLicenseAggregator }} + - name: "CLA" + value: {{ .Values.cpxLicenseAggregator | quote }} +{{- else if .Values.ADMSettings.licenseServerIP }} + - name: "LS_IP" + value: {{ .Values.ADMSettings.licenseServerIP | quote }} + - name: "LS_PORT" + value: {{ .Values.ADMSettings.licenseServerPort | quote }} +{{- end }} + - name: "EULA" + value: "{{ .Values.license.accept }}" + - name: "KUBERNETES_TASK_ID" + value: "" +{{- if not .Values.cpxBgpRouter }} + - name: "MGMT_HTTP_PORT" + value: {{ .Values.mgmtHttpPort | quote }} + - name: "MGMT_HTTPS_PORT" + value: {{ .Values.mgmtHttpsPort | quote }} +{{- end }} +{{- if .Values.cpxBgpRouter }} + - name: NS_NETMODE + value: HOST +{{- if .Values.nsIP }} + - name: "NS_IP" + value: "{{ .Values.nsIP }}" +{{- end }} +{{- if .Values.nsGateway }} + - name: "NS_GATEWAY" + value: "{{ .Values.nsGateway }}" +{{- end }} +{{- end }} +{{- if .Values.ADMSettings.ADMIP }} + - name: "NS_MGMT_SERVER" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "NS_HTTP_PORT" + value: {{ .Values.mgmtHttpPort | quote }} + - name: "NS_HTTPS_PORT" + value: {{ .Values.mgmtHttpsPort | quote }} + - name: "LOGSTREAM_COLLECTOR_IP" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "ANALYTICS_SERVER" + value: {{ .Values.ADMSettings.ADMIP | quote }} + - name: "ANALYTICS_SERVER_PORT" + value: {{ .Values.ADMSettings.analyticsServerPort | quote }} +{{- end }} +##Need to set env var BANDWIDTH in order to provide Bandwidth license to Citrix ADC CPX from ADM or CPX License Aggregator +{{- if and ( or ( .Values.ADMSettings.licenseServerIP ) ( .Values.cpxLicenseAggregator ) ) ( eq .Values.ADMSettings.bandWidthLicense true ) }} + - name: "BANDWIDTH" + value: {{ .Values.ADMSettings.bandWidth | quote }} +{{- end }} +#for multiple-PE support, need to set CPX_CORES +{{- if or .Values.ADMSettings.licenseServerIP .Values.cpxLicenseAggregator }} +{{- if or ( eq .Values.ADMSettings.vCPULicense true ) ( eq .Values.ADMSettings.bandWidthLicense true ) }} + - name: "CPX_CORES" + value: {{ .Values.ADMSettings.cpxCores | default 1 | quote }} +{{- end }} +{{- end }} + - name: "EDITION" + value: {{ .Values.ADMSettings.licenseEdition }} +{{- if or (.Values.ADMSettings.ADMIP) (.Values.ADMSettings.licenseServerIP) }} + - name: NS_MGMT_USER + valueFrom: + secretKeyRef: + name: {{ required "Provide Secret for ADM/LicenseServer credentials" .Values.ADMSettings.loginSecret }} + key: username + - name: NS_MGMT_PASS + valueFrom: + secretKeyRef: + name: {{ required "Provide Secret for ADM/LicenseServer credentials" .Values.ADMSettings.loginSecret }} + key: password +{{- end }} +{{- if .Values.exporter.required }} + - name: "METRICS_EXPORTER_PORT" + value: {{ .Values.exporter.ports.containerPort | quote }} +{{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - mountPath: /var/deviceinfo + name: shared-data + - mountPath: /cpx/ + name: cpx-volume +{{- if .Values.cic.required }} + # Add cic as a sidecar + - name: cic + image: "{{ tpl .Values.cic.image . }}" + imagePullPolicy: {{ .Values.cic.pullPolicy }} + env: + - name: "EULA" + value: "{{ .Values.license.accept }}" +{{- if .Values.cpxBgpRouter }} + - name: "NS_IP" + value: {{ .Values.nsIP | default "192.168.1.2" | quote }} +{{- else }} + - name: "NS_IP" + value: "127.0.0.1" +{{- end }} + - name: "NS_APPS_NAME_PREFIX" + value: {{ .Values.entityPrefix | default "k8s"}} + - name: "NS_DEPLOYMENT_MODE" + value: "SIDECAR" +{{- if and .Values.openshift .Values.routeLabels }} + - name: "ROUTE_LABELS" + value: {{ .Values.routeLabels | quote}} +{{- end }} +{{- if and .Values.openshift .Values.namespaceLabels }} + - name: "NAMESPACE_LABELS" + value: {{ .Values.namespaceLabels | quote }} +{{- end }} +{{- if .Values.cpxBgpRouter }} +{{- if eq (upper .Values.nsProtocol) "HTTPS" }} + - name: NS_PROTOCOL + value: HTTPS + - name: NS_PORT + value: "9443" +{{- else }} + - name: NS_PROTOCOL + value: HTTP + - name: NS_PORT + value: "9080" +{{- end }} +{{- if .Values.bgpPort }} + - name: "BGP_PORT" + value: {{ .Values.bgpPort | quote }} +{{- end }} +{{- end }} + - name: "NS_ENABLE_MONITORING" + value: "YES" +{{- if .Values.logProxy }} + - name: "NS_LOGPROXY" + value: {{ .Values.logProxy | quote }} +{{- end }} +{{- if .Values.ingressIP }} + - name: "NS_VIP" + value: {{ .Values.ingressIP | quote }} +{{- end }} +{{- if .Values.nitroReadTimeout }} + - name: "NS_NITRO_READ_TIMEOUT" + value: "{{ .Values.nitroReadTimeout }}" +{{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName +{{- if .Values.kubernetesURL }} + - name: "kubernetes_url" + value: "{{ .Values.kubernetesURL }}" +{{- end }} +{{- if .Values.disableOpenshiftRoutes }} + - name: "DISABLE_OPENSHIFT_ROUTES" + value: "{{ .Values.disableOpenshiftRoutes }}" +{{- end }} +{{- if .Values.nsConfigDnsRec }} + - name: "NS_CONFIG_DNS_REC" + value: "{{ .Values.nsConfigDnsRec }}" +{{- end }} +{{- if .Values.nsSvcLbDnsRec }} + - name: "NS_SVC_LB_DNS_REC" + value: "{{ .Values.nsSvcLbDnsRec }}" +{{- end }} +{{- if .Values.optimizeEndpointBinding }} + - name: "OPTIMIZE_ENDPOINT_BINDING" + value: "{{ .Values.optimizeEndpointBinding }}" +{{- end }} +{{- if .Values.cpxBgpRouter }} + securityContext: + runAsUser: 0 + capabilities: + add: + - NET_ADMIN +{{- end }} + args: + - --configmap + {{ .Release.Namespace }}/{{ include "cpxconfigmap.fullname" . }} +{{- if .Values.ipam }} + - --ipam + citrix-ipam-controller +{{- end }} +{{- if .Values.disableAPIServerCertVerify }} + - --disable-apiserver-cert-verify + {{ .Values.disableAPIServerCertVerify }} +{{- end }} +{{- if .Values.cpxBgpRouter }} + - --deployment-type + kube-bgp-router +{{- end }} +{{- if .Values.ingressClass }} + - --ingress-classes +{{- range .Values.ingressClass}} + {{.}} +{{- end }} +{{- end }} +{{- if .Values.defaultSSLCertSecret }} + - --default-ssl-certificate + {{ .Release.Namespace }}/{{ .Values.defaultSSLCertSecret }} +{{- end }} +{{- end }} +{{- if .Values.updateIngressStatus }} +{{- if .Values.cpxBgpRouter }} + - --update-ingress-status + yes +{{- else }} + - --cpx-service + {{ .Release.Namespace }}/{{ include "cpxservice.fullname" . }} +{{- end }} +{{- end }} + volumeMounts: + - mountPath: /var/deviceinfo + name: shared-data + resources: + {{- toYaml .Values.cic.resources | nindent 12 }} +{{- if .Values.exporter.required }} + - name: exporter + image: "{{ tpl .Values.exporter.image . }}" + imagePullPolicy: {{ .Values.exporter.pullPolicy }} + args: + - "--secure=no" +{{- if .Values.cpxBgpRouter }} + - --target-nsip={{ .Values.nsIP | default "192.168.1.2" }}:9080 +{{- else }} + - "--target-nsip=127.0.0.1" +{{- end }} + - "--port={{ .Values.exporter.ports.containerPort }}" + env: + - name: "NS_DEPLOYMENT_MODE" + value: "SIDECAR" + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /var/deviceinfo + name: shared-data + resources: + {{- toYaml .Values.exporter.resources | nindent 12 }} +{{- end }} + volumes: + - name: shared-data + emptyDir: {} + - name: cpx-volume + emptyDir: {} +{{- if and .Values.nodeSelector.key .Values.nodeSelector.value }} + nodeSelector: + {{ .Values.nodeSelector.key }}: {{ .Values.nodeSelector.value }} +{{- end }} +{{- if .Values.tolerations }} + tolerations: {{ .Values.tolerations | toYaml | nindent 8 }} +{{- end }} +{{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} +{{- end }} + +--- +{{- if .Values.cpxBgpRouter }} +{{- if .Values.exporter.required }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "cpxexporter.fullname" . }} + labels: + app: {{ include "cpxexporter.fullname" . }} + service-type: {{ include "cpxservicemonitorlabel" . }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.exporter.ports.containerPort }} + targetPort: {{ .Values.exporter.ports.containerPort }} + name: exporter-port + selector: + app: {{ include "citrix-cpx-ingress-controller.fullname" . }} +{{- end }} +{{- else }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "cpxservice.fullname" . }} + labels: + app: cpx-service + service-type: {{ include "cpxservicemonitorlabel" . }} +{{- if .Values.serviceAnnotations }} + annotations: +{{- with .Values.serviceAnnotations }} +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} +spec: +{{- if or .Values.serviceType.loadBalancer.enabled ( and (.Values.updateIngressStatus) (not .Values.cpxBgpRouter)) }} + externalTrafficPolicy: {{ .Values.serviceSpec.externalTrafficPolicy }} + type: LoadBalancer +{{- if .Values.serviceSpec.loadBalancerIP }} + loadBalancerIP: {{ .Values.serviceSpec.loadBalancerIP }} +{{- end }} +{{- else if .Values.serviceType.nodePort.enabled }} + type: NodePort + externalTrafficPolicy: {{ .Values.serviceSpec.externalTrafficPolicy }} +{{- end }} +{{- if and .Values.serviceType.loadBalancer.enabled .Values.serviceSpec.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{- range .Values.serviceSpec.loadBalancerSourceRanges}} + - {{.}} +{{- end }} +{{- end }} + ports: +{{- if .Values.servicePorts }} +{{- with .Values.servicePorts }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- else }} + - port: 80 + protocol: TCP + name: http +{{- if and .Values.serviceType.nodePort.enabled .Values.serviceType.nodePort.httpPort }} + nodePort: {{ .Values.serviceType.nodePort.httpPort }} +{{- end }} + - port: 443 + protocol: TCP + name: https +{{- if and .Values.serviceType.nodePort.enabled .Values.serviceType.nodePort.httpsPort }} + nodePort: {{ .Values.serviceType.nodePort.httpsPort}} +{{- end }} +{{- end }} +{{- if .Values.exporter.required }} + - port: {{ .Values.exporter.ports.containerPort }} + targetPort: {{ .Values.exporter.ports.containerPort }} + name: exporter-port +{{- end }} + selector: + app: {{ include "citrix-cpx-ingress-controller.fullname" . }} +{{- end }} + +--- + +{{- if .Values.exporter.required }} + +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "cpxservicemonitor.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + servicemonitor: citrix-adc-cpx +spec: + endpoints: + - interval: 30s + port: exporter-port + selector: + matchLabels: + service-type: {{ include "cpxservicemonitorlabel" . }} + namespaceSelector: + matchNames: + - monitoring + - default + - {{ .Release.Namespace }} + +{{- end }} diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/configmap.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/templates/configmap.yaml new file mode 100644 index 000000000..dff57083e --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/configmap.yaml @@ -0,0 +1,71 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "cpxconfigmap.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + LOGLEVEL: {{ .Values.logLevel | quote | lower }} + JSONLOG: {{ .Values.jsonLog | quote | lower }} +{{- if eq (upper .Values.nsProtocol) "HTTPS" }} + NS_PROTOCOL: "https" +{{- if .Values.cpxBgpRouter }} + NS_PORT: "9443" +{{- else }} + NS_PORT: "443" +{{- end }} +{{- else }} + NS_PROTOCOL: "http" +{{- if .Values.cpxBgpRouter }} + NS_PORT: "9080" +{{- else }} + NS_PORT: "80" +{{- end }} +{{- end }} + +{{- if ne (upper .Values.nsHTTP2ServerSide) "OFF" }} + NS_HTTP2_SERVER_SIDE: {{ .Values.nsHTTP2ServerSide | quote }} +{{- end }} +{{- if ne (toString .Values.nsCookieVersion) "0" }} + NS_COOKIE_VERSION: {{ .Values.nsCookieVersion | quote }} +{{- end }} +{{- if .Values.nsDnsNameserver }} + NS_DNS_NAMESERVER: {{ .Values.nsDnsNameserver }} +{{- end }} + +{{- if .Values.analyticsConfig.required }} + NS_ANALYTICS_CONFIG: | + distributed_tracing: + enable: {{ .Values.analyticsConfig.distributedTracing.enable | quote }} + samplingrate: {{ .Values.analyticsConfig.distributedTracing.samplingrate }} + endpoint: + server: {{ include "analytics.server" . | quote }} + service: {{ .Values.analyticsConfig.endpoint.service | quote }} + timeseries: + port: {{ .Values.analyticsConfig.timeseries.port }} + metrics: + enable: {{ .Values.analyticsConfig.timeseries.metrics.enable | quote }} + mode: {{ .Values.analyticsConfig.timeseries.metrics.mode | quote }} + auditlogs: + enable: {{ .Values.analyticsConfig.timeseries.auditlogs.enable | quote }} + events: + enable: {{ .Values.analyticsConfig.timeseries.events.enable | quote }} + transactions: + enable: {{ .Values.analyticsConfig.transactions.enable | quote }} + port: {{ .Values.analyticsConfig.transactions.port }} +{{- end }} + +{{- if .Values.cpxBgpRouter }} +{{- if .Values.bgpSettings.required }} + NS_BGP_CONFIG: | +{{- with .Values.bgpSettings.bgpConfig }} + bgpConfig: +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} +{{- end }} + +{{- if .Values.nsLbHashAlgo.required }} + NS_LB_HASH_ALGO: | + hashFingers: {{ .Values.nsLbHashAlgo.hashFingers }} + hashAlgorithm: {{ .Values.nsLbHashAlgo.hashAlgorithm | quote }} +{{- end }} diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/ingressclass.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/templates/ingressclass.yaml new file mode 100644 index 000000000..d75537b79 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/ingressclass.yaml @@ -0,0 +1,18 @@ +{{- $default := .Values.setAsDefaultIngressClass -}} +{{- if semverCompare ">=1.19.0-0" .Capabilities.KubeVersion.GitVersion }} +{{- if .Values.ingressClass }} +{{- range .Values.ingressClass }} +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: {{ . | quote }} +{{- if $default }} + annotations: + ingressclass.kubernetes.io/is-default-class: "true" +{{- end }} +spec: + controller: citrix.com/ingress-controller +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/templates/rbac.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/templates/rbac.yaml new file mode 100644 index 000000000..c7e46b153 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/templates/rbac.yaml @@ -0,0 +1,89 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} +rules: + - apiGroups: [""] +{{- if .Values.openshift }} + resources: ["endpoints", "pods", "secrets", "routes", "tokenreviews", "subjectaccessreviews", "nodes", "namespaces", "configmaps", "services"] +{{- else }} + resources: ["endpoints", "pods", "secrets", "routes", "nodes", "namespaces", "configmaps", "services"] +{{- end }} + verbs: ["get", "list", "watch"] + # services/status is needed to update the loadbalancer IP in service status for integrating + # service of type LoadBalancer with external-dns + - apiGroups: [""] + resources: ["services/status"] + verbs: ["patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create"] + - apiGroups: ["extensions", "networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions", "networking.k8s.io"] + resources: ["ingresses/status"] + verbs: ["patch"] + - apiGroups: ["networking.k8s.io"] + resources: ["ingressclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] + - apiGroups: ["citrix.com"] + resources: ["rewritepolicies", "continuousdeployments", "authpolicies", "ratelimits", "listeners", "httproutes", "wafs", "apigatewaypolicies", "bots", "corspolicies", "appqoepolicies", "wildcarddnsentries"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: ["citrix.com"] + resources: ["rewritepolicies/status", "continuousdeployments/status", "authpolicies/status", "ratelimits/status", "listeners/status", "httproutes/status", "wafs/status", "apigatewaypolicies/status", "bots/status", "corspolicies/status", "appqoepolicies/status", "wildcarddnsentries/status"] + verbs: ["patch"] + - apiGroups: ["citrix.com"] + resources: ["vips"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: ["crd.projectcalico.org"] + resources: ["ipamblocks"] + verbs: ["get", "list", "watch"] +{{- if .Values.openshift }} + - apiGroups: ["route.openshift.io"] + resources: ["routes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["network.openshift.io"] + resources: ["hostsubnets"] + verbs: ["get", "list", "watch"] + - apiGroups: ["config.openshift.io"] + resources: ["networks"] + verbs: ["get", "list"] +{{- end }} + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} +subjects: +- kind: ServiceAccount + name: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "citrix-cpx-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- if .Values.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.imagePullSecrets }} +- name: {{.}} +{{- end }} +{{- end }} + +--- diff --git a/charts/citrix/citrix-cpx-with-ingress-controller/values.yaml b/charts/citrix/citrix-cpx-with-ingress-controller/values.yaml new file mode 100644 index 000000000..3a9ad26b5 --- /dev/null +++ b/charts/citrix/citrix-cpx-with-ingress-controller/values.yaml @@ -0,0 +1,221 @@ +# Default values for citrix-cpx-with-ingress-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Citrix ADC CPX config details +imageRegistry: quay.io +imageRepository: citrix/citrix-k8s-cpx-ingress +imageTag: 13.1-30.52 +image: "{{ .Values.imageRegistry }}/{{ .Values.imageRepository }}:{{ .Values.imageTag }}" +pullPolicy: IfNotPresent +imagePullSecrets: [] +daemonSet: False +nameOverride: "" +replicaCount: 1 +fullnameOverride: "" +mgmtHttpPort: 9080 +mgmtHttpsPort: 9443 +openshift: false +nsHTTP2ServerSide: "OFF" +nsCookieVersion: "0" +nsConfigDnsRec: +nsSvcLbDnsRec: +nsDnsNameserver: +optimizeEndpointBinding: +routeLabels: +namespaceLabels: + +# Service Type LoadBalancer and ingress support with CPX through BGP advertisement +# If you enable this, CPX is run as DaemonSet. Please edit the bgpSettings for configuring +# BGP neighbors for propgation of external IPs. +cpxBgpRouter: false + +# If cpxBgpRouter is true, then this is the NSIP used by CPX for internal communication +nsIP: 192.168.1.2 + +# If cpxBgpRouter is true, then this is the Gateway used by CPX for internal communication +nsGateway: 192.168.1.1 + +# Protocol used for communication between Citrix Ingress Controller sidecar and Citrix CPX +nsProtocol: http + +# External IP for ingress resource when bgpRouter is set to True +ingressIP: + +# If IPAM controller is used for auto allocation of the external IP for service of type LoadBalancer, set this option to true +ipam: False + +# API server Cert verification can be disabled, while communicating with API Server, if disableAPIServerCertVerify set to True +disableAPIServerCertVerify: False + +cpxLicenseAggregator: + +sslCertManagedByAWS: False + +nodeSelector: + key: + value: +tolerations: [] + +serviceType: + loadBalancer: + enabled: False + nodePort: + enabled: False + httpPort: + httpsPort: + +serviceAnnotations: {} + +serviceSpec: + externalTrafficPolicy: "Cluster" + loadBalancerIP: + loadBalancerSourceRanges: [] + +servicePorts: [] + +# Citrix Ingress Controller config details +cic: + imageRegistry: quay.io + imageRepository: citrix/citrix-k8s-ingress-controller + imageTag: 1.27.15 + image: "{{ .Values.cic.imageRegistry }}/{{ .Values.cic.imageRepository }}:{{ .Values.cic.imageTag }}" + pullPolicy: IfNotPresent + required: true + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # Following values depends on no of ingresses configured by Ingress Controllers, so it is + # advised to test with maximum no of ingresses to set these values. + # limits: + # cpu: 1000m + # memory: 1000Mi + # requests: + # cpu: 250m + # memory: 256Mi +entityPrefix: +license: + accept: no +ingressClass: +setAsDefaultIngressClass: False +# nitroReadTimeout is timeout value in seconds for nitro api read timeout(default is 20) +nitroReadTimeout: +logLevel: INFO +jsonLog: false +defaultSSLCertSecret: +updateIngressStatus: False +logProxy: +kubernetesURL: +disableOpenshiftRoutes: + +# Citrix ADM/License Server config details +ADMSettings: + licenseServerIP: + licenseServerPort: 27000 + ADMIP: + loginSecret: + bandWidthLicense: false + bandWidth: 1000 #bandwidth value shoule be in Mbps + vCPULicense: false + cpxCores: + analyticsServerPort: 5557 + licenseEdition: PLATINUM + +# Exporter config details +exporter: + required: false + imageRegistry: quay.io + imageRepository: citrix/citrix-adc-metrics-exporter + imageTag: 1.4.9 + image: "{{ .Values.exporter.imageRegistry }}/{{ .Values.exporter.imageRepository }}:{{ .Values.exporter.imageTag }}" + pullPolicy: IfNotPresent + ports: + containerPort: 8888 + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + +# For CRDs supported by Citrix Ingress Controller +crds: + install: false + retainOnDelete: false + +# Config required to be done by Citrix Ingress Controller for sending metrics to Citrix Observability Exporter +analyticsConfig: + required: false + distributedTracing: + enable: false + samplingrate: 100 + endpoint: + server: + service: + timeseries: + port: 5563 + metrics: + enable: false + mode: 'avro' + auditlogs: + enable: false + events: + enable: false + transactions: + enable: false + port: 5557 + +# BGP configurations: local AS, remote AS and remote address is mandatory to provide. Please do the approrpiate changes with respect to your environment +bgpSettings: + # When bgpConfig is configured correctly, set the required to true for the configuration to be applied. + required: false + bgpConfig: + - bgpRouter: + # Local AS number for BGP advertisement + localAS: 100 + neighbor: + # Address of the nighbor router for BGP advertisement + - address: + # Remote AS number + remoteAS: 100 + advertisementInterval: 10 + ASOriginationInterval: 10 + +bgpPort: + +nsLbHashAlgo: + required: false + hashFingers: 256 + hashAlgorithm: 'DEFAULT' + +# Specifies whether a ServiceAccount should be created +serviceAccount: + create: true + # The name of the ServiceAccount to use. + # If not set and `create` is true, a name is generated using the fullname template + # name: + +podAnnotations: {} + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:' + # This is the resource for CPX container. + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 128Mi + +affinity: {} diff --git a/charts/citrix/citrix-ingress-controller/Chart.yaml b/charts/citrix/citrix-ingress-controller/Chart.yaml new file mode 100644 index 000000000..39d69bb9b --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/Chart.yaml @@ -0,0 +1,20 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Ingress Controller + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-ingress-controller +apiVersion: v2 +appVersion: 1.27.15 +description: A Helm chart for Citrix Ingress Controller configuring MPX/VPX. +home: https://www.citrix.com +icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png +kubeVersion: '>=v1.16.0-0' +maintainers: +- email: priyanka.sharma@citrix.com + name: priyankash-citrix +- email: subash.dangol@citrix.com + name: subashd +name: citrix-ingress-controller +sources: +- https://github.com/citrix/citrix-k8s-ingress-controller +version: 1.27.15 diff --git a/charts/citrix/citrix-ingress-controller/README.md b/charts/citrix/citrix-ingress-controller/README.md new file mode 100644 index 000000000..1ae3c07dc --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/README.md @@ -0,0 +1,492 @@ +# Citrix Ingress Controller + +[Citrix](https://www.citrix.com/en-in/) provides an Ingress Controller for Citrix ADC MPX (hardware), Citrix ADC VPX (virtualized), and [Citrix ADC CPX](https://docs.citrix.com/en-us/citrix-adc-cpx/13/about.html) (containerized) for [bare metal](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment/baremetal) and [cloud](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment) deployments. It configures one or more Citrix ADC based on the Ingress resource configuration in [Kubernetes](https://kubernetes.io/) or in [OpenShift](https://www.openshift.com) cluster. + +## TL;DR; + +### For Kubernetes + ``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cic citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret= + ``` + + To install Citrix Provided Custom Resource Definition(CRDs) along with Citrix Ingress Controller + ``` + helm install cic citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,crds.install=true + ``` + +### For OpenShift + + ``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ + + helm install cic citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,openshift=true + ``` + + To install Citrix Provided Custom Resource Definition(CRDs) along with Citrix Ingress Controller + ``` + helm install cic citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,openshift=true,crds.install=true + ``` + +> **Important:** +> +> The `license.accept` argument is mandatory. Ensure that you set the value as `yes` to accept the terms and conditions of the Citrix license. + +## Introduction +This Helm chart deploys Citrix ingress controller in the [Kubernetes](https://kubernetes.io) or in the [Openshift](https://www.openshift.com) cluster using [Helm](https://helm.sh) package manager. + +### Prerequisites + +- The [Kubernetes](https://kubernetes.io/) version should be 1.16 and above if using Kubernetes environment. +- The [Openshift](https://www.openshift.com) version 4.8 or later if using OpenShift platform. +- The [Helm](https://helm.sh/) version 3.x or later. You can follow instruction given [here](https://github.com/citrix/citrix-helm-charts/blob/master/Helm_Installation_version_3.md) to install the same. +- You determine the NS_IP IP address needed by the controller to communicate with Citrix ADC. The IP address might be anyone of the following depending on the type of Citrix ADC deployment: + + - (Standalone appliances) NSIP - The management IP address of a standalone Citrix ADC appliance. For more information, see [IP Addressing in Citrix ADC](https://docs.citrix.com/en-us/citrix-adc/12-1/networking/ip-addressing.html). + + - (Appliances in High Availability mode) SNIP - The subnet IP address. For more information, see [IP Addressing in Citrix ADC](https://docs.citrix.com/en-us/citrix-adc/12-1/networking/ip-addressing.html). + + - (Appliances in Clustered mode) CLIP - The cluster management IP (CLIP) address for a clustered Citrix ADC deployment. For more information, see [IP addressing for a cluster](https://docs.citrix.com/en-us/citrix-adc/12-1/clustering/cluster-overview/ip-addressing.html). + +- You have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator), if you want to view the metrics of the Citrix ADC CPX collected by the [metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics). + +- The user name and password of the Citrix ADC VPX or MPX appliance used as the ingress device. The Citrix ADC appliance needs to have system user account (non-default) with certain privileges so that Citrix ingress controller can configure the Citrix ADC VPX or MPX appliance. For instructions to create the system user account on Citrix ADC, see [Create System User Account for CIC in Citrix ADC](#create-system-user-account-for-cic-in-citrix-adc). + + You can pass user name and password using Kubernetes secrets. Create a Kubernetes secret for the user name and password using the following command: + + ``` + kubectl create secret generic nslogin --from-literal=username='cic' --from-literal=password='mypassword' + ``` + +#### Create system User account for Citrix ingress controller in Citrix ADC + +Citrix ingress controller configures the Citrix ADC using a system user account of the Citrix ADC. The system user account should have certain privileges so that the CIC has permission configure the following on the Citrix ADC: + +- Add, Delete, or View Content Switching (CS) virtual server +- Configure CS policies and actions +- Configure Load Balancing (LB) virtual server +- Configure Service groups +- Cofigure SSl certkeys +- Configure routes +- Configure user monitors +- Add system file (for uploading SSL certkeys from Kubernetes) +- Configure Virtual IP address (VIP) +- Check the status of the Citrix ADC appliance + +> **Note:** +> +> The system user account would have privileges based on the command policy that you define. + +To create the system user account, do the following: + +1. Log on to the Citrix ADC appliance. Perform the following: + 1. Use an SSH client, such as PuTTy, to open an SSH connection to the Citrix ADC appliance. + + 2. Log on to the appliance by using the administrator credentials. + +2. Create the system user account using the following command: + + ``` + add system user + ``` + + For example: + + ``` + add system user cic mypassword + ``` + +3. Create a policy to provide required permissions to the system user account. Use the following command: + + ``` + add cmdpolicy cic-policy ALLOW '^(\?!shell)(\?!sftp)(\?!scp)(\?!batch)(\?!source)(\?!.*superuser)(\?!.*nsroot)(\?!install)(\?!show\s+system\s+(user|cmdPolicy|file))(\?!(set|add|rm|create|export|kill)\s+system)(\?!(unbind|bind)\s+system\s+(user|group))(\?!diff\s+ns\s+config)(\?!(set|unset|add|rm|bind|unbind|switch)\s+ns\s+partition).*|(^install\s*(wi|wf))|(^\S+\s+system\s+file)^(\?!shell)(\?!sftp)(\?!scp)(\?!batch)(\?!source)(\?!.*superuser)(\?!.*nsroot)(\?!install)(\?!show\s+system\s+(user|cmdPolicy|file))(\?!(set|add|rm|create|export|kill)\s+system)(\?!(unbind|bind)\s+system\s+(user|group))(\?!diff\s+ns\s+config)(\?!(set|unset|add|rm|bind|unbind|switch)\s+ns\s+partition).*|(^install\s*(wi|wf))|(^\S+\s+system\s+file)' + ``` + + **Note**: The system user account would have privileges based on the command policy that you define. + The command policy mentioned in ***step 3*** is similar to the built-in `sysAdmin` command policy with another permission to upload files. + + The command policy spec provided above have already escaped special characters for easier copy pasting into the Citrix ADC command line. + + For configuring the command policy from Citrix ADC Configuration Wizard (GUI), use the below command policy spec. + + ``` + ^(?!shell)(?!sftp)(?!scp)(?!batch)(?!source)(?!.*superuser)(?!.*nsroot)(?!install)(?!show\s+system\s+(user|cmdPolicy|file))(?!(set|add|rm|create|export|kill)\s+system)(?!(unbind|bind)\s+system\s+(user|group))(?!diff\s+ns\s+config)(?!(set|unset|add|rm|bind|unbind|switch)\s+ns\s+partition).*|(^install\s*(wi|wf))|(^\S+\s+system\s+file)^(?!shell)(?!sftp)(?!scp)(?!batch)(?!source)(?!.*superuser)(?!.*nsroot)(?!install)(?!show\s+system\s+(user|cmdPolicy|file))(?!(set|add|rm|create|export|kill)\s+system)(?!(unbind|bind)\s+system\s+(user|group))(?!diff\s+ns\s+config)(?!(set|unset|add|rm|bind|unbind|switch)\s+ns\s+partition).*|(^install\s*(wi|wf))|(^\S+\s+system\s+file) + ``` + +4. Bind the policy to the system user account using the following command: + + ``` + bind system user cic cic-policy 0 + ``` + +## Installing the Chart +Add the Citrix Ingress Controller helm chart repository using command: + +``` + helm repo add citrix https://citrix.github.io/citrix-helm-charts/ +``` + +### For Kubernetes: +#### 1. Citrix Ingress Controller +To install the chart with the release name, `my-release`, use the following command: + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,ingressClass[0]= + ``` + +> **Note:** +> +> By default the chart installs the recommended [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) roles and role bindings. + +The command deploys Citrix ingress controller on Kubernetes cluster with the default configuration. The [configuration](#configuration) section lists the mandatory and optional parameters that you can configure during installation. + +#### 2. Citrix Ingress Controller with Exporter +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed along with Citrix ingress controller and collects metrics from the Citrix ADC instances. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. + +> **Note:** +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator). + +Use the following command for this: + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,ingressClass[0]=,exporter.required=true + ``` + +### For Openshift: +Add the name of the service account created when the chart is deployed to the privileged Security Context Constraints of OpenShift: + + ``` + oc adm policy add-scc-to-user privileged system:serviceaccount:: + ``` + +#### 1. Citrix Ingress Controller +To install the chart with the release name, `my-release`, use the following command: + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,openshift=true + ``` + +The command deploys Citrix ingress controller on your Openshift cluster in the default configuration. The [configuration](#configuration) section lists the mandatory and optional parameters that you can configure during installation. + +#### 2. Citrix Ingress Controller with Exporter +[Metrics exporter](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/metrics-visualizer#visualization-of-metrics) can be deployed along with Citrix ingress controller and collects metrics from the Citrix ADC instances. You can then [visualize these metrics](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/metrics/promotheus-grafana/) using Prometheus Operator and Grafana. + +> **Note:** +> Ensure that you have installed [Prometheus Operator](https://github.com/coreos/prometheus-operator) + +Use the following command for this: + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,openshift=true,exporter.required=true + ``` + +### Installed components + +The following components are installed: + +- [Citrix ingress controller](https://github.com/citrix/citrix-k8s-ingress-controller) +- [Exporter](https://github.com/citrix/citrix-adc-metrics-exporter) (if enabled) + +## Configuration for ServiceGraph: + If Citrix ADC VPX/MPX need to send data to the Citrix ADM to bring up the servicegraph, then the below steps can be followed to install Citrix ingress controller for Citrix ADC VPX/MPX. Citrix ingress controller configures Citrix ADC VPX/MPX with the configuration required for servicegraph. + + 1. Create secret using Citrix ADC VPX credentials, which will be used by Citrix ingress controller for configuring Citrix ADC VPX/MPX: + + kubectl create secret generic nslogin --from-literal=username='cic' --from-literal=password='mypassword' + + 2. Deploy Citrix ingress controller using helm command: + + helm install my-release citrix/citrix-ingress-controller --set nsIP=,nsVIP=,license.accept=yes,adcCredentialSecret=,analyticsConfig.required=true,analyticsConfig.timeseries.metrics.enable=true,analyticsConfig.timeseries.port=5563,analyticsConfig.distributedTracing.enable=true,analyticsConfig.transactions.enable=true,analyticsConfig.transactions.port=5557,analyticsConfig.endpoint.server= + +> **Note:** +> If container agent is being used here for Citrix ADM, please provide `podIP` of container agent in the `analyticsConfig.endpoint.server` parameter. + +## CRDs configuration + +CRDs can be installed/upgraded when we install/upgrade Citrix ingress controller using `crds.install=true` parameter in Helm. If you do not want to install CRDs, then set the option `crds.install` to `false`. By default, CRDs too get deleted if you uninstall through Helm. This means, even the CustomResource objects created by the customer will get deleted. If you want to avoid this data loss set `crds.retainOnDelete` to `true`. + +> **Note:** +> Installing again may fail due to the presence of CRDs. Make sure that you back up all CustomResource objects and clean up CRDs before re-installing Citrix Ingress Controller. + +There are a few examples of how to use these CRDs, which are placed in the folder: [Example-CRDs](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds). Refer to them and install as needed, using the following command: +```kubectl create -f ``` + +### Details of the supported CRDs: + +#### authpolicies CRD: + +Authentication policies are used to enforce access restrictions to resources hosted by an application or an API server. + +Citrix provides a Kubernetes CustomResourceDefinitions (CRDs) called the [Auth CRD](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/auth) that you can use with the Citrix ingress controller to define authentication policies on the ingress Citrix ADC. + +Example file: [auth_example.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/auth_example.yaml) + +#### continuousdeployments CRD for canary: + +Canary release is a technique to reduce the risk of introducing a new software version in production by first rolling out the change to a small subset of users. After user validation, the application is rolled out to the larger set of users. Citrix ADC-Integrated [Canary Deployment solution](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/canary) stitches together all components of continuous delivery (CD) and makes canary deployment easier for the application developers. + +#### httproutes and listeners CRDs for contentrouting: + +[Content Routing (CR)](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/contentrouting) is the execution of defined rules that determine the placement and configuration of network traffic between users and web applications, based on the content being sent. For example, a pattern in the URL or header fields of the request. + +Example files: [HTTPRoute_crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/HTTPRoute_crd.yaml), [Listener_crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/Listener_crd.yaml) + +#### ratelimits CRD: + +In a Kubernetes deployment, you can [rate limit the requests](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/ratelimit) to the resources on the back end server or services using rate limiting feature provided by the ingress Citrix ADC. + +Example files: [ratelimit-example1.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/ratelimit-example1.yaml), [ratelimit-example2.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/ratelimit-example2.yaml) + +#### vips CRD: + +Citrix provides a CustomResourceDefinitions (CRD) called [VIP](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/crd/vip) for asynchronous communication between the IPAM controller and Citrix ingress controller. + +The IPAM controller is provided by Citrix for IP address management. It allocates IP address to the service from a defined IP address range. The Citrix ingress controller configures the IP address allocated to the service as virtual IP (VIP) in Citrix ADX VPX. And, the service is exposed using the IP address. + +When a new service is created, the Citrix ingress controller creates a CRD object for the service with an empty IP address field. The IPAM Controller listens to addition, deletion, or modification of the CRD and updates it with an IP address to the CRD. Once the CRD object is updated, the Citrix ingress controller automatically configures Citrix ADC-specfic configuration in the tier-1 Citrix ADC VPX. + +#### rewritepolicies CRD: + +In kubernetes environment, to deploy specific layer 7 policies to handle scenarios such as, redirecting HTTP traffic to a specific URL, blocking a set of IP addresses to mitigate DDoS attacks, imposing HTTP to HTTPS and so on, requires you to add appropriate libraries within the microservices and manually configure the policies. Instead, you can use the [Rewrite and Responder features](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/crd/rewrite-responder-policies-deployment.yaml) provided by the Ingress Citrix ADC device to deploy these policies. + +Example files: [target-url-rewrite.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/target-url-rewrite.yaml) + +#### wafs CRD: + +[WAF CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/waf.md) can be used to configure the web application firewall policies with the Citrix ingress controller on the Citrix ADC VPX, MPX, SDX, and CPX. The WAF CRD enables communication between the Citrix ingress controller and Citrix ADC for enforcing web application firewall policies. + +In a Kubernetes deployment, you can enforce a web application firewall policy to protect the server using the WAF CRD. For more information about web application firewall, see [Web application security](https://docs.citrix.com/en-us/citrix-adc/13/application-firewall/introduction/web-application-security.html). + +Example files: [wafhtmlxsssql.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/wafhtmlxsssql.yaml) + +#### apigateway CRD: + +API Gateway CRD is used to configure gitops framework on citrix API gateway. This solution enables citrix ingress controller to generate API gateway configurations out of Open API Specification documents checked in to git repository by API developers and designers. + +Example files: [api-gateway-crd-instance.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/api-gateway-crd-instance.yaml) +#### bots CRD: + +[BOT CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/bot.md) You can use Bot CRDs to configure the bot management policies with the Citrix ingress controller on the Citrix ADC VPX. The Bot custom resource definition enables communication between the Citrix ingress controller and Citrix ADC for enforcing bot management policies. + +In a Kubernetes deployment, you can enforce bot management policy on therequests and responses from and to the server using the Bot CRDs. For more information on security vulnerabilities, see [Bot Detection](https://docs.citrix.com/en-us/citrix-adc/current-release/bot-management/bot-detection.html). + +Example files: [botallowlist.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/botallowlist.yaml) + +#### CORS CRD: + +[CORS CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/cors.md) Cross-origin resource sharing (CORS) is a mechanism allows a web application running under one domain to securely access resources in another domain. You can configure CORS policies on Citrix ADC using Citrix ingress controller to allow one domain (the origin domain) to call APIs in another domain. For more information, see the [cross-origin resource sharing CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/cors.md) documentation. + +Example files: [cors-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/corspolicy-example.yaml) + +#### APPQOE CRD: + +[APPQOE CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/appqoe.md) When a Citrix ADC appliance receives an HTTP request and forwards it to a back-end server, sometimes there may be connection failures with the back-end server. You can configure the request-retry feature on Citrix ADC to forward the request to the next available server, instead of sending the reset to the client. Hence, the client saves round trip time when Citrix ADC initiates the same request to the next available service. +For more information, see the AppQoE support documentation. [Appqoe resource sharing CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/appqoe.md) documentation. + +Example files: [appqoe-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/appqoe_example.yaml) + +#### WILDCARDDNS CRD: + +[WILDCARDDNS CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/wildcarddns.md) Wildcard DNS domains are used to handle requests for nonexistent domains and subdomains. In a zone, use wildcard domains to redirect queries for all nonexistent domains or subdomains to a particular server, instead of creating a separate Resource Record (RR) for each domain. The most common use of a wildcard DNS domain is to create a zone that can be used to forward mail from the internet to some other mail system. +For more information, see the Wild card DNS domains support documentation. [Wildcard DNS Entry CRD](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/crds/wildcarddns.md) documentation. + +Example files: [wildcarddns-crd.yaml](https://github.com/citrix/citrix-helm-charts/tree/master/example-crds/wildcarddns-example.yaml) + +### Tolerations + +Taints are applied on cluster nodes whereas tolerations are applied on pods. Tolerations enable pods to be scheduled on node with matching taints. For more information see [Taints and Tolerations in Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + +Toleration can be applied to Citrix ingress controller pod using `tolerations` argument while deploying CIC using helm chart. This argument takes list of tolerations that user need to apply on the CIC pods. + +For example, following command can be used to apply toleration on the CIC pod: + +``` +helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,tolerations[0].key=,tolerations[0].value=,tolerations[0].operator=,tolerations[0].effect= +``` + +Here tolerations[0].key, tolerations[0].value and tolerations[0].effect are the key, value and effect that was used while tainting the node. +Effect represents what should happen to the pod if the pod don't have any matching toleration. It can have values `NoSchedule`, `NoExecute` and `PreferNoSchedule`. +Operator represents the operation to be used for key and value comparison between taint and tolerations. It can have values `Exists` and `Equal`. The default value for operator is `Equal`. + + + +### Configuration + +The following table lists the mandatory and optional parameters that you can configure during installation: + +| Parameters | Mandatory or Optional | Default value | Description | +| --------- | --------------------- | ------------- | ----------- | +| license.accept | Mandatory | no | Set `yes` to accept the CIC end user license agreement. | +| imageRegistry | Mandatory | `quay.io` | The Citrix ingress controller image registry | +| imageRepository | Mandatory | `citrix/citrix-k8s-ingress-controller` | The Citrix ingress controller image repository | +| imageTag | Mandatory | `1.27.15` | The Citrix ingress controller image tag | +| pullPolicy | Mandatory | IfNotPresent | The CIC image pull policy. | +| imagePullSecrets | Optional | N/A | Provide list of Kubernetes secrets to be used for pulling the images from a private Docker registry or repository. For more information on how to create this secret please see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). | +| nameOverride | Optional | N/A | String to partially override deployment fullname template with a string (will prepend the release name) | +| fullNameOverride | Optional | N/A | String to fully override deployment fullname template with a string | +| resources | Optional | {} | CPU/Memory resource requests/limits for Citrix Ingress Controller container | +| adcCredentialSecret | Mandatory | N/A | The secret key to log on to the Citrix ADC VPX or MPX. For information on how to create the secret keys, see [Prerequisites](#prerequistes). | +| secretStore.enabled | Optional | False | Set to "True" for deploying other Secret Provider classes | +| secretStore.username | Optional | N/A | if `secretStore.enabled`, `username` of ADC will be fetched from the Secret Provider | +| secretStore.password | Optional | N/A | if `secretStore.enabled`, `password` of ADC will be fetched from the Secret Provider | +| nsIP | Mandatory | N/A | The IP address of the Citrix ADC device. For details, see [Prerequisites](#prerequistes). | +| nsVIP | Optional | N/A | The Virtual IP address on the Citrix ADC device. | +| nsSNIPS | Optional | N/A | The list of subnet IPAddresses on the Citrix ADC device, which will be used to create PBR Routes instead of Static Routes [PBR support](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/docs/how-to/pbr.md) | +| nsPort | Optional | 443 | The port used by CIC to communicate with Citrix ADC. You can use port 80 for HTTP. | +| nsProtocol | Optional | HTTPS | The protocol used by CIC to communicate with Citrix ADC. You can also use HTTP on port 80. | +| nsEnableLabel | Optional | True | Set to true for plotting Servicegraph. Ensure ``analyticsConfig` are set. | +| nitroReadTimeout | Optional | 20 | The nitro Read timeout in seconds, defaults to 20 | +| logLevel | Optional | DEBUG | The loglevel to control the logs generated by CIC. The supported loglevels are: CRITICAL, ERROR, WARNING, INFO, DEBUG and TRACE. For more information, see [Logging](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/configure/log-levels.md).| +| jsonLog | Optional | false | Set this argument to true if log messages are required in JSON format | +| nsConfigDnsRec | Optional | false | To enable/disable DNS address Record addition in ADC through Ingress | +| nsSvcLbDnsRec | Optional | false | To enable/disable DNS address Record addition in ADC through Type Load Balancer Service | +| nsDnsNameserver | Optional | N/A | To add DNS Nameservers in ADC | +| optimizeEndpointBinding | Optional | false | To enable/disable binding of backend endpoints to servicegroup in a single API-call. Recommended when endpoints(pods) per application are large in number. Applicable only for Citrix ADC Version >=13.0-45.7 | +| kubernetesURL | Optional | N/A | The kube-apiserver url that CIC uses to register the events. If the value is not specified, CIC uses the [internal kube-apiserver IP address](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod). | +| clusterName | Optional | N/A | The unique identifier of the kubernetes cluster on which the CIC is deployed. Used in multi-cluster deployments. | +| ingressClass | Optional | N/A | If multiple ingress load balancers are used to load balance different ingress resources. You can use this parameter to specify CIC to configure Citrix ADC associated with specific ingress class. For more information on Ingress class, see [Ingress class support](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/configure/ingress-classes/). For Kubernetes version >= 1.19, this will create an IngressClass object with the name specified here | +| setAsDefaultIngressClass | Optional | False | Set the IngressClass object as default ingress class. New Ingresses without an "ingressClassName" field specified will be assigned the class specified in ingressClass. Applicable only for kubernetes versions >= 1.19 | +| serviceClass | Optional | N/A | By Default ingress controller configures all TypeLB Service on the ADC. You can use this parameter to finetune this behavior by specifing CIC to only configure TypeLB Service with specific service class. For more information on Service class, see [Service class support](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/configure/service-classes/). | +| nodeWatch | Optional | false | Use the argument if you want to automatically configure network route from the Ingress Citrix ADC VPX or MPX to the pods in the Kubernetes cluster. For more information, see [Automatically configure route on the Citrix ADC instance](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/network/staticrouting/#automatically-configure-route-on-the-citrix-adc-instance). | +| cncPbr | Optional | False | Use this argument to inform CIC that Citrix Node Controller(CNC) is configuring Policy Based Routes(PBR) on the Citrix ADC. For more information, see [CNC-PBR-SUPPORT](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/docs/how-to/pbr.md#configure-pbr-using-the-citrix-node-controller) | +| defaultSSLCertSecret | Optional | N/A | Provide Kubernetes secret name that needs to be used as a default non-SNI certificate in Citrix ADC. | +| podIPsforServiceGroupMembers | Optional | False | By default Citrix Ingress Controller will add NodeIP and NodePort as service group members while configuring type LoadBalancer Services and NodePort services. This variable if set to `True` will change the behaviour to add pod IP and Pod port instead of nodeIP and nodePort. Users can set this to `True` if there is a route between ADC and K8s clusters internal pods either using feature-node-watch argument or using Citrix Node Controller. | +| ignoreNodeExternalIP | Optional | False | While adding NodeIP, as Service group members for type LoadBalancer services or NodePort services, Citrix Ingress Controller has a selection criteria whereas it choose Node ExternalIP if available and Node InternalIP, if Node ExternalIP is not present. But some users may want to use Node InternalIP over Node ExternalIP even if Node ExternalIP is present. If this variable is set to `True`, then it prioritises the Node Internal IP to be used for service group members even if node ExternalIP is present | +| nsHTTP2ServerSide | Optional | OFF | Set this argument to `ON` for enabling HTTP2 for Citrix ADC service group configurations. | +| nsCookieVersion | Optional | 0 | Specify the persistence cookie version (0 or 1). | +| ipam | Optional | False | Set this argument if you want to use the IPAM controller to automatically allocate an IP address to the service of type LoadBalancer. | +| disableAPIServerCertVerify | Optional | False | Set this parameter to True for disabling API Server certificate verification. | +| logProxy | Optional | N/A | Provide Elasticsearch or Kafka or Zipkin endpoint for Citrix observability exporter. | +| entityPrefix | Optional | k8s | The prefix for the resources on the Citrix ADC VPX/MPX. | +| updateIngressStatus | Optional | True | Set this argurment if `Status.LoadBalancer.Ingress` field of the Ingress resources managed by the Citrix ingress controller needs to be updated with allocated IP addresses. For more information see [this](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/configure/ingress-classes.md#updating-the-ingress-status-for-the-ingress-resources-with-the-specified-ip-address). | +| routeLabels | Optional | N/A | You can use this parameter to provide the route labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster. | +| namespaceLabels | Optional | N/A | You can use this parameter to provide the namespace labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster. | +| podAnnotations | Optional | N/A | Map of annotations to add to the pods. | +| affinity | Optional | N/A | Affinity labels for pod assignment. | +| exporter.required | Optional | false | Use the argument, if you want to run the [Exporter for Citrix ADC Stats](https://github.com/citrix/citrix-adc-metrics-exporter) along with CIC to pull metrics for the Citrix ADC VPX or MPX| +| exporter.imageRegistry | Optional | `quay.io` | The Exporter for Citrix ADC Stats image registry | +| exporter.imageRepository | Optional | `citrix/citrix-adc-metrics-exporter` | The Exporter for Citrix ADC Stats image repository | +| exporter.imageTag | Optional | `1.4.9` | The Exporter for Citrix ADC Stats image tag | +| exporter.pullPolicy | Optional | IfNotPresent | The Exporter image pull policy. | +| exporter.ports.containerPort | Optional | 8888 | The Exporter container port. | +| exporter.resources | Optional | {} | CPU/Memory resource requests/limits for Metrics exporter container | +| exporter.extraVolumeMounts | Optional | [] | Specify the Additional VolumeMounts to be mounted in Exporter container. Specify the volumes in `extraVolumes` | +| openshift | Optional | false | Set this argument if OpenShift environment is being used. | +| disableOpenshiftRoutes | Optional | false | By default Openshift routes are processed in openshift environment, this variable can be used to disable Ingress controller processing the openshift routes. | +| nodeSelector.key | Optional | N/A | Node label key to be used for nodeSelector option in CIC deployment. | +| nodeSelector.value | Optional | N/A | Node label value to be used for nodeSelector option in CIC deployment. | +| tolerations | Optional | N/A | Specify the tolerations for the CIC deployment. | +| crds.install | Optional | False | Unset this argument if you don't want to install CustomResourceDefinitions which are consumed by CIC. | +| crds.retainOnDelete | Optional | false | Set this argument if you want to retain CustomResourceDefinitions even after uninstalling CIC. This will avoid data-loss of Custom Resource Objects created before uninstallation. | +| analyticsConfig.required | Mandatory | false | Set this to true if you want to configure Citrix ADC to send metrics and transaction records to analytics . | +| analyticsConfig.distributedTracing.enable | Optional | false | Set this value to true to enable OpenTracing in Citrix ADC. | +| analyticsConfig.distributedTracing.samplingrate | Optional | 100 | Specifies the OpenTracing sampling rate in percentage. | +| analyticsConfig.endpoint.server | Optional | N/A | Set this value as the IP address or DNS address of the analytics server. | +| analyticsConfig.endpoint.service | Optional | N/A | Set this value as the IP address or service name with namespace of the analytics service deployed in k8s environment. Format: namespace/servicename | +| analyticsConfig.timeseries.port | Optional | 30002 | Specify the port used to expose analytics service outside cluster for timeseries endpoint. | +| analyticsConfig.timeseries.metrics.enable | Optional | False | Set this value to true to enable sending metrics from Citrix ADC. | +| analyticsConfig.timeseries.metrics.mode | Optional | avro | Specifies the mode of metric endpoint. | +| analyticsConfig.timeseries.auditlogs.enable | Optional | false | Set this value to true to export audit log data from Citrix ADC. | +| analyticsConfig.timeseries.events.enable | Optional | false | Set this value to true to export events from the Citrix ADC. | +| analyticsConfig.transactions.enable | Optional | false | Set this value to true to export transactions from Citrix ADC. | +| analyticsConfig.transactions.port | Optional | 30001 | Specify the port used to expose analytics service outside cluster for transaction endpoint. | +| nsLbHashAlgo.required | Optional | false | Set this value to set the LB consistent hashing Algorithm | +| nsLbHashAlgo.hashFingers | Optional | 256 | Specifies the number of fingers to be used for hashing algorithm. Possible values are from 1 to 1024, Default value is 256 | +| nsLbHashAlgo.hashAlgorithm | Optional | 'default' | Specifies the supported algorithm. Supported algorithms are "default", "jarh", "prac", Default value is 'default' | +| extraVolumeMounts | Optional | [] | Specify the Additional VolumeMounts to be mounted in CIC container | +| extraVolumes | Optional | [] | Specify the Additional Volumes for additional volumeMounts | + +Alternatively, you can define a YAML file with the values for the parameters and pass the values while installing the chart. + +For example: + ``` + helm install my-release citrix/citrix-ingress-controller -f values.yaml + ``` + +> **Tip:** +> +> The [values.yaml](https://github.com/citrix/citrix-helm-charts/blob/master/citrix-ingress-controller/values.yaml) contains the default values of the parameters. + +> **Note:** +> +> Please provide frontend-ip (VIP) in your application ingress yaml file. For more info refer [this](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/configure/annotations.md). + +## Route Addition in MPX/VPX +For seamless functioning of services deployed in the Kubernetes cluster, it is essential that Ingress NetScaler device should be able to reach the underlying overlay network over which Pods are running. +`feature-node-watch` knob of Citrix Ingress Controller can be used for automatic route configuration on NetScaler towards the pod network. Refer [Static Route Configuration](https://github.com/citrix/citrix-k8s-ingress-controller/blob/master/docs/network/staticrouting.md) for further details regarding the same. +By default, `feature-node-watch` is false. It needs to be explicitly set to true if auto route configuration is required. + +This can also be achieved by deploying [Citrix Node Controller](https://github.com/citrix/citrix-k8s-node-controller). + +If your deployment uses one single Citrix ADC Device to loadbalance between multiple k8s clusters, there is a possibilty of CNI subnets to overlap, causing the above mentioned static routing to fail due to route conflicts. In such deployments [Policy Based Routing(PBR)] (https://docs.citrix.com/en-us/citrix-adc/current-release/networking/ip-routing/configuring-policy-based-routes/configuring-policy-based-routes-pbrs-for-ipv4-traffic.html) can be used instead. This would require you to provide one or more subnet IP Addresses unique for each kubernetes cluster either via Environment variable or Configmap, see [PBR Support](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/docs/how-to/pbr.md) + + Use the following command to provide subnet IPAddresses(SNIPs) to configure Policy Based Routes(PBR) on the Citrix ADC + + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,nsSNIPS='[\, \, ...]' + ``` + + [Citrix Node Controller](https://github.com/citrix/citrix-k8s-node-controller) by default also adds static routes while creating the VXLAN tunnel. To use [Policy Based Routing(PBR)] (https://docs.citrix.com/en-us/citrix-adc/current-release/networking/ip-routing/configuring-policy-based-routes/configuring-policy-based-routes-pbrs-for-ipv4-traffic.html) to avoid static route clash, both Citrix Node Controller and Citrix Ingress Controller has to work in conjunction and has to be started with specific arguments. For more details refer [CNC-PBR-SUPPORT](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/docs/how-to/pbr.md#configure-pbr-using-the-citrix-node-controller). + + Use the following command to inform Citrix Ingress Controller that Citrix Node Controller is configuring Policy Based Routes(PBR) on the Citrix ADC + + ``` + helm install my-release citrix/citrix-ingress-controller --set nsIP=,license.accept=yes,adcCredentialSecret=,clusterName=,cncPbr= + ``` + +For configuring static routes manually on Citrix ADC VPX or MPX to reach the pods inside the cluster follow: +### For Kubernetes: +1. Obtain podCIDR using below options: + ``` + kubectl get nodes -o yaml | grep podCIDR + ``` + * podCIDR: 10.244.0.0/24 + * podCIDR: 10.244.1.0/24 + * podCIDR: 10.244.2.0/24 + +2. Log on to the Citrix ADC instance. + +3. Add Route in Netscaler VPX/MPX + ``` + add route + ``` +4. Ensure that Ingress MPX/VPX has a SNIP present in the host-network (i.e. network over which K8S nodes communicate with each other. Usually eth0 IP is from this network). + + Example: + * Node1 IP = 192.0.2.1 + * podCIDR = 10.244.1.0/24 + * add route 10.244.1.0 255.255.255.0 192.0.2.1 + +### For OpenShift: +1. Use the following command to get the information about host names, host IP addresses, and subnets for static route configuration. + ``` + oc get hostsubnet + ``` + +2. Log on to the Citrix ADC instance. + +3. Add the route on the Citrix ADC instance using the following command. + ```add route ``` + +4. Ensure that Ingress MPX/VPX has a SNIP present in the host-network (i.e. network over which OpenShift nodes communicate with each other. Usually eth0 IP is from this network). + + For example, if the output of the `oc get hostsubnet` is as follows: + * oc get hostsubnet + + NAME HOST HOST IP SUBNET + os.example.com os.example.com 192.0.2.1 10.1.1.0/24 + + * The required static route is as follows: + + add route 10.1.1.0 255.255.255.0 192.0.2.1 + +## Uninstalling the Chart +To uninstall/delete the ```my-release``` deployment: + + ``` + helm delete my-release + ``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Related documentation + +- [Citrix ingress controller Documentation](https://developer-docs.citrix.com/projects/citrix-k8s-ingress-controller/en/latest/) +- [Citrix ingress controller GitHub](https://github.com/citrix/citrix-k8s-ingress-controller) diff --git a/packages/citrix-ingress-controller/generated-changes/overlay/app-readme.md b/charts/citrix/citrix-ingress-controller/app-readme.md similarity index 100% rename from packages/citrix-ingress-controller/generated-changes/overlay/app-readme.md rename to charts/citrix/citrix-ingress-controller/app-readme.md diff --git a/packages/citrix-ingress-controller/generated-changes/overlay/questions.yml b/charts/citrix/citrix-ingress-controller/questions.yml similarity index 100% rename from packages/citrix-ingress-controller/generated-changes/overlay/questions.yml rename to charts/citrix/citrix-ingress-controller/questions.yml diff --git a/charts/citrix/citrix-ingress-controller/templates/NOTES.txt b/charts/citrix/citrix-ingress-controller/templates/NOTES.txt new file mode 100644 index 000000000..4d07f639f --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/NOTES.txt @@ -0,0 +1,15 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get {{ .Release.Name }} + + +To delete : + helm delete {{ .Release.Name }} + + diff --git a/charts/citrix/citrix-ingress-controller/templates/_helpers.tpl b/charts/citrix/citrix-ingress-controller/templates/_helpers.tpl new file mode 100644 index 000000000..efca8083c --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/_helpers.tpl @@ -0,0 +1,94 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Analytics Server IP or DNS +*/}} +{{- define "analytics.server" -}} +{{- if .Values.analyticsConfig.endpoint.server -}} +{{- printf .Values.analyticsConfig.endpoint.server -}} +{{- else -}} +{{- $addresses := first (first (lookup "v1" "Node" "" "").items).status.addresses -}} +{{- printf "%s" ($addresses).address -}} +{{- end -}} +{{- end -}} + + + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "citrix-ingress-controller.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "citrix-ingress-controller.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "exporter.fullname" -}} +{{- $name := default .Chart.Name "exporter" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "servicemonitor.fullname" -}} +{{- $name := default .Chart.Name "citrix-adc-servicemonitor" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "servicemonitorlabel" -}} +{{- $name := default .Chart.Name "citrix-adc-svcmon" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "cicconfigmap.fullname" -}} +{{- $name := default .Chart.Name "cic-configmap" .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "citrix-ingress-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "citrix-ingress-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "citrix-ingress-controller.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/citrix/citrix-ingress-controller/templates/cic_crds.yaml b/charts/citrix/citrix-ingress-controller/templates/cic_crds.yaml new file mode 100644 index 000000000..6ff58466f --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/cic_crds.yaml @@ -0,0 +1,2515 @@ +{{- if .Values.crds.install }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: rewritepolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: rewritepolicy + plural: rewritepolicies + singular: rewritepolicy + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + rewrite-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to rewrite policy.' + type: array + items: + type: string + maxLength: 127 + goto-priority-expression: + description: 'Expression or other value specifying the next policy to be + evaluated if the current policy evaluates to TRUE. + Specify one of the following values: + * NEXT - Evaluate the policy with the next higher priority number. + * END - End policy evaluation. + Default value of goto-priority-expression: END' + type: string + maxLength: 1499 + logpackets: + type: object + description: 'Adds an audit message action. + The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + rewrite-policy: + type: object + properties: + rewrite-criteria: + description: 'Expression against which traffic is evaluated.' + type: string + maxLength: 1299 + default-action: + description: 'Action to perform if the result of policy evaluation is undefined (UNDEF). + An UNDEF event indicates an internal error condition.' + type: string + maxLength: 77 + enum: ['NOREWRITE', 'RESET', 'DROP'] + operation: + description: 'Type of user-defined rewrite action.' + type: string + enum: ["noop", "delete", "insert_http_header", "delete_http_header", + "corrupt_http_header", "insert_before", "insert_after", "replace", + "replace_http_res", "delete_all", "replace_all", "insert_before_all", + "insert_after_all", "clientless_vpn_encode", "clientless_vpn_encode_all", + "clientless_vpn_decode", "clientless_vpn_decode_all", "insert_sip_header", + "delete_sip_header", "corrupt_sip_header", "replace_sip_res", "replace_diameter_header_field", + "replace_dns_header_field", "replace_dns_answer_section"] + target: + description: 'Default syntax expression that specifies which part of the request or response to rewrite.' + type: string + maxLength: 1229 + modify-expression: + description: 'Default syntax expression that specifies the content to insert into the request + or response at the specified location, or that replaces the specified string.' + type: string + maxLength: 7991 + multiple-occurence-modify: + description: 'Search facility that is used to match multiple strings in the request or response.' + type: string + maxLength: 171 + additional-multiple-occurence-modify: + description: 'Specify additional criteria to refine the results of the search. + Always starts with the "extend(m,n)" operation, where "m" specifies number of bytes to the left of selected data + and "n" specifies number of bytes to the right of selected data. + You can use refineSearch only on body expressions, and only when rewrite-criteria is any one of this: + INSERT_BEFORE_ALL, INSERT_AFTER_ALL, REPLACE_ALL, and DELETE_ALL.' + type: string + maxLength: 1299 + direction: + description: 'Bind point to which to bind the policy.' + type: string + enum: ["REQUEST","RESPONSE"] + comment: + description: 'Any comments to preserve information about this rewrite policy.' + type: string + maxLength: 255 + required: [rewrite-criteria, operation, target, direction] + required: [rewrite-policy] + + responder-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to responder policy.' + type: array + items: + type: string + maxLength: 127 + goto-priority-expression: + description: 'Expression or other value specifying the next policy to be + evaluated if the current policy evaluates to TRUE. + Specify one of the following values: + * NEXT - Evaluate the policy with the next higher priority number. + * END - End policy evaluation. + Default value of goto-priority-expression: END' + type: string + maxLength: 1499 + logpackets: + type: object + description: 'Adds an audit message action. + The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", + "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + responder-policy: + type: object + properties: + redirect: + type: object + description: 'Use this option when you want to Redirect the request when request matches to policy.' + properties: + url: + description: 'URL on which you want to redirect the request.' + type: string + maxLength: 7991 + redirect-status-code: + description: 'HTTP response status code, for example 200, 302, 404, etc.' + type: integer + minimum: 100 + maximum: 599 + redirect-reason: + description: 'Expression specifying the reason for redirecting the request.' + type: string + maxLength: 7991 + required: [url] + respondwith: + type: object + description: 'Use this parameter when you want to respond to the request when request matches to policy.' + properties: + http-payload-string: + description: 'Expression that you want to sent as response to the request.' + type: string + maxLength: 7991 + required: [http-payload-string] + noop: + type: string + description: 'Use this option when you want to send the request to the protected server instead of + responding to it when request matches to policy.' + properties: + target: + description: 'Default syntax expression that specifies to perform noop operation on' + type: string + maxLength: 1229 + reset: + type: string + description: 'Use this option when you want to Reset the client connection by closing it when request matches to policy.' + properties: + drop: + type: string + description: 'Use this option when you want to drop the request without sending a response to the user when request matches to policy.' + properties: + respond-criteria: + description: 'Default syntax expression that the policy uses to determine whether to respond to the specified request.' + type: string + maxLength: 1299 + default-action: + description: 'Action to perform if the result of policy evaluation is undefined (UNDEF). + An UNDEF event indicates an internal error condition.' + type: string + maxLength: 77 + enum: ['NOOP', 'RESET', 'DROP'] + comment: + description: 'Any comments to preserve information about this responder policy.' + type: string + maxLength: 255 + required: [respond-criteria] + oneOf: [required: [redirect], required: [respondwith], required: [noop], required: [reset], required: [drop]] + required: [responder-policy] + + dataset: + type: array + items: + type: object + properties: + name: + description: 'Name of the dataset.' + type: string + maxLength: 32 + type: + description: 'Type of value to bind to the dataset.' + type: string + enum: ["ipv4", "number", "ipv6", "ulong", "double", "mac"] + comment: + description: 'Any comments to preserve information about this dataset.' + type: string + maxLength: 255 + values: + description: 'Value of the specified type that is associated with this dataset.' + type: array + items: + type: string + required: [name, type, values] + + patset: + type: array + items: + type: object + properties: + name: + description: 'Name of the Patset.' + type: string + maxLength: 32 + comment: + description: 'Any comments to preserve information about this patset.' + type: string + maxLength: 255 + values: + description: 'String of characters that constitutes a pattern and is associated with this patset.' + type: array + items: + type: string + required: [name, values] + + stringmap: + type: array + items: + type: object + properties: + name: + description: 'Name of the Stringmap.' + type: string + maxLength: 32 + comment: + description: 'Any comments to preserve information about this stringmap.' + type: string + maxLength: 255 + values: + description: 'List of (key,value) pairs to be bound to this string map.' + type: array + items: + type: object + properties: + key: + description: 'Character string constituting the key to be bound to this string map.' + type: string + maxLength: 2047 + value: + description: 'Character string constituting the value associated with the key.' + type: string + maxLength: 2047 + required: [name, values] + + httpcallout_policy: + type: array + items: + type: object + properties: + name: + description: 'httpcallout name' + type: string + maxLength: 32 + server_ip: + description: 'IP Address of the server(callout agent) to which the callout is sent.' + type: string + server_port: + description: 'Port of the server(callout agent) to which the callout is sent.' + type: integer + minimum: 1 + maximum: 65535 + http_method: + description: |+ + 'Method used in the HTTP request that this callout sends. + Default http method is GET' + type: string + enum: ['GET', 'POST'] + host_expr: + description: |+ + 'String expression to configure the Host header. Can contain a literal value + (for example, 10.101.10.11) or a derived value (for example, http.req.header("Host")). + The literal value can be an IP address or a fully qualified domain name. Mutually + exclusive with the full HTTP request expression.' + type: string + maxLength: 255 + url_stem_expr: + description: |+ + 'String expression for generating the URL stem. Can contain a literal string + (for example, "/mysite/index.html") or an expression that derives the value + (for example, http.req.url).' + type: string + maxLength: 8191 + headers: + type: array + description: |+ + 'One or more headers to insert into the HTTP request. Each header is represented by + name and expr, where expr is an expression that is evaluated at runtime to provide + the value for the named header. You can configure a maximum of eight headers for + an HTTP callout.' + items: + type: object + properties: + name: + description: 'header name' + type: string + expr: + description: 'header expression' + type: string + parameters: + type: array + description: |+ + 'One or more query parameters to insert into the HTTP request URL (for a GET request) + or into the request body (for a POST request). Each parameter is represented by + name and expr, where expr is an expression that is evaluated at run time to provide + the value for the named parameter (name=value). The parameter values are URL encoded.' + items: + type: object + properties: + name: + description: 'parameter name' + type: string + expr: + description: 'parameter expression' + type: string + body_expr: + description: |+ + 'An advanced string expression for generating the body of the request. + The expression can contain a literal string or an expression that derives + the value (for example, client.ip.src).' + type: string + full_req_expr: + description: |+ + 'Exact HTTP request, in the form of an expression, which the Citrix ADC sends + to the callout agent. The request expression is constrained by the feature + for which the callout is used. For example, an HTTP.RES expression cannot be + used in a request-time policy bank or in a TCP content switching policy bank.' + type: string + scheme: + description: |+ + 'Type of scheme for the callout server. + Default scheme is HTTP' + type: string + enum: ['HTTP', 'HTTPS'] + cache_for_secs: + description: |+ + 'Duration, in seconds, for which the callout response is cached. + The cached responses are stored in an integrated caching content + group named "calloutContentGroup". If no duration is configured, + the callout responses will not be cached unless normal caching + configuration is used to cache them. This parameter takes precedence over any + normal caching configuration that would otherwise apply to these responses.' + type: integer + minimum: 1 + maximum: 31536000 + return_type: + description: |+ + 'Type of data that the target callout agent returns in response to the callout + Available settings function as follows: + * TEXT - Treat the returned value as a text string. + * NUM - Treat the returned value as a number. + * BOOL - Treat the returned value as a Boolean value.' + type: string + enum: ['TEXT', 'NUM', 'BOOL'] + result_expr: + description: |+ + 'Expression that extracts the callout results from the response sent by the HTTP callout + agent. Must be a response based expression, that is, it must begin with HTTP.RES. The + operations in this expression must match the return type. For example, if you configure + a return type of TEXT, the result expression must be a text based expression. If the + return type is NUM, the result expression (resultExpr) must return a numeric value, + as in the following example: http.res.body(10000).length.' + type: string + maxLength: 8191 + comment: + description: 'Any comments to preserve information about this HTTP callout.' + type: string + maxLength: 255 + allOf: + - properties: + required: [name, server_ip, server_port] + - properties: + oneOf: + - properties: + required: [full_req_expr] + - properties: + anyOf: + - properties: + required: [http_method] + - properties: + required: [host_expr] + - properties: + required: [url_stem_expr] + - properties: + required: [headers] + - properties: + required: [parameters] + - properties: + required: [body_expr] + anyOf: [required: [rewrite-policies], required: [responder-policies]] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ratelimits.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: ratelimit + plural: ratelimits + singular: ratelimit + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the ratelimit policies are applied.' + type: array + items: + type: string + maxLength: 127 + selector_keys: + type: object + description: 'Traffic match criteria to which apply above rate-limit/throttling. All keys are applied as AND condition. If no keys are specified, rate-limit applies at service level' + properties: + basic: + type: object + description: "Basic traffic stream selection criteria to which to apply the ratelimit" + properties: + path: + type: array + description: "api resource path prefix match. e.g. /api/v1/products" + items: + type: string + method: + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header_name: + description: "HTTP header that identifies the unique API client for e.g. X-apikey" + type: string + per_client_ip: + description: "Setting this applies the throttling limit to each unique Client IP address accessing the API resource" + type: boolean + req_threshold: + description: 'Max requests per timeslice units to be allowed' + type: integer + timeslice: + description: 'Timeslice in miliseconds in multiple of 10. Defaults to 1000 miliseconds' + type: integer + limittype: + description: "Burst mode or smooth. Defaults to smooth limittype if not specified" + type: string + enum: ['BURSTY','SMOOTH'] + throttle_action: + type: string + enum: ['DROP', 'RESET','REDIRECT', 'RESPOND'] + description: "Drop will drop the requests exceeding limits, RESET will reset the client connection, Redirect will redirect to specified URL, respond will respond with 429 'Exceeded allowed rate of requests'" + redirect_url: + type: string + description: "Redirect-URL" + logpackets: + type: object + description: 'Adds an audit message action. The action specifies whether to log the message, and to which log.' + properties: + logexpression: + description: 'Default-syntax expression that defines the format and content of the log message.' + type: string + maxLength: 7991 + loglevel: + description: 'Audit log level, which specifies the severity level of the log message being generated.' + type: string + enum: ["EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFORMATIONAL", "DEBUG"] + required: [logexpression, loglevel] + required: [req_threshold] +--- +#Sample CRD instance + +#apiVersion: citrix.com/v1 +#description: VIP for apache service +#kind: vip +#metadata: +# name: service-apache +# namespace: default +#spec: +# description: VIP for the apache Service +# ipaddress: 10.99.98.90 +# kind: service +# name: apache + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vips.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: vip + plural: vips + singular: vip + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + additionalPrinterColumns: + - jsonPath: .spec.ipaddress + name: VIP + type: string + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + ipaddress: + type: string + name: + type: string + kind: + type: string + enum: ["service", "ingress"] + description: + type: string + range-name: + type: string +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: authpolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: authpolicy + plural: authpolicies + singular: authpolicy + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: 'Current Status of the CRD' + jsonPath: .status.state + - name: Message + type: string + description: 'Status Message' + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: |+ + 'Name of the services for which the policies applied' + type: array + items: + type: string + maxLength: 63 + authentication_mechanism: + type: object + description: |+ + 'Authentication mechanism. Options: using forms or using request header. + Default is Authentication using request header, when no option is specified' + properties: + using_request_header: + description: |+ + 'Enable user authentication using request header. Use when the credentials + or api keys are passed in a header. For example, when using Basic, Digest, + Bearer authentication or api keys. + When authentication using forms is provided, this is set to OFF' + + type: string + using_forms: + type: object + description: 'Enables authentication using forms. Use with user/web authentication.' + properties: + authentication_host: + description: |+ + 'Fully qualified domain name (FQDN) for authentication. + This FQDN should be unique and should resolve to frontend IP of + ADC with Ingress/service type LoadBalancer (or) vip of Listener CRD' + type: string + maxLength: 255 + authentication_host_cert: + description: |+ + 'Name of the SSL certificate to be used with authentication_host. + This certificate is mandatory while using_forms' + type: object + properties: + tls_secret: + type: string + description: 'Name of the Kubernetes Secret of type tls referring to Certificate' + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + preconfigured: + type: string + maxLength: 63 + description: |+ + 'Preconfigured SSL certkey name on ADC with the + certificate and key already added on ADC' + oneOf: + - properties: + required: [tls_secret] + - properties: + required: [preconfigured] + ingress_name: + description: |+ + 'Ingress name for which the authentication using forms + is applicable.' + type: string + maxLength: 63 + lb_service_name: + description: |+ + 'Service of type LoadBalancer for which the authentication using forms + is applicable.' + type: string + maxLength: 63 + listener_name: + description: |+ + 'Listener CRD name for which the authentication using forms is applicable.' + type: string + maxLength: 63 + vip: + description: |+ + 'Frontend IP of ingress for which the authentication + using forms is applicable. This refers to frontend-ip provided + with Ingress. It is suggested to use vip, if more than one Ingress + resource use the same frontend-ip' + type: string + required: [authentication_host, authentication_host_cert] + oneOf: + - properties: + required: [ingress_name] + - properties: + required: [lb_service_name] + - properties: + required: [listener_name] + - properties: + required: [vip] + oneOf: + - properties: + using_request_header: + enum: ['ON'] + required: [using_request_header] + - properties: + required: [using_forms] + + authentication_providers: + description: |+ + 'Authentication Configuration for required authentication providers/schemes. + One or more of these can be created' + type: array + items: + description: 'Create config for a single authentication provider of a particular type' + type: object + properties: + name: + description: 'Name for this provider, has to be unique, referenced by authentication policies' + type: string + maxLength: 127 + + oauth: + description: 'Authentication provided by external oAuth provider' + type: object + properties: + issuer: + description: 'Identity of the server whose tokens are to be accepted' + type: string + maxLength: 127 + audience: + description: 'Audience for which token sent by Authorization server is applicable' + type: array + items: + type: string + maxLength: 127 + jwks_uri: + description: |+ + 'URL of the endpoint that contains JWKs (Json Web Key) for + JWT (Json Web Token) verification' + type: string + maxLength: 127 + introspect_url: + description: ' URL of the introspection server' + type: string + maxLength: 127 + client_credentials: + description: |+ + 'secrets object that contains Client Id and secret as known + to Introspection server' + type: string + maxLength: 253 + token_in_hdr: + description: |+ + 'custom header name where token is present, + default is Authorization header' + type: array + items: + type: string + maxLength: 127 + maxItems: 2 + token_in_param: + description: 'query parameter name where token is present' + type: array + items: + type: string + maxLength: 127 + maxItems: 2 + signature_algorithms: + description: 'list of allowed signature algorithms, by default HS256, RS256, RS512 are allowed' + type: array + items: + type: string + enum: ['HS256', 'RS256', 'RS512'] + claims_to_save: + description: 'list of claims to be saved, used to create authorization policies' + type: array + items: + type: string + maxLength: 127 + metadata_url: + description: 'URL used to get OAUTH/OIDC provider metadata' + type: string + maxLength: 255 + user_field: + description: |+ + 'Attribute in the token from which username should be extracted. + by default, ADC looks at email attribute for user id' + type: string + maxLength: 127 + default_group: + description: |+ + 'group assigned to the request if authentication succeeds, + this is in addition to any extracted groups from token' + type: string + maxLength: 63 + grant_type: + description: 'used to specify the type of flow to the token end point, defaults to CODE' + type: array + items: + type: string + enum: ['CODE','PASSWORD'] + pkce: + description: 'specify whether to enable Proof Key Code Exchange, defaults to ENABLED' + type: string + enum: ['ENABLED', 'DISABLED'] + token_ep_auth_method: + description: |+ + 'authentication method to be used with token end point, + defaults to client_secret_post' + type: string + enum: ['client_secret_post', 'client_secret_jwt'] + + anyOf: + - properties: + required : [jwks_uri] + - properties: + required : [introspect_url, client_credentials] + - properties: + required : [metadata_url] + + ldap: + description: 'LDAP authentication provider' + type: object + properties: + server_ip: + description: 'IP address assigned to the LDAP server' + type: string + server_name: + description: 'LDAP server name as a FQDN' + type: string + maxLength: 127 + server_port: + description: 'Port on which the LDAP server accepts connections. Default is 389' + type: integer + minimum: 1 + maximum: 65535 + base: + description: |+ + 'Base (node) from which to start LDAP searches. If the LDAP server is + running locally, the default value of base is dc=netscaler, dc=com' + type: string + maxLength: 127 + server_login_credentials: + description: |+ + 'Kubernetes secret object providing credentials to login to LDAP server, + The secret data should have username and password' + type: string + login_name: + description: |+ + 'LDAP login name attribute. The Citrix ADC uses the LDAP login name + to query external LDAP servers or Active Directories' + type: string + maxLength: 127 + security_type: + description: |+ + 'Type of security used for communications between the Citrix ADC + and the LDAP server. Default is TLS' + type: string + enum: ['PLAINTEXT', 'TLS', 'SSL'] + validate_server_cert: + description: 'Validate LDAP Server certs. Default is NO' + type: string + enum: ['YES', 'NO'] + hostname: + description: |+ + 'Hostname for the LDAP server. If validate_server_cert is ON, + this must be the host name on the certificate from the LDAP + A hostname mismatch will cause a connection failure' + type: string + maxLength: 127 + sub_attribute_name: + description: 'LDAP group sub-attribute name. Used for group extraction from the LDAP server.' + type: string + maxLength: 31 + group_attribute_name: + description: 'LDAP group attribute name. Used for group extraction on the LDAP server.' + type: string + maxLength: 31 + search_filter: + description: |+ + 'String to be combined with the default LDAP user search string to form the + search value. For example, if the search filter "vpnallowed=true" is combined + with the LDAP login name "samaccount" and the user-supplied username is "bob", + the result is the LDAP search string ""(&(vpnallowed=true)(samaccount=bob)"" + (Be sure to enclose the search string in two sets of double quotation marks)' + type: string + maxLength: 255 + auth_timeout: + description: |+ + 'Number of seconds the Citrix ADC waits for a response from the server + Default is 3' + type: integer + minimum: 1 + maximum: 4294967295 + password_change: + description: 'Allow password change requests. Default is DISABLED' + type: string + enum: ['ENABLED', 'DISABLED'] + attributes_to_save: + description: |+ + 'List of attribute names separated by comma which needs to be fetched + from LDAP server and stored as key-value pair for the session on ADC' + type: string + maxLength: 2047 + oneOf: + - properties: + required: [server_ip] + - properties: + required: [server_name] + + saml: + description: |+ + 'SAML authentication provider. + Currently SAML is supported only with authentication mechanism using forms' + type: object + properties: + metadata_url: + description: 'URL is used for obtaining saml metadata.' + type: string + maxLength: 255 + metadata_refresh_interval: + description: |+ + 'Interval in minutes for fetching metadata from specified metadata URL. + Default is 36000' + type: integer + minimum: 1 + maximum: 4294967295 + signing_cert: + description: 'SSL certificate to sign requests from SP to IDP' + type: object + properties: + tls_secret: + type: string + description: 'Name of the Kubernetes Secret of type tls referring to Certificate' + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + preconfigured: + type: string + maxLength: 63 + description: |+ + 'Preconfigured SSL certkey name on ADC with the + certificate and key already added on ADC' + oneOf: + - properties: + required: [tls_secret] + - properties: + required: [preconfigured] + audience: + description: 'Audience for which assertion sent by IdP is applicable' + type: string + maxLength: 127 + issuer_name: + description: 'The name to be used in requests sent from SP to IDP to identify citrix ADC' + type: string + maxLength: 63 + binding: + description: 'Specifies the transport mechanism of saml message. Default is POST' + type: string + enum: ['REDIRECT', 'POST', 'ARTIFACT'] + artifact_resolution_service_url: + description: 'URL of the Artifact Resolution Service on IdP' + type: string + maxLength: 255 + logout_binding: + description: 'Specifies the transport mechanism of saml logout. Default is POST' + type: string + enum: ['REDIRECT', 'POST'] + reject_unsigned_assertion: + description: |+ + 'Reject unsigned SAML assertions. ON, rejects assertion without signature. + STRICT ensure that both Response and Assertion are signed. Default is ON' + type: string + enum: ['ON', 'OFF', 'STRICT'] + user_field: + description: 'SAML user ID, as given in the SAML assertion' + type: string + maxLength: 63 + default_authentication_group: + description: |+ + 'This is the default group that is chosen when the authentication + succeeds in addition to extracted groups' + type: string + maxLength: 63 + skew_time: + description: |+ + 'Allowed clock skew in number of minutes on an incoming assertion. + Default is 5' + type: integer + minimum: 1 + attributes_to_save: + description: |+ + 'List of attribute names separated by comma which needs to be extracted + and stored as key-value pair for the session on ADC' + type: string + maxLength: 2047 + required: + - metadata_url + + basic_local_db: + type: object + description: |+ + 'Basic HTTP authentication supported by ADC, user data in local DB of ADC. + Users needs to be added on ADC' + properties: + use_local_auth: + description: 'Use ADC authentication' + type: string + enum: ['YES'] + + required: + - name + + authentication_policies: + description: 'Authentication policies' + type: array + items: + type: object + description: 'Authentication policy' + properties: + resource: + type: object + description: 'endpoint/resource selection criteria' + properties: + path: + description: 'api resource path e.g. /products. ' + type: array + items: + type: string + maxLength: 511 + method: + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + required: + - path + expression: + description: 'ADC syntax expression for authentication' + type: string + maxLength: 1229 + provider: + description: 'name of the authentication provider for the policy, empty if no authentication required' + type: array + items: + type: string + maxLength: 127 + maxItems: 1 + oneOf: + - required: [resource, provider] + - required: [expression, provider] + + authorization_policies: + description: 'Authorization policies' + type: array + items: + type: object + description: 'Authorization policy' + properties: + resource: + type: object + description: 'endpoint/resource selection criteria' + properties: + path: + description: 'api resource path e.g. /products. ' + type: array + items: + type: string + maxLength: 511 + method: + description: ' http method' + type: array + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + claims: + description: 'authorization scopes required for selected resource saved as claims or attributes' + type: array + items: + type: object + properties: + name: + description: 'name of the claim/attribute to check' + type: string + maxLength: 127 + values: + description: 'list of claim values required for the request' + type: array + items: + type: string + maxLength: 127 + minItems: 1 + required: + - name + - values + required: + - claims + expression: + description: 'ADC syntax expression for authorization' + type: string + maxLength: 1229 + oneOf: + - required: [resource] + - required: [expression] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: listeners.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + version: null + names: + kind: Listener + plural: listeners + singular: listener + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + required: [spec] + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + required: [protocol] + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + protocol: + type: string + enum: ["https", "http"] + description: "Protocol for this listener" + vip: + type: string + description: "VIP address, Optional for CPX, required for Tier-1 deployments" + secondaryVips: + type: array + description: "An array of Secondary VIPs. All the VIPs will be part of an ipset" + minItems: 1 + items: + type: string + redirectPort: + type: integer + minimum: 1 + maximum: 65535 + description: "Port from which http traffic should be redirected to https" + port: + type: integer + minimum: 1 + maximum: 65535 + certificates: + type: array + description: "certificates attached to the endpoints - Not applicable for HTTP" + minItems: 1 + items: + type: object + properties: + preconfigured: + type: string + description: "Preconfigured Certificate name on ADC " + secret: + type: object + description: "Kuberentes secret object" + required: [name] + properties: + name: + type: string + description: "name of the Kubernetes Secret object where Cert is located" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + namespace: + type: string + description: "Namespace of the kubernetes secret object; Default is same namespace where the Listener object is located" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + default: + type: boolean + description: "Only one of the certificate can be marked as default which will be presented if none of the cert matches with the hostname" + oneOf: + - required: ["preconfigured"] + - required: ["secret"] + policies: + type: object + description: "Policies attached to the Listener" + properties: + httpprofile: + type: object + description: "HTTP profile configurations for the Listener, HTTP level configurations" + properties: + preconfigured: + type: string + description: "Preconfigured or Built-in HTTP profile name" + config: + type: object + description: "HTTP profile configuration for the listener. For individual fields, refer:https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ns/nshttpprofile/nshttpprofile/ Name field is auto populated" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + tcpprofile: + type: object + description: "TCP level configurations, uses ns tcpprofile of citrix ADC" + properties: + preconfigured: + description: "Preconfigured or Built-in TCP profile name" + type: string + config: + type: object + description: "TCPprofile configurations for the listener. For individual fields refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ns/nstcpprofile/ ; Name field is auto populated" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + csvserverConfig: + type: object + description: "CS Vserver configuration for the listener" + additionalProperties: + type: string + sslprofile: + type: object + description: "SSL profile configuration" + properties: + preconfigured: + type: string + description: "SSL profile which is preconfigured in ADC. Ciphers bound to the profile is not overriden" + config: + description: "Citrix ADC frontend SSL profile configurations. Refer:https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/ssl/sslprofile/ for all configurations; Name field is auto generated" + type: object + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + sslciphers: + type: array + description: "List of ciphers to be bound to the ssl profile for the listener. Priority is as per the order in the list. A cipher suite, predefined cipher group or User created cipher group can be mentioned" + minItems: 1 + items: + type: string + description: "Cipher suite, cipher group name" + analyticsprofile: + type: object + description: "Analytics profile configuration" + properties: + preconfigured: + type: array + description: "Preconfigured Analytics profile that needs to be bound to the vserver" + minItems: 1 + items: + type: string + description: "Name of the analytics profile preconfigured that will be bound to the Vserver" + config: + type: array + description: "An array of analytics to be enabled" + minItems: 1 + items: + type: object + description: "Anlytics to be enabled" + required: ['type'] + properties: + type: + description: "Analytics profile to be enabled, you can enable one or more of the webinsight, tcpinsight, securityinsight, videoinsight, hdxinsight, gatewayinsight, timeseries, lsninsight, botinsight " + type: string + enum: ["webinsight", "tcpinsight", "securityinsight", "videoinsight", "hdxinsight", "gatewayinsight", "timeseries", "lsninsight", "botinsight"] + parameters: + type: object + description: "Additional parameters for analytics profile. Please refer:https://developer-docs.citrix.com/projects/citrix-adc-nitro-api-reference/en/latest/configuration/analytics/analyticsprofile/" + additionalProperties: + type: string + oneOf: + - required: ["preconfigured"] + - required: ["config"] + routes: + type: array + description: "List of route objects attached to the listener" + minItems: 1 + items: + type: object + properties: + name: + type: string + description: "Name of the HTTPRoute object" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + namespace: + type: string + description: "Namespace of the HTTPRoute object" + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + labelSelector: + description: "Labels key value pair, if the route carries the same labels, it is automatically attached" + type: object + additionalProperties: + type: string + oneOf: + - required: [name, namespace] + - required: [labelSelector] + defaultAction: + type: object + description: "Default action for the listener: One of Backend or Redirect" + properties: + backend: + type: object + oneOf: + - required: [kube] + properties: + kube: + type: object + required: [service, port] + properties: + service: + description: "Name of the backend service" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + port: + description: "Service port" + type: integer + minimum: 1 + maximum: 65535 + namespace: + description: "Service namespace" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + backendConfig: + description: "General backend service options" + type: object + properties: + secure_backend: + description: "Use Secure communications to the backends" + type: boolean + lbConfig: + description: "Citrix ADC LB vserver configurations for the backend. Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/load-balancing/lbvserver/lbvserver/ for all configurations" + type: object + additionalProperties: + type: string + servicegroupConfig: + description: "Citrix ADC service group configurations for the backend; Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/basic/servicegroup/servicegroup/ for all configurations" + type: object + additionalProperties: + type: string + redirect: + type: object + oneOf: + - required: [targetExpression] + - required: [hostRedirect] + - required: [httpsRedirect] + properties: + httpsRedirect: + description: "Change the scheme from http to https keeping URL intact" + type: boolean + hostRedirect: + description: "Host name specified is used for redirection with URL intact" + type: string + targetExpression: + description: "A target can be specified using Citrix ADC policy expression" + type: string + responseCode: + description: "Default response code is 302, which can be customised using this attribute" + type: integer + minimum: 100 + maximum: 599 + oneOf: + - required: ["backend"] + - required: ["redirect"] + subresources: + # status enables the status subresource. + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: httproutes.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + version: null + names: + kind: HTTPRoute + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + required: [rules] + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + hostname: + type: array + description: "List of domain names that share the same route, default is '*'" + minItems: 1 + items: + type: string + description: "Domain name" + rules: + type: array + description: "List Content routing rules with an action defined" + minItems: 1 + items: + type: object + required: [name, action] + properties: + name: + type: string + description: "A name to represent the rule, this is used as an identifier in content routing policy name in ADC" + minLength: 1 + maxLength: 20 + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + match: + type: array + description: "List of rules with same action" + minItems: 1 + items: + type: object + anyOf: + - required: [path] + - required: [headers] + - required: [cookies] + - required: [queryParams] + - required: [method] + - required: [policyExpression] + properties: + path: + type: object + description: "URL Path based content routing" + properties: + prefix: + type: string + description: "URL path matches the prefix expression" + exact: + type: string + description: "URL Path must match exact path" + regex: + type: string + description: "PCRE based regex expression for path matching" + headers: + type: array + description: "List of header for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Header details for content routing, Check for existence of a header or header name-value match" + properties: + headerName: + type: object + description: "Header name based content routing, Here existence of header is used for routing" + properties: + exact: + type: string + description: "Header Name - treated as exact must exist" + contains: + type: string + description: "Header Name - A header must exist that contain the string the name" + regex: + type: string + description: "header Name - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e header name must not exist" + oneOf: + - required: [exact] + - required: [contains] + - required: [regex] + headerValue: + type: object + description: "Header Name and Value based match" + properties: + name: + type: string + description: "Header name that must match the value" + exact: + type: string + description: "Header value - treated as exact" + contains: + type: string + description: "Header value - treated as contains" + regex: + type: string + description: "header value - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e header if present must not match the value" + oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + queryParams: + type: array + description: "List of Query parameters for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Query parameters Name and Value based match" + properties: + name: + type: string + description: "Query name that must match the value. If no value is specified, matches with any value" + exact: + type: string + description: "Query value - Exact match" + contains: + type: string + description: "Query value - value must have the string(substring)" + regex: + type: string + description: "Query value - Value must match this regex patterm" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e query if present must not match the value" + anyOf: + - required: [name] + - oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + cookies: + type: array + description: "List of Cookie params for content routing - Must match all the rules- Treated as AND condition if more than 1 rule" + minItems: 1 + items: + type: object + description: "Cookie based routing" + properties: + name: + type: string + description: "cookie name that must match the value. If no value specified, it matches with any value" + exact: + type: string + description: "cookie value - treated as exact" + contains: + type: string + description: "cookie value - treated as substring" + regex: + type: string + description: "cookie value - treated as PCRE regex expression" + not: + type: boolean + description: "Default False, if present, rules are inverted. I.e cookie if present must not match the value" + anyOf: + - required: [name] + - oneOf: + - required: [name, exact] + - required: [name, contains] + - required: [name, regex] + method: + type: string + description: "HTTP method for content routing eg: POST, PUT, DELETE etc" + policyExpression: + type: string + description: "Citrix ADC policy expressions; refer: https://docs.citrix.com/en-us/netscaler/media/expression-prefix.pdf" + action: + type: object + description: "Action for the matched rule" + properties: + backend: + type: object + oneOf: + - required: [kube] + properties: + kube: + type: object + required: [service, port] + properties: + service: + description: "Name of the backend service" + type: string + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + port: + description: "Service port" + type: integer + minimum: 1 + maximum: 65535 + backendConfig: + type: object + description: "General backend service options" + properties: + secureBackend: + description: "Use Secure communications to the backends" + type: boolean + lbConfig: + description: "Citrix ADC LB vserver configurations for the backend. Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/load-balancing/lbvserver/lbvserver/ for all configurations" + type: object + additionalProperties: + type: string + servicegroupConfig: + description: "Citrix ADC service group configurations for the backend; Refer: https://developer-docs.citrix.com/projects/netscaler-nitro-api/en/12.0/configuration/basic/servicegroup/servicegroup/ for all configurations" + type: object + additionalProperties: + type: string + redirect: + type: object + oneOf: + - required: [targetExpression] + - required: [hostRedirect] + - required: [httpsRedirect] + properties: + httpsRedirect: + description: "Change the scheme from http to https keeping URL intact" + type: boolean + hostRedirect: + description: "Host name specified is used for redirection with URL intact" + type: string + targetExpression: + description: "A target can be specified using Citrix ADC policy expression" + type: string + responseCode: + description: "Default response code is 302, which can be customised using this attribute" + type: integer + minimum: 100 + maximum: 599 + oneOf: + - required: ["backend"] + - required: ["redirect"] + subresources: + # status enables the status subresource. + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: continuousdeployments.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: continuousdeployment + plural: continuousdeployments + singular: continuousdeployment + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + cronSpec: + type: integer + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: wafs.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: waf + plural: wafs + singular: waf + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the waf policies are applied.' + type: array + items: + type: string + maxLength: 127 + application_type: + description: 'Type of applications to protect' + type: array + items: + type: string + enum: ['HTML', 'JSON', 'XML'] + signatures: + description: 'Location of external signature file' + type: string + redirect_url: + description: 'When a URL is blocked/down, redirect_url represents the alternate URL where the client requests should be sent.' + type: string + html_error_object: + description: 'Location of customized error page to respond when html or common violation are hit' + type: string + xml_error_object: + description: 'Location of customized error page to respond when xml violations are hit' + type: string + json_error_object: + description: 'Location of customized error page to respond when json violations are hit' + type: string + ip_reputation: + type: object + x-kubernetes-preserve-unknown-fields: true + description: 'Enabling IP reputation feature' + target: + description: 'To control what traffic to be inspected by Web Application Firewall. If you do not provide the target, everything will be inspected by default' + type: object + properties: + path: + type: array + description: "List of http urls to inspect" + items: + type: string + description: "URL path" + method: + type: array + description: "List of http methods to inspect" + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header: + type: array + description: "List of http headers to inspect" + items: + type: string + description: "header name" + security_checks: + description: 'To enable/disable application firewall security checks' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + settings: + description: 'To fine tune application firewall security checks default settings' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + relaxations: + description: 'Section which contains relaxation rules for known traffic and false positives' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true + enforcements: + description: 'Section which contains enforcement or restriction rules' + type: object + properties: + common: + type: object + x-kubernetes-preserve-unknown-fields: true + html: + type: object + x-kubernetes-preserve-unknown-fields: true + json: + type: object + x-kubernetes-preserve-unknown-fields: true + xml: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bots.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: bot + plural: bots + singular: bot + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'Name of the services to which the bot policies are applied.' + type: array + items: + type: string + maxLength: 127 + signatures: + description: 'Location of external bot signature file' + type: string + redirect_url: + description: 'url to redirect when bot violation is hit' + type: string + target: + description: 'To control what traffic to be inspected by BOT. If you do not provide the target, everything will be inspected by default' + type: object + properties: + path: + type: array + description: "List of http urls to inspect" + items: + type: string + description: "URL path" + method: + type: array + description: "List of http methods to inspect" + items: + type: string + enum: ['GET', 'PUT', 'POST','DELETE'] + header: + type: array + description: "List of http headers to inspect" + items: + type: string + description: "header name" + security_checks: + description: 'To enable/disable bot ecurity checks' + type: object + properties: + allow_list: + type: string + enum: ['ON', 'OFF'] + block_list: + type: string + enum: ['ON', 'OFF'] + device_fingerprint: + type: object + x-kubernetes-preserve-unknown-fields: true + reputation: + type: string + enum: ['ON', 'OFF'] + ratelimit: + type: string + enum: ['ON', 'OFF'] + tps: + type: string + enum: ['ON', 'OFF'] + trap: + type: object + x-kubernetes-preserve-unknown-fields: true + bindings: + description: 'Section which contains binding rules for bot security checks' + type: object + properties: + allow_list: + type: array + items: + type: object + properties: + subnet: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + expression: + type: object + x-kubernetes-preserve-unknown-fields: true + + block_list: + type: array + items: + type: object + properties: + subnet: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + expression: + type: object + x-kubernetes-preserve-unknown-fields: true + ratelimit: + type: array + items: + type: object + properties: + url: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + cookie: + type: object + x-kubernetes-preserve-unknown-fields: true + reputation: + type: object + x-kubernetes-preserve-unknown-fields: true + captcha: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + tps: + type: object + properties: + geolocation: + type: object + x-kubernetes-preserve-unknown-fields: true + host: + type: object + x-kubernetes-preserve-unknown-fields: true + ip: + type: object + x-kubernetes-preserve-unknown-fields: true + trapinsertion: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: apigatewaypolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: apigatewaypolicy + plural: apigatewaypolicies + singular: apigatewaypolicy + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + required: [spec] + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + api_definition: + type: object + properties: + repository: + type: string + branch: + type: string + oas_secret_ref: + type: string + files: + type: array + items: + type: string + maxLength: 127 + api_proxy: + type: object + properties: + ipaddress: + type: string + port: + type: integer + protocol: + type: string + secret: + type: string + policies: + type: array + items: + type: object + properties: + name: + type: string + selector: + type: array + items: + type: object + properties: + tags: + type: array + items: + type: string + api: + type: string + method: + type: array + items: + type: string + maxLength: 127 + upstream: + type: object + properties: + service: + type: string + port: + type: integer + policy_bindings: + type: object + properties: + ratelimit: + type: object + properties: + name: + type: string + waf: + type: object + properties: + name: + type: string + rewritepolicy: + type: object + properties: + name: + type: string + bot: + type: object + properties: + name: + type: string + aaa: + type: array + items: + type: object + properties: + crd_name: + type: string + mappings: + type: array + items: + type: object + properties: + petstore_auth: + type: string + api_key: + type: string +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: corspolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: corspolicy + plural: corspolicies + singular: corspolicy + shortNames: + - cp + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: 'Current Status of the CRD' + jsonPath: .status.state + - name: Message + type: string + description: 'Status Message' + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + ingressclass: + type: string + description: "Ingress class, if not specified then all citrix ingress controllers in the cluster will process the resource otherwise only the controller with that ingress class will process this resource" + servicenames: + description: 'The list of Kubernetes services to which you want to apply the cors policies.' + type: array + items: + type: string + maxLength: 63 + allow_origin: + description: 'Represents list of allowed origins, it is used to screen the “origin” in the cors pre flight request' + type: array + items: + type: string + maxLength: 2083 + allow_methods: + description: 'Indicates which methods are supported by the response’s URL for the purposes of the CORS protocol. This variable will be used to set Access-Control-Allow-Methods in the pre-flight cors response.' + type: array + items: + type: string + maxLength: 127 + allow_headers: + description: 'Indicates which headers are supported by the response’s URL for the purposes of the CORS protocol. This variable will be used to set Access-Control-Allow-Headers in the pre-flight cors response.' + type: array + items: + type: string + maxLength: 127 + max_age: + description: 'Indicates the number of seconds (5 by default) the information provided by the `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` headers can be cached. This variable will be used to set Access-Control-Max-Age in the pre-flight cors response.' + type: integer + allow_credentials: + description: 'Indicates whether the response can be shared when the request’s credentials mode is "include". This variable will be set to Access-Control-Allow-Credentials in the rewrite action.' + type: boolean + required: [servicenames, allow_origin, allow_methods, allow_headers] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: appqoepolicies.citrix.com +{{- if .Values.crds.retainOnDelete }} + annotations: + "helm.sh/resource-policy": keep +{{- end }} +spec: + group: citrix.com + names: + kind: appqoepolicy + plural: appqoepolicies + singular: appqoepolicy + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: "Current Status of the CRD" + jsonPath: .status.state + - name: Message + type: string + description: "Status Message" + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + appqoe-policies: + type: array + items: + type: object + properties: + servicenames: + description: 'Name of the services that needs to be binded to appqoe policy.' + type: array + items: + type: string + maxLength: 127 + appqoe-policy: + type: object + properties: + operation-retry: + type: object + properties: + on-reset: + description: "To set Retry on Connection Reset or Not" + type: string + enum: ['YES','NO'] + on-timeout: + description: "Time in milliseconds for retry" + type: integer + minimum: 30 + maximum: 2000 + number-of-retries: + description: "To set number of retries" + type: integer + minimum: 1 + maximum: 7 + required: [operation-retry] + appqoe-criteria: + description: 'Expression against which traffic is evaluated.' + type: string + maxLength: 1299 + direction: + description: 'Bind point to which to bind the policy.' + type: string + enum: ["REQUEST","RESPONSE"] + required: [appqoe-criteria, operation-retry] + required: [appqoe-policy] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: wildcarddnsentries.citrix.com +spec: + group: citrix.com + names: + kind: wildcarddnsentry + plural: wildcarddnsentries + singular: wildcarddnsentry + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Status + type: string + description: Current Status of the CRD + jsonPath: .status.state + - name: Message + type: string + description: Status Message + jsonPath: .status.status_message + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + properties: + state: + type: string + status_message: + type: string + spec: + type: object + properties: + zone: + type: object + description: DNS configuration for a zone + properties: + domain: + type: string + description: Domain name + dnsaddrec: + type: object + description: DNS Address record + properties: + domain-ip: + type: string + description: IPv4 addresses to assign to the domain name + ttl: + type: integer + description: >- + TTL is the time for which the record must be cached + by DNS proxies + dnsaaaarec: + type: object + description: DNS AAAA record + properties: + domain-ip: + type: string + description: IPv6 addresses to assign to the domain name + ttl: + type: integer + description: >- + TTL is the time for which the record must be cached + by DNS proxies + soarec: + type: object + description: SOA record + properties: + origin-server: + type: string + description: Origin server domain + contact: + type: string + description: Admin contact + serial: + type: integer + description: >- + The secondary server uses this parameter to + determine whether it requires a zone transfer from + the primary server. + refresh: + type: integer + description: >- + Time, in seconds, for which a secondary server must + wait between successive checks on the value of the + serial number. + retry: + type: integer + description: >- + Time, in seconds, between retries if a secondary server's + attempt to contact the primary server for a zone refresh fails. + expire: + type: integer + description: >- + Time, in seconds, after which the zone data on a secondary + nameserver can no longer be considered authoritative because + all refresh and retry attempts made during the period have failed." + nsrec: + type: object + description: Name server record + properties: + nameserver: + type: string + description: Host name of the name server to add to the domain. + ttl: + type: integer + description: >- + Time to Live (TTL), in seconds, for the record. TTL + is the time for which the record must be cached by + DNS proxies. The specified TTL is applied to all the + resource records that are of the same record type + and belong to the specified domain name +--- +{{- end }} diff --git a/charts/citrix/citrix-ingress-controller/templates/citrix-k8s-ingress.yaml b/charts/citrix/citrix-ingress-controller/templates/citrix-k8s-ingress.yaml new file mode 100644 index 000000000..c18d69207 --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/citrix-k8s-ingress.yaml @@ -0,0 +1,260 @@ +{{- if .Values.openshift }} +apiVersion: apps.openshift.io/v1 +kind: DeploymentConfig +{{- else }} +apiVersion: apps/v1 +kind: Deployment +{{- end }} +metadata: + name: {{ include "citrix-ingress-controller.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: +{{- if .Values.openshift }} + router: {{ include "citrix-ingress-controller.fullname" . }} +{{- else }} + matchLabels: + app: {{ include "citrix-ingress-controller.fullname" . }} +{{- end }} + replicas: 1 +{{- if .Values.openshift }} + strategy: + resources: {} + rollingParams: + intervalSeconds: 1 + maxSurge: 0 + maxUnavailable: 25% + timeoutSeconds: 600 + updatePeriodSeconds: 1 + type: Rolling +{{- end }} + template: + metadata: + name: cic + labels: +{{- if .Values.openshift }} + router: {{ include "citrix-ingress-controller.fullname" . }} +{{- else }} + app: {{ include "citrix-ingress-controller.fullname" . }} +{{- end }} +{{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} +{{- end }} + spec: + serviceAccountName: {{ include "citrix-ingress-controller.serviceAccountName" . }} + containers: + - name: cic + image: "{{ tpl .Values.image . }}" + imagePullPolicy: {{ .Values.pullPolicy }} + args: + - --configmap + {{ .Release.Namespace }}/{{ include "cicconfigmap.fullname" . }} +{{- if .Values.defaultSSLCertSecret }} + - --default-ssl-certificate + {{ .Release.Namespace }}/{{ .Values.defaultSSLCertSecret }} +{{- end }} +{{- if .Values.ingressClass }} + - --ingress-classes +{{- range .Values.ingressClass}} + {{.}} +{{- end }} +{{- end }} +{{- if .Values.serviceClass }} + - --service-classes +{{- range .Values.serviceClass}} + {{.}} +{{- end }} +{{- end }} + - --feature-node-watch + {{ .Values.nodeWatch }} + - --enable-cnc-pbr + {{ .Values.cncPbr }} +{{- if .Values.ipam }} + - --ipam + citrix-ipam-controller +{{- end }} +{{- if .Values.disableAPIServerCertVerify }} + - --disable-apiserver-cert-verify + {{ .Values.disableAPIServerCertVerify }} +{{- end }} +{{- if .Values.updateIngressStatus }} + - --update-ingress-status + yes +{{- end }} + env: + - name: "NS_IP" + value: "{{ .Values.nsIP }}" +{{- if .Values.nsVIP }} + - name: "NS_VIP" + value: "{{ .Values.nsVIP }}" +{{- end }} +{{- if .Values.nitroReadTimeout }} + - name: "NS_NITRO_READ_TIMEOUT" + value: "{{ .Values.nitroReadTimeout }}" +{{- end }} + - name: "NS_USER" + {{- if and .Values.secretStore.enabled .Values.secretStore.username}} + {{- toYaml .Values.secretStore.username | nindent 10 }} + {{- else }} + valueFrom: + secretKeyRef: + name: {{ .Values.adcCredentialSecret }} + key: username + {{- end }} + - name: "NS_PASSWORD" + {{- if and .Values.secretStore.enabled .Values.secretStore.password}} + {{- toYaml .Values.secretStore.password | nindent 10 }} + {{- else }} + valueFrom: + secretKeyRef: + name: {{ .Values.adcCredentialSecret }} + key: password + {{- end }} + - name: "EULA" + value: "{{ .Values.license.accept }}" +{{- if and .Values.openshift .Values.routeLabels }} + - name: "ROUTE_LABELS" + value: {{ .Values.routeLabels | quote}} +{{- end }} +{{- if and .Values.openshift .Values.namespaceLabels }} + - name: "NAMESPACE_LABELS" + value: {{ .Values.namespaceLabels | quote }} +{{- end }} + - name: "NS_APPS_NAME_PREFIX" + value: {{ .Values.entityPrefix | default "k8s"}} +{{- if .Values.kubernetesURL }} + - name: "kubernetes_url" + value: "{{ .Values.kubernetesURL }}" +{{- end }} +{{- if .Values.clusterName }} + - name: "CLUSTER_NAME" + value: "{{ .Values.clusterName }}" +{{- end }} +{{- if .Values.logProxy }} + - name: "NS_LOGPROXY" + value: "{{ .Values.logProxy }}" +{{- end }} +{{- if .Values.disableOpenshiftRoutes }} + - name: "DISABLE_OPENSHIFT_ROUTES" + value: "{{ .Values.disableOpenshiftRoutes }}" +{{- end }} +{{- if .Values.nsConfigDnsRec }} + - name: "NS_CONFIG_DNS_REC" + value: "{{ .Values.nsConfigDnsRec }}" +{{- end }} +{{- if .Values.nsSvcLbDnsRec }} + - name: "NS_SVC_LB_DNS_REC" + value: "{{ .Values.nsSvcLbDnsRec }}" +{{- end }} +{{- if .Values.optimizeEndpointBinding }} + - name: "OPTIMIZE_ENDPOINT_BINDING" + value: "{{ .Values.optimizeEndpointBinding }}" +{{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if ne (len .Values.extraVolumeMounts) 0 }} + volumeMounts: +{{- toYaml .Values.extraVolumeMounts | nindent 8 }} + {{- end }} +{{- if .Values.exporter.required }} + - name: exporter + image: "{{ tpl .Values.exporter.image . }}" + imagePullPolicy: {{ .Values.exporter.pullPolicy }} + args: + - "--target-nsip={{ .Values.nsIP }}" + - "--port={{ .Values.exporter.ports.containerPort }}" + env: + - name: "NS_USER" + {{- if and .Values.secretStore.enabled .Values.secretStore.username}} + {{- toYaml .Values.secretStore.username | nindent 10 }} + {{- else }} + valueFrom: + secretKeyRef: + name: {{ .Values.adcCredentialSecret }} + key: username + {{- end }} + - name: "NS_PASSWORD" + {{- if and .Values.secretStore.enabled .Values.secretStore.password}} + {{- toYaml .Values.secretStore.password | nindent 10 }} + {{- else }} + valueFrom: + secretKeyRef: + name: {{ .Values.adcCredentialSecret }} + key: password + {{- end }} + {{- if ne (len .Values.exporter.extraVolumeMounts) 0 }} + volumeMounts: + {{- toYaml .Values.exporter.extraVolumeMounts | nindent 8 }} + {{- end }} + securityContext: + readOnlyRootFilesystem: true + resources: +{{- toYaml .Values.exporter.resources | nindent 12 }} +{{- end }} +{{- if or (and .Values.extraVolumeMounts .Values.extraVolumes) (and .Values.exporter.extraVolumeMounts .Values.extraVolumes) }} + volumes: +{{- end }} +{{- if ne (len .Values.extraVolumes) 0 }} +{{ toYaml .Values.extraVolumes | indent 6 }} +{{- end }} +{{- if and .Values.nodeSelector.key .Values.nodeSelector.value }} + nodeSelector: + {{ .Values.nodeSelector.key }}: {{ .Values.nodeSelector.value }} +{{- end }} +{{- if .Values.tolerations }} + tolerations: {{ .Values.tolerations | toYaml | nindent 8 }} +{{- end }} +{{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} +{{- end }} + +--- + +{{- if .Values.exporter.required }} + + +apiVersion: v1 +kind: Service +metadata: + name: {{ include "exporter.fullname" . }} + labels: + app: {{ include "exporter.fullname" . }} + service-type: {{ include "servicemonitorlabel" . }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.exporter.ports.containerPort }} + targetPort: {{ .Values.exporter.ports.containerPort }} + name: exporter-port + selector: +{{- if .Values.openshift }} + router: {{ include "citrix-ingress-controller.fullname" . }} +{{- else }} + app: {{ include "citrix-ingress-controller.fullname" . }} +{{- end }} + +--- + +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "servicemonitor.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + servicemonitor: citrix-adc +spec: + endpoints: + - interval: 30s + port: exporter-port + selector: + matchLabels: + service-type: {{ include "servicemonitorlabel" . }} + namespaceSelector: + matchNames: + - monitoring + - default + - {{ .Release.Namespace }} + +{{- end }} diff --git a/charts/citrix/citrix-ingress-controller/templates/configmap.yaml b/charts/citrix/citrix-ingress-controller/templates/configmap.yaml new file mode 100644 index 000000000..a765d0005 --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/configmap.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "cicconfigmap.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + LOGLEVEL: {{ .Values.logLevel | quote | lower }} + JSONLOG: {{ .Values.jsonLog | quote | lower }} + NS_PROTOCOL: {{ .Values.nsProtocol | quote | lower }} + NS_PORT: {{ .Values.nsPort | quote }} +{{- if .Values.nsSNIPS }} + NS_SNIPS: {{ .Values.nsSNIPS | toJson}} +{{- end }} +{{- if and .Values.analyticsConfig.required .Values.nsEnableLabel }} + NS_ENABLE_LABELS: {{ .Values.nsEnableLabel | quote}} +{{- end }} +{{- if .Values.podIPsforServiceGroupMembers }} + POD_IPS_FOR_SERVICEGROUP_MEMBERS: {{ .Values.podIPsforServiceGroupMembers | quote }} +{{- end }} +{{- if .Values.ignoreNodeExternalIP }} + IGNORE_NODE_EXTERNAL_IP: {{ .Values.ignoreNodeExternalIP | quote }} +{{- end }} + +{{- if ne (upper .Values.nsHTTP2ServerSide) "OFF" }} + NS_HTTP2_SERVER_SIDE: {{ .Values.nsHTTP2ServerSide | quote }} +{{- end }} +{{- if ne (toString .Values.nsCookieVersion) "0" }} + NS_COOKIE_VERSION: {{ .Values.nsCookieVersion | quote }} +{{- end }} +{{- if .Values.nsDnsNameserver }} + NS_DNS_NAMESERVER: {{ .Values.nsDnsNameserver }} +{{- end }} + +{{- if .Values.analyticsConfig.required }} + NS_ANALYTICS_CONFIG: | + distributed_tracing: + enable: {{ .Values.analyticsConfig.distributedTracing.enable | quote }} + samplingrate: {{ .Values.analyticsConfig.distributedTracing.samplingrate }} + endpoint: + server: {{ include "analytics.server" . | quote }} + service: {{ .Values.analyticsConfig.endpoint.service | quote }} + timeseries: + port: {{ .Values.analyticsConfig.timeseries.port }} + metrics: + enable: {{ .Values.analyticsConfig.timeseries.metrics.enable | quote }} + mode: {{ .Values.analyticsConfig.timeseries.metrics.mode | quote }} + auditlogs: + enable: {{ .Values.analyticsConfig.timeseries.auditlogs.enable | quote }} + events: + enable: {{ .Values.analyticsConfig.timeseries.events.enable | quote }} + transactions: + enable: {{ .Values.analyticsConfig.transactions.enable | quote }} + port: {{ .Values.analyticsConfig.transactions.port }} +{{- end }} + +{{- if .Values.nsLbHashAlgo.required }} + NS_LB_HASH_ALGO: | + hashFingers: {{ .Values.nsLbHashAlgo.hashFingers }} + hashAlgorithm: {{ .Values.nsLbHashAlgo.hashAlgorithm | quote }} +{{- end }} diff --git a/charts/citrix/citrix-ingress-controller/templates/ingressclass.yaml b/charts/citrix/citrix-ingress-controller/templates/ingressclass.yaml new file mode 100644 index 000000000..d75537b79 --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/ingressclass.yaml @@ -0,0 +1,18 @@ +{{- $default := .Values.setAsDefaultIngressClass -}} +{{- if semverCompare ">=1.19.0-0" .Capabilities.KubeVersion.GitVersion }} +{{- if .Values.ingressClass }} +{{- range .Values.ingressClass }} +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: {{ . | quote }} +{{- if $default }} + annotations: + ingressclass.kubernetes.io/is-default-class: "true" +{{- end }} +spec: + controller: citrix.com/ingress-controller +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/citrix/citrix-ingress-controller/templates/rbac.yaml b/charts/citrix/citrix-ingress-controller/templates/rbac.yaml new file mode 100644 index 000000000..fe7c883a4 --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/templates/rbac.yaml @@ -0,0 +1,89 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "citrix-ingress-controller.serviceAccountName" . }} +rules: + - apiGroups: [""] +{{- if .Values.openshift }} + resources: ["endpoints", "pods", "secrets", "routes", "tokenreviews", "subjectaccessreviews", "nodes", "namespaces", "configmaps", "services"] +{{- else }} + resources: ["endpoints", "pods", "secrets", "routes", "nodes", "namespaces", "configmaps", "services"] +{{- end }} + verbs: ["get", "list", "watch"] + # services/status is needed to update the loadbalancer IP in service status for integrating + # service of type LoadBalancer with external-dns + - apiGroups: [""] + resources: ["services/status"] + verbs: ["patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create"] + - apiGroups: ["extensions", "networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions","networking.k8s.io"] + resources: ["ingresses/status"] + verbs: ["patch"] + - apiGroups: ["networking.k8s.io"] + resources: ["ingressclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] + - apiGroups: ["citrix.com"] + resources: ["rewritepolicies", "continuousdeployments", "authpolicies", "ratelimits", "listeners", "httproutes", "wafs", "apigatewaypolicies", "bots", "corspolicies", "appqoepolicies", "wildcarddnsentries"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: ["citrix.com"] + resources: ["rewritepolicies/status", "continuousdeployments/status", "authpolicies/status", "ratelimits/status", "listeners/status", "httproutes/status", "wafs/status", "apigatewaypolicies/status", "bots/status", "corspolicies/status", "appqoepolicies/status", "wildcarddnsentries/status"] + verbs: ["patch"] + - apiGroups: ["citrix.com"] + resources: ["vips"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: ["crd.projectcalico.org"] + resources: ["ipamblocks"] + verbs: ["get", "list", "watch"] +{{- if .Values.openshift }} + - apiGroups: ["route.openshift.io"] + resources: ["routes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["network.openshift.io"] + resources: ["hostsubnets"] + verbs: ["get", "list", "watch"] + - apiGroups: ["config.openshift.io"] + resources: ["networks"] + verbs: ["get", "list"] +{{- end }} + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "citrix-ingress-controller.serviceAccountName" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "citrix-ingress-controller.serviceAccountName" . }} +subjects: +- kind: ServiceAccount + name: {{ include "citrix-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "citrix-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- if .Values.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.imagePullSecrets }} +- name: {{.}} +{{- end }} +{{- end }} + +--- diff --git a/charts/citrix/citrix-ingress-controller/values.yaml b/charts/citrix/citrix-ingress-controller/values.yaml new file mode 100644 index 000000000..8c660b854 --- /dev/null +++ b/charts/citrix/citrix-ingress-controller/values.yaml @@ -0,0 +1,177 @@ +# Default values for citrix-ingress-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Citrix Ingress Controller config details +imageRegistry: quay.io +imageRepository: citrix/citrix-k8s-ingress-controller +imageTag: 1.27.15 +image: "{{ .Values.imageRegistry }}/{{ .Values.imageRepository }}:{{ .Values.imageTag }}" +pullPolicy: IfNotPresent +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +openshift: false +adcCredentialSecret: # K8s Secret Name +# Enable secretStore to implement CSI Secret Provider classes for holding the nslogin credentials +secretStore: + enabled: false + username: {} + #valueFrom: + # configMapKeyRef: + # name: test1 + # key: username + password: {} + #valueFrom: + # configMapKeyRef: + # name: test1 + # key: password +nsIP: x.x.x.x +nsVIP: +nsSNIPS: +license: + accept: no +nsPort: 443 +nsProtocol: HTTPS +nsEnableLabel: true +# nitroReadTimeout is timeout value in seconds for nitro api read timeout(default is 20) +nitroReadTimeout: +logLevel: INFO +jsonLog: false +entityPrefix: +kubernetesURL: +clusterName: +ingressClass: +setAsDefaultIngressClass: False +serviceClass: +defaultSSLCertSecret: +podIPsforServiceGroupMembers: False +ignoreNodeExternalIP: False +ipam: False +# API server Cert verification can be disabled, while communicating with API Server, if disableAPIServerCertVerify set to True +disableAPIServerCertVerify: False +logProxy: +nodeWatch: false +cncPbr: False +nodeSelector: + key: + value: +tolerations: [] +updateIngressStatus: True +nsHTTP2ServerSide: "OFF" +nsCookieVersion: "0" +nsConfigDnsRec: +nsSvcLbDnsRec: +nsDnsNameserver: +optimizeEndpointBinding: +routeLabels: +namespaceLabels: +disableOpenshiftRoutes: + +# Exporter config details +exporter: + required: false + imageRegistry: quay.io + imageRepository: citrix/citrix-adc-metrics-exporter + imageTag: 1.4.9 + image: "{{ .Values.exporter.imageRegistry }}/{{ .Values.exporter.imageRepository }}:{{ .Values.exporter.imageTag }}" + pullPolicy: IfNotPresent + ports: + containerPort: 8888 + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + extraVolumeMounts: [] + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. + #- name: github-key + # mountPath: /etc/config/keys/ + # readOnly: true + #- name: agent-init-scripts + # mountPath: /docker-entrypoint.d/ + +# For CRDs supported by Citrix Ingress Controller +crds: + install: false + retainOnDelete: false + +# Config required to be done by Citrix Ingress Controller for sending metrics to Citrix Observability Exporter +analyticsConfig: + required: false + distributedTracing: + enable: false + samplingrate: 100 + endpoint: + server: + service: + timeseries: + port: 30002 + metrics: + enable: false + mode: 'avro' + auditlogs: + enable: false + events: + enable: false + transactions: + enable: false + port: 30001 + +nsLbHashAlgo: + required: false + hashFingers: 256 + hashAlgorithm: 'DEFAULT' + +# Specifies whether a ServiceAccount should be created +serviceAccount: + create: true + # The name of the ServiceAccount to use. + # If not set and `create` is true, a name is generated using the fullname template + # name: + +podAnnotations: {} + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # Following values depends on no of ingresses configured by Ingress Controllers, so it is + # advised to test with maximum no of ingresses to set these values. + # limits: + # cpu: 1000m + # memory: 1000Mi + # requests: + # cpu: 500m + # memory: 500Mi + +affinity: {} + +extraVolumeMounts: [] + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. + #- name: github-key + # mountPath: /etc/config/keys/ + # readOnly: true + #- name: agent-init-scripts + # mountPath: /docker-entrypoint.d/ + +extraVolumes: [] + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. + #- name: agent-init-scripts + # configMap: + # name: agent-init-scripts + # defaultMode: 0755 + #- name: github-key + # secret: + # secretName: github-key + # defaultMode: 0744 diff --git a/index.yaml b/index.yaml index d80f93967..f354f20fc 100644 --- a/index.yaml +++ b/index.yaml @@ -2010,6 +2010,31 @@ entries: - assets/codefresh/cf-runtime-0.1.401.tgz version: 0.1.401 citrix-adc-istio-ingress-gateway: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Adc Istio Ingress Gateway + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-adc-istio-ingress-gateway + apiVersion: v2 + appVersion: 1.14.0 + created: "2022-12-01T23:59:01.209934-05:00" + description: A Helm chart for Citrix ADC as Ingress Gateway installation in Istio + Service Mesh on Kubernetes platform + digest: 97fbe0c1968d5125c060b8ce706c743da4be20273c5ace5f2c9eeb8477cf2bcf + home: https://www.citrix.com + icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png + kubeVersion: '>=v1.16.0-0' + maintainers: + - email: dhiraj.gedam@citrix.com + name: dheerajng + - email: subash.dangol@citrix.com + name: subashd + name: citrix-adc-istio-ingress-gateway + sources: + - https://github.com/citrix/citrix-xds-adaptor + urls: + - assets/citrix/citrix-adc-istio-ingress-gateway-1.14.0.tgz + version: 1.14.0 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Citrix Adc Istio Ingress Gateway @@ -2034,7 +2059,7 @@ entries: sources: - https://github.com/citrix/citrix-xds-adaptor urls: - - assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.1.tgz + - assets/citrix/citrix-adc-istio-ingress-gateway-1.11.1.tgz version: 1.11.1 - annotations: catalog.cattle.io/certified: partner @@ -2060,7 +2085,7 @@ entries: sources: - https://github.com/citrix/citrix-xds-adaptor urls: - - assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.11.0.tgz + - assets/citrix/citrix-adc-istio-ingress-gateway-1.11.0.tgz version: 1.11.0 - annotations: catalog.cattle.io/certified: partner @@ -2082,9 +2107,34 @@ entries: sources: - https://github.com/citrix/citrix-istio-adaptor urls: - - assets/citrix-adc-istio-ingress-gateway/citrix-adc-istio-ingress-gateway-1.2.100.tgz + - assets/citrix/citrix-adc-istio-ingress-gateway-1.2.100.tgz version: 1.2.100 citrix-cpx-istio-sidecar-injector: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Cpx Istio Sidecar Injector + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-cpx-istio-sidecar-injector + apiVersion: v2 + appVersion: 1.14.1 + created: "2022-12-01T23:59:01.212143-05:00" + description: A Helm chart to deploy resources which install Citrix ADC CPX in + Istio Service Mesh as sidecar in application pod + digest: 3f47026101ddc3f23ad6e9d7b15137aa8ac9c474bb066c4cc78c886b32ee44bd + home: https://www.citrix.com + icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png + kubeVersion: '>=v1.16.0-0' + maintainers: + - email: dhiraj.gedam@citrix.com + name: dheerajng + - email: subash.dangol@citrix.com + name: subashd + name: citrix-cpx-istio-sidecar-injector + sources: + - https://github.com/citrix/citrix-xds-adaptor + urls: + - assets/citrix/citrix-cpx-istio-sidecar-injector-1.14.1.tgz + version: 1.14.1 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Citrix Cpx Istio Sidecar Injector @@ -2109,7 +2159,7 @@ entries: sources: - https://github.com/citrix/citrix-xds-adaptor urls: - - assets/citrix-cpx-istio-sidecar-injector/citrix-cpx-istio-sidecar-injector-1.11.1.tgz + - assets/citrix/citrix-cpx-istio-sidecar-injector-1.11.1.tgz version: 1.11.1 - annotations: catalog.cattle.io/certified: partner @@ -2135,9 +2185,34 @@ entries: sources: - https://github.com/citrix/citrix-xds-adaptor urls: - - assets/citrix-cpx-istio-sidecar-injector/citrix-cpx-istio-sidecar-injector-1.11.0.tgz + - assets/citrix/citrix-cpx-istio-sidecar-injector-1.11.0.tgz version: 1.11.0 citrix-cpx-with-ingress-controller: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Cpx with Ingress Controller + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-cpx-with-ingress-controller + apiVersion: v2 + appVersion: 1.27.15 + created: "2022-12-01T23:59:01.213129-05:00" + description: A Helm chart for Citrix ADC CPX with Citrix ingress Controller running + as sidecar. + digest: cdd942918f67ddbae6aaabd7fbbcc51f0435351f12c2225b45f6c380bff8d54a + home: https://www.citrix.com + icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png + kubeVersion: '>=v1.16.0-0' + maintainers: + - email: priyanka.sharma@citrix.com + name: priyankash-citrix + - email: subash.dangol@citrix.com + name: subashd + name: citrix-cpx-with-ingress-controller + sources: + - https://github.com/citrix/citrix-k8s-ingress-controller + urls: + - assets/citrix/citrix-cpx-with-ingress-controller-1.27.15.tgz + version: 1.27.15 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/release-name: citrix-cpx-with-ingress-controller @@ -2158,9 +2233,33 @@ entries: sources: - https://github.com/citrix/citrix-k8s-ingress-controller urls: - - assets/citrix-cpx-with-ingress-controller/citrix-cpx-with-ingress-controller-1.8.2800.tgz + - assets/citrix/citrix-cpx-with-ingress-controller-1.8.2800.tgz version: 1.8.2800 citrix-ingress-controller: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Citrix Ingress Controller + catalog.cattle.io/kube-version: '>=v1.16.0-0' + catalog.cattle.io/release-name: citrix-ingress-controller + apiVersion: v2 + appVersion: 1.27.15 + created: "2022-12-01T23:59:01.21585-05:00" + description: A Helm chart for Citrix Ingress Controller configuring MPX/VPX. + digest: 236a9b2e391bf5a89d0e77ebf8f5af174421ed0c81dabea2268f50d6b66d935a + home: https://www.citrix.com + icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png + kubeVersion: '>=v1.16.0-0' + maintainers: + - email: priyanka.sharma@citrix.com + name: priyankash-citrix + - email: subash.dangol@citrix.com + name: subashd + name: citrix-ingress-controller + sources: + - https://github.com/citrix/citrix-k8s-ingress-controller + urls: + - assets/citrix/citrix-ingress-controller-1.27.15.tgz + version: 1.27.15 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Citrix Ingress Controller @@ -2182,7 +2281,7 @@ entries: sources: - https://github.com/citrix/citrix-k8s-ingress-controller urls: - - assets/citrix-ingress-controller/citrix-ingress-controller-1.19.600.tgz + - assets/citrix/citrix-ingress-controller-1.19.600.tgz version: 1.19.600 cloudcasa: - annotations: diff --git a/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/Chart.yaml.patch b/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/Chart.yaml.patch deleted file mode 100644 index 848158d00..000000000 --- a/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/Chart.yaml.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- charts-original/Chart.yaml -+++ charts/Chart.yaml -@@ -1,10 +1,14 @@ -+annotations: -+ catalog.cattle.io/certified: partner -+ catalog.cattle.io/display-name: Citrix Adc Istio Ingress Gateway -+ catalog.cattle.io/release-name: citrix-adc-istio-ingress-gateway - apiVersion: v2 - appVersion: "1.11.0" - kubeVersion: ">=v1.16.0-0" - description: A Helm chart for Citrix ADC as Ingress Gateway installation in Istio Service Mesh on Kubernetes platform - name: citrix-adc-istio-ingress-gateway - version: 1.11.0 --icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png -+icon: https://raw.githubusercontent.com/citrix/citrix-xds-adaptor/master/docs/media/Citrix_Logo_Trademark.png - home: https://www.citrix.com - sources: - - https://github.com/citrix/citrix-xds-adaptor -@@ -13,3 +17,5 @@ - email: dhiraj.gedam@citrix.com - - name: subashd - email: subash.dangol@citrix.com -+- name: ajeetas -+ email: ajeeta.shaket@citrix.com diff --git a/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/values.yaml.patch b/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/values.yaml.patch deleted file mode 100644 index a2cea8271..000000000 --- a/packages/citrix-adc-istio-ingress-gateway/generated-changes/patch/values.yaml.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- charts-original/values.yaml -+++ charts/values.yaml -@@ -48,7 +48,7 @@ - mgmtHttpsPort: 10443 - httpNodePort: 30180 - httpsNodePort: 31443 -- nodePortRequired: false -+ nodePortRequired: true - lightWeightCPX: 1 - secretVolumes: - #licenseServerIP: this value will be taken from ADMSettings.ADMIP diff --git a/packages/citrix-adc-istio-ingress-gateway/package.yaml b/packages/citrix-adc-istio-ingress-gateway/package.yaml deleted file mode 100644 index 720bbbca6..000000000 --- a/packages/citrix-adc-istio-ingress-gateway/package.yaml +++ /dev/null @@ -1,4 +0,0 @@ -url: https://github.com/citrix/citrix-helm-charts.git -subdirectory: citrix-adc-istio-ingress-gateway -commit: c34bc90141ad8fb2809610ee9d7cb55c90aa6e08 -packageVersion: 01 diff --git a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/Chart.yaml.patch b/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/Chart.yaml.patch deleted file mode 100644 index 55624834b..000000000 --- a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/Chart.yaml.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- charts-original/Chart.yaml -+++ charts/Chart.yaml -@@ -1,10 +1,14 @@ -+annotations: -+ catalog.cattle.io/certified: partner -+ catalog.cattle.io/display-name: Citrix Cpx Istio Sidecar Injector -+ catalog.cattle.io/release-name: citrix-cpx-istio-sidecar-injector - apiVersion: v2 - appVersion: "1.11.0" - kubeVersion: ">=v1.16.0-0" - description: A Helm chart to deploy resources which install Citrix ADC CPX in Istio Service Mesh as sidecar in application pod - name: citrix-cpx-istio-sidecar-injector - version: 1.11.0 --icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png -+icon: https://raw.githubusercontent.com/citrix/citrix-xds-adaptor/master/docs/media/Citrix_Logo_Trademark.png - home: https://www.citrix.com - sources: - - https://github.com/citrix/citrix-xds-adaptor -@@ -13,3 +17,5 @@ - email: dhiraj.gedam@citrix.com - - name: subashd - email: subash.dangol@citrix.com -+- name: ajeetas -+ email: ajeeta.shakeet@citrix.com diff --git a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/README.md.patch b/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/README.md.patch deleted file mode 100644 index f6a820b77..000000000 --- a/packages/citrix-cpx-istio-sidecar-injector/generated-changes/patch/README.md.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- charts-original/README.md -+++ charts/README.md -@@ -163,7 +163,7 @@ - helm install cpx-sidecar-injector citrix/citrix-cpx-istio-sidecar-injector --namespace citrix-system --set cpxProxy.EULA=YES --set ADMSettings.ADMIP= - - > **Note:** --> If container agent is being used here for Citrix ADM, specify `serviceIP` of container agent in the `ADMSettings.ADMIP` parameter. -+> If container agent is being used here for Citrix ADM, specify `PodIP` of container agent in the `ADMSettings.ADMIP` parameter. - - ## Generate Certificate for Application - diff --git a/packages/citrix-cpx-istio-sidecar-injector/package.yaml b/packages/citrix-cpx-istio-sidecar-injector/package.yaml deleted file mode 100644 index b5e9f253c..000000000 --- a/packages/citrix-cpx-istio-sidecar-injector/package.yaml +++ /dev/null @@ -1,4 +0,0 @@ -url: https://github.com/citrix/citrix-helm-charts.git -subdirectory: citrix-cpx-istio-sidecar-injector -commit: c34bc90141ad8fb2809610ee9d7cb55c90aa6e08 -packageVersion: 01 diff --git a/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/Chart.yaml.patch b/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/Chart.yaml.patch deleted file mode 100644 index 10431631b..000000000 --- a/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/Chart.yaml.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- charts-original/Chart.yaml -+++ charts/Chart.yaml -@@ -13,3 +13,6 @@ - sources: - - https://github.com/citrix/citrix-k8s-ingress-controller - version: 1.8.28 -+annotations: -+ catalog.cattle.io/certified: partner -+ catalog.cattle.io/release-name: citrix-cpx-with-ingress-controller diff --git a/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/README.md.patch b/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/README.md.patch deleted file mode 100644 index 601001beb..000000000 --- a/packages/citrix-cpx-with-ingress-controller/generated-changes/patch/README.md.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- charts-original/README.md -+++ charts/README.md -@@ -187,7 +187,7 @@ - | ADMSettings.cpxCores | Optional | 1 | Desired number of vCPU to be set for Citrix ADC CPX. | - - | exporter.required | Optional | false | Use the argument if you want to run the [Exporter for Citrix ADC Stats](https://github.com/citrix/citrix-adc-metrics-exporter) along with Citrix ingress controller to pull metrics for the Citrix ADC CPX| --| exporter.image | Optional | `quay.io/citrix/citrix-adc-metrics-exporter:1.4.4` | The Exporter for Citrix ADC Stats image. | -+| exporter.image | Optional | `quay.io/citrix/citrix-adc-metrics-exporter:1.4.5` | The Exporter for Citrix ADC Stats image. | - | exporter.pullPolicy | Optional | IfNotPresent | The Exporter for Citrix ADC Stats image pull policy. | - | exporter.ports.containerPort | Optional | 8888 | The Exporter for Citrix ADC Stats container port. | - diff --git a/packages/citrix-cpx-with-ingress-controller/package.yaml b/packages/citrix-cpx-with-ingress-controller/package.yaml deleted file mode 100644 index f28467eea..000000000 --- a/packages/citrix-cpx-with-ingress-controller/package.yaml +++ /dev/null @@ -1,2 +0,0 @@ -url: https://citrix.github.io/citrix-helm-charts/citrix-cpx-with-ingress-controller-1.8.28.tgz -packageVersion: 00 diff --git a/packages/citrix-ingress-controller/generated-changes/patch/Chart.yaml.patch b/packages/citrix-ingress-controller/generated-changes/patch/Chart.yaml.patch deleted file mode 100644 index ea0e623b8..000000000 --- a/packages/citrix-ingress-controller/generated-changes/patch/Chart.yaml.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- charts-original/Chart.yaml -+++ charts/Chart.yaml -@@ -1,8 +1,12 @@ -+annotations: -+ catalog.cattle.io/certified: partner -+ catalog.cattle.io/display-name: Citrix Ingress Controller -+ catalog.cattle.io/release-name: citrix-ingress-controller - apiVersion: v2 - appVersion: 1.19.6 - description: A Helm chart for Citrix Ingress Controller configuring MPX/VPX. - home: https://www.citrix.com --icon: https://raw.githubusercontent.com/citrix/citrix-helm-charts/gh-pages/icon.png -+icon: https://raw.githubusercontent.com/citrix/citrix-xds-adaptor/master/docs/media/Citrix_Logo_Trademark.png - kubeVersion: '>=v1.16.0-0' - maintainers: - - email: priyanka.sharma@citrix.com diff --git a/packages/citrix-ingress-controller/package.yaml b/packages/citrix-ingress-controller/package.yaml deleted file mode 100644 index d556cc76b..000000000 --- a/packages/citrix-ingress-controller/package.yaml +++ /dev/null @@ -1,2 +0,0 @@ -url: https://citrix.github.io/citrix-helm-charts/citrix-ingress-controller-1.19.6.tgz -packageVersion: 00 diff --git a/packages/citrix-adc-istio-ingress-gateway/generated-changes/overlay/app-readme.md b/packages/citrix/citrix-adc-istio-ingress-gateway/overlay/app-readme.md similarity index 100% rename from packages/citrix-adc-istio-ingress-gateway/generated-changes/overlay/app-readme.md rename to packages/citrix/citrix-adc-istio-ingress-gateway/overlay/app-readme.md diff --git a/packages/citrix-adc-istio-ingress-gateway/generated-changes/overlay/questions.yml b/packages/citrix/citrix-adc-istio-ingress-gateway/overlay/questions.yml similarity index 100% rename from packages/citrix-adc-istio-ingress-gateway/generated-changes/overlay/questions.yml rename to packages/citrix/citrix-adc-istio-ingress-gateway/overlay/questions.yml diff --git a/packages/citrix/citrix-adc-istio-ingress-gateway/upstream.yaml b/packages/citrix/citrix-adc-istio-ingress-gateway/upstream.yaml new file mode 100644 index 000000000..ca70553cc --- /dev/null +++ b/packages/citrix/citrix-adc-istio-ingress-gateway/upstream.yaml @@ -0,0 +1,4 @@ +HelmRepo: https://citrix.github.io/citrix-helm-charts +HelmChart: citrix-adc-istio-ingress-gateway +Vendor: Citrix +DisplayName: Citrix Adc Istio Ingress Gateway diff --git a/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/app-readme.md b/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/app-readme.md new file mode 100644 index 000000000..aa16d2136 --- /dev/null +++ b/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/app-readme.md @@ -0,0 +1,28 @@ +# Citrix ADC as a Sidecar for Istio + +Citrix ADC [CPX](https://docs.citrix.com/en-us/citrix-adc-cpx) can act as a sidecar proxy to an application container in Istio. You can inject the Citrix ADC CPX manually or automatically using the [Istio sidecar injector](https://istio.io/docs/setup/additional-setup/sidecar-injection/). + + +### Prerequisites + +The following prerequisites are required for deploying Citrix ADC as a sidecar in an application pod + +- Ensure that **Istio** is enabled. +- Ensure that your cluster has Kubernetes version 1.16.0 or later. +- Ensure the [Kubernetes controller manager](https://rancher.com/docs/rke/latest/en/config-options/services/#kubernetes-controller-manager)’s default certificate signer is enabled. + +**Note**: For RKE based cluster, extra arguments need to be provided for kube-controller service. +```services: + kube-controller: + extra_args: + cluster-signing-cert-file: "/etc/kubernetes/ssl/kube-ca.pem" + cluster-signing-key-file: "/etc/kubernetes/ssl/kube-ca-key.pem" +``` +For detailed information follow this [link](https://github.com/citrix/citrix-xds-adaptor/blob/master/docs/istio-integration/rancher-provisioned-cluster.md) + +### Important NOTE: + - We should not **Enable Istio Auto Injection** on Application namespace. + - The cpx-injection=enabled label is mandatory for injecting sidecars. + - An example to deploy application along with Citrix ADC CPX sidecar is provided [here](https://github.com/citrix/citrix-helm-charts/blob/master/examples/citrix-adc-in-istio/README.md). + +This catalog create resources required for automatically deploying Citrix ADC CPX as a sidecar proxy.For detailed information follow this [link](https://github.com/citrix/citrix-helm-charts/tree/master/citrix-cpx-istio-sidecar-injector) diff --git a/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/questions.yml b/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/questions.yml new file mode 100644 index 000000000..18483b84a --- /dev/null +++ b/packages/citrix/citrix-cpx-istio-sidecar-injector/overlay/questions.yml @@ -0,0 +1,291 @@ +labels: + io.rancher.certified: partner +questions: +- variable: xDSAdaptor.image + required: true + type: string + default: "quay.io/citrix/citrix-xds-adaptor:0.9.9" + description: "xds-adaptor Image to be used" + label: xDSAdaptor Image + group: "xDSAdaptor Settings" +- variable: xDSAdaptor.imagePullPolicy + required: true + type: enum + default: IfNotPresent + description: "Istio-adaptor Image pull policy" + label: istioAdaptor imagePullPolicy + options: + - "Always" + - "IfNotPresent" + - "Never" + group: "xDSAdaptor Settings" +- variable: xDSAdaptor.proxyType + required: true + type: string + default: true + label: xDSAdaptor proxyType + description: "xDSAdaptor proxyType type set to router by default" + group: "xDSAdaptor Settings" +- variable: xDSAdaptor.secureConnect + required: false + type: boolean + default: true + label: xDSAdaptor secureConnect + description: "xDSAdaptor establishes secure gRPC channel with Istio Pilot, if value is set to true" + group: "xDSAdaptor Settings" +- variable: xDSAdaptor.logLevel + required: false + type: enum + default: DEBUG + label: xDSAdaptor logLevel + description: "xDSAdaptor logLevel" + options: + - "TRACE" + - "DEBUG" + - "INFO" + - "WARN" + - "ERROR" + group: "xDSAdaptor Settings" +- variable: xDSAdaptor.jsonLog + required: false + type: string + default: "true" + label: xDSAdaptor jsonLog + description: "Set this argument to true if log messages are required in JSON format" + group: "xDSAdaptor Settings" +- variable: coe.coeURL + required: false + type: string + label: coe coeURL + description: "Name of Citrix Observability Exporter Service" + group: "COE Settings" +- variable: coe.coeTracing + required: false + type: boolean + label: coe coeTracing + description: "Used to send appflow transactions to Zipkin endpoint,if true ADM servicegraph (if configured) can be impacted" + group: "COE Settings" +- variable: istioPilot.name + required: true + type: string + default: istio-pilot + label: istio-pilot name + group: "istio-pilot Settings" +- variable: istioPilot.namespace + required: true + type: string + default: istio-system + label: istio-pilot namespace + description: "Name of the Istio Pilot service" + group: "istio-pilot Settings" +- variable: istioPilot.secureGrpcPort + required: true + type: int + default: 15011 + description: "Secure GRPC port where Istio Pilot is listening" + label: istio-pilot secureGrpcPort + show_if: "xDSAdaptor.secureConnect=true" + group: "istio-pilot Settings" +- variable: istioPilot.insecureGrpcPort + required: true + type: int + default: 15010 + label: istio-pilot insecureGrpcPort + description: "Insecure GRPC port where Istio Pilot is listening" + show_if: "xDSAdaptor.secureConnect=false" + group: "istio-pilot Settings" +- variable: istioPilot.SAN + required: false + type: string + default: + label: istio-pilot SAN + description: "Subject alternative name for Istio Pilot which is (SPIFFE) ID of Istio Pilot" + show_if: "xDSAdaptor.secureConnect=true" + group: "istio-pilot Settings" +- variable: certProvider.caAddr + required: true + type: string + default: "istiod.istio-system.svc" + label: certProvider caAddr + description: "Certificate Authority (CA) address issuing certificate to application" + group: "certProvider Settings" +- variable: certProvider.caPort + required: true + type: int + default: 15012 + label: certProvider caPort + description: "Certificate Authority (CA) port issuing certificate to application" + group: "certProvider Settings" +- variable: certProvider.trustDomain + required: true + type: string + default: "cluster.local" + label: certProvider trustDomain + description: "SPIFFE Trust Domain" + group: "certProvider Settings" +- variable: certProvider.certTTLinHours + required: true + type: int + default: 720 + label: certProvider certTTLinHours + description: "Validity of certificate generated by xds-adaptor and signed by Istiod (Istio Citadel) in hours." + group: "certProvider Settings" +- variable: certProvider.clusterId + required: true + type: string + default: "Kubernetes" + label: certProvider clusterId + description: "clusterId is the ID of the cluster where Istiod CA instance resides (default Kubernetes). It can be different value on some cloud platforms or in m +ulticluster environments. For example, in Anthos servicemesh, it might be of the format of `cn--`. In multiCluster environments, it is the val +ue of global.multiCluster.clusterName provided during servicemesh control plane installation" + group: "certProvider Settings" +- variable: certProvider.jwtPolicy + required: true + type: enum + default: "first-party-jwt" + label: certProvider jwtPolicy + description: "Kubernetes platform supports First party tokens and Third party tokens" + options: + - "first-party-jwt" + - "third-party-jwt" +- variable: cpxProxy.netscalerUrl + required: true + type: string + default: "http://127.0.0.1" + description: "Citrix ADC CPX image used as sidecar proxy" + label: cpxProxy image + group: "cpxProxy Settings" +- variable: cpxProxy.image + required: true + type: string + default: "quay.io/citrix/citrix-k8s-cpx-ingress:13.0-79.64" + description: "Citrix ADC CPX image used as sidecar proxy" + label: cpxProxy image + group: "cpxProxy Settings" +- variable: cpxProxy.imagePullPolicy + required: true + type: enum + default: IfNotPresent + description: "cpxProxy Image pull policy" + label: cpxProxy imagePullPolicy + options: + - "Always" + - "IfNotPresent" + - "Never" + group: "cpxProxy Settings" +- variable: cpxProxy.EULA + required: true + type: enum + label: cpxProxy EULA license + options: + - "YES" + - "NO" + group: "cpxProxy Settings" +- variable: cpxProxy.cpxSidecarMode + required: true + type: string + default: "YES" + description: "Environment variable for Citrix ADC CPX. It indicates that Citrix ADC CPX is running as sidecar mode or not" + label: cpxProxy image + options: + - "YES" + - "NO" + group: "cpxProxy Settings" +- variable: cpxProxy.mgmtHttpPort + required: true + type: int + default: 10080 + label: cpxProxy mgmtHttpPort + group: "cpxProxy Settings" +- variable: cpxProxy.mgmtHttpsPort + required: true + type: int + default: 10443 + label: cpxProxy mgmtHttpsPort + group: "cpxProxy Settings" +- variable: cpxProxy.cpxDisableProbe + required: true + type: string + default: YES + description: "Environment variable for Citrix ADC CPX. It indicates that Citrix ADC CPX will disable probing dynamic services. It should be enabled for multicluster setup." + label: cpxProxy cpxDisableProbe + options: + - "YES" + - "NO" + group: "cpxProxy Settings" +- variable: sidecarWebHook.webhookImage + required: true + type: string + default: "quay.io/citrix/cpx-istio-sidecar-injector:1.0.0" + label: sidecarWebHook webhookImage + description: "webhookImage image to be used" + group: "sidecarWebHook Settings" +- variable: sidecarWebHook.imagePullPolicy + required: true + type: enum + default: IfNotPresent + label: sidecarWebHook imagePullPolicy + options: + - "Always" + - "IfNotPresent" + - "Never" + group: "sidecarWebHook Settings" +- variable: sidecarCertsGenerator.image + required: true + type: string + default: " quay.io/citrix/cpx-sidecar-injector-certgen:1.1.0" + label: sidecarWebHook webhookImage + description: "webhookImage image to be used" + group: "sidecarCertsGenerator Settings" +- variable: sidecarCertsGenerator.imagePullPolicy + required: true + type: enum + default: IfNotPresent + label: sidecarWebHook imagePullPolicy + options: + - "Always" + - "IfNotPresent" + - "Never" + group: "sidecarCertsGenerator Settings" +- variable: ADMSettings.ADMIP + required: false + type: string + default: + label: ADMSettings ADMIP + description: "Citrix Application Delivery Management (ADM) IP address" + group: "ADMSettings Settings" +- variable: ADMSettings.licenseServerIP + required: false + type: string + default: + label: ADMSettings licenseServerIP + description: "Citrix License Server IP address" + group: "ADMSettings Settings" +- variable: ADMSettings.licenseServerPort + required: false + type: int + default: 27000 + label: ADMSettings licenseServerPort + description: "Citrix ADM port if a non-default port is used" + group: "ADMSettings Settings" +- variable: ADMSettings.bandWidthLicense + required: false + type: boolean + default: false + label: ADMSettings bandWidthLicense + description: "To specify bandwidth based licensing" + group: "ADMSettings Settings" +- variable: ADMSettings.bandWidth + required: false + type: string + default: + label: ADMSettings bandWidth + description: "Desired bandwidth capacity to be set for Citrix ADC CPX in Mbps" + group: "ADMSettings Settings" +- variable: webhook.injectionLabelName + required: true + type: string + default: "cpx-injection" + label: webhook injectionLabelName + description: "Label of namespace, where automatic sidecr injection is required" + group: "webhook Settings" diff --git a/packages/citrix/citrix-cpx-istio-sidecar-injector/upstream.yaml b/packages/citrix/citrix-cpx-istio-sidecar-injector/upstream.yaml new file mode 100644 index 000000000..fcd5a87b8 --- /dev/null +++ b/packages/citrix/citrix-cpx-istio-sidecar-injector/upstream.yaml @@ -0,0 +1,4 @@ +HelmRepo: https://citrix.github.io/citrix-helm-charts +HelmChart: citrix-cpx-istio-sidecar-injector +Vendor: Citrix +DisplayName: Citrix Cpx Istio Sidecar Injector diff --git a/packages/citrix/citrix-cpx-with-ingress-controller/overlay/app-readme.md b/packages/citrix/citrix-cpx-with-ingress-controller/overlay/app-readme.md new file mode 100644 index 000000000..ef45a3d90 --- /dev/null +++ b/packages/citrix/citrix-cpx-with-ingress-controller/overlay/app-readme.md @@ -0,0 +1,5 @@ +# Citrix ADC CPX with Citrix Ingress Controller running as sidecar. + +In a [Kubernetes](https://kubernetes.io/) or [OpenShift](https://www.openshift.com) cluster, you can deploy [Citrix ADC CPX](https://docs.citrix.com/en-us/citrix-adc-cpx) with Citrix ingress controller as a [sidecar](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/). The Citrix ADC CPX instance is used for load balancing the North-South traffic to the microservices in your cluster. And, the sidecar Citrix ingress controller configures the Citrix ADC CPX. + +This Chart bootstraps deployment of Citrix ADC CPX with Citrix Ingress Controller as sidecar. diff --git a/packages/citrix/citrix-cpx-with-ingress-controller/overlay/questions.yml b/packages/citrix/citrix-cpx-with-ingress-controller/overlay/questions.yml new file mode 100644 index 000000000..0c8714413 --- /dev/null +++ b/packages/citrix/citrix-cpx-with-ingress-controller/overlay/questions.yml @@ -0,0 +1,211 @@ +questions: +- variable: license.accept + required: true + default: "no" + type: enum + description: "Set to yes to accept the terms and conditions of the Citrix license." + label: Accept License + group: "Deployment Settings" + options: + - "yes" + - "no" +- variable: openshift + default: false + type: boolean + description: "openshift is set to true if charts are being deployed in OpenShift environment" + label: Openshift flag + group: "Deployment Settings" +- variable: nsNamespace + type: string + description: "Prefix for the resources on Citrix ADC" + label: Resource Prefix + group: "Deployment Settings" +- variable: ingressClass[0] + type: string + description: "ingressClass is the name of the Ingress Class" + label: Ingress Class + group: "Deployment Settings" +- variable: logLevel + default: "DEBUG" + type: enum + options: + - "TRACE" + - "DEBUG" + - "INFO" + - "WARNING" + - "ERROR" + description: "logLevel of Citrix Ingress Controller pod" + label: LogLevel + group: "Deployment Settings" +- variable: defaultSSLCert + type: string + description: "Secret containing the default ceritifcate for SSL vservers" + label: Default SSLCert + group: "ADC Settings" +- variable: logProxy + type: string + description: "Elasticsearch or Kafka or Zipkin endpoint for Citrix observability exporte" + label: LogProxy + group: "Deployment Settings" +- variable: http2ServerSide + default: "OFF" + type: enum + options: + - "ON" + - "OFF" + description: "Set to ON to enable HTTP2 for Citrix ADC service group configurations" + label: HTTP2 on ADC + group: "ADC Settings" +- variable: nodeSelector.key + type: string + label: NodeSelector Key + group: "Deployment Settings" +- variable: nodeSelector.value + type: string + label: NodeSelector Value + group: "Deployment Settings" + + +- variable: ADMSettings.licenseServerIP + type: string + label: ADM LicenseServerIP + group: "ADM Settings" +- variable: ADMSettings.licenseServerPort + default: 27000 + type: int + label: ADM LicenseServerPort + group: "ADM Settings" +- variable: ADMSettings.ADMIP + type: string + label: ADM IP + group: "ADM Settings" +- variable: ADMSettings.ADMFingerPrint + type: string + label: ADM FingerPrint + group: "ADM Settings" +- variable: ADMSettings.loginSecret + type: string + label: ADM Login Secret + group: "ADM Settings" +- variable: ADMSettings.bandWidthLicense + type: boolean + label: CPX Bandwidth License + group: "ADM Settings" +- variable: ADMSettings.bandWidth + type: int + label: CPX Bandwidth + group: "ADM Settings" +- variable: ADMSettings.vCPULicense + type: boolean + label: CPX vCPU License + group: "ADM Settings" +- variable: ADMSettings.cpxCores + type: int + label: CPX Cores + group: "ADM Settings" +- variable: cic.pullpolicy + default: "IfNotPresent" + type: enum + label: CIC Image Pullpolicy + group: "CIC/CPX Image Settings" + options: + - "Always" + - "IfNotPresent" + - "Never" +- variable: pullpolicy + default: "IfNotPresent" + type: enum + label: CPX Image Pullpolicy + group: "CIC/CPX Image Settings" + options: + - "Always" + - "IfNotPresent" + - "Never" +- variable: cic.image + default: "quay.io/citrix/citrix-k8s-ingress-controller:1.8.28" + type: string + label: CIC Image + group: "CIC/CPX Image Settings" +- variable: image + type: string + default: "quay.io/citrix/citrix-k8s-cpx-ingress:13.0-58.30" + label: CPX Image + group: "CIC/CPX Image Settings" +- variable: exporter.image + default: "quay.io/citrix/citrix-adc-metrics-exporter:1.4.5" + type: string + description: "Exporter Image to be used" + label: Exporter Image + group: "Exporter Settings" +- variable: exporter.pullPolicy + default: "IfNotPresent" + type: string + description: "Exporter Image pull policy" + label: Exporter Image PullPolicy + group: "Exporter Settings" +- variable: exporter.ports.containerPort + default: 8888 + type: int + label: Exporter ContainerPort + group: "Exporter Settings" +- variable: coeConfig.distributedTracing.enable + default: false + type: boolean + label: Enable distributedTracing + group: "COE Settings" +- variable: coeConfig.distributedTracing.samplingrate + default: 100 + type: int + label: COE Sampling Rate + group: "COE Settings" +- variable: coeConfig.endpoint.server + type: string + label: COE Endpoint Server + group: "COE Settings" +- variable: coeConfig.timeseries.port + default: 5563 + type: int + label: COE timeseries port + group: "COE Settings" +- variable: coeConfig.timeseries.metrics.enable + default: false + type: boolean + label: Enable timeseries metrics + group: "COE Settings" +- variable: coeConfig.timeseries.metrics.mode + default: 'avro' + type: string + label: COE timeseries metrics Mode + group: "COE Settings" +- variable: coeConfig.timeseries.auditlogs.enable + default: false + type: string + label: Enable timeseries auditlogs + group: "COE Settings" +- variable: coeConfig.timeseries.events.enable + default: false + type: string + label: Enable timeseries events + group: "COE Settings" +- variable: coeConfig.transactions.enable + default: false + type: string + label: Enable transactions + group: "COE Settings" +- variable: coeConfig.transactions.port + default: 5557 + type: int + label: COE transactions port + group: "COE Settings" +- variable: crds.install + default: true + type: boolean + description: "If set to true the charts will install CustomResourceDefinitions which are consumed by CIC." + label: CRD flag + group: "Deployment Settings" +- variable: crds.retainOnDelete + default: false + type: boolean + description: "Set this argument to true if you want to retain CustomResourceDefinitions even after uninstalling CIC. This will avoid data-loss of Custom Resource Objects created before uninstallation." + label: CRD retainOnDelete flag + group: "Deployment Settings" diff --git a/packages/citrix/citrix-cpx-with-ingress-controller/upstream.yaml b/packages/citrix/citrix-cpx-with-ingress-controller/upstream.yaml new file mode 100644 index 000000000..759e259c3 --- /dev/null +++ b/packages/citrix/citrix-cpx-with-ingress-controller/upstream.yaml @@ -0,0 +1,4 @@ +HelmRepo: https://citrix.github.io/citrix-helm-charts +HelmChart: citrix-cpx-with-ingress-controller +Vendor: Citrix +DisplayName: Citrix Cpx with Ingress Controller diff --git a/packages/citrix/citrix-ingress-controller/overlay/app-readme.md b/packages/citrix/citrix-ingress-controller/overlay/app-readme.md new file mode 100644 index 000000000..a8a8ebc15 --- /dev/null +++ b/packages/citrix/citrix-ingress-controller/overlay/app-readme.md @@ -0,0 +1,5 @@ +# Citrix Ingress Controller + +[Citrix Ingress Controler](https://github.com/citrix/citrix-k8s-ingress-controller) is an ingress controller for Citrix ADC MPX (hardware), Citrix ADC VPX (virtualized), and Citrix ADC CPX (containerized) for bare metal and cloud deployments. It is built around Kubernetes Ingress and automatically configures Citrix ADC based on the Ingress resource configuration. + +This Chart bootstraps standalone Citrix Ingress Controller which can be used to configure Citrix MPX or VPX. diff --git a/packages/citrix/citrix-ingress-controller/overlay/questions.yml b/packages/citrix/citrix-ingress-controller/overlay/questions.yml new file mode 100644 index 000000000..89389ae11 --- /dev/null +++ b/packages/citrix/citrix-ingress-controller/overlay/questions.yml @@ -0,0 +1,348 @@ +labels: + io.rancher.certified: partner +questions: +- variable: license.accept + required: true + type: enum + description: "Set to yes to accept the terms and conditions of the Citrix license." + label: Accept License + group: "Deployment Settings" + options: + - "yes" + - "no" +- variable: openshift + default: false + type: boolean + description: "openshift is set to true if charts are being deployed in OpenShift environment" + label: Openshift flag + group: "Deployment Settings" +- variable: adcCredentialSecret + required: true + default: "" + type: string + description: "adcCredentialSecret is secret file for NetScaler login" + label: adcCredentialSecret Name + group: "Deployment Settings" +- variable: imagePullSecrets[0] + required: false + type: string + description: "Provide list of Kubernetes secrets to be used for pulling the images from a private Docker registry or repository" + label: imagePullSecrets + group: "Deployment Settings" +- variable: nsIP + required: true + type: string + description: "nsIP is NetScaler NSIP/SNIP, SNIP in case of HA (mgmt has to be enabled)" + label: Citrix ADC IP + group: "ADC Settings" +- variable: nsVIP + required: false + type: string + label: Virtual IP of Citrix ADC + group: "ADC Settings" +- variable: nsSNIPS + required: false + type: string + description: "The list of subnet IPAddresses on the Citrix ADC device, which will be used to create PBR Routes instead of Static Routes" + label: Citrix ADC nsSNIPS + group: "ADC Settings" +- variable: nsPort + required: false + default: 443 + type: int + description: "nsPort is port for ADC NITRO" + label: nsPort + group: "ADC Settings" +- variable: nsProtocol + required: false + default: "HTTPS" + type: string + description: "nsProtocol is protocol for ADC NITRO" + label: nsProtocol + group: "ADC Settings" +- variable: entityPrefix + required: false + type: string + description: "The prefix for the resources on the Citrix ADC VPX/MPX" + label: entityPrefix + group: "ADC Settings" +- variable: kubernetesURL + required: false + type: string + description: "kubernetesURL is for registering events to kubeapi server" + label: Kubernetes API-server URL + group: "Deployment Settings" +- variable: clusterName + required: false + type: string + description: "The unique identifier of the kubernetes cluster on which the CIC is deployed" + label: Cluster Name + group: "Deployment Settings" +- variable: ingressClass[0] + required: false + type: string + description: "ingressClass is the name of the Ingress Class" + label: Ingress Class + group: "Deployment Settings" +- variable: setAsDefaultIngressClass + required: false + default: False + type: boolean + description: "Set the IngressClass object as default ingress class. New Ingresses without an `ingressClassName` field specified will be assigned the class specified in ingressClass. Applicable only for kubernetes versions >= 1.19" + label: setAsDefaultIngressClass + group: "Deployment Settings" +- variable: serviceClass[0] + required: false + type: string + description: "serviceClass is the name of the Service Class" + label: Service Class + group: "Deployment Settings" +- variable: defaultSSLCertSecret + required: false + type: string + description: "Provide Kubernetes secret name that needs to be used as a default non-SNI certificate in Citrix ADC." + label: defaultSSLCertSecret + group: "ADC Settings" +- variable: podIPsforServiceGroupMembers + required: false + default: False + type: boolean + description: "By default Citrix Ingress Controller will add NodeIP and NodePort as service group members,This variable if set to True will change the behaviour to add pod IP and Pod port instead of nodeIP and nodePort." + label: podIPsforServiceGroupMembers + group: "Deployment Settings" +- variable: ignoreNodeExternalIP + required: false + default: False + type: boolean + label: ignoreNodeExternalIP + group: "Deployment Settings" +- variable: ipam + required: false + default: False + type: boolean + description: "Set this argument if you want to use the IPAM controller to automatically allocate an IP address to the service of type LoadBalancer" + label: ipam + group: "Deployment Settings" +- variable: logProxy + required: false + default: False + type: string + description: "Provide Elasticsearch or Kafka or Zipkin endpoint for Citrix observability exporter." + label: Log Proxy + group: "Deployment Settings" +- variable: nodeWatch + required: false + default: false + type: boolean + description: "nodeWatch is used for automatic route configuration on NetScaler towards the pod network" + label: NodeWatch + group: "ADC Settings" +- variable: cncPbr + required: false + default: false + type: boolean + description: "Use this argument to inform CIC that Citrix Node Controller(CNC) is configuring Policy Based Routes(PBR) on the Citrix ADC." + label: CNC PBR + group: "ADC Settings" +- variable: nodeSelector.key + required: false + type: string + description: "Node label key to be used for nodeSelector option in CIC deployment" + label: NodeSelector Key + group: "Deployment Settings" +- variable: nodeSelector.value + required: false + type: string + description: "Node label value to be used for nodeSelector option in CIC deployment." + label: NodeSelector value + group: "Deployment Settings" +- variable: tolerations[0] + required: false + type: string + description: "Specify the tolerations for the CIC deployment" + label: Tolerations + group: "Deployment Settings" +- variable: updateIngressStatus + required: false + default: false + type: boolean + description: "Set this argurment if Status.LoadBalancer.Ingress field of the Ingress resources managed by the Citrix ingress controller needs to be updated with allocated IP addresses" + label: Update Ingress Status + group: "Deployment Settings" +- variable: nsHTTP2ServerSide + required: false + default: "OFF" + type: string + description: "Set this argument to ON for enabling HTTP2 for Citrix ADC service group configurations." + label: nsHTTP2ServerSide + group: "Deployment Settings" +- variable: nsCookieVersion + required: false + default: "0" + type: string + description: "Specify the persistence cookie version (0 or 1)" + label: nsCookieVersion + group: "Deployment Settings" +- variable: routeLabels + required: false + type: string + description: "You can use this parameter to provide the route labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster." + label: Route Labels + group: "Deployment Settings" +- variable: namespaceLabels + required: false + type: string + description: "you can use this parameter to provide the namespace labels selectors to be used by Citrix Ingress Controller for routeSharding in OpenShift cluster" + label: namespaceLabels + group: "Deployment Settings" +- variable: cic.image + required: true + type: string + default: "quay.io/citrix/citrix-k8s-ingress-controller:1.19.6" + label: CIC Image + group: "CIC Image Settings" +- variable: cic.pullpolicy + required: true + default: "IfNotPresent" + type: enum + label: CIC Image Pullpolicy + group: "CIC Image Settings" + options: + - "Always" + - "IfNotPresent" + - "Never" +- variable: logLevel + required: false + default: "INFO" + type: enum + label: CIC Loglevel + group: "CIC Image Settings" + options: + - "DEBUG" + - "INFO" + - "WARNING" + - "ERROR" + - "TRACE" +- variable: exporter.required + default: false + type: boolean + description: "If set to true exporter will be deployed as sidecar" + label: Enable Exporter + group: "Exporter Settings" +- variable: exporter.image + default: "quay.io/citrix/citrix-adc-metrics-exporter:1.4.9" + required: false + type: string + description: "Exporter Image" + label: Exporter Image + group: "Exporter Settings" +- variable: exporter.pullPolicy + required: false + default: IfNotPresent + type: string + description: "Exporter Image pull policy" + label: Exporter Image PullPolicy + group: "Exporter Settings" +- variable: exporter.ports.containerPort + required: false + default: 8888 + type: int + label: Exporter ContainerPort + group: "Exporter Settings" +- variable: crds.install + required: false + default: true + type: boolean + description: "If set to true the charts will install CustomResourceDefinitions which are consumed by CIC." + label: CRD flag + group: "Deployment Settings" +- variable: crds.retainOnDelete + required: false + default: false + type: boolean + description: "Set this argument to true if you want to retain CustomResourceDefinitions even after uninstalling CIC. This will avoid data-loss of Custom Resource Objects created before uninstallation." + label: CRD retainOnDelete flag + group: "Deployment Settings" +- variable: coeConfig.required + required: true + default: false + type: boolean + description: "Set this to true if you want to configure Citrix ADC to send metrics and transaction records to COE" + label: Enable COE + group: "COE Settings" +- variable: coeConfig.distributedTracing.enable + required: false + default: false + type: boolean + description: "Set this value to true to enable OpenTracing in Citrix ADC." + label: Enable coeConfig DistributedTracing + group: "COE Settings" +- variable: coeConfig.distributedTracing.samplingrate + required: false + default: "100" + type: string + description: "Specifies the OpenTracing sampling rate in percentage." + label: coeConfig DistributedTracing Samplingrate + group: "COE Settings" +- variable: coeConfig.endpoint.server + required: false + type: string + description: "Set this value as the IP address or DNS address of the analytics server" + label: coeConfig Endpoint Server + group: "COE Settings" +- variable: coeConfig.timeseries.port + required: false + default: "30002" + type: string + description: "Specify the port used to expose COE service outside cluster for timeseries endpoint" + label: coeConfig timeseries Port + group: "COE Settings" +- variable: coeConfig.timeseries.metrics.enable + required: false + default: False + type: boolean + description: "Set this value to true to enable sending metrics from Citrix ADC" + label: Enable coeConfig Timeseries Metrics + group: "COE Settings" +- variable: coeConfig.timeseries.metrics.mode + required: false + default: "avro" + type: string + description: "Specifies the mode of metric endpoint" + label: coeConfig Timeseries Metrics Mode + group: "COE Settings" +- variable: coeConfig.timeseries.auditlogs.enable + required: false + default: False + type: boolean + description: "Set this value to true to export audit log data from Citrix ADC" + label: coeConfig Timeseries Auditlogs Enable + group: "COE Settings" +- variable: coeConfig.timeseries.events.enable + required: false + default: False + type: boolean + description: "Set this value to true to export events from the Citrix ADC" + label: Enable coeConfig Timeseries Events + group: "COE Settings" +- variable: coeConfig.transactions.enable + required: false + default: False + type: boolean + description: "Set this value to true to export transactions from Citrix ADC" + label: Enable coeConfig Transactions + group: "COE Settings" +- variable: coeConfig.transactions.port + required: false + default: 30001 + type: string + description: "Specify the port used to expose COE service outside cluster for transaction endpoint" + label: coeConfig Transactions Port + group: "COE Settings" +- variable: serviceAccount.create + required: false + default: true + type: boolean + description: "Specifies whether a ServiceAccount should be created" + label: ServiceAccount Create + group: "Deployment Settings" diff --git a/packages/citrix/citrix-ingress-controller/upstream.yaml b/packages/citrix/citrix-ingress-controller/upstream.yaml new file mode 100644 index 000000000..ec50de989 --- /dev/null +++ b/packages/citrix/citrix-ingress-controller/upstream.yaml @@ -0,0 +1,4 @@ +HelmRepo: https://citrix.github.io/citrix-helm-charts +HelmChart: citrix-ingress-controller +Vendor: Citrix +DisplayName: Citrix Ingress Controller