From 7b6abcd904dc9e10115b70f511e836d81c1a75be Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 18 Oct 2024 00:38:22 +0000 Subject: [PATCH] Added chart versions: airlock/microgateway: - 4.3.4 airlock/microgateway-cni: - 4.3.4 codefresh/cf-runtime: - 6.4.6 loft/loft: - 4.0.0 --- assets/airlock/microgateway-4.3.4.tgz | Bin 0 -> 61765 bytes assets/airlock/microgateway-cni-4.3.4.tgz | Bin 0 -> 10969 bytes assets/codefresh/cf-runtime-6.4.6.tgz | Bin 0 -> 43758 bytes assets/loft/loft-4.0.0.tgz | Bin 0 -> 9665 bytes .../microgateway-cni/4.3.4/.helmignore | 27 + .../airlock/microgateway-cni/4.3.4/Chart.yaml | 43 + .../airlock/microgateway-cni/4.3.4/README.md | 137 ++ .../microgateway-cni/4.3.4/gke-values.yaml | 4 + .../4.3.4/openshift-values.yaml | 15 + .../microgateway-cni/4.3.4/questions.yml | 18 + .../4.3.4/templates/NOTES.txt | 15 + .../4.3.4/templates/_helpers.tpl | 101 + .../4.3.4/templates/clusterrole.yaml | 22 + .../4.3.4/templates/clusterrolebinding.yaml | 20 + .../4.3.4/templates/configmap.yaml | 22 + .../4.3.4/templates/daemonset.yaml | 136 ++ .../network-attachment-definition.yaml | 13 + .../4.3.4/templates/scc-role.yaml | 22 + .../4.3.4/templates/scc-rolebinding.yaml | 20 + .../4.3.4/templates/serviceaccount.yaml | 13 + .../4.3.4/templates/tests/rbac.yaml | 64 + .../4.3.4/templates/tests/test-install.yaml | 103 + .../microgateway-cni/4.3.4/values.schema.json | 225 ++ .../microgateway-cni/4.3.4/values.yaml | 85 + charts/airlock/microgateway/4.3.4/.helmignore | 28 + charts/airlock/microgateway/4.3.4/Chart.yaml | 44 + charts/airlock/microgateway/4.3.4/README.md | 180 ++ .../airlock/microgateway/4.3.4/app-readme.md | 28 + ...cesscontrols.microgateway.airlock.com.yaml | 124 ++ ...ntsecurities.microgateway.airlock.com.yaml | 139 ++ .../denyrules.microgateway.airlock.com.yaml | 1804 +++++++++++++++++ ...nvoyclusters.microgateway.airlock.com.yaml | 58 + ...nfigurations.microgateway.airlock.com.yaml | 185 ++ ...yhttpfilters.microgateway.airlock.com.yaml | 58 + .../graphqls.microgateway.airlock.com.yaml | 88 + ...aderrewrites.microgateway.airlock.com.yaml | 759 +++++++ ...propagations.microgateway.airlock.com.yaml | 108 + .../crds/limits.microgateway.airlock.com.yaml | 651 ++++++ ...idcproviders.microgateway.airlock.com.yaml | 305 +++ ...lyingparties.microgateway.airlock.com.yaml | 224 ++ .../openapis.microgateway.airlock.com.yaml | 167 ++ .../parsers.microgateway.airlock.com.yaml | 358 ++++ ...disproviders.microgateway.airlock.com.yaml | 159 ++ ...ionhandlings.microgateway.airlock.com.yaml | 77 + ...ecargateways.microgateway.airlock.com.yaml | 758 +++++++ .../telemetries.microgateway.airlock.com.yaml | 96 + .../4.3.4/dashboards/blockLogs.json | 510 +++++ .../4.3.4/dashboards/blockMetrics.json | 758 +++++++ .../4.3.4/dashboards/license.json | 521 +++++ .../4.3.4/dashboards/overview.json | 1138 +++++++++++ .../microgateway/4.3.4/templates/NOTES.txt | 47 + .../microgateway/4.3.4/templates/_helpers.tpl | 153 ++ .../templates/operator/_operator_helpers.tpl | 42 + .../4.3.4/templates/operator/_rbac.gen.tpl | 237 +++ .../templates/operator/_webhooks.gen.tpl | 339 ++++ .../4.3.4/templates/operator/configmap.yaml | 394 ++++ .../operator/dashboard-configmap.yaml | 28 + .../4.3.4/templates/operator/deployment.yaml | 143 ++ .../templates/operator/manager-role.yaml | 33 + .../operator/manager-rolebinding.yaml | 45 + .../templates/operator/metrics-service.yaml | 47 + .../templates/operator/mutating-webhook.yaml | 28 + .../4.3.4/templates/operator/podmonitor.yaml | 27 + .../4.3.4/templates/operator/role.yaml | 45 + .../4.3.4/templates/operator/rolebinding.yaml | 20 + .../templates/operator/selfsigned-issuer.yaml | 13 + .../templates/operator/serviceaccount.yaml | 13 + .../templates/operator/servicemonitor.yaml | 60 + .../operator/serving-certificate.yaml | 19 + .../operator/validating-webhook.yaml | 28 + .../templates/operator/webhook-service.yaml | 23 + .../4.3.4/templates/operator/xds-service.yaml | 24 + .../4.3.4/templates/tests/rbac.yaml | 143 ++ .../4.3.4/templates/tests/service.yaml | 23 + .../4.3.4/templates/tests/statefulset.yaml | 56 + .../4.3.4/templates/tests/test-install.yaml | 227 +++ .../microgateway/4.3.4/values.schema.json | 540 +++++ charts/airlock/microgateway/4.3.4/values.yaml | 213 ++ charts/codefresh/cf-runtime/6.4.6/.helmignore | 3 + charts/codefresh/cf-runtime/6.4.6/Chart.yaml | 28 + charts/codefresh/cf-runtime/6.4.6/README.md | 1230 +++++++++++ .../cf-runtime/6.4.6/README.md.gotmpl | 1007 +++++++++ .../cf-runtime/6.4.6/files/cleanup-runtime.sh | 37 + .../6.4.6/files/configure-dind-certs.sh | 132 ++ .../cf-runtime/6.4.6/files/init-runtime.sh | 80 + .../6.4.6/files/reconcile-runtime.sh | 38 + .../_components/app-proxy/_deployment.yaml | 70 + .../_components/app-proxy/_env-vars.yaml | 19 + .../_components/app-proxy/_helpers.tpl | 43 + .../_components/app-proxy/_ingress.yaml | 32 + .../_components/app-proxy/_rbac.yaml | 47 + .../_components/app-proxy/_service.yaml | 17 + .../event-exporter/_deployment.yaml | 62 + .../_components/event-exporter/_env-vars.yaml | 14 + .../_components/event-exporter/_helpers.tpl | 43 + .../_components/event-exporter/_rbac.yaml | 47 + .../_components/event-exporter/_service.yaml | 17 + .../event-exporter/_serviceMontor.yaml | 14 + .../_components/monitor/_deployment.yaml | 70 + .../_components/monitor/_env-vars.yaml | 26 + .../_components/monitor/_helpers.tpl | 42 + .../templates/_components/monitor/_rbac.yaml | 56 + .../_components/monitor/_service.yaml | 17 + .../_components/runner/_deployment.yaml | 103 + .../templates/_components/runner/_helpers.tpl | 42 + .../templates/_components/runner/_rbac.yaml | 53 + .../_init-container.yaml | 30 + .../_main-container.yaml | 28 + .../_sidecar-container.yaml | 22 + .../volume-provisioner/_cronjob.yaml | 58 + .../volume-provisioner/_daemonset.yaml | 98 + .../volume-provisioner/_deployment.yaml | 67 + .../volume-provisioner/_env-vars.yaml | 88 + .../volume-provisioner/_helpers.tpl | 93 + .../_components/volume-provisioner/_rbac.yaml | 71 + .../volume-provisioner/_secret.yaml | 22 + .../volume-provisioner/_storageclass.yaml | 47 + .../cf-runtime/6.4.6/templates/_helpers.tpl | 51 + .../6.4.6/templates/app-proxy/deployment.yaml | 9 + .../6.4.6/templates/app-proxy/ingress.yaml | 9 + .../6.4.6/templates/app-proxy/rbac.yaml | 9 + .../6.4.6/templates/app-proxy/service.yaml | 9 + .../templates/event-exporter/deployment.yaml | 9 + .../6.4.6/templates/event-exporter/rbac.yaml | 9 + .../templates/event-exporter/service.yaml | 11 + .../templates/extra/extra-resources.yaml | 6 + .../templates/extra/runtime-images-cm.yaml | 19 + .../hooks/post-install/cm-update-runtime.yaml | 18 + .../hooks/post-install/job-gencerts-dind.yaml | 68 + .../post-install/job-update-runtime.yaml | 77 + .../post-install/rbac-gencerts-dind.yaml | 37 + .../pre-delete/job-cleanup-resources.yaml | 73 + .../pre-delete/rbac-cleanup-resources.yaml | 46 + .../6.4.6/templates/monitor/deployment.yaml | 9 + .../6.4.6/templates/monitor/rbac.yaml | 9 + .../6.4.6/templates/monitor/service.yaml | 9 + .../templates/other/external-secrets.yaml | 2 + .../6.4.6/templates/other/podMonitor.yaml | 2 + .../6.4.6/templates/other/serviceMonitor.yaml | 2 + .../6.4.6/templates/runner/deployment.yaml | 9 + .../6.4.6/templates/runner/rbac.yaml | 9 + .../6.4.6/templates/runtime/_helpers.tpl | 123 ++ .../templates/runtime/cm-dind-daemon.yaml | 10 + .../6.4.6/templates/runtime/rbac.yaml | 48 + .../runtime/runtime-env-spec-tmpl.yaml | 214 ++ .../6.4.6/templates/runtime/secret.yaml | 11 + .../6.4.6/templates/runtime/svc-dind.yaml | 16 + .../templates/volume-provisioner/cronjob.yaml | 11 + .../volume-provisioner/daemonset.yaml | 11 + .../volume-provisioner/deployment.yaml | 10 + .../templates/volume-provisioner/rbac.yaml | 9 + .../templates/volume-provisioner/secret.yaml | 10 + .../volume-provisioner/storageclass.yaml | 10 + charts/codefresh/cf-runtime/6.4.6/values.yaml | 951 +++++++++ charts/loft/loft/4.0.0/.helmignore | 21 + charts/loft/loft/4.0.0/Chart.yaml | 32 + charts/loft/loft/4.0.0/app-readme.md | 12 + charts/loft/loft/4.0.0/templates/NOTES.txt | 8 + charts/loft/loft/4.0.0/templates/_helpers.tpl | 68 + .../loft/loft/4.0.0/templates/apiservice.yaml | 58 + .../4.0.0/templates/cert-issuer/issuer.yaml | 22 + .../loft/loft/4.0.0/templates/deployment.yaml | 188 ++ .../templates/ingress-wakeup-service.yaml | 21 + charts/loft/loft/4.0.0/templates/ingress.yaml | 48 + charts/loft/loft/4.0.0/templates/pdb.yaml | 24 + charts/loft/loft/4.0.0/templates/pvc.yaml | 41 + .../templates/rbac/clusterrolebinding.yaml | 21 + charts/loft/loft/4.0.0/templates/secret.yaml | 101 + charts/loft/loft/4.0.0/templates/service.yaml | 39 + .../loft/4.0.0/templates/serviceaccount.yaml | 25 + .../loft/4.0.0/templates/servicemonitor.yaml | 32 + charts/loft/loft/4.0.0/templates/webhook.yaml | 24 + charts/loft/loft/4.0.0/tests/README.md | 9 + .../loft/4.0.0/tests/deployment_test.yaml | 201 ++ charts/loft/loft/4.0.0/tests/pdb_test.yaml | 78 + charts/loft/loft/4.0.0/tests/secret_test.yaml | 27 + charts/loft/loft/4.0.0/values.yaml | 215 ++ index.yaml | 165 +- 178 files changed, 20877 insertions(+), 1 deletion(-) create mode 100644 assets/airlock/microgateway-4.3.4.tgz create mode 100644 assets/airlock/microgateway-cni-4.3.4.tgz create mode 100644 assets/codefresh/cf-runtime-6.4.6.tgz create mode 100644 assets/loft/loft-4.0.0.tgz create mode 100644 charts/airlock/microgateway-cni/4.3.4/.helmignore create mode 100644 charts/airlock/microgateway-cni/4.3.4/Chart.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/README.md create mode 100644 charts/airlock/microgateway-cni/4.3.4/gke-values.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/openshift-values.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/questions.yml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/NOTES.txt create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/_helpers.tpl create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/clusterrole.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/clusterrolebinding.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/configmap.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/daemonset.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/network-attachment-definition.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/scc-role.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/scc-rolebinding.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/serviceaccount.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/tests/rbac.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/templates/tests/test-install.yaml create mode 100644 charts/airlock/microgateway-cni/4.3.4/values.schema.json create mode 100644 charts/airlock/microgateway-cni/4.3.4/values.yaml create mode 100644 charts/airlock/microgateway/4.3.4/.helmignore create mode 100644 charts/airlock/microgateway/4.3.4/Chart.yaml create mode 100644 charts/airlock/microgateway/4.3.4/README.md create mode 100644 charts/airlock/microgateway/4.3.4/app-readme.md create mode 100644 charts/airlock/microgateway/4.3.4/crds/accesscontrols.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/contentsecurities.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/denyrules.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/envoyclusters.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/envoyconfigurations.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/envoyhttpfilters.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/graphqls.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/headerrewrites.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/identitypropagations.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/limits.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/oidcproviders.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/oidcrelyingparties.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/openapis.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/parsers.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/redisproviders.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/sessionhandlings.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/sidecargateways.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/crds/telemetries.microgateway.airlock.com.yaml create mode 100644 charts/airlock/microgateway/4.3.4/dashboards/blockLogs.json create mode 100644 charts/airlock/microgateway/4.3.4/dashboards/blockMetrics.json create mode 100644 charts/airlock/microgateway/4.3.4/dashboards/license.json create mode 100644 charts/airlock/microgateway/4.3.4/dashboards/overview.json create mode 100644 charts/airlock/microgateway/4.3.4/templates/NOTES.txt create mode 100644 charts/airlock/microgateway/4.3.4/templates/_helpers.tpl create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/_operator_helpers.tpl create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/_rbac.gen.tpl create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/_webhooks.gen.tpl create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/configmap.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/dashboard-configmap.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/deployment.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/manager-role.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/manager-rolebinding.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/metrics-service.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/mutating-webhook.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/podmonitor.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/role.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/rolebinding.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/selfsigned-issuer.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/serviceaccount.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/servicemonitor.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/serving-certificate.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/validating-webhook.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/webhook-service.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/operator/xds-service.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/tests/rbac.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/tests/service.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/tests/statefulset.yaml create mode 100644 charts/airlock/microgateway/4.3.4/templates/tests/test-install.yaml create mode 100644 charts/airlock/microgateway/4.3.4/values.schema.json create mode 100644 charts/airlock/microgateway/4.3.4/values.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/.helmignore create mode 100644 charts/codefresh/cf-runtime/6.4.6/Chart.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/README.md create mode 100644 charts/codefresh/cf-runtime/6.4.6/README.md.gotmpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/files/cleanup-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.4.6/files/configure-dind-certs.sh create mode 100644 charts/codefresh/cf-runtime/6.4.6/files/init-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.4.6/files/reconcile-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_serviceMontor.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_init-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_main-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_sidecar-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/extra/extra-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/extra/runtime-images-cm.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/cm-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/rbac-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/job-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/rbac-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/monitor/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/monitor/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/monitor/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/other/external-secrets.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/other/podMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/other/serviceMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/cm-dind-daemon.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/runtime-env-spec-tmpl.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/runtime/svc-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.4.6/values.yaml create mode 100644 charts/loft/loft/4.0.0/.helmignore create mode 100644 charts/loft/loft/4.0.0/Chart.yaml create mode 100644 charts/loft/loft/4.0.0/app-readme.md create mode 100644 charts/loft/loft/4.0.0/templates/NOTES.txt create mode 100644 charts/loft/loft/4.0.0/templates/_helpers.tpl create mode 100644 charts/loft/loft/4.0.0/templates/apiservice.yaml create mode 100644 charts/loft/loft/4.0.0/templates/cert-issuer/issuer.yaml create mode 100644 charts/loft/loft/4.0.0/templates/deployment.yaml create mode 100644 charts/loft/loft/4.0.0/templates/ingress-wakeup-service.yaml create mode 100644 charts/loft/loft/4.0.0/templates/ingress.yaml create mode 100644 charts/loft/loft/4.0.0/templates/pdb.yaml create mode 100644 charts/loft/loft/4.0.0/templates/pvc.yaml create mode 100644 charts/loft/loft/4.0.0/templates/rbac/clusterrolebinding.yaml create mode 100644 charts/loft/loft/4.0.0/templates/secret.yaml create mode 100644 charts/loft/loft/4.0.0/templates/service.yaml create mode 100644 charts/loft/loft/4.0.0/templates/serviceaccount.yaml create mode 100644 charts/loft/loft/4.0.0/templates/servicemonitor.yaml create mode 100644 charts/loft/loft/4.0.0/templates/webhook.yaml create mode 100644 charts/loft/loft/4.0.0/tests/README.md create mode 100644 charts/loft/loft/4.0.0/tests/deployment_test.yaml create mode 100644 charts/loft/loft/4.0.0/tests/pdb_test.yaml create mode 100644 charts/loft/loft/4.0.0/tests/secret_test.yaml create mode 100644 charts/loft/loft/4.0.0/values.yaml diff --git a/assets/airlock/microgateway-4.3.4.tgz b/assets/airlock/microgateway-4.3.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e2ac49f62eda0dbd006a0d8a7b416e539d65ed40 GIT binary patch literal 61765 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 z z!lX6k8mt7fJ~*o;e`&kpw^*aYlRRg&hC1A!Md(d?dpDcGswJp-(VA=HT^F>N;z|^Fh`lRq9M3jlazVESjNb4hGhT)A{NWn0YuSr|HatG`!@a)- z&xeFfrZg@w*t$;iU_*4R8-%Vd1k`r7*4nq9nrHQ%EYEMjFl;jf{R!$!{N?r0?RLBS zySwV&Znr!8?{07Z;HTd1L3ej&dw;Lj`>EU8-RU0u1iH&Zq4h|BMER5hM@?1PXkO!0$&#XJGwzGyvIM5)vOAot?@vxImu#X#=Rx z4f#?~5bEE7B0(-ijfZ&W+1lFAKZDl@iijb;_RP{9CIXF^?nKqC!-9iYmEHu$Dm)LI zBdy(llSI4Vn_x^uo1uV0e-pq+&|?FA5sO-wQ_H4h9;s6gQK44_-VplWID8ThCy6J}Vi z$TgjUHk<4rPppFjK$w z3>;G;5D|bQFJcnoxXB@9@yyG<;Rs^F1-K&gh5#r8^sYEq|M2_K#TmGyA?S5C)}DbQ z&qJI8j}pOXAXg6t0lfi~1k-Hi$OjRZ-AD-ijToc2L*#>aon@P6ry2Cjg6kpwV?~4kCRcoI?Rbp5D>W)Q9AXc{0Qh-WAxV0cGHcT8#8+ca=%s(N(S4gw6iAH_JD9(11{>~3pDmQ7zwxj++e z#Jn+Ft2|A0tx^F&}y&% literal 0 HcmV?d00001 diff --git a/assets/airlock/microgateway-cni-4.3.4.tgz b/assets/airlock/microgateway-cni-4.3.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cd01dd278f48b39325986616509a953ab2e9f781 GIT binary patch literal 10969 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 H0N?-s4S2cK literal 0 HcmV?d00001 diff --git a/assets/codefresh/cf-runtime-6.4.6.tgz b/assets/codefresh/cf-runtime-6.4.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d86ab5028275c65a3b093aa0c2f5fe90062c0946 GIT binary patch literal 43758 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%0DkN6|_7c85Me@cic5Qd{6mC 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 aK<~%<)W>@r7#P^s7pIi)KA0dB*na|w6Dc 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 D)p!8T literal 0 HcmV?d00001 diff --git a/charts/airlock/microgateway-cni/4.3.4/.helmignore b/charts/airlock/microgateway-cni/4.3.4/.helmignore new file mode 100644 index 0000000000..8561d28926 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/.helmignore @@ -0,0 +1,27 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +# Helm unit tests +/tests +/validation diff --git a/charts/airlock/microgateway-cni/4.3.4/Chart.yaml b/charts/airlock/microgateway-cni/4.3.4/Chart.yaml new file mode 100644 index 0000000000..002c307985 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/Chart.yaml @@ -0,0 +1,43 @@ +annotations: + artifacthub.io/category: security + artifacthub.io/license: MIT + artifacthub.io/links: | + - name: Airlock Microgateway Documentation + url: https://docs.airlock.com/microgateway/4.3/ + - name: Airlock Microgateway Labs + url: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=artifacthub.io + - name: Airlock Microgateway Forum + url: https://forum.airlock.com/ + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Airlock Microgateway CNI + catalog.cattle.io/kube-version: '>=1.25.0-0' + catalog.cattle.io/release-name: microgateway-cni + charts.openshift.io/name: Airlock Microgateway CNI +apiVersion: v2 +appVersion: 4.3.4 +description: A Helm chart for deploying the Airlock Microgateway CNI plugin +home: https://www.airlock.com/en/microgateway +icon: file://assets/icons/microgateway-cni.svg +keywords: +- WAF +- Web Application Firewall +- WAAP +- Web Application and API protection +- OWASP +- Airlock +- Microgateway +- Security +- Filtering +- DevSecOps +- shift left +- CNI +kubeVersion: '>=1.25.0-0' +maintainers: +- email: support@airlock.com + name: Airlock + url: https://www.airlock.com/ +name: microgateway-cni +sources: +- https://github.com/airlock/microgateway +type: application +version: 4.3.4 diff --git a/charts/airlock/microgateway-cni/4.3.4/README.md b/charts/airlock/microgateway-cni/4.3.4/README.md new file mode 100644 index 0000000000..1559e00a41 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/README.md @@ -0,0 +1,137 @@ +# Airlock Microgateway CNI + +![Version: 4.3.4](https://img.shields.io/badge/Version-4.3.4-informational?style=flat-square) ![AppVersion: 4.3.4](https://img.shields.io/badge/AppVersion-4.3.4-informational?style=flat-square) + +*Airlock Microgateway is a Kubernetes native WAAP (Web Application and API Protection) solution to protect microservices.* + + + + + Microgateway + + +Modern application security is embedded in the development workflow and follows DevSecOps paradigms. Airlock Microgateway is the perfect fit for these requirements. It is a lightweight alternative to the Airlock Gateway appliance, optimized for Kubernetes environments. Airlock Microgateway protects your applications and microservices with the tried-and-tested Airlock security features against attacks, while also providing a high degree of scalability. +__This Helm chart is part of Airlock Microgateway. See our [GitHub repo](https://github.com/airlock/microgateway/tree/4.3.4).__ + +### Features +* Kubernetes native integration with its Operator, Custom Resource Definitions, hot-reload, automatic sidecar injection. +* Reverse proxy functionality with request routing rules, TLS termination and remote IP extraction +* Using native Envoy HTTP filters like Lua scripting, RBAC, ext_authz, JWT authentication +* Content security filters for protecting against known attacks (OWASP Top 10) +* Access control using OpenID Connect to allow only authenticated users to access the protected services +* API security features like JSON parsing, OpenAPI specification enforcement or GraphQL schema validation + +For a list of all features, view the **[comparison of the community and premium edition](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html)**. + +## Documentation and links + +Check the official documentation at **[docs.airlock.com](https://docs.airlock.com/microgateway/latest/)** or the product website at **[airlock.com/microgateway](https://www.airlock.com/en/microgateway)**. The links below point out the most interesting documentation sites when starting with Airlock Microgateway. + +* [Getting Started](https://docs.airlock.com/microgateway/latest/#data/1660804708742.html) +* [System Architecture](https://docs.airlock.com/microgateway/latest/#data/1660804709650.html) +* [Installation](https://docs.airlock.com/microgateway/latest/#data/1660804708637.html) +* [Troubleshooting](https://docs.airlock.com/microgateway/latest/#data/1659430054787.html) +* [GitHub](https://github.com/airlock/microgateway) + +# Quick start guide + +The instructions below provide a quick start guide. Detailed information are provided in the **[manual](https://docs.airlock.com/microgateway/latest/)**. + +## Prerequisites +* [helm](https://helm.sh/docs/intro/install/) (>= v3.8.0) + +## Deploy Airlock Microgateway CNI +1. Install the CNI Plugin with Helm. + > **Note**: Certain environments such as OpenShift or GKE require non-default configurations when installing the CNI plugin. For the most common setups, values files are provided in the [chart folder](/deploy/charts/airlock-microgateway-cni). + ```bash + # Standard setup + helm install airlock-microgateway-cni -n kube-system oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' + kubectl -n kube-system rollout status daemonset -l app.kubernetes.io/instance=airlock-microgateway-cni + ``` + ```bash + # GKE setup + helm install airlock-microgateway-cni -n kube-system oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' -f https://raw.githubusercontent.com/airlock/microgateway/4.3.4/deploy/charts/airlock-microgateway-cni/gke-values.yaml + kubectl -n kube-system rollout status daemonset -l app.kubernetes.io/instance=airlock-microgateway-cni + ``` + ```bash + # OpenShift setup + helm install airlock-microgateway-cni -n openshift-operators oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' -f https://raw.githubusercontent.com/airlock/microgateway/4.3.4/deploy/charts/airlock-microgateway-cni/openshift-values.yaml + kubectl -n openshift-operators rollout status daemonset -l app.kubernetes.io/instance=airlock-microgateway-cni + ``` + **Important:** On OpenShift, all pods which should be protected by Airlock Microgateway must explicitly reference the Airlock Microgateway CNI NetworkAttachmentDefinition via the annotation `k8s.v1.cni.cncf.io/networks` (see [documentation](https://docs.airlock.com/microgateway/latest/#data/1658483168033.html) for details). + +2. (Recommended) You can verify the correctness of the installation with `helm test`. + ```bash + # Standard and GKE setup + helm upgrade airlock-microgateway-cni -n kube-system --set tests.enabled=true --reuse-values oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' + helm test airlock-microgateway-cni -n kube-system --logs + helm upgrade airlock-microgateway-cni -n kube-system --set tests.enabled=false --reuse-values oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' + ``` + ```bash + # OpenShift setup + helm upgrade airlock-microgateway-cni -n openshift-operators --set tests.enabled=true --reuse-values oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' + helm test airlock-microgateway-cni -n openshift-operators --logs + helm upgrade airlock-microgateway-cni -n openshift-operators --set tests.enabled=false --reuse-values oci://quay.io/airlockcharts/microgateway-cni --version '4.3.4' + ``` + + Consult our [documentation](https://docs.airlock.com/microgateway/latest/#data/1699611533587.html) in case of any installation error. + +## Support + +### Premium support +If you have a paid license, please follow the [premium support process](https://techzone.ergon.ch/support-process). + +### Community support +For the community edition, check our **[Airlock community forum](https://forum.airlock.com/)** for FAQs or register to post your question. +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Custom affinity for the DaemonSet to only deploy the CNI plugin on specific nodes. | +| commonAnnotations | object | `{}` | Annotations to add to all resources. | +| commonLabels | object | `{}` | Labels to add to all resources. | +| config.cniBinDir | string | `"/opt/cni/bin"` | Directory where the CNI plugin binaries reside on the host. This path can either be found in the documentation of your Kubernetes distribution or CNI provider. It can also be queried by running the command `crictl info -o go-template --template '{{.config.cni.binDir}}'` on your Kubernetes node. | +| config.cniNetDir | string | `"/etc/cni/net.d"` | Directory where the CNI config files reside on the host. This path can either be found in the documentation of your Kubernetes distribution or CNI provider. It can also be queried by running the command `crictl info -o go-template --template '{{.config.cni.confDir}}'` on your Kubernetes node. | +| config.excludeNamespaces | list | `["kube-system"]` | Namespaces for which this CNI plugin should not apply any modifications. | +| config.installMode | string | `"chained"` | Whether to install the CNI plugin as a `chained` plugin (default, required with most interface CNI providers), as a `standalone` plugin (required for use with Multus CNI, e.g. on OpenShift) or in `manual` mode, where no CNI network configuration is written. | +| config.logLevel | string | `"info"` | Log level for the CNI installer and plugin. | +| fullnameOverride | string | `""` | Allows overriding the name to use as full name of resources. | +| image.digest | string | `"sha256:1e01310b3ad8566e9b39ee539ed5c959049aadda1a18c1a534e96d8865e20172"` | SHA256 image digest to pull (in the format "sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a"). Overrides tag when specified. | +| image.pullPolicy | string | `"IfNotPresent"` | Pull policy for this image. | +| image.repository | string | `"quay.io/airlock/microgateway-cni"` | Image repository from which to pull the Airlock Microgateway CNI image. | +| image.tag | string | `"4.3.4"` | Image tag to pull. | +| imagePullSecrets | list | `[]` | ImagePullSecrets to use when pulling images. | +| multusNetworkAttachmentDefinition.create | bool | `false` | Whether a NetworkAttachmentDefinition CR should be created, which can be used for applying the CNI plugin to Pods. | +| multusNetworkAttachmentDefinition.namespace | string | `"default"` | Namespace in which the NetworkAttachmentDefinition is deployed. Note: If namespace is set to a custom value, referencing the created NetworkAttachmentDefinition from other namespaces may not work if Multus namespace isolation is enabled. https://github.com/k8snetworkplumbingwg/multus-cni/blob/v4.0.2/docs/configuration.md#namespace-isolation | +| nameOverride | string | `""` | Allows overriding the name to use instead of "microgateway-cni". | +| nodeSelector | object | `{"kubernetes.io/os":"linux"}` | NodeSelector to apply to the CNI DaemonSet in order to only deploy the CNI plugin on specific nodes. | +| podAnnotations | object | `{}` | Annotations to add to all Pods. | +| podLabels | object | `{}` | Labels to add to all Pods. | +| privileged | bool | `false` | Whether the DaemonSet should run in privileged mode. Must be enabled for environments which require it for writing files to the host (e.g. OpenShift). | +| rbac.create | bool | `true` | Whether to create RBAC resources which are required for the CNI plugin to function. | +| rbac.createSCCRole | OpenShift | `false` | Whether to create RBAC resources which allow the CNI installer to use the "privileged" security context constraint. | +| resources | object | `{"requests":{"cpu":"10m","memory":"100Mi"}}` | Resource restrictions to apply to the CNI installer container. | +| serviceAccount.annotations | object | `{}` | Annotations to add to the ServiceAccount. | +| serviceAccount.create | bool | `true` | Whether a ServiceAccount should be created. | +| serviceAccount.name | string | `""` | Name of the ServiceAccount to use. If not set and create is true, a name is generated using the fullname template. | +| tests.enabled | bool | `false` | Whether additional resources required for running `helm test` should be created (e.g. Roles and ServiceAccounts). If set to false, `helm test` will not run any tests. | + +## License +View the [detailed license terms](https://www.airlock.com/en/airlock-license) for the software contained in this image. +* Decompiling or reverse engineering is not permitted. +* Using any of the deny rules or parts of these filter patterns outside of the image is not permitted. + +Airlock® is a security innovation by [ergon](https://www.ergon.ch/en) + + + + + + + Airlock Secure Access Hub + + diff --git a/charts/airlock/microgateway-cni/4.3.4/gke-values.yaml b/charts/airlock/microgateway-cni/4.3.4/gke-values.yaml new file mode 100644 index 0000000000..d6d5c21d14 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/gke-values.yaml @@ -0,0 +1,4 @@ +# values for deploying on GKE + +config: + cniBinDir: "/home/kubernetes/bin" diff --git a/charts/airlock/microgateway-cni/4.3.4/openshift-values.yaml b/charts/airlock/microgateway-cni/4.3.4/openshift-values.yaml new file mode 100644 index 0000000000..3b1d6cccde --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/openshift-values.yaml @@ -0,0 +1,15 @@ +# values for deploying on OpenShift + +rbac: + createSCCRole: true + +privileged: true + +multusNetworkAttachmentDefinition: + create: true + namespace: default + +config: + installMode: "standalone" + cniNetDir: "/etc/cni/multus/net.d" + cniBinDir: "/var/lib/cni/bin" diff --git a/charts/airlock/microgateway-cni/4.3.4/questions.yml b/charts/airlock/microgateway-cni/4.3.4/questions.yml new file mode 100644 index 0000000000..73ed44d646 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/questions.yml @@ -0,0 +1,18 @@ +questions: + - variable: config.cniNetDir + required: true + type: string + label: CNI Network Configuration Directory + group: "CNI Settings" + description: "Directory where the CNI config files reside on the host. This value depends on the kubernetes distribution and interface CNI Provider used. It can be fetched by running `crictl info -o go-template --template '{{.config.cni.confDir}}'` on your kubernetes host." + - variable: config.cniBinDir + required: true + type: string + label: CNI Plugin Binaries Directory + group: "CNI Settings" + description: "Directory where the CNI plugin binaries reside on the host. This value depends on the kubernetes distribution and interface CNI Provider used. It can be fetched by running `crictl info -o go-template --template '{{.config.cni.binDir}}'` on your kubernetes host." + - variable: config.installMode + required: true + label: CNI Plugin Installation Mode + group: "CNI Settings" + description: "Whether to install the CNI plugin as a `chained` plugin (default, required with most interface CNI providers) as a `standalone` plugin (required for use with Multus CNI, e.g. on OpenShift) or in `manual` mode, where no CNI network configuration is written. Please refer to the CNI installation documentation (https://github.com/airlock/microgateway?tab=readme-ov-file#deploy-airlock-microgateway-cni) to correctly setup the CNI Plugin for your environment." diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/NOTES.txt b/charts/airlock/microgateway-cni/4.3.4/templates/NOTES.txt new file mode 100644 index 0000000000..bb94ff521e --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/NOTES.txt @@ -0,0 +1,15 @@ +Thank you for installing Airlock Microgateway CNI. + +Please ensure that the helm values'.config.cniNetDir' and '.config.cniBinDir' are configured for your Kubernetes distribution. +For further information, consider our manual https://docs.airlock.com/microgateway/{{ include "airlock-microgateway-cni.docsVersion" . }}. +The chapter 'Setup > Installation' describes how to set those settings correctly. + +Further information: +* Documentation: https://docs.airlock.com/microgateway/{{ include "airlock-microgateway-cni.docsVersion" . }} +* Airlock Microgateway Labs: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=helm + +Next steps: +* Install Airlock Microgateway (if not done already) + https://artifacthub.io/packages/helm/airlock-microgateway/microgateway + +Your release version is {{ .Chart.Version }}. \ No newline at end of file diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/_helpers.tpl b/charts/airlock/microgateway-cni/4.3.4/templates/_helpers.tpl new file mode 100644 index 0000000000..996491a873 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/_helpers.tpl @@ -0,0 +1,101 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "airlock-microgateway-cni.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Convert an image configuration object into an image ref string. +*/}} +{{- define "airlock-microgateway-cni.image" -}} + {{- if .digest -}} + {{- printf "%s@%s" .repository .digest -}} + {{- else if .tag -}} + {{- printf "%s:%s" .repository .tag -}} + {{- else -}} + {{- printf "%s" .repository -}} + {{- end -}} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 50 chars because some Kubernetes name fields are limited to 63 chars (by the DNS naming spec) +and the longest suffix is 13 characters. +If release name contains chart name it will be used as a full name. +*/}} +{{- define "airlock-microgateway-cni.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 50 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 50 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 50 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "airlock-microgateway-cni.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "airlock-microgateway-cni.labels" -}} +helm.sh/chart: {{ include "airlock-microgateway-cni.chart" . }} +{{ include "airlock-microgateway-cni.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Values.commonLabels }} +{{ toYaml .}} +{{- end }} +{{- end }} + +{{/* +Common labels without component +*/}} +{{- define "airlock-microgateway-cni.labelsWithoutComponent" -}} +{{- $labels := fromYaml (include "airlock-microgateway-cni.labels" .) -}} +{{ unset $labels "app.kubernetes.io/component" | toYaml }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "airlock-microgateway-cni.selectorLabels" -}} +app.kubernetes.io/component: cni-plugin-installer +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/name: {{ include "airlock-microgateway-cni.name" . }} +{{- end }} + +{{/* +Create the name of the service account to use for the CNI Plugin +*/}} +{{- define "airlock-microgateway-cni.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "airlock-microgateway-cni.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "airlock-microgateway-cni.isSemver" -}} +{{- regexMatch `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` . -}} +{{- end -}} + +{{- define "airlock-microgateway-cni.docsVersion" -}} +{{- if and (eq "true" (include "airlock-microgateway-cni.isSemver" .Chart.AppVersion)) (not (contains "-" .Chart.AppVersion)) -}} + {{- $version := (semver .Chart.AppVersion) -}} + {{- $version.Major }}.{{ $version.Minor -}} +{{- else -}} + {{- print "latest" -}} +{{- end -}} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/clusterrole.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/clusterrole.yaml new file mode 100644 index 0000000000..ef88ac7836 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + - patch +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/clusterrolebinding.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..04f87cb0fa --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "airlock-microgateway-cni.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "airlock-microgateway-cni.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/configmap.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/configmap.yaml new file mode 100644 index 0000000000..b880116ef9 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/configmap.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + plugin-conf.json: |- + { + "type": "{{ include "airlock-microgateway-cni.fullname" . }}", + "debug": {{ eq .Values.config.logLevel "debug" }}, + "logFilePath": "/var/log/{{ include "airlock-microgateway-cni.fullname" . }}.log", + "kubernetes": { + "kubeconfig": "{{ .Values.config.cniNetDir }}/{{ include "airlock-microgateway-cni.fullname" . }}-kubeconfig", + "excludeNamespaces": {{ toJson .Values.config.excludeNamespaces }} + } + } diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/daemonset.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/daemonset.yaml new file mode 100644 index 0000000000..4ba9f2669c --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/daemonset.yaml @@ -0,0 +1,136 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "airlock-microgateway-cni.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + kubectl.kubernetes.io/default-container: cni-installer + {{- with mustMerge .Values.podAnnotations .Values.commonAnnotations}} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - args: + - --log-level + - "{{ .Values.config.logLevel }}" + env: + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + key: plugin-conf.json + name: {{ include "airlock-microgateway-cni.fullname" . }} + - name: CNI_BIN_DIR + value: /host/opt/cni/bin + - name: CNI_NET_DIR + value: /host/etc/cni/net.d + - name: KUBECONFIG_FILE_NAME + value: "{{ include "airlock-microgateway-cni.fullname" . }}-kubeconfig" + - name: INSTALL_MODE + value: {{ .Values.config.installMode }} + - name: KUBERNETES_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + image: {{ include "airlock-microgateway-cni.image" .Values.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: cni-installer + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + startupProbe: + exec: + command: + - /cni-installer + - probe + failureThreshold: 5 + initialDelaySeconds: 3 + periodSeconds: 3 + timeoutSeconds: 3 + readinessProbe: + exec: + command: + - /cni-installer + - probe + failureThreshold: 1 + periodSeconds: 60 + timeoutSeconds: 3 + securityContext: + allowPrivilegeEscalation: {{ .Values.privileged }} + capabilities: + drop: + - ALL + privileged: {{ .Values.privileged }} + readOnlyRootFilesystem: true + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + - mountPath: /run/cni-installer + name: cni-installer-status + hostNetwork: true + priorityClassName: system-node-critical + restartPolicy: Always + securityContext: + fsGroup: 0 + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + serviceAccountName: {{ include "airlock-microgateway-cni.serviceAccountName" . }} + terminationGracePeriodSeconds: 5 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + tolerations: + - effect: NoSchedule + operator: Exists + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + volumes: + - hostPath: + path: "{{ .Values.config.cniBinDir }}" + type: Directory + name: cni-bin-dir + - hostPath: + path: "{{ .Values.config.cniNetDir }}" + type: Directory + name: cni-net-dir + - emptyDir: {} + name: cni-installer-status diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/network-attachment-definition.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/network-attachment-definition.yaml new file mode 100644 index 0000000000..5d657e309c --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/network-attachment-definition.yaml @@ -0,0 +1,13 @@ +{{- if .Values.multusNetworkAttachmentDefinition.create -}} +apiVersion: "k8s.cni.cncf.io/v1" +kind: NetworkAttachmentDefinition +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }} + namespace: {{ .Values.multusNetworkAttachmentDefinition.namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/scc-role.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/scc-role.yaml new file mode 100644 index 0000000000..8627486928 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/scc-role.yaml @@ -0,0 +1,22 @@ +{{- if .Values.rbac.createSCCRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }}-privileged + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +- apiGroups: + - security.openshift.io + resourceNames: + - privileged + resources: + - securitycontextconstraints + verbs: + - use +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/scc-rolebinding.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/scc-rolebinding.yaml new file mode 100644 index 0000000000..ebd02982c0 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/scc-rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.createSCCRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "airlock-microgateway-cni.fullname" . }}-privileged + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "airlock-microgateway-cni.fullname" . }}-privileged +subjects: +- kind: ServiceAccount + name: {{ include "airlock-microgateway-cni.serviceAccountName" . }} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/serviceaccount.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/serviceaccount.yaml new file mode 100644 index 0000000000..3dc8d58eae --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "airlock-microgateway-cni.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labels" . | nindent 4 }} + {{- with mustMerge .Values.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/tests/rbac.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/tests/rbac.yaml new file mode 100644 index 0000000000..744799333f --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/tests/rbac.yaml @@ -0,0 +1,64 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labelsWithoutComponent" . | nindent 4 }} + app.kubernetes.io/component: tests +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labelsWithoutComponent" . | nindent 4 }} + app.kubernetes.io/component: tests +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" +subjects: +- kind: ServiceAccount + name: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labelsWithoutComponent" . | nindent 4 }} + app.kubernetes.io/component: tests +rules: +- apiGroups: + - "apps" + resources: + - daemonsets + resourceNames: + - {{ include "airlock-microgateway-cni.fullname" . }} + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - pods + - pods/log + verbs: + - get + - list +{{- if .Values.rbac.createSCCRole }} +- apiGroups: + - security.openshift.io + resourceNames: + - privileged + resources: + - securitycontextconstraints + verbs: + - use +{{- end -}} +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/templates/tests/test-install.yaml b/charts/airlock/microgateway-cni/4.3.4/templates/tests/test-install.yaml new file mode 100644 index 0000000000..12d8c8de78 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/templates/tests/test-install.yaml @@ -0,0 +1,103 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "airlock-microgateway-cni.fullname" . }}-test-install" + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway-cni.labelsWithoutComponent" . | nindent 4 }} + app.kubernetes.io/component: test-install + annotations: + helm.sh/hook: test + helm.sh/hook-delete-policy: before-hook-creation +spec: + restartPolicy: Never + containers: + - name: test + image: "bitnami/kubectl:{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}" + securityContext: + allowPrivilegeEscalation: {{ .Values.privileged }} + capabilities: + drop: + - ALL + privileged: {{ .Values.privileged }} + readOnlyRootFilesystem: true + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + readOnly: true + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + readOnly: true + command: + - sh + - -c + - | + set -eu + + fail() { + echo "Error: ${1}" + echo "" + echo 'CNI installer logs:' + kubectl logs -n {{ .Release.Namespace }} daemonsets/{{ include "airlock-microgateway-cni.fullname" .}} -c cni-installer + exit 1 + } + + containsMGWCNIConf() { + cat "${1}" | grep -qe '"type":.*"{{ include "airlock-microgateway-cni.fullname" . }}"' + } + + if ! kubectl rollout status --timeout=60s -n {{ .Release.Namespace }} daemonsets/{{ include "airlock-microgateway-cni.fullname" .}}; then + fail 'CNI DaemonSet rollout did not complete within timeout' + fi + + echo "Checking whether CNI binary was installed" + if ! [ -f "/host/opt/cni/bin/{{ include "airlock-microgateway-cni.fullname" . }}" ]; then + fail 'CNI binary was not installed' + fi + + echo "Checking whether CNI kubeconfig was installed" + if ! [ -f "/host/etc/cni/net.d/{{ include "airlock-microgateway-cni.fullname" . }}-kubeconfig" ]; then + fail 'CNI kubeconfig was not created' + fi + + echo "Checking whether CNI configuration was written" + case {{ .Values.config.installMode }} in + "chained") + for file in "/host/etc/cni/net.d/"*.conflist; do + if containsMGWCNIConf "${file}"; then + echo "Success" + exit 0 + fi + done + ;; + "standalone") + if containsMGWCNIConf "/host/etc/cni/net.d/{{ include "airlock-microgateway-cni.fullname" . }}.conflist"; then + echo "Success" + exit 0 + fi + ;; + "manual") + echo "- Skipping because we are in 'manual' install mode" + echo "Success" + exit 0 + ;; + esac + + fail 'Configuration for plugin "{{ include "airlock-microgateway-cni.fullname" . }}" was not found' + serviceAccountName: "{{ include "airlock-microgateway-cni.fullname" . }}-tests" + volumes: + - hostPath: + path: "{{ .Values.config.cniBinDir }}" + type: Directory + name: cni-bin-dir + - hostPath: + path: "{{ .Values.config.cniNetDir }}" + type: Directory + name: cni-net-dir +{{- end -}} diff --git a/charts/airlock/microgateway-cni/4.3.4/values.schema.json b/charts/airlock/microgateway-cni/4.3.4/values.schema.json new file mode 100644 index 0000000000..e087bd7004 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/values.schema.json @@ -0,0 +1,225 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "nameOverride": { + "type": "string" + }, + "fullnameOverride": { + "type": "string" + }, + "commonLabels": { + "$ref": "#/definitions/StringMap" + }, + "commonAnnotations": { + "$ref": "#/definitions/StringMap" + }, + "imagePullSecrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name" + ], + "additionalProperties": true + } + }, + "image": { + "$ref": "#/definitions/Image" + }, + "podAnnotations": { + "$ref": "#/definitions/StringMap" + }, + "podLabels": { + "$ref": "#/definitions/StringMap" + }, + "resources": { + "type": "object" + }, + "nodeSelector": { + "$ref": "#/definitions/StringMap" + }, + "affinity": { + "type": "object" + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "createSCCRole": { + "type": "boolean" + } + }, + "required": [ + "create", + "createSCCRole" + ], + "additionalProperties": false + }, + "privileged": { + "type": "boolean" + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "annotations": { + "$ref": "#/definitions/StringMap" + }, + "name": { + "type": "string" + } + }, + "required": [ + "annotations", + "create", + "name" + ], + "additionalProperties": false + }, + "multusNetworkAttachmentDefinition": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "namespace": { + "type": "string" + } + }, + "required": [ + "create", + "namespace" + ], + "additionalProperties": false + }, + "config": { + "type": "object", + "properties": { + "installMode": { + "type": "string", + "enum": [ + "chained", + "standalone", + "manual" + ] + }, + "logLevel": { + "type": "string", + "enum": [ + "debug", + "info", + "warn", + "error" + ] + }, + "cniNetDir": { + "type": "string", + "minLength": 1 + }, + "cniBinDir": { + "type": "string", + "minLength": 1 + }, + "excludeNamespaces": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "cniBinDir", + "cniNetDir", + "excludeNamespaces", + "installMode", + "logLevel" + ], + "additionalProperties": false + }, + "tests": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + }, + "global": { + "type": "object" + } + }, + "required": [ + "affinity", + "commonAnnotations", + "commonLabels", + "config", + "fullnameOverride", + "image", + "imagePullSecrets", + "multusNetworkAttachmentDefinition", + "nameOverride", + "nodeSelector", + "podAnnotations", + "podLabels", + "privileged", + "rbac", + "resources", + "serviceAccount", + "tests" + ], + "additionalProperties": false, + "definitions": { + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Image": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "minLength": 1 + }, + "tag": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^$|^sha256:[a-f0-9]{64}$" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "required": [ + "digest", + "pullPolicy", + "repository", + "tag" + ], + "additionalProperties": false + } + } +} diff --git a/charts/airlock/microgateway-cni/4.3.4/values.yaml b/charts/airlock/microgateway-cni/4.3.4/values.yaml new file mode 100644 index 0000000000..63ef360335 --- /dev/null +++ b/charts/airlock/microgateway-cni/4.3.4/values.yaml @@ -0,0 +1,85 @@ +# -- Allows overriding the name to use instead of "microgateway-cni". +nameOverride: "" +# -- Allows overriding the name to use as full name of resources. +fullnameOverride: "" +# -- Labels to add to all resources. +commonLabels: {} +# -- Annotations to add to all resources. +commonAnnotations: {} +# -- ImagePullSecrets to use when pulling images. +imagePullSecrets: [] +# - name: myRegistryKeySecretName + +# Specifies the Airlock Microgateway CNI image. +image: + # -- Image repository from which to pull the Airlock Microgateway CNI image. + repository: "quay.io/airlock/microgateway-cni" + # -- Image tag to pull. + tag: "4.3.4" + # -- SHA256 image digest to pull (in the format "sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a"). + # Overrides tag when specified. + digest: "sha256:1e01310b3ad8566e9b39ee539ed5c959049aadda1a18c1a534e96d8865e20172" + # -- Pull policy for this image. + pullPolicy: IfNotPresent +# -- Annotations to add to all Pods. +podAnnotations: {} +# -- Labels to add to all Pods. +podLabels: {} +# -- Resource restrictions to apply to the CNI installer container. +resources: + requests: + cpu: 10m + memory: 100Mi +# -- NodeSelector to apply to the CNI DaemonSet in order to only deploy the CNI plugin on specific nodes. +nodeSelector: + kubernetes.io/os: linux +# -- Custom affinity for the DaemonSet to only deploy the CNI plugin on specific nodes. +affinity: {} +# Configures the generation of RBAC Roles and RoleBindings. +rbac: + # -- Whether to create RBAC resources which are required for the CNI plugin to function. + create: true + # -- (OpenShift) Whether to create RBAC resources which allow the CNI installer to use the "privileged" security context constraint. + createSCCRole: false +# -- Whether the DaemonSet should run in privileged mode. Must be enabled for environments which require it for writing files to the host (e.g. OpenShift). +privileged: false +# Configures the generation of the ServiceAccount. +serviceAccount: + # -- Whether a ServiceAccount should be created. + create: true + # -- Annotations to add to the ServiceAccount. + annotations: {} + # -- Name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template. + name: "" +# Configures the generation of a NetworkAttachmentDefinition for use with Multus CNI (OpenShift) +multusNetworkAttachmentDefinition: + # -- Whether a NetworkAttachmentDefinition CR should be created, which can be used for applying the CNI plugin to Pods. + create: false + # -- Namespace in which the NetworkAttachmentDefinition is deployed. + # Note: If namespace is set to a custom value, referencing the created NetworkAttachmentDefinition from other namespaces + # may not work if Multus namespace isolation is enabled. https://github.com/k8snetworkplumbingwg/multus-cni/blob/v4.0.2/docs/configuration.md#namespace-isolation + namespace: default +# Parameters for the CNI installer configuration. +config: + # -- Whether to install the CNI plugin as a `chained` plugin (default, required with most interface CNI providers), + # as a `standalone` plugin (required for use with Multus CNI, e.g. on OpenShift) + # or in `manual` mode, where no CNI network configuration is written. + installMode: "chained" + # -- Log level for the CNI installer and plugin. + logLevel: info + # -- Directory where the CNI config files reside on the host. + # This path can either be found in the documentation of your Kubernetes distribution or CNI provider. + # It can also be queried by running the command `crictl info -o go-template --template '{{.config.cni.confDir}}'` on your Kubernetes node. + cniNetDir: "/etc/cni/net.d" + # -- Directory where the CNI plugin binaries reside on the host. + # This path can either be found in the documentation of your Kubernetes distribution or CNI provider. + # It can also be queried by running the command `crictl info -o go-template --template '{{.config.cni.binDir}}'` on your Kubernetes node. + cniBinDir: "/opt/cni/bin" + # -- Namespaces for which this CNI plugin should not apply any modifications. + excludeNamespaces: + - kube-system +tests: + # -- Whether additional resources required for running `helm test` should be created (e.g. Roles and ServiceAccounts). + # If set to false, `helm test` will not run any tests. + enabled: false diff --git a/charts/airlock/microgateway/4.3.4/.helmignore b/charts/airlock/microgateway/4.3.4/.helmignore new file mode 100644 index 0000000000..101ff5ac56 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/.helmignore @@ -0,0 +1,28 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# CRDs kustomization.yaml +/crds/kustomization.yaml +# Helm unit tests +/tests +/validation diff --git a/charts/airlock/microgateway/4.3.4/Chart.yaml b/charts/airlock/microgateway/4.3.4/Chart.yaml new file mode 100644 index 0000000000..afc6038570 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/Chart.yaml @@ -0,0 +1,44 @@ +annotations: + artifacthub.io/category: security + artifacthub.io/license: MIT + artifacthub.io/links: | + - name: Airlock Microgateway Documentation + url: https://docs.airlock.com/microgateway/4.3/ + - name: Airlock Microgateway Labs + url: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=artifacthub.io + - name: Airlock Microgateway Forum + url: https://forum.airlock.com/ + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Airlock Microgateway + catalog.cattle.io/kube-version: '>=1.25.0-0' + catalog.cattle.io/release-name: microgateway + charts.openshift.io/name: Airlock Microgateway +apiVersion: v2 +appVersion: 4.3.4 +description: A Helm chart for deploying the Airlock Microgateway +home: https://www.airlock.com/en/microgateway +icon: file://assets/icons/microgateway.svg +keywords: +- WAF +- Web Application Firewall +- WAAP +- Web Application and API protection +- OWASP +- Airlock +- Microgateway +- Security +- Filtering +- DevSecOps +- shift left +- control plane +- Operator +kubeVersion: '>=1.25.0-0' +maintainers: +- email: support@airlock.com + name: Airlock + url: https://www.airlock.com/ +name: microgateway +sources: +- https://github.com/airlock/microgateway +type: application +version: 4.3.4 diff --git a/charts/airlock/microgateway/4.3.4/README.md b/charts/airlock/microgateway/4.3.4/README.md new file mode 100644 index 0000000000..5028932b15 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/README.md @@ -0,0 +1,180 @@ +# Airlock Microgateway + +![Version: 4.3.4](https://img.shields.io/badge/Version-4.3.4-informational?style=flat-square) ![AppVersion: 4.3.4](https://img.shields.io/badge/AppVersion-4.3.4-informational?style=flat-square) + +*Airlock Microgateway is a Kubernetes native WAAP (Web Application and API Protection) solution to protect microservices.* + + + + + Microgateway + + +Modern application security is embedded in the development workflow and follows DevSecOps paradigms. Airlock Microgateway is the perfect fit for these requirements. It is a lightweight alternative to the Airlock Gateway appliance, optimized for Kubernetes environments. Airlock Microgateway protects your applications and microservices with the tried-and-tested Airlock security features against attacks, while also providing a high degree of scalability. +__This Helm chart is part of Airlock Microgateway. See our [GitHub repo](https://github.com/airlock/microgateway/tree/4.3.4).__ + +### Features +* Kubernetes native integration with its Operator, Custom Resource Definitions, hot-reload, automatic sidecar injection. +* Reverse proxy functionality with request routing rules, TLS termination and remote IP extraction +* Using native Envoy HTTP filters like Lua scripting, RBAC, ext_authz, JWT authentication +* Content security filters for protecting against known attacks (OWASP Top 10) +* Access control using OpenID Connect to allow only authenticated users to access the protected services +* API security features like JSON parsing, OpenAPI specification enforcement or GraphQL schema validation + +For a list of all features, view the **[comparison of the community and premium edition](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html)**. + +## Documentation and links + +Check the official documentation at **[docs.airlock.com](https://docs.airlock.com/microgateway/latest/)** or the product website at **[airlock.com/microgateway](https://www.airlock.com/en/microgateway)**. The links below point out the most interesting documentation sites when starting with Airlock Microgateway. + +* [Getting Started](https://docs.airlock.com/microgateway/latest/#data/1660804708742.html) +* [System Architecture](https://docs.airlock.com/microgateway/latest/#data/1660804709650.html) +* [Installation](https://docs.airlock.com/microgateway/latest/#data/1660804708637.html) +* [Troubleshooting](https://docs.airlock.com/microgateway/latest/#data/1659430054787.html) +* [GitHub](https://github.com/airlock/microgateway) + +# Quick start guide + +The instructions below provide a quick start guide. Detailed information are provided in the **[manual](https://docs.airlock.com/microgateway/latest/)**. + +## Prerequisites +* [Airlock Microgateway CNI](https://artifacthub.io/packages/helm/airlock-microgateway-cni/microgateway-cni) +* [Airlock Microgateway License](#obtain-airlock-microgateway-license) +* [cert-manager](https://cert-manager.io/) +* [helm](https://helm.sh/docs/intro/install/) (>= v3.8.0) + +In order to use Airlock Microgateway you need a license and the cert-manager. You may either request a community license free of charge or purchase a premium license. +For an easy start in non-production environments, you may deploy the same cert-manager we are using internally for testing. +### Obtain Airlock Microgateway License +1. Either request a community or premium license + * Community license: [airlock.com/microgateway-community](https://airlock.com/en/microgateway-community) + * Premium license: [airlock.com/microgateway-premium](https://airlock.com/en/microgateway-premium) +2. Check your inbox and save the license file microgateway-license.txt locally. + +> See [Community vs. Premium editions in detail](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html) to choose the right license type. +### Deploy cert-manager +```bash +helm repo add jetstack https://charts.jetstack.io +helm install cert-manager jetstack/cert-manager --version '1.15.1' -n cert-manager --create-namespace --set crds.enabled=true --wait +``` + +## Deploy Airlock Microgateway Operator + +> This guide assumes a microgateway-license.txt file is present in the working directory. + +1. Install CRDs and Operator. + ```bash + # Create namespace + kubectl create namespace airlock-microgateway-system + + # Install License + kubectl -n airlock-microgateway-system create secret generic airlock-microgateway-license --from-file=microgateway-license.txt + + # Install Operator (CRDs are included via the standard Helm 3 mechanism, i.e. Helm will handle initial installation but not upgrades) + helm install airlock-microgateway -n airlock-microgateway-system oci://quay.io/airlockcharts/microgateway --version '4.3.4' --wait + ``` + +2. (Recommended) You can verify the correctness of the installation with `helm test`. + ```bash + helm upgrade airlock-microgateway -n airlock-microgateway-system --set tests.enabled=true --reuse-values oci://quay.io/airlockcharts/microgateway --version '4.3.4' + helm test airlock-microgateway -n airlock-microgateway-system --logs + helm upgrade airlock-microgateway -n airlock-microgateway-system --set tests.enabled=false --reuse-values oci://quay.io/airlockcharts/microgateway --version '4.3.4' + ``` + +### Upgrading CRDs + +The `helm install/upgrade` command currently does not support upgrading CRDs that already exist in the cluster. +CRDs should instead be manually upgraded before upgrading the Operator itself via the following command: +```bash +kubectl apply -k https://github.com/airlock/microgateway/deploy/charts/airlock-microgateway/crds/?ref=4.3.4 --server-side --force-conflicts +``` + +**Note**: Certain GitOps solutions such as e.g. Argo CD or Flux CD have their own mechanisms for automatically upgrading CRDs included with Helm charts. + +## Support + +### Premium support +If you have a paid license, please follow the [premium support process](https://techzone.ergon.ch/support-process). + +### Community support +For the community edition, check our **[Airlock community forum](https://forum.airlock.com/)** for FAQs or register to post your question. +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| commonAnnotations | object | `{}` | Annotations to add to all resources. | +| commonLabels | object | `{}` | Labels to add to all resources. | +| crds.skipVersionCheck | bool | `false` | Whether to skip the sanity check which prevents installing/upgrading the helm chart in a cluster with outdated Airlock Microgateway CRDs. The check aims to prevent unexpected behavior and issues due to Helm v3 not automatically upgrading CRDs which are already present in the cluster when performing a "helm install/upgrade". | +| dashboards.config.grafana.dashboardLabel.name | string | `"grafana_dashboard"` | Name of the label that lets Grafana identify ConfigMaps that represent dashboards. | +| dashboards.config.grafana.dashboardLabel.value | string | `"1"` | Value of the label that lets Grafana identify ConfigMaps that represent dashboards. | +| dashboards.config.grafana.folderAnnotation.name | string | `"grafana_folder"` | Name of the annotation containing the folder name to file dashboards into. | +| dashboards.config.grafana.folderAnnotation.value | string | `"Airlock Microgateway"` | Name of the folder dashboards are filed into within the Grafana UI. | +| dashboards.create | bool | `false` | Whether to create any ConfigMaps containing Grafana dashboards to import. | +| dashboards.instances.blockLogs.create | bool | `true` | Whether to create the block logs dashboard. | +| dashboards.instances.blockMetrics.create | bool | `true` | Whether to create the block metrics dashboard. | +| dashboards.instances.license.create | bool | `true` | Whether to create the license dashboard. | +| dashboards.instances.overview.create | bool | `true` | Whether to create the overview dashboard. | +| engine.image.digest | string | `"sha256:91e05c509bed3b51ff4888d7475980d56cbc85db121aa766d1bde413204f9070"` | SHA256 image digest to pull (in the format "sha256:a3051f42d3013813b05f7513bb86ed6a3209cb3003f1bb2f7b72df249aa544d3"). Overrides tag when specified. | +| engine.image.pullPolicy | string | `"IfNotPresent"` | Pull policy for this image. | +| engine.image.repository | string | `"quay.io/airlock/microgateway-engine"` | Image repository from which to pull the Airlock Microgateway Engine image. | +| engine.image.tag | string | `"4.3.4"` | Image tag to pull. | +| engine.resources | object | `{}` | Resource restrictions to apply to the Airlock Microgateway Engine container. | +| engine.sidecar.podMonitor.create | bool | `false` | Whether to create a PodMonitor resource for monitoring. | +| engine.sidecar.podMonitor.labels | object | `{}` | Labels to add to the PodMonitor. | +| fullnameOverride | string | `""` | Allows overriding the name to use as full name of resources. | +| imagePullSecrets | list | `[]` | ImagePullSecrets to use when pulling images. | +| license.secretName | string | `"airlock-microgateway-license"` | Name of the secret containing the "microgateway-license.txt" key. | +| nameOverride | string | `""` | Allows overriding the name to use instead of "microgateway". | +| networkValidator.image.digest | string | `"sha256:7a73d4b82a2d4165bbc5efa55de4fee9d43f2b1c1edb3505cdc8afd1361bad9b"` | SHA256 image digest to pull (in the format "sha256:7a73d4b82a2d4165bbc5efa55de4fee9d43f2b1c1edb3505cdc8afd1361bad9b"). Overrides tag when specified. | +| networkValidator.image.pullPolicy | string | `"IfNotPresent"` | Pull policy for this image. | +| networkValidator.image.repository | string | `"cgr.dev/chainguard/netcat"` | Image repository from which to pull the netcat image for the Airlock Microgateway Network Validator init-container. | +| networkValidator.image.tag | string | `""` | Image tag to pull. | +| operator.affinity | object | `{}` | Custom affinity to apply to the operator Deployment. Used to influence the scheduling. | +| operator.config.logLevel | string | `"info"` | Operator application log level. | +| operator.image.digest | string | `"sha256:6819c78d5570de66edce6c13964c6e1b4cc4746d0c0bc6f4975cd38e324828c0"` | SHA256 image digest to pull (in the format "sha256:c79ee3f85862fb386e9dd62b901b607161d27807f512d7fbdece05e9ee3d7c63"). Overrides tag when specified. | +| operator.image.pullPolicy | string | `"IfNotPresent"` | Pull policy for this image. | +| operator.image.repository | string | `"quay.io/airlock/microgateway-operator"` | Image repository from which to pull the Airlock Microgateway Operator image. | +| operator.image.tag | string | `"4.3.4"` | Image tag to pull. | +| operator.nodeSelector | object | `{}` | Custom nodeSelector to apply to the operator Deployment in order to constrain its Pods to certain nodes. | +| operator.podAnnotations | object | `{}` | Annotations to add to all Pods. | +| operator.podLabels | object | `{}` | Labels to add to all Pods. | +| operator.rbac.create | bool | `true` | Whether to create RBAC resources which are required for the Airlock Microgateway Operator to function. | +| operator.replicaCount | int | `2` | Number of replicas for the operator Deployment. | +| operator.resources | object | `{}` | Resource restrictions to apply to the operator container. | +| operator.serviceAccount.annotations | object | `{}` | Annotations to add to the ServiceAccount. | +| operator.serviceAccount.create | bool | `true` | Whether a ServiceAccount should be created. | +| operator.serviceAccount.name | string | `""` | Name of the ServiceAccount to use. If not set and create is true, a name is generated using the fullname template. | +| operator.serviceAnnotations | object | `{}` | Annotations to add to the Service. | +| operator.serviceLabels | object | `{}` | Labels to add to the Service. | +| operator.serviceMonitor.create | bool | `false` | Whether to create a ServiceMonitor resource for monitoring. | +| operator.serviceMonitor.labels | object | `{}` | Labels to add to the ServiceMonitor. | +| operator.tolerations | list | `[]` | Custom tolerations to apply to the operator Deployment in order to allow its Pods to run on tainted nodes. | +| operator.updateStrategy | object | `{"type":"RollingUpdate"}` | Specifies the operator update strategy. | +| operator.watchNamespaceSelector | object | `{}` | Allows to dynamically select watch namespaces of the operator and the scope of the webhooks based on a Namespace label selector. It is able to detect and reconcile resources in all namespaces that match the label selector automatically, even for new namespaces, without restarting the operator. This facilitates a dynamic `MultiNamespace` installation mode, but still requires cluster-scoped permissions (i.e., ClusterRoles and ClusterRoleBindings). An `AllNamespaces` installation or the usage of the `watchNamespaces` requires the `watchNamespaceSelector` to be empty. Please note that this feature requires a Premium license. | +| operator.watchNamespaces | list | `[]` | Allows to restrict the operator to specific namespaces, depending on your needs. For a `OwnNamespace` or `SingleNamespace` installation the list may only contain one namespace (e.g., `watchNamespaces: ["airlock-microgateway-system"]`). In case of the `OwnNamespace` installation mode the specified namespace should be equal to the installation namespace. For a static `MultiNamespace` installation, the complete list of namespaces must be provided in the `watchNamespaces`. An `AllNamespaces` installation or the usage of the `watchNamespaceSelector` requires the `watchNamespaces` to be empty. Regardless of the installation modes supported by `watchNamespaces`, RBAC is created only namespace-scoped (using Roles and RoleBindings) in the respective namespaces. Please note that this feature requires a Premium license. | +| sessionAgent.image.digest | string | `"sha256:df4e50d0929cb4c5e4486452979b59ec17f5e49a1516b685acd3a1ab0ddb3cf4"` | SHA256 image digest to pull (in the format "sha256:a3051f42d3013813b05f7513bb86ed6a3209cb3003f1bb2f7b72df249aa544d3"). Overrides tag when specified. | +| sessionAgent.image.pullPolicy | string | `"IfNotPresent"` | Pull policy for this image. | +| sessionAgent.image.repository | string | `"quay.io/airlock/microgateway-session-agent"` | Image repository from which to pull the Airlock Microgateway Session Agent image. | +| sessionAgent.image.tag | string | `"4.3.4"` | Image tag to pull. | +| sessionAgent.resources | object | `{}` | Resource restrictions to apply to the Airlock Microgateway Session Agent container. | +| tests.enabled | bool | `false` | Whether additional resources required for running `helm test` should be created (e.g. Roles and ServiceAccounts). If set to false, `helm test` will not run any tests. | + +## License +View the [detailed license terms](https://www.airlock.com/en/airlock-license) for the software contained in this image. +* Decompiling or reverse engineering is not permitted. +* Using any of the deny rules or parts of these filter patterns outside of the image is not permitted. + +Airlock® is a security innovation by [ergon](https://www.ergon.ch/en) + + + + + + + Airlock Secure Access Hub + + diff --git a/charts/airlock/microgateway/4.3.4/app-readme.md b/charts/airlock/microgateway/4.3.4/app-readme.md new file mode 100644 index 0000000000..e32cac0259 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/app-readme.md @@ -0,0 +1,28 @@ +# Airlock Microgateway + +*Airlock Microgateway is a Kubernetes native WAAP (Web Application and API Protection) solution to protect microservices.* + +## Features +* Kubernetes native integration with its Operator, Custom Resource Definitions, hot-reload, automatic sidecar injection. +* Reverse proxy functionality with request routing rules, TLS termination and remote IP extraction +* Using native Envoy HTTP filters like Lua scripting, RBAC, ext_authz, JWT authentication +* Content security filters for protecting against known attacks (OWASP Top 10) +* Access control to allow only authenticated users to access the protected services +* API security features like JSON parsing or OpenAPI specification enforcement + +For a list of all features, view the **[comparison of the community and premium edition](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html)**. + +## Requirements +* [Airlock Microgateway CNI Helm Chart](https://artifacthub.io/packages/helm/airlock-microgateway-cni/microgateway-cni) (Also available as Rancher Chart) +* [Airlock Microgateway License](https://github.com/airlock/microgateway?tab=readme-ov-file#obtain-airlock-microgateway-license) (After obtaining the license install it according to the [documentation](https://github.com/airlock/microgateway?tab=readme-ov-file#deploy-airlock-microgateway-operator)) +* [cert-manager](https://cert-manager.io/docs/installation/) + +## Documentation and links + +Check the official documentation at **[docs.airlock.com](https://docs.airlock.com/microgateway/latest/)** or the product website at **[airlock.com/microgateway](https://www.airlock.com/en/microgateway)**. The links below point out the most interesting documentation sites when starting with Airlock Microgateway. + +* [Getting Started](https://docs.airlock.com/microgateway/latest/#data/1660804708742.html) +* [System Architecture](https://docs.airlock.com/microgateway/latest/#data/1660804709650.html) +* [Installation](https://docs.airlock.com/microgateway/latest/#data/1660804708637.html) +* [Troubleshooting](https://docs.airlock.com/microgateway/latest/#data/1659430054787.html) +* [GitHub](https://github.com/airlock/microgateway) \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/crds/accesscontrols.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/accesscontrols.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..9dc81f14dc --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/accesscontrols.microgateway.airlock.com.yaml @@ -0,0 +1,124 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: accesscontrols.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: AccessControl + listKind: AccessControlList + plural: accesscontrols + singular: accesscontrol + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: AccessControl specifies the options to perform access control with a Microgateway Engine container. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specifies how the Airlock Microgateway Engine performs access control. + properties: + policies: + description: Policies configures access control policies. + items: + properties: + authorization: + description: Authorization configures how requests are authorized. An empty object value {} disables authorization. + properties: + authentication: + description: Authentication specifies that clients need to be authenticated with the provided method. + properties: + oidc: + description: OIDC configures client authentication using OpenID Connect. + properties: + oidcRelyingPartyRef: + description: OIDCRelyingPartyRef configures how the Airlock Microgateway Engine interacts with the OpenID provider. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - oidcRelyingPartyRef + type: object + type: object + type: object + identityPropagation: + description: IdentityPropagation configures how the authenticated user's identity is communicated to the protected application. + properties: + actions: + description: Actions specifies the propagation actions. + items: + properties: + identityPropagationRef: + description: IdentityPropagationRef selects an IdentityPropagation to apply. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - identityPropagationRef + type: object + type: array + onFailure: + description: |- + OnFailure configures what should happen, if an identity propagation fails. Meaning of the possible values: + _Pass_: The request should be forwarded to the upstream, without including the information from the failed identity propagations. + enum: + - Pass + type: string + required: + - actions + - onFailure + type: object + required: + - authorization + type: object + maxItems: 1 + minItems: 1 + type: array + required: + - policies + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/contentsecurities.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/contentsecurities.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..e63a5b1eb8 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/contentsecurities.microgateway.airlock.com.yaml @@ -0,0 +1,139 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: contentsecurities.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: ContentSecurity + listKind: ContentSecurityList + plural: contentsecurities + singular: contentsecurity + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: ContentSecurity specifies the options to secure an upstream web application with a Microgateway Engine container. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specifies the options to secure an upstream web application with a Microgateway Engine container. + properties: + apiProtection: + description: |- + APIProtection defines the relevant configurations to protect APIs. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + graphQLRef: + description: |- + GraphQLRef selects the relevant GraphQL configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + openAPIRef: + description: |- + OpenAPIRef selects the relevant OpenAPI configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + filter: + description: |- + Filter defines the set of filters, e.g. Airlock Deny Rules, to be applied to incoming requests + to protect against various attack patterns. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + denyRulesRef: + description: |- + DenyRulesRef selects the relevant DenyRules configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + headerRewritesRef: + description: |- + HeaderRewritesRef selects the relevant HeaderRewrites. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + limitsRef: + description: |- + LimitsRef selects the relevant Limits configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + parserRef: + description: |- + ParserRef selects the relevant Parser configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/denyrules.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/denyrules.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..7108ee5e0f --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/denyrules.microgateway.airlock.com.yaml @@ -0,0 +1,1804 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: denyrules.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: DenyRules + listKind: DenyRulesList + plural: denyrules + singular: denyrules + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + DenyRules configures request filtering using Airlock built-in and custom deny rules. + Deny rules establish a negative security model. They define prohibited patterns which, when a match is found in a request, lead to it being blocked from reaching the upstream web application. + To handle possible false positives, lower the security level or define fine-granular deny rule exceptions + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired deny rules behavior. + properties: + request: + description: Request configures deny rules for downstream requests. + properties: + builtIn: + description: BuiltIn configures the built-in deny rules. + properties: + exceptions: + description: Exceptions allows to define exceptions for specific requests and deny rules. + items: + description: |- + DenyRulesException defines an exception for deny rules. Exceptions may be defined by any or a combination of the following elements: blockedData (the request data causing a block) or requestConditions (properties of a request without taking into consideration the reason why a request has been blocked). + At least one of blockedData and requestConditions must be set. + properties: + blockedData: + description: BlockedData defines an exception based on the request data causing the block. + properties: + graphQL: + description: |- + GraphQL defines an exception based on a blocked GraphQL query. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + argument: + description: |- + Argument defines an argument of a field of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + field: + description: |- + Field defines a field of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: |- + Value defines the value of an argument of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + header: + description: |- + Header defines an exception based on a blocked header. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + json: + description: |- + JSON defines an exception based on a blocked JSON property. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + jsonPath: + description: |- + JSONPath defines the JSONPath pattern to match the path within the JSON. + Expressions in JSONPath i.e. `?(expr)` are not supported. + minLength: 1 + type: string + key: + description: |- + Key defines the key of the JSON property. + At most one of key and value can be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: |- + Value defines the value of the JSON property. + At most one of key and value can be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + parameter: + description: |- + Parameter defines an exception based on a blocked parameter. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + name: + description: Name defines the name of a parameter. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + source: + default: Any + description: Source defines the source of the parameter. + enum: + - Query + - Post + - Any + type: string + value: + description: Value defines the value of a parameter. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + path: + description: |- + Path defines an exception based on the blocked path. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + pathSegment: + description: |- + PathSegment defines an exception based on a blocked path segment. + Only one of parameter, header, path, pathSegment, json or graphQL can be set. + properties: + segments: + description: Segments defines the position of a segment within the path. + properties: + index: + description: Index specifies an exact path segment position by index (0-based). + minimum: 0 + type: integer + type: object + value: + description: Value defines the value of a path segment. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + type: object + requestConditions: + description: RequestConditions defines an exception based on a property of a request without taking into consideration the reason why a request has been blocked. + properties: + header: + description: Header defines the matching headers of a request. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + invert: + default: false + description: Invert indicates whether the request condition should be inverted. + type: boolean + mediaType: + description: MediaType defines the matching media type from the content-type header of a request. + properties: + matcher: + description: |- + NonInvertableCaseInsensitiveStringMatcher defines the way to match a string. + In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + method: + description: Method defines the matching methods of a request. + items: + description: Method defines common HTTP methods. + enum: + - GET + - HEAD + - POST + - PUT + - PATCH + - DELETE + - CONNECT + - OPTIONS + - TRACE + type: string + type: array + path: + description: Path defines the matching path of a request. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + remoteIP: + description: RemoteIP defines the matching remote IPs of a request. + properties: + cidrRanges: + description: CIDRRanges defines the IPv4 or IPv6 CIDR ranges, e.g. ``196.148.3.128/26`` or ``2001:db8::/28``. + items: + description: CIDRRange defines an IPv4 or IPv6 CIDR range, e.g. “196.148.3.128/26“ or “2001:db8::/28“. + format: cidr + type: string + minItems: 1 + type: array + invert: + default: false + description: Invert indicates whether the match should be inverted. + type: boolean + required: + - cidrRanges + type: object + type: object + ruleKeys: + description: RuleKeys restricts the exception to a set of deny rules. + items: + description: |- + A deny rule name can be any of the following values: + ENCODING | + EXPLOIT | + HPP | + HTML | + IDOR | + LDAP | + NOSQL | + OGNL | + PHP | + PROTOCOL | + SANITY | + SCANNING | + SQL | + TEMPLATE | + UNIXCMD | + WINCMD | + XSS + enum: + - ENCODING + - EXPLOIT + - HPP + - HTML + - IDOR + - LDAP + - NOSQL + - OGNL + - PHP + - PROTOCOL + - SANITY + - SCANNING + - SQL + - TEMPLATE + - UNIXCMD + - WINCMD + - XSS + type: string + minItems: 1 + type: array + type: object + type: array + overrides: + description: Overrides allows to override the builtIn settings for specific deny rules. + items: + description: DenyRulesOverride allows to override the builtIn settings for specific deny rules. + properties: + conditions: + description: Conditions select which built-in deny rules' settings will be adjusted. + properties: + ruleKeys: + description: RuleKeys is a list of built-in deny rule names. + items: + description: |- + A deny rule name can be any of the following values: + ENCODING | + EXPLOIT | + HPP | + HTML | + IDOR | + LDAP | + NOSQL | + OGNL | + PHP | + PROTOCOL | + SANITY | + SCANNING | + SQL | + TEMPLATE | + UNIXCMD | + WINCMD | + XSS + enum: + - ENCODING + - EXPLOIT + - HPP + - HTML + - IDOR + - LDAP + - NOSQL + - OGNL + - PHP + - PROTOCOL + - SANITY + - SCANNING + - SQL + - TEMPLATE + - UNIXCMD + - WINCMD + - XSS + type: string + minItems: 1 + type: array + types: + description: Types defines the type of attributes the override should be applied on. If Types are defined without any RuleKeys the override is applied to all deny rules. + items: + description: |- + A deny rule override type name can be any of the following values: + Header | + Parameter | + Path | + JSON | + GraphQL + enum: + - Header + - Parameter + - Path + - PathSegment + - JSON + - GraphQL + type: string + minItems: 0 + type: array + type: object + settings: + description: Settings override the corresponding properties for the selected rules. + properties: + level: + description: Level specifies the filter strength. + enum: + - Unfiltered + - Basic + - Standard + - Strict + type: string + threatHandlingMode: + description: ThreatHandlingMode specifies how threats should be handled. + enum: + - Block + - LogOnly + type: string + type: object + type: object + type: array + settings: + description: Settings contains the keys which will be adjusted. + properties: + level: + default: Standard + description: Level represents a set of deny rules with different filter strengths. + enum: + - Unfiltered + - Basic + - Standard + - Strict + type: string + threatHandlingMode: + default: Block + description: ThreatHandlingMode specifies how threats should be handled when a deny rule matches. + enum: + - Block + - LogOnly + type: string + type: object + type: object + custom: + description: Custom allows configuring additional deny rules. + properties: + rules: + description: Rules defines list of additional deny rules. + items: + properties: + blockData: + description: BlockData specifies the request data which should cause a block. + properties: + graphQL: + description: |- + GraphQL specifies to block requests containing a matching GraphQL property. + At least one of field, argument and value must be set. + properties: + argument: + description: |- + Argument defines an argument of a field of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + field: + description: |- + Field defines a field of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: |- + Value defines the value of an argument of the GraphQL query. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + header: + description: |- + Header specifies to block requests containing a matching header. + Only one of parameter, header, path, pathSegment or json can be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: |- + NonInvertableCaseInsensitiveStringMatcher defines the way to match a string. + In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + json: + description: |- + JSON specifies to block requests containing a matching JSON property in the body. + Only one of parameter, header, path, pathSegment or json can be set. + properties: + key: + description: Key defines the key of a JSON object. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a JSON object. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + parameter: + description: |- + Parameter specifies to block requests containing a matching parameter. + Only one of parameter, header, path, pathSegment or json can be set. + properties: + name: + description: Name defines the name of a parameter. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a parameter. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + path: + description: |- + Path specifies to block requests with a matching path. + Only one of parameter, header, path, pathSegment or json can be set. + properties: + matcher: + description: Matcher specifies which path to block. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + pathSegment: + description: |- + PathSegment specifies to block requests containing a matching path segment. + Only one of parameter, header, path, pathSegment or json can be set. + properties: + segments: + description: |- + Segments restricts which path segments are filtered by this rule. + If not specified, all segments of a path are filtered. + properties: + index: + description: Index restricts the rule to the path segment at this index (0-based). + minimum: 0 + type: integer + type: object + value: + description: Value specifies which path segment values to block. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + required: + - value + type: object + type: object + requestConditions: + description: RequestConditions defines additional request properties which must be matched in order for this rule to apply. + properties: + header: + description: Header defines the matching headers of a request. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + invert: + default: false + description: Invert indicates whether the request condition should be inverted. + type: boolean + mediaType: + description: MediaType defines the matching media type from the content-type header of a request. + properties: + matcher: + description: |- + NonInvertableCaseInsensitiveStringMatcher defines the way to match a string. + In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + method: + description: Method defines the matching methods of a request. + items: + description: Method defines common HTTP methods. + enum: + - GET + - HEAD + - POST + - PUT + - PATCH + - DELETE + - CONNECT + - OPTIONS + - TRACE + type: string + type: array + path: + description: Path defines the matching path of a request. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + remoteIP: + description: RemoteIP defines the matching remote IPs of a request. + properties: + cidrRanges: + description: CIDRRanges defines the IPv4 or IPv6 CIDR ranges, e.g. ``196.148.3.128/26`` or ``2001:db8::/28``. + items: + description: CIDRRange defines an IPv4 or IPv6 CIDR range, e.g. “196.148.3.128/26“ or “2001:db8::/28“. + format: cidr + type: string + minItems: 1 + type: array + invert: + default: false + description: Invert indicates whether the match should be inverted. + type: boolean + required: + - cidrRanges + type: object + type: object + ruleKey: + description: RuleKey defines a technical key for the deny rule. Must be unique. + minLength: 1 + pattern: ^[A-Z][A-Z0-9_]*$ + type: string + threatHandlingMode: + default: Block + description: ThreatHandlingMode specifies how threats should be handled when a deny rule matches. + enum: + - Block + - LogOnly + type: string + required: + - blockData + - ruleKey + type: object + type: array + x-kubernetes-list-map-keys: + - ruleKey + x-kubernetes-list-type: map + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/envoyclusters.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/envoyclusters.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..35dda9f2f0 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/envoyclusters.microgateway.airlock.com.yaml @@ -0,0 +1,58 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: envoyclusters.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: EnvoyCluster + listKind: EnvoyClusterList + plural: envoyclusters + singular: envoycluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: EnvoyCluster is an additional Envoy Cluster resource which is added to those defined by the Airlock Microgateway. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired additional Envoy cluster. + properties: + value: + description: Value defines the Envoy Cluster which is added to those configured by the Airlock Microgateway. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/envoyconfigurations.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/envoyconfigurations.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..c4f61f20d0 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/envoyconfigurations.microgateway.airlock.com.yaml @@ -0,0 +1,185 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: envoyconfigurations.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: EnvoyConfiguration + listKind: EnvoyConfigurationList + plural: envoyconfigurations + singular: envoyconfiguration + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + EnvoyConfiguration is the Schema for the envoyconfigurations API + {{% notice warning %}} EnvoyConfiguration resources may contain sensitive information and thus RBAC permissions should be granted with care. {{% /notice %}} + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: EnvoyConfigurationSpec defines the desired state of EnvoyConfiguration + properties: + envoyResources: + properties: + clusters: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + endpoints: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extensions: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + listeners: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + routes: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + runtimes: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + scopedRoutes: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + secrets: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + envoyResourcesRaw: + description: |- + EnvoyResourcesRaw defines the desired state for each resource type. The resources are stored as zstd compressed JSON bytes. + For debugging purposes, the resources can be inspected with the following command: `kubectl get envoyconfiguration -ojsonpath='{.spec.envoyResourcesRaw}' | base64 -d | zstd -d | jq` + format: byte + type: string + nodeID: + description: '**Deprecated:** This field is now ignored as NodeID is always derived from the resource name.' + type: string + type: object + status: + description: EnvoyConfigurationStatus defines the observed state of EnvoyConfiguration + properties: + conditions: + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of EnvoyConfiguration condition. + type: string + required: + - status + - type + type: object + type: array + status: + type: string + xds: + properties: + resourceTypes: + additionalProperties: + description: XdsResourceTypeSyncStatus defines the sync status of xDS for a specific resource type + properties: + errorMessage: + description: ErrorMessage defines an optional message why the currently served resources of this resource type are rejected by the client. + type: string + resources: + additionalProperties: + description: XdsResourceStatus defines the status of xDS for a specific resource + properties: + version: + description: Version defines the version which is currently served for this resource. + type: string + required: + - version + type: object + description: Resources defines the resources which are currently served for this resource type. + type: object + status: + description: Status defines the current sync status of this resource type. + type: string + version: + description: Version defines the version which is currently served for this resource type. + type: string + required: + - resources + - status + - version + type: object + description: ResourceTypes defines the sync statuses for each resource type. + type: object + version: + description: Version defines the version of the underlying xDS snapshot. + type: integer + required: + - version + type: object + required: + - status + - xds + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/envoyhttpfilters.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/envoyhttpfilters.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..538ff672f1 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/envoyhttpfilters.microgateway.airlock.com.yaml @@ -0,0 +1,58 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: envoyhttpfilters.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: EnvoyHTTPFilter + listKind: EnvoyHTTPFilterList + plural: envoyhttpfilters + singular: envoyhttpfilter + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: EnvoyHTTPFilter is an additional Envoy HTTP Filter resource which is added to those defined by the Airlock Microgateway. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired additional Envoy HTTP filter. + properties: + value: + description: Value defines the HTTP filter which is added to those configured by the Airlock Microgateway. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/graphqls.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/graphqls.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..165abe0a2c --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/graphqls.microgateway.airlock.com.yaml @@ -0,0 +1,88 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: graphqls.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: GraphQL + listKind: GraphQLList + plural: graphqls + singular: graphql + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: GraphQL contains the configuration for the GraphQL specification. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired GraphQL specification. + properties: + settings: + description: Settings defines the settings to configure GraphQL. + properties: + allowIntrospection: + default: true + description: AllowIntrospection specifies if the introspection system is exposed. + type: boolean + allowMutations: + default: true + description: AllowMutations specifies if mutations are allowed. + type: boolean + schema: + description: Specifies the GraphQL schema. + properties: + source: + description: Source specifies the GraphQL schema to be enforced. + properties: + configMapRef: + description: ConfigMapRef references the configmap by its name containing the well-known key 'schema.graphql'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + required: + - source + type: object + threatHandlingMode: + default: Block + description: ThreatHandlingMode specifies how threats should be handled. + enum: + - Block + - LogOnly + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/headerrewrites.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/headerrewrites.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..72a1067f9f --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/headerrewrites.microgateway.airlock.com.yaml @@ -0,0 +1,759 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: headerrewrites.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: HeaderRewrites + listKind: HeaderRewritesList + plural: headerrewrites + singular: headerrewrites + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HeaderRewrites is the Schema for the headerrewrites API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired header rewriting behavior. + properties: + request: + description: Request defines manipulations on upstream request headers. + properties: + add: + description: Add defines which request headers will be added before forwarding to the upstream. + properties: + custom: + description: |- + Custom allows configuring additional upstream request headers. + Add selected headers. + items: + properties: + headers: + description: Headers to add. + items: + description: HeaderRewritesHeader specifies a header with a particular value + properties: + name: + description: Name defines the name of a header. + minLength: 1 + type: string + value: + description: Value defines the value of a header. + type: string + required: + - name + - value + type: object + minItems: 1 + type: array + mode: + default: AddIfAbsent + description: Mode defines the header addition strategy. + enum: + - AddIfAbsent + - OverwriteOrAdd + type: string + name: + description: Name describing the configured operation. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + allow: + description: |- + Allow defines which request headers will be forwarded to the upstream. + This can either be allHeaders or matchingHeaders. + Default: matchingHeaders: {...} + properties: + allHeaders: + description: AllHeaders specifies that all request headers should be forwarded. + type: object + matchingHeaders: + description: MatchingHeaders specifies which request headers should be forwarded. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined upstream request headers. + properties: + standardHeaders: + default: true + description: StandardHeaders defines whether the request headers which are forwarded to the upstream will be restricted to a set of common request headers. + type: boolean + type: object + custom: + description: Custom allows configuring additional upstream request headers. + items: + properties: + headers: + description: Headers to allow. + items: + description: |- + HeaderMatcher defines a matcher for an HTTP header. + At least one of name and value must be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + minItems: 1 + type: array + name: + description: Name describing the configured operation. Must be unique. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + remove: + description: Remove defines which request headers will be removed before forwarding to the upstream. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined upstream request headers. + properties: + alternativeForwardedHeaders: + default: true + description: |- + AlternativeForwardedHeaders removes downstream request headers which could potentially + be abused to alter the upstream's view of the remote connection. + type: boolean + type: object + custom: + description: Custom allows configuring additional upstream request headers. + items: + properties: + headers: + description: Headers to remove. + items: + description: |- + HeaderMatcher defines a matcher for an HTTP header. + At least one of name and value must be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + minItems: 1 + type: array + name: + description: Name describing the configured operation. Must be unique. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + response: + description: Response defines manipulations on upstream response headers. + properties: + add: + description: Add defines which response headers will be added before forwarding to the downstream. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined upstream response headers. + properties: + csp: + default: true + description: |- + CSP sets a content security policy which allows only same-origin requests except for images + if the 'Content-Security-Policy' header is not set by the upstream. + type: boolean + featurePolicy: + default: false + description: |- + FeaturePolicy sets a feature policy which prevents cross-origin use of several browser features + if the 'Feature-Policy' header is not set by the upstream. + **Deprecated:** Use permissionsPolicy instead. + type: boolean + hsts: + default: true + description: HSTS enforces the use of HTTPS if the 'Strict-Transport-Security' header is not already set by the upstream. + type: boolean + hstsPreload: + default: false + description: HSTSPreload enforces the use of HTTPS including for subdomains and enables HSTS preload. + type: boolean + permissionsPolicy: + default: true + description: |- + PermissionsPolicy sets a permissions policy which prevents cross-origin use of several browser features + if the 'Permissions-Policy' header is not set by the upstream. + type: boolean + referrerPolicy: + default: true + description: |- + ReferrerPolicy ensures that no 'Referer' header is sent for cross-origin requests + if the 'Referrer-Policy' header is not set by the upstream. + type: boolean + xContentTypeOptions: + default: true + description: XContentTypeOptions sets 'X-Content-Type-Options' to 'nosniff' if it is not set by the upstream. + type: boolean + xFrameOptions: + default: true + description: XFrameOptions sets 'X-Frame-Options' to SAMEORIGIN if it is not set by the upstream. + type: boolean + type: object + custom: + description: Custom allows configuring additional upstream response headers. + items: + properties: + headers: + description: Headers to add. + items: + description: HeaderRewritesHeader specifies a header with a particular value + properties: + name: + description: Name defines the name of a header. + minLength: 1 + type: string + value: + description: Value defines the value of a header. + type: string + required: + - name + - value + type: object + minItems: 1 + type: array + mode: + default: AddIfAbsent + description: Mode defines the header addition strategy. + enum: + - AddIfAbsent + - OverwriteOrAdd + type: string + name: + description: Name describing the configured operation. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + allow: + description: |- + Allow defines which response headers will be forwarded to the downstream. + This can either be allHeaders or matchingHeaders. + Default: allHeaders: {} + properties: + allHeaders: + description: AllHeaders specifies that all response headers should be forwarded. + type: object + matchingHeaders: + description: MatchingHeaders specifies which response headers should be forwarded. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined upstream response header. + properties: + standardHeaders: + default: false + description: StandardHeaders defines whether the response headers which are forwarded to the downstream will be restricted to a set of common response headers. + type: boolean + type: object + custom: + description: Custom allows configuring additional upstream response headers. + items: + properties: + headers: + description: Headers to allow. + items: + description: |- + HeaderMatcher defines a matcher for an HTTP header. + At least one of name and value must be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + minItems: 1 + type: array + name: + description: Name describing the configured operation. Must be unique. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + remove: + description: Remove defines which response headers will be removed before forwarding to the downstream. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined upstream response headers. + properties: + auth: + description: Auth defines the categories of headers concerning authentication. + properties: + basic: + default: false + description: Basic removes upstream response headers that advise clients to authenticate with Basic Authentication. + type: boolean + negotiate: + default: true + description: Negotiate removes upstream response headers that advise clients to authenticate with Negotiate. + type: boolean + ntlm: + default: true + description: |- + NTLM removes upstream response headers that advise clients to authenticate with NTLM. + By default, these headers are removed, because NTLM pass-through is not supported. + type: boolean + type: object + informationLeakage: + description: InformationLeakage defines the categories of headers concerning information leakage. + properties: + application: + default: true + description: Application removes upstream response headers that leak information about the deployed software. + type: boolean + server: + default: true + description: Server removes upstream response headers that leak information about the server. + type: boolean + type: object + permissiveCors: + default: true + description: PermissiveCORS removes upstream response headers for CORS (Cross-Origin Resource Sharing) which have no restrictions and therefore reduce client-side security. + type: boolean + type: object + custom: + description: Custom allows configuring additional upstream response headers. + items: + properties: + headers: + description: Headers to remove. + items: + description: |- + HeaderMatcher defines a matcher for an HTTP header. + At least one of name and value must be set. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + minItems: 1 + type: array + name: + description: Name describing the configured remove operation. Must be unique. + minLength: 1 + type: string + required: + - headers + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + settings: + description: Settings configures the HeaderRewrites filter. + properties: + operationalMode: + default: Production + description: OperationalMode defines the behavior of the filter. In integration mode more information is logged about the requests and responses. + enum: + - Production + - Integration + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/identitypropagations.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/identitypropagations.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..661e932f78 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/identitypropagations.microgateway.airlock.com.yaml @@ -0,0 +1,108 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: identitypropagations.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: IdentityPropagation + listKind: IdentityPropagationList + plural: identitypropagations + singular: identitypropagation + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: IdentityPropagation specifies the desired identity propagation. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired identity propagation. + properties: + header: + description: Header configures identity propagation via a request header. + properties: + name: + description: Name of the header to set. + minLength: 1 + type: string + value: + description: Value to propagate to the application. + properties: + source: + description: Source from which to extract the value. + properties: + metadata: + description: Metadata specifies to extract a value from an Envoy dynamic filter metadata key. + properties: + key: + description: Key specifies the metadata key from which to load the value, e.g. `some_payload.aud`. + minLength: 1 + type: string + namespace: + description: Namespace specifies the metadata namespace within which the lookup should be performed, e.g. `envoy.filters.http.jwt_authn`. + minLength: 1 + type: string + required: + - key + - namespace + type: object + oidc: + description: OIDC specifies to extract a value from the result of an OpenID Connect flow. + properties: + idToken: + description: IDToken specifies to extract the value from the OpenID Connect ID Token. + properties: + claim: + description: Claim selects the JWT claim from which to extract the value. + minLength: 1 + type: string + required: + - claim + type: object + required: + - idToken + type: object + type: object + required: + - source + type: object + required: + - name + - value + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/limits.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/limits.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..a75813dc4e --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/limits.microgateway.airlock.com.yaml @@ -0,0 +1,651 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: limits.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: Limits + listKind: LimitsList + plural: limits + singular: limits + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Limits contains the configuration for limits. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired limits behavior. + properties: + request: + description: Request defines the limits for requests. + properties: + limited: + description: Limited enables limits on request scope. + properties: + exceptions: + description: Exceptions defines limit exceptions. + items: + description: LimitsException defines an exception for limits. + properties: + length: + description: Length defines an exception for length limits based on the data element exceeding the limit. + properties: + graphQL: + description: GraphQL defines a field, argument or value length limit exception for a GraphQL query. + properties: + argument: + description: |- + Argument restricts the exception to GraphQL queries with a matching argument of a field. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + field: + description: |- + Field restricts the exception to GraphQL queries with a matching field. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: |- + Value restricts the exception to GraphQL queries with a matching argument value. + At least one of field, argument and value must be set. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + json: + description: JSON defines a key and value length limit exception for a JSON property. + properties: + jsonPath: + description: |- + JSONPath restricts the exception to JSON properties with a matching JSONPath. + Expressions in JSONPath i.e. `?(expr)` are not supported. + minLength: 1 + type: string + required: + - jsonPath + type: object + parameter: + description: Parameter defines a name and value length limit exception for a parameter. + properties: + name: + description: Name restricts the exception to parameters with a matching name. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + source: + default: Any + description: Source restricts the exception to parameters of this kind. + enum: + - Query + - Post + - Any + type: string + required: + - name + type: object + type: object + requestConditions: + description: RequestConditions defines additional request properties which must be matched in order for this exception to apply. + properties: + header: + description: Header defines the matching headers of a request. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + invert: + default: false + description: Invert indicates whether the request condition should be inverted. + type: boolean + mediaType: + description: MediaType defines the matching media type from the content-type header of a request. + properties: + matcher: + description: |- + NonInvertableCaseInsensitiveStringMatcher defines the way to match a string. + In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + method: + description: Method defines the matching methods of a request. + items: + description: Method defines common HTTP methods. + enum: + - GET + - HEAD + - POST + - PUT + - PATCH + - DELETE + - CONNECT + - OPTIONS + - TRACE + type: string + type: array + path: + description: Path defines the matching path of a request. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + remoteIP: + description: RemoteIP defines the matching remote IPs of a request. + properties: + cidrRanges: + description: CIDRRanges defines the IPv4 or IPv6 CIDR ranges, e.g. ``196.148.3.128/26`` or ``2001:db8::/28``. + items: + description: CIDRRange defines an IPv4 or IPv6 CIDR range, e.g. “196.148.3.128/26“ or “2001:db8::/28“. + format: cidr + type: string + minItems: 1 + type: array + invert: + default: false + description: Invert indicates whether the match should be inverted. + type: boolean + required: + - cidrRanges + type: object + type: object + type: object + type: array + general: + description: General defines general request limits. + properties: + bodySize: + anyOf: + - type: integer + - type: string + default: 100Mi + description: BodySize limits the total size of the request body. It specifies the number of bytes (0 = unlimited). This limit is effective for any request not processed by one of the content parsers (e.g. json) as configured in the Parser CRD. **Note** This limit does not apply to WebSocket or gRPC traffic. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + pathLength: + anyOf: + - type: integer + - type: string + default: 1Ki + description: PathLength defines the maximum path length for all requests (parsed and unparsed). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + graphQL: + description: GraphQL defines the limits for GraphQL requests. + properties: + nestingDepth: + default: 10 + description: NestingDepth defines the maximum depth of nesting for GraphQL objects. + format: int64 + type: integer + querySize: + anyOf: + - type: integer + - type: string + default: 1Ki + description: QuerySize defines the maximum size for GraphQL queries. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + valueLength: + anyOf: + - type: integer + - type: string + default: "256" + description: ValueLength defines the maximum length for GraphQL values. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + json: + description: JSON defines the limits for JSON requests. + properties: + bodySize: + anyOf: + - type: integer + - type: string + default: 100Ki + description: BodySize limits the total size of the JSON request body. It specifies the number of bytes (0 = unlimited). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + elementCount: + default: 10000 + description: ElementCount defines the maximum number of keys and array items in the whole JSON document (recursive). + format: int64 + type: integer + keyCount: + default: 250 + description: KeyCount defines the maximum number of keys of a single JSON object (non-recursive). + format: int64 + type: integer + keyLength: + anyOf: + - type: integer + - type: string + default: "128" + description: KeyLength defines the maximum length for JSON keys. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + nestingDepth: + default: 100 + description: NestingDepth defines the maximum depth of nesting for JSON objects and JSON arrays. + format: int64 + type: integer + valueLength: + anyOf: + - type: integer + - type: string + default: 8Ki + description: ValueLength defines the maximum length for JSON values. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + multipart: + description: Multipart defines the limits for Multipart requests. + properties: + bodySize: + anyOf: + - type: integer + - type: string + default: 100Mi + description: BodySize limits the total size of the Multipart request body. It specifies the number of bytes (0 = unlimited). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + parameter: + description: Parameter defines the limits for request parameters. + properties: + bodySize: + anyOf: + - type: integer + - type: string + default: 100Ki + description: BodySize limits the total size of the form data body. It specifies the number of bytes (0 = unlimited). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + count: + default: 128 + description: Count defines the maximum number of request parameters. + format: int64 + type: integer + nameLength: + anyOf: + - type: integer + - type: string + default: "128" + description: NameLength defines the maximum length for parameter names. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + valueLength: + anyOf: + - type: integer + - type: string + default: 8Ki + description: ValueLength defines the maximum length for parameter values. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + unlimited: + description: Unlimited disables all limits on request scope. + type: object + type: object + settings: + description: Settings configures the limits filter. + properties: + threatHandlingMode: + default: Block + description: ThreatHandlingMode specifies how threats should be handled when a limit hits. + enum: + - Block + - LogOnly + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/oidcproviders.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/oidcproviders.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..030bd153bb --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/oidcproviders.microgateway.airlock.com.yaml @@ -0,0 +1,305 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: oidcproviders.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: OIDCProvider + listKind: OIDCProviderList + plural: oidcproviders + singular: oidcprovider + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + OIDCProvider specifies an OpenID Provider (OP). + + + {{% notice warning %}} The OIDC feature is currently in an experimental state. + + + We encourage you to try it out and give feedback, but be aware that we do not recommend using it in a production environment yet, as security has not yet been hardened. + In particular, the current implementation has the following limitations, which we intend to address in future Microgateway releases: + - The state parameter is guessable. + - Sessions are always shared across all Microgateway Engines using the same Redis instance. + I.e. if application A and B (with different SidecarGateways) have the same Redis instance configured in their SessionHandling CR, users which are logged into application A + may be able to access authenticated routes on application B, even if their OIDCRelyingParty configuration differs. + + + {{% /notice %}} + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of an OpenID Provider. + properties: + static: + description: Static configures an OpenID Provider by explicitly specifying all endpoints. + properties: + endpoints: + description: Endpoints specifies the OpenID Provider endpoints. + properties: + authorization: + description: Authorization specifies the endpoint to which the authorization request is sent. + properties: + uri: + description: URI specifies the endpoint address. + format: uri + minLength: 1 + pattern: ^(http|https)://.*$ + type: string + required: + - uri + type: object + token: + description: Token configures the endpoint from which the access, ID and refresh tokens are obtained. + properties: + tls: + description: TLS defines TLS settings. + properties: + certificateVerification: + description: CertificateVerification specifies how the certificate presented by the server is verified. + properties: + custom: + description: |- + Custom explicitly specifies how the server certificate should be verified. + Typical use cases include specifying a custom CA and SAN match when working with self-signed certificates or pinning a specific public key. + properties: + allowedSANs: + description: |- + AllowedSANs is a list of matchers to verify the Subject Alternative name. If specified, it will verify that the + Subject Alternative Name of the presented certificate matches one of the specified matchers. The matching uses “any” semantics, + that is to say, the SAN is verified if at least one matcher is matched. + AllowedSANs requires trustedCA to be set. + items: + description: |- + TLSValidationContextSANMatcher is a list of matchers to verify the Subject Alternative name. If specified, it will verify that the + Subject Alternative Name of the presented certificate matches one of the specified matchers. + properties: + matcher: + description: Matcher defines the string matcher for the SAN value. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + sanType: + description: SanType defines the type of SAN matcher. + enum: + - DNS + - Email + - URI + - IPAddress + type: string + required: + - matcher + - sanType + type: object + minItems: 1 + type: array + certificatePinning: + description: |- + CertificatePinning defines constraints the presented certificate must fulfill. + If more than one constraint is configured only one must be satisfied. + At least one of allowedSPKIs and allowedHashes must be set. + properties: + allowedHashes: + description: |- + AllowedHashes is a list of hex-encoded SHA-256 hashes. + If specified, it will verify that the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + items: + type: string + minItems: 1 + type: array + allowedSPKIs: + description: |- + AllowedSPKIs is a list of base64-encoded SHA-256 hashes. + If specified, it will verify that the SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate matches one of the specified values. + items: + type: string + minItems: 1 + type: array + type: object + crl: + description: CRL defines the Certificate Revocation List (CRL) settings. + properties: + lists: + description: Lists defines the list of secretRefs containing Certificate Revocation Lists. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CRL's (in PEM format) under the key 'ca.crl'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + validationMode: + default: VerifyChain + description: ValidationMode defines whether only the leaf certificate or also the CA certs should be checked. + enum: + - VerifyLeafCertOnly + - VerifyChain + type: string + type: object + trustedCA: + description: TrustedCA defines which CA certificates are trusted. + properties: + certificates: + description: Certificates defines the list of secretRefs containing trusted CA certificates. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CA certificates under the key 'ca.crt'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + verificationDepth: + default: 1 + description: |- + VerificationDepth specifies the hops in the certificate chain at which validation is performed. + 1 means that either the leaf or the signing CA must be in the set of trusted certificates. + format: int32 + type: integer + required: + - certificates + type: object + type: object + disabled: + description: |- + Disabled specifies to trust any certificate without verification. + THIS IS INSECURE AND SHOULD ONLY BE USED FOR TESTING. + type: object + publicCAs: + description: PublicCAs specifies to only accept certificates with a SAN matching "uri" and which are signed by a CA which is either directly or indirectly trusted by any of the root CA certificates shipped with the Airlock Microgateway Engine's base image. + type: object + type: object + ciphers: + description: Ciphers defines a list of the supported TLS cipher suites. For details on cipher list refer to the envoy documentation on cipher_suites in common tls configuration. + items: + type: string + minItems: 1 + type: array + protocol: + description: Protocol defines the supported TLS protocol versions. + properties: + maximum: + description: Maximum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + minimum: + description: Minimum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + type: object + type: object + uri: + description: URI specifies the endpoint address. + format: uri + minLength: 1 + pattern: ^(http|https)://.*$ + type: string + required: + - uri + type: object + required: + - authorization + - token + type: object + required: + - endpoints + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/oidcrelyingparties.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/oidcrelyingparties.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..7398b262b0 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/oidcrelyingparties.microgateway.airlock.com.yaml @@ -0,0 +1,224 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: oidcrelyingparties.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: OIDCRelyingParty + listKind: OIDCRelyingPartyList + plural: oidcrelyingparties + singular: oidcrelyingparty + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + OIDCRelyingParty specifies how the Airlock Microgateway Engine interacts with an OpenID Provider (OP). + + + {{% notice warning %}} The OIDC feature is currently in an experimental state. + + + We encourage you to try it out and give feedback, but be aware that we do not recommend using it in a production environment yet, as security has not yet been hardened. + In particular, the current implementation has the following limitations, which we intend to address in future Microgateway releases: + - The state parameter is guessable. + - Sessions are always shared across all Microgateway Engines using the same Redis instance. + I.e. if application A and B (with different SidecarGateways) have the same Redis instance configured in their SessionHandling CR, users which are logged into application A + may be able to access authenticated routes on application B, even if their OIDCRelyingParty configuration differs. + + + {{% /notice %}} + {{% notice info %}} The OIDC feature requires SessionHandling to be configured in the SidecarGateway. {{% /notice %}} + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the OIDC Relying Party configuration. + properties: + clientID: + description: ClientID specifies the OIDCRelyingParty "client_id". + minLength: 1 + type: string + credentials: + description: Credentials used for client authentication on the back-channel with the authorization server. + properties: + clientSecret: + description: ClientSecret authenticates with the client password issued by the OpenID Provider (OP). + properties: + method: + default: BasicAuth + description: Method specifies in which format the client secret is sent with the authorization request. + enum: + - BasicAuth + - FormURLEncoded + type: string + secretRef: + description: SecretRef specifies the kubernetes secret containing the client password with key "client.secret". + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - clientSecret + type: object + oidcProviderRef: + description: OIDCProviderRef selects the OpenID Provider (OP) used to authenticate users. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + pathMapping: + description: PathMapping configures the action matching. + properties: + logoutPath: + description: LogoutPath specifies which request paths should initiate a logout. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + redirectPath: + description: RedirectPath specifies which request paths should be interpreted as a response from the authorization endpoint. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + required: + - logoutPath + - redirectPath + type: object + redirectURI: + description: |- + RedirectURI configures the "redirect_uri" parameter included in the authorization request. + May contain envoy command operators, e.g. '%REQ(:x-forwarded-proto)%://%REQ(:authority)%/callback'. + minLength: 1 + type: string + required: + - clientID + - credentials + - oidcProviderRef + - pathMapping + - redirectURI + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/openapis.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/openapis.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..b05f43ef21 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/openapis.microgateway.airlock.com.yaml @@ -0,0 +1,167 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: openapis.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: OpenAPI + listKind: OpenAPIList + plural: openapis + singular: openapi + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OpenAPI contains the configuration for the OpenAPI specification. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired OpenAPI specification. + properties: + response: + description: Response defines the validation behaviour for responses. + properties: + secured: + description: Secured enables response checking. + properties: + validation: + default: Lax + description: Validation defines the validation mode for responses. + enum: + - Lax + - Strict + type: string + type: object + unsecured: + description: Unsecured disables response checking. + type: object + type: object + settings: + description: Settings defines the settings to configure OpenAPI specification enforcement. + properties: + logging: + description: Logging specifies the access log behavior. + properties: + maxFailedSubvalidations: + default: 10 + description: MaxFailedSubvalidations defines the maximum number of failed subvalidations being logged. + format: int64 + type: integer + type: object + schema: + description: Schema configures the OpenAPI specification. + properties: + source: + description: Source specifies the OpenAPI specification to be enforced. + properties: + configMapRef: + description: ConfigMapRef references the configmap by its name containing the well-known key 'openapi.json'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + required: + - source + type: object + threatHandlingMode: + default: Block + description: ThreatHandlingMode specifies how threats should be handled. + enum: + - Block + - LogOnly + type: string + validation: + description: Validation specifies the patterns for the validation behavior. + properties: + authentication: + description: Authentication defines the settings for the authentication scheme. + properties: + oAuth2: + description: OAuth2 specifies the OAuth2 parameters. + properties: + allowedParameters: + description: AllowedParameters specifies the allowed parameters for the authentication scheme. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined allowed parameters. + properties: + standardParameters: + default: true + description: StandardParameters defines whether the allowed parameters should be expanded by the set of common parameters. + type: boolean + type: object + custom: + description: Custom allows configuring additional allowed parameters. + items: + minLength: 1 + type: string + minItems: 1 + type: array + type: object + type: object + oidc: + description: Oidc specifies the OIDC parameters. + properties: + allowedParameters: + description: AllowedParameters specifies the allowed parameters for the authentication scheme. + properties: + builtIn: + description: BuiltIn allows configuring a set of predefined allowed parameters. + properties: + standardParameters: + default: true + description: StandardParameters defines whether the allowed parameters should be expanded by the set of common parameters. + type: boolean + type: object + custom: + description: Custom allows configuring additional allowed parameters. + items: + minLength: 1 + type: string + minItems: 1 + type: array + type: object + type: object + type: object + type: object + required: + - schema + type: object + required: + - settings + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/parsers.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/parsers.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..15171f2b71 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/parsers.microgateway.airlock.com.yaml @@ -0,0 +1,358 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: parsers.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: Parser + listKind: ParserList + plural: parsers + singular: parser + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Parser contains the configuration for content parsers (default and custom). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired parser behavior. + properties: + request: + description: Request defines the parsing for downstream requests. + properties: + custom: + description: Custom allows configuring additional rules for parser selection. + properties: + rules: + description: |- + Rules defines a custom set prepended before built-in rules of enabled request parsers. + Disable all built-in parsers to overrule them completely. + items: + properties: + action: + description: |- + Action specifies what should happen when a request condition matches. + Only one of parse or skip can be set. + properties: + parse: + description: Parse activates the configured parser. + properties: + form: + description: Form activates the Form parser. + type: object + json: + description: JSON activates the JSON parser. + type: object + multipart: + description: Multipart activates the multipart parser. + type: object + type: object + skip: + description: Skip disables any content parsing + type: object + type: object + requestConditions: + description: RequestConditions defines additional request properties which must be matched in order for this rule to apply. + properties: + header: + description: Header defines the matching headers of a request. + properties: + name: + description: Name defines the name of a header. + properties: + matcher: + description: Matcher defines the way to match a string. In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + value: + description: Value defines the value of a header. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + type: object + invert: + default: false + description: Invert indicates whether the request condition should be inverted. + type: boolean + mediaType: + description: MediaType defines the matching media type from the content-type header of a request. + properties: + matcher: + description: |- + NonInvertableCaseInsensitiveStringMatcher defines the way to match a string. + In comparison to a normal StringMatcher, a value is always matched ignoring the case and can't be inverted. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + method: + description: Method defines the matching methods of a request. + items: + description: Method defines common HTTP methods. + enum: + - GET + - HEAD + - POST + - PUT + - PATCH + - DELETE + - CONNECT + - OPTIONS + - TRACE + type: string + type: array + path: + description: Path defines the matching path of a request. + properties: + matcher: + description: StringMatcher defines the way to match a string. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + required: + - matcher + type: object + remoteIP: + description: RemoteIP defines the matching remote IPs of a request. + properties: + cidrRanges: + description: CIDRRanges defines the IPv4 or IPv6 CIDR ranges, e.g. ``196.148.3.128/26`` or ``2001:db8::/28``. + items: + description: CIDRRange defines an IPv4 or IPv6 CIDR range, e.g. “196.148.3.128/26“ or “2001:db8::/28“. + format: cidr + type: string + minItems: 1 + type: array + invert: + default: false + description: Invert indicates whether the match should be inverted. + type: boolean + required: + - cidrRanges + type: object + type: object + required: + - action + - requestConditions + type: object + type: array + type: object + defaultContentType: + default: application/x-www-form-urlencoded + description: DefaultContentType specifies the content-type header which should be injected into the request before parser selection if it is not already present and the request has a body. + minLength: 1 + type: string + parsers: + description: Parsers defines the configuration for the available content parsers. + properties: + form: + description: Form defines the configuration for the form parser. + properties: + enable: + default: true + description: Enable defines whether form payloads are inspected. + type: boolean + mediaTypePattern: + default: .*urlencoded.* + description: MediaTypePattern is a regex specifying the media types for which the request body should be treated as form arguments. + minLength: 1 + type: string + type: object + json: + description: JSON defines the configuration for the JSON parser. + properties: + enable: + default: true + description: Enable defines whether json payloads are inspected. + type: boolean + mediaTypePattern: + default: .*json.* + description: MediaTypePattern is a regex specifying the media types for which the request body should be treated as JSON. + minLength: 1 + type: string + type: object + multipart: + description: Multipart defines the configuration for the multipart parser. + properties: + enable: + default: true + description: Enable defines whether multipart payloads are inspected. + type: boolean + mediaTypePattern: + default: .*multipart.* + description: MediaTypePattern is a regex specifying the media types for which the request body should be treated as a multipart payload. + minLength: 1 + type: string + type: object + type: object + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/redisproviders.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/redisproviders.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..9acdf4ddbe --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/redisproviders.microgateway.airlock.com.yaml @@ -0,0 +1,159 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: redisproviders.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: RedisProvider + listKind: RedisProviderList + plural: redisproviders + singular: redisprovider + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RedisProvider contains a client configuration for connecting to a Redis database. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of a Redis database client configuration. + properties: + auth: + description: Auth specifies the Redis credentials. + properties: + password: + description: Password specifies the Redis password. + properties: + secretRef: + description: SecretRef selects the secret containing the Redis password under the key 'redis.password'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + username: + default: default + description: Username specifies the Redis username to authenticate with. + minLength: 1 + pattern: ^[^\s]+$ + type: string + required: + - password + type: object + mode: + description: Mode configures the redis deployment mode. + properties: + standalone: + description: Standalone specifies the standalone Redis instance to connect to. + properties: + host: + description: Host specifies the IP or hostname. + minLength: 1 + pattern: ^(\d{1,3}(\.\d{1,3}){3}|([0-9a-fA-F]{1,4}|:)+(:\d{1,3}(\.\d{1,3}){3})?|[a-z0-9\-]+(\.[a-z0-9\-]+)*)$ + type: string + port: + default: 6379 + description: Port specifies the port. + maximum: 65535 + minimum: 1 + type: integer + required: + - host + type: object + type: object + timeouts: + description: Timeouts specifies the timeouts when interacting with the Redis endpoint. + properties: + connect: + default: 5s + description: Connect specifies the timeout for establishing a connection. + type: string + maxDuration: + default: 2s + description: MaxDuration specifies the response timeout. + type: string + type: object + tls: + description: TLS defines TLS settings. If not specified, TLS is disabled i.e. unencrypted TCP is used when connecting to the Redis instance. + properties: + certificateVerification: + description: CertificateVerification specifies how the certificate presented by the server is verified. + properties: + custom: + description: Custom explicitly specifies how the server certificate should be verified. + properties: + trustedCA: + description: TrustedCA defines which CA certificates are trusted. + properties: + certificates: + description: Certificates defines the list of secretRefs containing trusted CA certificates. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CA certificates under the key 'ca.crt'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + required: + - certificates + type: object + required: + - trustedCA + type: object + disabled: + description: 'Disabled specifies to trust any certificate without verification. THIS IS INSECURE AND SHOULD ONLY BE USED FOR TESTING. Note: This setting currently also disables TLS SNI.' + type: object + publicCAs: + description: PublicCAs specifies to only accept certificates with a SAN matching the host and which are signed by a CA which is either directly or indirectly trusted by any of the root CA certificates shipped with the Airlock Microgateway Session Agent’s base image. + type: object + type: object + type: object + required: + - mode + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/sessionhandlings.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/sessionhandlings.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..bb4c0f9c1d --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/sessionhandlings.microgateway.airlock.com.yaml @@ -0,0 +1,77 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: sessionhandlings.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: SessionHandling + listKind: SessionHandlingList + plural: sessionhandlings + singular: sessionhandling + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + SessionHandling contains the configuration for session handling. + + + {{% notice warning %}} The Session Handling feature (required for OIDC) is currently in an experimental state. + + + We encourage you to try it out and give feedback, but be aware that we do not recommend using it in a production environment yet, as high-availability Redis configurations (e.g. Sentinel/Cluster) are not yet supported. + {{% /notice %}} + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired session handling behavior. + properties: + persistence: + description: Persistence configures where to store the session state. + properties: + redisProviderRef: + description: RedisProviderRef specifies to cache session information in the provided Redis instance. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - redisProviderRef + type: object + required: + - persistence + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/crds/sidecargateways.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/sidecargateways.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..6847f73930 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/sidecargateways.microgateway.airlock.com.yaml @@ -0,0 +1,758 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: sidecargateways.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: SidecarGateway + listKind: SidecarGatewayList + plural: sidecargateways + singular: sidecargateway + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: SidecarGateway contains the configuration how to configure the Airlock Microgateway Engine when used as Sidecar Container within the Pod of an application. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired sidecar gateway behavior. + properties: + applications: + description: Applications defines applications which run on different ports. + items: + properties: + containerPort: + default: 8080 + description: |- + ContainerPort refers to the container port. + This must be a valid port number, 0 < x < 65536. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + downstream: + description: Downstream defines the downstream configuration for this application + properties: + protocol: + description: |- + Protocol defines the exposed HTTP protocol version. At most one of http1, http2 and auto can be set. + Default: auto: {} + properties: + auto: + description: Auto specifies that the protocol should be inferred. + properties: + http2: + description: HTTP2 specifies the settings for when HTTP/2 is inferred. + properties: + allowConnect: + default: false + description: Allows proxying Websocket and other upgrades over H2 connect. + type: boolean + type: object + type: object + http1: + description: HTTP1 specifies that the client is assumed to speak HTTP/1.1. + type: object + http2: + description: HTTP2 specifies that the client is assumed to speak HTTP/2. + properties: + allowConnect: + default: false + description: Allows proxying Websocket and other upgrades over H2 connect. + type: boolean + type: object + type: object + remoteIP: + description: |- + RemoteIP defines how the remote IP of a client is propagated. + Default: xff: {...} + properties: + connectionIP: + description: ConnectionIP configures to use the source IP address of the direct downstream connection. + type: object + customHeader: + description: CustomHeader specifies to use a custom header for remote IP extraction. + properties: + headerName: + description: HeaderName specifies the name of the custom header containing the remote IP. + minLength: 1 + type: string + required: + default: true + description: Required specifies if the custom header is required. If true and not available the request will be rejected with 403. + type: boolean + required: + - headerName + type: object + xff: + description: XFF configures to use the standard 'X-Forwarded-For' header for IP extraction. + properties: + numTrustedHops: + default: 1 + description: NumTrustedHops specifies to extract the client's originating IP from the nth rightmost entry in the X-Forwarded-For header. With the default value of 1, the IP is extracted from the rightmost entry. + format: int32 + minimum: 1 + type: integer + type: object + type: object + requestNormalizations: + description: RequestNormalizations defines a set of normalization actions which are applied to the request before route matching. + properties: + mergeSlashes: + default: true + description: MergeSlashes ensures that adjacent slashes in the path are merged into one. + type: boolean + normalizePath: + default: true + description: NormalizePath ensures normalization according to RFC 3986 without case normalization. + type: boolean + type: object + restrictions: + description: Restrictions defines restrictions for downstream. + properties: + http: + description: HTTP defines limits for the HTTP protocol. + properties: + headersLength: + anyOf: + - type: integer + - type: string + default: 60Ki + description: HeadersLength defines maximum size of all request headers combined. Requests that exceed this limit will receive a 431 response. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + timeouts: + description: Timeouts defines timeouts for downstream + properties: + http: + description: HTTP defines the settings for HTTP timeouts. + properties: + idle: + default: 5m + description: |- + Idle defines the settings for the idle timeout when no data is sent or received. + A value of 0 will completely disable the timeout. + Default: 5m + type: string + maxDuration: + default: 5m + description: |- + MaxDuration defines the total duration for a HTTP request/response stream. + A value of 0 will completely disable the timeout. + Default: 5m + type: string + requestHeaders: + default: 10s + description: |- + RequestHeaders defines the duration before all request headers must be received. + A value of 0 will completely disable the timeout. + Default: 10s + type: string + type: object + type: object + tls: + description: TLS defines the TLS settings. + properties: + ciphers: + description: Ciphers defines a list of the supported TLS cipher suites. For details on cipher list refer to the envoy documentation on cipher_suites in common tls configuration. + items: + type: string + minItems: 1 + type: array + clientCertificate: + description: |- + ClientCertificate defines the TLS settings for verification of client certificates. + At most one of ignored, optional and required can be set. + Default: ignored: {} + properties: + ignored: + description: Ignored disables verification of the client certificate. + type: object + optional: + description: |- + Optional enables verification of the client certificate if one is presented. + In this mode only trustedCA and crl settings can be configured since certificatePinning and allowedSANs require a client certificate. + properties: + crl: + description: CRL defines the Certificate Revocation List (CRL) settings. + properties: + lists: + description: Lists defines the list of secretRefs containing Certificate Revocation Lists. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CRL's (in PEM format) under the key 'ca.crl'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + validationMode: + default: VerifyChain + description: ValidationMode defines whether only the leaf certificate or also the CA certs should be checked. + enum: + - VerifyLeafCertOnly + - VerifyChain + type: string + type: object + trustedCA: + description: TrustedCA defines which CA certificates are trusted. + properties: + certificates: + description: Certificates defines the list of secretRefs containing trusted CA certificates. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CA certificates under the key 'ca.crt'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + verificationDepth: + default: 1 + description: |- + VerificationDepth specifies the hops in the certificate chain at which validation is performed. + 1 means that either the leaf or the signing CA must be in the set of trusted certificates. + format: int32 + type: integer + required: + - certificates + type: object + required: + - trustedCA + type: object + required: + description: |- + Required contains settings for client certificate verification. A client must present a valid certificate. + At least one of trustedCA and certificatePinning must be set. + properties: + allowedSANs: + description: |- + AllowedSANs is a list of matchers to verify the Subject Alternative name. If specified, it will verify that the + Subject Alternative Name of the presented certificate matches one of the specified matchers. The matching uses “any” semantics, + that is to say, the SAN is verified if at least one matcher is matched. + AllowedSANs requires trustedCA to be set. + items: + description: |- + TLSValidationContextSANMatcher is a list of matchers to verify the Subject Alternative name. If specified, it will verify that the + Subject Alternative Name of the presented certificate matches one of the specified matchers. + properties: + matcher: + description: Matcher defines the string matcher for the SAN value. + properties: + contains: + description: |- + Contains defines a substring match on the substring specified here. Empty contains match is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + exact: + description: |- + Exact defines an explicit match on the string specified here. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + ignoreCase: + default: false + description: IgnoreCase indicates whether the matching should be case-insensitive. In case of a regex match, the regex gets wrapped with a group `(?i:...)`. + type: boolean + prefix: + description: |- + Prefix defines a prefix match on the prefix specified here. Empty prefix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + regex: + description: |- + Regex defines a regex match on the regular expression specified here. Google's [RE2 regex engine](https://github.com/google/re2/wiki/Syntax) is used. + The regex matches only single-line by default, even with ".*". To match a multi-line string prepend (?s) to your regex. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + suffix: + description: |- + Suffix defines a suffix match on the suffix specified here. Empty suffix is not allowed, please use regex instead. + Only one of exact, prefix, suffix, regex or contains can be set. + minLength: 1 + type: string + type: object + sanType: + description: SanType defines the type of SAN matcher. + enum: + - DNS + - Email + - URI + - IPAddress + type: string + required: + - matcher + - sanType + type: object + minItems: 1 + type: array + certificatePinning: + description: |- + CertificatePinning defines the constraints a client certificate must fulfill. + If more than one constraint is configured only one must be satisfied. + At least one of allowedSPKIs and allowedHashes must be set. + properties: + allowedHashes: + description: |- + AllowedHashes is a list of hex-encoded SHA-256 hashes. + If specified, it will verify that the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + items: + type: string + minItems: 1 + type: array + allowedSPKIs: + description: |- + AllowedSPKIs is a list of base64-encoded SHA-256 hashes. + If specified, it will verify that the SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate matches one of the specified values. + items: + type: string + minItems: 1 + type: array + type: object + crl: + description: CRL defines the Certificate Revocation List (CRL) settings. + properties: + lists: + description: Lists defines the list of secretRefs containing Certificate Revocation Lists. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CRL's (in PEM format) under the key 'ca.crl'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + validationMode: + default: VerifyChain + description: ValidationMode defines whether only the leaf certificate or also the CA certs should be checked. + enum: + - VerifyLeafCertOnly + - VerifyChain + type: string + type: object + trustedCA: + description: TrustedCA defines which CA certificates are trusted. + properties: + certificates: + description: Certificates defines the list of secretRefs containing trusted CA certificates. + items: + properties: + secretRef: + description: SecretRef defines the reference to a secret containing one or more CA certificates under the key 'ca.crt'. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + minItems: 1 + type: array + verificationDepth: + default: 1 + description: |- + VerificationDepth specifies the hops in the certificate chain at which validation is performed. + 1 means that either the leaf or the signing CA must be in the set of trusted certificates. + format: int32 + type: integer + required: + - certificates + type: object + type: object + type: object + enable: + default: false + description: Enable defines if the downstream connection is encrypted. + type: boolean + protocol: + description: Protocol defines the supported TLS protocol versions. + properties: + maximum: + description: Maximum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + minimum: + description: Minimum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + type: object + secretRef: + description: SecretRef defines the reference to the TLS server certificate (secret of type kubernetes.io/tls). + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + xfcc: + description: |- + XFCC defines the handling of X-Forwarded-Client-Cert header. Meaning of the possible values: + _Sanitize_: Do not send the XFCC header to the next hop. This is the default value. + _ForwardOnly_: When the client connection is mTLS (Mutual TLS), forward the XFCC header in the request. + _AppendAndForward_: When the client connection is mTLS, append the client certificate information to the request’s XFCC header and forward it. + _SanitizeAndSet_: When the client connection is mTLS, reset the XFCC header with the client certificate information and send it to the next hop. + _AlwaysForwardOnly_: Always forward the XFCC header in the request, regardless of whether the client connection is mTLS. + Note: When forwarding the XFCC header in the request you might have to adjust the header length restrictions (See sidecargateway.spec.applications.downstream.restrictions.http) + enum: + - Sanitize + - ForwardOnly + - AppendAndForward + - SanitizeAndSet + - AlwaysForwardOnly + type: string + type: object + type: object + envoyHTTPFilterRefs: + description: EnvoyHTTPFilterRefs selects the relevant EnvoyHTTPFilters. + properties: + prepend: + description: Prepend selects the relevant EnvoyHTTPFilters which are added before those configured by the Airlock Microgateway. + items: + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: array + type: object + routes: + description: Routes defines the security configurations for different paths. The first matching route (from top to bottom) applies. + items: + description: |- + SidecarGatewayApplicationRoute defines the security configurations for different paths. + At most one of secured and unsecured can be set. + Default: secured: {...} + properties: + pathPrefix: + default: / + description: PathPrefix defines the path prefix used during route selection. + minLength: 1 + type: string + secured: + description: Secured enables WAF processing for this route. + properties: + accessControlRef: + description: |- + AccessControlRef selects the relevant AccessControl configuration resource. + If undefined, Airlock Microgateway does not perform any access control. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + contentSecurityRef: + description: |- + ContentSecurityRef selects the relevant ContentSecurity configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: object + unsecured: + description: |- + Unsecured disables all WAF functionality and therefore protection for this route. + WARNING: Using this setting when the application is exposed to untrusted downstream traffic is highly discouraged. + type: object + type: object + type: array + x-kubernetes-list-map-keys: + - pathPrefix + x-kubernetes-list-type: map + telemetryRef: + description: |- + TelemetryRef selects the relevant Telemetry configuration resource. + If undefined, default settings are applied, designed to work with most upstream web application services. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + upstream: + description: Upstream defines the upstream configuration for this application + properties: + protocol: + description: |- + Protocol defines HTTP protocol version used to communicate with the upstream. At most one of http1, http2 and auto can be set. + Default: auto: {} + properties: + auto: + description: Auto specifies to negotiate the protocol with TLS ALPN (if TLS is enabled) or, as a fallback, use the same protocol that is used by the downstream connection. + properties: + http2: + description: HTTP2 specifies the settings for when HTTP/2 is inferred. + properties: + allowConnect: + default: false + description: Allows proxying Websocket and other upgrades over H2 connect. + type: boolean + type: object + type: object + http1: + description: HTTP1 specifies to use HTTP/1.1. + type: object + http2: + description: HTTP2 specifies to use HTTP/2. + properties: + allowConnect: + default: false + description: Allows proxying Websocket and other upgrades over H2 connect. + type: boolean + type: object + type: object + timeouts: + description: Timeouts defines the timeout settings. + properties: + http: + description: HTTP defines the settings for HTTP timeouts. + properties: + idle: + description: |- + Timeout defines the settings for http timeouts. If this setting is not specified, the value of applications[].downstream.timeouts.http.idle is inherited. + A value of 0 will completely disable the timeout. + type: string + maxDuration: + default: 15s + description: |- + MaxDuration defines the total duration for a HTTP request/response stream. + Default: 15s + type: string + type: object + type: object + tls: + description: TLS defines the TLS settings. + properties: + ciphers: + description: Ciphers defines a list of the supported TLS cipher suites. For details on cipher list refer to the envoy documentation on cipher_suites in common tls configuration. + items: + type: string + minItems: 1 + type: array + enable: + default: false + description: Enable defines if the upstream connection is encrypted. + type: boolean + protocol: + description: Protocol defines the supported TLS protocol versions. + properties: + maximum: + description: Maximum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + minimum: + description: Minimum supported TLS version. + enum: + - TLSv1_0 + - TLSv1_1 + - TLSv1_2 + - TLSv1_3 + type: string + type: object + type: object + type: object + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - containerPort + x-kubernetes-list-type: map + envoyClusterRefs: + description: EnvoyClusterRefs selects the relevant EnvoyClusters. + items: + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + podSelector: + description: PodSelector defines to which Pods the configuration will be applied to. + properties: + matchLabels: + additionalProperties: + type: string + description: MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels. + type: object + type: object + sessionHandlingRef: + description: SessionHandlingRef selects the SessionHandling configuration to apply. + properties: + name: + description: Name of the resource + minLength: 1 + type: string + required: + - name + type: object + required: + - applications + type: object + status: + description: Most recently observed status of the SidecarGateway which is populated by the system. This data is read-only and may not be up to date. + properties: + conditions: + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: A human-readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of SidecarGateway condition. + type: string + required: + - status + - type + type: object + type: array + pods: + items: + properties: + envoyConfig: + description: EnvoyConfig indicates the name of the EnvoyConfig CR for the Pod. + type: string + name: + description: Name indicates the name of a Pod selected by the SidecarGateway. + type: string + sessionAgentSecret: + type: string + required: + - name + type: object + type: array + status: + type: string + unmanagedPods: + items: + properties: + managedBy: + description: ManagedBy indicates the Airlock Microgateway Operator instance which manages this Pod. + type: string + name: + description: Name indicates the name of a Pod selected by the SidecarGateway. + type: string + sessionAgentSecret: + type: string + required: + - name + type: object + type: array + required: + - status + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/airlock/microgateway/4.3.4/crds/telemetries.microgateway.airlock.com.yaml b/charts/airlock/microgateway/4.3.4/crds/telemetries.microgateway.airlock.com.yaml new file mode 100644 index 0000000000..d1a8897a74 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/crds/telemetries.microgateway.airlock.com.yaml @@ -0,0 +1,96 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + app.kubernetes.io/name: airlock-microgateway-operator + app.kubernetes.io/version: 4.3.4 + name: telemetries.microgateway.airlock.com +spec: + group: microgateway.airlock.com + names: + categories: + - airlock-microgateway + kind: Telemetry + listKind: TelemetryList + plural: telemetries + singular: telemetry + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Telemetry contains the configuration for telemetry (logging, metrics & tracing). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired telemetry behavior. + properties: + correlation: + description: Correlation defines the correlation aspects of Telemetry. + properties: + idSource: + description: IDSource specifies how an external correlation ID should be obtained for a request. If not specified, no correlation ID will be logged. + properties: + header: + description: Header specifies to extract the correlation ID from a request header. If the header is absent from a request, no correlation ID will be logged. + properties: + name: + default: X-Correlation-Id + description: Name of the header (case-insensitive) from which to extract the correlation ID. + minLength: 1 + type: string + type: object + required: + - header + type: object + request: + description: Request defines the request related correlation settings of Telemetry. + properties: + allowDownstreamRequestID: + default: true + description: AllowDownstreamRequestID defines whether trace sampling will consider a provided x-request-id. + type: boolean + alterRequestID: + default: true + description: AlterRequestID defines whether to alter the UUID to reflect the trace sampling decision. If disabled no modification to the UUID will be performed, this may break tracing in the upstream. + type: boolean + type: object + type: object + logging: + description: Logging defines the logging aspects of Telemetry. + properties: + accessLog: + description: AccessLog defines the access log settings of Telemetry. + properties: + format: + description: Format defines the Access Log format of the sidecar. + properties: + json: + description: JSON defines the Access Log format as JSON. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/airlock/microgateway/4.3.4/dashboards/blockLogs.json b/charts/airlock/microgateway/4.3.4/dashboards/blockLogs.json new file mode 100644 index 0000000000..ef0ce6d624 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/dashboards/blockLogs.json @@ -0,0 +1,510 @@ +{ + "__inputs": [ + { + "name": "DS_LOKI", + "label": "Loki", + "description": "", + "type": "datasource", + "pluginId": "loki", + "pluginName": "Loki" + }, + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.2.0" + }, + { + "type": "datasource", + "id": "loki", + "name": "Loki", + "version": "1.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Blocked requests by Airlock Microgateway retrieved from corresponding access logs.\n\nThe dashboard can be filtered by namespace and block type. Column filters on the table allow for even a more granular filtering of the logs.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "airlock-microgateway" + ], + "targetBlank": true, + "title": "Airlock Microgateway", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": true + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Namespace" + }, + "properties": [ + { + "id": "custom.width", + "value": 221 + }, + { + "id": "custom.filterable" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Timestamp" + }, + "properties": [ + { + "id": "custom.width", + "value": 214 + }, + { + "id": "unit", + "value": "dateTimeAsIso" + }, + { + "id": "custom.filterable" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Method" + }, + "properties": [ + { + "id": "custom.width", + "value": 89 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Client IP" + }, + "properties": [ + { + "id": "custom.width", + "value": 138 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 328 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Block Type" + }, + "properties": [ + { + "id": "custom.width", + "value": 116 + }, + { + "id": "custom.filterable", + "value": false + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request Size" + }, + "properties": [ + { + "id": "custom.width", + "value": 126 + }, + { + "id": "unit", + "value": "bytes" + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Attack Type" + }, + "properties": [ + { + "id": "custom.width", + "value": 217 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Application" + }, + "properties": [ + { + "id": "custom.width", + "value": 207 + } + ] + } + ] + }, + "gridPos": { + "h": 27, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "editorMode": "code", + "expr": "{container=\"airlock-microgateway-engine\", namespace=~\"${namespace:regex}\"} |= \"airlock_request_blocked_deny_rule\" |= \"envoy.access\"\n| json http_method=\"http.request.method\", url=\"url.path\", request_size=\"http.request.bytes\", client_ip=\"network.forwarded_ip\", request_id=\"http.request.id\", details=\"airlock.deny_rules.matches\"\n| label_format block_type=\"deny_rules\", attack_type=`{{ range $q := fromJson .details }} {{ if eq $q.threat_handling_mode \"block\" }} {{ $q.rule_key }} {{ end }} {{ end }}` | block_type=~\"${blockType:regex}\"", + "hide": false, + "queryType": "range", + "refId": "Deny Rule Blocks" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "editorMode": "code", + "expr": "{container=\"airlock-microgateway-engine\", namespace=~\"${namespace:regex}\"} |= \"airlock_request_blocked_limit\" |= \"envoy.access\"\n| json http_method=\"http.request.method\", url=\"url.path\", request_size=\"http.request.bytes\", client_ip=\"network.forwarded_ip\", request_id=\"http.request.id\", details=\"airlock.limits.matches\"\n| label_format block_type=\"limits\", attack_type=`{{ range $q := fromJson .details }} {{ if eq $q.threat_handling_mode \"block\" }} {{ $q.rule }} {{ end }} {{ end }}` | block_type=~\"${blockType:regex}\"", + "hide": false, + "queryType": "range", + "refId": "Limit Blocks" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "editorMode": "code", + "expr": "{container=\"airlock-microgateway-engine\", namespace=~\"${namespace:regex}\"} |= \"airlock_request_blocked_openapi\" |= \"envoy.access\"\n| json http_method=\"http.request.method\", url=\"url.path\", request_size=\"http.request.bytes\", client_ip=\"network.forwarded_ip\", request_id=\"http.request.id\", reference=\"airlock.openapi.reference\", constraint=\"airlock.openapi.request.failed_validation.constraint\", position=\"airlock.openapi.request.failed_validation.position\", message=\"airlock.openapi.request.failed_validation.message\"\n| label_format block_type=\"openapi\", attack_type=\"openapi\", details=`{{.reference }}: {{.constraint }} at {{ .position }} ({{ .message }})` | block_type=~\"${blockType:regex}\"", + "hide": false, + "queryType": "range", + "refId": "OpenAPI Blocks" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "editorMode": "code", + "expr": "{container=\"airlock-microgateway-engine\", namespace=~\"${namespace:regex}\"} |= \"airlock_request_blocked_parser\" |= \"envoy.access\"\n| json http_method=\"http.request.method\", url=\"url.path\", request_size=\"http.request.bytes\", client_ip=\"network.forwarded_ip\", request_id=\"http.request.id\", attack_type=\"airlock.parser\", failed_check=\"airlock.parser.matches[0].failed_check\", message=\"airlock.parser.matches[0].message\"\n| label_format block_type=\"parsing\", attack_type=\"parsing\", details=`{{.failed_check}}: {{.message}}` | block_type=~\"${blockType:regex}\"", + "hide": false, + "queryType": "range", + "refId": "Parser Blocks" + }, + { + "datasource": { + "type": "loki", + "uid": "${DS_LOKI}" + }, + "editorMode": "code", + "expr": "{container=\"airlock-microgateway-engine\", namespace=~\"${namespace:regex}\"} |= \"airlock_request_blocked_graphql\" |= \"envoy.access\"\n| json http_method=\"http.request.method\", url=\"url.path\", request_size=\"http.request.bytes\", client_ip=\"network.forwarded_ip\", request_id=\"http.request.id\", reference=\"airlock.graphql.reference\", message=\"airlock.graphql.request.failed_validation.message\"\n| label_format block_type=\"graphql\", attack_type=\"graphql\", details=`{{ .reference }}: {{ .message }}` | block_type=~\"${blockType:regex}\"", + "hide": false, + "queryType": "range", + "refId": "GraphQL Blocks" + } + ], + "title": "Blocked Request logs", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "extractFields", + "options": { + "format": "json", + "source": "labels" + } + }, + { + "id": "filterFieldsByName", + "options": { + "byVariable": false, + "include": { + "names": [ + "Time", + "attack_type", + "block_type", + "client_ip", + "details", + "http_method", + "namespace", + "request_id", + "request_size", + "url", + "pod" + ] + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Line": true, + "id": true, + "labelTypes": true, + "labels": true, + "tsNs": false + }, + "includeByName": {}, + "indexByName": { + "Time": 0, + "attack_type": 7, + "block_type": 6, + "client_ip": 9, + "details": 8, + "http_method": 3, + "namespace": 1, + "pod": 2, + "request_id": 10, + "request_size": 5, + "url": 4 + }, + "renameByName": { + "Time": "Timestamp", + "attack_type": "Attack Type", + "block_type": "Block Type", + "client_ip": "Client IP", + "details": "Details", + "http_method": "Method", + "namespace": "Namespace", + "pod": "Pod", + "request_id": "Request ID", + "request_size": "Request Size", + "tsNs": "", + "url": "Path" + } + } + } + ], + "type": "table" + } + ], + "schemaVersion": 39, + "tags": [ + "airlock-microgateway" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Loki", + "value": "P8E80F9AEF21F6940" + }, + "hide": 2, + "includeAll": false, + "label": "DS_LOKI", + "multi": false, + "name": "DS_LOKI", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_http_rq_total,namespace)", + "hide": 0, + "includeAll": true, + "label": "Application Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_http_rq_total,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_http_downstream_rq_threats_blocked_total,block_type)", + "hide": 0, + "includeAll": true, + "label": "Block Type", + "multi": true, + "name": "blockType", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_http_downstream_rq_threats_blocked_total,block_type)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "PBFA97CFB590B2093" + }, + "hide": 2, + "includeAll": false, + "label": "DS_PROMETHEUS", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "Airlock Microgateway Blocked Request Logs", + "uid": "adnyzcvwnyadcc", + "version": 3, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/dashboards/blockMetrics.json b/charts/airlock/microgateway/4.3.4/dashboards/blockMetrics.json new file mode 100644 index 0000000000..ba383d22e8 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/dashboards/blockMetrics.json @@ -0,0 +1,758 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "barchart", + "name": "Bar chart", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.2.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Metrics on requests blocked by Airlock Microgateway.\n\nDashboard can be filtered by namespaces as well as block types.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "airlock-microgateway" + ], + "targetBlank": true, + "title": "Airlock Microgateway", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 6, + "title": "Airlock Microgateway Block Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of requests processed by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum(increase(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])))", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "Processed Requests", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Ratio of blocked requests vs. processed requests by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "nan", + "result": { + "index": 0, + "text": "n/a" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(microgateway_http_downstream_rq_threats_blocked_total{block_type=~\"${blockType:regex}\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])) / sum(increase(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range]))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "Blocked Requests (%)", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "% Blocked Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Requests per second processed by Airlock Microgateway along with the corresponding block rate.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "left", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "% Blocks" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + }, + { + "id": "max", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Requests per second" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "custom.fillOpacity", + "value": 25 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 20, + "x": 0, + "y": 5 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timezone": [ + "" + ], + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m]))", + "instant": false, + "legendFormat": "Requests per second", + "range": true, + "refId": "Requests per Second" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(microgateway_http_downstream_rq_threats_blocked_total{block_type=~\"${blockType:regex}\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) / sum(rate(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m]))", + "hide": false, + "instant": false, + "legendFormat": "% Blocks", + "range": true, + "refId": "Blocks" + } + ], + "title": "Requests vs. % Blocks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Blocked requests by block type.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-orange", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 10, + "x": 0, + "y": 15 + }, + "id": 4, + "options": { + "barRadius": 0, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "never", + "stacking": "none", + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "asc" + }, + "xField": "block_type", + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum by (block_type) (increase(microgateway_http_downstream_rq_threats_blocked_total{block_type=~\"${blockType:regex}\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])))", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Block Type", + "transformations": [ + { + "id": "reduce", + "options": { + "includeTimeField": false, + "labelsToFields": true, + "mode": "seriesToRows", + "reducers": [ + "sum" + ] + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Blocked requests by attack type, which are subsets of the various block types.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-orange", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 10, + "x": 10, + "y": 15 + }, + "id": 5, + "options": { + "barRadius": 0, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "never", + "stacking": "none", + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + }, + "xField": "attack_type", + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum by (attack_type) (increase(microgateway_http_downstream_rq_threats_blocked_total{block_type=~\"${blockType:regex}\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])))", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Attack Type", + "transformations": [ + { + "id": "reduce", + "options": { + "labelsToFields": true, + "reducers": [ + "sum" + ] + } + } + ], + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "airlock-microgateway" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "PBFA97CFB590B2093" + }, + "hide": 2, + "includeAll": false, + "label": "Datasource Prometheus", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "Loki", + "value": "P8E80F9AEF21F6940" + }, + "hide": 2, + "includeAll": false, + "label": "DS_LOKI", + "multi": false, + "name": "DS_LOKI", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_valid,namespace)", + "hide": 0, + "includeAll": true, + "label": "Operator Namespace", + "multi": true, + "name": "operator_namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_valid,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": ".*", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_http_rq_total,namespace)", + "hide": 0, + "includeAll": true, + "label": "Application Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_http_rq_total,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_http_downstream_rq_threats_blocked_total,block_type)", + "hide": 0, + "includeAll": true, + "label": "Block Type", + "multi": true, + "name": "blockType", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_http_downstream_rq_threats_blocked_total,block_type)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": { + "hidden": false + }, + "timezone": "browser", + "title": "Airlock Microgateway Block Metrics", + "uid": "ddnqoczu7qvb4cdd3dd", + "version": 3, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/dashboards/license.json b/charts/airlock/microgateway/4.3.4/dashboards/license.json new file mode 100644 index 0000000000..b9d5777e23 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/dashboards/license.json @@ -0,0 +1,521 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.2.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "airlock-microgateway" + ], + "targetBlank": true, + "title": "Airlock Microgateway", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "License status of Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 1, + "text": "Invalid" + }, + "1": { + "color": "green", + "index": 0, + "text": "Valid" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "min(microgateway_license_valid{namespace=~\"${operator_namespace.regex}\"})", + "instant": true, + "legendFormat": "License Status", + "range": false, + "refId": "Licenses" + } + ], + "title": "License Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Expiry date of the Airlock Microgateway license associated with the selected operator.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "time: L" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 3, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "min(microgateway_license_expiry_timestamp_seconds{namespace=~\"${operator_namespace.regex}\"})*1000", + "instant": true, + "legendFormat": "Expiry Date (MM/DD/YYYY)", + "range": false, + "refId": "A" + } + ], + "title": "License Expiry Date", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of licensed requests for applications protected by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 7, + "y": 0 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(microgateway_license_max_rq_count_per_month{namespace=~\"${operator_namespace.regex}\"})", + "instant": true, + "legendFormat": "Licensed Requests", + "range": false, + "refId": "A" + } + ], + "title": "Licensed Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Estimated number of requests protected by Airlock Microgateway over 30 days based on the last 7 days.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 11, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(microgateway_license_http_rq_total{job=~\"${operator_namespace.regex}/.*-engine\"}[7d]))/7*30", + "instant": true, + "legendFormat": "Estimated Requests", + "range": false, + "refId": "A" + } + ], + "title": "Requests over 30 days (estimated)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of requests per week processed by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 16, + "x": 0, + "y": 4 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(avg_over_time(increase(microgateway_license_http_rq_total{job=~\"${operator_namespace.regex}/.*-engine\"}[7d])[2m:30s]))", + "instant": false, + "legendFormat": "# Requests per week", + "range": true, + "refId": "A" + } + ], + "title": "Processed Requests per week", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "tags": [ + "airlock-microgateway" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "PBFA97CFB590B2093" + }, + "hide": 2, + "includeAll": false, + "label": "DS_PROMETHEUS", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_valid,namespace)", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Operator Namespace", + "multi": false, + "name": "operator_namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_valid,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "Airlock Microgateway License", + "uid": "cdpq79bzrr01se", + "version": 2, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/dashboards/overview.json b/charts/airlock/microgateway/4.3.4/dashboards/overview.json new file mode 100644 index 0000000000..0942766217 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/dashboards/overview.json @@ -0,0 +1,1138 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.2.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "airlock-microgateway" + ], + "targetBlank": true, + "title": "Airlock Microgateway", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 3, + "title": "Overview", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of pods that are protected by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(microgateway_sidecars{namespace=~\"${operator_namespace.regex}\"})", + "instant": true, + "legendFormat": "Protected Pods", + "range": false, + "refId": "A" + } + ], + "title": "Protected Pods", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of requests processed by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum(increase(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])))", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "Processed Requests", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Ratio of blocked requests vs. processed requests by Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "nan", + "result": { + "index": 0, + "text": "n/a" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(microgateway_http_downstream_rq_threats_blocked_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range])) / sum(increase(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[$__range]))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "Blocked Requests (%)", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "% Blocked Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "License status of Airlock Microgateway.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 1, + "text": "Invalid" + }, + "1": { + "color": "green", + "index": 0, + "text": "Valid" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 1 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "min(microgateway_license_valid{namespace=~\"${operator_namespace.regex}\"})", + "instant": true, + "legendFormat": "License Status", + "range": false, + "refId": "Licenses" + } + ], + "title": "License", + "type": "stat" + }, + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 2, + "title": "Blocks", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Requests per second processed by Airlock Microgateway along with the corresponding block rate.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "left", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "% Blocks" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + }, + { + "id": "max", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Requests per second" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "custom.fillOpacity", + "value": 25 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timezone": [ + "" + ], + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m]))", + "instant": false, + "legendFormat": "Requests per second", + "range": true, + "refId": "Requests per Second" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(microgateway_http_downstream_rq_threats_blocked_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) / sum(rate(microgateway_license_http_rq_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m]))", + "hide": false, + "instant": false, + "legendFormat": "% Blocks", + "range": true, + "refId": "Blocks" + } + ], + "title": "Requests vs. % Blocks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Requests blocked by Airlock Microgateway categorized by their corresponding type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "barAlignment": 0, + "drawStyle": "line", + "gradientMode": "none", + "hideValue": false, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 10, + 10 + ], + "fill": "solid" + }, + "showPoints": "never", + "spanNulls": false, + "type": "sparkline" + }, + "inspect": false + }, + "displayName": "Block Type", + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "block_type" + }, + "properties": [ + { + "id": "custom.width", + "value": 153 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "auto" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trend #Block Types" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 7, + "options": { + "cellHeight": "lg", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": [ + "Value" + ], + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": false, + "sortBy": [ + { + "desc": true, + "displayName": "block_type" + } + ] + }, + "pluginVersion": "11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (block_type) (increase(microgateway_http_downstream_rq_threats_blocked_total{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m] offset -1m))/(60000/$__interval_ms)", + "format": "time_series", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Block Types" + } + ], + "title": "Blocked Requests by Type", + "transformations": [ + { + "id": "timeSeriesTable", + "options": { + "A": { + "timeField": "Time" + }, + "Block Types": { + "stat": "sum", + "timeField": "Time" + } + } + } + ], + "type": "table" + }, + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 1, + "title": "Latency", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Percentiles of the application downstream latency over one minute.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "25th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "50th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "95th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.25, sum(rate(envoy_http_downstream_rq_time_bucket{envoy_http_conn_manager_prefix=\"http\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "instant": false, + "legendFormat": "25th Percentile", + "range": true, + "refId": "25th Percentile" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum(rate(envoy_http_downstream_rq_time_bucket{envoy_http_conn_manager_prefix=\"http\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "50th Percentile", + "range": true, + "refId": "50th Percentile" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(envoy_http_downstream_rq_time_bucket{envoy_http_conn_manager_prefix=\"http\", namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "95th Percentile", + "range": true, + "refId": "95th Percentile" + } + ], + "title": "Application Downstream Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Percentiles of the Airlock Microgateway processing time over one minute.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "25th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "50th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "95th Percentile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.25, sum(rate(microgateway_rq_processing_time_ms_bucket{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "instant": false, + "legendFormat": "25th Percentile", + "range": true, + "refId": "0.25 Percentile" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum(rate(microgateway_rq_processing_time_ms_bucket{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "50th Percentile", + "range": true, + "refId": "0.5 Percentile" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(microgateway_rq_processing_time_ms_bucket{namespace=~\"${namespace:regex}\", job=~\"${operator_namespace.regex}/.*-engine\"}[1m])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "95th Percentile", + "range": true, + "refId": "0.95 Percentile" + } + ], + "title": "Airlock Microgateway Processing Time", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "airlock-microgateway" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "PBFA97CFB590B2093" + }, + "hide": 2, + "includeAll": false, + "label": "DS_PROMETHEUS", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_valid,namespace)", + "hide": 0, + "includeAll": true, + "label": "Operator Namespace", + "multi": true, + "name": "operator_namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_valid,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": ".*", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(microgateway_license_http_rq_total,namespace)", + "hide": 0, + "includeAll": true, + "label": "Application Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(microgateway_license_http_rq_total,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "Airlock Microgateway Overview", + "uid": "fdp5jb8fnrmyoa", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/NOTES.txt b/charts/airlock/microgateway/4.3.4/templates/NOTES.txt new file mode 100644 index 0000000000..6e5ce218ae --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/NOTES.txt @@ -0,0 +1,47 @@ +Thank you for installing Airlock Microgateway. + +Please ensure the following prerequisites are fulfilled: +* Cert-Manager is installed. + https://cert-manager.io/docs/installation/helm/ +* Airlock Microgateway CNI is also installed on the cluster. + https://artifacthub.io/packages/helm/airlock-microgateway-cni/microgateway-cni +* A valid Airlock Microgateway license is deployed in the Kubernetes secret 'airlock-microgateway-license'. + * Get a free Community license: https://airlock.com/en/microgateway-community + * Order a Premium license: https://airlock.com/en/microgateway-premium + +Further information: +* Documentation: https://docs.airlock.com/microgateway/{{ include "airlock-microgateway.docsVersion" . }} +* CRD API reference documentation: https://docs.airlock.com/microgateway/{{ include "airlock-microgateway.docsVersion" . }}/api/crds +* Airlock Microgateway Labs: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=helm +{{- if .Values.crds.skipVersionCheck }} + +Warning: CRD version check skipped +{{- else -}} +{{- $outdatedCRDs := (include "airlock-microgateway.outdatedCRDs" .) -}} +{{- if $outdatedCRDs -}} + {{- fail (printf ` + +Helm does not automatically upgrade CRDs from the chart's 'crds/' directory during 'helm install/upgrade'. +Therefore, the CRDs must be manually upgraded with the following command before deploying this chart: + +kubectl apply -k https://github.com/airlock/microgateway/deploy/charts/airlock-microgateway/crds/?ref=%s --server-side --force-conflicts + +If you are not using the helm install/upgrade command and instead rely on some other mechanism which is able to upgrade CRDs for deploying this chart, you can suppress this error by setting the helm value 'crds.skipVersionCheck=true'.` + .Chart.AppVersion) + -}} +{{- end -}} +{{- end -}} +{{- if .Values.tests.enabled -}} + {{- if .Values.operator.watchNamespaces -}} + {{- if not (has .Release.Namespace .Values.operator.watchNamespaces) -}} + {{- fail (printf ` + +To execute 'helm test', it is necessary that the release namespace '%s' is part of the operator's watch scope. Either disable the tests or ensure that the release namespace is added to watch namspace list ('operator.watchNamespaces') in the helm values. +` + .Release.Namespace) + -}} + {{- end -}} + {{- end -}} +{{- end }} + +Your release version is {{ .Chart.Version }}. \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/_helpers.tpl b/charts/airlock/microgateway/4.3.4/templates/_helpers.tpl new file mode 100644 index 0000000000..733ba96486 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/_helpers.tpl @@ -0,0 +1,153 @@ +{{/* +Expand the name of the chart. +We truncate at 49 chars because some Kubernetes name fields are limited to 63 chars (by the DNS naming spec) +and the longest explicit suffix is 14 characters. +*/}} +{{- define "airlock-microgateway.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 49 | trimSuffix "-" }} +{{- end }} + +{{/* +Convert an image configuration object into an image ref string. +*/}} +{{- define "airlock-microgateway.image" -}} + {{- if .digest -}} + {{- printf "%s@%s" .repository .digest -}} + {{- else if .tag -}} + {{- printf "%s:%s" .repository .tag -}} + {{- else -}} + {{- printf "%s" .repository -}} + {{- end -}} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 36 chars because some Kubernetes name fields are limited to 63 chars (by the DNS naming spec) +and the longest implicit suffix is 27 characters. +If release name contains chart name it will be used as a full name. +*/}} +{{- define "airlock-microgateway.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 36 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 36 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 36 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "airlock-microgateway.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "airlock-microgateway.sharedLabels" -}} +helm.sh/chart: {{ include "airlock-microgateway.chart" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: {{ .Chart.Name }} +{{- with .Values.commonLabels }} +{{ toYaml .}} +{{- end }} +{{- end }} + +{{/* +Common Selector labels +*/}} +{{- define "airlock-microgateway.sharedSelectorLabels" -}} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Restricted Container Security Context +*/}} +{{- define "airlock-microgateway.restrictedSecurityContext" -}} +allowPrivilegeEscalation: false +privileged: false +runAsNonRoot: true +capabilities: + drop: ["ALL"] +readOnlyRootFilesystem: true +seccompProfile: + type: RuntimeDefault +{{- end }} + +{{/* Precondition: May only be used if AppVersion is isSemver */}} +{{- define "airlock-microgateway.supportedCRDVersionPattern" -}} +{{- $version := (semver .Chart.AppVersion) -}} +{{- if $version.Prerelease -}} +>= {{ $version.Major }}.{{ $version.Minor }}.{{ $version.Patch }}-{{ $version.Prerelease }} +{{- else -}} +>= {{ $version.Major }}.{{ $version.Minor }}.0 || >= {{ $version.Major }}.{{ $version.Minor }}.{{ add1 $version.Patch }}-0 +{{- end -}} +{{- end -}} + +{{- define "airlock-microgateway.outdatedCRDs" -}} +{{- if (eq "true" (include "airlock-microgateway.isSemver" .Chart.AppVersion)) -}} + {{- $supportedVersion := (include "airlock-microgateway.supportedCRDVersionPattern" .) -}} + {{- range $path, $_ := .Files.Glob "crds/*.yaml" -}} + {{- $api := ($.Files.Get $path | fromYaml).metadata.name -}} + {{- $crd := (lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" $api) -}} + {{- $isOutdated := false -}} + {{- if $crd -}} + {{/* If CRD is already present in the cluster, it must have the minimum supported version */}} + {{- $isOutdated = true -}} + {{- if hasKey $crd.metadata "labels" -}} + {{- $crdVersion := get $crd.metadata.labels "app.kubernetes.io/version" -}} + {{- if (eq "true" (include "airlock-microgateway.isSemver" $crdVersion)) -}} + {{- if (semverCompare $supportedVersion $crdVersion) }} + {{- $isOutdated = false -}} + {{- end }} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if $isOutdated }} +{{ base $path }} + {{- end }} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- define "airlock-microgateway.isSemver" -}} +{{- regexMatch `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` . -}} +{{- end -}} + +{{- define "airlock-microgateway.docsVersion" -}} +{{- if and (eq "true" (include "airlock-microgateway.isSemver" .Chart.AppVersion)) (not (contains "-" .Chart.AppVersion)) -}} + {{- $version := (semver .Chart.AppVersion) -}} + {{- $version.Major }}.{{ $version.Minor -}} +{{- else -}} + {{- print "latest" -}} +{{- end -}} +{{- end -}} + +{{- define "airlock-microgateway.watchNamespaceSelector.labelQuery" -}} +{{- $list := list -}} +{{- with .matchLabels -}} + {{- range $key, $value := . -}} + {{- $list = append $list (printf "%s=%s" $key $value) -}} + {{- end -}} +{{- end -}} +{{- with .matchExpressions -}} + {{- range . -}} + {{- if has .operator (list "In" "NotIn") -}} + {{- $list = append $list (printf "%s %s (%s)" .key (lower .operator) (join "," .values)) -}} + {{- else if eq .operator "Exists" -}} + {{- $list = append $list .key -}} + {{- else if eq .operator "DoesNotExist" -}} + {{- $list = append $list (printf "!%s" .key) -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- join "," $list -}} +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/_operator_helpers.tpl b/charts/airlock/microgateway/4.3.4/templates/operator/_operator_helpers.tpl new file mode 100644 index 0000000000..a540ff9f4f --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/_operator_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Create a default fully qualified name for operator components. +*/}} +{{- define "airlock-microgateway.operator.fullname" -}} +{{ include "airlock-microgateway.fullname" . }}-operator +{{- end }} + + +{{/* +Common operator labels +*/}} +{{- define "airlock-microgateway.operator.labels" -}} +{{ include "airlock-microgateway.sharedLabels" . }} +{{ include "airlock-microgateway.operator.selectorLabels" . }} +{{- end }} + +{{/* +Operator Selector labels +*/}} +{{- define "airlock-microgateway.operator.selectorLabels" -}} +{{ include "airlock-microgateway.sharedSelectorLabels" . }} +app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-operator +app.kubernetes.io/component: controller +{{- end }} + +{{/* +Create the name of the service account to use for the operator +*/}} +{{- define "airlock-microgateway.operator.serviceAccountName" -}} +{{- if .Values.operator.serviceAccount.create }} +{{- default (include "airlock-microgateway.operator.fullname" .) .Values.operator.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.operator.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +ServiceMonitor metrics regex pattern for leader only metrics +*/}} +{{- define "airlock-microgateway.operator.metricsLeaderOnlyRegexPattern" -}} +^(microgateway_license|microgateway_sidecars).*$ +{{- end }} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/_rbac.gen.tpl b/charts/airlock/microgateway/4.3.4/templates/operator/_rbac.gen.tpl new file mode 100644 index 0000000000..83b314cbcf --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/_rbac.gen.tpl @@ -0,0 +1,237 @@ +{{/* AUTOGENERATED FILE DO NOT EDIT */}} + +{{/* +Operator rbac permission rules +*/}} +{{- define "airlock-microgateway-operator.rbacRules" -}} +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - pods/finalizers + verbs: + - update +- apiGroups: + - "" + resources: + - pods/status + verbs: + - patch + - update +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - update + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - accesscontrols + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - contentsecurities + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - denyrules + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - envoyclusters + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - envoyconfigurations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - envoyconfigurations/status + verbs: + - get + - patch + - update +- apiGroups: + - microgateway.airlock.com + resources: + - envoyhttpfilters + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - graphqls + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - headerrewrites + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - identitypropagations + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - limits + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - oidcproviders + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - oidcrelyingparties + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - openapis + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - parsers + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - redisproviders + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - sessionhandlings + verbs: + - get + - list + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - sidecargateways + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - microgateway.airlock.com + resources: + - sidecargateways/finalizers + verbs: + - update +- apiGroups: + - microgateway.airlock.com + resources: + - sidecargateways/status + verbs: + - get + - patch + - update +- apiGroups: + - microgateway.airlock.com + resources: + - telemetries + verbs: + - get + - list + - watch +{{- end }} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/_webhooks.gen.tpl b/charts/airlock/microgateway/4.3.4/templates/operator/_webhooks.gen.tpl new file mode 100644 index 0000000000..02e3048904 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/_webhooks.gen.tpl @@ -0,0 +1,339 @@ +{{/* AUTOGENERATED FILE DO NOT EDIT */}} + +{{/* +Operator mutating webhooks +*/}} +{{- define "airlock-microgateway-operator.mutatingWebhooks" -}} +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /mutate-v1-pod + failurePolicy: Fail + name: mutate-pod.microgateway.airlock.com + reinvocationPolicy: IfNeeded + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods + sideEffects: None + objectSelector: + matchLabels: + sidecar.microgateway.airlock.com/inject: "true" +{{- end }} + +{{/* +Operator validating webhooks +*/}} +{{- define "airlock-microgateway-operator.validatingWebhooks" -}} +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-v1-pod + failurePolicy: Fail + name: validate-pod.microgateway.airlock.com + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - pods + sideEffects: None + objectSelector: + matchLabels: + sidecar.microgateway.airlock.com/inject: "true" +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-accesscontrol + failurePolicy: Fail + name: validate-accesscontrol.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - accesscontrols + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-denyrules + failurePolicy: Fail + name: validate-denyrules.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - denyrules + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-envoycluster + failurePolicy: Fail + name: validate-envoycluster.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - envoyclusters + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-envoyhttpfilter + failurePolicy: Fail + name: validate-envoyhttpfilter.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - envoyhttpfilters + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-graphql + failurePolicy: Fail + name: validate-graphql.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - graphqls + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-headerrewrites + failurePolicy: Fail + name: validate-headerrewrites.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - headerrewrites + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-identitypropagation + failurePolicy: Fail + name: validate-identitypropagation.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - identitypropagations + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-limits + failurePolicy: Fail + name: validate-limits.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - limits + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-oidcprovider + failurePolicy: Fail + name: validate-oidcprovider.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - oidcproviders + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-oidcrelyingparty + failurePolicy: Fail + name: validate-oidcrelyingparty.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - oidcrelyingparties + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-openapi + failurePolicy: Fail + name: validate-openapi.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - openapis + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-parser + failurePolicy: Fail + name: validate-parser.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - parsers + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-redisprovider + failurePolicy: Fail + name: validate-redisprovider.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - redisproviders + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: airlock-microgateway-operator-webhook + namespace: '{{ .Release.Namespace }}' + path: /validate-microgateway-airlock-com-v1alpha1-sidecargateway + failurePolicy: Fail + name: validate-sidecargateway.microgateway.airlock.com + rules: + - apiGroups: + - microgateway.airlock.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - sidecargateways + sideEffects: None +{{- end }} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/configmap.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/configmap.yaml new file mode 100644 index 0000000000..95e52d7df1 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/configmap.yaml @@ -0,0 +1,394 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-config + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + engine_bootstrap_config_template.yaml: | + # Base configuration, admin interface on port 19000 + admin: + address: + socket_address: + address: 127.0.0.1 + port_value: 19000 + dynamic_resources: + cds_config: + initial_fetch_timeout: 10s + resource_api_version: V3 + api_config_source: + api_type: GRPC + transport_api_version: V3 + grpc_services: + - envoy_grpc: + cluster_name: xds_cluster + set_node_on_first_message_only: true + # Prevent Envoy Node from overloading the xDS server due to rejected configuration when using xDS SotW gRPC + rate_limit_settings: + max_tokens: 5 + fill_rate: 0.2 + lds_config: + resource_api_version: V3 + initial_fetch_timeout: 10s + api_config_source: + api_type: GRPC + transport_api_version: V3 + grpc_services: + - envoy_grpc: + cluster_name: xds_cluster + set_node_on_first_message_only: true + # Prevent Envoy Node from overloading the xDS server due to rejected configuration when using xDS SotW gRPC + rate_limit_settings: + max_tokens: 5 + fill_rate: 0.2 + static_resources: + listeners: + - name: probe + address: + socket_address: + address: 0.0.0.0 + port_value: 19001 + filter_chains: + - filters: + - name: http_connection_manager + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: probe + codec_type: AUTO + http2_protocol_options: + initial_connection_window_size: 1048576 + initial_stream_window_size: 65536 + max_concurrent_streams: 100 + route_config: + name: probe + virtual_hosts: + - name: probe + domains: + - '*' + routes: + - name: ready + match: + path: /ready + headers: + - name: ':method' + string_match: + exact: 'GET' + route: + cluster: airlock_microgateway_engine_admin + http_filters: + - name: envoy.filters.http.router + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + - name: metrics + address: + socket_address: + address: 0.0.0.0 + port_value: 19002 + filter_chains: + - filters: + - name: http_connection_manager + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: metrics + codec_type: AUTO + http2_protocol_options: + initial_connection_window_size: 1048576 + initial_stream_window_size: 65536 + max_concurrent_streams: 100 + route_config: + name: metrics + virtual_hosts: + - name: metrics + domains: + - '*' + routes: + - name: metrics + match: + path: /metrics + headers: + - name: ':method' + string_match: + exact: 'GET' + route: + prefix_rewrite: '/stats/prometheus' + cluster: airlock_microgateway_engine_admin + http_filters: + - name: envoy.filters.http.router + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: xds_cluster + connect_timeout: 1s + type: STRICT_DNS + load_assignment: + cluster_name: xds_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: airlock-microgateway-operator-xds.$(OPERATOR_NAMESPACE).svc.cluster.local + port_value: 13377 + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicit_http_config: + http2_protocol_options: + connection_keepalive: + interval: 360s + timeout: 5s + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + common_tls_context: + tls_params: + tls_minimum_protocol_version: TLSv1_3 + tls_maximum_protocol_version: TLSv1_3 + validation_context_sds_secret_config: + name: validation_context_sds + sds_config: + resource_api_version: V3 + path_config_source: + path: /etc/envoy/validation_context_sds_secret.yaml + watched_directory: + path: /etc/envoy/ + tls_certificate_sds_secret_configs: + - name: tls_certificate_sds + sds_config: + resource_api_version: V3 + path_config_source: + path: /etc/envoy/tls_certificate_sds_secret.yaml + watched_directory: + path: /etc/envoy/ + - name: airlock_microgateway_engine_admin + connect_timeout: 1s + type: STATIC + load_assignment: + cluster_name: airlock_microgateway_engine_admin + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 19000 + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicit_http_config: + http2_protocol_options: + connection_keepalive: + interval: 360s + timeout: 5s + stats_config: + stats_tags: + - tag_name: "block_type" + regex: "\\.(block_type\\.([^.]+))" + - tag_name: "attack_type" + regex: "\\.(attack_type\\.([^.]+))" + - tag_name: "envoy_cluster_name" + regex: "\\.(cluster\\.([^.]+))" + - tag_name: "version" + regex: "\\.(version\\.([^.]+))" + use_all_default_tags: true + overload_manager: + resource_monitors: + - name: "envoy.resource_monitors.global_downstream_max_connections" + typed_config: + "@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig + max_active_downstream_connections: 50000 + bootstrap_extensions: + - name: airlock.bootstrap.engine_build_info + typed_config: + '@type': type.googleapis.com/airlock.extensions.bootstrap.stats.v1alpha.Stats + application_log_config: + log_format: + text_format: '{"@timestamp":"%Y-%m-%dT%T.%e%z","log":{"logger":"%n","level":"%l","origin":{"file":{"name":"%g","line":%#},"function":"%!"}},"event":{"module":"envoy","dataset":"envoy.application"},"process":{"pid":%P,"thread":{"id":%t}},"ecs":{"version":"8.5"},"message":"%j"}' + engine_container_template.yaml: | + name: "$(ENGINE_NAME)" + image: "$(ENGINE_IMAGE)" + imagePullPolicy: {{ .Values.engine.image.pullPolicy }} + args: + - "--config-path" + - "/etc/envoy/bootstrap_config.yaml" + - "--base-id" + - "$(BASE_ID)" + - "--file-flush-interval-msec" + - '1000' + - "--drain-time-s" + - '60' + - "--service-node" + - "$(POD_NAME).$(POD_NAMESPACE)" + - "--service-cluster" + - "$(APP_NAME).$(POD_NAMESPACE)" + - "--log-path" + - "/dev/stdout" + - "--log-level" + - "$(LOG_LEVEL)" + volumeMounts: + - name: airlock-microgateway-bootstrap-secret-volume + mountPath: /etc/envoy + readOnly: true + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + ports: + - containerPort: 13378 + protocol: TCP + - containerPort: 19001 + protocol: TCP + - containerPort: 19002 + protocol: TCP + livenessProbe: + httpGet: + path: /ready + port: 19001 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 5 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + httpGet: + path: /ready + port: 19001 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 6 }} + runAsUser: $(SECURITYCONTEXT_UID) + {{- with .Values.engine.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + session_agent_container_template.yaml: | + name: "$(SESSION_AGENT_NAME)" + image: "$(SESSION_AGENT_IMAGE)" + imagePullPolicy: {{ .Values.sessionAgent.image.pullPolicy }} + args: + - "--port" + - "19004" + - "--config-path" + - "/etc/microgateway-session-agent/config.json" + volumeMounts: + - name: airlock-microgateway-session-agent-volume + mountPath: /etc/microgateway-session-agent + readOnly: true + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + ports: + - containerPort: 19004 + livenessProbe: + {{- if (semverCompare ">=1.27 || >=1.27.1-0" .Capabilities.KubeVersion.Version)}} + grpc: + port: 19004 + {{- else }} + tcpSocket: + port: 19004 + {{- end }} + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 5 + successThreshold: 1 + timeoutSeconds: 5 + readinessProbe: + {{- if (semverCompare ">=1.27 || >=1.27.1-0" .Capabilities.KubeVersion.Version)}} + grpc: + port: 19004 + {{- else }} + tcpSocket: + port: 19004 + {{- end }} + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + timeoutSeconds: 5 + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 6 }} + runAsUser: $(SECURITYCONTEXT_UID) + {{- with .Values.sessionAgent.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + network_validator_container_template.yaml: | + name: "$(NETWORK_VALIDATOR_NAME)" + image: "$(NETWORK_VALIDATOR_IMAGE)" + imagePullPolicy: {{ .Values.networkValidator.image.pullPolicy }} + command: ["/bin/sh", "-c"] + args: + - |- + echo 'pong' | nc -v -l 127.0.0.1 13378 & + for i in 1 2 3; do + sleep 1s + if r=$(echo 'ping' | nc -v -q 0 127.0.0.1 19003) && [ $r == pong ]; then + echo -n 'Traffic redirection to Airlock Microgateway Engine is working.' > /dev/termination-log + exit 0 + fi + done + echo -en 'Traffic redirection to Airlock Microgateway Engine is not working.\nRestart the pod after ensuring that hostNetwork is disabled and a compatible Airlock Microgateway CNI version is installed on the node.\nCertain environments may also require additional configuration (see docs.airlock.com for more information).' > /dev/termination-log + exit 1 + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 6 }} + runAsUser: $(SECURITYCONTEXT_UID) + operator_config.yaml: | + apiVersion: config.airlock.com/v1alpha1 + kind: OperatorConfig + health: + healthProbeBindAddress: :8081 + metrics: + bindAddress: 0.0.0.0:8080 + webhook: + port: 9443 + deployment: + sidecar: + engineContainerTemplate: "/sidecar/engine_container_template.yaml" + networkValidatorContainerTemplate: "/sidecar/network_validator_container_template.yaml" + sessionAgentContainerTemplate: "/sidecar/session_agent_container_template.yaml" + engine: + bootstrapConfigTemplate: "/engine_bootstrap_config_template.yaml" + log: + level: {{ .Values.operator.config.logLevel }} + {{- with $.Values.operator.watchNamespaceSelector }} + namespaces: + selector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $.Values.operator.watchNamespaces }} + namespaces: + list: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/dashboard-configmap.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/dashboard-configmap.yaml new file mode 100644 index 0000000000..b71ac89b65 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/dashboard-configmap.yaml @@ -0,0 +1,28 @@ +{{- if .Values.dashboards.create -}} +{{- range $instance := (keys .Values.dashboards.instances | sortAlpha) -}} +{{- $dashboard := get $.Values.dashboards.instances $instance -}} +{{- if $dashboard.create }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "airlock-microgateway.fullname" $ }}-dashboard-{{ $instance | lower }} + namespace: {{ $.Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" $ | nindent 4 }} + {{- with $.Values.dashboards.config.grafana.dashboardLabel -}} + {{- .name | nindent 4 -}}: {{ .value | quote }} + {{- end }} + annotations: + {{- with $.Values.dashboards.config.grafana.folderAnnotation -}} + {{- .name | nindent 4 -}}: {{ .value | quote }} + {{- end }} + {{- with $.Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + {{- printf "%s.json" $instance | nindent 2 }}: |- + {{- ($.Files.Get (printf "dashboards/%s.json" $instance)) | nindent 4 -}} +{{- end -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/deployment.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/deployment.yaml new file mode 100644 index 0000000000..db340cdecc --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/deployment.yaml @@ -0,0 +1,143 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.operator.replicaCount }} + {{- with .Values.operator.updateStrategy }} + strategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/operator/configmap.yaml") . | sha256sum }} + kubectl.kubernetes.io/default-container: manager + {{- with mustMerge .Values.operator.podAnnotations .Values.commonAnnotations}} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 8 }} + {{- with .Values.operator.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + - args: + - --config=operator_config.yaml + env: + - name: ENGINE_IMAGE + value: {{ include "airlock-microgateway.image" .Values.engine.image }} + - name: NETWORK_VALIDATOR_IMAGE + value: {{ include "airlock-microgateway.image" .Values.networkValidator.image }} + - name: SESSION_AGENT_IMAGE + value: {{ include "airlock-microgateway.image" .Values.sessionAgent.image }} + - name: OPERATOR_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: {{ include "airlock-microgateway.image" .Values.operator.image }} + imagePullPolicy: {{ .Values.operator.image.pullPolicy }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + - containerPort: 13377 + name: xds-server + protocol: TCP + - containerPort: 8080 + protocol: TCP + - containerPort: 8081 + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + {{- with .Values.operator.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 10 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + - mountPath: /opt/airlock/license/ + name: airlock-microgateway-license + readOnly: true + - mountPath: /operator_config.yaml + name: operator-config + subPath: operator_config.yaml + - mountPath: /sidecar/engine_container_template.yaml + name: operator-config + subPath: engine_container_template.yaml + - mountPath: /sidecar/network_validator_container_template.yaml + name: operator-config + subPath: network_validator_container_template.yaml + - mountPath: /sidecar/session_agent_container_template.yaml + name: operator-config + subPath: session_agent_container_template.yaml + - mountPath: /engine_bootstrap_config_template.yaml + name: operator-config + subPath: engine_bootstrap_config_template.yaml + securityContext: + runAsNonRoot: true + serviceAccountName: {{ include "airlock-microgateway.operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: {{ include "airlock-microgateway.operator.fullname" . }}-webhook-server-cert + - name: airlock-microgateway-license + secret: + defaultMode: 292 + optional: true + secretName: {{ .Values.license.secretName }} + - configMap: + name: {{ include "airlock-microgateway.operator.fullname" . }}-config + name: operator-config diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/manager-role.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/manager-role.yaml new file mode 100644 index 0000000000..90335bcfe1 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/manager-role.yaml @@ -0,0 +1,33 @@ +{{- if .Values.operator.rbac.create }} +{{- if empty .Values.operator.watchNamespaces }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-manager-{{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +{{ include "airlock-microgateway-operator.rbacRules" . -}} +{{- else }} +{{- range $namespace := (append .Values.operator.watchNamespaces .Release.Namespace | uniq) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "airlock-microgateway.operator.fullname" $ }}-manager + namespace: {{ $namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" $ | nindent 4 }} + {{- with $.Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +{{ include "airlock-microgateway-operator.rbacRules" $ }} +--- +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/manager-rolebinding.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/manager-rolebinding.yaml new file mode 100644 index 0000000000..ae99cfb7b6 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/manager-rolebinding.yaml @@ -0,0 +1,45 @@ +{{- if .Values.operator.rbac.create }} +{{- if empty .Values.operator.watchNamespaces }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-manager-{{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "airlock-microgateway.operator.fullname" . }}-manager-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: {{ include "airlock-microgateway.operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- else }} +{{- range $namespace := (append .Values.operator.watchNamespaces .Release.Namespace | uniq) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "airlock-microgateway.operator.fullname" $ }}-manager + namespace: {{ $namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" $ | nindent 4 }} + {{- with $.Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "airlock-microgateway.operator.fullname" $ }}-manager +subjects: + - kind: ServiceAccount + name: {{ include "airlock-microgateway.operator.serviceAccountName" $ }} + namespace: {{ $.Release.Namespace }} +--- +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/metrics-service.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/metrics-service.yaml new file mode 100644 index 0000000000..34d23f6d67 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/metrics-service.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: Service +metadata: + name: airlock-microgateway-operator-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with mustMerge .Values.operator.serviceAnnotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ports: + - appProtocol: http + name: metrics + port: 8080 + protocol: TCP + selector: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 4 }} +--- +apiVersion: v1 +kind: Service +metadata: + name: airlock-microgateway-operator-leader-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + operator.microgateway.airlock.com/isLeader: "true" + {{- with mustMerge .Values.operator.serviceAnnotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ports: + - appProtocol: http + name: metrics + port: 8080 + protocol: TCP + selector: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 4 }} + operator.microgateway.airlock.com/isLeader: "true" \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/mutating-webhook.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/mutating-webhook.yaml new file mode 100644 index 0000000000..311f9726ad --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/mutating-webhook.yaml @@ -0,0 +1,28 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-webhook-{{ .Release.Namespace }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "airlock-microgateway.operator.fullname" . }}-serving-cert + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +webhooks: +{{- range $webhook := (include "airlock-microgateway-operator.mutatingWebhooks" .) | fromYamlArray }} +- {{ toYaml $webhook | indent 2 | trim }} + {{- with $.Values.operator.watchNamespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $.Values.operator.watchNamespaces }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: In + values: + {{- toYaml . | nindent 10 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/podmonitor.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/podmonitor.yaml new file mode 100644 index 0000000000..1fe34fcb35 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/podmonitor.yaml @@ -0,0 +1,27 @@ +{{- if .Values.engine.sidecar.podMonitor.create }} +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ include "airlock-microgateway.fullname" . }}-engine + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.engine.sidecar.podMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + namespaceSelector: + any: true + selector: + matchLabels: + sidecar.microgateway.airlock.com/inject: "true" + microgateway.airlock.com/managedBy: {{ .Release.Namespace }} + podMetricsEndpoints: + - targetPort: 19002 + path: /metrics + scheme: http +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/role.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/role.yaml new file mode 100644 index 0000000000..5378be8ef9 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/role.yaml @@ -0,0 +1,45 @@ +{{- if .Values.operator.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/rolebinding.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/rolebinding.yaml new file mode 100644 index 0000000000..bafec10156 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.operator.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "airlock-microgateway.operator.fullname" . }}-leader-election +subjects: + - kind: ServiceAccount + name: {{ include "airlock-microgateway.operator.serviceAccountName" . }} +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/selfsigned-issuer.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/selfsigned-issuer.yaml new file mode 100644 index 0000000000..466c56338e --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/selfsigned-issuer.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-selfsigned-issuer + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selfSigned: {} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/serviceaccount.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/serviceaccount.yaml new file mode 100644 index 0000000000..434d7e9d30 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.operator.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "airlock-microgateway.operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with mustMerge .Values.operator.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/servicemonitor.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/servicemonitor.yaml new file mode 100644 index 0000000000..ff85a9a310 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/servicemonitor.yaml @@ -0,0 +1,60 @@ +{{- if .Values.operator.serviceMonitor.create }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 6 }} + matchExpressions: + - { key: "operator.microgateway.airlock.com/isLeader", operator: DoesNotExist } + endpoints: + - path: /metrics + port: metrics + scheme: http + metricRelabelings: + - sourceLabels: + - __name__ + regex: {{ include "airlock-microgateway.operator.metricsLeaderOnlyRegexPattern" . }} + action: drop +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-leader + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 6 }} + operator.microgateway.airlock.com/isLeader: "true" + endpoints: + - path: /metrics + port: metrics + scheme: http + metricRelabelings: + - sourceLabels: + - __name__ + regex: {{ include "airlock-microgateway.operator.metricsLeaderOnlyRegexPattern" . }} + action: keep +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/serving-certificate.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/serving-certificate.yaml new file mode 100644 index 0000000000..60b92e1e2c --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/serving-certificate.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-serving-cert + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + dnsNames: + - airlock-microgateway-operator-webhook.{{ .Release.Namespace }}.svc + - airlock-microgateway-operator-webhook.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "airlock-microgateway.operator.fullname" . }}-selfsigned-issuer + secretName: {{ include "airlock-microgateway.operator.fullname" . }}-webhook-server-cert diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/validating-webhook.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/validating-webhook.yaml new file mode 100644 index 0000000000..5d6b4396ba --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/validating-webhook.yaml @@ -0,0 +1,28 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ include "airlock-microgateway.operator.fullname" . }}-webhook-{{ .Release.Namespace }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "airlock-microgateway.operator.fullname" . }}-serving-cert + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +webhooks: +{{- range $webhook := (include "airlock-microgateway-operator.validatingWebhooks" .) | fromYamlArray }} +- {{ toYaml $webhook | indent 2 | trim }} + {{- with $.Values.operator.watchNamespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $.Values.operator.watchNamespaces }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: In + values: + {{- toYaml . | nindent 10 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/webhook-service.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/webhook-service.yaml new file mode 100644 index 0000000000..477ea839f3 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/webhook-service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: airlock-microgateway-operator-webhook + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with mustMerge .Values.operator.serviceAnnotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ports: + - appProtocol: https + name: webhook + port: 443 + protocol: TCP + targetPort: 9443 + selector: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/operator/xds-service.yaml b/charts/airlock/microgateway/4.3.4/templates/operator/xds-service.yaml new file mode 100644 index 0000000000..81b41acf5b --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/operator/xds-service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: airlock-microgateway-operator-xds + namespace: {{ .Release.Namespace }} + labels: + {{- include "airlock-microgateway.operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with mustMerge .Values.operator.serviceAnnotations .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ports: + - appProtocol: grpc + name: xds + port: 13377 + protocol: TCP + targetPort: 13377 + selector: + {{- include "airlock-microgateway.operator.selectorLabels" . | nindent 4 }} + operator.microgateway.airlock.com/isLeader: "true" diff --git a/charts/airlock/microgateway/4.3.4/templates/tests/rbac.yaml b/charts/airlock/microgateway/4.3.4/templates/tests/rbac.yaml new file mode 100644 index 0000000000..93bd4cd1bd --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/tests/rbac.yaml @@ -0,0 +1,143 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: tests + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + name: "{{ include "airlock-microgateway.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: tests + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + name: "{{ include "airlock-microgateway.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "{{ include "airlock-microgateway.fullname" . }}-tests" +subjects: +- kind: ServiceAccount + name: "{{ include "airlock-microgateway.fullname" . }}-tests" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: tests + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + name: "{{ include "airlock-microgateway.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - microgateway.airlock.com + resources: + - sidecargateways + resourceNames: + - "{{ include "airlock-microgateway.fullname" . }}-test-sidecargateway" + verbs: + - get + - list + - watch + - delete +- apiGroups: + - microgateway.airlock.com + resources: + - sidecargateways + verbs: + - create +- apiGroups: + - "" + resources: + - events + verbs: + - list +- apiGroups: + - "apps" + resources: + - deployments + resourceNames: + - "{{ include "airlock-microgateway.operator.fullname" . }}" + verbs: + - get + - list + - watch +- apiGroups: + - "apps" + resources: + - statefulsets + - statefulsets/scale + resourceNames: + - "{{ include "airlock-microgateway.fullname" . }}-test-backend" + verbs: + - get + - list + - watch + - patch +- apiGroups: + - "" + resources: + - pods + - pods/log + - pods/status + - pods/attach + resourceNames: + - "{{ include "airlock-microgateway.fullname" . }}-test-backend-0" + - "{{ include "airlock-microgateway.fullname" . }}-test-valid-request" + - "{{ include "airlock-microgateway.fullname" . }}-test-injection-request" + verbs: + - get + - list + - create + - watch + - delete +- apiGroups: + - "" + resources: + - pods + verbs: + - create +{{- if .Values.operator.watchNamespaceSelector }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: tests + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + name: "{{ include "airlock-microgateway.fullname" . }}-tests-{{ .Release.Namespace }}" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: "{{ include "airlock-microgateway.fullname" . }}-tests-{{ .Release.Namespace }}" +subjects: + - kind: ServiceAccount + name: "{{ include "airlock-microgateway.fullname" . }}-tests" + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: tests + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + name: "{{ include "airlock-microgateway.fullname" . }}-tests-{{ .Release.Namespace }}" +rules: +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list +{{- end }} +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/templates/tests/service.yaml b/charts/airlock/microgateway/4.3.4/templates/tests/service.yaml new file mode 100644 index 0000000000..30ddc278d6 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/tests/service.yaml @@ -0,0 +1,23 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ include "airlock-microgateway.fullname" . }}-test-service" + namespace: {{ .Release.Namespace }} + labels: + app: test-service + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 4 }} +spec: + selector: + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + app: "{{ include "airlock-microgateway.fullname" . }}-test-backend" + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 4 }} + ports: + - name: http + port: 8080 + targetPort: 8080 +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/tests/statefulset.yaml b/charts/airlock/microgateway/4.3.4/templates/tests/statefulset.yaml new file mode 100644 index 0000000000..710a7b9f67 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/tests/statefulset.yaml @@ -0,0 +1,56 @@ +{{- if .Values.tests.enabled -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "{{ include "airlock-microgateway.fullname" . }}-test-backend" + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + app: "{{ include "airlock-microgateway.fullname" . }}-test-backend" + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 4 }} +spec: + serviceName: nginx + replicas: 0 + selector: + matchLabels: + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + app: "{{ include "airlock-microgateway.fullname" . }}-test-backend" + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + k8s.v1.cni.cncf.io/networks: default/airlock-microgateway-cni + labels: + sidecar.microgateway.airlock.com/inject: "true" + sidecar.istio.io/inject: "false" + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + app: "{{ include "airlock-microgateway.fullname" . }}-test-backend" + {{- include "airlock-microgateway.sharedLabels" . | nindent 8 }} + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 8 }} + spec: + containers: + - image: cgr.dev/chainguard/nginx + name: nginx + ports: + - containerPort: 8080 + volumeMounts: + - mountPath: /var/lib/nginx/tmp/ + name: nginx-tmp + - mountPath: /var/run + name: nginx-run + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 12 }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - emptyDir: {} + name: nginx-tmp + - emptyDir: {} + name: nginx-run +{{- end -}} \ No newline at end of file diff --git a/charts/airlock/microgateway/4.3.4/templates/tests/test-install.yaml b/charts/airlock/microgateway/4.3.4/templates/tests/test-install.yaml new file mode 100644 index 0000000000..ab82abea73 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/templates/tests/test-install.yaml @@ -0,0 +1,227 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "airlock-microgateway.fullname" . }}-test-install" + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/component: test-install + app.kubernetes.io/name: {{ include "airlock-microgateway.name" . }}-tests + sidecar.istio.io/inject: "false" + {{- include "airlock-microgateway.sharedLabels" . | nindent 4 }} + {{- include "airlock-microgateway.sharedSelectorLabels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-delete-policy: before-hook-creation +spec: + restartPolicy: Never + containers: + - name: test + image: "bitnami/kubectl:{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}" + securityContext: + {{- include "airlock-microgateway.restrictedSecurityContext" . | nindent 6 }} + command: + - sh + - -c + - | + set -eu + + clean_up() { + echo "" + echo "### Clean up test resources" + kubectl delete --ignore-not-found=true -n {{ .Release.Namespace }} sidecargateways.microgateway.airlock.com {{ include "airlock-microgateway.fullname" . }}-test-sidecargateway || true + echo "" + echo "### Scale down '{{ include "airlock-microgateway.fullname" . }}-test-backend'" + kubectl scale -n {{ .Release.Namespace }} statefulset/{{ include "airlock-microgateway.fullname" . }}-test-backend --replicas=0 --timeout=60s + sleep 3s + echo "" + } + + fail() { + echo "" + echo "### Error: ${1}" + echo "" + + if kubectl get -n {{ .Release.Namespace }} sidecargateway.microgateway.airlock.com/{{ include "airlock-microgateway.fullname" . }}-test-sidecargateway >/dev/null 2>&1; then + echo "" + echo 'Microgateway Sidecargateway status:' + kubectl get -n {{ .Release.Namespace }} sidecargateway.microgateway.airlock.com/{{ include "airlock-microgateway.fullname" . }}-test-sidecargateway -o jsonpath-as-json='{.status}' || true + echo "" + echo "" + fi + + if kubectl get -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 >/dev/null 2>&1; then + echo "Pod '{{ include "airlock-microgateway.fullname" . }}-test-backend-0':" + kubectl describe -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 || true + echo "" + echo "" + echo 'Logs of Nginx container:' + kubectl logs -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 -c nginx --tail 5 || true + echo "" + echo "" + # Wait for engine logs + sleep 10s + echo 'Logs of Microgateway Engine container:' + kubectl logs -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 -c airlock-microgateway-engine --tail 5 || true + fi + + exit 1 + } + + create_sidecargateway() { + # create SidecarGateway resource for testing purposes + kubectl delete --ignore-not-found=true -n {{ .Release.Namespace }} sidecargateways.microgateway.airlock.com {{ include "airlock-microgateway.fullname" . }}-test-sidecargateway || true + kubectl apply -f - </dev/null 2>&1; do sleep 1s; i=$((i+1)); done + kubectl logs -f -n {{ .Release.Namespace }} {{ include "airlock-microgateway.fullname" . }}-test-valid-request + kubectl delete pod --ignore-not-found=true -n {{ .Release.Namespace }} {{ include "airlock-microgateway.fullname" . }}-test-valid-request + } + + {{- if .Values.operator.watchNamespaceSelector }} + echo "### Verify that Namespace Selector matches Namespace '{{ .Release.Namespace }}'" + if ! kubectl get namespace -l '{{ include "airlock-microgateway.watchNamespaceSelector.labelQuery" .Values.operator.watchNamespaceSelector }}' | grep -q {{ .Release.Namespace }}; then + labels=$(kubectl get namespace {{ .Release.Namespace }} -o jsonpath={.metadata.labels} | jq | awk '{print " " $0}') + fail {{printf `"Operator namespace '%s' is not part of the operator's watch scope. To execute 'helm test', the selector configured in the helm value 'operator.watchNamespaceSelector' must match the namespace's labels:\n* Current selector:\n%s\n\n* Current labels:\n$labels\n###"` + .Release.Namespace + (replace "\"" "\\\"" (replace "\n" "\\n" (.Values.operator.watchNamespaceSelector | toPrettyJson | indent 2))) + }} + fi + echo "" + {{- end }} + + trap clean_up EXIT + echo "" + + echo "### Waiting for Microgateway Operator Deployments to be ready" + if ! kubectl rollout status -n {{ .Release.Namespace }} --timeout=90s \ + deployments/{{ include "airlock-microgateway.operator.fullname" . }}; then + fail 'Timout occurred' + fi + echo "" + + echo "### Scale '{{ include "airlock-microgateway.fullname" . }}-test-backend' to '1' replica" + # scale to zero replicas to ensure no pods are present from previous runs + kubectl scale -n {{ .Release.Namespace }} statefulset/{{ include "airlock-microgateway.fullname" . }}-test-backend --replicas=0 --timeout=10s + kubectl scale -n {{ .Release.Namespace }} statefulset/{{ include "airlock-microgateway.fullname" . }}-test-backend --replicas=1 --timeout=10s + echo "" + + echo "### Waiting for backend pod" + i=0 + while true; do + if kubectl get -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0; then + break + elif [ $i -gt 3 ]; then + fail 'Pod not ready' + fi + sleep 2s + i=$((i+1)) + done + + echo "### Checking Microgateway Engine sidecar container was injected" + if ! kubectl get -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 -o jsonpath='{.spec.containers[?(@.name=="airlock-microgateway-engine")]}' | grep -q "airlock-microgateway-engine"; then + fail 'Microgateway Engine sidecar container not injected' + fi + echo "True" + echo "" + + echo "### Checking for valid license" + i=0 + while true; do + if [ "$(kubectl get -n {{ .Release.Namespace }} pods/{{ include "airlock-microgateway.fullname" . }}-test-backend-0 -o jsonpath='{.metadata.labels.sidecar\.microgateway\.airlock\.com/licensed}')" = 'true' ]; then + break + elif [ $i -gt 30 ]; then + fail 'Microgateway license is missing or invalid' + fi + sleep 2s + i=$((i+1)) + done + echo "True" + echo "" + + echo "### Create SidecarGateway resource for testing" + if ! create_sidecargateway ; then + fail 'Creation of SidecarGateway resource failed' + fi + echo "" + + echo "### Waiting for '{{ include "airlock-microgateway.fullname" . }}-test-backend' to be ready" + if ! kubectl rollout status -n {{ .Release.Namespace }} statefulset/{{ include "airlock-microgateway.fullname" . }}-test-backend --timeout=90s; then + fail 'Timout occurred' + fi + echo "" + + echo "### Waiting for 'engine-config-valid' condition" + if ! kubectl wait -n {{ .Release.Namespace }} pods --field-selector=metadata.name={{ include "airlock-microgateway.fullname" . }}-test-backend-0 --timeout=90s --for=condition=microgateway.airlock.com/engine-config-valid=True; then + fail 'Configuration was never accepted by the Microgateway Engine' + fi + sleep 5s + echo "" + echo "" + + echo "### Checking whether a valid request is successful and returns HTTP status code '200'" + out=$(curl -vsS --retry 3 --retry-connrefused --connect-timeout 10 "http://{{ include "airlock-microgateway.fullname" . }}-test-service:8080/" || true) + echo "Response:" + echo "${out}" + if ! echo "${out}" | grep -q "200 OK"; then + fail 'A valid request was not successful' + fi + echo "" + echo "" + + echo "### Checking whether a request with an injection attack is blocked and returns HTTP status code '400'" + out=$(curl -vsS --retry 3 --retry-connrefused --connect-timeout 10 "http://{{ include "airlock-microgateway.fullname" . }}-test-service:8080/?token='%20UnION%20all%20select%20A" || true) + echo "Response:" + echo "${out}" + if ! echo "${out}" | grep -q "400 Bad Request"; then + fail 'A malicious request was not blocked' + fi + echo "" + echo "" + + echo "### Installation of '{{ include "airlock-microgateway.fullname" . }}' succeeded" + exit 0 + serviceAccountName: "{{ include "airlock-microgateway.fullname" . }}-tests" +{{- end -}} diff --git a/charts/airlock/microgateway/4.3.4/values.schema.json b/charts/airlock/microgateway/4.3.4/values.schema.json new file mode 100644 index 0000000000..173d6b084c --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/values.schema.json @@ -0,0 +1,540 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "nameOverride": { + "type": "string" + }, + "fullnameOverride": { + "type": "string" + }, + "commonLabels": { + "$ref": "#/definitions/StringMap" + }, + "commonAnnotations": { + "$ref": "#/definitions/StringMap" + }, + "crds": { + "type": "object", + "properties": { + "skipVersionCheck": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "imagePullSecrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name" + ], + "additionalProperties": true + } + }, + "operator": { + "type": "object", + "properties": { + "replicaCount": { + "type": "integer", + "minimum": 0 + }, + "updateStrategy": { + "$ref": "#/definitions/UpdateStrategy" + }, + "image": { + "$ref": "#/definitions/Image" + }, + "podAnnotations": { + "$ref": "#/definitions/StringMap" + }, + "podLabels": { + "$ref": "#/definitions/StringMap" + }, + "serviceAnnotations": { + "$ref": "#/definitions/StringMap" + }, + "serviceLabels": { + "$ref": "#/definitions/StringMap" + }, + "resources": { + "type": "object" + }, + "nodeSelector": { + "$ref": "#/definitions/StringMap" + }, + "tolerations": { + "type": "array", + "items": { + "type": "object" + } + }, + "affinity": { + "type": "object" + }, + "config": { + "type": "object", + "properties": { + "logLevel": { + "type": "string", + "enum": [ + "debug", + "info", + "warn", + "error" + ] + } + }, + "required": [ + "logLevel" + ], + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "annotations": { + "$ref": "#/definitions/StringMap" + }, + "name": { + "type": "string" + } + }, + "required": [ + "annotations", + "create", + "name" + ], + "additionalProperties": false + }, + "watchNamespaces": { + "type": "array", + "items": { + "type": "string" + } + }, + "watchNamespaceSelector": { + "$ref": "#/definitions/LabelSelector" + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + } + }, + "required": [ + "create" + ], + "additionalProperties": false + }, + "serviceMonitor": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "labels": { + "$ref": "#/definitions/StringMap" + } + }, + "required": [ + "create" + ], + "additionalProperties": false + } + }, + "oneOf": [ + { + "properties": { + "watchNamespaces": { + "minItems": 1 + }, + "watchNamespaceSelector": { + "additionalProperties": false + } + } + }, + { + "properties": { + "watchNamespaces": { + "maxItems": 0 + }, + "watchNamespaceSelector": { + "$ref": "#/definitions/LabelSelector" + } + } + } + ], + "required": [ + "affinity", + "config", + "image", + "updateStrategy", + "nodeSelector", + "podAnnotations", + "podLabels", + "rbac", + "replicaCount", + "resources", + "serviceAccount", + "serviceAnnotations", + "serviceLabels", + "serviceMonitor", + "tolerations" + ], + "additionalProperties": false + }, + "engine": { + "type": "object", + "properties": { + "image": { + "$ref": "#/definitions/Image" + }, + "resources": { + "type": "object" + }, + "sidecar": { + "type": "object", + "properties":{ + "podMonitor": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "labels": { + "$ref": "#/definitions/StringMap" + } + }, + "required": [ + "create" + ], + "additionalProperties": false + } + }, + "required": [ + "podMonitor" + ], + "additionalProperties": false + } + }, + "required": [ + "image", + "resources", + "sidecar" + ], + "additionalProperties": false + }, + "networkValidator": { + "type": "object", + "properties": { + "image": { + "$ref": "#/definitions/Image" + } + }, + "required": [ + "image" + ], + "additionalProperties": false + }, + "sessionAgent": { + "type": "object", + "properties": { + "image": { + "$ref": "#/definitions/Image" + }, + "resources": { + "type": "object" + } + }, + "required": [ + "image", + "resources" + ], + "additionalProperties": false + }, + "license": { + "type": "object", + "properties": { + "secretName": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "secretName" + ], + "additionalProperties": false + }, + "dashboards": { + "type": "object", + "properties" : { + "create": { + "type": "boolean" + }, + "config": { + "type": "object", + "properties": { + "grafana": { + "type": "object", + "properties": { + "folderAnnotation": { + "$ref": "#/definitions/NameValuePair" + }, + "dashboardLabel": { + "$ref": "#/definitions/NameValuePair" + } + }, + "required": [ + "folderAnnotation", + "dashboardLabel" + ], + "additionalProperties": false + } + }, + "required": [ + "grafana" + ], + "additionalProperties": false + }, + "instances": { + "type": "object", + "properties": { + "overview": { + "$ref": "#/definitions/DashboardInstance" + }, + "license" : { + "$ref": "#/definitions/DashboardInstance" + }, + "blockMetrics" : { + "$ref": "#/definitions/DashboardInstance" + }, + "blockLogs" : { + "$ref": "#/definitions/DashboardInstance" + } + }, + "required": [ + "overview", + "license", + "blockMetrics", + "blockLogs" + ], + "additionalProperties": false + } + }, + "required": [ + "create", + "config", + "instances" + ], + "additionalProperties": false + }, + "tests": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + }, + "global": { + "type": "object" + } + }, + "required": [ + "commonAnnotations", + "commonLabels", + "crds", + "engine", + "fullnameOverride", + "imagePullSecrets", + "license", + "nameOverride", + "operator", + "networkValidator", + "sessionAgent", + "dashboards", + "tests" + ], + "additionalProperties": false, + "definitions": { + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Image": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "minLength": 1 + }, + "tag": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^$|^sha256:[a-f0-9]{64}$" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "required": [ + "digest", + "pullPolicy", + "repository", + "tag" + ], + "additionalProperties": false + }, + "LabelSelector": { + "type": "object", + "properties": { + "matchExpressions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "operator" + ], + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "matchLabels": { + "$ref": "#/definitions/StringMap" + } + }, + "additionalProperties": false + }, + "UpdateStrategy": { + "type": "object", + "oneOf" : [ + { + "properties": { + "type": { + "$ref": "#/definitions/RecreateType" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "properties": { + "type": { + "$ref": "#/definitions/RollingUpdateType" + }, + "rollingUpdate": { + "$ref": "#/definitions/RollingUpdate" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "RecreateType": { + "type": "string", + "enum": [ + "Recreate" + ] + }, + "RollingUpdateType": { + "type": "string", + "enum": [ + "RollingUpdate" + ] + }, + "RollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "type": ["integer", "string"], + "minimum": 0, + "pattern": "^\\d+%?$" + }, + "maxUnavailable": { + "type": ["integer", "string"], + "minimum": 0, + "pattern": "^\\d+%?$" + } + }, + "anyOf": [ + {"required": ["maxSurge"]}, + {"required": ["maxUnavailable"]} + ], + "additionalProperties": false + }, + "DashboardInstance" : { + "type" : "object", + "properties" : { + "create" : { + "type" : "boolean" + } + }, + "required" : [ + "create" + ], + "additionalProperties": false + }, + "NameValuePair" : { + "type" : "object", + "properties" : { + "name" : { + "type": "string", + "minLength": 1 + }, + "value" : { + "type" : "string", + "minLength": 1 + } + }, + "required" : [ + "name", + "value" + ], + "additionalProperties": false + } + } +} diff --git a/charts/airlock/microgateway/4.3.4/values.yaml b/charts/airlock/microgateway/4.3.4/values.yaml new file mode 100644 index 0000000000..af720d5c62 --- /dev/null +++ b/charts/airlock/microgateway/4.3.4/values.yaml @@ -0,0 +1,213 @@ +# -- Allows overriding the name to use instead of "microgateway". +nameOverride: "" +# -- Allows overriding the name to use as full name of resources. +fullnameOverride: "" +# -- Labels to add to all resources. +commonLabels: {} +# -- Annotations to add to all resources. +commonAnnotations: {} +# -- ImagePullSecrets to use when pulling images. +imagePullSecrets: [] +# - name: myRegistryKeySecretName + +crds: + # -- Whether to skip the sanity check which prevents installing/upgrading the helm chart in a cluster with outdated Airlock Microgateway CRDs. + # The check aims to prevent unexpected behavior and issues due to Helm v3 not automatically upgrading CRDs which are already present in the cluster + # when performing a "helm install/upgrade". + skipVersionCheck: false +operator: + # -- Number of replicas for the operator Deployment. + replicaCount: 2 + # -- Specifies the operator update strategy. + updateStrategy: + type: RollingUpdate + # Specifies the Airlock Microgateway Operator image. + image: + # -- Image repository from which to pull the Airlock Microgateway Operator image. + repository: "quay.io/airlock/microgateway-operator" + # -- Image tag to pull. + tag: "4.3.4" + # -- SHA256 image digest to pull (in the format "sha256:c79ee3f85862fb386e9dd62b901b607161d27807f512d7fbdece05e9ee3d7c63"). + # Overrides tag when specified. + digest: "sha256:6819c78d5570de66edce6c13964c6e1b4cc4746d0c0bc6f4975cd38e324828c0" + # -- Pull policy for this image. + pullPolicy: IfNotPresent + # -- Annotations to add to all Pods. + podAnnotations: {} + # -- Labels to add to all Pods. + podLabels: {} + # -- Annotations to add to the Service. + serviceAnnotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "8080" + + # -- Labels to add to the Service. + serviceLabels: {} + # -- Resource restrictions to apply to the operator container. + resources: {} + # We recommend at least the following resource specification. + # limits: + # cpu: 1000m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 512Mi + + # -- Custom nodeSelector to apply to the operator Deployment in order to constrain its Pods to certain nodes. + nodeSelector: {} + # -- Custom tolerations to apply to the operator Deployment in order to allow its Pods to run on tainted nodes. + tolerations: [] + # -- Custom affinity to apply to the operator Deployment. Used to influence the scheduling. + affinity: {} + # Parameters for the operator configuration. + config: + # -- Operator application log level. + logLevel: "info" + # Configures the generation of the ServiceAccount. + serviceAccount: + # -- Whether a ServiceAccount should be created. + create: true + # -- Annotations to add to the ServiceAccount. + annotations: {} + # -- Name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template. + name: "" + # -- Allows to restrict the operator to specific namespaces, depending on your needs. + # For a `OwnNamespace` or `SingleNamespace` installation the list may only contain one namespace (e.g., `watchNamespaces: ["airlock-microgateway-system"]`). + # In case of the `OwnNamespace` installation mode the specified namespace should be equal to the installation namespace. + # For a static `MultiNamespace` installation, the complete list of namespaces must be provided in the `watchNamespaces`. + # An `AllNamespaces` installation or the usage of the `watchNamespaceSelector` requires the `watchNamespaces` to be empty. + # Regardless of the installation modes supported by `watchNamespaces`, RBAC is created only namespace-scoped (using Roles and RoleBindings) in the respective namespaces. + # Please note that this feature requires a Premium license. + watchNamespaces: [] + # -- Allows to dynamically select watch namespaces of the operator and the scope of the webhooks based on a Namespace label selector. + # It is able to detect and reconcile resources in all namespaces that match the label selector automatically, even for new namespaces, without restarting the operator. + # This facilitates a dynamic `MultiNamespace` installation mode, but still requires cluster-scoped permissions (i.e., ClusterRoles and ClusterRoleBindings). + # An `AllNamespaces` installation or the usage of the `watchNamespaces` requires the `watchNamespaceSelector` to be empty. + # Please note that this feature requires a Premium license. + watchNamespaceSelector: {} + # For further examples, see: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements. + # matchLabels: + # microgateway.airlock.com/enable: "true" + # matchExpressions: + # - { key: environment, operator: NotIn, values: [dev] } + + # Configures the generation of Role and RoleBinding as well as ClusterRoles and ClusterRoleBinding pairs for the ServiceAccount specified above. + rbac: + # -- Whether to create RBAC resources which are required for the Airlock Microgateway Operator to function. + create: true + # Configures the generation of a Prometheus Operator ServiceMonitor. + serviceMonitor: + # -- Whether to create a ServiceMonitor resource for monitoring. + create: false + # -- Labels to add to the ServiceMonitor. + labels: {} + # release: "" +engine: + # Specifies the Airlock Microgateway Engine image. + image: + # -- Image repository from which to pull the Airlock Microgateway Engine image. + repository: "quay.io/airlock/microgateway-engine" + # -- Image tag to pull. + tag: "4.3.4" + # -- SHA256 image digest to pull (in the format "sha256:a3051f42d3013813b05f7513bb86ed6a3209cb3003f1bb2f7b72df249aa544d3"). + # Overrides tag when specified. + digest: "sha256:91e05c509bed3b51ff4888d7475980d56cbc85db121aa766d1bde413204f9070" + # -- Pull policy for this image. + pullPolicy: IfNotPresent + # -- Resource restrictions to apply to the Airlock Microgateway Engine container. + resources: {} + # We recommend at least the following resource specification. + # limits: + # cpu: 500m + # memory: 128Mi + # requests: + # cpu: 10m + # memory: 40Mi + + # Additional configuration when deployed as a sidecar. + sidecar: + # Configures the generation of a Prometheus Operator PodMonitor. + podMonitor: + # -- Whether to create a PodMonitor resource for monitoring. + create: false + # -- Labels to add to the PodMonitor. + labels: {} + # release: "" +networkValidator: + # Specifies the Airlock Microgateway Network Validator image to be injected as an init-container. + image: + # -- Image repository from which to pull the netcat image for the Airlock Microgateway Network Validator init-container. + repository: "cgr.dev/chainguard/netcat" + # -- Image tag to pull. + tag: "" + # -- SHA256 image digest to pull (in the format "sha256:7a73d4b82a2d4165bbc5efa55de4fee9d43f2b1c1edb3505cdc8afd1361bad9b"). + # Overrides tag when specified. + digest: "sha256:7a73d4b82a2d4165bbc5efa55de4fee9d43f2b1c1edb3505cdc8afd1361bad9b" + # -- Pull policy for this image. + pullPolicy: IfNotPresent +sessionAgent: + # Specifies the Airlock Microgateway Session Agent image. + image: + # -- Image repository from which to pull the Airlock Microgateway Session Agent image. + repository: "quay.io/airlock/microgateway-session-agent" + # -- Image tag to pull. + tag: "4.3.4" + # -- SHA256 image digest to pull (in the format "sha256:a3051f42d3013813b05f7513bb86ed6a3209cb3003f1bb2f7b72df249aa544d3"). + # Overrides tag when specified. + digest: "sha256:df4e50d0929cb4c5e4486452979b59ec17f5e49a1516b685acd3a1ab0ddb3cf4" + # -- Pull policy for this image. + pullPolicy: IfNotPresent + # -- Resource restrictions to apply to the Airlock Microgateway Session Agent container. + resources: {} + # We recommend at least the following resource specification. + # limits: + # cpu: 150m + # memory: 32Mi + # requests: + # cpu: 10m + # memory: 8Mi +license: + # -- Name of the secret containing the "microgateway-license.txt" key. + secretName: "airlock-microgateway-license" +# Creates dashboards in the form of ConfigMaps that can be imported +# by Grafana using its sidecar setup. +dashboards: + # -- Whether to create any ConfigMaps containing Grafana dashboards to import. + create: false + config: + # Configures the necessary label and annotations along with their values + # to enable Grafana to correctly identify the ConfigMaps containing + # dashboards and file them within a dedicated folder in the dashboard overview. + # These settings need to match the Grafana sidecar configuration. + grafana: + folderAnnotation: + # -- Name of the annotation containing the folder name to file dashboards into. + name: "grafana_folder" + # -- Name of the folder dashboards are filed into within the Grafana UI. + value: "Airlock Microgateway" + dashboardLabel: + # -- Name of the label that lets Grafana identify ConfigMaps that represent dashboards. + name: "grafana_dashboard" + # -- Value of the label that lets Grafana identify ConfigMaps that represent dashboards. + value: "1" + instances: + # Available dashboard instances that can be individually created/deployed. + overview: + # -- Whether to create the overview dashboard. + create: true + license: + # -- Whether to create the license dashboard. + create: true + blockMetrics: + # -- Whether to create the block metrics dashboard. + create: true + blockLogs: + # -- Whether to create the block logs dashboard. + create: true +# Check whether the installation of the Airlock Microgateway Helm Chart was successful. +# Requires a secret with a valid Airlock Microgateway license key already to be present. +tests: + # -- Whether additional resources required for running `helm test` should be created (e.g. Roles and ServiceAccounts). + # If set to false, `helm test` will not run any tests. + enabled: false diff --git a/charts/codefresh/cf-runtime/6.4.6/.helmignore b/charts/codefresh/cf-runtime/6.4.6/.helmignore new file mode 100644 index 0000000000..bc71d4240b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/.helmignore @@ -0,0 +1,3 @@ +tests/ +.ci/ +test-values/ \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/Chart.yaml b/charts/codefresh/cf-runtime/6.4.6/Chart.yaml new file mode 100644 index 0000000000..6c78aa4470 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/Chart.yaml @@ -0,0 +1,28 @@ +annotations: + artifacthub.io/changes: | + - kind: fixed + description: "updated docker-builder version to allow users to specify the qemu image on docker builds" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime +apiVersion: v2 +dependencies: +- name: cf-common + repository: oci://quay.io/codefresh/charts + version: 0.16.0 +description: A Helm chart for Codefresh Runner +home: https://codefresh.io/ +icon: file://assets/icons/cf-runtime.png +keywords: +- codefresh +- runner +kubeVersion: '>=1.18-0' +maintainers: +- name: codefresh + url: https://codefresh-io.github.io/ +name: cf-runtime +sources: +- https://github.com/codefresh-io/venona +version: 6.4.6 diff --git a/charts/codefresh/cf-runtime/6.4.6/README.md b/charts/codefresh/cf-runtime/6.4.6/README.md new file mode 100644 index 0000000000..4e1ec3ddc1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/README.md @@ -0,0 +1,1230 @@ +## Codefresh Runner + +![Version: 6.4.6](https://img.shields.io/badge/Version-6.4.6-informational?style=flat-square) + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}_{{ .Release.Namespace }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}/{{ .Release.Namespace }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ .Release.Namespace }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ .Release.Namespace }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{.data.token}}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| oci://quay.io/codefresh/charts | cf-common | 0.16.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| appProxy.affinity | object | `{}` | Set affinity | +| appProxy.enabled | bool | `false` | Enable app-proxy | +| appProxy.env | object | `{}` | Add additional env vars | +| appProxy.image | object | `{"registry":"quay.io","repository":"codefresh/cf-app-proxy","tag":"0.0.47"}` | Set image | +| appProxy.ingress.annotations | object | `{}` | Set extra annotations for ingress object | +| appProxy.ingress.class | string | `""` | Set ingress class | +| appProxy.ingress.host | string | `""` | Set DNS hostname the ingress will use | +| appProxy.ingress.pathPrefix | string | `""` | Set path prefix for ingress (keep empty for default `/` path) | +| appProxy.ingress.tlsSecret | string | `""` | Set k8s tls secret for the ingress object | +| appProxy.nodeSelector | object | `{}` | Set node selector | +| appProxy.podAnnotations | object | `{}` | Set pod annotations | +| appProxy.podSecurityContext | object | `{}` | Set security context for the pod | +| appProxy.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| appProxy.rbac.create | bool | `true` | Create RBAC resources | +| appProxy.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.rbac.rules | list | `[]` | Add custom rule to the role | +| appProxy.readinessProbe | object | See below | Readiness probe configuration | +| appProxy.replicasCount | int | `1` | Set number of pods | +| appProxy.resources | object | `{}` | Set requests and limits | +| appProxy.serviceAccount | object | `{"annotations":{},"create":true,"name":"","namespaced":true}` | Service Account parameters | +| appProxy.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| appProxy.serviceAccount.create | bool | `true` | Create service account | +| appProxy.serviceAccount.name | string | `""` | Override service account name | +| appProxy.serviceAccount.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.tolerations | list | `[]` | Set tolerations | +| appProxy.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| dockerRegistry | string | `""` | | +| event-exporter | object | See below | Event exporter parameters | +| event-exporter.affinity | object | `{}` | Set affinity | +| event-exporter.enabled | bool | `false` | Enable event-exporter | +| event-exporter.env | object | `{}` | Add additional env vars | +| event-exporter.image | object | `{"registry":"docker.io","repository":"codefresh/k8s-event-exporter","tag":"latest"}` | Set image | +| event-exporter.nodeSelector | object | `{}` | Set node selector | +| event-exporter.podAnnotations | object | `{}` | Set pod annotations | +| event-exporter.podSecurityContext | object | See below | Set security context for the pod | +| event-exporter.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| event-exporter.rbac.create | bool | `true` | Create RBAC resources | +| event-exporter.rbac.rules | list | `[]` | Add custom rule to the role | +| event-exporter.replicasCount | int | `1` | Set number of pods | +| event-exporter.resources | object | `{}` | Set resources | +| event-exporter.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| event-exporter.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| event-exporter.serviceAccount.create | bool | `true` | Create service account | +| event-exporter.serviceAccount.name | string | `""` | Override service account name | +| event-exporter.tolerations | list | `[]` | Set tolerations | +| event-exporter.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | +| extraResources | list | `[]` | Array of extra objects to deploy with the release | +| fullnameOverride | string | `""` | String to fully override cf-runtime.fullname template | +| global | object | See below | Global parameters | +| global.accountId | string | `""` | Account ID (required!) Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information | +| global.agentName | string | `""` | Agent Name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` | +| global.agentToken | string | `""` | DEPRECATED Agent token in plain text. !!! MUST BE provided if migrating from < 6.x chart version | +| global.agentTokenSecretKeyRef | object | `{}` | DEPRECATED Agent token that references an existing secret containing API key. !!! MUST BE provided if migrating from < 6.x chart version | +| global.codefreshHost | string | `"https://g.codefresh.io"` | URL of Codefresh Platform (required!) | +| global.codefreshToken | string | `""` | User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) Ref: https://g.codefresh.io/user/settings (see API Keys) Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) | +| global.codefreshTokenSecretKeyRef | object | `{}` | User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) | +| global.context | string | `""` | K8s context name (required!) | +| global.imagePullSecrets | list | `[]` | Global Docker registry secret names as array | +| global.imageRegistry | string | `""` | Global Docker image registry | +| global.runtimeName | string | `""` | Runtime name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` | +| monitor.affinity | object | `{}` | Set affinity | +| monitor.enabled | bool | `false` | Enable monitor Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component | +| monitor.env | object | `{}` | Add additional env vars | +| monitor.image | object | `{"registry":"quay.io","repository":"codefresh/cf-k8s-agent","tag":"1.3.18"}` | Set image | +| monitor.nodeSelector | object | `{}` | Set node selector | +| monitor.podAnnotations | object | `{}` | Set pod annotations | +| monitor.podSecurityContext | object | `{}` | | +| monitor.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| monitor.rbac.create | bool | `true` | Create RBAC resources | +| monitor.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| monitor.rbac.rules | list | `[]` | Add custom rule to the role | +| monitor.readinessProbe | object | See below | Readiness probe configuration | +| monitor.replicasCount | int | `1` | Set number of pods | +| monitor.resources | object | `{}` | Set resources | +| monitor.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| monitor.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| monitor.serviceAccount.create | bool | `true` | Create service account | +| monitor.serviceAccount.name | string | `""` | Override service account name | +| monitor.tolerations | list | `[]` | Set tolerations | +| monitor.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| nameOverride | string | `""` | String to partially override cf-runtime.fullname template (will maintain the release name) | +| podMonitor | object | See below | Add podMonitor (for engine pods) | +| podMonitor.main.enabled | bool | `false` | Enable pod monitor for engine pods | +| podMonitor.runner.enabled | bool | `false` | Enable pod monitor for runner pod | +| podMonitor.volume-provisioner.enabled | bool | `false` | Enable pod monitor for volumeProvisioner pod | +| re | object | `{}` | | +| runner | object | See below | Runner parameters | +| runner.affinity | object | `{}` | Set affinity | +| runner.enabled | bool | `true` | Enable the runner | +| runner.env | object | `{}` | Add additional env vars | +| runner.image | object | `{"registry":"quay.io","repository":"codefresh/venona","tag":"1.10.2"}` | Set image | +| runner.init | object | `{"image":{"registry":"quay.io","repository":"codefresh/cli","tag":"0.85.0-rootless"},"resources":{"limits":{"cpu":"1","memory":"512Mi"},"requests":{"cpu":"0.2","memory":"256Mi"}}}` | Init container | +| runner.nodeSelector | object | `{}` | Set node selector | +| runner.podAnnotations | object | `{}` | Set pod annotations | +| runner.podSecurityContext | object | See below | Set security context for the pod | +| runner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runner.rbac.create | bool | `true` | Create RBAC resources | +| runner.rbac.rules | list | `[]` | Add custom rule to the role | +| runner.readinessProbe | object | See below | Readiness probe configuration | +| runner.replicasCount | int | `1` | Set number of pods | +| runner.resources | object | `{}` | Set requests and limits | +| runner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| runner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| runner.serviceAccount.create | bool | `true` | Create service account | +| runner.serviceAccount.name | string | `""` | Override service account name | +| runner.sidecar | object | `{"enabled":false,"env":{"RECONCILE_INTERVAL":300},"image":{"registry":"quay.io","repository":"codefresh/codefresh-shell","tag":"0.0.2"},"resources":{}}` | Sidecar container Reconciles runtime spec from Codefresh API for drift detection | +| runner.tolerations | list | `[]` | Set tolerations | +| runner.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| runtime | object | See below | Set runtime parameters | +| runtime.accounts | list | `[]` | (for On-Premise only) Assign accounts to runtime (list of account ids) | +| runtime.agent | bool | `true` | (for On-Premise only) Enable agent | +| runtime.description | string | `""` | Runtime description | +| runtime.dind | object | `{"affinity":{},"env":{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"pvcs":{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}},"resources":{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null},"schedulerName":"","serviceAccount":"codefresh-engine","terminationGracePeriodSeconds":30,"tolerations":[],"userAccess":true,"userVolumeMounts":{},"userVolumes":{}}` | Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). | +| runtime.dind.affinity | object | `{}` | Set affinity | +| runtime.dind.env | object | `{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true}` | Set additional env vars. | +| runtime.dind.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"}` | Set dind image. | +| runtime.dind.nodeSelector | object | `{}` | Set node selector. | +| runtime.dind.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.dind.podLabels | object | `{}` | Set pod labels. | +| runtime.dind.pvcs | object | `{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}}` | PV claim spec parametes. | +| runtime.dind.pvcs.dind | object | `{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}` | Default dind PVC parameters | +| runtime.dind.pvcs.dind.annotations | object | `{}` | PV annotations. | +| runtime.dind.pvcs.dind.name | string | `"dind"` | PVC name prefix. Keep `dind` as default! Don't change! | +| runtime.dind.pvcs.dind.reuseVolumeSelector | string | `"codefresh-app,io.codefresh.accountName"` | PV reuse selector. Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy | +| runtime.dind.pvcs.dind.storageClassName | string | `"{{ include \"dind-volume-provisioner.storageClassName\" . }}"` | PVC storage class name. Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner | +| runtime.dind.pvcs.dind.volumeSize | string | `"16Gi"` | PVC size. | +| runtime.dind.resources | object | `{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null}` | Set dind resources. | +| runtime.dind.schedulerName | string | `""` | Set scheduler name. | +| runtime.dind.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.dind.terminationGracePeriodSeconds | int | `30` | Set termination grace period. | +| runtime.dind.tolerations | list | `[]` | Set tolerations. | +| runtime.dind.userAccess | bool | `true` | Keep `true` as default! | +| runtime.dind.userVolumeMounts | object | `{}` | Add extra volume mounts | +| runtime.dind.userVolumes | object | `{}` | Add extra volumes | +| runtime.dindDaemon | object | See below | DinD pod daemon config | +| runtime.engine | object | `{"affinity":{},"command":["npm","run","start"],"env":{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.174.13"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"resources":{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}},"runtimeImages":{"COMPOSE_IMAGE":"quay.io/codefresh/compose:v2.28.1-1.5.0","CONTAINER_LOGGER_IMAGE":"quay.io/codefresh/cf-container-logger:1.11.7","COSIGN_IMAGE_SIGNER_IMAGE":"quay.io/codefresh/cf-cosign-image-signer:2.4.0-cf.2","CR_6177_FIXER":"quay.io/codefresh/alpine:edge","DOCKER_BUILDER_IMAGE":"quay.io/codefresh/cf-docker-builder:1.3.14","DOCKER_PULLER_IMAGE":"quay.io/codefresh/cf-docker-puller:8.0.18","DOCKER_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-pusher:6.0.16","DOCKER_TAG_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-tag-pusher:1.3.14","FS_OPS_IMAGE":"quay.io/codefresh/fs-ops:1.2.3","GC_BUILDER_IMAGE":"quay.io/codefresh/cf-gc-builder:0.5.3","GIT_CLONE_IMAGE":"quay.io/codefresh/cf-git-cloner:10.1.28","KUBE_DEPLOY":"quay.io/codefresh/cf-deploy-kubernetes:16.1.11","PIPELINE_DEBUGGER_IMAGE":"quay.io/codefresh/cf-debugger:1.3.6","TEMPLATE_ENGINE":"quay.io/codefresh/pikolo:0.14.1"},"schedulerName":"","serviceAccount":"codefresh-engine","terminationGracePeriodSeconds":180,"tolerations":[],"userEnvVars":[],"workflowLimits":{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}}` | Parameters for Engine pod (aka "pipeline" orchestrator). | +| runtime.engine.affinity | object | `{}` | Set affinity | +| runtime.engine.command | list | `["npm","run","start"]` | Set container command. | +| runtime.engine.env | object | `{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100}` | Set additional env vars. | +| runtime.engine.env.CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS | int | `1000` | Interval to check the exec status in the container-logger | +| runtime.engine.env.DOCKER_REQUEST_TIMEOUT_MS | int | `30000` | Timeout while doing requests to the Docker daemon | +| runtime.engine.env.FORCE_COMPOSE_SERIAL_PULL | bool | `false` | If "true", composition images will be pulled sequentially | +| runtime.engine.env.LOGGER_LEVEL | string | `"debug"` | Level of logging for engine | +| runtime.engine.env.LOG_OUTGOING_HTTP_REQUESTS | bool | `false` | Enable debug-level logging of outgoing HTTP/HTTPS requests | +| runtime.engine.env.METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS | bool | `false` | Enable collecting process metrics | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLED | bool | `true` | Enable emitting metrics from engine | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS | bool | `false` | Enable legacy metrics | +| runtime.engine.env.METRICS_PROMETHEUS_HOST | string | `"0.0.0.0"` | Host for Prometheus metrics server | +| runtime.engine.env.METRICS_PROMETHEUS_PORT | int | `9100` | Port for Prometheus metrics server | +| runtime.engine.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.174.13"}` | Set image. | +| runtime.engine.nodeSelector | object | `{}` | Set node selector. | +| runtime.engine.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.engine.podLabels | object | `{}` | Set pod labels. | +| runtime.engine.resources | object | `{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}` | Set resources. | +| runtime.engine.runtimeImages | object | See below. | Set system(base) runtime images. | +| runtime.engine.schedulerName | string | `""` | Set scheduler name. | +| runtime.engine.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.engine.terminationGracePeriodSeconds | int | `180` | Set termination grace period. | +| runtime.engine.tolerations | list | `[]` | Set tolerations. | +| runtime.engine.userEnvVars | list | `[]` | Set extra env vars | +| runtime.engine.workflowLimits | object | `{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}` | Set workflow limits. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS | int | `600` | Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION | int | `86400` | Maximum time for workflow execution; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ELECTED_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "elected" state; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_RETRY_ATTEMPTS_ALLOWED | int | `20` | Maximum retry attempts allowed for workflow. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE | int | `300` | Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_TERMINATION | int | `300` | Time since the last health check report after which workflow is terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY | int | `60` | Time since the last health check report after which the engine is considered unhealthy; seconds. | +| runtime.engine.workflowLimits.TIME_INACTIVE_UNTIL_TERMINATION | int | `2700` | Time since the last workflow logs activity after which workflow is terminated; seconds. | +| runtime.gencerts | object | See below | Parameters for `gencerts-dind` post-upgrade/install hook | +| runtime.inCluster | bool | `true` | (for On-Premise only) Set inCluster runtime | +| runtime.patch | object | See below | Parameters for `runtime-patch` post-upgrade/install hook | +| runtime.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runtime.rbac.create | bool | `true` | Create RBAC resources | +| runtime.rbac.rules | list | `[]` | Add custom rule to the engine role | +| runtime.runtimeExtends | list | `["system/default/hybrid/k8s_low_limits"]` | Set parent runtime to inherit. Should not be changes. Parent runtime is controlled from Codefresh side. | +| runtime.serviceAccount | object | `{"annotations":{},"create":true}` | Set annotation on engine Service Account Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster | +| serviceMonitor | object | See below | Add serviceMonitor | +| serviceMonitor.main.enabled | bool | `false` | Enable service monitor for dind pods | +| storage.azuredisk.cachingMode | string | `"None"` | | +| storage.azuredisk.skuName | string | `"Premium_LRS"` | Set storage type (`Premium_LRS`) | +| storage.backend | string | `"local"` | Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) | +| storage.ebs.accessKeyId | string | `""` | Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.accessKeyIdSecretKeyRef | object | `{}` | Existing secret containing AWS_ACCESS_KEY_ID. | +| storage.ebs.availabilityZone | string | `"us-east-1a"` | Set EBS volumes availability zone (required) | +| storage.ebs.encrypted | string | `"false"` | Enable encryption (optional) | +| storage.ebs.kmsKeyId | string | `""` | Set KMS encryption key ID (optional) | +| storage.ebs.secretAccessKey | string | `""` | Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.secretAccessKeySecretKeyRef | object | `{}` | Existing secret containing AWS_SECRET_ACCESS_KEY | +| storage.ebs.volumeType | string | `"gp2"` | Set EBS volume type (`gp2`/`gp3`/`io1`) (required) | +| storage.fsType | string | `"ext4"` | Set filesystem type (`ext4`/`xfs`) | +| storage.gcedisk.availabilityZone | string | `"us-west1-a"` | Set GCP volume availability zone | +| storage.gcedisk.serviceAccountJson | string | `""` | Set Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.serviceAccountJsonSecretKeyRef | object | `{}` | Existing secret containing containing Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.volumeType | string | `"pd-ssd"` | Set GCP volume backend type (`pd-ssd`/`pd-standard`) | +| storage.local.volumeParentDir | string | `"/var/lib/codefresh/dind-volumes"` | Set volume path on the host filesystem | +| storage.mountAzureJson | bool | `false` | | +| volumeProvisioner | object | See below | Volume Provisioner parameters | +| volumeProvisioner.affinity | object | `{}` | Set affinity | +| volumeProvisioner.dind-lv-monitor | object | See below | `dind-lv-monitor` DaemonSet parameters (local volumes cleaner) | +| volumeProvisioner.enabled | bool | `true` | Enable volume-provisioner | +| volumeProvisioner.env | object | `{}` | Add additional env vars | +| volumeProvisioner.image | object | `{"registry":"quay.io","repository":"codefresh/dind-volume-provisioner","tag":"1.35.0"}` | Set image | +| volumeProvisioner.nodeSelector | object | `{}` | Set node selector | +| volumeProvisioner.podAnnotations | object | `{}` | Set pod annotations | +| volumeProvisioner.podSecurityContext | object | See below | Set security context for the pod | +| volumeProvisioner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| volumeProvisioner.rbac.create | bool | `true` | Create RBAC resources | +| volumeProvisioner.rbac.rules | list | `[]` | Add custom rule to the role | +| volumeProvisioner.replicasCount | int | `1` | Set number of pods | +| volumeProvisioner.resources | object | `{}` | Set resources | +| volumeProvisioner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| volumeProvisioner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| volumeProvisioner.serviceAccount.create | bool | `true` | Create service account | +| volumeProvisioner.serviceAccount.name | string | `""` | Override service account name | +| volumeProvisioner.tolerations | list | `[]` | Set tolerations | +| volumeProvisioner.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | + diff --git a/charts/codefresh/cf-runtime/6.4.6/README.md.gotmpl b/charts/codefresh/cf-runtime/6.4.6/README.md.gotmpl new file mode 100644 index 0000000000..96e5ca5748 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/README.md.gotmpl @@ -0,0 +1,1007 @@ +## Codefresh Runner + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}_{{ .Release.Namespace }}` }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}/{{ .Release.Namespace }}` }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ "{{ .Release.Namespace }}" }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ "{{ .Release.Namespace }}" }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{ `{{.data.token}}` }}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{ `{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}` }}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}` }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}` }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + diff --git a/charts/codefresh/cf-runtime/6.4.6/files/cleanup-runtime.sh b/charts/codefresh/cf-runtime/6.4.6/files/cleanup-runtime.sh new file mode 100644 index 0000000000..c1fc5f3682 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/files/cleanup-runtime.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "AGENT: ${AGENT}" +echo "AGENT_SECRET_NAME: ${AGENT_SECRET_NAME}" +echo "DIND_SECRET_NAME: ${DIND_SECRET_NAME}" +echo "-----" + +auth() { + codefresh auth create-context --api-key ${API_TOKEN} --url ${API_HOST} +} + +remove_runtime() { + if [ "$AGENT" == "true" ]; then + codefresh delete re ${RUNTIME_NAME} || true + else + codefresh delete sys-re ${RUNTIME_NAME} || true + fi +} + +remove_agent() { + codefresh delete agent ${AGENT_NAME} || true +} + +remove_secrets() { + kubectl patch secret $(kubectl get secret -l codefresh.io/internal=true | awk 'NR>1{print $1}' | xargs) -p '{"metadata":{"finalizers":null}}' --type=merge || true + kubectl delete secret $AGENT_SECRET_NAME || true + kubectl delete secret $DIND_SECRET_NAME || true +} + +auth +remove_runtime +remove_agent +remove_secrets \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/files/configure-dind-certs.sh b/charts/codefresh/cf-runtime/6.4.6/files/configure-dind-certs.sh new file mode 100644 index 0000000000..a1092eb1e6 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/files/configure-dind-certs.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# + +#--- +fatal() { + echo "ERROR: $1" + exit 1 +} + +msg() { echo -e "\e[32mINFO ---> $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + +exit_trap () { + local lc="$BASH_COMMAND" rc=$? + if [ $rc != 0 ]; then + if [[ -n "$SLEEP_ON_ERROR" ]]; then + echo -e "\nSLEEP_ON_ERROR is set - Sleeping to fix error" + sleep $SLEEP_ON_ERROR + fi + fi +} +trap exit_trap EXIT + +usage() { + echo "Usage: + $0 [-n | --namespace] [--server-cert-cn] [--server-cert-extra-sans] codefresh-api-host codefresh-api-token + +Example: + $0 -n workflow https://g.codefresh.io 21341234.423141234.412431234 + +" +} + +# Args +while [[ $1 =~ ^(-(n|h)|--(namespace|server-cert-cn|server-cert-extra-sans|help)) ]] +do + key=$1 + value=$2 + + case $key in + -h|--help) + usage + exit + ;; + -n|--namespace) + NAMESPACE="$value" + shift + ;; + --server-cert-cn) + SERVER_CERT_CN="$value" + shift + ;; + --server-cert-extra-sans) + SERVER_CERT_EXTRA_SANS="$value" + shift + ;; + esac + shift # past argument or value +done + +API_HOST=${1:-"$CF_API_HOST"} +API_TOKEN=${2:-"$CF_API_TOKEN"} + +[[ -z "$API_HOST" ]] && usage && fatal "Missing API_HOST" +[[ -z "$API_TOKEN" ]] && usage && fatal "Missing token" + + +API_SIGN_PATH=${API_SIGN_PATH:-"api/custom_clusters/signServerCerts"} + +NAMESPACE=${NAMESPACE:-default} +RELEASE=${RELEASE:-cf-runtime} + +DIR=$(dirname $0) +TMPDIR=/tmp/codefresh/ + +TMP_CERTS_FILE_ZIP=$TMPDIR/cf-certs.zip +TMP_CERTS_HEADERS_FILE=$TMPDIR/cf-certs-response-headers.txt +CERTS_DIR=$TMPDIR/ssl +SRV_TLS_CA_CERT=${CERTS_DIR}/ca.pem +SRV_TLS_KEY=${CERTS_DIR}/server-key.pem +SRV_TLS_CSR=${CERTS_DIR}/server-cert.csr +SRV_TLS_CERT=${CERTS_DIR}/server-cert.pem +CF_SRV_TLS_CERT=${CERTS_DIR}/cf-server-cert.pem +CF_SRV_TLS_CA_CERT=${CERTS_DIR}/cf-ca.pem +mkdir -p $TMPDIR $CERTS_DIR + +K8S_CERT_SECRET_NAME=codefresh-certs-server +echo -e "\n------------------\nGenerating server tls certificates ... " + +SERVER_CERT_CN=${SERVER_CERT_CN:-"docker.codefresh.io"} +SERVER_CERT_EXTRA_SANS="${SERVER_CERT_EXTRA_SANS}" +### + + openssl genrsa -out $SRV_TLS_KEY 4096 || fatal "Failed to generate openssl key " + openssl req -subj "/CN=${SERVER_CERT_CN}" -new -key $SRV_TLS_KEY -out $SRV_TLS_CSR || fatal "Failed to generate openssl csr " + GENERATE_CERTS=true + CSR=$(sed ':a;N;$!ba;s/\n/\\n/g' ${SRV_TLS_CSR}) + + SERVER_CERT_SANS="IP:127.0.0.1,DNS:dind,DNS:*.dind.${NAMESPACE},DNS:*.dind.${NAMESPACE}.svc${KUBE_DOMAIN},DNS:*.cf-cd.com,DNS:*.codefresh.io" + if [[ -n "${SERVER_CERT_EXTRA_SANS}" ]]; then + SERVER_CERT_SANS=${SERVER_CERT_SANS},${SERVER_CERT_EXTRA_SANS} + fi + echo "{\"reqSubjectAltName\": \"${SERVER_CERT_SANS}\", \"csr\": \"${CSR}\" }" > ${TMPDIR}/sign_req.json + + rm -fv ${TMP_CERTS_HEADERS_FILE} ${TMP_CERTS_FILE_ZIP} + + SIGN_STATUS=$(curl -k -sSL -d @${TMPDIR}/sign_req.json -H "Content-Type: application/json" -H "Authorization: ${API_TOKEN}" -H "Expect: " \ + -o ${TMP_CERTS_FILE_ZIP} -D ${TMP_CERTS_HEADERS_FILE} -w '%{http_code}' ${API_HOST}/${API_SIGN_PATH} ) + + echo "Sign request completed with HTTP_STATUS_CODE=$SIGN_STATUS" + if [[ $SIGN_STATUS != 200 ]]; then + echo "ERROR: Cannot sign certificates" + if [[ -f ${TMP_CERTS_FILE_ZIP} ]]; then + mv ${TMP_CERTS_FILE_ZIP} ${TMP_CERTS_FILE_ZIP}.error + cat ${TMP_CERTS_FILE_ZIP}.error + fi + exit 1 + fi + unzip -o -d ${CERTS_DIR}/ ${TMP_CERTS_FILE_ZIP} || fatal "Failed to unzip certificates to ${CERTS_DIR} " + cp -v ${CF_SRV_TLS_CA_CERT} $SRV_TLS_CA_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains ca.pem" + cp -v ${CF_SRV_TLS_CERT} $SRV_TLS_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains cf-server-cert.pem" + + +echo -e "\n------------------\nCreating certificate secret " + +kubectl -n $NAMESPACE create secret generic $K8S_CERT_SECRET_NAME \ + --from-file=$SRV_TLS_CA_CERT \ + --from-file=$SRV_TLS_KEY \ + --from-file=$SRV_TLS_CERT \ + --dry-run=client -o yaml | kubectl apply --overwrite -f - +kubectl -n $NAMESPACE label --overwrite secret ${K8S_CERT_SECRET_NAME} codefresh.io/internal=true +kubectl -n $NAMESPACE patch secret $K8S_CERT_SECRET_NAME -p '{"metadata": {"finalizers": ["kubernetes"]}}' diff --git a/charts/codefresh/cf-runtime/6.4.6/files/init-runtime.sh b/charts/codefresh/cf-runtime/6.4.6/files/init-runtime.sh new file mode 100644 index 0000000000..eb3488af11 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/files/init-runtime.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "KUBE_CONTEXT: ${KUBE_CONTEXT}" +echo "KUBE_NAMESPACE: ${KUBE_NAMESPACE}" +echo "OWNER_NAME: ${OWNER_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "SECRET_NAME: ${SECRET_NAME}" +echo "-----" + +create_agent_secret() { + + kubectl apply -f - < $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + + +if [ -z "${USER_CODEFRESH_TOKEN}" ]; then + err "missing codefresh user token. must supply \".global.codefreshToken\" if agent-codefresh-token does not exist" + exit 1 +fi + +codefresh auth create-context --api-key ${USER_CODEFRESH_TOKEN} --url ${API_HOST} + +while true; do + msg "Reconciling ${RUNTIME_NAME} runtime" + + sleep $RECONCILE_INTERVAL + + codefresh get re \ + --name ${RUNTIME_NAME} \ + -o yaml \ + | yq 'del(.version, .metadata.changedBy, .metadata.creationTime)' > /tmp/runtime.yaml + + kubectl get cm ${CONFIGMAP_NAME} -n ${KUBE_NAMESPACE} -o yaml \ + | yq 'del(.metadata.resourceVersion, .metadata.uid)' \ + | yq eval '.data["runtime.yaml"] = load_str("/tmp/runtime.yaml")' \ + | kubectl apply -f - +done diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_deployment.yaml new file mode 100644 index 0000000000..26f3576b77 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "app-proxy.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "app-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "app-proxy.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "app-proxy.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: app-proxy + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "app-proxy.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 3000 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_env-vars.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_env-vars.yaml new file mode 100644 index 0000000000..c9b9a0e36a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_env-vars.yaml @@ -0,0 +1,19 @@ +{{- define "app-proxy.environment-variables.defaults" }} +PORT: 3000 +{{- end }} + +{{- define "app-proxy.environment-variables.calculated" }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +{{- with .Values.ingress.pathPrefix }} +API_PATH_PREFIX: {{ . | quote }} +{{- end }} +{{- end }} + +{{- define "app-proxy.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "app-proxy.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "app-proxy.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_helpers.tpl new file mode 100644 index 0000000000..2d4272ca92 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app-proxy.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "app-proxy" | 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 "app-proxy.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "app-proxy" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "app-proxy.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: app-proxy +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "app-proxy.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: app-proxy +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "app-proxy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app-proxy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_ingress.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_ingress.yaml new file mode 100644 index 0000000000..d7860b3638 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_ingress.yaml @@ -0,0 +1,32 @@ +{{- define "app-proxy.resources.ingress" -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + {{- if .Values.ingress.tlsSecret }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ .Values.tlsSecret }} + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.pathPrefix | default "/" }} + pathType: ImplementationSpecific + backend: + service: + name: {{ include "app-proxy.fullname" . }} + port: + number: 80 +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_rbac.yaml new file mode 100644 index 0000000000..87bd869ba0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "app-proxy.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app-proxy.serviceAccountName" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "app-proxy.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "app-proxy.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_service.yaml new file mode 100644 index 0000000000..4c3a93bf27 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/app-proxy/_service.yaml @@ -0,0 +1,17 @@ +{{- define "app-proxy.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 3000 + selector: + {{- include "app-proxy.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_deployment.yaml new file mode 100644 index 0000000000..62588b4d3d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_deployment.yaml @@ -0,0 +1,62 @@ +{{- define "event-exporter.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "event-exporter.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "event-exporter.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: event-exporter + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + args: [--running-in-cluster=true] + env: + {{- include "event-exporter.environment-variables" . | nindent 8 }} + ports: + - name: metrics + containerPort: 9102 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_env-vars.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_env-vars.yaml new file mode 100644 index 0000000000..d28d0776f3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_env-vars.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.environment-variables.defaults" }} +{{- end }} + +{{- define "event-exporter.environment-variables.calculated" }} +{{- end }} + +{{- define "event-exporter.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "event-exporter.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "event-exporter.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_helpers.tpl new file mode 100644 index 0000000000..5b8b5eff7f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "event-exporter.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "event-exporter" | 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 "event-exporter.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "event-exporter" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "event-exporter.labels" -}} +{{ include "cf-runtime.labels" . }} +app: event-exporter +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "event-exporter.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +app: event-exporter +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "event-exporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "event-exporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_rbac.yaml new file mode 100644 index 0000000000..69d7b6b2fb --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "event-exporter.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "event-exporter.serviceAccountName" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: [events] + verbs: [get, list, watch] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "event-exporter.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "event-exporter.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_service.yaml new file mode 100644 index 0000000000..6fa29ec1a0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_service.yaml @@ -0,0 +1,17 @@ +{{- define "event-exporter.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: metrics + port: 9102 + targetPort: metrics + protocol: TCP + selector: + {{- include "event-exporter.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_serviceMontor.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_serviceMontor.yaml new file mode 100644 index 0000000000..6092443f0a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/event-exporter/_serviceMontor.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.resources.serviceMonitor" -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + endpoints: + - port: metrics + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_deployment.yaml new file mode 100644 index 0000000000..7efa6557b1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "monitor.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "monitor.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "monitor.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 9020 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /api/ping + port: 9020 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_env-vars.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_env-vars.yaml new file mode 100644 index 0000000000..f58c7fa250 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_env-vars.yaml @@ -0,0 +1,26 @@ +{{- define "monitor.environment-variables.defaults" }} +SERVICE_NAME: {{ include "monitor.fullname" . }} +PORT: 9020 +HELM3: true +NODE_OPTIONS: "--max_old_space_size=4096" +{{- end }} + +{{- define "monitor.environment-variables.calculated" }} +API_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +CLUSTER_ID: {{ include "runtime.runtime-environment-spec.context-name" . }} +API_URL: {{ include "runtime.runtime-environment-spec.codefresh-host" . }}/api/k8s-monitor/events +ACCOUNT_ID: {{ .Values.global.accountId }} +NAMESPACE: {{ .Release.Namespace }} +{{- if .Values.rbac.namespaced }} +ROLE_BINDING: true +{{- end }} +{{- end }} + +{{- define "monitor.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "monitor.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "monitor.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_helpers.tpl new file mode 100644 index 0000000000..71cc1c027d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "monitor.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "monitor" | 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 "monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "monitor.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "monitor.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_rbac.yaml new file mode 100644 index 0000000000..88204796ae --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_rbac.yaml @@ -0,0 +1,56 @@ +{{- define "monitor.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "monitor.serviceAccountName" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch", "create", "delete" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "deletecollection" ] + - apiGroups: [ "extensions" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "apps" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "monitor.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} + name: {{ include "monitor.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_service.yaml new file mode 100644 index 0000000000..f6ae9bb0f7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/monitor/_service.yaml @@ -0,0 +1,17 @@ +{{- define "monitor.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 9020 + selector: + {{- include "monitor.selectorLabels" . | nindent 4 }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_deployment.yaml new file mode 100644 index 0000000000..e1fb9439ab --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_deployment.yaml @@ -0,0 +1,103 @@ +{{- define "runner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "runner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "runner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "runner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + initContainers: + - name: init + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.init.image "context" .) }} + imagePullPolicy: {{ .Values.init.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/init-runtime.sh" | nindent 10 }} + env: + {{- include "runner-init.environment-variables" . | nindent 8 }} + {{- with .Values.init.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + containers: + - name: runner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" }} + env: + {{- include "runner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.sidecar.enabled }} + - name: reconcile-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.sidecar.image "context" .) }} + imagePullPolicy: {{ .Values.sidecar.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/reconcile-runtime.sh" | nindent 10 }} + env: + {{- include "runner-sidecar.environment-variables" . | nindent 8 }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_helpers.tpl new file mode 100644 index 0000000000..2608cb67ee --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "runner" | 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 "runner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "runner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "runner.serviceAccountName" -}} + {{- if .Values.serviceAccount.create }} + {{- default (include "runner.fullname" .) .Values.serviceAccount.name }} + {{- else }} + {{- default "default" .Values.serviceAccount.name }} + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_rbac.yaml new file mode 100644 index 0000000000..d95b958d54 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/_rbac.yaml @@ -0,0 +1,53 @@ +{{- define "runner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runner.serviceAccountName" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "pods", "persistentvolumeclaims" ] + verbs: [ "get", "create", "delete", patch ] + - apiGroups: [ "" ] + resources: [ "configmaps", "secrets" ] + verbs: [ "get", "create", "update", patch ] + - apiGroups: [ "apps" ] + resources: [ "deployments" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "runner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "runner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_init-container.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_init-container.yaml new file mode 100644 index 0000000000..6dda110f78 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_init-container.yaml @@ -0,0 +1,30 @@ +{{- define "runner-init.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-init.environment-variables.calculated" }} +AGENT_NAME: {{ include "runtime.runtime-environment-spec.agent-name" . }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +AGENT_CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token + optional: true +EXISTING_AGENT_CODEFRESH_TOKEN: {{ include "runtime.agent-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +SECRET_NAME: {{ include "runner.fullname" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +{{- end }} + +{{- define "runner-init.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-init.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-init.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_main-container.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_main-container.yaml new file mode 100644 index 0000000000..4d3f0304e2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_main-container.yaml @@ -0,0 +1,28 @@ +{{- define "runner.environment-variables.defaults" }} +AGENT_MODE: InCluster +SELF_DEPLOYMENT_NAME: + valueFrom: + fieldRef: + fieldPath: metadata.name +{{- end }} + +{{- define "runner.environment-variables.calculated" }} +AGENT_ID: {{ include "runtime.runtime-environment-spec.agent-name" . }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +CODEFRESH_IN_CLUSTER_RUNTIME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +{{- end }} + +{{- define "runner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "runner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "runner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_sidecar-container.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_sidecar-container.yaml new file mode 100644 index 0000000000..3adcbe5d49 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/runner/environment-variables/_sidecar-container.yaml @@ -0,0 +1,22 @@ +{{- define "runner-sidecar.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-sidecar.environment-variables.calculated" }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CONFIGMAP_NAME: {{ printf "%s-%s" (include "runtime.fullname" .) "spec" }} +{{- end }} + +{{- define "runner-sidecar.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-sidecar.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-sidecar.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.sidecar.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_cronjob.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_cronjob.yaml new file mode 100644 index 0000000000..20bd2d56e1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_cronjob.yaml @@ -0,0 +1,58 @@ +{{- define "dind-volume-provisioner.resources.cronjob" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- if not (eq .Values.storage.backend "local") }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "dind-volume-cleanup.fullname" . }} + labels: + {{- include "dind-volume-cleanup.labels" . | nindent 4 }} +spec: + concurrencyPolicy: {{ .Values.concurrencyPolicy }} + schedule: {{ .Values.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.successfulJobsHistory }} + failedJobsHistoryLimit: {{ .Values.failedJobsHistory }} + {{- with .Values.suspend }} + suspend: {{ . }} + {{- end }} + jobTemplate: + spec: + template: + metadata: + labels: + {{- include "dind-volume-cleanup.selectorLabels" . | nindent 12 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 10 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.restartPolicy | default "Never" }} + containers: + - name: dind-volume-cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 12 }} + - name: PROVISIONED_BY + value: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + resources: + {{- toYaml .Values.resources | nindent 14 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_daemonset.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_daemonset.yaml new file mode 100644 index 0000000000..cb463231d2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_daemonset.yaml @@ -0,0 +1,98 @@ +{{- define "dind-volume-provisioner.resources.daemonset" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $localVolumeParentDir := .Values.storage.local.volumeParentDir }} +{{- if eq .Values.storage.backend "local" }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "dind-lv-monitor.fullname" . }} + labels: + {{- include "dind-lv-monitor.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.volumePermissions.enabled }} + initContainers: + - name: volume-permissions + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.volumePermissions.image "context" .) }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -ec + - | + chown -R {{ .Values.podSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ $localVolumeParentDir }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + name: dind-volume-dir + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 10 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 10 }} + {{- end }} + resources: + {{- toYaml .Values.volumePermissions.resources | nindent 10 }} + {{- end }} + containers: + - name: dind-lv-monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 10 }} + {{- end }} + command: + - /home/dind-volume-utils/bin/local-volumes-agent + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 10 }} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: VOLUME_PARENT_DIR + value: {{ $localVolumeParentDir }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + readOnly: false + name: dind-volume-dir + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + - name: dind-volume-dir + hostPath: + path: {{ $localVolumeParentDir }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_deployment.yaml new file mode 100644 index 0000000000..9252b45200 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_deployment.yaml @@ -0,0 +1,67 @@ +{{- define "dind-volume-provisioner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: dind-volume-provisioner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + command: + - /usr/local/bin/dind-volume-provisioner + - -v=4 + - --resync-period=50s + env: + {{- include "dind-volume-provisioner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- include "dind-volume-provisioner.volumeMounts.calculated" . | nindent 8 }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- include "dind-volume-provisioner.volumes.calculated" . | nindent 6 }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_env-vars.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_env-vars.yaml new file mode 100644 index 0000000000..e1f5dfe603 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_env-vars.yaml @@ -0,0 +1,88 @@ +{{- define "dind-volume-provisioner.environment-variables.defaults" }} +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables.calculated" }} +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +PROVISIONER_NAME: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.accessKeyIdSecretKeyRef }} +AWS_ACCESS_KEY_ID: + {{- if .Values.storage.ebs.accessKeyId }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_access_key_id + {{- else if .Values.storage.ebs.accessKeyIdSecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.accessKeyIdSecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.ebs.secretAccessKey .Values.storage.ebs.secretAccessKeySecretKeyRef }} +AWS_SECRET_ACCESS_KEY: + {{- if .Values.storage.ebs.secretAccessKey }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_secret_access_key + {{- else if .Values.storage.ebs.secretAccessKeySecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.secretAccessKeySecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +GOOGLE_APPLICATION_CREDENTIALS: {{ printf "/etc/dind-volume-provisioner/credentials/%s" (.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.key | default "google-service-account.json") }} +{{- end }} + +{{- if and .Values.storage.mountAzureJson }} +AZURE_CREDENTIAL_FILE: /etc/kubernetes/azure.json +CLOUDCONFIG_AZURE: /etc/kubernetes/azure.json +{{- end }} + +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "dind-volume-provisioner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "dind-volume-provisioner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} + + +{{- define "dind-volume-provisioner.volumes.calculated" }} + {{- if .Values.storage.gcedisk.serviceAccountJson }} +- name: credentials + secret: + secretName: {{ include "dind-volume-provisioner.fullname" . }} + optional: true + {{- else if .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + secret: + secretName: {{ .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.name }} + optional: true + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + hostPath: + path: /etc/kubernetes/azure.json + type: File + {{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.volumeMounts.calculated" }} + {{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + readOnly: true + mountPath: "/etc/dind-volume-provisioner/credentials" + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + readOnly: true + mountPath: "/etc/kubernetes/azure.json" + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_helpers.tpl new file mode 100644 index 0000000000..e3d3a0d3f7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_helpers.tpl @@ -0,0 +1,93 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dind-volume-provisioner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "volume-provisioner" | 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 "dind-volume-provisioner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-provisioner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-volume-cleanup.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-cleanup" | trunc 52 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-lv-monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "lv-monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Provisioner name for storage class +*/}} +{{- define "dind-volume-provisioner.volumeProvisionerName" }} + {{- printf "codefresh.io/dind-volume-provisioner-runner-%s" .Release.Namespace }} +{{- end }} + +{{/* +Common labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Selector labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Common labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Selector labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dind-volume-provisioner.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dind-volume-provisioner.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.storageClassName" }} +{{- printf "dind-local-volumes-runner-%s" .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_rbac.yaml new file mode 100644 index 0000000000..fbcbc684fc --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_rbac.yaml @@ -0,0 +1,71 @@ +{{- define "dind-volume-provisioner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "persistentvolumes" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "persistentvolumeclaims" ] + verbs: [ "get", "list", "watch", "update", "delete" ] + - apiGroups: [ "storage.k8s.io" ] + resources: [ "storageclasses" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "events" ] + verbs: [ "list", "watch", "create", "update", "patch" ] + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get", "list" ] + - apiGroups: [ "" ] + resources: [ "nodes" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "endpoints" ] + verbs: [ "get", "list", "watch", "create", "update", "delete" ] + - apiGroups: [ "coordination.k8s.io" ] + resources: [ "leases" ] + verbs: [ "get", "create", "update" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "dind-volume-provisioner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_secret.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_secret.yaml new file mode 100644 index 0000000000..f361a79910 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_secret.yaml @@ -0,0 +1,22 @@ +{{- define "dind-volume-provisioner.resources.secret" -}} +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.secretAccessKey .Values.storage.gcedisk.serviceAccountJson }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +stringData: + {{- with .Values.storage.gcedisk.serviceAccountJson }} + google-service-account.json: | +{{- . | nindent 4 }} + {{- end }} + {{- with .Values.storage.ebs.accessKeyId }} + aws_access_key_id: {{ . }} + {{- end }} + {{- with .Values.storage.ebs.secretAccessKey }} + aws_secret_access_key: {{ . }} + {{- end }} +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_storageclass.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_storageclass.yaml new file mode 100644 index 0000000000..62e910c87e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_components/volume-provisioner/_storageclass.yaml @@ -0,0 +1,47 @@ +{{- define "dind-volume-provisioner.resources.storageclass" -}} +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + {{/* has to be exactly that */}} + name: {{ include "dind-volume-provisioner.storageClassName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +provisioner: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} +parameters: +{{- if eq .Values.storage.backend "local" }} + volumeBackend: local + volumeParentDir: {{ .Values.storage.local.volumeParentDir }} +{{- else if eq .Values.storage.backend "gcedisk" }} + volumeBackend: {{ .Values.storage.backend }} + type: {{ .Values.storage.gcedisk.volumeType | default "pd-ssd" }} + zone: {{ required ".Values.storage.gcedisk.availabilityZone is required" .Values.storage.gcedisk.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} +{{- else if or (eq .Values.storage.backend "ebs") (eq .Values.storage.backend "ebs-csi")}} + volumeBackend: {{ .Values.storage.backend }} + VolumeType: {{ .Values.storage.ebs.volumeType | default "gp3" }} + AvailabilityZone: {{ required ".Values.storage.ebs.availabilityZone is required" .Values.storage.ebs.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + encrypted: {{ .Values.storage.ebs.encrypted | default "false" | quote }} + {{- with .Values.storage.ebs.kmsKeyId }} + kmsKeyId: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.iops }} + iops: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.throughput }} + throughput: {{ . | quote }} + {{- end }} +{{- else if or (eq .Values.storage.backend "azuredisk") (eq .Values.storage.backend "azuredisk-csi")}} + volumeBackend: {{ .Values.storage.backend }} + kind: managed + skuName: {{ .Values.storage.azuredisk.skuName | default "Premium_LRS" }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + cachingMode: {{ .Values.storage.azuredisk.cachingMode | default "None" }} + {{- with .Values.storage.azuredisk.availabilityZone }} + availabilityZone: {{ . | quote }} + {{- end }} + {{- with .Values.storage.azuredisk.resourceGroup }} + resourceGroup: {{ . | quote }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/_helpers.tpl new file mode 100644 index 0000000000..72f44e36af --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cf-runtime.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 "cf-runtime.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cf-runtime.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cf-runtime.labels" -}} +helm.sh/chart: {{ include "cf-runtime.chart" . }} +{{ include "cf-runtime.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cf-runtime.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cf-runtime.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/deployment.yaml new file mode 100644 index 0000000000..90341b3059 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/deployment.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.deployment" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/ingress.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/ingress.yaml new file mode 100644 index 0000000000..56ab5e95ea --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/ingress.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.ingress" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/rbac.yaml new file mode 100644 index 0000000000..4db87dcb45 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/rbac.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.rbac" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/service.yaml new file mode 100644 index 0000000000..0b9d85ec0d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/app-proxy/service.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.service" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/deployment.yaml new file mode 100644 index 0000000000..4942882407 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/deployment.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.deployment" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/rbac.yaml new file mode 100644 index 0000000000..6a9bf5c65a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/rbac.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.rbac" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/service.yaml new file mode 100644 index 0000000000..c5d856dfe3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/event-exporter/service.yaml @@ -0,0 +1,11 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.service" $eventExporterContext }} +--- +{{- include "event-exporter.resources.serviceMonitor" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/extra/extra-resources.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/extra/extra-resources.yaml new file mode 100644 index 0000000000..1a9777c649 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/extra/extra-resources.yaml @@ -0,0 +1,6 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + +{{- range .Values.extraResources }} +--- +{{ include (printf "%s.tplrender" $cfCommonTplSemver) (dict "Values" . "context" $) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/extra/runtime-images-cm.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/extra/runtime-images-cm.yaml new file mode 100644 index 0000000000..f269c84b2b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/extra/runtime-images-cm.yaml @@ -0,0 +1,19 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.engine.runtimeImages }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + {{- /* dummy template just to list runtime images */}} + name: {{ include "runtime.fullname" . }}-images + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + images: | + {{- range $key, $val := $values }} + image: {{ $val }} + {{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/cm-update-runtime.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/cm-update-runtime.yaml new file mode 100644 index 0000000000..46a306c560 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/cm-update-runtime.yaml @@ -0,0 +1,18 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "runtime.fullname" . }}-spec + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + runtime.yaml: | + {{ include "runtime.runtime-environment-spec.template" . | nindent 4 | trim }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-gencerts-dind.yaml new file mode 100644 index 0000000000..4a08a229c8 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-gencerts-dind.yaml @@ -0,0 +1,68 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "3" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-gencerts-dind + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: gencerts-dind + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/configure-dind-certs.sh" | nindent 10 }} + env: + - name: NAMESPACE + value: {{ .Release.Namespace }} + - name: RELEASE + value: {{ .Release.Name }} + - name: CF_API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: CF_API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-update-runtime.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-update-runtime.yaml new file mode 100644 index 0000000000..955e882d77 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/job-update-runtime.yaml @@ -0,0 +1,77 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "5" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: patch-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | + codefresh auth create-context --api-key $API_KEY --url $API_HOST + cat /usr/share/extras/runtime.yaml + codefresh get re +{{- if .Values.runtime.agent }} + codefresh patch re -f /usr/share/extras/runtime.yaml +{{- else }} + codefresh patch sys-re -f /usr/share/extras/runtime.yaml +{{- end }} + env: + - name: API_KEY + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + volumeMounts: + - name: config + mountPath: /usr/share/extras/runtime.yaml + subPath: runtime.yaml + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure + volumes: + - name: config + configMap: + name: {{ include "runtime.fullname" . }}-spec +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/rbac-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/rbac-gencerts-dind.yaml new file mode 100644 index 0000000000..4907dac380 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/post-install/rbac-gencerts-dind.yaml @@ -0,0 +1,37 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-gencerts-dind +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/job-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/job-cleanup-resources.yaml new file mode 100644 index 0000000000..0e3c7659f1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/job-cleanup-resources.yaml @@ -0,0 +1,73 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-cleanup + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/cleanup-runtime.sh" | nindent 10 }} + env: + - name: AGENT_NAME + value: {{ include "runtime.runtime-environment-spec.agent-name" . }} + - name: RUNTIME_NAME + value: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: AGENT + value: {{ .Values.runtime.agent | quote }} + - name: AGENT_SECRET_NAME + value: {{ include "runner.fullname" . }} + - name: DIND_SECRET_NAME + value: codefresh-certs-server + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/rbac-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/rbac-cleanup-resources.yaml new file mode 100644 index 0000000000..468ec2212d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/hooks/pre-delete/rbac-cleanup-resources.yaml @@ -0,0 +1,46 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +rules: + - apiGroups: + - "*" + resources: + - "*" + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-cleanup +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/monitor/deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/deployment.yaml new file mode 100644 index 0000000000..00c9fb2f91 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/deployment.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.deployment" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/monitor/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/rbac.yaml new file mode 100644 index 0000000000..f9812d565d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/rbac.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.rbac" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/monitor/service.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/service.yaml new file mode 100644 index 0000000000..f99706614a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/monitor/service.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.service" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/other/external-secrets.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/other/external-secrets.yaml new file mode 100644 index 0000000000..dc24e24e51 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/other/external-secrets.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.external-secrets" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/other/podMonitor.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/other/podMonitor.yaml new file mode 100644 index 0000000000..4319b722b9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/other/podMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.podMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/other/serviceMonitor.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/other/serviceMonitor.yaml new file mode 100644 index 0000000000..29f890fe2b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/other/serviceMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.serviceMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runner/deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runner/deployment.yaml new file mode 100644 index 0000000000..85777c487f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runner/deployment.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.deployment" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runner/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runner/rbac.yaml new file mode 100644 index 0000000000..d5f8c13233 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.rbac" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/_helpers.tpl b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/_helpers.tpl new file mode 100644 index 0000000000..6ba04fcc3e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/_helpers.tpl @@ -0,0 +1,123 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runtime.name" -}} + {{- printf "%s" (include "cf-runtime.name" .) | 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 "runtime.fullname" -}} + {{- printf "%s" (include "cf-runtime.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runtime.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runtime.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Return runtime image (classic runtime) with private registry prefix +*/}} +{{- define "runtime.runtimeImageName" -}} + {{- if .registry -}} + {{- $imageName := (trimPrefix "quay.io/" .imageFullName) -}} + {{- printf "%s/%s" .registry $imageName -}} + {{- else -}} + {{- printf "%s" .imageFullName -}} + {{- end -}} +{{- end -}} + +{{/* +Environment variable value of Codefresh installation token +*/}} +{{- define "runtime.installation-token-env-var-value" -}} + {{- if .Values.global.codefreshToken }} +valueFrom: + secretKeyRef: + name: {{ include "runtime.installation-token-secret-name" . }} + key: codefresh-api-token + {{- else if .Values.global.codefreshTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.codefreshTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Environment variable value of Codefresh agent token +*/}} +{{- define "runtime.agent-token-env-var-value" -}} + {{- if .Values.global.agentToken }} +{{- printf "%s" .Values.global.agentToken | toYaml }} + {{- else if .Values.global.agentTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.agentTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Print Codefresh API token secret name +*/}} +{{- define "runtime.installation-token-secret-name" }} +{{- print "codefresh-user-token" }} +{{- end }} + +{{/* +Print Codefresh host +*/}} +{{- define "runtime.runtime-environment-spec.codefresh-host" }} +{{- if and (not .Values.global.codefreshHost) }} + {{- fail "ERROR: .global.codefreshHost is required" }} +{{- else }} + {{- printf "%s" (trimSuffix "/" .Values.global.codefreshHost) }} +{{- end }} +{{- end }} + +{{/* +Print runtime-environment name +*/}} +{{- define "runtime.runtime-environment-spec.runtime-name" }} +{{- if and (not .Values.global.runtimeName) }} + {{- printf "%s/%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.runtimeName }} +{{- end }} +{{- end }} + +{{/* +Print agent name +*/}} +{{- define "runtime.runtime-environment-spec.agent-name" }} +{{- if and (not .Values.global.agentName) }} + {{- printf "%s_%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.agentName }} +{{- end }} +{{- end }} + +{{/* +Print context +*/}} +{{- define "runtime.runtime-environment-spec.context-name" }} +{{- if and (not .Values.global.context) }} + {{- fail "ERROR: .global.context is required" }} +{{- else }} + {{- printf "%s" .Values.global.context }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/cm-dind-daemon.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/cm-dind-daemon.yaml new file mode 100644 index 0000000000..fc7f92905b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/cm-dind-daemon.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + {{- /* has to be a constant */}} + name: codefresh-dind-config + labels: + {{- include "runtime.labels" . | nindent 4 }} +data: + daemon.json: | +{{ coalesce .Values.re.dindDaemon .Values.runtime.dindDaemon | toPrettyJson | indent 4 }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/rbac.yaml new file mode 100644 index 0000000000..a51b125262 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/rbac.yaml @@ -0,0 +1,48 @@ +{{ $values := .Values.runtime }} +--- +{{- if or $values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- /* has to be a constant */}} + name: codefresh-engine + labels: + {{- include "runtime.labels" . | nindent 4 }} + {{- with $values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if $values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with $values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and $values.serviceAccount.create $values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: codefresh-engine +roleRef: + kind: Role + name: codefresh-engine + apiGroup: rbac.authorization.k8s.io +{{- end }} + diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/runtime-env-spec-tmpl.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/runtime-env-spec-tmpl.yaml new file mode 100644 index 0000000000..baf7265116 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/runtime-env-spec-tmpl.yaml @@ -0,0 +1,214 @@ +{{- define "runtime.runtime-environment-spec.template" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version -}} +{{- $kubeconfigFilePath := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $name := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $engineContext := .Values.runtime.engine -}} +{{- $dindContext := .Values.runtime.dind -}} +{{- $imageRegistry := .Values.global.imageRegistry -}} +metadata: + name: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + agent: {{ .Values.runtime.agent }} +runtimeScheduler: + type: KubernetesPod + {{- if $engineContext.image }} + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $engineContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $engineContext.image.pullPolicy }} + {{- with $engineContext.command }} + command: {{- toYaml . | nindent 4 }} + {{- end }} + envVars: + {{- with $engineContext.env }} + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + COMPOSE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.COMPOSE_IMAGE) | squote }} + CONTAINER_LOGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CONTAINER_LOGGER_IMAGE) | squote }} + DOCKER_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_BUILDER_IMAGE) | squote }} + DOCKER_PULLER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PULLER_IMAGE) | squote }} + DOCKER_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PUSHER_IMAGE) | squote }} + DOCKER_TAG_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_TAG_PUSHER_IMAGE) | squote }} + FS_OPS_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.FS_OPS_IMAGE) | squote }} + GIT_CLONE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GIT_CLONE_IMAGE) | squote }} + KUBE_DEPLOY: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.KUBE_DEPLOY) | squote }} + PIPELINE_DEBUGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.PIPELINE_DEBUGGER_IMAGE) | squote }} + TEMPLATE_ENGINE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.TEMPLATE_ENGINE) | squote }} + CR_6177_FIXER: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CR_6177_FIXER) | squote }} + GC_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GC_BUILDER_IMAGE) | squote }} + COSIGN_IMAGE_SIGNER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.COSIGN_IMAGE_SIGNER_IMAGE) | squote }} + {{- with $engineContext.userEnvVars }} + userEnvVars: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.workflowLimits }} + workflowLimits: {{- toYaml . | nindent 4 }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $engineContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $engineContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $engineContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $engineContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $engineContext.schedulerName }} + schedulerName: {{ $engineContext.schedulerName }} + {{- end }} + resources: + {{- if $engineContext.resources}} + {{- toYaml $engineContext.resources | nindent 4 }} + {{- end }} + {{- with $engineContext.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} +dockerDaemonScheduler: + type: DindKubernetesPod + {{- if $dindContext.image }} + dindImage: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $dindContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $dindContext.image.pullPolicy }} + {{- with $dindContext.userAccess }} + userAccess: {{ . }} + {{- end }} + {{- with $dindContext.env }} + envVars: + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $dindContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $dindContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $dindContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $dindContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $dindContext.schedulerName }} + schedulerName: {{ $dindContext.schedulerName }} + {{- end }} + {{- if $dindContext.pvcs }} + pvcs: + {{- range $index, $pvc := $dindContext.pvcs }} + - name: {{ $pvc.name }} + reuseVolumeSelector: {{ $pvc.reuseVolumeSelector | squote }} + reuseVolumeSortOrder: {{ $pvc.reuseVolumeSortOrder }} + storageClassName: {{ include (printf "%v.tplrender" $cfCommonTplSemver) (dict "Values" $pvc.storageClassName "context" $) }} + volumeSize: {{ $pvc.volumeSize }} + {{- with $pvc.annotations }} + annotations: {{ . | toYaml | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + defaultDindResources: + {{- with $dindContext.resources }} + {{- if not .requests }} + limits: {{- toYaml .limits | nindent 6 }} + requests: null + {{- else }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- with $dindContext.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} + {{- with $dindContext.userVolumeMounts }} + userVolumeMounts: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.userVolumes }} + userVolumes: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if and (not .Values.runtime.agent) }} + clientCertPath: /etc/ssl/cf/ + volumeMounts: + codefresh-certs-server: + name: codefresh-certs-server + mountPath: /etc/ssl/cf + readOnly: false + volumes: + codefresh-certs-server: + name: codefresh-certs-server + secret: + secretName: codefresh-certs-server + {{- end }} +extends: {{- toYaml .Values.runtime.runtimeExtends | nindent 2 }} + {{- if .Values.runtime.description }} +description: {{ .Values.runtime.description }} + {{- else }} +description: null + {{- end }} +{{- if .Values.global.accountId }} +accountId: {{ .Values.global.accountId }} +{{- end }} +{{- if not .Values.runtime.agent }} +accounts: {{- toYaml .Values.runtime.accounts | nindent 2 }} +{{- end }} +{{- if .Values.appProxy.enabled }} +appProxy: + externalIP: >- + {{ printf "https://%s%s" .Values.appProxy.ingress.host (.Values.appProxy.ingress.pathPrefix | default "/") }} +{{- end }} +{{- if not .Values.runtime.agent }} +systemHybrid: true +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/secret.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/secret.yaml new file mode 100644 index 0000000000..2366d3ccf6 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/secret.yaml @@ -0,0 +1,11 @@ +{{- if and .Values.global.codefreshToken }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "runtime.installation-token-secret-name" . }} + labels: + {{- include "runtime.labels" . | nindent 4 }} +stringData: + codefresh-api-token: {{ .Values.global.codefreshToken }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/runtime/svc-dind.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/svc-dind.yaml new file mode 100644 index 0000000000..098edb4e87 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/runtime/svc-dind.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "runtime.labels" . | nindent 4 }} + app: dind + {{/* has to be a constant */}} + name: dind +spec: + ports: + - name: "dind-port" + port: 1300 + protocol: TCP + clusterIP: None + selector: + app: dind diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/cronjob.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/cronjob.yaml new file mode 100644 index 0000000000..db955bc771 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/cronjob.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-volume-cleanup") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.cronjob" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/daemonset.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/daemonset.yaml new file mode 100644 index 0000000000..39927149e8 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/daemonset.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-lv-monitor") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.daemonset" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/deployment.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/deployment.yaml new file mode 100644 index 0000000000..522fa8791f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/deployment.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.deployment" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/rbac.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/rbac.yaml new file mode 100644 index 0000000000..f3ae9609f9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.rbac" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/secret.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/secret.yaml new file mode 100644 index 0000000000..accf601d13 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/secret.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.secret" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/storageclass.yaml b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/storageclass.yaml new file mode 100644 index 0000000000..77a7602da1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/templates/volume-provisioner/storageclass.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.storageclass" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.4.6/values.yaml b/charts/codefresh/cf-runtime/6.4.6/values.yaml new file mode 100644 index 0000000000..e843ca1a6c --- /dev/null +++ b/charts/codefresh/cf-runtime/6.4.6/values.yaml @@ -0,0 +1,951 @@ +# -- String to partially override cf-runtime.fullname template (will maintain the release name) +nameOverride: "" +# -- String to fully override cf-runtime.fullname template +fullnameOverride: "" + +# -- Global parameters +# @default -- See below +global: + # -- Global Docker image registry + imageRegistry: "" + # -- Global Docker registry secret names as array + imagePullSecrets: [] + + # -- URL of Codefresh Platform (required!) + codefreshHost: "https://g.codefresh.io" + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace + + # -- DEPRECATED Agent token in plain text. + # !!! MUST BE provided if migrating from < 6.x chart version + agentToken: "" + # -- DEPRECATED Agent token that references an existing secret containing API key. + # !!! MUST BE provided if migrating from < 6.x chart version + agentTokenSecretKeyRef: {} + # E.g. + # agentTokenSecretKeyRef: + # name: my-codefresh-agent-secret + # key: codefresh-agent-token + +# DEPRECATED -- Use `.Values.global.imageRegistry` instead +dockerRegistry: "" + +# DEPRECATED -- Use `.Values.runtime` instead +re: {} + +# -- Runner parameters +# @default -- See below +runner: + # -- Enable the runner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/venona + tag: 1.10.2 + + # -- Init container + init: + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + + resources: + limits: + memory: 512Mi + cpu: '1' + requests: + memory: 256Mi + cpu: '0.2' + + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: false + image: + registry: quay.io + repository: codefresh/codefresh-shell + tag: 0.0.2 + env: + RECONCILE_INTERVAL: 300 + resources: {} + + # -- Add additional env vars + env: {} + # E.g. + # env: + # WORKFLOW_CONCURRENCY: 50 # The number of workflow creation and termination tasks the Runner can handle in parallel. Defaults to 50 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Volume Provisioner parameters +# @default -- See below +volumeProvisioner: + # -- Enable volume-provisioner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/dind-volume-provisioner + tag: 1.35.0 + # -- Add additional env vars + env: {} + # E.g. + # env: + # THREADINESS: 4 # The number of PVC requests the dind-volume-provisioner can process in parallel. Defaults to 4 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 3000 + runAsGroup: 3000 + fsGroup: 3000 + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + + # -- `dind-lv-monitor` DaemonSet parameters + # (local volumes cleaner) + # @default -- See below + dind-lv-monitor: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-utils + tag: 1.29.4 + podAnnotations: {} + podSecurityContext: + enabled: true + runAsUser: 1000 + fsGroup: 1000 + containerSecurityContext: {} + env: {} + resources: {} + nodeSelector: {} + tolerations: + - key: 'codefresh/dind' + operator: 'Exists' + effect: 'NoSchedule' + volumePermissions: + enabled: true + image: + registry: docker.io + repository: alpine + tag: 3.18 + resources: {} + securityContext: + runAsUser: 0 # auto + + # `dind-volume-cleanup` CronJob parameters + # (external volumes cleaner) + # @default -- See below + dind-volume-cleanup: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-cleanup + tag: 1.2.0 + env: {} + concurrencyPolicy: Forbid + schedule: "*/10 * * * *" + successfulJobsHistory: 3 + failedJobsHistory: 1 + suspend: false + podAnnotations: {} + podSecurityContext: + enabled: true + fsGroup: 3000 + runAsGroup: 3000 + runAsUser: 3000 + nodeSelector: {} + affinity: {} + tolerations: [] + +# Storage parameters for volume-provisioner +# @default -- See below +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: local + # -- Set filesystem type (`ext4`/`xfs`) + fsType: "ext4" + + # Storage parametrs example for local volumes on the K8S nodes filesystem (i.e. `storage.backend=local`) + # https://kubernetes.io/docs/concepts/storage/volumes/#local + # @default -- See below + local: + # -- Set volume path on the host filesystem + volumeParentDir: /var/lib/codefresh/dind-volumes + + # Storage parameters example for aws ebs disks (i.e. `storage.backend=ebs`/`storage.backend=ebs-csi`) + # https://aws.amazon.com/ebs/ + # https://codefresh.io/docs/docs/installation/codefresh-runner/#aws-backend-volume-configuration + # @default -- See below + ebs: + # -- Set EBS volume type (`gp2`/`gp3`/`io1`) (required) + volumeType: "gp2" + # -- Set EBS volumes availability zone (required) + availabilityZone: "us-east-1a" + # -- Enable encryption (optional) + encrypted: "false" + # -- Set KMS encryption key ID (optional) + kmsKeyId: "" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: + + # E.g. + # ebs: + # volumeType: gp3 + # availabilityZone: us-east-1c + # encrypted: false + # iops: "5000" + # # I/O operations per second. Only effetive when gp3 volume type is specified. + # # Default value - 3000. + # # Max - 16,000 + # throughput: "500" + # # Throughput in MiB/s. Only effective when gp3 volume type is specified. + # # Default value - 125. + # # Max - 1000. + # ebs: + # volumeType: gp2 + # availabilityZone: us-east-1c + # encrypted: true + # kmsKeyId: "1234abcd-12ab-34cd-56ef-1234567890ab" + # accessKeyId: "MYKEYID" + # secretAccessKey: "MYACCESSKEY" + + # Storage parameters example for gce disks + # https://cloud.google.com/compute/docs/disks#pdspecs + # https://codefresh.io/docs/docs/installation/codefresh-runner/#gke-google-kubernetes-engine-backend-volume-configuration + # @default -- See below + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-ssd" + # -- Set GCP volume availability zone + availabilityZone: "us-west1-a" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: "" + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g. + # gcedisk: + # volumeType: pd-ssd + # availabilityZone: us-central1-c + # serviceAccountJson: |- + # { + # "type": "service_account", + # "project_id": "...", + # "private_key_id": "...", + # "private_key": "...", + # "client_email": "...", + # "client_id": "...", + # "auth_uri": "...", + # "token_uri": "...", + # "auth_provider_x509_cert_url": "...", + # "client_x509_cert_url": "..." + # } + + # Storage parameters example for Azure Disks + # https://codefresh.io/docs/docs/installation/codefresh-runner/#install-codefresh-runner-on-azure-kubernetes-service-aks + # @default -- See below + azuredisk: + # -- Set storage type (`Premium_LRS`) + skuName: Premium_LRS + cachingMode: None + # availabilityZone: northeurope-1 + # resourceGroup: + # DiskIOPSReadWrite: 500 + # DiskMBpsReadWrite: 100 + + mountAzureJson: false + +# -- Set runtime parameters +# @default -- See below + +runtime: + # -- Set annotation on engine Service Account + # Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster + serviceAccount: + create: true + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- Set parent runtime to inherit. + # Should not be changes. Parent runtime is controlled from Codefresh side. + runtimeExtends: + - system/default/hybrid/k8s_low_limits + # -- Runtime description + description: "" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the engine role + rules: [] + + # -- (for On-Premise only) Enable agent + agent: true + # -- (for On-Premise only) Set inCluster runtime + inCluster: true + # -- (for On-Premise only) Assign accounts to runtime (list of account ids) + accounts: [] + + # -- Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). + dind: + # -- Set dind image. + image: + registry: quay.io + repository: codefresh/dind + tag: 26.1.4-1.28.7 # use `latest-rootless/rootless/26.1.4-1.28.7-rootless` tags for rootless-dind + pullPolicy: IfNotPresent + # -- Set dind resources. + resources: + requests: null + limits: + cpu: 400m + memory: 800Mi + # -- Set termination grace period. + terminationGracePeriodSeconds: 30 + # -- PV claim spec parametes. + pvcs: + # -- Default dind PVC parameters + dind: + # -- PVC name prefix. + # Keep `dind` as default! Don't change! + name: dind + # -- PVC storage class name. + # Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner + storageClassName: '{{ include "dind-volume-provisioner.storageClassName" . }}' + # -- PVC size. + volumeSize: 16Gi + # -- PV reuse selector. + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy + reuseVolumeSelector: codefresh-app,io.codefresh.accountName + reuseVolumeSortOrder: pipeline_id + # -- PV annotations. + annotations: {} + # E.g.: + # annotations: + # codefresh.io/volume-retention: 7d + # -- Set additional env vars. + env: + DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE: true + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Keep `true` as default! + userAccess: true + # -- Add extra volumes + userVolumes: {} + # E.g.: + # userVolumes: + # regctl-docker-registry: + # name: regctl-docker-registry + # secret: + # items: + # - key: .dockerconfigjson + # path: config.json + # secretName: regctl-docker-registry + # optional: true + # -- Add extra volume mounts + userVolumeMounts: {} + # E.g.: + # userVolumeMounts: + # regctl-docker-registry: + # name: regctl-docker-registry + # mountPath: /home/appuser/.docker/ + # readOnly: true + + # -- Parameters for Engine pod (aka "pipeline" orchestrator). + engine: + # -- Set image. + image: + registry: quay.io + repository: codefresh/engine + tag: 1.174.13 + pullPolicy: IfNotPresent + # -- Set container command. + command: + - npm + - run + - start + # -- Set resources. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 1000m + memory: 2048Mi + # -- Set termination grace period. + terminationGracePeriodSeconds: 180 + # -- Set system(base) runtime images. + # @default -- See below. + runtimeImages: + COMPOSE_IMAGE: quay.io/codefresh/compose:v2.28.1-1.5.0 + CONTAINER_LOGGER_IMAGE: quay.io/codefresh/cf-container-logger:1.11.7 + DOCKER_BUILDER_IMAGE: quay.io/codefresh/cf-docker-builder:1.3.14 + DOCKER_PULLER_IMAGE: quay.io/codefresh/cf-docker-puller:8.0.18 + DOCKER_PUSHER_IMAGE: quay.io/codefresh/cf-docker-pusher:6.0.16 + DOCKER_TAG_PUSHER_IMAGE: quay.io/codefresh/cf-docker-tag-pusher:1.3.14 + FS_OPS_IMAGE: quay.io/codefresh/fs-ops:1.2.3 + GIT_CLONE_IMAGE: quay.io/codefresh/cf-git-cloner:10.1.28 + KUBE_DEPLOY: quay.io/codefresh/cf-deploy-kubernetes:16.1.11 + PIPELINE_DEBUGGER_IMAGE: quay.io/codefresh/cf-debugger:1.3.6 + TEMPLATE_ENGINE: quay.io/codefresh/pikolo:0.14.1 + CR_6177_FIXER: 'quay.io/codefresh/alpine:edge' + GC_BUILDER_IMAGE: 'quay.io/codefresh/cf-gc-builder:0.5.3' + COSIGN_IMAGE_SIGNER_IMAGE: 'quay.io/codefresh/cf-cosign-image-signer:2.4.0-cf.2' + # -- Set additional env vars. + env: + # -- Interval to check the exec status in the container-logger + CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS: 1000 + # -- Timeout while doing requests to the Docker daemon + DOCKER_REQUEST_TIMEOUT_MS: 30000 + # -- If "true", composition images will be pulled sequentially + FORCE_COMPOSE_SERIAL_PULL: false + # -- Level of logging for engine + LOGGER_LEVEL: debug + # -- Enable debug-level logging of outgoing HTTP/HTTPS requests + LOG_OUTGOING_HTTP_REQUESTS: false + # -- Enable emitting metrics from engine + METRICS_PROMETHEUS_ENABLED: true + # -- Enable legacy metrics + METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS: false + # -- Enable collecting process metrics + METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS: false + # -- Host for Prometheus metrics server + METRICS_PROMETHEUS_HOST: '0.0.0.0' + # -- Port for Prometheus metrics server + METRICS_PROMETHEUS_PORT: 9100 + # -- Set workflow limits. + workflowLimits: + # -- Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. + MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS: 600 + # -- Maximum time for workflow execution; seconds. + MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION: 86400 + # -- Maximum time allowed to workflow to spend in "elected" state; seconds. + MAXIMUM_ELECTED_STATE_AGE_ALLOWED: 900 + # -- Maximum retry attempts allowed for workflow. + MAXIMUM_RETRY_ATTEMPTS_ALLOWED: 20 + # -- Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED: 900 + # -- Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE: 300 + # -- Time since the last health check report after which workflow is terminated; seconds. + TIME_ENGINE_INACTIVE_UNTIL_TERMINATION: 300 + # -- Time since the last health check report after which the engine is considered unhealthy; seconds. + TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY: 60 + # -- Time since the last workflow logs activity after which workflow is terminated; seconds. + TIME_INACTIVE_UNTIL_TERMINATION: 2700 + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Set extra env vars + userEnvVars: [] + # E.g. + # userEnvVars: + # - name: GITHUB_TOKEN + # valueFrom: + # secretKeyRef: + # name: github-token + # key: token + + # -- Parameters for `runtime-patch` post-upgrade/install hook + # @default -- See below + patch: + enabled: true + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + env: + HOME: /tmp + + # -- Parameters for `gencerts-dind` post-upgrade/install hook + # @default -- See below + gencerts: + enabled: true + image: + registry: quay.io + repository: codefresh/kubectl + tag: 1.28.4 + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + + # -- DinD pod daemon config + # @default -- See below + dindDaemon: + hosts: + - unix:///var/run/docker.sock + - tcp://0.0.0.0:1300 + tlsverify: true + tls: true + tlscacert: /etc/ssl/cf-client/ca.pem + tlscert: /etc/ssl/cf/server-cert.pem + tlskey: /etc/ssl/cf/server-key.pem + insecure-registries: + - 192.168.99.100:5000 + metrics-addr: 0.0.0.0:9323 + experimental: true + +# App-Proxy parameters +# Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#app-proxy-installation +# @default -- See below +appProxy: + # -- Enable app-proxy + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-app-proxy + tag: 0.0.47 + # -- Add additional env vars + env: {} + + # Set app-proxy ingress parameters + # @default -- See below + ingress: + # -- Set path prefix for ingress (keep empty for default `/` path) + pathPrefix: "" + # -- Set ingress class + class: "" + # -- Set DNS hostname the ingress will use + host: "" + # -- Set k8s tls secret for the ingress object + tlsSecret: "" + # -- Set extra annotations for ingress object + annotations: {} + # E.g. + # ingress: + # pathPrefix: "/cf-app-proxy" + # class: "nginx" + # host: "mydomain.com" + # tlsSecret: "tls-cert-app-proxy" + # annotations: + # nginx.ingress.kubernetes.io/whitelist-source-range: 123.123.123.123/130 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + podSecurityContext: {} + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# Monitor parameters +# @default -- See below +monitor: + # -- Enable monitor + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component + enabled: false + + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-k8s-agent + tag: 1.3.18 + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + podSecurityContext: {} + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Add serviceMonitor +# @default -- See below +serviceMonitor: + main: + # -- Enable service monitor for dind pods + enabled: false + nameOverride: dind + selector: + matchLabels: + app: dind + endpoints: + - path: /metrics + targetPort: 9100 + relabelings: + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + +# -- Add podMonitor (for engine pods) +# @default -- See below +podMonitor: + main: + # -- Enable pod monitor for engine pods + enabled: false + nameOverride: engine + selector: + matchLabels: + app: runtime + podMetricsEndpoints: + - path: /metrics + targetPort: 9100 + + runner: + # -- Enable pod monitor for runner pod + enabled: false + nameOverride: runner + selector: + matchLabels: + codefresh.io/application: runner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + + volume-provisioner: + # -- Enable pod monitor for volumeProvisioner pod + enabled: false + nameOverride: volume-provisioner + selector: + matchLabels: + codefresh.io/application: volume-provisioner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + +# -- Event exporter parameters +# @default -- See below +event-exporter: + # -- Enable event-exporter + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: docker.io + repository: codefresh/k8s-event-exporter + tag: latest + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: false + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Array of extra objects to deploy with the release +extraResources: [] +# E.g. +# extraResources: +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRole +# metadata: +# name: codefresh-role +# rules: +# - apiGroups: [ "*"] +# resources: ["*"] +# verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# - apiVersion: v1 +# kind: ServiceAccount +# metadata: +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRoleBinding +# metadata: +# name: codefresh-user +# roleRef: +# apiGroup: rbac.authorization.k8s.io +# kind: ClusterRole +# name: codefresh-role +# subjects: +# - kind: ServiceAccount +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: v1 +# kind: Secret +# type: kubernetes.io/service-account-token +# metadata: +# name: codefresh-user-token +# namespace: "{{ .Release.Namespace }}" +# annotations: +# kubernetes.io/service-account.name: "codefresh-user" diff --git a/charts/loft/loft/4.0.0/.helmignore b/charts/loft/loft/4.0.0/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/loft/loft/4.0.0/.helmignore @@ -0,0 +1,21 @@ +# 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 diff --git a/charts/loft/loft/4.0.0/Chart.yaml b/charts/loft/loft/4.0.0/Chart.yaml new file mode 100644 index 0000000000..78d5d3989d --- /dev/null +++ b/charts/loft/loft/4.0.0/Chart.yaml @@ -0,0 +1,32 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Loft + catalog.cattle.io/kube-version: '>=1.22-0' + catalog.cattle.io/release-name: loft +apiVersion: v2 +description: Secure Cluster Sharing, Self-Service Namespace Provisioning and Virtual + Clusters +home: https://loft.sh +icon: file://assets/icons/loft.svg +keywords: +- developer +- development +- sharing +- share +- multi-tenancy +- tenancy +- cluster +- space +- namespace +- vcluster +- vclusters +kubeVersion: '>=1.22-0' +maintainers: +- email: info@loft.sh + name: Loft Labs, Inc. + url: https://twitter.com/loft_sh +name: loft +sources: +- https://github.com/loft-sh/loft +type: application +version: 4.0.0 diff --git a/charts/loft/loft/4.0.0/app-readme.md b/charts/loft/loft/4.0.0/app-readme.md new file mode 100644 index 0000000000..d566f14929 --- /dev/null +++ b/charts/loft/loft/4.0.0/app-readme.md @@ -0,0 +1,12 @@ +# Loft Chart + +## Namespace & Virtual Cluster Manager for Kubernetes + +- Lightweight Virtual Clusters that are flexible like namespaces but much more powerful +- Sleep Mode to put idle namespaces and virtual clusters asleep and saves up to 70% cloud costs +- Accounts & Account Users to separate tenants in a shared Kubernetes cluster +- Self-Service Namespace Provisioning for account users +- Account Limits to ensure quality of service and fairness when sharing a cluster +- Namespace Templates for secure tenant isolation and self-service namespace initialization +- Multi-Cluster Tenant Management for sharing a pool of clusters +- GitOps-Ready: Custom Resource Definitions for everything loft does diff --git a/charts/loft/loft/4.0.0/templates/NOTES.txt b/charts/loft/loft/4.0.0/templates/NOTES.txt new file mode 100644 index 0000000000..6f54f1872c --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/NOTES.txt @@ -0,0 +1,8 @@ +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 all {{ .Release.Name }} diff --git a/charts/loft/loft/4.0.0/templates/_helpers.tpl b/charts/loft/loft/4.0.0/templates/_helpers.tpl new file mode 100644 index 0000000000..d2ffb20001 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/_helpers.tpl @@ -0,0 +1,68 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +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 "loft.fullname" -}} +{{- printf "loft" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "loft.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{ default (include "loft.fullname" .) .Values.serviceAccount.name }} +{{- else -}} +{{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Default image name for a given product +*/}} +{{- define "loft.defaultImage" -}} +{{- printf "ghcr.io/loft-sh/loft:%s" .Chart.Version -}} +{{- end -}} + +{{- define "loft.image" -}} + {{- if .Values.product -}} + {{- if eq .Values.product "vcluster-pro" -}} + {{- printf "ghcr.io/loft-sh/vcluster-platform:%s" .Chart.Version -}} + {{- else if eq .Values.product "devpod-pro" -}} + {{- printf "ghcr.io/loft-sh/devpod-pro:%s" .Chart.Version -}} + {{- else -}} + {{ include "loft.defaultImage" . }} + {{- end -}} + {{- else -}} + {{ include "loft.defaultImage" . }} + {{- end -}} +{{- end -}} + +{{- define "loft.strategyType" -}} + {{- if and .Values.strategy .Values.strategy.type -}} + {{- .Values.strategy.type -}} + {{- else -}} + {{- if eq (int .Values.replicaCount) 1 -}} + {{ printf "Recreate" }} + {{- else -}} + {{ printf "RollingUpdate" }} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- define "loft.strategy" -}} +{{- $type := include "loft.strategyType" . -}} +type: {{ $type }} +{{- if eq $type "RollingUpdate" }} +rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.replicaCount) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} +{{- end -}} +{{- end -}} diff --git a/charts/loft/loft/4.0.0/templates/apiservice.yaml b/charts/loft/loft/4.0.0/templates/apiservice.yaml new file mode 100644 index 0000000000..11850859e2 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/apiservice.yaml @@ -0,0 +1,58 @@ +{{- if .Values.apiservice }} +{{- if .Values.apiservice.create }} +{{- if not .Values.agentOnly }} +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1.management.loft.sh +spec: + version: v1 + versionPriority: 1000 + group: management.loft.sh + groupPriorityMinimum: 10000 + service: + name: loft-apiservice + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: Service +metadata: + name: loft-apiservice + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + ports: + - name: apiservice + port: 443 + targetPort: 8443 + protocol: TCP + selector: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +--- +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: loft-apiservice-agent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + ports: + - name: apiservice + port: 443 + targetPort: 9444 + protocol: TCP + selector: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +{{- end }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/cert-issuer/issuer.yaml b/charts/loft/loft/4.0.0/templates/cert-issuer/issuer.yaml new file mode 100644 index 0000000000..3497386714 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/cert-issuer/issuer.yaml @@ -0,0 +1,22 @@ +{{- if .Values.certIssuer.create }} +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: {{ .Values.certIssuer.name }} +spec: + acme: + email: {{ .Values.certIssuer.email }} + server: {{ .Values.certIssuer.server }} + privateKeySecretRef: + name: {{ .Values.certIssuer.secretName }} + solvers: + {{- if .Values.certIssuer.httpResolver.enabled }} + - http01: + ingress: + class: {{ .Values.certIssuer.httpResolver.ingressClass }} + {{- end }} + {{- range .Values.certIssuer.resolvers }} + - +{{ toYaml . | indent 6 }} + {{- end }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/deployment.yaml b/charts/loft/loft/4.0.0/templates/deployment.yaml new file mode 100644 index 0000000000..65119da232 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/deployment.yaml @@ -0,0 +1,188 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "loft.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + matchLabels: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} + replicas: {{ .Values.replicaCount }} + strategy: +{{ include "loft.strategy" . | indent 4}} + template: + metadata: + labels: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + {{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + terminationGracePeriodSeconds: 10 + serviceAccountName: {{ template "loft.serviceAccountName" . }} + volumes: + {{- if .Values.volumes }} +{{ toYaml .Values.volumes | indent 8 }} + {{- end }} + {{- if or (and .Values.persistence .Values.persistence.enabled) (and .Values.audit .Values.audit.persistence.enabled) }} + - name: loft-data + persistentVolumeClaim: + claimName: {{ template "loft.fullname" . }}-audit + {{- else }} + - name: loft-data + emptyDir: {} + {{- end }} + {{- if .Values.additionalCA }} + - name: loft-additional-ca + secret: + secretName: loft-additional-ca + {{- end }} + containers: + - name: manager + {{- if .Values.agentOnly }} + command: ["loft", "agent"] + {{- end }} + image: {{ default (include "loft.image" .) .Values.image }} + ports: + - name: http + containerPort: 8080 + - name: https + containerPort: 10443 + - name: https-webhook + containerPort: 9443 + - name: http-wakeup + containerPort: 9090 + {{- if .Values.livenessProbe }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8080 + failureThreshold: 30 + initialDelaySeconds: 5 + periodSeconds: 5 + {{- end }} + {{- end }} + {{- if .Values.readinessProbe }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /healthz + port: 8080 + failureThreshold: 30 + initialDelaySeconds: 5 + periodSeconds: 5 + {{- end }} + {{- end }} + env: + - name: ADMIN_EMAIL + value: {{ .Values.admin.email | quote }} + - name: CHART_VERSION + value: {{ .Chart.Version }} + {{- if .Values.admin.password }} + - name: ADMIN_PASSWORD_HASH + value: {{ .Values.admin.password | sha256sum | quote }} + {{- end }} + {{- if (gt (int .Values.replicaCount) 1) }} + {{- if not (and .Values.env .Values.env.LEADER_ELECTION_ENABLED) }} + - name: LEADER_ELECTION_ENABLED + value: "true" + {{- end }} + {{- end }} + {{- range $key, $value := .Values.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: +{{ toYaml $value | indent 12 }} + {{- end }} + {{- if .Values.tls }} + {{- if .Values.tls.enabled }} + - name: PROXY_TLS_CERT + valueFrom: + secretKeyRef: + name: {{ .Values.tls.secret }} + key: {{ .Values.tls.crtKey }} + - name: PROXY_TLS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.tls.secret }} + key: {{ .Values.tls.keyKey }} + {{- end }} + {{- end }} + {{- if .Values.logging }} + - name: LOFT_LOG_ENCODING + value: {{ default "console" .Values.logging.encoding }} + - name: LOFT_LOG_LEVEL + value: {{ default "info" .Values.logging.level }} + {{- end }} + {{- if .Values.insecureSkipVerify }} + - name: TS_DEBUG_TLS_DIAL_INSECURE_SKIP_VERIFY + value: "true" + {{- end }} + {{- range $key, $value := .Values.env }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + volumeMounts: + {{- if .Values.volumeMounts }} +{{ toYaml .Values.volumeMounts | indent 10 }} + {{- end }} + - mountPath: /var/lib/loft + name: loft-data + {{- if .Values.additionalCA }} + - name: loft-additional-ca + mountPath: /etc/ssl/certs/loft-additional-ca.crt + readOnly: true + subPath: ca.crt + {{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 | replace "enabled: true" "" | replace "enabled: false" "" }} + {{- if .Values.audit }} + {{- if .Values.audit.enableSideCar }} + - name: audit + image: "{{ .Values.audit.image }}" + command: ["sh"] + args: ["-c", "touch /var/lib/loft/audit.log && tail -F /var/lib/loft/audit.log"] + volumeMounts: + - mountPath: /var/lib/loft + name: loft-data + {{- end }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} diff --git a/charts/loft/loft/4.0.0/templates/ingress-wakeup-service.yaml b/charts/loft/loft/4.0.0/templates/ingress-wakeup-service.yaml new file mode 100644 index 0000000000..0431ea9bc8 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/ingress-wakeup-service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: loft-ingress-wakeup-agent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + loft.sh/service: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + ports: + - name: http-wakeup + port: 9090 + targetPort: 9090 + protocol: TCP + selector: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} diff --git a/charts/loft/loft/4.0.0/templates/ingress.yaml b/charts/loft/loft/4.0.0/templates/ingress.yaml new file mode 100644 index 0000000000..dba8c15e92 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/ingress.yaml @@ -0,0 +1,48 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Values.ingress.name }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- with .Values.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "43200" + nginx.ingress.kubernetes.io/proxy-send-timeout: "43200" + nginx.org/websocket-services: loft + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.ingressClass }} + ingressClassName: {{ .Values.ingress.ingressClass }} + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.path }} + pathType: ImplementationSpecific + backend: + service: + name: loft + port: + number: 80 + {{- if .Values.ingress.tls.enabled }} + tls: + - hosts: + - {{ .Values.ingress.host }} + {{- if .Values.ingress.tls.secret }} + secretName: {{ .Values.ingress.tls.secret }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/pdb.yaml b/charts/loft/loft/4.0.0/templates/pdb.yaml new file mode 100644 index 0000000000..bb4699e7a4 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/pdb.yaml @@ -0,0 +1,24 @@ +{{ if (dig "podDisruptionBudget" "create" "true" (.Values|merge (dict) )) }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "loft.fullname" . }} + labels: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +spec: + {{- if .Values.podDisruptionBudget }} + minAvailable: {{ (dig "podDisruptionBudget" "minAvailable" "" (.Values|merge (dict) )) }} + {{- else }} + minAvailable: 1 + {{- end }} + {{- if (dig "podDisruptionBudget" "maxUnavailable" false (.Values|merge (dict) )) }} + maxUnavailable: {{ (dig "podDisruptionBudget" "maxUnavailable" "" (.Values|merge (dict) )) }} + {{- end }} + selector: + matchLabels: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +{{ end }} + diff --git a/charts/loft/loft/4.0.0/templates/pvc.yaml b/charts/loft/loft/4.0.0/templates/pvc.yaml new file mode 100644 index 0000000000..76da4f8118 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/pvc.yaml @@ -0,0 +1,41 @@ +{{- if and .Values.audit .Values.audit.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "loft.fullname" . }}-audit + {{- if .Values.commonAnnotations }} + annotations: + {{- toYaml .Values.commonAnnotations | nindent 4 }} + {{- end }} +spec: + {{- if .Values.audit.persistence.accessModes }} + accessModes: +{{ toYaml .Values.audit.persistence.accessModes | indent 4 }} + {{- else }} + accessModes: ["ReadWriteOnce"] + {{- end }} + storageClassName: {{ .Values.audit.persistence.storageClassName }} + resources: + requests: + storage: {{ .Values.audit.persistence.size }} +{{- else if and .Values.persistence .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "loft.fullname" . }}-audit + {{- if .Values.commonAnnotations }} + annotations: + {{- toYaml .Values.commonAnnotations | nindent 4 }} + {{- end }} +spec: + {{- if .Values.persistence.accessModes }} + accessModes: +{{ toYaml .Values.persistence.accessModes | indent 4 }} + {{- else }} + accessModes: ["ReadWriteOnce"] + {{- end }} + storageClassName: {{ .Values.persistence.storageClassName }} + resources: + requests: + storage: {{ .Values.persistence.size }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/rbac/clusterrolebinding.yaml b/charts/loft/loft/4.0.0/templates/rbac/clusterrolebinding.yaml new file mode 100644 index 0000000000..175eedbdb0 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/rbac/clusterrolebinding.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: loft-management-admin + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- if .Values.commonAnnotations }} + annotations: + {{- toYaml .Values.commonAnnotations | nindent 4 }} + {{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "loft.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Values.serviceAccount.clusterRole }} + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/charts/loft/loft/4.0.0/templates/secret.yaml b/charts/loft/loft/4.0.0/templates/secret.yaml new file mode 100644 index 0000000000..f0ed0930e6 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/secret.yaml @@ -0,0 +1,101 @@ +{{- if .Values.config }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: loft-manager-config + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: + loft.sh/version: {{ .Chart.Version }} + {{- if or .Values.commonAnnotations .Values.secretAnnotations }} + {{- with .Values.secretAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + config: {{ toYaml .Values.config | b64enc }} +{{- end }} + +{{- if .Values.agentValues }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: loft-default-agent-values + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: + {{- if or .Values.commonAnnotations .Values.agentSecretAnnotations }} + {{- with .Values.agentSecretAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + values: {{ toYaml .Values.agentValues | b64enc }} +{{- end }} + +{{- if .Values.agentOnly }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: loft-agent-connection + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: + {{- if or .Values.commonAnnotations .Values.agentSecretAnnotations }} + {{- with .Values.agentSecretAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + token: {{ toYaml .Values.token | b64enc }} + url: {{ toYaml .Values.url | b64enc }} +{{- end }} + +{{- if .Values.additionalCA }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: loft-additional-ca + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: + {{- if or .Values.commonAnnotations .Values.agentSecretAnnotations }} + {{- with .Values.agentSecretAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + ca.crt: {{ .Values.additionalCA | quote }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/service.yaml b/charts/loft/loft/4.0.0/templates/service.yaml new file mode 100644 index 0000000000..7394c60797 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/service.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: loft + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + loft.sh/service: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- with .Values.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - name: http + port: 80 + targetPort: 8080 + nodePort: {{ .Values.service.httpNodePort }} + protocol: TCP + - name: https + port: 443 + targetPort: 10443 + nodePort: {{ .Values.service.httpsNodePort }} + protocol: TCP + selector: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} diff --git a/charts/loft/loft/4.0.0/templates/serviceaccount.yaml b/charts/loft/loft/4.0.0/templates/serviceaccount.yaml new file mode 100644 index 0000000000..0ca0fb51e8 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/serviceaccount.yaml @@ -0,0 +1,25 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "loft.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.serviceAccount.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- if .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .Values.serviceAccount.imagePullSecrets | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/templates/servicemonitor.yaml b/charts/loft/loft/4.0.0/templates/servicemonitor.yaml new file mode 100644 index 0000000000..d85207d7af --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/servicemonitor.yaml @@ -0,0 +1,32 @@ +{{- if .Values.serviceMonitor }} +{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: loft + {{- if .Values.serviceMonitor.namespace }} + namespace: {{ .Values.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: + app: {{ template "loft.fullname" . }} +{{- if .Values.serviceMonitor.labels }} +{{ toYaml .Values.serviceMonitor.labels | indent 4}} +{{- end }} +spec: + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + targetPort: {{ .Values.serviceMonitor.targetPort }} + path: {{ .Values.serviceMonitor.path }} + interval: {{ .Values.serviceMonitor.interval }} + scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }} + jobLabel: {{ .Values.serviceMonitor.jobLabel }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + loft.sh/service: {{ template "loft.fullname" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/loft/loft/4.0.0/templates/webhook.yaml b/charts/loft/loft/4.0.0/templates/webhook.yaml new file mode 100644 index 0000000000..7b7f1ed6a8 --- /dev/null +++ b/charts/loft/loft/4.0.0/templates/webhook.yaml @@ -0,0 +1,24 @@ +{{- if .Values.webhook }} +{{- if .Values.webhook.create }} +apiVersion: v1 +kind: Service +metadata: + name: loft-webhook-agent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "loft.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + ports: + - name: https-webhook + port: 443 + targetPort: 9443 + protocol: TCP + selector: + app: {{ template "loft.fullname" . }} + release: {{ .Release.Name }} +{{- end }} +{{- end }} diff --git a/charts/loft/loft/4.0.0/tests/README.md b/charts/loft/loft/4.0.0/tests/README.md new file mode 100644 index 0000000000..ef1c551a38 --- /dev/null +++ b/charts/loft/loft/4.0.0/tests/README.md @@ -0,0 +1,9 @@ +Add [unittest plugin](https://github.com/helm-unittest/helm-unittest) via: +``` +helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` + +Run tests via: +``` +helm unittest chart +``` diff --git a/charts/loft/loft/4.0.0/tests/deployment_test.yaml b/charts/loft/loft/4.0.0/tests/deployment_test.yaml new file mode 100644 index 0000000000..922346db15 --- /dev/null +++ b/charts/loft/loft/4.0.0/tests/deployment_test.yaml @@ -0,0 +1,201 @@ +suite: Deployment +templates: + - deployment.yaml + +tests: + - it: allow double LEADER_ELECTION_ENABLED + release: + name: my-release + namespace: my-namespace + set: + replicaCount: 3 + env: + LEADER_ELECTION_ENABLED: "false" + asserts: + - hasDocuments: + count: 1 + - notContains: + path: spec.template.spec.containers[0].env + content: + name: "LEADER_ELECTION_ENABLED" + value: "true" + - contains: + path: spec.template.spec.containers[0].env + content: + name: "LEADER_ELECTION_ENABLED" + value: "false" + count: 1 + + - it: automatic LEADER_ELECTION_ENABLED + release: + name: my-release + namespace: my-namespace + set: + replicaCount: 3 + asserts: + - hasDocuments: + count: 1 + - contains: + path: spec.template.spec.containers[0].env + content: + name: "LEADER_ELECTION_ENABLED" + value: "true" + count: 1 + + - it: Preferred node anti-affinity is applied by default + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.template.spec.affinity + value: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: eks.amazonaws.com/capacityType + operator: NotIn + values: + - SPOT + - key: kubernetes.azure.com/scalesetpriority + operator: NotIn + values: + - spot + - key: cloud.google.com/gke-provisioning + operator: NotIn + values: + - spot + + - it: Deployment strategy is applied correctly for Recreate + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.strategy.type + value: Recreate + + - it: Deployment strategy is applied correctly for RollingUpdate + set: + replicaCount: 2 + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.strategy.type + value: RollingUpdate + - equal: + path: spec.strategy.rollingUpdate.maxSurge + value: 1 + - equal: + path: spec.strategy.rollingUpdate.maxUnavailable + value: 1 + - it: SecurityContext defaults + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.template.spec.containers[0].securityContext.privileged + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.capabilities.drop[0] + value: "ALL" + - equal: + path: spec.template.spec.containers[0].securityContext.runAsNonRoot + value: true + + - it: SecurityContext kyverno strict policies + set: + podSecurityContext: + runAsGroup: 1000 + fsGroup: 1000 + supplementalGroups: + - 1000 + securityContext: + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + asserts: + - hasDocuments: + count: 1 + # container checks + - equal: + path: spec.template.spec.containers[0].securityContext.privileged + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.capabilities.drop[0] + value: "ALL" + - equal: + path: spec.template.spec.containers[0].securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - equal: + path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 1000 + # pod checks + - equal: + path: spec.template.spec.securityContext.runAsGroup + value: 1000 + - equal: + path: spec.template.spec.securityContext.fsGroup + value: 1000 + - equal: + path: spec.template.spec.securityContext.supplementalGroups[0] + value: 1000 + - it: SecurityContext kyverno strict policies (backward compatibility with .enabled) + set: + podSecurityContext: + runAsGroup: 1000 + fsGroup: 1000 + supplementalGroups: + - 1000 + securityContext: + enabled: true + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + asserts: + - hasDocuments: + count: 1 + - notExists: + path: spec.template.spec.containers[0].securityContext.enabled + - it: SecurityContext kyverno strict policies (backward compatibility with .enabled=false) + set: + podSecurityContext: + runAsGroup: 1000 + fsGroup: 1000 + supplementalGroups: + - 1000 + securityContext: + enabled: false + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + asserts: + - hasDocuments: + count: 1 + - notExists: + path: spec.template.spec.containers[0].securityContext.enabled diff --git a/charts/loft/loft/4.0.0/tests/pdb_test.yaml b/charts/loft/loft/4.0.0/tests/pdb_test.yaml new file mode 100644 index 0000000000..7543374d37 --- /dev/null +++ b/charts/loft/loft/4.0.0/tests/pdb_test.yaml @@ -0,0 +1,78 @@ +suite: PodDisruptionBudget +templates: + - pdb.yaml + +tests: + - it: enabled by default + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.minAvailable + value: 1 + - isNull: + path: spec.maxUnavailable + + - it: enabled by default on upgrade + set: + podDisruptionBudget: {} + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.minAvailable + value: 1 + - isNull: + path: spec.maxUnavailable + + - it: can be disabled + set: + podDisruptionBudget: + create: false + asserts: + - hasDocuments: + count: 0 + + - it: minAvailable is set correctly + set: + podDisruptionBudget: + create: true + minAvailable: 2 + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.minAvailable + value: 2 + - isNull: + path: spec.maxUnavailable + + - it: maxUnavailable is set correctly + set: + podDisruptionBudget: + create: true + maxUnavailable: 2 + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.maxUnavailable + value: 2 + - isNull: + path: spec.minAnavailable + + - it: selector is set correctly + release: + name: loft + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.selector.matchLabels.app + value: loft + - equal: + path: spec.selector.matchLabels.release + value: loft + - equal: + path: spec.minAvailable + value: 1 diff --git a/charts/loft/loft/4.0.0/tests/secret_test.yaml b/charts/loft/loft/4.0.0/tests/secret_test.yaml new file mode 100644 index 0000000000..c5b87c3858 --- /dev/null +++ b/charts/loft/loft/4.0.0/tests/secret_test.yaml @@ -0,0 +1,27 @@ +suite: Secret +templates: + - secret.yaml + +tests: + - it: AdditionalCA + set: + additionalCA: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5ekNDQWJPZ0F3SUJBZ0lRQnpRT0xkdVVHQXBSY0pTM2ZyU0dPREFOQmdrcWhraUc5dzBCQVFzRkFEQUEKTUI0WERUSTBNRGt4T1RFd01qQXdPVm9YRFRJME1USXhPREV3TWpBd09Wb3dBRENDQVNJd0RRWUpLb1pJaHZjTgpBUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTGZpdEVVdVJyNnRuc1htMlZYb3EvMDdabnpjSDlHUHpyL1VFa2pZClFqazVOSUhoYmRUOUVnOWlJN2RZcWEzMUozMkpJbmlVZ3B6RnF0dFhuNTVvRlhYMndNWXpKS3d5dE9GdkpoZ1QKUkp3U0pOd1BwOWVqTVZCVXFzbnNwYURoazJNL1VsUVBYUkFrcms2VmJvdUtxVUN0Y1VoWmF1NW82UmlyYzNzMwo3anlJNzJwUG0zNkg5T29uVytuVkIvMitXSVEweUc5UXR2MTJlMnJjSGNnaml1QVYyb2ZXaStlQlE0UjhBSEtpCmh3WEU1cVpFdmxYdGZHb2hzVkJNOElQb1ExYTd4cWRlTHJxVHoydXhGdjJ2Z1ZsRTdhK0pNTlJLdjN4SmY4bmgKbFZPY3E0RGZ3ZGQ4V2hVL2NRWTZ3N1lTbW1hWWNtZWJUWC9nT3dKOTNJYWVaVEVDQXdFQUFhTkJNRDh3RGdZRApWUjBQQVFIL0JBUURBZ1dnTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwUkFRSC9CQlV3RTRJUllUWnlOSEZoCmFpNXNiMlowTG1odmMzUXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSi94Y0ovQ2UvRlVxWlJlUFNvMTNNNEcKUVg1WVJIR0JYTndmUk5kN0RuZTRDcGZlUWYwRmR4UDdqUVVkZTJ2dUFBUFpJVmZpYTVvOXhycjhyNVZXellaZQpHQkMwV1VDL2t2ekkwVGRLUVNod3FYOXdCMGVIa3JIamk5ZWszQktlNHRRZ1gvaGgwM09kcjk4ZGQvazhjd01mClFUQVllMHdlUmNsVlFhSjBrTFR6M3plS1lIMXZTMEl4WGZEQm96S3I1cDQ3SmlXSUUrZ3VWSGJ5SEl1SlJGV0QKQ3RYcEltWU1oR2Zkcnc3Nkl0MUtOdUo2a3NuNk5EN2cyV2tFZzV6d1IwcXp1UUMwVGprcmtHRjhERUc0dUFhZQo3aDIxTmJzWUFqVWRMNGlDaEQ3TmEyVjE4VU9oSVRrcU1UbWozdHJJRy9wZlVtWGdHS1JhV2xLRUlBRU5XUkU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + + documentSelector: + path: metadata.name + value: loft-additional-ca + asserts: + - equal: + path: metadata.name + value: loft-additional-ca + - it: AdditionalCA 2 + set: + additionalCA: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5ekNDQWJPZ0F3SUJBZ0lRQnpRT0xkdVVHQXBSY0pTM2ZyU0dPREFOQmdrcWhraUc5dzBCQVFzRkFEQUEKTUI0WERUSTBNRGt4T1RFd01qQXdPVm9YRFRJME1USXhPREV3TWpBd09Wb3dBRENDQVNJd0RRWUpLb1pJaHZjTgpBUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTGZpdEVVdVJyNnRuc1htMlZYb3EvMDdabnpjSDlHUHpyL1VFa2pZClFqazVOSUhoYmRUOUVnOWlJN2RZcWEzMUozMkpJbmlVZ3B6RnF0dFhuNTVvRlhYMndNWXpKS3d5dE9GdkpoZ1QKUkp3U0pOd1BwOWVqTVZCVXFzbnNwYURoazJNL1VsUVBYUkFrcms2VmJvdUtxVUN0Y1VoWmF1NW82UmlyYzNzMwo3anlJNzJwUG0zNkg5T29uVytuVkIvMitXSVEweUc5UXR2MTJlMnJjSGNnaml1QVYyb2ZXaStlQlE0UjhBSEtpCmh3WEU1cVpFdmxYdGZHb2hzVkJNOElQb1ExYTd4cWRlTHJxVHoydXhGdjJ2Z1ZsRTdhK0pNTlJLdjN4SmY4bmgKbFZPY3E0RGZ3ZGQ4V2hVL2NRWTZ3N1lTbW1hWWNtZWJUWC9nT3dKOTNJYWVaVEVDQXdFQUFhTkJNRDh3RGdZRApWUjBQQVFIL0JBUURBZ1dnTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwUkFRSC9CQlV3RTRJUllUWnlOSEZoCmFpNXNiMlowTG1odmMzUXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSi94Y0ovQ2UvRlVxWlJlUFNvMTNNNEcKUVg1WVJIR0JYTndmUk5kN0RuZTRDcGZlUWYwRmR4UDdqUVVkZTJ2dUFBUFpJVmZpYTVvOXhycjhyNVZXellaZQpHQkMwV1VDL2t2ekkwVGRLUVNod3FYOXdCMGVIa3JIamk5ZWszQktlNHRRZ1gvaGgwM09kcjk4ZGQvazhjd01mClFUQVllMHdlUmNsVlFhSjBrTFR6M3plS1lIMXZTMEl4WGZEQm96S3I1cDQ3SmlXSUUrZ3VWSGJ5SEl1SlJGV0QKQ3RYcEltWU1oR2Zkcnc3Nkl0MUtOdUo2a3NuNk5EN2cyV2tFZzV6d1IwcXp1UUMwVGprcmtHRjhERUc0dUFhZQo3aDIxTmJzWUFqVWRMNGlDaEQ3TmEyVjE4VU9oSVRrcU1UbWozdHJJRy9wZlVtWGdHS1JhV2xLRUlBRU5XUkU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + documentIndex: 1 + asserts: + - equal: + path: metadata.name + value: loft-additional-ca + - equal: + path: data["ca.crt"] + value: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5ekNDQWJPZ0F3SUJBZ0lRQnpRT0xkdVVHQXBSY0pTM2ZyU0dPREFOQmdrcWhraUc5dzBCQVFzRkFEQUEKTUI0WERUSTBNRGt4T1RFd01qQXdPVm9YRFRJME1USXhPREV3TWpBd09Wb3dBRENDQVNJd0RRWUpLb1pJaHZjTgpBUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTGZpdEVVdVJyNnRuc1htMlZYb3EvMDdabnpjSDlHUHpyL1VFa2pZClFqazVOSUhoYmRUOUVnOWlJN2RZcWEzMUozMkpJbmlVZ3B6RnF0dFhuNTVvRlhYMndNWXpKS3d5dE9GdkpoZ1QKUkp3U0pOd1BwOWVqTVZCVXFzbnNwYURoazJNL1VsUVBYUkFrcms2VmJvdUtxVUN0Y1VoWmF1NW82UmlyYzNzMwo3anlJNzJwUG0zNkg5T29uVytuVkIvMitXSVEweUc5UXR2MTJlMnJjSGNnaml1QVYyb2ZXaStlQlE0UjhBSEtpCmh3WEU1cVpFdmxYdGZHb2hzVkJNOElQb1ExYTd4cWRlTHJxVHoydXhGdjJ2Z1ZsRTdhK0pNTlJLdjN4SmY4bmgKbFZPY3E0RGZ3ZGQ4V2hVL2NRWTZ3N1lTbW1hWWNtZWJUWC9nT3dKOTNJYWVaVEVDQXdFQUFhTkJNRDh3RGdZRApWUjBQQVFIL0JBUURBZ1dnTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwUkFRSC9CQlV3RTRJUllUWnlOSEZoCmFpNXNiMlowTG1odmMzUXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSi94Y0ovQ2UvRlVxWlJlUFNvMTNNNEcKUVg1WVJIR0JYTndmUk5kN0RuZTRDcGZlUWYwRmR4UDdqUVVkZTJ2dUFBUFpJVmZpYTVvOXhycjhyNVZXellaZQpHQkMwV1VDL2t2ekkwVGRLUVNod3FYOXdCMGVIa3JIamk5ZWszQktlNHRRZ1gvaGgwM09kcjk4ZGQvazhjd01mClFUQVllMHdlUmNsVlFhSjBrTFR6M3plS1lIMXZTMEl4WGZEQm96S3I1cDQ3SmlXSUUrZ3VWSGJ5SEl1SlJGV0QKQ3RYcEltWU1oR2Zkcnc3Nkl0MUtOdUo2a3NuNk5EN2cyV2tFZzV6d1IwcXp1UUMwVGprcmtHRjhERUc0dUFhZQo3aDIxTmJzWUFqVWRMNGlDaEQ3TmEyVjE4VU9oSVRrcU1UbWozdHJJRy9wZlVtWGdHS1JhV2xLRUlBRU5XUkU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K diff --git a/charts/loft/loft/4.0.0/values.yaml b/charts/loft/loft/4.0.0/values.yaml new file mode 100644 index 0000000000..60eb10d1ec --- /dev/null +++ b/charts/loft/loft/4.0.0/values.yaml @@ -0,0 +1,215 @@ +# If agentOnly is true, will deploy only the agent +agentOnly: false +# If an admin user should be created during deployment +admin: + create: true + username: admin + password: "my-password" +# Loft service options +service: + type: ClusterIP + # labels: {} # {key: value} map of labels for the service + # annotations: {} # {key: value} map of annotations for the service +# Ingress options to use loft behind an ingress +ingress: + enabled: false + name: loft-ingress + # labels: {} # {key: value} map of labels for the ingress + # annotations: {} # {key: value} map of annotations for the ingress + host: loft.mydomain.tld + ingressClass: nginx + path: / + tls: + enabled: true + secret: loft-tls +# TLS configuration with a custom cert and key +# Make sure the secret exists prior to deploying loft, +# otherwise the loft pod will not be able to start +tls: + enabled: false + secret: loft-tls + crtKey: tls.crt + keyKey: tls.key +# Additional annotations for the loft deployment +# annotations: {} + +# Additional labels for the loft deployment +# labels: {} + +# Additional annotations for the loft pod +# podAnnotations: {} + +# Additional common annotations for all resources +# commonAnnotations: {} + +# Annotations for the loft-config secret +# secretAnnotations: {} + +# Annotations for the loft-default-agent-values secret +# agentSecretAnnotations: {} + +# Additional labels for the loft pod +# podLabels: {} + +# Default values for loft deployment. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default value is: ghcr.io/loft:{{ .Chart.Version }} +# Note: images prior to 3.1 use the docker.io/loftsh registry +# image: ghcr.io/loft-sh/loft + +# Additional enviroment variables in the form of +# VAR_NAME: VAR_VALUE +env: {} +# Additional environment variables in the form of +# VAR_NAME: +# secretKeyRef: +# name: mysecret +# key: username +envValueFrom: {} +# Replica amount of the loft deployment +replicaCount: 1 +# Deployment strategy to be used for rolling out new replicasets +# strategy: +# type: RollingUpdate + +# Resources of the loft deployment +resources: + requests: + memory: 256Mi + cpu: 200m + limits: + memory: 4Gi + cpu: "2" +# Additional volumes that should be mounted to the loft deployment +volumes: [] +# Additional volume mounts that should be mounted into the loft container +volumeMounts: [] +# If the readinessProbe should be enabled +readinessProbe: + enabled: true +# If the livenessProbe should be enabled +livenessProbe: + enabled: true +# If an extension api service should be registered for +# the loft apis in kubernetes +apiservice: + create: true +# Additional loft service account options +serviceAccount: + name: loft + create: true + clusterRole: cluster-admin + imagePullSecrets: [] + annotations: {} +# If a cert issuer should be created for loft +certIssuer: + create: false + email: "" # This is a required field if create == true + name: lets-encrypt-http-issuer + secretName: loft-letsencrypt-credentials + server: https://acme-v02.api.letsencrypt.org/directory + httpResolver: + enabled: true + ingressClass: nginx + resolvers: [] +# Persistence options +persistence: + enabled: false + size: 30Gi + # Optional storage class + #storageClassName: my-storage-class + # Optional custom accessModes + #accessModes: ["ReadWriteOnce"] +# Additional options for audit logging +audit: + enableSideCar: false + image: library/alpine:3.13.1 + # Deprecated, use persistence instead + persistence: + enabled: false + size: 10Gi + # Optional storage class + #storageClassName: my-storage-class + # Optional custom accessModes + #accessModes: ["ReadWriteOnce"] +# Prometheus Service Monitor Configuration +serviceMonitor: + enabled: false + jobLabel: loft + targetPort: 8080 + path: /metrics + interval: 60s + scrapeTimeout: 30s + labels: {} +# Loft config to use, all options can be seen at: +# https://loft.sh/docs/admin/config +config: + audit: + enabled: true +# Enables running loft agent with a security context that: +# - disables privileged escalation +# - drops all capabilities +# - runs as non-root +securityContext: + # DEPRECATED: enabled field is deprecated, please use only fields valid for pod.spec.containers.securityContext here + enabled: true + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - ALL + runAsNonRoot: true +# Sets pod security context for loft +# Example: +# podSecurityContext: +# fsGroup: 2000 +podSecurityContext: {} +# Loft *agent* default values to use, options can be seen in the loft-agent chart values: +# https://github.com/loft-sh/loft/blob/master/chart/values.yaml +# agent values cluster annotations take precedent over these values +agentValues: {} +# if the webhook should be deployed +webhook: + create: true +# Configures structured logging within Loft +logging: + encoding: console # Can be either json or console + level: info # Can be either: debug, info, error +# The product to use +product: loft +# Token is used to connect to the network peer coordinator server of a Loft instance +token: "" +# URL is used to connect as the endpoint of the network peer coordinator server +url: "" +# AdditionalCA is used to add an additional CA certificate to the application's +# x509 root ca verification flow. Needs to be base64 encoded. +additionalCA: "" +# insecureSkipVerify is used to omit tls verification within loft and all its +# managed components +insecureSkipVerify: false +podDisruptionBudget: + ## Specifies whether a Pod disruption budget should be created + ## + create: true + minAvailable: 1 + # maxUnavailable: 1 +affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: eks.amazonaws.com/capacityType + operator: NotIn + values: + - SPOT + - key: kubernetes.azure.com/scalesetpriority + operator: NotIn + values: + - spot + - key: cloud.google.com/gke-provisioning + operator: NotIn + values: + - spot diff --git a/index.yaml b/index.yaml index 9bf43ad03f..6546023833 100644 --- a/index.yaml +++ b/index.yaml @@ -4274,6 +4274,38 @@ entries: - assets/cerbos/cerbos-0.37.0.tgz version: 0.37.0 cf-runtime: + - annotations: + artifacthub.io/changes: | + - kind: fixed + description: "updated docker-builder version to allow users to specify the qemu image on docker builds" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime + apiVersion: v2 + created: "2024-10-18T00:35:23.204669848Z" + dependencies: + - name: cf-common + repository: oci://quay.io/codefresh/charts + version: 0.16.0 + description: A Helm chart for Codefresh Runner + digest: 4a26f701b28608fad3775e4a1b45ccf0bacae07e3e211b9140623dbd3b9c9dc2 + home: https://codefresh.io/ + icon: file://assets/icons/cf-runtime.png + keywords: + - codefresh + - runner + kubeVersion: '>=1.18-0' + maintainers: + - name: codefresh + url: https://codefresh-io.github.io/ + name: cf-runtime + sources: + - https://github.com/codefresh-io/venona + urls: + - assets/codefresh/cf-runtime-6.4.6.tgz + version: 6.4.6 - annotations: artifacthub.io/changes: | - kind: added @@ -26480,6 +26512,42 @@ entries: - assets/linkerd/linkerd-crds-2024.3.3.tgz version: 2024.3.3 loft: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Loft + catalog.cattle.io/kube-version: '>=1.22-0' + catalog.cattle.io/release-name: loft + apiVersion: v2 + created: "2024-10-18T00:35:26.14137391Z" + description: Secure Cluster Sharing, Self-Service Namespace Provisioning and Virtual + Clusters + digest: e0e5b4bcfeeec3ef88edc34ade76aa5a5fa101d3c5dd7c8461ac6e4d182f5ef2 + home: https://loft.sh + icon: file://assets/icons/loft.svg + keywords: + - developer + - development + - sharing + - share + - multi-tenancy + - tenancy + - cluster + - space + - namespace + - vcluster + - vclusters + kubeVersion: '>=1.22-0' + maintainers: + - email: info@loft.sh + name: Loft Labs, Inc. + url: https://twitter.com/loft_sh + name: loft + sources: + - https://github.com/loft-sh/loft + type: application + urls: + - assets/loft/loft-4.0.0.tgz + version: 4.0.0 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Loft @@ -27147,6 +27215,54 @@ entries: - assets/loft/loft-3.2.0.tgz version: 3.2.0 microgateway: + - annotations: + artifacthub.io/category: security + artifacthub.io/license: MIT + artifacthub.io/links: | + - name: Airlock Microgateway Documentation + url: https://docs.airlock.com/microgateway/4.3/ + - name: Airlock Microgateway Labs + url: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=artifacthub.io + - name: Airlock Microgateway Forum + url: https://forum.airlock.com/ + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Airlock Microgateway + catalog.cattle.io/kube-version: '>=1.25.0-0' + catalog.cattle.io/release-name: microgateway + charts.openshift.io/name: Airlock Microgateway + apiVersion: v2 + appVersion: 4.3.4 + created: "2024-10-18T00:35:22.811065588Z" + description: A Helm chart for deploying the Airlock Microgateway + digest: 7d96cb36c9311d41f83356734b1df066248015fe1d0b6db6ee7d70cf2289faa0 + home: https://www.airlock.com/en/microgateway + icon: file://assets/icons/microgateway.svg + keywords: + - WAF + - Web Application Firewall + - WAAP + - Web Application and API protection + - OWASP + - Airlock + - Microgateway + - Security + - Filtering + - DevSecOps + - shift left + - control plane + - Operator + kubeVersion: '>=1.25.0-0' + maintainers: + - email: support@airlock.com + name: Airlock + url: https://www.airlock.com/ + name: microgateway + sources: + - https://github.com/airlock/microgateway + type: application + urls: + - assets/airlock/microgateway-4.3.4.tgz + version: 4.3.4 - annotations: artifacthub.io/category: security artifacthub.io/license: MIT @@ -27388,6 +27504,53 @@ entries: - assets/airlock/microgateway-4.2.3.tgz version: 4.2.3 microgateway-cni: + - annotations: + artifacthub.io/category: security + artifacthub.io/license: MIT + artifacthub.io/links: | + - name: Airlock Microgateway Documentation + url: https://docs.airlock.com/microgateway/4.3/ + - name: Airlock Microgateway Labs + url: https://play.instruqt.com/airlock/invite/hyi9fy4b4jzc?icp_referrer=artifacthub.io + - name: Airlock Microgateway Forum + url: https://forum.airlock.com/ + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Airlock Microgateway CNI + catalog.cattle.io/kube-version: '>=1.25.0-0' + catalog.cattle.io/release-name: microgateway-cni + charts.openshift.io/name: Airlock Microgateway CNI + apiVersion: v2 + appVersion: 4.3.4 + created: "2024-10-18T00:35:22.81463947Z" + description: A Helm chart for deploying the Airlock Microgateway CNI plugin + digest: c0778f7f5b9a95bb2385d5a03aa7f43e47b88ea7610ddb2a6a6c955d7683a02b + home: https://www.airlock.com/en/microgateway + icon: file://assets/icons/microgateway-cni.svg + keywords: + - WAF + - Web Application Firewall + - WAAP + - Web Application and API protection + - OWASP + - Airlock + - Microgateway + - Security + - Filtering + - DevSecOps + - shift left + - CNI + kubeVersion: '>=1.25.0-0' + maintainers: + - email: support@airlock.com + name: Airlock + url: https://www.airlock.com/ + name: microgateway-cni + sources: + - https://github.com/airlock/microgateway + type: application + urls: + - assets/airlock/microgateway-cni-4.3.4.tgz + version: 4.3.4 - annotations: artifacthub.io/category: security artifacthub.io/license: MIT @@ -45193,4 +45356,4 @@ entries: urls: - assets/netfoundry/ziti-host-1.5.1.tgz version: 1.5.1 -generated: "2024-10-17T00:35:31.131133003Z" +generated: "2024-10-18T00:35:22.797392069Z"