From 6584189d24d4f6f047b5f23746dfd25488dc6ba2 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Mon, 11 Oct 2021 10:18:37 -0600 Subject: [PATCH 1/2] Add NSM package --- .../generated-changes/overlay/app-readme.md | 5 + .../generated-changes/overlay/questions.yaml | 197 ++++++++++++++++++ .../generated-changes/patch/Chart.yaml.patch | 10 + packages/nginx-service-mesh/package.yaml | 2 + 4 files changed, 214 insertions(+) create mode 100644 packages/nginx-service-mesh/generated-changes/overlay/app-readme.md create mode 100644 packages/nginx-service-mesh/generated-changes/overlay/questions.yaml create mode 100644 packages/nginx-service-mesh/generated-changes/patch/Chart.yaml.patch create mode 100644 packages/nginx-service-mesh/package.yaml diff --git a/packages/nginx-service-mesh/generated-changes/overlay/app-readme.md b/packages/nginx-service-mesh/generated-changes/overlay/app-readme.md new file mode 100644 index 000000000..5f4fda928 --- /dev/null +++ b/packages/nginx-service-mesh/generated-changes/overlay/app-readme.md @@ -0,0 +1,5 @@ +# NGINX Service Mesh + +[NGINX Service Mesh](https://docs.nginx.com/nginx-service-mesh/) is a fully integrated lightweight service mesh that leverages a data plane powered by NGINX Plus to manage container traffic in Kubernetes environments. + +NGINX Service Mesh is currently only supported in Rancher 2.6+ when deploying from the Apps and Marketplace. NGINX Service Mesh is not currently supported on k3s. diff --git a/packages/nginx-service-mesh/generated-changes/overlay/questions.yaml b/packages/nginx-service-mesh/generated-changes/overlay/questions.yaml new file mode 100644 index 000000000..933e22c5f --- /dev/null +++ b/packages/nginx-service-mesh/generated-changes/overlay/questions.yaml @@ -0,0 +1,197 @@ +questions: +- variable: useDefaultImages + default: true + description: "Use default image settings." + label: Use default images + type: boolean + show_subquestion_if: false + group: "Image Registry" + subquestions: + - variable: registry.server + default: "docker-registry.nginx.com/nsm" + description: "Hostname:port (if needed) for registry and path to images." + label: Image registry server + type: string + - variable: registry.imageTag + default: "1.2.1" + description: "Tag used for pulling images from registry." + label: Image tag + type: string + - variable: registry.key + default: "" + description: "Contents of your Google Cloud JSON key file. Cannot be used with username or password." + label: Image registry key + type: string + - variable: registry.username + default: "" + description: "Username for accessing private registry." + label: Image registry username + type: string + - variable: registry.password + default: "" + description: "Password for accessing private registry." + label: Image registry password + type: string + - variable: registry.disablePublicImages + default: false + description: "Do not pull third party images from public repositories. If true, registry.server is used for all images." + label: Disable public images + type: boolean + - variable: registry.imagePullPolicy + default: "IfNotPresent" + description: "Image pull policy." + label: Image pull policy + type: string +- variable: useMtlsDefaults + default: true + description: "Use default mTLS settings." + label: Use default mTLS settings + type: boolean + show_subquestion_if: false + group: "Mutual TLS" + subquestions: + - variable: mtls.mode + default: "permissive" + description: "mTLS mode for pod-to-pod communication." + label: mTLS mode + type: enum + options: + - "off" + - "permissive" + - "strict" + - variable: mtls.caTTL + default: "720h" + description: "The CA/signing key TTL in hours(h) or minutes(m)." + label: mTLS caTTL + type: string + - variable: mtls.svidTTL + default: "1h" + description: "The TTL of certificates issued to workloads in hours(h) or minutes(m)." + label: mTLS svidTTL + type: string + - variable: mtls.trustDomain + default: "example.org" + description: "The trust domain of the NGINX Service Mesh." + label: mTLS trust domain + type: string + - variable: mtls.persistentStorage + default: "on" + description: "Use persistent storage; 'on' assumes that a StorageClass exists." + label: mTLS persistent storage + type: enum + options: + - "on" + - "off" + - variable: mtls.spireServerKeyManager + default: "disk" + description: "Storage logic for Spire Server's private keys." + label: mTLS spire server key manager + type: enum + options: + - "disk" + - "memory" +- variable: useTracingDefaults + default: true + description: "Use default tracing settings." + label: Use default tracing settings + type: boolean + show_subquestion_if: false + group: "Tracing" + subquestions: + - variable: tracing.disable + default: false + description: "Disable tracing for all services." + label: Disable tracing + type: boolean + - variable: tracing.address + default: "" + description: "The address of a tracing server deployed in your Kubernetes cluster." + label: Tracing address + type: string + - variable: tracing.backend + default: "jaeger" + description: "The tracing backend that you want to use." + label: Tracing backend + type: enum + options: + - "jaeger" + - "zipkin" + - "datadog" + - variable: tracing.sampleRate + default: 0.01 + description: "The sample rate to use for tracing. Float between 0 and 1." + label: Tracing sample rate + type: float +- variable: autoInjection.disable + default: false + description: "Disable automatic sidecar injection upon resource creation." + label: Disable auto injection + type: boolean + group: "General Settings" +- variable: accessControlMode + default: "allow" + description: "Default access control mode for service-to-service communication." + label: Access control mode + type: enum + options: + - "allow" + - "deny" + group: "General Settings" +- variable: deployGrafana + default: true + description: "Deploy Grafana as a part of NGINX Service Mesh." + label: Deploy Grafana + type: boolean + group: "General Settings" +- variable: nginxErrorLogLevel + default: "warn" + description: "NGINX error log level." + label: NGINX error log level. + type: enum + options: + - "debug" + - "info" + - "notice" + - "warn" + - "error" + - "crit" + - "alert" + - "emerg" + group: "General Settings" +- variable: nginxLogFormat + default: "default" + description: "NGINX log format." + label: NGINX log format. + type: enum + options: + - "default" + - "json" + group: "General Settings" +- variable: nginxLBMethod + default: "least_time" + description: "NGINX load balancing method." + label: NGINX load balancing method. + type: enum + options: + - "least_conn" + - "least_time" + - "least_time last_byte" + - "least_time last_byte inflight" + - "random" + - "random two" + - "random two least_conn" + - "random two least_time" + - "random two least_time=last_byte" + - "round_robin" + group: "General Settings" +- variable: prometheusAddress + description: "The address of a Prometheus server deployed in your Kubernetes cluster." + label: Prometheus address. + type: string + group: "General Settings" +- variable: rancher + default: true + description: "Enables Rancher for NGINX Service Mesh (do not disable)." + label: Rancher + type: boolean + group: "General Settings" diff --git a/packages/nginx-service-mesh/generated-changes/patch/Chart.yaml.patch b/packages/nginx-service-mesh/generated-changes/patch/Chart.yaml.patch new file mode 100644 index 000000000..638b12209 --- /dev/null +++ b/packages/nginx-service-mesh/generated-changes/patch/Chart.yaml.patch @@ -0,0 +1,10 @@ +--- charts-original/Chart.yaml ++++ charts/Chart.yaml +@@ -5,3 +5,7 @@ + kubeVersion: 1.16-0 - 1.21-0 + name: nginx-service-mesh + version: 0.2.1 ++annotations: ++ catalog.cattle.io/certified: partner ++ catalog.cattle.io/release-name: nginx-service-mesh ++ catalog.cattle.io/display-name: NGINX Service Mesh diff --git a/packages/nginx-service-mesh/package.yaml b/packages/nginx-service-mesh/package.yaml new file mode 100644 index 000000000..062593cca --- /dev/null +++ b/packages/nginx-service-mesh/package.yaml @@ -0,0 +1,2 @@ +url: https://raw.githubusercontent.com/nginxinc/helm-charts/master/stable/nginx-service-mesh-0.2.1.tgz +packageVersion: 00 \ No newline at end of file From f2c0e050996a575fd96d96ee8ca519802e8bb026 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Mon, 11 Oct 2021 10:20:49 -0600 Subject: [PATCH 2/2] Add NSM assets/charts --- .../nginx-service-mesh-0.2.100.tgz | Bin 0 -> 34990 bytes .../nginx-service-mesh/0.2.100/Chart.yaml | 11 + .../nginx-service-mesh/0.2.100/README.md | 11 + .../nginx-service-mesh/0.2.100/app-readme.md | 5 + .../nginx-service-mesh/0.2.100/chart-icon.png | Bin 0 -> 12094 bytes .../configs/grafana-dashboard-conf.yaml | 11 + .../configs/grafana-datasources-conf.yaml | 12 + .../configs/grafana-top-dashboard.json | 697 ++++++++++++++++++ .../0.2.100/configs/grafana.ini | 15 + .../configs/k8s-workload-registrar.conf | 9 + .../0.2.100/configs/mesh-config.conf | 60 ++ .../0.2.100/configs/nats.conf | 8 + .../0.2.100/configs/prometheus-config.yaml | 72 ++ .../0.2.100/configs/spire-agent.conf | 33 + .../0.2.100/configs/spire-server.conf | 61 ++ .../upstreamAuthority/aws-credentials.conf | 3 + .../configs/upstreamAuthority/aws-pca-ua.conf | 16 + .../upstreamAuthority/aws-secret-ua.conf | 15 + .../configs/upstreamAuthority/disk-ua.conf | 8 + .../configs/upstreamAuthority/vault-ua.conf | 28 + .../0.2.100/crds/circuitbreaker.yaml | 78 ++ .../0.2.100/crds/httproutegroup.yaml | 68 ++ .../0.2.100/crds/ratelimit.yaml | 175 +++++ .../0.2.100/crds/tcproute.yaml | 23 + .../0.2.100/crds/trafficsplit.yaml | 72 ++ .../0.2.100/crds/traffictarget.yaml | 92 +++ .../nginx-service-mesh/0.2.100/questions.yaml | 197 +++++ .../0.2.100/templates/NOTES.txt | 1 + .../0.2.100/templates/_helpers.tpl | 165 +++++ .../0.2.100/templates/grafana.yaml | 137 ++++ .../0.2.100/templates/jaeger.yaml | 56 ++ .../0.2.100/templates/nats.yaml | 146 ++++ .../0.2.100/templates/nginx-mesh-api.yaml | 323 ++++++++ .../0.2.100/templates/nginx-mesh-metrics.yaml | 157 ++++ .../0.2.100/templates/post-delete-hook.yaml | 144 ++++ .../0.2.100/templates/pre-delete-hook.yaml | 29 + .../0.2.100/templates/pre-install-hook.yaml | 104 +++ .../0.2.100/templates/prometheus.yaml | 114 +++ .../0.2.100/templates/registry-key.yaml | 12 + .../0.2.100/templates/spire-agent.yaml | 141 ++++ .../0.2.100/templates/spire-server.yaml | 466 ++++++++++++ .../0.2.100/templates/zipkin.yaml | 46 ++ .../0.2.100/values.schema.json | 455 ++++++++++++ .../nginx-service-mesh/0.2.100/values.yaml | 209 ++++++ index.yaml | 16 + 45 files changed, 4501 insertions(+) create mode 100644 assets/nginx-service-mesh/nginx-service-mesh-0.2.100.tgz create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/Chart.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/README.md create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/app-readme.md create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/chart-icon.png create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-dashboard-conf.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-datasources-conf.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-top-dashboard.json create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana.ini create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/k8s-workload-registrar.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/mesh-config.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/nats.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/prometheus-config.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-agent.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-server.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-credentials.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-pca-ua.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-secret-ua.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/disk-ua.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/vault-ua.conf create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/circuitbreaker.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/httproutegroup.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/ratelimit.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/tcproute.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/trafficsplit.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/traffictarget.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/questions.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/NOTES.txt create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/_helpers.tpl create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/grafana.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/jaeger.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nats.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-api.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-metrics.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/post-delete-hook.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-delete-hook.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-install-hook.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/prometheus.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/registry-key.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-agent.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-server.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/zipkin.yaml create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.schema.json create mode 100644 charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.yaml diff --git a/assets/nginx-service-mesh/nginx-service-mesh-0.2.100.tgz b/assets/nginx-service-mesh/nginx-service-mesh-0.2.100.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5a444f85b5c41c5345127e20b39a1729ac562811 GIT binary patch literal 34990 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 O0RR8ffsYmdt^xp%2g?=! literal 0 HcmV?d00001 diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/Chart.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/Chart.yaml new file mode 100644 index 000000000..851d386df --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/Chart.yaml @@ -0,0 +1,11 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: NGINX Service Mesh + catalog.cattle.io/release-name: nginx-service-mesh +apiVersion: v2 +appVersion: 1.2.1 +description: NGINX Service Mesh +icon: https://raw.githubusercontent.com/nginxinc/nginx-service-mesh/master/helm-chart/chart-icon.png +kubeVersion: 1.16-0 - 1.21-0 +name: nginx-service-mesh +version: 0.2.100 diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/README.md b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/README.md new file mode 100644 index 000000000..62bca1853 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/README.md @@ -0,0 +1,11 @@ +# NGINX Service Mesh + +Before deploying NGINX Service Mesh, see the [Platform Guide](https://docs.nginx.com/nginx-service-mesh/get-started/kubernetes-platform/) to ensure your environment is properly configured. If [Persistent Storage](https://docs.nginx.com/nginx-service-mesh/get-started/kubernetes-platform/persistent-storage/) is not configured in your cluster, set the `mTLS.persistentStorage` field to `off`. Verify that no other service meshes exist in your Kubernetes cluster. It is advised to install NGINX Service Mesh in a dedicated namespace. + +## Helm Installation and Configuration + +For information on the configuration options and installation process when using Helm with NGINX Service Mesh, see the [Installation Guide](https://docs.nginx.com/nginx-service-mesh/get-started/install-with-helm/). + +## Rancher users + +When deploying NGINX Service Mesh via the Rancher Apps and Marketplace, the Helm value `rancher` is set to `true` by default. This value causes Pods in the `cattle-*`, `ingress-nginx`, and `cert-manager` namespaces to be ignored by the automatic sidecar injection webhook. If this behavior is not desired, the `rancher` value can be set to `false`, or the `injector.nsm.nginx.com/auto-inject` label can be manually removed from these namespaces. diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/app-readme.md b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/app-readme.md new file mode 100644 index 000000000..5f4fda928 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/app-readme.md @@ -0,0 +1,5 @@ +# NGINX Service Mesh + +[NGINX Service Mesh](https://docs.nginx.com/nginx-service-mesh/) is a fully integrated lightweight service mesh that leverages a data plane powered by NGINX Plus to manage container traffic in Kubernetes environments. + +NGINX Service Mesh is currently only supported in Rancher 2.6+ when deploying from the Apps and Marketplace. NGINX Service Mesh is not currently supported on k3s. diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/chart-icon.png b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/chart-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..612ba3569ccad1889bc81221af59f0899d516dac GIT binary patch literal 12094 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 HBIN%8DFREw literal 0 HcmV?d00001 diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-dashboard-conf.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-dashboard-conf.yaml new file mode 100644 index 000000000..9ee1af722 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-dashboard-conf.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 +providers: +- name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: true + editable: true + options: + path: /var/lib/grafana/dashboards + homeDashboardId: nginx-mesh-top diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-datasources-conf.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-datasources-conf.yaml new file mode 100644 index 000000000..acce701bd --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-datasources-conf.yaml @@ -0,0 +1,12 @@ +apiVersion: 1 +datasources: +- name: prometheus + type: prometheus + access: proxy + orgId: 1 + url: http://{{ include "prometheus.address" . }} + isDefault: true + jsonData: + timeInterval: "5s" +version: 1 +editable: true diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-top-dashboard.json b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-top-dashboard.json new file mode 100644 index 000000000..3b56a6f0a --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana-top-dashboard.json @@ -0,0 +1,697 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "prometheus", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(nginxplus_upstream_server_responses{code=~\"1xx|2xx\"}[30s])) / sum(irate(nginxplus_upstream_server_responses[30s]))", + "format": "time_series", + "interval": "5s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "GLOBAL SUCCESS RATE", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "prometheus", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "format": "reqps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 13, + "x": 8, + "y": 0 + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(nginxplus_http_requests_total[30s]))", + "format": "time_series", + "interval": "5s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "GLOBAL REQUEST VOLUME", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "prometheus", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(nginxplus_http_requests_total)", + "format": "time_series", + "interval": "5s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "PODS MONITORED", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 6 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(nginxplus_http_requests_total[30s])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request Volume", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 6 + }, + "hiddenSeries": false, + "id": 123124, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(nginxplus_upstream_server_responses{code=~\"1xx|2xx\"}[30s])) by (app, version) / sum(irate(nginxplus_upstream_server_responses[30s])) by (app, version)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pod Success", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "RSS used by NGINX Service Mesh sidecars", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "hiddenSeries": false, + "id": 123126, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.7", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nginxplus_workers_mem_rss", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Sidecar Memory Usage (RSS)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "Private memory used by NGINX Service Mesh sidecars", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "hiddenSeries": false, + "id": 123128, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.7", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nginxplus_workers_mem_private", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Sidecar Memory Usage (Private)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 27, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "NGINX Mesh Top", + "uid": "N3zQ72OWk", + "version": 1 + } diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana.ini b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana.ini new file mode 100644 index 000000000..4e289e198 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/grafana.ini @@ -0,0 +1,15 @@ +instance_name = nginx-mesh-grafana + +[auth] +disable_login_form = true + +[auth.anonymous] +enabled = true +org_role = Admin + +[auth.basic] +enabled = false + +[analytics] +check_for_updates = false +Events: diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/k8s-workload-registrar.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/k8s-workload-registrar.conf new file mode 100644 index 000000000..cd3302bb4 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/k8s-workload-registrar.conf @@ -0,0 +1,9 @@ +log_level = "debug" +trust_domain = {{ quote .Values.mtls.trustDomain }} +server_socket_path = "/run/spire/sockets/spire-registration.sock" +cluster = "nginx-mesh" +pod_controller = true +add_svc_dns_name = true +mode = "crd" +webhook_enabled = true +webhook_cert_dir = "/tmp/k8s-webhook-server/serving-certs" diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/mesh-config.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/mesh-config.conf new file mode 100644 index 000000000..f0989ecde --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/mesh-config.conf @@ -0,0 +1,60 @@ +{ + "accessControlMode": {{ quote .Values.accessControlMode }}, + "api": { + "address": {{ printf "nginx-mesh-api.%s" .Release.Namespace }}, + "containerPort": 8443, + "port": 443 + }, + "autoInjectorPort": 9443, + "injection": { + "disabledNamespaces": {{ .Values.autoInjection.disabledNamespaces }}, + "enabledNamespaces": {{ .Values.autoInjection.enabledNamespaces }}, + "isAutoInjectEnabled": {{ not .Values.autoInjection.disable }} + }, + "loadBalancingMethod": {{ quote .Values.nginxLBMethod }}, + "mtlsMode": {{ quote .Values.mtls.mode }}, + "namespace": {{ quote .Release.Namespace }}, + "nginxErrorLogLevel": {{ quote .Values.nginxErrorLogLevel }}, + "nginxLogFormat": {{ quote .Values.nginxLogFormat }}, + "prometheusAddress": {{ include "prometheus.address" . | quote }}, + "proxy": { + "ports": { + "incoming": 8888, + "incomingGrpc": 8891, + "incomingGrpcPermissive": 8893, + "incomingNotInKeyval": 8903, + "incomingPermissive": 8890, + "incomingRedirect": 8901, + "incomingTcp": 8904, + "incomingTcpDeny": 8905, + "incomingTcpPermissive": 8907, + "metrics": 8887, + "outgoing": 8889, + "outgoingDefaultEgress": 8894, + "outgoingGrpc": 8892, + "outgoingNotInKeyval": 8902, + "outgoingRedirect": 8900, + "outgoingTcp": 8906, + "plusApi": 8886, + "redirectHealthPort": 8895, + "redirectHealthPortHTTPS": 8896 + }, + "transparent": false + }, + "registryKeyName": {{ if (include "docker-config-json" .) }}{{ include "registry-key-name" . | quote }}{{ else }}""{{ end }}, + "sidecarImage": { + "image": {{ printf "%s/nginx-mesh-sidecar:%s" .Values.registry.server .Values.registry.imageTag }}, + "name": "nginx-mesh-sidecar" + }, + "sidecarInitImage": { + "image": {{ printf "%s/nginx-mesh-init:%s" .Values.registry.server .Values.registry.imageTag }}, + "name": "nginx-mesh-init" + }, + "tracing": { + "backend": {{ quote .Values.tracing.backend }}, + "backendAddress": {{ include "tracing.address" . | quote }}, + "isEnabled": {{ not .Values.tracing.disable }}, + "sampleRate": {{ .Values.tracing.sampleRate }} + }, + "trustDomain": {{ quote .Values.mtls.trustDomain }} + } diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/nats.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/nats.conf new file mode 100644 index 000000000..bea951208 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/nats.conf @@ -0,0 +1,8 @@ +pid_file: "/var/run/nats/nats.pid" +http: 8222 +tls: { + ca_file: "/etc/ssl/ca.crt" + cert_file: "/etc/ssl/tls.crt" + key_file: "/etc/ssl/tls.key" + verify: true +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/prometheus-config.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/prometheus-config.yaml new file mode 100644 index 000000000..b2d7ca0af --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/prometheus-config.yaml @@ -0,0 +1,72 @@ +global: + scrape_interval: 10s +scrape_configs: +- job_name: 'nginx-mesh-sidecars' + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_name] + action: keep + regex: nginx-mesh-sidecar + - action: labelmap + regex: __meta_kubernetes_pod_label_nsm_nginx_com_(.+) + - action: labeldrop + regex: __meta_kubernetes_pod_label_nsm_nginx_com_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod +- job_name: 'nginx-plus-ingress' + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_name] + action: keep + regex: nginx-plus-ingress + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: (.+)(?::\d+);(\d+) + replacement: $1:$2 + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod + - action: labelmap + regex: __meta_kubernetes_pod_label_nsm_nginx_com_(.+) + - action: labeldrop + regex: __meta_kubernetes_pod_label_nsm_nginx_com_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_annotation_nsm_nginx_com_enable_(.+) + metric_relabel_configs: + - source_labels: [__name__] + regex: 'nginx_ingress_controller_upstream_server_response_latency_ms(.+)' + target_label: __name__ + replacement: 'nginxplus_upstream_server_response_latency_ms$1' + - source_labels: [__name__] + regex: 'nginx_ingress_nginxplus(.+)' + target_label: __name__ + replacement: 'nginxplus$1' + - source_labels: [service] + target_label: dst_service + - source_labels: [resource_namespace] + target_label: dst_namespace + - source_labels: [pod_owner] + regex: '(.+)\/(.+)' + target_label: dst_$1 + replacement: $2 + - action: labeldrop + regex: pod_owner + - source_labels: [pod_name] + target_label: dst_pod diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-agent.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-agent.conf new file mode 100644 index 000000000..726af1573 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-agent.conf @@ -0,0 +1,33 @@ +agent { + data_dir = "/run/spire" + log_level = "DEBUG" + server_address = "spire-server" + server_port = "8081" + socket_path = "/run/spire/sockets/agent.sock" + trust_bundle_path = "/run/spire/bundle/bundle.crt" + trust_domain = {{ quote .Values.mtls.trustDomain }} +} + +plugins { + NodeAttestor "k8s_psat" { + plugin_data { + cluster = "nginx-mesh" + } + } + + KeyManager "memory" { + plugin_data { + } + } + + WorkloadAttestor "k8s" { + plugin_data { + skip_kubelet_verification = true + } + } + + WorkloadAttestor "unix" { + plugin_data { + } + } +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-server.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-server.conf new file mode 100644 index 000000000..97a575b41 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/spire-server.conf @@ -0,0 +1,61 @@ +server { + bind_address = "0.0.0.0" + bind_port = "8081" + ca_ttl = {{ quote .Values.mtls.caTTL }} + data_dir = "/run/spire/data" + log_level = "DEBUG" + socket_path = "/run/spire/sockets/spire-registration.sock" + default_svid_ttl = {{ quote .Values.mtls.svidTTL }} + trust_domain = {{ quote .Values.mtls.trustDomain }} + ca_subject = { + country = ["US"], + organization = ["NGINX"], + common_name = "", + } +} + +plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/data/datastore.sqlite3" + } + } + + NodeAttestor "k8s_psat" { + plugin_data { + clusters = { + "nginx-mesh" = { + service_account_allow_list = [{{ printf "%s:spire-agent" .Release.Namespace | quote }}] + } + } + } + } + + Notifier "k8sbundle" { + plugin_data { + namespace = {{ quote .Release.Namespace }} + webhook_label = "spiffe.io/webhook" + api_service_label = "spiffe.io/apiservice" + } + } + + KeyManager {{ quote .Values.mtls.spireServerKeyManager }} { + {{- if eq .Values.mtls.spireServerKeyManager "disk" }} + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + {{- end }} + } + + {{ if .Values.mtls.upstreamAuthority.awsPCA }} + {{ tpl (.Files.Get "configs/upstreamAuthority/aws-pca-ua.conf") . }} + {{ else if .Values.mtls.upstreamAuthority.awsSecret }} + {{ tpl (.Files.Get "configs/upstreamAuthority/aws-secret-ua.conf") . }} + {{ else if .Values.mtls.upstreamAuthority.disk }} + {{ tpl (.Files.Get "configs/upstreamAuthority/disk-ua.conf") . }} + {{ else if .Values.mtls.upstreamAuthority.vault }} + {{ tpl (.Files.Get "configs/upstreamAuthority/vault-ua.conf") . }} + {{ end }} + +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-credentials.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-credentials.conf new file mode 100644 index 000000000..422c92265 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-credentials.conf @@ -0,0 +1,3 @@ +[default] +aws_access_key_id = {{ .Values.mtls.upstreamAuthority.awsPCA.awsAccessKeyID }} +aws_secret_access_key = {{ .Values.mtls.upstreamAuthority.awsPCA.awsSecretAccessKey }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-pca-ua.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-pca-ua.conf new file mode 100644 index 000000000..a296cf881 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-pca-ua.conf @@ -0,0 +1,16 @@ +UpstreamAuthority "aws_pca" { + plugin_data { + region = {{ quote .Values.mtls.upstreamAuthority.awsPCA.region }} + certificate_authority_arn = {{ quote .Values.mtls.upstreamAuthority.awsPCA.certificateAuthorityArn }} + {{- if .Values.mtls.upstreamAuthority.awsPCA.caSigningTemplateArn }} + ca_signing_template_arn = {{ quote .Values.mtls.upstreamAuthority.awsPCA.caSigningTemplateArn }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.awsPCA.signingAlgorithm }} + signing_algorithm = {{ quote .Values.mtls.upstreamAuthority.awsPCA.signingAlgorithm }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.awsPCA.assumeRoleArn }} + assume_role_arn = {{ quote .Values.mtls.upstreamAuthority.awsPCA.assumeRoleArn }}{{end}} + {{- if .Values.mtls.upstreamAuthority.awsPCA.endpoint }} + endpoint = {{ quote .Values.mtls.upstreamAuthority.awsPCA.endpoint }}{{end}} + {{- if .Values.mtls.upstreamAuthority.awsPCA.supplementalBundlePath }} + supplemental_bundle_path = "/run/spire/config/upstreamBundle.crt"{{end}} + } +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-secret-ua.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-secret-ua.conf new file mode 100644 index 000000000..5e8763aff --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/aws-secret-ua.conf @@ -0,0 +1,15 @@ +UpstreamAuthority "awssecret" { + plugin_data { + region = {{ quote .Values.mtls.upstreamAuthority.awsSecret.region }} + cert_file_arn = {{ quote .Values.mtls.upstreamAuthority.awsSecret.certFileArn }} + key_file_arn = {{ quote .Values.mtls.upstreamAuthority.awsSecret.keyFileArn }} + {{- if .Values.mtls.upstreamAuthority.awsSecret.awsAccessKeyID }} + access_key_id = {{ quote .Values.mtls.upstreamAuthority.awsSecret.awsAccessKeyID }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.awsSecret.awsSecretAccessKey }} + secret_access_key = {{ quote .Values.mtls.upstreamAuthority.awsSecret.awsSecretAccessKey }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.awsSecret.awsSecretToken }} + secret_token = {{ quote .Values.mtls.upstreamAuthority.awsSecret.awsSecretToken }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.awsSecret.assumeRoleArn }} + assume_role_arn = {{ quote .Values.mtls.upstreamAuthority.awsSecret.assumeRoleArn }}{{ end }} + } +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/disk-ua.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/disk-ua.conf new file mode 100644 index 000000000..87f402d41 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/disk-ua.conf @@ -0,0 +1,8 @@ +UpstreamAuthority "disk" { + plugin_data { + cert_file_path = "/run/spire/config/upstreamCA.crt" + key_file_path = "/run/spire/secrets/upstreamCA.key" + {{- if .Values.mtls.upstreamAuthority.disk.bundle }} + bundle_file_path = "/run/spire/config/upstreamBundle.crt"{{ end }} + } +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/vault-ua.conf b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/vault-ua.conf new file mode 100644 index 000000000..744eb77fa --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/configs/upstreamAuthority/vault-ua.conf @@ -0,0 +1,28 @@ +UpstreamAuthority "vault" { + plugin_data { + vault_addr = {{ quote .Values.mtls.upstreamAuthority.vault.vaultAddr }} + namespace = {{ quote .Values.mtls.upstreamAuthority.vault.namespace }} + ca_cert_path = "/run/spire/config/upstreamCA.crt" + {{- if .Values.mtls.upstreamAuthority.vault.pkiMountPoint }} + pki_mount_path = {{ quote .Values.mtls.upstreamAuthority.vault.pkiMountPoint }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.vault.insecureSkipVerify }} + insecure_skip_verify = {{ .Values.mtls.upstreamAuthority.vault.insecureSkipVerify }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.vault.certAuth}} + cert_auth = { + client_cert_path = "/run/spire/config/upstreamClient.crt" + client_key_path = "/run/spire/secrets/upstreamClient.key" + {{- if .Values.mtls.upstreamAuthority.vault.certAuth.certAuthRoleName }} + cert_auth_role_name = {{ quote .Values.mtls.upstreamAuthority.vault.certAuth.certAuthRoleName }}{{ end }} + {{- if .Values.mtls.upstreamAuthority.vault.certAuth.certAuthMountPoint }} + cert_auth_mount_point = {{ quote .Values.mtls.upstreamAuthority.vault.certAuth.certAuthMountPoint }}{{ end }} + }{{ end }} + {{- if .Values.mtls.upstreamAuthority.vault.tokenAuth }} + token_auth = {}{{ end }} + {{- if .Values.mtls.upstreamAuthority.vault.approleAuth }} + approle_auth = { + approle_id = {{ quote .Values.mtls.upstreamAuthority.vault.approleAuth.approleID }} + {{- if .Values.mtls.upstreamAuthority.vault.approleAuth.approleAuthMountPoint }} + approle_auth_mount_point = {{ quote .Values.mtls.upstreamAuthority.vault.approleAuth.approleAuthMountPoint }}{{ end }} + }{{ end }} + } +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/circuitbreaker.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/circuitbreaker.yaml new file mode 100644 index 000000000..d5155fbb2 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/circuitbreaker.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: circuitbreakers.specs.smi.nginx.com + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: specs.smi.nginx.com + scope: Namespaced + names: + kind: CircuitBreaker + listKind: CircuitBreakerList + shortNames: + - cb + plural: circuitbreakers + singular: circuitbreaker + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + description: Specifications of this circuit breaker. + type: object + required: + - destination + - errors + - timeoutSeconds + properties: + destination: + description: The destination of this circuit breaker. + type: object + required: + - name + - kind + properties: + kind: + description: Kind of the destination. + type: string + enum: + - Service + name: + description: Name of the destination. + type: string + minLength: 1 + namespace: + description: Namespace of the destination. + type: string + errors: + description: The number of errors allowed within the timeout before + tripping the circuit. + type: integer + minimum: 0 + timeoutSeconds: + description: The timeout window for errors to occur, and the amount + of time to wait before closing the circuit. + type: integer + minimum: 0 + fallback: + description: The fallback Service to send traffic to when the circuit + is tripped. + type: object + properties: + service: + description: The fallback Service to send traffic to when the + circuit is tripped. + type: string + port: + description: The port of the fallback Service. + type: integer + minimum: 0 + maximum: 65535 diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/httproutegroup.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/httproutegroup.yaml new file mode 100644 index 000000000..b1ee68f88 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/httproutegroup.yaml @@ -0,0 +1,68 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: httproutegroups.specs.smi-spec.io + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: specs.smi-spec.io + scope: Namespaced + names: + kind: HTTPRouteGroup + shortNames: + - htr + plural: httproutegroups + singular: httproutegroup + versions: + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - matches + properties: + matches: + description: Match conditions of this route group. + type: array + items: + type: object + required: + - name + properties: + name: + description: Name of the HTTP route. + type: string + pathRegex: + description: URI path regex of the HTTP route. + type: string + methods: + description: The HTTP methods of this HTTP route. + type: array + items: + type: string + description: The HTTP method of this HTTP route. + enum: + - "*" + - GET + - HEAD + - PUT + - POST + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + headers: + description: Header match conditions of this route. + type: array + items: + description: Header match condition of this route. + type: object + additionalProperties: + type: string diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/ratelimit.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/ratelimit.yaml new file mode 100644 index 000000000..95fe8433b --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/ratelimit.yaml @@ -0,0 +1,175 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ratelimits.specs.smi.nginx.com + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: specs.smi.nginx.com + scope: Namespaced + names: + kind: RateLimit + listKind: RateLimitList + shortNames: + - rl + plural: ratelimits + singular: ratelimit + versions: + - name: v1alpha1 + served: true + storage: false + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - name + - destination + - rate + properties: + destination: + description: The destination of this rate limit. + type: object + required: + - name + - kind + properties: + kind: + description: Kind of the destination. + type: string + minLength: 1 + name: + description: Name of the destination. + type: string + minLength: 1 + namespace: + description: Namespace of the destination. + type: string + sources: + description: Sources of this rate limit. + type: array + items: + type: object + required: + - name + - kind + properties: + kind: + description: Kind of this source. + type: string + minLength: 1 + name: + description: Name of this source. + type: string + minLength: 1 + namespace: + description: Namespace of this source. + type: string + name: + description: Name of this rate limit spec. + type: string + minLength: 1 + rate: + description: The allowed rate of traffic. + type: string + pattern: "^[0-9]+r/[s,m]$" + burst: + description: The number of requests to allow beyond the given rate. + type: integer + minimum: 0 + delay: + description: The number of requests after which to delay requests. + x-kubernetes-int-or-string: true + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - name + - destination + - rate + properties: + destination: + description: The destination of this rate limit. + type: object + required: + - name + - kind + properties: + kind: + description: Kind of the destination. + type: string + minLength: 1 + name: + description: Name of the destination. + type: string + minLength: 1 + namespace: + description: Namespace of the destination. + type: string + sources: + description: Sources of this rate limit. + type: array + items: + type: object + required: + - name + - kind + properties: + kind: + description: Kind of this source. + type: string + minLength: 1 + name: + description: Name of this source. + type: string + minLength: 1 + namespace: + description: Namespace of this source. + type: string + name: + description: Name of this rate limit spec. + type: string + minLength: 1 + rate: + description: The allowed rate of traffic. + type: string + pattern: "^[0-9]+r/[s,m]$" + burst: + description: The number of requests to allow beyond the given rate. + type: integer + minimum: 0 + delay: + description: The number of requests after which to delay requests. + x-kubernetes-int-or-string: true + rules: + description: Routing rules of this rate limit. + type: array + items: + type: object + required: + - name + - kind + properties: + kind: + description: Kind of this routing rule. + type: string + enum: + - HTTPRouteGroup + name: + description: Name of this routing rule. + type: string + minLength: 1 + matches: + description: Match conditions of this routing rule. + type: array + items: + type: string diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/tcproute.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/tcproute.yaml new file mode 100644 index 000000000..4f91f25a1 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/tcproute.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tcproutes.specs.smi-spec.io + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: specs.smi-spec.io + scope: Namespaced + names: + kind: TCPRoute + shortNames: + - tr + plural: tcproutes + singular: tcproute + versions: + - name: v1alpha3 + served: true + storage: true + schema: + openAPIV3Schema: + type: object diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/trafficsplit.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/trafficsplit.yaml new file mode 100644 index 000000000..90ca7010a --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/trafficsplit.yaml @@ -0,0 +1,72 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trafficsplits.split.smi-spec.io + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: split.smi-spec.io + scope: Namespaced + names: + kind: TrafficSplit + listKind: TrafficSplitList + shortNames: + - ts + plural: trafficsplits + singular: trafficsplit + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - name: Service + type: string + description: The apex service of this split. + jsonPath: .spec.service + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - service + - backends + properties: + service: + description: The apex service of this split. + type: string + matches: + description: The HTTP route groups that this traffic split should + match. + type: array + items: + type: object + required: + - kind + - name + properties: + kind: + description: Kind of the matching group. + type: string + enum: + - HTTPRouteGroup + name: + description: Name of the matching group. + type: string + backends: + description: The backend services of this split. + type: array + items: + type: object + required: + - service + - weight + properties: + service: + description: Name of the Kubernetes service. + type: string + weight: + description: Traffic weight value of this backend. + type: number diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/traffictarget.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/traffictarget.yaml new file mode 100644 index 000000000..24bae1428 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/crds/traffictarget.yaml @@ -0,0 +1,92 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: traffictargets.access.smi-spec.io + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: access.smi-spec.io + scope: Namespaced + names: + kind: TrafficTarget + shortNames: + - tt + plural: traffictargets + singular: traffictarget + versions: + - name: v1alpha2 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + required: + - destination + properties: + destination: + description: The destination of this traffic target. + type: object + required: + - name + - kind + properties: + kind: + description: Kind of the destination. + type: string + name: + description: Name of the destination. + type: string + namespace: + description: Namespace of the destination. + type: string + port: + description: Port number of the destination. + type: number + rules: + description: Specifications of this traffic target. + type: array + items: + type: object + required: + - name + - kind + properties: + kind: + description: Kind of this spec. + type: string + enum: + - HTTPRouteGroup + - TCPRoute + name: + description: Name of this spec. + type: string + matches: + description: Match conditions of this spec. + type: array + items: + type: string + sources: + description: Sources of this traffic target. + type: array + items: + type: object + required: + - name + - kind + properties: + kind: + description: Kind of this source. + type: string + name: + description: Name of this source. + type: string + namespace: + description: Namespace of this source. + type: string + port: + description: Port number of the source. + type: number diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/questions.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/questions.yaml new file mode 100644 index 000000000..933e22c5f --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/questions.yaml @@ -0,0 +1,197 @@ +questions: +- variable: useDefaultImages + default: true + description: "Use default image settings." + label: Use default images + type: boolean + show_subquestion_if: false + group: "Image Registry" + subquestions: + - variable: registry.server + default: "docker-registry.nginx.com/nsm" + description: "Hostname:port (if needed) for registry and path to images." + label: Image registry server + type: string + - variable: registry.imageTag + default: "1.2.1" + description: "Tag used for pulling images from registry." + label: Image tag + type: string + - variable: registry.key + default: "" + description: "Contents of your Google Cloud JSON key file. Cannot be used with username or password." + label: Image registry key + type: string + - variable: registry.username + default: "" + description: "Username for accessing private registry." + label: Image registry username + type: string + - variable: registry.password + default: "" + description: "Password for accessing private registry." + label: Image registry password + type: string + - variable: registry.disablePublicImages + default: false + description: "Do not pull third party images from public repositories. If true, registry.server is used for all images." + label: Disable public images + type: boolean + - variable: registry.imagePullPolicy + default: "IfNotPresent" + description: "Image pull policy." + label: Image pull policy + type: string +- variable: useMtlsDefaults + default: true + description: "Use default mTLS settings." + label: Use default mTLS settings + type: boolean + show_subquestion_if: false + group: "Mutual TLS" + subquestions: + - variable: mtls.mode + default: "permissive" + description: "mTLS mode for pod-to-pod communication." + label: mTLS mode + type: enum + options: + - "off" + - "permissive" + - "strict" + - variable: mtls.caTTL + default: "720h" + description: "The CA/signing key TTL in hours(h) or minutes(m)." + label: mTLS caTTL + type: string + - variable: mtls.svidTTL + default: "1h" + description: "The TTL of certificates issued to workloads in hours(h) or minutes(m)." + label: mTLS svidTTL + type: string + - variable: mtls.trustDomain + default: "example.org" + description: "The trust domain of the NGINX Service Mesh." + label: mTLS trust domain + type: string + - variable: mtls.persistentStorage + default: "on" + description: "Use persistent storage; 'on' assumes that a StorageClass exists." + label: mTLS persistent storage + type: enum + options: + - "on" + - "off" + - variable: mtls.spireServerKeyManager + default: "disk" + description: "Storage logic for Spire Server's private keys." + label: mTLS spire server key manager + type: enum + options: + - "disk" + - "memory" +- variable: useTracingDefaults + default: true + description: "Use default tracing settings." + label: Use default tracing settings + type: boolean + show_subquestion_if: false + group: "Tracing" + subquestions: + - variable: tracing.disable + default: false + description: "Disable tracing for all services." + label: Disable tracing + type: boolean + - variable: tracing.address + default: "" + description: "The address of a tracing server deployed in your Kubernetes cluster." + label: Tracing address + type: string + - variable: tracing.backend + default: "jaeger" + description: "The tracing backend that you want to use." + label: Tracing backend + type: enum + options: + - "jaeger" + - "zipkin" + - "datadog" + - variable: tracing.sampleRate + default: 0.01 + description: "The sample rate to use for tracing. Float between 0 and 1." + label: Tracing sample rate + type: float +- variable: autoInjection.disable + default: false + description: "Disable automatic sidecar injection upon resource creation." + label: Disable auto injection + type: boolean + group: "General Settings" +- variable: accessControlMode + default: "allow" + description: "Default access control mode for service-to-service communication." + label: Access control mode + type: enum + options: + - "allow" + - "deny" + group: "General Settings" +- variable: deployGrafana + default: true + description: "Deploy Grafana as a part of NGINX Service Mesh." + label: Deploy Grafana + type: boolean + group: "General Settings" +- variable: nginxErrorLogLevel + default: "warn" + description: "NGINX error log level." + label: NGINX error log level. + type: enum + options: + - "debug" + - "info" + - "notice" + - "warn" + - "error" + - "crit" + - "alert" + - "emerg" + group: "General Settings" +- variable: nginxLogFormat + default: "default" + description: "NGINX log format." + label: NGINX log format. + type: enum + options: + - "default" + - "json" + group: "General Settings" +- variable: nginxLBMethod + default: "least_time" + description: "NGINX load balancing method." + label: NGINX load balancing method. + type: enum + options: + - "least_conn" + - "least_time" + - "least_time last_byte" + - "least_time last_byte inflight" + - "random" + - "random two" + - "random two least_conn" + - "random two least_time" + - "random two least_time=last_byte" + - "round_robin" + group: "General Settings" +- variable: prometheusAddress + description: "The address of a Prometheus server deployed in your Kubernetes cluster." + label: Prometheus address. + type: string + group: "General Settings" +- variable: rancher + default: true + description: "Enables Rancher for NGINX Service Mesh (do not disable)." + label: Rancher + type: boolean + group: "General Settings" diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/NOTES.txt b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/NOTES.txt new file mode 100644 index 000000000..ae929df6d --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/NOTES.txt @@ -0,0 +1 @@ +NGINX Service Mesh has been installed. Ensure all NGINX Service Mesh Pods are in the Ready state before deploying your apps. diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/_helpers.tpl b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/_helpers.tpl new file mode 100644 index 000000000..e0c43f378 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/_helpers.tpl @@ -0,0 +1,165 @@ +{{- define "jaeger.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}jaegertracing{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "zipkin.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}openzipkin{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "tracing.address" -}} +{{- if ne .Values.tracing.address "" -}} +{{ .Values.tracing.address }} +{{- else if eq .Values.tracing.backend "jaeger" -}} +jaeger.{{.Release.Namespace}}.svc.cluster.local:6831 +{{- else if eq .Values.tracing.backend "zipkin" -}} +zipkin.{{.Release.Namespace}}.svc.cluster.local:9411 +{{- end }} +{{- end }} + +{{- define "prometheus.address" -}} +{{- if eq .Values.prometheusAddress "" -}} +prometheus.{{.Release.Namespace}}.svc.cluster.local:9090 +{{- else -}} +{{ .Values.prometheusAddress }} +{{- end }} +{{- end }} + +{{- define "prometheus.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}prom{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "grafana.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}grafana{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "nats.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}{{ else }}{{ .Values.registry.server }}/{{ end }} +{{- end }} + +{{- define "spire.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}gcr.io/spiffe-io{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "hook.image-server" -}} +{{- if not .Values.registry.disablePublicImages }}bitnami{{ else }}{{ .Values.registry.server }}{{ end }} +{{- end }} + +{{- define "registry-key-name" -}} +nginx-mesh-registry-key +{{- end }} + +{{- define "docker-config-json" -}} +{{- if (and (.Values.registry.username) (.Values.registry.password)) }} +{ + "auths": { + {{ quote .Values.registry.server }}: { + "username": {{ quote .Values.registry.username }}, + "password": {{ quote .Values.registry.password }}, + "auth": {{ printf "%s:%s" .Values.registry.username .Values.registry.password | b64enc | quote }} + } + } +} +{{- else if (.Values.registry.key) }} +{ + "auths": { + {{ quote .Values.registry.server }}: { + "username": "_json_key", + "password": {{ quote .Values.registry.key }} + } + } +} +{{- end }} +{{- end }} + +{{/* +Define the name of the key where the Upstream Authority secret data is stored. +*/}} +{{- define "ua-secret-name" -}} +{{- if .Values.mtls.upstreamAuthority.awsPCA -}} +credentials +{{- else if .Values.mtls.upstreamAuthority.disk -}} +upstreamCA.key +{{- else if .Values.mtls.upstreamAuthority.vault }}{{ if .Values.mtls.upstreamAuthority.vault.certAuth -}} +upstreamClient.key{{ end }} +{{- end }} +{{- end }} + +{{/* +Define the name of the mount path where the Upstream Authority secret data is stored. +*/}} +{{- define "ua-secret-mountpath" -}} +{{- if .Values.mtls.upstreamAuthority.awsPCA -}} +/root/.aws +{{- else if .Values.mtls.upstreamAuthority.disk -}} +/run/spire/secrets +{{- else if .Values.mtls.upstreamAuthority.vault }}{{ if .Values.mtls.upstreamAuthority.vault.certAuth -}} +/run/spire/secrets{{ end }} +{{- end }} +{{- end }} + +{{/* +Define the upstream certificate to be used for the Upstream Authority. +*/}} +{{- define "ua-upstream-cert" -}} +{{- if .Values.mtls.upstreamAuthority.disk -}} +upstreamCA.crt: {{ quote .Values.mtls.upstreamAuthority.disk.cert }} +{{- else if .Values.mtls.upstreamAuthority.vault -}} +upstreamCA.crt: {{ quote .Values.mtls.upstreamAuthority.vault.caCert }} +{{- end }} +{{- end }} + +{{/* +Define the upstream bundle to be used for the Upstream Authority. +*/}} +{{- define "ua-upstream-bundle" -}} +{{- if .Values.mtls.upstreamAuthority.disk }}{{ if .Values.mtls.upstreamAuthority.disk.bundle -}} +upstreamBundle.crt: {{ quote .Values.mtls.upstreamAuthority.disk.bundle }}{{ end }} +{{- else if .Values.mtls.upstreamAuthority.awsPCA }}{{ if .Values.mtls.upstreamAuthority.awsPCA.supplementalBundle -}} +upstreamBundle.crt: {{ quote .Values.mtls.upstreamAuthority.awsPCA.supplementalBundle }}{{ end }} +{{- end }} +{{- end }} + +{{/* +Define the Upstream Authority key to be stored in the Secret. +*/}} +{{- define "ua-upstream-key" -}} +{{- if .Values.mtls.upstreamAuthority.awsPCA -}} +{{ tpl (.Files.Get "configs/upstreamAuthority/aws-credentials.conf") . | b64enc }} +{{- else if .Values.mtls.upstreamAuthority.disk -}} +{{ .Values.mtls.upstreamAuthority.disk.key | b64enc }} +{{- else if .Values.mtls.upstreamAuthority.vault }}{{ if .Values.mtls.upstreamAuthority.vault.certAuth -}} +{{ .Values.mtls.upstreamAuthority.vault.certAuth.clientKey | b64enc }}{{ end }} +{{- end }} +{{- end }} + +{{/* +Define variables associated with the Vault Upstream Authority. +*/}} + +{{- define "ua-vault-env-name" -}} +{{- if .Values.mtls.upstreamAuthority.vault -}} +{{- if .Values.mtls.upstreamAuthority.vault.tokenAuth -}} +VAULT_TOKEN +{{- else if .Values.mtls.upstreamAuthority.vault.approleAuth -}} +VAULT_APPROLE_SECRET_ID +{{- end }} +{{- end }} +{{- end }} + +{{- define "ua-vault-env-value" -}} +{{- if .Values.mtls.upstreamAuthority.vault -}} +{{- if .Values.mtls.upstreamAuthority.vault.tokenAuth -}} +{{ b64enc .Values.mtls.upstreamAuthority.vault.tokenAuth.token }} +{{- else if .Values.mtls.upstreamAuthority.vault.approleAuth -}} +{{ b64enc .Values.mtls.upstreamAuthority.vault.approleAuth.approleSecretID }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "ua-upstream-client-cert" -}} +{{- if .Values.mtls.upstreamAuthority.vault -}} +{{- if .Values.mtls.upstreamAuthority.vault.certAuth -}} +upstreamClient.crt: {{ quote .Values.mtls.upstreamAuthority.vault.certAuth.clientCert }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/grafana.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/grafana.yaml new file mode 100644 index 000000000..f7d3a0996 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/grafana.yaml @@ -0,0 +1,137 @@ +{{- if .Values.deployGrafana }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: grafana + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: grafana.metrics.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - services + - endpoints + - pods + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: grafana.metrics.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: grafana.metrics.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: grafana + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-config + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + dashboards.yaml: {{ .Files.Get "configs/grafana-dashboard-conf.yaml" | quote }} + datasources.yaml: {{ tpl (.Files.Get "configs/grafana-datasources-conf.yaml") . | quote }} + grafana.ini: {{ .Files.Get "configs/grafana.ini" | quote }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-dashboards + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + top.json: {{ .Files.Get "configs/grafana-top-dashboard.json" | quote }} +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana + labels: + app.kubernetes.io/name: grafana + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + app.kubernetes.io/name: grafana + app.kubernetes.io/part-of: nginx-service-mesh + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + labels: + app.kubernetes.io/name: grafana + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: grafana + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: grafana + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: grafana + containers: + - name: grafana + image: {{ include "grafana.image-server" . }}/grafana:8.1.7 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + ports: + - containerPort: 3000 + volumeMounts: + - name: grafana-config-volume + mountPath: "/etc/grafana" + - name: grafana-dashboard-volume + mountPath: "/var/lib/grafana/dashboards" + - name: grafana-dashboard-home + mountPath: "/usr/share/grafana/public/dashboards" + volumes: + - name: grafana-config-volume + configMap: + name: grafana-config + items: + - key: dashboards.yaml + path: provisioning/dashboards/dashboards.yaml + - key: datasources.yaml + path: provisioning/datasources/datasources.yaml + - key: grafana.ini + path: grafana.ini + - name: grafana-dashboard-volume + configMap: + name: grafana-dashboards + items: + - key: top.json + path: top.json + - name: grafana-dashboard-home + configMap: + name: grafana-dashboards + items: + - key: top.json + path: home.json +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/jaeger.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/jaeger.yaml new file mode 100644 index 000000000..36784672a --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/jaeger.yaml @@ -0,0 +1,56 @@ +{{- if (and (not .Values.tracing.disable) (eq .Values.tracing.backend "jaeger") (eq .Values.tracing.address "")) }} +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger + labels: + app.kubernetes.io/name: jaeger + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + app.kubernetes.io/name: jaeger + app.kubernetes.io/part-of: nginx-service-mesh + type: ClusterIP + ports: + - name: frontend + port: 16686 + targetPort: 16686 + - name: collector + port: 6831 + targetPort: 6831 + protocol: UDP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jaeger + labels: + app.kubernetes.io/name: jaeger + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: jaeger + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: jaeger + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '16686' + spec: + imagePullSecrets: + - name: {{ include "registry-key-name" . }} + containers: + - name: jaeger + image: {{ include "jaeger.image-server" . }}/all-in-one:1.26.0 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + ports: + - containerPort: 16686 + - containerPort: 6831 + protocol: UDP +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nats.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nats.yaml new file mode 100644 index 000000000..0e269620c --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nats.yaml @@ -0,0 +1,146 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nats + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: nats-config + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + nats.conf: {{ .Files.Get "configs/nats.conf" | quote }} +--- +apiVersion: v1 +kind: Service +metadata: + name: nats-server + labels: + app.kubernetes.io/name: nats-server + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + app.kubernetes.io/name: nats-server + app.kubernetes.io/part-of: nginx-service-mesh + clusterIP: None + ports: + - name: client + port: 4222 + - name: monitor + port: 8222 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nats-server + labels: + app.kubernetes.io/name: nats-server + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + matchLabels: + app.kubernetes.io/name: nats-server + app.kubernetes.io/part-of: nginx-service-mesh + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: nats-server + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: nats + volumes: + - name: config-volume + configMap: + name: nats-config + - name: pid + emptyDir: {} + - name: tls + emptyDir: {} + - hostPath: + path: "/run/spire/sockets" + type: DirectoryOrCreate + name: spire-agent-socket + shareProcessNamespace: true + terminationGracePeriodSeconds: 60 + imagePullSecrets: + - name: {{ include "registry-key-name" . }} + initContainers: + - name: nginx-mesh-cert-reloader-init + image: {{ .Values.registry.server }}/nginx-mesh-cert-reloader:{{ .Values.registry.imageTag }} + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + volumeMounts: + - name: tls + mountPath: "/etc/ssl" + - name: spire-agent-socket + mountPath: "/run/spire/sockets" + containers: + - name: nginx-mesh-cert-reloader + image: {{ .Values.registry.server }}/nginx-mesh-cert-reloader:{{ .Values.registry.imageTag }} + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - "-pid" + - "/var/run/nats/nats.pid" + - "-is-daemon" + volumeMounts: + - name: pid + mountPath: "/var/run/nats" + - name: tls + mountPath: "/etc/ssl" + - name: spire-agent-socket + mountPath: "/run/spire/sockets" + - name: nats-server + image: {{ include "nats.image-server" . }}nats:2.4.0-alpine3.14 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + ports: + - containerPort: 4222 + name: client + - containerPort: 8222 + name: monitor + command: + - nats-server + - "--config" + - "/etc/nats-config/nats.conf" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CLUSTER_ADVERTISE + value: "$(POD_NAME).nats-server.$(POD_NAMESPACE).svc" + volumeMounts: + - name: config-volume + mountPath: "/etc/nats-config" + - name: pid + mountPath: "/var/run/nats" + - name: tls + mountPath: "/etc/ssl" + livenessProbe: + httpGet: + path: "/" + port: 8222 + initialDelaySeconds: 10 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: "/" + port: 8222 + initialDelaySeconds: 10 + timeoutSeconds: 5 + lifecycle: + preStop: + exec: + command: + - "/bin/sh" + - "-c" + - "/nats-server -sl=ldm=/var/run/nats/nats.pid && /bin/sleep 60" diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-api.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-api.yaml new file mode 100644 index 000000000..99cce3371 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-api.yaml @@ -0,0 +1,323 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nginx-mesh-api + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: nginx-mesh-api.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - '' + resources: + - services + - endpoints + verbs: + - "*" +- apiGroups: + - '' + resources: + - secrets + - pods + verbs: + - create + - get + - list + - watch +- apiGroups: + - '' + resources: + - configmaps + verbs: + - get + - list + - watch + - update +- apiGroups: + - '' + resources: + - events + verbs: + - create + - patch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - list + - watch +- apiGroups: + - split.smi-spec.io + resources: + - trafficsplits + verbs: + - "*" +- apiGroups: + - access.smi-spec.io + resources: + - traffictargets + verbs: + - "*" +- apiGroups: + - specs.smi-spec.io + - specs.smi.nginx.com + resources: + - httproutegroups + - tcproutes + - ratelimits + - circuitbreakers + verbs: + - "*" +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + resourceNames: + - sidecar-injector-webhook-cfg.internal.builtin.nsm.nginx + verbs: + - get + - update +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + resourceNames: + - validating-webhook-cfg.internal.builtin.nsm.nginx + verbs: + - get + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: nginx-mesh-api.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nginx-mesh-api.internal.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: nginx-mesh-api + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: mesh-config + labels: + app.kubernetes.io/part-of: nginx-service-mesh +binaryData: + mesh-config.json: {{ tpl (.Files.Get "configs/mesh-config.conf") . | b64enc | quote }} +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-mesh-api + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + type: ClusterIP + ports: + - name: https + port: 443 + targetPort: 8443 + protocol: TCP + selector: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-mesh-webhook + labels: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh +spec: + type: ClusterIP + ports: + - name: admission + port: 443 + targetPort: 9443 + protocol: TCP + selector: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: sidecar-injector-webhook-cfg.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + spiffe.io/webhook: "true" +webhooks: +- name: nginx-mesh-api.sidecar.injector + namespaceSelector: + matchExpressions: + - key: injector.nsm.nginx.com/auto-inject + operator: NotIn + values: + - 'false' + clientConfig: + service: + name: nginx-mesh-webhook + namespace: {{ .Release.Namespace }} + path: "/inject" + sideEffects: None + admissionReviewVersions: + - v1 + - v1beta1 + rules: + - apiGroups: + - '' + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-cfg.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + spiffe.io/webhook: "true" +webhooks: +- name: nginx-mesh-api.policy.validator + clientConfig: + service: + name: nginx-mesh-webhook + namespace: {{ .Release.Namespace }} + path: "/validate" + sideEffects: None + admissionReviewVersions: + - v1 + - v1beta1 + rules: + - apiGroups: + - split.smi-spec.io + apiVersions: + - "*" + operations: + - CREATE + - UPDATE + - DELETE + resources: + - trafficsplits + - apiGroups: + - specs.smi-spec.io + apiVersions: + - "*" + operations: + - CREATE + - UPDATE + resources: + - httproutegroups + - apiGroups: + - specs.smi.nginx.com + apiVersions: + - "*" + operations: + - CREATE + - UPDATE + - DELETE + resources: + - circuitbreakers + - ratelimits +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-mesh-api + labels: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: nginx-mesh-api + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: nginx-mesh-api + containers: + - name: nginx-mesh-api + image: {{ .Values.registry.server }}/nginx-mesh-api:{{ .Values.registry.imageTag }} + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - "-meshconfig=/etc/config/mesh-config.json" + - "-logtostderr" + - "-v=3" + env: + - name: PULL_POLICY + value: {{ .Values.registry.imagePullPolicy }} + - name: MY_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + readinessProbe: + httpGet: + path: "/healthz" + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 30 + livenessProbe: + httpGet: + path: "/healthz" + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 30 + volumeMounts: + - name: config-volume + mountPath: "/etc/config" + - name: spire-agent-socket + mountPath: "/run/spire/sockets" + volumes: + - name: config-volume + configMap: + name: mesh-config + items: + - key: mesh-config.json + path: mesh-config.json + - name: spire-agent-socket + hostPath: + path: "/run/spire/sockets" + type: DirectoryOrCreate diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-metrics.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-metrics.yaml new file mode 100644 index 000000000..b68f17b57 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/nginx-mesh-metrics.yaml @@ -0,0 +1,157 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nginx-mesh-metrics + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: nginx-mesh-metrics.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - pods + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: nginx-mesh-metrics.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nginx-mesh-metrics.internal.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: nginx-mesh-metrics + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: nginx-mesh-metrics-svc.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: nginx-mesh-metrics + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: nginx-mesh-metrics-svc.internal.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: nginx-mesh-metrics + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-mesh-metrics-svc + labels: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh +spec: + type: ClusterIP + ports: + - name: http + port: 443 + targetPort: metrics + protocol: TCP + selector: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh +--- +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1alpha1.metrics.smi-spec.io + labels: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh + spiffe.io/apiservice: "true" +spec: + service: + name: nginx-mesh-metrics-svc + namespace: {{ .Release.Namespace }} + group: metrics.smi-spec.io + version: v1alpha1 + groupPriorityMinimum: 100 + versionPriority: 100 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-mesh-metrics + labels: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: nginx-mesh-metrics + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: nginx-mesh-metrics + containers: + - name: nginx-mesh-metrics + image: {{ .Values.registry.server }}/nginx-mesh-metrics:{{ .Values.registry.imageTag }} + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - "--prometheus-address={{ include "prometheus.address" . }}" + readinessProbe: + httpGet: + scheme: HTTPS + path: "/liveness" + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 30 + livenessProbe: + httpGet: + scheme: HTTPS + path: "/liveness" + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 30 + ports: + - name: metrics + containerPort: 8080 + volumeMounts: + - name: spire-agent-socket + mountPath: "/run/spire/sockets" + volumes: + - name: spire-agent-socket + hostPath: + path: "/run/spire/sockets" + type: DirectoryOrCreate diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/post-delete-hook.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/post-delete-hook.yaml new file mode 100644 index 000000000..61c2c7524 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/post-delete-hook.yaml @@ -0,0 +1,144 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: post-delete + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: post-delete.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +rules: +- apiGroups: + - '' + resources: + - namespaces + verbs: + - get + - list + - patch +- apiGroups: + - spiffeid.spiffe.io + resources: + - spiffeids + verbs: + - get + - list + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: post-delete.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: post-delete.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: post-delete + namespace: {{ .Release.Namespace }} +{{- if (include "docker-config-json" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "registry-key-name" . }} + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +data: + .dockerconfigjson: {{ include "docker-config-json" . | b64enc }} +type: kubernetes.io/dockerconfigjson +{{- end }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: remove-spiffeids + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "0" +spec: + template: + metadata: + name: remove-spiffeids + spec: + restartPolicy: Never + serviceAccountName: post-delete + containers: + - name: remove-spiffeids + image: {{ include "hook.image-server" . }}/kubectl + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + command: + - /bin/sh + - -c + - | + for ns in $(kubectl get ns | awk '{print $1}' | tail -n +2); do + if [ $(kubectl get spiffeids -n $ns 2>/dev/null | wc -l) -ne 0 ]; then + kubectl patch spiffeid $(kubectl get spiffeids -n $ns | awk '{print $1}' | tail -n +2) --type='merge' -p '{"metadata":{"finalizers":null}}' -n $ns + fi + done +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: remove-namespace-label + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "0" +spec: + template: + metadata: + name: remove-namespace-label + spec: + restartPolicy: Never + serviceAccountName: post-delete + containers: + - name: remove-namespace-label + image: {{ include "hook.image-server" . }}/kubectl + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + command: + - /bin/sh + - -c + - | + kubectl label namespace kube-system injector.nsm.nginx.com/auto-inject- + kubectl label namespace {{ .Release.Namespace }} injector.nsm.nginx.com/auto-inject- app.kubernetes.io/part-of- + {{- if .Values.rancher }} + kubectl label namespace ingress-nginx cert-manager injector.nsm.nginx.com/auto-inject- + for ns in $(kubectl get ns | awk '{print $1}' | tail -n +2); do + case "$ns" in + cattle-*) kubectl label namespace $ns injector.nsm.nginx.com/auto-inject- ;; + esac + done + {{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-delete-hook.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-delete-hook.yaml new file mode 100644 index 000000000..f53286921 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-delete-hook.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: turn-proxies-transparent + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "0" +spec: + template: + metadata: + name: turn-proxies-transparent + spec: + restartPolicy: Never + containers: + - name: turn-proxies-transparent + image: {{ include "hook.image-server" . }}/kubectl + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + command: + - /bin/sh + - -c + - | + curl -m 30 -k https://nginx-mesh-api.{{ .Release.Namespace }}.svc:443/clear -X POST + exit 0 + imagePullSecrets: + - name: {{ include "registry-key-name" . }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-install-hook.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-install-hook.yaml new file mode 100644 index 000000000..11f102ca7 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/pre-install-hook.yaml @@ -0,0 +1,104 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pre-install + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pre-install.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +rules: +- apiGroups: + - '' + resources: + - namespaces + verbs: + - get + - list + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pre-install.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pre-install.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: pre-install + namespace: {{ .Release.Namespace }} +{{- if (include "docker-config-json" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "registry-key-name" . }} + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "-5" +data: + .dockerconfigjson: {{ include "docker-config-json" . | b64enc }} +type: kubernetes.io/dockerconfigjson +{{- end }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: label-namespace + labels: + app.kubernetes.io/part-of: nginx-service-mesh + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + "helm.sh/hook-weight": "0" +spec: + template: + metadata: + name: label-namespace + spec: + restartPolicy: Never + serviceAccountName: pre-install + containers: + - name: label-namespace + image: {{ include "hook.image-server" . }}/kubectl + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + command: + - /bin/sh + - -c + - | + kubectl label namespace kube-system injector.nsm.nginx.com/auto-inject=false + kubectl label namespace {{ .Release.Namespace }} injector.nsm.nginx.com/auto-inject=false app.kubernetes.io/part-of=nginx-service-mesh + {{- if .Values.rancher }} + kubectl label namespace ingress-nginx cert-manager injector.nsm.nginx.com/auto-inject=false + for ns in $(kubectl get ns | awk '{print $1}' | tail -n +2); do + case "$ns" in + cattle-*) kubectl label namespace $ns injector.nsm.nginx.com/auto-inject=false ;; + esac + done + {{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/prometheus.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/prometheus.yaml new file mode 100644 index 000000000..25da2d6d6 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/prometheus.yaml @@ -0,0 +1,114 @@ +{{- if eq .Values.prometheusAddress "" }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus.metrics.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - services + - endpoints + - pods + verbs: + - get + - list + - watch +- nonResourceURLs: + - "/metrics" + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus.metrics.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus.metrics.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-configuration + labels: + app.kubernetes.io/part-of: nginx-service-mesh +binaryData: + prometheus.yaml: {{ .Files.Get "configs/prometheus-config.yaml" | b64enc }} +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + labels: + app.kubernetes.io/name: prometheus + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + app.kubernetes.io/name: prometheus + app.kubernetes.io/part-of: nginx-service-mesh + type: ClusterIP + ports: + - port: 9090 + targetPort: 9090 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + labels: + app.kubernetes.io/name: prometheus + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: prometheus + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: prometheus + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: prometheus + containers: + - name: prometheus + image: {{ include "prometheus.image-server" . }}/prometheus:v2.20.1 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - "--config.file=/etc/prometheus/prometheus.yaml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: "/etc/prometheus" + - name: prometheus-storage-volume + mountPath: "/prometheus/" + volumes: + - name: prometheus-config-volume + configMap: + name: prometheus-configuration + - name: prometheus-storage-volume + emptyDir: {} +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/registry-key.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/registry-key.yaml new file mode 100644 index 000000000..beee39c5e --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/registry-key.yaml @@ -0,0 +1,12 @@ +{{- if (include "docker-config-json" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "registry-key-name" . }} + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + .dockerconfigjson: {{ include "docker-config-json" . | b64enc }} +type: kubernetes.io/dockerconfigjson +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-agent.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-agent.yaml new file mode 100644 index 000000000..f553fae12 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-agent.yaml @@ -0,0 +1,141 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-agent.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - pods + - nodes + - nodes/proxy + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-agent.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: spire-agent.security.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: spire-agent + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + agent.conf: {{ tpl (.Files.Get "configs/spire-agent.conf") . | quote }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + labels: + app.kubernetes.io/name: spire-agent + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + matchLabels: + app.kubernetes.io/name: spire-agent + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: spire-agent + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: spire-agent + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + initContainers: + - name: init + image: {{ include "spire.image-server" . }}/wait-for-it + args: + - "-t" + - '30' + - spire-server:8081 + containers: + - name: spire-agent + image: {{ include "spire.image-server" . }}/spire-agent:1.0.2 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - "-config" + - "/run/spire/config/agent.conf" + env: + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumeMounts: + - name: spire-config + mountPath: "/run/spire/config" + readOnly: true + - name: spire-bundle + mountPath: "/run/spire/bundle" + - name: spire-agent-socket + mountPath: "/run/spire/sockets" + readOnly: false + - name: spire-token + mountPath: "/var/run/secrets/tokens" + livenessProbe: + exec: + command: + - "/opt/spire/bin/spire-agent" + - healthcheck + - "-shallow" + - "-socketPath" + - "/run/spire/sockets/agent.sock" + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + exec: + command: + - "/opt/spire/bin/spire-agent" + - healthcheck + - "-socketPath" + - "/run/spire/sockets/agent.sock" + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: spire-bundle + - name: spire-agent-socket + hostPath: + path: "/run/spire/sockets" + type: DirectoryOrCreate + - name: spire-token + projected: + sources: + - serviceAccountToken: + audience: spire-server + expirationSeconds: 7200 + path: spire-agent diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-server.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-server.yaml new file mode 100644 index 000000000..6048d49b0 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/spire-server.yaml @@ -0,0 +1,466 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server + labels: + app.kubernetes.io/part-of: nginx-service-mesh +imagePullSecrets: +- name: {{ include "registry-key-name" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-server.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - pods + - nodes + verbs: + - get +- apiGroups: + - '' + resources: + - configmaps + resourceNames: + - spire-bundle + verbs: + - get + - patch +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + verbs: + - get + - list + - patch + - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - get + - list + - patch + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-server.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: spire-server.security.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: spire-server + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: k8s-workload-registrar.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +rules: +- apiGroups: + - '' + resources: + - endpoints + - pods + - nodes + verbs: + - get + - list + - watch +- apiGroups: + - spiffeid.spiffe.io + resources: + - spiffeids + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - spiffeid.spiffe.io + resources: + - spiffeids/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: k8s-workload-registrar.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: k8s-workload-registrar.security.builtin.nsm.nginx +subjects: +- kind: ServiceAccount + name: spire-server + namespace: {{ .Release.Namespace }} +{{- if (or (include "ua-secret-name" .) (include "ua-vault-env-name" .)) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: spire-server + labels: + app.kubernetes.io/part-of: nginx-service-mesh +type: Opaque +data: + {{- if (include "ua-secret-name" .) }} + {{ include "ua-secret-name" . }}: {{ include "ua-upstream-key" . }}{{ end }} + {{- if (include "ua-vault-env-name" .) }} + {{ include "ua-vault-env-name" . }}: {{ include "ua-vault-env-value" . }}{{ end }} +{{- end }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-bundle + labels: + app.kubernetes.io/part-of: nginx-service-mesh +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + server.conf: {{ tpl (.Files.Get "configs/spire-server.conf") . | quote }} + {{ if (include "ua-upstream-cert" .) -}} + {{ include "ua-upstream-cert" . }}{{ end }} + {{ if (include "ua-upstream-client-cert" .) -}} + {{ include "ua-upstream-client-cert" . }}{{ end }} + {{ if (include "ua-upstream-bundle" .) -}} + {{ include "ua-upstream-bundle" . }}{{ end }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: k8s-workload-registrar + labels: + app.kubernetes.io/part-of: nginx-service-mesh +data: + k8s-workload-registrar.conf: {{ tpl (.Files.Get "configs/k8s-workload-registrar.conf") . | quote }} +--- +{{- $caKey := genPrivateKey "ecdsa"}} +{{- $caCrt := genCAWithKey "K8S WORKLOAD REGISTRAR CA" 9999 $caKey }} +{{- $serverKey := genPrivateKey "ecdsa" }} +{{- $serverCrt := genSignedCertWithKey "K8S WORKLOAD REGISTRAR SERVER" nil (list (printf "k8s-workload-registrar.%s.svc" .Release.Namespace )) 9999 $caCrt $serverKey }} +apiVersion: v1 +kind: Secret +metadata: + name: k8s-workload-registrar-secret + labels: + app.kubernetes.io/part-of: nginx-service-mesh +type: Opaque +data: + tls.crt: {{ b64enc $serverCrt.Cert | quote }} + tls.key: {{ b64enc $serverKey | quote }} +--- +apiVersion: v1 +kind: Service +metadata: + name: spire-server + labels: + app.kubernetes.io/name: spire-server + app.kubernetes.io/part-of: nginx-service-mesh +spec: + type: ClusterIP + ports: + - name: grpc + protocol: TCP + port: 8081 + targetPort: 8081 + selector: + app.kubernetes.io/name: spire-server + app.kubernetes.io/part-of: nginx-service-mesh +--- +apiVersion: v1 +kind: Service +metadata: + name: k8s-workload-registrar + labels: + app.kubernetes.io/name: k8s-workload-registrar + app.kubernetes.io/part-of: nginx-service-mesh +spec: + ports: + - name: webhook + protocol: TCP + port: 443 + targetPort: 9443 + selector: + app.kubernetes.io/name: spire-server +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: k8s-workload-registrar.security.builtin.nsm.nginx + labels: + app.kubernetes.io/part-of: nginx-service-mesh +webhooks: +- name: k8s-workload-registrar.{{ .Release.Namespace }}.svc + clientConfig: + caBundle: {{ b64enc $caCrt.Cert | quote }} + service: + name: k8s-workload-registrar + namespace: {{ .Release.Namespace }} + path: "/validate-spiffeid-spiffe-io-v1beta1-spiffeid" + rules: + - apiGroups: + - spiffeid.spiffe.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - spiffeids + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: spiffeids.spiffeid.spiffe.io + labels: + app.kubernetes.io/part-of: nginx-service-mesh +spec: + group: spiffeid.spiffe.io + scope: Namespaced + names: + kind: SpiffeID + listKind: SpiffeIDList + plural: spiffeids + singular: spiffeid + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + properties: + dnsNames: + type: array + items: + type: string + parentId: + type: string + selector: + type: object + properties: + arbitrary: + items: + type: string + type: array + containerImage: + type: string + containerName: + type: string + namespace: + type: string + nodeName: + type: string + podLabel: + additionalProperties: + type: string + type: object + podName: + type: string + podUid: + type: string + serviceAccount: + type: string + cluster: + type: string + agent_node_uid: + type: string + spiffeId: + type: string + required: + - parentId + - selector + - spiffeId + status: + type: object + properties: + entryId: + type: string +--- +apiVersion: apps/v1 +{{- if eq .Values.mtls.persistentStorage "on" }} +kind: StatefulSet +{{- else }} +kind: Deployment +{{- end }} +metadata: + name: spire-server + labels: + app.kubernetes.io/name: spire-server + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: spire-server + app.kubernetes.io/part-of: nginx-service-mesh + {{- if eq .Values.mtls.persistentStorage "on" }} + serviceName: spire-server + {{- end }} + template: + metadata: + labels: + app.kubernetes.io/name: spire-server + app.kubernetes.io/part-of: nginx-service-mesh + spec: + serviceAccountName: spire-server + shareProcessNamespace: true + containers: + - name: spire-server + image: {{ include "spire.image-server" . }}/spire-server:1.0.2 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - '-config' + - /run/spire/config/server.conf + ports: + - name: spire-server + protocol: TCP + containerPort: 8081 + {{- if (include "ua-vault-env-name" .) }} + env: + - name: {{ include "ua-vault-env-name" . }} + valueFrom: + secretKeyRef: + name: spire-server + key: {{ include "ua-vault-env-name" . }} + {{- end }} + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + {{- if (include "ua-secret-mountpath" .) }} + - name: spire-secrets + mountPath: {{ include "ua-secret-mountpath" . }} + readOnly: true + {{- end }} + {{- if eq .Values.mtls.persistentStorage "on" }} + - name: spire-data + mountPath: /run/spire/data + readOnly: false + {{- end }} + - name: spire-server-socket + mountPath: /run/spire/sockets + readOnly: false + livenessProbe: + exec: + command: + - /opt/spire/bin/spire-server + - healthcheck + - '-shallow' + - '-registrationUDSPath' + - /run/spire/sockets/spire-registration.sock + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + exec: + command: + - /opt/spire/bin/spire-server + - healthcheck + - '-registrationUDSPath' + - /run/spire/sockets/spire-registration.sock + initialDelaySeconds: 5 + periodSeconds: 5 + - name: k8s-workload-registrar + image: {{ include "spire.image-server" . }}/k8s-workload-registrar:1.0.2 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + args: + - '-config' + - /run/spire/config/k8s-workload-registrar.conf + ports: + - name: webhook + protocol: TCP + containerPort: 9443 + volumeMounts: + - name: k8s-workload-registrar-config + mountPath: /run/spire/config + readOnly: true + - name: k8s-workload-registrar-secret + mountPath: /tmp/k8s-webhook-server/serving-certs + readOnly: true + - name: spire-server-socket + mountPath: /run/spire/sockets + readOnly: true + volumes: + - name: spire-config + configMap: + name: spire-server + {{- if (include "ua-secret-name" .) }} + - name: spire-secrets + secret: + secretName: spire-server + items: + - key: {{ include "ua-secret-name" . }} + path: {{ include "ua-secret-name" . }} + {{- end }} + - name: spire-server-socket + emptyDir: {} + - name: k8s-workload-registrar-config + configMap: + name: k8s-workload-registrar + - name: k8s-workload-registrar-secret + secret: + secretName: k8s-workload-registrar-secret + {{- if eq .Values.mtls.persistentStorage "on" }} + volumeClaimTemplates: + - metadata: + name: spire-data + namespace: {{ .Release.Namespace }} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + {{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/zipkin.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/zipkin.yaml new file mode 100644 index 000000000..aeedc8f26 --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/templates/zipkin.yaml @@ -0,0 +1,46 @@ +{{- if (and (not .Values.tracing.disable) (eq .Values.tracing.backend "zipkin") (eq .Values.tracing.address "")) }} +--- +apiVersion: v1 +kind: Service +metadata: + name: zipkin + labels: + app.kubernetes.io/name: zipkin + app.kubernetes.io/part-of: nginx-service-mesh +spec: + selector: + app.kubernetes.io/name: zipkin + app.kubernetes.io/part-of: nginx-service-mesh + type: ClusterIP + ports: + - port: 9411 + targetPort: 9411 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zipkin + labels: + app.kubernetes.io/name: zipkin + app.kubernetes.io/part-of: nginx-service-mesh +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: zipkin + app.kubernetes.io/part-of: nginx-service-mesh + template: + metadata: + labels: + app.kubernetes.io/name: zipkin + app.kubernetes.io/part-of: nginx-service-mesh + spec: + imagePullSecrets: + - name: {{ include "registry-key-name" . }} + containers: + - name: zipkin + image: {{ include "zipkin.image-server" . }}/zipkin:2.21 + imagePullPolicy: {{ .Values.registry.imagePullPolicy }} + ports: + - containerPort: 9411 +{{- end }} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.schema.json b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.schema.json new file mode 100644 index 000000000..3783d041b --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.schema.json @@ -0,0 +1,455 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "NGINX Service Mesh Values", + "type": "object", + "properties": { + "mtls": { + "type": "object", + "properties": { + "mode": { + "description": "mTLS mode for pod-to-pod communication", + "type": "string", + "enum": ["off", "permissive", "strict"], + "default": "permissive" + }, + "caTTL": { + "description": "The CA/signing key TTL in hours(h) or minutes(m)", + "type": "string", + "pattern": "[0-9]*(h|m)", + "default": "720h" + }, + "svidTTL": { + "description": "The TTL of certificates issued to workloads in hours(h) or minutes(m)", + "type": "string", + "pattern": "[0-9]*(h|m)", + "default": "1h" + }, + "trustDomain": { + "description": "The trust domain of the NGINX Service Mesh", + "type": "string", + "default": "example.org" + }, + "persistentStorage": { + "description": "Use persistent storage", + "type": "string", + "enum": ["on", "off"], + "default": "on" + }, + "spireServerKeyManager": { + "description": "Storage logic for Spire Server's private keys", + "type": "string", + "enum": ["disk", "memory"], + "default": "disk" + }, + "upstreamAuthority": { + "description": "Upstream authority settings", + "type": "object", + "properties": { + "disk": { + "description": "Disk object", + "type": "object", + "properties": { + "cert": { + "description": "Contents of your PEM encoded certificate file", + "type": "string", + "minLength": 1 + }, + "key": { + "description": "Contents of your PEM encoded key file", + "type": "string", + "minLength": 1 + }, + "bundle": { + "description": "Contents of your CA bundle file", + "type": "string" + } + }, + "required": ["cert", "key"] + }, + "awsPCA": { + "description": "AWS PCA object", + "type": "object", + "properties": { + "region": { + "description": "AWS region to use", + "type": "string", + "minLength": 1 + }, + "certificateAuthorityArn": { + "description": "ARN of the upstream CA certificate", + "type": "string", + "minLength": 1 + }, + "awsAccessKeyID": { + "description": "AWS access key ID", + "type": "string", + "minLength": 1 + }, + "awsSecretAccessKey": { + "description": "AWS secret access key", + "type": "string", + "minLength": 1 + }, + "caSigningTemplateArn": { + "description": "ARN of the signing template to use for the server's CA", + "type": "string" + }, + "signingAlgorithm": { + "description": "Signing algorithm to use for the server's CA", + "type": "string" + }, + "assumeRoleArn": { + "description": " ARN of an IAM role to assume", + "type": "string" + }, + "endpoint": { + "description": "Endpoint as hostname or fully-qualified URI that overrides the default endpoint", + "type": "string" + }, + "supplementalBundle": { + "description": "Contents of a PEM encoded CA certificates file that should be additionally included in the bundle", + "type": "string" + } + }, + "required": ["region", "certificateAuthorityArn", "awsAccessKeyID", "awsSecretAccessKey"] + }, + "awsSecret": { + "description": "AWS Secret object", + "type": "object", + "properties": { + "region": { + "description": "AWS region to use", + "type": "string", + "minLength": 1 + }, + "certFileArn": { + "description": "ARN of the upstream CA certificate", + "type": "string", + "minLength": 1 + }, + "keyFileArn": { + "description": "ARN of the upstream CA key file", + "type": "string", + "minLength": 1 + }, + "awsAccessKeyID": { + "description": "AWS access key ID", + "type": "string" + }, + "awsSecretKeyID": { + "description": "AWS secret access key", + "type": "string" + }, + "awsSecretToken": { + "description": "AWS secret token", + "type": "string" + }, + "assumeRoleArn": { + "description": "ARN of role to assume", + "type": "string" + } + }, + "required": ["region", "certFileArn", "keyFileArn"] + }, + "vault": { + "description": "Vault object", + "type": "object", + "properties": { + "vaultAddr": { + "description": "URL of the Vault server", + "type": "string", + "minLength": 1 + }, + "namespace": { + "description": "Vault namespace", + "type": "string", + "minLength": 1 + }, + "caCert": { + "description": "Contents of a PEM encoded CA certificate file to verify the Vault server certificate", + "type": "string", + "minLength": 1 + }, + "pkiMountPoint": { + "description": "Name of the mount point where the PKI secret engine is mounted", + "type": "string", + "default": "pki" + }, + "insecureSkipVerify": { + "description": "If true, vault client accepts any server certificates", + "type": "boolean", + "default": false + }, + "certAuth": { + "description": "Client certificate authentication object", + "type": "object", + "properties": { + "clientCert": { + "description": "Contents of your client cert file", + "type": "string", + "minLength": 1 + }, + "clientKey": { + "description": "Contents of your client key file", + "type": "string", + "minLength": 1 + }, + "certAuthMountPoint": { + "description": "Name of the mount point where TLS certificate auth method is mounted", + "type": "string", + "default": "cert" + }, + "certAuthRoleName": { + "description": "Name of the vault role. If given, the plugin authenticates against only the named role. Default to trying all roles.", + "type": "string" + } + }, + "required": ["clientCert", "clientKey"] + }, + "tokenAuth": { + "description": "Token authentication object", + "type": "object", + "properties": { + "token": { + "description": "Token string set into X-Vault-Token header", + "type": "string", + "minLength": 1 + } + }, + "required": ["token"] + }, + "approleAuth": { + "description": "AppRole authentication object", + "type": "object", + "properties": { + "approleID": { + "description": "An identifier of AppRole", + "type": "string", + "minLength": 1 + }, + "approleSecretID": { + "description": "A credential of AppRole", + "type": "string", + "minLength": 1 + }, + "approleAuthMountPoint": { + "description": "Name of the mount point where the AppRole auth method is mounted", + "type": "string", + "default": "approle" + } + }, + "required": ["approleID", "approleSecretID"] + } + }, + "required": ["vaultAddr", "namespace", "caCert"], + "oneOf": [ + {"required": ["certAuth"]}, + {"required": ["tokenAuth"]}, + {"required": ["approleAuth"]} + ] + } + }, + "oneOf": [ + {"const": {}}, + {"required": ["disk"]}, + {"required": ["awsPCA"]}, + {"required": ["awsSecret"]}, + {"required": ["vault"]} + ] + } + }, + "required": ["mode", "caTTL", "svidTTL", "trustDomain", "persistentStorage", "spireServerKeyManager"] + }, + "registry": { + "description": "NGINX Service Mesh image registry settings", + "type": "object", + "properties": { + "server": { + "description": "Hostname:port (if needed) for registry and path to images", + "type": "string", + "default": "docker-registry.nginx.com/nsm" + }, + "imageTag": { + "description": "Tag used for pulling images from registry. ", + "type": "string", + "default": "1.1.0" + }, + "key": { + "description": "Contents of your Google Cloud JSON key file", + "type": "string" + }, + "username": { + "description": "Username for accessing private registry", + "type": "string" + }, + "password": { + "description": "Password for accessing private registry", + "type": "string" + }, + "disablePublicImages": { + "description": "Disable the pulling of third party images from public repositories", + "type": "boolean", + "default": false + }, + "imagePullPolicy": { + "description": "Image pull policy", + "type": "string", + "enum": ["Never", "IfNotPresent", "Always"], + "default": "IfNotPresent" + } + }, + "oneOf": [ + { + "properties": { + "key": {"$ref": "#/definitions/emptyString"}, + "username": {"$ref": "#/definitions/emptyString"}, + "password": {"$ref": "#/definitions/emptyString"} + } + }, + { + "properties": { + "key": {"$ref": "#/definitions/nonEmptyString"}, + "username": {"$ref": "#/definitions/emptyString"}, + "password": {"$ref": "#/definitions/emptyString"} + } + }, + { + "properties": { + "username": {"$ref": "#/definitions/nonEmptyString"}, + "password": {"$ref": "#/definitions/nonEmptyString"}, + "key": {"$ref": "#/definitions/emptyString"} + } + } + ], + "required": ["server", "imageTag", "disablePublicImages", "imagePullPolicy"] + }, + "accessControlMode": { + "description": "Default access control mode for service-to-service communication", + "type": "string", + "enum": ["allow", "deny"] + }, + "deployGrafana": { + "description": "Deploy Grafana as a part of the NGINX Service Mesh", + "type": "boolean" + }, + "nginxErrorLogLevel": { + "description": "NGINX error log level", + "type": "string", + "enum": ["debug", "info", "notice", "warn", "error", "crit", "alert", "emerg"] + }, + "nginxLogFormat": { + "description": "NGINX log format", + "type": "string", + "enum": ["default", "json"] + }, + "nginxLBMethod": { + "description": "NGINX load balancing method", + "type": "string", + "enum": ["least_conn", "least_time", "least_time last_byte", "least_time last_byte inflight", "random", "random two", "random two least_conn", "random two least_time", "random two least_time=last_byte", "round_robin"] + }, + "prometheusAddress": { + "description": "The address of a Prometheus server deployed in your Kubernetes cluster", + "type": "string" + }, + "autoInjection": { + "description": "NGINX Service Mesh auto-injection settings", + "type": "object", + "properties": { + "disable": { + "description": "Disable automatic sidecar injection upon resource creation", + "type": "boolean" + }, + "disabledNamespaces": { + "description": "Disable automatic sidecar injection for specific namespace", + "type": "array", + "items": { + "type": "string" + } + }, + "enabledNamespaces": { + "description": "Enable automatic sidecar injection for specific namespaces", + "type": "array", + "items": { + "type": "string" + } + } + }, + "oneOf": [ + { + "properties": { + "disabledNamespaces": {"$ref": "#/definitions/nonEmptyArray"}, + "disable": {"const": false} + } + }, + { + "properties": { + "enabledNamespaces": {"$ref": "#/definitions/nonEmptyArray"}, + "disable": {"const": true} + } + }, + { + "properties": { + "enabledNamespaces": {"$ref": "#/definitions/emptyArray"}, + "disabledNamespaces": {"$ref": "#/definitions/emptyArray"} + } + } + ], + "required": ["disable"] + }, + "tracing": { + "description": "NGINX Service Mesh tracing settings", + "type": "object", + "properties": { + "disable": { + "description": "Disable tracing for all services", + "type": "boolean" + }, + "address": { + "description": "The address of a tracing server deploying in your Kubernetes cluster", + "type": "string" + }, + "backend": { + "description": "The tracing backend that you want to use", + "type": "string", + "enum": ["datadog", "jaeger", "zipkin"] + }, + "sampleRate": { + "description": "The sample rate to use for tracing. Float between 0 and 1", + "type": "number", + "minimum": 0.0, + "maximum": 1.0 + } + }, + "required": ["disable", "sampleRate"] + } + }, + "definitions": { + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "emptyString": { + "type": "string", + "const": "" + }, + "nonEmptyArray": { + "type": "array", + "minItems": 1 + }, + "emptyArray": { + "type": "array", + "maxItems": 0 + } + }, + "required": [ + "mtls", + "registry", + "accessControlMode", + "deployGrafana", + "nginxErrorLogLevel", + "nginxLogFormat", + "nginxLBMethod", + "autoInjection", + "tracing" + ] +} diff --git a/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.yaml b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.yaml new file mode 100644 index 000000000..05cd5384b --- /dev/null +++ b/charts/nginx-service-mesh/nginx-service-mesh/0.2.100/values.yaml @@ -0,0 +1,209 @@ +# NGINX Service Mesh image registry settings. +registry: + # Hostname:port (if needed) for registry and path to images. + # Affects: nginx-mesh-api, nginx-mesh-cert-reloader, nginx-mesh-init, nginx-mesh-metrics, nginx-mesh-sidecar + server: "docker-registry.nginx.com/nsm" + + # Tag used for pulling images from registry + # Affects: nginx-mesh-api, nginx-mesh-cert-reloader, nginx-mesh-init, nginx-mesh-metrics, nginx-mesh-sidecar + imageTag: "1.2.1" + + # Note: Currently only works with Google Cloud registry. + # Contents of your Google Cloud JSON key file. Can be set via "--set-file registry.key=.json" + # Cannot be used with username or password. + key: "" + + # Username for accessing private registry. + # Requires password to be set. Cannot be used with key. + username: "" + + # Password for accessing private registry. + # Requires username to be set. Cannot be used with key. + password: "" + + # Do not pull third party images from public repositories. + # If true, registry.server is used for all images. + disablePublicImages: false + + # Image pull policy + # Valid values: Always, IfNotPresent, Never + imagePullPolicy: "IfNotPresent" + +# Default access control mode for service-to-service communication. +# Valid values: allow, deny +accessControlMode: "allow" + +# Deploy Grafana as a part of the NGINX Service Mesh. +# Valid values: true, false +deployGrafana: true + +# NGINX error log level. +# Valid values: debug, info, notice, warn, error, crit, alert, emerg +nginxErrorLogLevel: "warn" + +# NGINX log format. +# Valid values: default, json +nginxLogFormat: "default" + +# NGINX load balancing method. +# Valid values: [least_conn, least_time, least_time last_byte, least_time last_byte inflight, +# random, random two, random two least_conn, random two least_time, random two least_time=last_byte, round_robin] +nginxLBMethod: "least_time" + +# The address of a Prometheus server deployed in your Kubernetes cluster. +# Address should be in the format .:. +prometheusAddress: "" + +# NGINX Service Mesh auto-injection settings. +autoInjection: + # Disable automatic sidecar injection upon resource creation. + # Use the "enabledNamespaces" flag to enable automatic injection in select namespaces. + disable: false + + # Disable automatic sidecar injection for specific namespaces. + # Cannot be used with "disable". + disabledNamespaces: [] + + # Enable automatic sidecar injection for specific namespaces. + # Must be used with "disable". + enabledNamespaces: [] + +# NGINX Service Mesh tracing settings. +tracing: + # Disable tracing for all services. + disable: false + + # The address of a tracing server deployed in your Kubernetes cluster. + # Address should be in the format .:. + address: "" + + # The tracing backend that you want to use. + # Valid values: datadog, jaeger, zipkin + backend: "jaeger" + + # The sample rate to use for tracing. Float between 0 and 1. + sampleRate: 0.01 + +# Mutual TLS settings. See https://docs.nginx.com/nginx-service-mesh/guides/secure-traffic-mtls for more info. +mtls: + # mTLS mode for pod-to-pod communication. + # Valid values: off, permissive, strict + mode: "permissive" + + # The CA/signing key TTL in hours(h) or minutes(m). + caTTL: "720h" + + # The TTL of certificates issued to workloads in hours(h) or minutes(m). + svidTTL: "1h" + + # The trust domain of NGINX Service Mesh. + trustDomain: "example.org" + + # Use persistent storage; "on" assumes that a StorageClass exists. + # Valid values: on, off + persistentStorage: "on" + + # Storage logic for Spire Server's private keys. + # Valid values: disk, memory + spireServerKeyManager: "disk" + + ## Upstream authority settings. If left empty, SPIRE is used as the upstream authority. + ## Only uncomment and fill out the object pertinent to you (disk, awsPCA, awsSecret, vault). + upstreamAuthority: {} + + # # Disk object (see https://github.com/spiffe/spire/blob/v0.12/doc/plugin_server_upstreamauthority_disk.md) + # disk: + # # Contents of your PEM encoded certificate file. Can be set via "--set-file mtls.upstreamAuthority.disk.cert=" + # cert: "" + # # Contents of your PEM encoded key file. Can be set via "--set-file mtls.upstreamAuthority.disk.key=" + # key: "" + # # Optional; contents of your CA bundle file. Can be set via "--set-file mtls.upstreamAuthority.disk.bundle=" + # bundle: "" + + # # AWS PCA object (see https://github.com/spiffe/spire/blob/v0.12/doc/plugin_server_upstreamauthority_aws_pca.md) + # awsPCA: + # # AWS region to use + # region: "" + # # ARN of the upstream CA certificate + # certificateAuthorityArn: "" + # # AWS access key ID + # awsAccessKeyID: "" + # # AWS secret access key + # awsSecretAccessKey: "" + + # ## Optional fields + + # # ARN of the signing template to use for the server's CA + # caSigningTemplateArn: "" + # # Signing algorithm to use for the server's CA + # signingAlgorithm: "" + # # ARN of an IAM role to assume + # assumeRoleArn: "" + # # Endpoint as hostname or fully-qualified URI that overrides the default endpoint + # endpoint: "" + # # Contents of a PEM encoded CA certificates file that should be additionally included in the bundle. + # # Can be set via "--set-file mtls.upstreamAuthority.awsPCA.supplementalBundle=" + # supplementalBundle: "" + + # # AWS Secret object (see https://github.com/spiffe/spire/blob/v0.12/doc/plugin_server_upstreamauthority_awssecret.md) + # awsSecret: + # # AWS region to use + # region: "" + # # ARN of the upstream CA certificate + # certFileArn: "" + # # ARN of the upstream CA key file + # keyFileArn: "" + + # ## Choose an appropriate auth method + + # # AWS access key ID + # awsAccessKeyID: "" + # # AWS secret access key + # awsSecretAccessKey: "" + # # AWS secret token + # awsSecretToken: "" + # # ARN of role to assume + # assumeRoleArn: "" + + # # Vault object (see https://github.com/spiffe/spire/blob/v0.12/doc/plugin_server_upstreamauthority_vault.md) + # vault: + # # URL of the Vault server + # vaultAddr: "" + # # Vault namespace + # namespace: "" + # # Contents of a PEM encoded CA certificate file to verify the Vault server certificate. + # # Can be set via "--set-file mtls.upstreamAuthority.vault.caCert=" + # caCert: "" + # # Name of the mount point where the PKI secret engine is mounted + # pkiMountPoint: "pki" + # # If true, vault client accepts any server certificates + # insecureSkipVerify: false + + # # Client Certificate Authentication + # certAuth: + # # Contents of your client cert file. Can be set via "--set-file mtls.upstreamAuthority.vault.certAuth.clientCert=" + # clientCert: "" + # # Contents of your client key file. Can be set via "--set-file mtls.upstreamAuthority.vault.certAuth.clientKey=" + # clientKey: "" + + # ## Optional fields + + # # Name of the mount point where TLS certificate auth method is mounted + # certAuthMountPoint: "cert" + # # Name of the vault role. If given, the plugin authenticates against only the named role. Default to trying all roles. + # certAuthRoleName: "" + + # # Token Authentication + # tokenAuth: + # # Token string set into "X-Vault-Token" header + # token: "" + + # # AppRole Authentication + # approleAuth: + # # An identifier of AppRole + # approleID: "" + # # A credential of AppRole + # approleSecretID: "" + + # # Name of the mount point where the AppRole auth method is mounted + # approleAuthMountPoint: "approle" diff --git a/index.yaml b/index.yaml index d879b320e..71377f61e 100755 --- a/index.yaml +++ b/index.yaml @@ -1340,6 +1340,22 @@ entries: urls: - assets/nginx-ingress/nginx-ingress-0.10.0.tgz version: 0.10.0 + nginx-service-mesh: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: NGINX Service Mesh + catalog.cattle.io/release-name: nginx-service-mesh + apiVersion: v2 + appVersion: 1.2.1 + created: "2021-10-11T10:18:55.101934-06:00" + description: NGINX Service Mesh + digest: 75ef707cadb314629a881a4f1f2b9862e62e3930dbed27c4ec56a9f380cc1759 + icon: https://raw.githubusercontent.com/nginxinc/nginx-service-mesh/master/helm-chart/chart-icon.png + kubeVersion: 1.16-0 - 1.21-0 + name: nginx-service-mesh + urls: + - assets/nginx-service-mesh/nginx-service-mesh-0.2.100.tgz + version: 0.2.100 nutanix-csi-storage: - annotations: catalog.cattle.io/certified: partner