diff --git a/.github/tests/spire-oidc-insecure/values.yaml b/.github/tests/spire-oidc-insecure/values.yaml index 4c1124e..86f7159 100644 --- a/.github/tests/spire-oidc-insecure/values.yaml +++ b/.github/tests/spire-oidc-insecure/values.yaml @@ -1,3 +1,23 @@ +spire-server: + ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + hosts: + - host: ingress-nginx-controller.spire-oidc-insecure + paths: + - path: / + pathType: Prefix + +spire-agent: + server: + address: ingress-nginx-controller.spire-oidc-insecure + port: 443 + spiffe-oidc-discovery-provider: enabled: true diff --git a/charts/spire/README.md b/charts/spire/README.md index 6250e26..c400772 100644 --- a/charts/spire/README.md +++ b/charts/spire/README.md @@ -319,6 +319,13 @@ Kubernetes: `>=1.21.0-0` | spire-server.federation.bundleEndpoint.address | string | `"0.0.0.0"` | | | spire-server.federation.bundleEndpoint.port | int | `8443` | | | spire-server.federation.enabled | bool | `false` | | +| spire-server.federation.ingress.annotations | object | `{}` | | +| spire-server.federation.ingress.className | string | `""` | | +| spire-server.federation.ingress.enabled | bool | `false` | | +| spire-server.federation.ingress.hosts[0].host | string | `"spire-server-federation.example.org"` | | +| spire-server.federation.ingress.hosts[0].paths[0].path | string | `"/"` | | +| spire-server.federation.ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | | +| spire-server.federation.ingress.tls | list | `[]` | | | spire-server.fullnameOverride | string | `""` | | | spire-server.image.pullPolicy | string | `"IfNotPresent"` | The image pull policy | | spire-server.image.registry | string | `"ghcr.io"` | The OCI registry to pull the image from | @@ -326,6 +333,13 @@ Kubernetes: `>=1.21.0-0` | spire-server.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | | spire-server.image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) | | spire-server.imagePullSecrets | list | `[]` | | +| spire-server.ingress.annotations | object | `{}` | | +| spire-server.ingress.className | string | `""` | | +| spire-server.ingress.enabled | bool | `false` | | +| spire-server.ingress.hosts[0].host | string | `"spire-server.example.org"` | | +| spire-server.ingress.hosts[0].paths[0].path | string | `"/"` | | +| spire-server.ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | | +| spire-server.ingress.tls | list | `[]` | | | spire-server.initContainers | list | `[]` | | | spire-server.jwtIssuer | string | `"oidc-discovery.example.org"` | The JWT issuer domain | | spire-server.logLevel | string | `"info"` | The log level, valid values are "debug", "info", "warn", and "error" | diff --git a/charts/spire/charts/spiffe-oidc-discovery-provider/templates/ingress.yaml b/charts/spire/charts/spiffe-oidc-discovery-provider/templates/ingress.yaml index ba3cf8c..f71db7d 100644 --- a/charts/spire/charts/spiffe-oidc-discovery-provider/templates/ingress.yaml +++ b/charts/spire/charts/spiffe-oidc-discovery-provider/templates/ingress.yaml @@ -1,42 +1,16 @@ {{- if .Values.ingress.enabled -}} {{- $fullName := include "spiffe-oidc-discovery-provider.fullname" . }} -{{- $port := .Values.service.port }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ $fullName }} namespace: {{ include "spiffe-oidc-discovery-provider.namespace" . }} labels: - {{- include "spiffe-oidc-discovery-provider.labels" . | nindent 4 }} + {{ include "spiffe-oidc-discovery-provider.labels" . | nindent 4 }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} spec: - ingressClassName: {{ .Values.ingress.className }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - pathType: {{ .pathType }} - backend: - service: - name: {{ $fullName }} - port: - number: {{ $port }} - {{- end }} - {{- end }} + {{ include "spire-lib.ingress-spec" (dict "ingress" .Values.ingress "svcName" $fullName "port" .Values.service.port "global" .Values.global) | nindent 2 }} {{- end }} diff --git a/charts/spire/charts/spire-server/README.md b/charts/spire/charts/spire-server/README.md index 3eb765f..76f935c 100644 --- a/charts/spire/charts/spire-server/README.md +++ b/charts/spire/charts/spire-server/README.md @@ -73,6 +73,13 @@ A Helm chart to install the SPIRE server. | federation.bundleEndpoint.address | string | `"0.0.0.0"` | | | federation.bundleEndpoint.port | int | `8443` | | | federation.enabled | bool | `false` | | +| federation.ingress.annotations | object | `{}` | | +| federation.ingress.className | string | `""` | | +| federation.ingress.enabled | bool | `false` | | +| federation.ingress.hosts[0].host | string | `"spire-server-federation.example.org"` | | +| federation.ingress.hosts[0].paths[0].path | string | `"/"` | | +| federation.ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | | +| federation.ingress.tls | list | `[]` | | | fullnameOverride | string | `""` | | | image.pullPolicy | string | `"IfNotPresent"` | The image pull policy | | image.registry | string | `"ghcr.io"` | The OCI registry to pull the image from | @@ -80,6 +87,13 @@ A Helm chart to install the SPIRE server. | image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | | image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) | | imagePullSecrets | list | `[]` | | +| ingress.annotations | object | `{}` | | +| ingress.className | string | `""` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts[0].host | string | `"spire-server.example.org"` | | +| ingress.hosts[0].paths[0].path | string | `"/"` | | +| ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | | +| ingress.tls | list | `[]` | | | initContainers | list | `[]` | | | jwtIssuer | string | `"oidc-discovery.example.org"` | The JWT issuer domain | | logLevel | string | `"info"` | The log level, valid values are "debug", "info", "warn", and "error" | diff --git a/charts/spire/charts/spire-server/templates/federation-ingress.yaml b/charts/spire/charts/spire-server/templates/federation-ingress.yaml new file mode 100644 index 0000000..013be91 --- /dev/null +++ b/charts/spire/charts/spire-server/templates/federation-ingress.yaml @@ -0,0 +1,18 @@ +{{- if .Values.federation.enabled }} +{{- if .Values.federation.ingress.enabled -}} +{{- $svcName := include "spire-server.fullname" . }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ printf "%s-federation" $svcName }} + namespace: {{ include "spire-server.namespace" . }} + labels: + {{ include "spire-server.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{ include "spire-lib.ingress-spec" (dict "ingress" .Values.federation.ingress "svcName" $svcName "port" .Values.federation.bundleEndpoint.port "global" .Values.global) | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-server/templates/ingress.yaml b/charts/spire/charts/spire-server/templates/ingress.yaml new file mode 100644 index 0000000..56da8c8 --- /dev/null +++ b/charts/spire/charts/spire-server/templates/ingress.yaml @@ -0,0 +1,16 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "spire-server.fullname" . -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "spire-server.namespace" . }} + labels: + {{ include "spire-server.labels" . | nindent 4}} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{ include "spire-lib.ingress-spec" (dict "ingress" .Values.ingress "svcName" $fullName "port" .Values.service.port "global" .Values.global) | nindent 2 }} +{{- end }} diff --git a/charts/spire/charts/spire-server/values.yaml b/charts/spire/charts/spire-server/values.yaml index 1585cce..499facf 100644 --- a/charts/spire/charts/spire-server/values.yaml +++ b/charts/spire/charts/spire-server/values.yaml @@ -127,6 +127,26 @@ federation: port: 8443 address: "0.0.0.0" + ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # If Profile Type == https_spiffe: + # nginx.ingress.kubernetes.io/ssl-passthrough: "true" + hosts: + - host: spire-server-federation.example.org + paths: + - path: / + pathType: Prefix + tls: [] + # - hosts: + # - spire-server-federation.example.org + # If Profile Type == https_web: + # secretName: spire-server-federation-tls + ca_subject: country: NL organization: Example @@ -247,6 +267,24 @@ telemetry: namespace: "" labels: {} +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/ssl-passthrough: "true" + hosts: + - host: spire-server.example.org + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: spire-server-tls + # hosts: + # - spire-server.example.org + extraVolumes: [] extraVolumeMounts: [] extraContainers: [] diff --git a/charts/spire/templates/_spire-lib.tpl b/charts/spire/templates/_spire-lib.tpl index ca059d9..eac2298 100644 --- a/charts/spire/templates/_spire-lib.tpl +++ b/charts/spire/templates/_spire-lib.tpl @@ -52,3 +52,41 @@ {{- printf "%s/%s" $registry $repo }} {{- end }} {{- end }} + +{{/* Takes in a dictionary with keys: + * ingress - the standardized ingress object + * svcName - The service to route to + * port - which port on the service to use +*/}} +{{ define "spire-lib.ingress-spec" }} +{{- $svcName := .svcName }} +{{- $port := .port }} +{{- with .ingress.className }} +ingressClassName: {{ . | quote }} +{{- end }} +{{- if .ingress.tls }} +tls: + {{- range .ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName | quote }} + {{- end }} +{{- end }} +rules: + {{- range .ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ $svcName | quote }} + port: + number: {{ $port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/examples/production/README.md b/examples/production/README.md index 0514ca4..8b7b196 100644 --- a/examples/production/README.md +++ b/examples/production/README.md @@ -12,3 +12,25 @@ helm upgrade --install --namespace spire-server spire charts/spire -f values.yam ``` See [values.yaml](./values.yaml) for more details on the chart configurations to achieve this setup. + +If you want to expose your spire-server outside of Kubernetes and are using ingress-nginx, add following values file when running `helm template/install/upgrade`. + +```shell +-f values-expose-spire-server-ingress-nginx.yaml +``` + +If you want to expose your federation endpoint outside of Kubernetes and are using ingress-nginx +you have two options as described here: +https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Federation.md#52-endpoint-profiles + +If you chose profile https_web, use: + +```shell +-f values-expose-federation-https-web-ingress-nginx.yaml +``` + +If you chose profile https_spiffe, use: + +```shell +-f values-expose-federation-https-spiffe-ingress-nginx.yaml +``` diff --git a/examples/production/values-export-federation-https-spiffe-ingress-nginx.yaml b/examples/production/values-export-federation-https-spiffe-ingress-nginx.yaml new file mode 100644 index 0000000..35aa85a --- /dev/null +++ b/examples/production/values-export-federation-https-spiffe-ingress-nginx.yaml @@ -0,0 +1,25 @@ +spire-server: + federation: + enabled: true + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + + # Optional settings you may put in your own values. + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + # className: nginx + + hosts: + - host: spire-server-federation.example.org + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - spire-server-federation.example.org diff --git a/examples/production/values-export-federation-https-web-ingress-nginx.yaml b/examples/production/values-export-federation-https-web-ingress-nginx.yaml new file mode 100644 index 0000000..e238c13 --- /dev/null +++ b/examples/production/values-export-federation-https-web-ingress-nginx.yaml @@ -0,0 +1,25 @@ +spire-server: + federation: + enabled: true + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + + # Optional settings you may put in your own values. + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + # className: nginx + + hosts: + - host: spire-server-federation.example.org + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - spire-server-federation.example.org + secretName: spire-server-federation-tls diff --git a/examples/production/values-export-spire-server-ingress-nginx.yaml b/examples/production/values-export-spire-server-ingress-nginx.yaml new file mode 100644 index 0000000..dceac42 --- /dev/null +++ b/examples/production/values-export-spire-server-ingress-nginx.yaml @@ -0,0 +1,25 @@ +spire-server: + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + + # Optional settings you may put in your own values. + # kubernetes.io/tls-acme: "true" + # kubernetes.io/ingress.class: nginx + + # className: nginx + + # You must override these in your own values file with the appropriate hostname + # and secret or it wont start. + hosts: + - host: spire-server.example.org + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - spire-server.example.org