Merge branch 'main' into hotfix/avoid-creating-executable-files

This commit is contained in:
Rami 2023-08-31 16:34:38 +03:00 committed by GitHub
commit cef9014ace
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
339 changed files with 6986 additions and 2801 deletions

View file

@ -42,7 +42,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter
@ -68,10 +68,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Run Gosec Security Scanner
uses: securego/gosec@c5ea1b7bdd9efc3792e513258853552b0ae31e06 # v2.16.0
uses: securego/gosec@a89e9d5a7acb4457f3891ac18532b142b1bf9221 # v2.17.0
with:
# G601 for zz_generated.deepcopy.go
# G306 TODO: Expect WriteFile permissions to be 0600 or less
@ -85,11 +85,11 @@ jobs:
(needs.changes.outputs.go == 'true')
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Set up Go
id: go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true
@ -104,11 +104,11 @@ jobs:
(needs.changes.outputs.go == 'true')
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Set up Go
id: go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true
@ -123,11 +123,11 @@ jobs:
(needs.changes.outputs.go == 'true')
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Set up Go
id: go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true
@ -144,11 +144,11 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Set up Go
id: go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true
@ -158,7 +158,7 @@ jobs:
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2.8.0
uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0
with:
version: latest
@ -167,8 +167,6 @@ jobs:
- name: Prepare Host
run: |
sudo apt-get -qq update || true
sudo apt-get install -y pigz
curl -LO https://dl.k8s.io/release/v1.25.5/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
@ -188,7 +186,7 @@ jobs:
nginx-ingress-controller:e2e \
ingress-controller/controller:1.0.0-dev \
ingress-controller/controller-chroot:1.0.0-dev \
| pigz > docker.tar.gz
| gzip > docker.tar.gz
- name: cache
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
@ -207,14 +205,14 @@ jobs:
strategy:
matrix:
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Setup Go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true
@ -260,7 +258,7 @@ jobs:
- name: Load images from cache
run: |
echo "loading docker images..."
pigz -dc docker.tar.gz | docker load
gzip -dc docker.tar.gz | docker load
- name: Test
env:
@ -282,11 +280,11 @@ jobs:
strategy:
matrix:
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: cache
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
@ -301,7 +299,7 @@ jobs:
- name: Load images from cache
run: |
echo "loading docker images..."
pigz -dc docker.tar.gz | docker load
gzip -dc docker.tar.gz | docker load
- name: Run e2e tests
env:
@ -319,6 +317,55 @@ jobs:
name: e2e-test-reports-${{ matrix.k8s }}
path: 'test/junitreports/report*.xml'
kubernetes-validations:
name: Kubernetes with Validations
runs-on: ubuntu-latest
needs:
- changes
- build
if: |
(needs.changes.outputs.go == 'true') || ${{ inputs.run_e2e }}
strategy:
matrix:
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
steps:
- name: Checkout
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: cache
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: docker.tar.gz
- name: Create Kubernetes ${{ matrix.k8s }} cluster
id: kind
run: |
kind create cluster --image=kindest/node:${{ matrix.k8s }} --config test/e2e/kind.yaml
- name: Load images from cache
run: |
echo "loading docker images..."
gzip -dc docker.tar.gz | docker load
- name: Run e2e tests
env:
KIND_CLUSTER_NAME: kind
SKIP_CLUSTER_CREATION: true
SKIP_IMAGE_CREATION: true
ENABLE_VALIDATIONS: true
run: |
kind get kubeconfig > $HOME/.kube/kind-config-kind
make kind-e2e-test
- name: Upload e2e junit-reports
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: success() || failure()
with:
name: e2e-test-reports-${{ matrix.k8s }}
path: 'test/junitreports/report*.xml'
kubernetes-chroot:
name: Kubernetes chroot
@ -331,12 +378,12 @@ jobs:
strategy:
matrix:
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: cache
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
@ -351,7 +398,7 @@ jobs:
- name: Load images from cache
run: |
echo "loading docker images..."
pigz -dc docker.tar.gz | docker load
gzip -dc docker.tar.gz | docker load
- name: Run e2e tests
env:
@ -380,7 +427,7 @@ jobs:
PLATFORMS: linux/amd64,linux/arm64
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter-images
@ -449,11 +496,11 @@ jobs:
strategy:
matrix:
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter-images
@ -472,7 +519,7 @@ jobs:
- name: Set up Go
id: go
if: ${{ steps.filter-images.outputs.kube-webhook-certgen == 'true' }}
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
check-latest: true

View file

@ -9,6 +9,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: 'Dependency Review'
uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6
uses: actions/dependency-review-action@f6fff72a3217f580d5afd49a46826795305b63c7 # v3.0.8

View file

@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter
@ -47,7 +47,7 @@ jobs:
steps:
- name: Checkout master
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Deploy
uses: ./.github/actions/mkdocs

View file

@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Run Artifact Hub lint
run: |
@ -61,7 +61,7 @@ jobs:
steps:
- name: Checkout master
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
# Fetch entire history. Required for chart-releaser; see https://github.com/helm/chart-releaser-action/issues/13#issuecomment-602063896
fetch-depth: 0
@ -75,7 +75,7 @@ jobs:
- name: Helm Chart Releaser
uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0
env:
CR_SKIP_EXISTING: "false"
CR_SKIP_EXISTING: true
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}"
with:

View file

@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Install K6
run: |

View file

@ -4,10 +4,8 @@ on:
push:
branches:
- "main"
paths:
- "cmd/plugin/**"
tags:
- "v*"
- 'v*.*.*\+plugin'
permissions:
contents: write # for goreleaser/goreleaser-action
@ -17,21 +15,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: 1.20
go-version: '1.20'
check-latest: true
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0
uses: goreleaser/goreleaser-action@3fa32b8bb5620a2c1afe798654bbad59f9da4906 # v4.4.0
with:
version: latest
args: release --rm-dist
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -27,7 +27,7 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
persist-credentials: false

View file

@ -22,7 +22,7 @@ jobs:
versions: ${{ steps.version.outputs.TAGS }}
steps:
- name: Checkout code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
@ -52,7 +52,7 @@ jobs:
versions: ${{ fromJSON(needs.version.outputs.versions) }}
steps:
- name: Checkout code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- shell: bash
id: test

View file

@ -45,14 +45,16 @@ if ! command -v helm &> /dev/null; then
exit 1
fi
function ver { printf "%d%03d%03d" $(echo "$1" | tr '.' ' '); }
HELM_VERSION=$(helm version 2>&1 | cut -f1 -d"," | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || true
echo $HELM_VERSION
if [[ ${HELM_VERSION} -lt 3.10.0 ]]; then
if [[ $(ver $HELM_VERSION) -lt $(ver "3.10.0") ]]; then
echo "Please upgrade helm to v3.10.0 or higher"
exit 1
fi
KUBE_CLIENT_VERSION=$(kubectl version --client --short 2>/dev/null | grep Client | awk '{print $3}' | cut -d. -f2) || true
KUBE_CLIENT_VERSION=$(kubectl version --client -oyaml 2>/dev/null | grep "minor:" | awk '{print $2}' | tr -d '"') || true
if [[ ${KUBE_CLIENT_VERSION} -lt 24 ]]; then
echo "Please update kubectl to 1.24.2 or higher"
exit 1

View file

@ -294,8 +294,9 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
| controller.enableAnnotationValidations | bool | `false` | |
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto" Defaults to false |
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
@ -306,6 +307,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
| controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
| controller.healthCheckPath | string | `"/healthz"` | Path of the health check endpoint. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. |
| controller.hostAliases | object | `{}` | Optionally customize the pod hostAliases. |
| controller.hostNetwork | bool | `false` | Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged |
| controller.hostPort.enabled | bool | `false` | Enable 'hostPort' or not |
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port |
@ -375,7 +377,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
| controller.opentelemetry.enabled | bool | `false` | |
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0"` | |
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472"` | |
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
@ -399,14 +401,14 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.scope.enabled | bool | `false` | Enable 'scope' or not |
| controller.scope.namespace | string | `""` | Namespace to limit the controller to; defaults to $(POD_NAMESPACE) |
| controller.scope.namespaceSelector | string | `""` | When scope.enabled == false, instead of watching all namespaces, we watching namespaces whose labels only match with namespaceSelector. Format like foo=bar. Defaults to empty, means watching all namespaces. |
| controller.service.annotations | object | `{}` | |
| controller.service.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
| controller.service.appProtocol | bool | `true` | If enabled is adding an appProtocol option for Kubernetes service. An appProtocol field replacing annotations that were using for setting a backend protocol. Here is an example for AWS: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http It allows choosing the protocol for each backend specified in the Kubernetes service. See the following GitHub issue for more details about the purpose: https://github.com/kubernetes/kubernetes/issues/40244 Will be ignored for Kubernetes versions older than 1.20 # |
| controller.service.enableHttp | bool | `true` | |
| controller.service.enableHttps | bool | `true` | |
| controller.service.enabled | bool | `true` | |
| controller.service.external.enabled | bool | `true` | |
| controller.service.externalIPs | list | `[]` | List of IP addresses at which the controller services are available # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips # |
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. |
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
| controller.service.internal.enabled | bool | `false` | Enables an additional internal load balancer (besides the external one). |
| controller.service.internal.loadBalancerIP | string | `""` | Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS. |
| controller.service.internal.loadBalancerSourceRanges | list | `[]` | Restrict access For LoadBalancer service. Defaults to 0.0.0.0/0. |

View file

@ -1,5 +1,8 @@
{{- define "ingress-nginx.params" -}}
- /nginx-ingress-controller
{{- if .Values.controller.enableAnnotationValidations }}
- --enable-annotation-validation=true
{{- end }}
{{- if .Values.defaultBackend.enabled }}
- --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
{{- end }}

View file

@ -19,7 +19,7 @@ spec:
matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: controller
{{- if not .Values.controller.autoscaling.enabled }}
{{- if not (or .Values.controller.autoscaling.enabled .Values.controller.keda.enabled) }}
replicas: {{ .Values.controller.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
@ -49,6 +49,9 @@ spec:
{{- if .Values.controller.dnsConfig }}
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostAliases }}
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostname }}
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
{{- end }}
@ -190,7 +193,7 @@ spec:
{{- end }}
{{- if .Values.controller.opentelemetry.enabled}}
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" false) | nindent 8}}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true) | nindent 8}}
{{- end}}
{{- end }}
{{- if .Values.controller.hostNetwork }}

View file

@ -4,7 +4,7 @@ kind: Service
metadata:
annotations:
{{- range $key, $value := .Values.controller.service.internal.annotations }}
{{ $key }}: {{ $value | quote }}
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View file

@ -4,7 +4,7 @@ kind: Service
metadata:
annotations:
{{- range $key, $value := .Values.controller.service.annotations }}
{{ $key }}: {{ $value | quote }}
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View file

@ -5,6 +5,8 @@ metadata:
name: {{ include "ingress-nginx.controller.fullname" . }}
{{- if .Values.controller.metrics.serviceMonitor.namespace }}
namespace: {{ .Values.controller.metrics.serviceMonitor.namespace | quote }}
{{- else }}
namespace: {{ .Release.Namespace }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View file

@ -15,6 +15,7 @@ commonLabels: {}
controller:
name: controller
enableAnnotationValidations: false
image:
## Keep false as default for now!
chroot: false
@ -48,6 +49,8 @@ controller:
addHeaders: {}
# -- Optionally customize the pod dnsConfig.
dnsConfig: {}
# -- Optionally customize the pod hostAliases.
hostAliases: {}
# -- Optionally customize the pod hostname.
hostname: {}
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
@ -63,7 +66,7 @@ controller:
watchIngressWithoutClass: false
# -- Process IngressClass per name (additionally as per spec.controller).
ingressClassByName: false
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto"
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto"
# Defaults to false
enableTopologyAwareRouting: false
# -- This configuration defines if Ingress Controller should allow users to set
@ -415,6 +418,7 @@ controller:
# Will be ignored for Kubernetes versions older than 1.20
##
appProtocol: true
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
annotations: {}
labels: {}
# clusterIP: ""
@ -476,7 +480,7 @@ controller:
internal:
# -- Enables an additional internal load balancer (besides the external one).
enabled: false
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service.
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
annotations: {}
# -- Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS.
loadBalancerIP: ""
@ -552,7 +556,7 @@ controller:
opentelemetry:
enabled: false
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
containerSecurityContext:
allowPrivilegeEscalation: false
admissionWebhooks:

View file

@ -18,11 +18,12 @@ package main
import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"net/http"
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"k8s.io/klog/v2"
"k8s.io/ingress-nginx/internal/ingress/controller"

View file

@ -114,7 +114,6 @@ func main() {
fmt.Println(err)
os.Exit(1)
}
}
func backendsAll() {
@ -155,10 +154,16 @@ func backendsList() {
fmt.Println(unmarshalErr)
return
}
backends := f.([]interface{})
backends, ok := f.([]interface{})
if !ok {
fmt.Printf("unexpected type: %T", f)
}
for _, backendi := range backends {
backend := backendi.(map[string]interface{})
backend, ok := backendi.(map[string]interface{})
if !ok {
fmt.Printf("unexpected type: %T", backendi)
}
fmt.Println(backend["name"].(string))
}
}
@ -180,12 +185,22 @@ func backendsGet(name string) {
fmt.Println(unmarshalErr)
return
}
backends := f.([]interface{})
backends, ok := f.([]interface{})
if !ok {
fmt.Printf("unexpected type: %T", f)
}
for _, backendi := range backends {
backend := backendi.(map[string]interface{})
backend, ok := backendi.(map[string]interface{})
if !ok {
fmt.Printf("unexpected type: %T", backendi)
}
if backend["name"].(string) == name {
printed, _ := json.MarshalIndent(backend, "", " ")
printed, err := json.MarshalIndent(backend, "", " ")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(printed))
return
}
@ -214,17 +229,6 @@ func certGet(host string) {
func general() {
// TODO: refactor to obtain ingress-nginx pod count from the api server
/*
statusCode, body, requestErr := nginx.NewGetStatusRequest(generalPath)
if requestErr != nil {
fmt.Println(requestErr)
return
}
if statusCode != 200 {
fmt.Printf("Nginx returned code %v\n", statusCode)
return
}
*/
var prettyBuffer bytes.Buffer
indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ")

View file

@ -47,5 +47,4 @@ func logger(address string) {
server.Wait()
klog.Infof("Stopping logger")
}

View file

@ -153,7 +153,6 @@ func main() {
if errExists == nil {
conf.IsChroot = true
go logger(conf.InternalLoggerAddress)
}
go metrics.StartHTTPServer(conf.HealthCheckHost, conf.ListenPorts.Health, mux)
@ -282,10 +281,10 @@ func checkService(key string, kubeClient *kubernetes.Clientset) error {
}
if errors.IsNotFound(err) {
return fmt.Errorf("No service with name %v found in namespace %v: %v", name, ns, err)
return fmt.Errorf("no service with name %v found in namespace %v: %v", name, ns, err)
}
return fmt.Errorf("Unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
return fmt.Errorf("unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
}
return nil

View file

@ -47,7 +47,7 @@ func TestCreateApiserverClient(t *testing.T) {
func init() {
// the default value of nginx.TemplatePath assumes the template exists in
// the root filesystem and not in the rootfs directory
path, err := filepath.Abs(filepath.Join("../../rootfs/", nginx.TemplatePath))
path, err := filepath.Abs(filepath.Join("..", "..", "rootfs", nginx.TemplatePath))
if err == nil {
nginx.TemplatePath = path
}
@ -87,14 +87,14 @@ func TestHandleSigterm(t *testing.T) {
ingressflags.ResetForTesting(func() { t.Fatal("bad parse") })
os.Setenv("POD_NAME", podName)
os.Setenv("POD_NAMESPACE", namespace)
t.Setenv("POD_NAME", podName)
t.Setenv("POD_NAMESPACE", namespace)
oldArgs := os.Args
defer func() {
os.Setenv("POD_NAME", "")
os.Setenv("POD_NAMESPACE", "")
t.Setenv("POD_NAME", "")
t.Setenv("POD_NAMESPACE", "")
os.Args = oldArgs
}()

View file

@ -63,13 +63,14 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd
}
func backends(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, backend string, onlyList bool) error {
func backends(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, backend string, onlyList bool) error {
var command []string
if onlyList {
switch {
case onlyList:
command = []string{"/dbg", "backends", "list"}
} else if backend != "" {
case backend != "":
command = []string{"/dbg", "backends", "get", backend}
} else {
default:
command = []string{"/dbg", "backends", "all"}
}

View file

@ -59,7 +59,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd
}
func certs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, host string) error {
func certs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, host string) error {
command := []string{"/dbg", "certs", "get", host}
pod, err := request.ChoosePod(flags, podName, deployment, selector)

View file

@ -55,7 +55,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd
}
func conf(flags *genericclioptions.ConfigFlags, host string, podName string, deployment string, selector string, container string) error {
func conf(flags *genericclioptions.ConfigFlags, host, podName, deployment, selector, container string) error {
pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil {
return err

View file

@ -55,7 +55,7 @@ type execFlags struct {
Stdin bool
}
func exec(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, cmd []string, opts execFlags) error {
func exec(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, cmd []string, opts execFlags) error {
pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil {
return err

View file

@ -47,7 +47,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd
}
func general(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
func general(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil {
return err

View file

@ -74,9 +74,9 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
if host != "" {
rowsWithHost := make([]ingressRow, 0)
for _, row := range rows {
if row.Host == host {
rowsWithHost = append(rowsWithHost, row)
for i := range rows {
if rows[i].Host == host {
rowsWithHost = append(rowsWithHost, rows[i])
}
}
rows = rowsWithHost
@ -91,7 +91,8 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
fmt.Fprintln(printer, "INGRESS NAME\tHOST+PATH\tADDRESSES\tTLS\tSERVICE\tSERVICE PORT\tENDPOINTS")
}
for _, row := range rows {
for i := range rows {
row := &rows[i]
var tlsMsg string
if row.TLS {
tlsMsg = "YES"
@ -134,8 +135,8 @@ type ingressRow struct {
func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
rows := make([]ingressRow, 0)
for _, ing := range *ingresses {
for i := range *ingresses {
ing := &(*ingresses)[i]
address := ""
for _, lbIng := range ing.Status.LoadBalancer.Ingress {
if len(lbIng.IP) > 0 {

View file

@ -24,7 +24,6 @@ import (
)
func TestGetIngressInformation(t *testing.T) {
testcases := map[string]struct {
ServiceBackend *networking.IngressServiceBackend
wantName string

View file

@ -111,11 +111,13 @@ type lintOptions struct {
}
func (opts *lintOptions) Validate() error {
//nolint:dogsled // Ignore 3 blank identifiers
_, _, _, err := util.ParseVersionString(opts.versionFrom)
if err != nil {
return err
}
//nolint:dogsled // Ignore 3 blank identifiers
_, _, _, err = util.ParseVersionString(opts.versionTo)
if err != nil {
return err
@ -131,9 +133,9 @@ type lint interface {
Version() string
}
func checkObjectArray(lints []lint, objects []kmeta.Object, opts lintOptions) {
func checkObjectArray(allLints []lint, objects []kmeta.Object, opts lintOptions) {
usedLints := make([]lint, 0)
for _, lint := range lints {
for _, lint := range allLints {
lintVersion := lint.Version()
if lint.Version() == "" {
lintVersion = "0.0.0"
@ -189,7 +191,7 @@ func ingresses(opts lintOptions) error {
return err
}
var iLints []lints.IngressLint = lints.GetIngressLints()
iLints := lints.GetIngressLints()
genericLints := make([]lint, len(iLints))
for i := range iLints {
genericLints[i] = iLints[i]
@ -216,7 +218,7 @@ func deployments(opts lintOptions) error {
return err
}
var iLints []lints.DeploymentLint = lints.GetDeploymentLints()
iLints := lints.GetDeploymentLints()
genericLints := make([]lint, len(iLints))
for i := range iLints {
genericLints[i] = iLints[i]

View file

@ -95,7 +95,7 @@ func (o *logsFlags) toStrings() []string {
return r
}
func logs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, opts logsFlags) error {
func logs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, opts logsFlags) error {
pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil {
return err

View file

@ -45,7 +45,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd
}
func ssh(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
func ssh(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil {
return err

View file

@ -38,11 +38,11 @@ func PodExecString(flags *genericclioptions.ConfigFlags, pod *apiv1.Pod, contain
// ExecToString runs a kubectl subcommand and returns stdout as a string
func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) {
kArgs := getKubectlConfigFlags(flags)
kArgs = append(kArgs, args...)
kubectlArgs := getKubectlConfigFlags(flags)
kubectlArgs = append(kubectlArgs, args...)
buf := bytes.NewBuffer(make([]byte, 0))
err := execToWriter(append([]string{"kubectl"}, kArgs...), buf)
err := execToWriter(append([]string{"kubectl"}, kubectlArgs...), buf)
if err != nil {
return "", err
}
@ -51,9 +51,9 @@ func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string,
// Exec replaces the current process with a kubectl invocation
func Exec(flags *genericclioptions.ConfigFlags, args []string) error {
kArgs := getKubectlConfigFlags(flags)
kArgs = append(kArgs, args...)
return execCommand(append([]string{"kubectl"}, kArgs...))
kubectlArgs := getKubectlConfigFlags(flags)
kubectlArgs = append(kubectlArgs, args...)
return execCommand(append([]string{"kubectl"}, kubectlArgs...))
}
// Replaces the currently running process with the given command
@ -70,6 +70,7 @@ func execCommand(args []string) error {
// Runs a command and returns stdout
func execToWriter(args []string, writer io.Writer) error {
//nolint:gosec // Ignore G204 error
cmd := exec.Command(args[0], args[1:]...)
op, err := cmd.StdoutPipe()
@ -78,7 +79,7 @@ func execToWriter(args []string, writer io.Writer) error {
}
go func() {
io.Copy(writer, op) //nolint:errcheck
io.Copy(writer, op) //nolint:errcheck // Ignore the error
}()
err = cmd.Run()
if err != nil {
@ -106,7 +107,6 @@ func getKubectlConfigFlags(flags *genericclioptions.ConfigFlags) []string {
appendStringFlag(o, flags.Password, "password")
appendStringFlag(o, flags.ClusterName, "cluster")
appendStringFlag(o, flags.AuthInfoName, "user")
//appendStringFlag(o, flags.Namespace, "namespace")
appendStringFlag(o, flags.Context, "context")
appendStringFlag(o, flags.APIServer, "server")
appendBoolFlag(o, flags.Insecure, "insecure-skip-tls-verify")
@ -128,7 +128,7 @@ func appendBoolFlag(out *[]string, in *bool, flag string) {
}
}
func appendStringArrayFlag(out *[]string, in *[]string, flag string) {
func appendStringArrayFlag(out, in *[]string, flag string) {
if in != nil && len(*in) > 0 {
*out = append(*out, fmt.Sprintf("--%v=%v'", flag, strings.Join(*in, ",")))
}

View file

@ -35,7 +35,10 @@ type DeploymentLint struct {
// Check returns true if the lint detects an issue
func (lint DeploymentLint) Check(obj kmeta.Object) bool {
cmp := obj.(*v1.Deployment)
cmp, ok := obj.(*v1.Deployment)
if !ok {
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
}
return lint.f(*cmp)
}
@ -72,11 +75,11 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
issue: issueNumber,
version: version,
f: func(dep v1.Deployment) bool {
if !isIngressNginxDeployment(dep) {
if !isIngressNginxDeployment(&dep) {
return false
}
args := getNginxArgs(dep)
args := getNginxArgs(&dep)
for _, arg := range args {
if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) {
return true
@ -88,8 +91,9 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
}
}
func getNginxArgs(dep v1.Deployment) []string {
for _, container := range dep.Spec.Template.Spec.Containers {
func getNginxArgs(dep *v1.Deployment) []string {
for i := range dep.Spec.Template.Spec.Containers {
container := &dep.Spec.Template.Spec.Containers[i]
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
return container.Args
}
@ -97,10 +101,10 @@ func getNginxArgs(dep v1.Deployment) []string {
return make([]string, 0)
}
func isIngressNginxDeployment(dep v1.Deployment) bool {
func isIngressNginxDeployment(dep *v1.Deployment) bool {
containers := dep.Spec.Template.Spec.Containers
for _, container := range containers {
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
for i := range containers {
if len(containers[i].Args) > 0 && containers[i].Args[0] == "/nginx-ingress-controller" {
return true
}
}

View file

@ -30,13 +30,16 @@ type IngressLint struct {
message string
issue int
version string
f func(ing networking.Ingress) bool
f func(ing *networking.Ingress) bool
}
// Check returns true if the lint detects an issue
func (lint IngressLint) Check(obj kmeta.Object) bool {
ing := obj.(*networking.Ingress)
return lint.f(*ing)
ing, ok := obj.(*networking.Ingress)
if !ok {
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
}
return lint.f(ing)
}
// Message is a description of the lint
@ -94,7 +97,7 @@ func GetIngressLints() []IngressLint {
}
}
func xForwardedPrefixIsBool(ing networking.Ingress) bool {
func xForwardedPrefixIsBool(ing *networking.Ingress) bool {
for name, val := range ing.Annotations {
if strings.HasSuffix(name, "/x-forwarded-prefix") && (val == "true" || val == "false") {
return true
@ -103,7 +106,7 @@ func xForwardedPrefixIsBool(ing networking.Ingress) bool {
return false
}
func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
func annotationPrefixIsNginxCom(ing *networking.Ingress) bool {
for name := range ing.Annotations {
if strings.HasPrefix(name, "nginx.com/") {
return true
@ -112,7 +115,7 @@ func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
return false
}
func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
func annotationPrefixIsNginxOrg(ing *networking.Ingress) bool {
for name := range ing.Annotations {
if strings.HasPrefix(name, "nginx.org/") {
return true
@ -121,7 +124,7 @@ func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
return false
}
func rewriteTargetWithoutCaptureGroup(ing networking.Ingress) bool {
func rewriteTargetWithoutCaptureGroup(ing *networking.Ingress) bool {
for name, val := range ing.Annotations {
if strings.HasSuffix(name, "/rewrite-target") && !strings.Contains(val, "$1") {
return true
@ -135,7 +138,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
message: fmt.Sprintf("Contains the removed %v annotation.", annotationName),
issue: issueNumber,
version: version,
f: func(ing networking.Ingress) bool {
f: func(ing *networking.Ingress) bool {
for annotation := range ing.Annotations {
if strings.HasSuffix(annotation, "/"+annotationName) {
return true
@ -146,7 +149,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
}
}
func satisfyDirective(ing networking.Ingress) bool {
func satisfyDirective(ing *networking.Ingress) bool {
for name, val := range ing.Annotations {
if strings.HasSuffix(name, "/configuration-snippet") {
return strings.Contains(val, "satisfy")

View file

@ -35,7 +35,7 @@ import (
)
// ChoosePod finds a pod either by deployment or by name
func ChoosePod(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) (apiv1.Pod, error) {
func ChoosePod(flags *genericclioptions.ConfigFlags, podName, deployment, selector string) (apiv1.Pod, error) {
if podName != "" {
return GetNamedPod(flags, podName)
}
@ -54,9 +54,9 @@ func GetNamedPod(flags *genericclioptions.ConfigFlags, name string) (apiv1.Pod,
return apiv1.Pod{}, err
}
for _, pod := range allPods {
if pod.Name == name {
return pod, nil
for i := range allPods {
if allPods[i].Name == name {
return allPods[i], nil
}
}
@ -132,7 +132,7 @@ func GetIngressDefinitions(flags *genericclioptions.ConfigFlags, namespace strin
}
// GetNumEndpoints counts the number of endpointslices adresses for the service with the given name
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, serviceName string) (*int, error) {
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace, serviceName string) (*int, error) {
epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
if err != nil {
return nil, err
@ -143,25 +143,26 @@ func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, ser
}
ret := 0
for _, eps := range epss {
for _, ep := range eps.Endpoints {
ret += len(ep.Addresses)
for i := range epss {
eps := &epss[i]
for j := range eps.Endpoints {
ret += len(eps.Endpoints[j].Addresses)
}
}
return &ret, nil
}
// GetEndpointSlicesByName returns the endpointSlices for the service with the given name
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace string, name string) ([]discoveryv1.EndpointSlice, error) {
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace, name string) ([]discoveryv1.EndpointSlice, error) {
allEndpointsSlices, err := getEndpointSlices(flags, namespace)
if err != nil {
return nil, err
}
var eps []discoveryv1.EndpointSlice
for _, slice := range allEndpointsSlices {
if svcName, ok := slice.ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
for i := range allEndpointsSlices {
if svcName, ok := allEndpointsSlices[i].ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
if svcName == name {
eps = append(eps, slice)
eps = append(eps, allEndpointsSlices[i])
}
}
}
@ -182,7 +183,7 @@ func getEndpointSlices(flags *genericclioptions.ConfigFlags, namespace string) (
tryAllNamespacesEndpointSlicesCache(flags)
}
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(flags, namespace)
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(namespace)
if cachedEndpointSlices != nil {
return *cachedEndpointSlices, nil
@ -217,13 +218,13 @@ func tryAllNamespacesEndpointSlicesCache(flags *genericclioptions.ConfigFlags) {
}
}
func tryFilteringEndpointSlicesFromAllNamespacesCache(flags *genericclioptions.ConfigFlags, namespace string) *[]discoveryv1.EndpointSlice {
func tryFilteringEndpointSlicesFromAllNamespacesCache(namespace string) *[]discoveryv1.EndpointSlice {
allEndpointSlices := endpointSlicesCache[""]
if allEndpointSlices != nil {
endpointSlices := make([]discoveryv1.EndpointSlice, 0)
for _, slice := range *allEndpointSlices {
if slice.Namespace == namespace {
endpointSlices = append(endpointSlices, slice)
for i := range *allEndpointSlices {
if (*allEndpointSlices)[i].Namespace == namespace {
endpointSlices = append(endpointSlices, (*allEndpointSlices)[i])
}
}
endpointSlicesCache[namespace] = &endpointSlices
@ -242,9 +243,9 @@ func GetServiceByName(flags *genericclioptions.ConfigFlags, name string, service
services = &servicesArray
}
for _, svc := range *services {
if svc.Name == name {
return svc, nil
for i := range *services {
if (*services)[i].Name == name {
return (*services)[i], nil
}
}
@ -288,7 +289,6 @@ func getLabeledPods(flags *genericclioptions.ConfigFlags, label string) ([]apiv1
pods, err := api.Pods(namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: label,
})
if err != nil {
return make([]apiv1.Pod, 0), err
}
@ -303,9 +303,9 @@ func getDeploymentPods(flags *genericclioptions.ConfigFlags, deployment string)
}
ingressPods := make([]apiv1.Pod, 0)
for _, pod := range pods {
if util.PodInDeployment(pod, deployment) {
ingressPods = append(ingressPods, pod)
for i := range pods {
if util.PodInDeployment(&pods[i], deployment) {
ingressPods = append(ingressPods, pods[i])
}
}
@ -331,5 +331,4 @@ func getServices(flags *genericclioptions.ConfigFlags) ([]apiv1.Service, error)
}
return services.Items, nil
}

View file

@ -47,17 +47,25 @@ func PrintError(e error) {
}
// ParseVersionString returns the major, minor, and patch numbers of a version string
func ParseVersionString(v string) (int, int, int, error) {
func ParseVersionString(v string) (major, minor, patch int, err error) {
parts := versionRegex.FindStringSubmatch(v)
if len(parts) != 4 {
return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v)
}
major, _ := strconv.Atoi(parts[1])
minor, _ := strconv.Atoi(parts[2])
patch, _ := strconv.Atoi(parts[3])
major, err = strconv.Atoi(parts[1])
if err != nil {
return 0, 0, 0, err
}
minor, err = strconv.Atoi(parts[2])
if err != nil {
return 0, 0, 0, err
}
patch, err = strconv.Atoi(parts[3])
if err != nil {
return 0, 0, 0, err
}
return major, minor, patch, nil
}
@ -90,7 +98,7 @@ func isVersionLessThan(a, b string) bool {
// PodInDeployment returns whether a pod is part of a deployment with the given name
// a pod is considered to be in {deployment} if it is owned by a replicaset with a name of format {deployment}-otherchars
func PodInDeployment(pod apiv1.Pod, deployment string) bool {
func PodInDeployment(pod *apiv1.Pod, deployment string) bool {
for _, owner := range pod.OwnerReferences {
if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" {
continue
@ -138,7 +146,7 @@ func AddContainerFlag(cmd *cobra.Command) *string {
// GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in
func GetNamespace(flags *genericclioptions.ConfigFlags) string {
namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()
if err != nil || len(namespace) == 0 {
if err != nil || namespace == "" {
namespace = apiv1.NamespaceDefault
}
return namespace

View file

@ -411,6 +411,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -420,6 +420,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -406,6 +406,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -407,6 +407,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -410,6 +410,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -510,6 +510,10 @@ spec:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
---
apiVersion: batch/v1
kind: Job

View file

@ -411,6 +411,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -410,6 +410,10 @@ spec:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:

View file

@ -80,6 +80,12 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont
Because of api deprecations, the default manifest may not work on your cluster.
Specific manifests for supported Kubernetes versions are available within a sub-folder of each provider.
### Firewall configuration
To check which ports are used by your installation of ingress-nginx, look at the output of `kubectl -n ingress-nginx get pod -o yaml`. In general, you need:
- Port 8443 open between all hosts on which the kubernetes nodes are running. This is used for the ingress-nginx [admission controller](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/).
- Port 80 (for HTTP) and/or 443 (for HTTPS) open to the public on the kubernetes nodes to which the DNS of your apps are pointing.
### Pre-flight check
A few pods should start in the `ingress-nginx` namespace:

View file

@ -716,7 +716,7 @@ Do not try to edit it manually.
### [[Flag] watch namespace selector](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L30)
- [should ingore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
- [should ignore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
### [[Security] no-auth-locations](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/no_auth_locations.go#L33)

View file

@ -23,7 +23,7 @@ Customization | [External authentication with response header propagation](custo
Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO
Features | [Rewrite](rewrite/README.md) | TODO | TODO
Features | [Session stickiness](affinity/cookie/README.md) | route requests consistently to the same endpoint | Advanced
Features | [Canary Deployments](canary/README.md) | weigthed canary routing to a seperate deployment | Intermediate
Features | [Canary Deployments](canary/README.md) | weighted canary routing to a seperate deployment | Intermediate
Scaling | [Static IP](static-ip/README.md) | a single ingress gets a single static IP | Intermediate
TLS | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO
TLS | [TLS termination](tls-termination/README.md) | TODO | TODO

View file

@ -15,6 +15,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
| `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. |
| `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) |
| `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". |
| `--enable-annotation-validation` | If true, will enable the annotation validation feature. This value will be defaulted to true on a future release. |
| `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) |
| `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). |
| `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) |
@ -24,7 +25,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |
| `--enable-topology-aware-routing` | Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto. (default false) |
| `--enable-topology-aware-routing` | Enable topology aware routing feature, needs service object annotation service.kubernetes.io/topology-mode sets to auto. (default false) |
| `--exclude-socket-metrics` | Set of socket request metrics to exclude which won't be exported nor being calculated. The possible socket request metrics to exclude are documented in the monitoring guide e.g. 'nginx_ingress_controller_request_duration_seconds,nginx_ingress_controller_response_size'|
| `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") |
| `--health-check-timeout` | Time limit, in seconds, for a probe to health-check-path to succeed. (default 10) |

View file

@ -1,7 +1,9 @@
# Exposing TCP and UDP services
Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags `--tcp-services-configmap` and `--udp-services-configmap` to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:
`<namespace/service name>:<service port>:[PROXY]:[PROXY]`
While the Kubernetes Ingress resource only officially supports routing external HTTP(s) traffic to services, ingress-nginx can be configured to receive external TCP/UDP traffic from non-HTTP protocols and route them to internal services using TCP/UDP port mappings that are specified within a ConfigMap.
To support this, the `--tcp-services-configmap` and `--udp-services-configmap` flags can be used to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:
`<service port>:<namespace/service name>:[PROXY]:[PROXY]`
It is also possible to use a number or the name of the port. The two last fields are optional.
Adding `PROXY` in either or both of the two last fields we can use [Proxy Protocol](https://www.nginx.com/resources/admin-guide/proxy-protocol) decoding (listen) and/or encoding (proxy_pass) in a TCP service.

View file

@ -33,6 +33,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|[nginx.ingress.kubernetes.io/auth-cache-key](#external-authentication)|string|
|[nginx.ingress.kubernetes.io/auth-cache-duration](#external-authentication)|string|
|[nginx.ingress.kubernetes.io/auth-keepalive](#external-authentication)|number|
|[nginx.ingress.kubernetes.io/auth-keepalive-share-vars](#external-authentication)|"true" or "false"|
|[nginx.ingress.kubernetes.io/auth-keepalive-requests](#external-authentication)|number|
|[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number|
|[nginx.ingress.kubernetes.io/auth-proxy-set-headers](#external-authentication)|string|
@ -467,6 +468,9 @@ Additionally it is possible to set:
> Note: does not work with HTTP/2 listener because of a limitation in Lua [subrequests](https://github.com/openresty/lua-nginx-module#spdy-mode-not-fully-supported).
> [UseHTTP2](./configmap.md#use-http2) configuration should be disabled!
* `nginx.ingress.kubernetes.io/auth-keepalive-share-vars`:
Whether to share Nginx variables among the current request and the auth request. Example use case is to track requests: when set to "true" X-Request-ID HTTP header will be the same for the backend and the auth request.
Defaults to "false".
* `nginx.ingress.kubernetes.io/auth-keepalive-requests`:
`<Requests>` to specify the maximum number of requests that can be served through one keepalive connection.
Defaults to `1000` and only applied if `auth-keepalive` is set to higher than `0`.

View file

@ -29,7 +29,9 @@ The following table shows a configuration option's name, type, and the default v
|:---|:---|:------|:----|
|[add-headers](#add-headers)|string|""||
|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"||
|[allow-cross-namespace-resources](#allow-cross-namespace-resources)|bool|"true"||
|[allow-snippet-annotations](#allow-snippet-annotations)|bool|true||
|[annotations-risk-level](#annotations-risk-level)|string|Critical||
|[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""||
|[hide-headers](#hide-headers)|string array|empty||
|[access-log-params](#access-log-params)|string|""||
@ -239,6 +241,20 @@ Sets custom headers from named configmap before sending traffic to the client. S
Enables the return of the header Server from the backend instead of the generic nginx string. _**default:**_ is disabled
## allow-cross-namespace-resources
Enables users to consume cross namespace resource on annotations, when was previously enabled . _**default:**_ true
**Annotations that may be impacted with this change**:
* `auth-secret`
* `auth-proxy-set-header`
* `auth-tls-secret`
* `fastcgi-params-configmap`
* `proxy-ssl-secret`
**This option will be defaulted to false in the next major release**
## allow-snippet-annotations
Enables Ingress to parse and add *-snippet annotations/directives created by the user. _**default:**_ `true`
@ -246,6 +262,16 @@ Enables Ingress to parse and add *-snippet annotations/directives created by the
Warning: We recommend enabling this option only if you TRUST users with permission to create Ingress objects, as this
may allow a user to add restricted configurations to the final nginx.conf file
**This option will be defaulted to false in the next major release**
## annotations-risk-level
Represents the risk accepted on an annotation. If the risk is, for instance `Medium`, annotations with risk High and Critical will not be accepted.
Accepted values are `Critical`, `High`, `Medium` and `Low`.
Defaults to `Critical` but will be changed to `High` on the next minor release
## annotation-value-word-blocklist
Contains a comma-separated value of chars/words that are well known of being used to abuse Ingress configuration

38
go.mod
View file

@ -15,7 +15,7 @@ require (
github.com/moul/pb v0.0.0-20220425114252-bca18df4138c
github.com/ncabatoff/process-exporter v0.7.10
github.com/onsi/ginkgo/v2 v2.9.5
github.com/opencontainers/runc v1.1.7
github.com/opencontainers/runc v1.1.9
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang v1.16.0
github.com/prometheus/client_model v0.4.0
@ -25,19 +25,19 @@ require (
github.com/stretchr/testify v1.8.4
github.com/yudai/gojsondiff v1.0.0
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
golang.org/x/crypto v0.10.0
google.golang.org/grpc v1.56.1
golang.org/x/crypto v0.12.0
google.golang.org/grpc v1.57.0
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
gopkg.in/go-playground/pool.v3 v3.1.1
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
k8s.io/api v0.26.4
k8s.io/api v0.27.4
k8s.io/apiextensions-apiserver v0.26.4
k8s.io/apimachinery v0.26.4
k8s.io/apimachinery v0.27.4
k8s.io/apiserver v0.26.4
k8s.io/cli-runtime v0.26.4
k8s.io/client-go v0.26.4
k8s.io/client-go v0.27.4
k8s.io/code-generator v0.26.4
k8s.io/component-base v0.26.4
k8s.io/component-base v0.27.4
k8s.io/klog/v2 v2.100.1
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
sigs.k8s.io/controller-runtime v0.14.6
@ -59,9 +59,9 @@ require (
github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.0.6 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
@ -72,14 +72,14 @@ require (
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
@ -103,22 +103,22 @@ require (
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect

89
go.sum
View file

@ -103,14 +103,12 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
@ -184,8 +182,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
@ -235,10 +233,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
@ -276,7 +272,6 @@ github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 h1:t4WWQ9I797y7QU
github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag=
github.com/ncabatoff/process-exporter v0.7.10 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@ -289,8 +284,8 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@ -331,7 +326,7 @@ github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPH
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@ -347,7 +342,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.1.3/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -355,6 +352,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/urfave/cli v1.17.1-0.20160602030128-01a33823596e/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@ -390,8 +390,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -524,19 +524,19 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -647,8 +647,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -661,8 +661,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@ -683,7 +683,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@ -717,31 +716,31 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.26.4 h1:qSG2PmtcD23BkYiWfoYAcak870eF/hE7NNYBYavTT94=
k8s.io/api v0.26.4/go.mod h1:WwKEXU3R1rgCZ77AYa7DFksd9/BAIKyOmRlbVxgvjCk=
k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
k8s.io/apiextensions-apiserver v0.26.4 h1:9D2RTxYGxrG5uYg6D7QZRcykXvavBvcA59j5kTaedQI=
k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw=
k8s.io/apimachinery v0.26.4 h1:rZccKdBLg9vP6J09JD+z8Yr99Ce8gk3Lbi9TCx05Jzs=
k8s.io/apimachinery v0.26.4/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/apiserver v0.26.4 h1:3Oq4mnJv0mzVX7BR/Nod+8KjlELf/3Ljvu9ZWDyLUoA=
k8s.io/apiserver v0.26.4/go.mod h1:yAY3O1vBM4/0OIGAGeWcdfzQvgdwJ188VirLcuSAVnw=
k8s.io/cli-runtime v0.26.4 h1:MgSU871KDzBDX7V9GtuqS6Ai9lhQCHgRzkurnXOWtZ0=
k8s.io/cli-runtime v0.26.4/go.mod h1:MjJ2DXMChw2zcG0/agzm17xwKpfVxOfuoCdfY9iOCOE=
k8s.io/client-go v0.26.4 h1:/7P/IbGBuT73A+G97trf44NTPSNqvuBREpOfdLbHvD4=
k8s.io/client-go v0.26.4/go.mod h1:6qOItWm3EwxJdl/8p5t7FWtWUOwyMdA8N9ekbW4idpI=
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
k8s.io/code-generator v0.26.4 h1:zgDD0qX13p/jtrAoYRRiYeQ5ibnriwmo2cMkMZAtJxc=
k8s.io/code-generator v0.26.4/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI=
k8s.io/component-base v0.26.4 h1:Bg2xzyXNKL3eAuiTEu3XE198d6z22ENgFgGQv2GGOUk=
k8s.io/component-base v0.26.4/go.mod h1:lTuWL1Xz/a4e80gmIC3YZG2JCO4xNwtKWHJWeJmsq20=
k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c=
k8s.io/component-base v0.27.4/go.mod h1:hoiEETnLc0ioLv6WPeDt8vD34DDeB35MfQnxCARq3kY=
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
@ -749,8 +748,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=

View file

@ -1,5 +1,9 @@
# AWS NLB with TLS termination
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,5 +1,9 @@
# AWS - NLB
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,5 +1,9 @@
# Baremetal
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: NodePort

View file

@ -1,4 +1,8 @@
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,5 +1,9 @@
# Digital Ocean
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,6 +1,10 @@
# Exoscale
controller:
kind: DaemonSet
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,4 +1,8 @@
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -1,5 +1,9 @@
# Scaleway
controller:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local

View file

@ -23,8 +23,6 @@ TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA)
REGISTRY ?= local
IMAGE = $(REGISTRY)/e2e-test-cfssl
# required to enable buildx

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/cfssl && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM alpine:3.18.0
FROM alpine:3.18.2
RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/custom-error-pages && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -32,6 +32,7 @@ FROM gcr.io/distroless/static:nonroot
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/nginx-errors /
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/www /www
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/etc /etc
USER nonroot:nonroot
CMD ["/nginx-errors"]

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/echo && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -18,7 +18,9 @@ SHELL=/bin/bash -o pipefail -o errexit
DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh
TAG ?=v1.0.0
SHORT_SHA ?=$(shell git rev-parse --short HEAD)
TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA)
REGISTRY ?= local
IMAGE = $(REGISTRY)/ext-auth-example-authsvc

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/ext-auth-example-authsvc && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -17,6 +15,4 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/fastcgi-helloserver && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -16,13 +16,13 @@ func hello(w http.ResponseWriter, r *http.Request) {
}
key := keys[0]
fmt.Fprintf(w, "Hello "+string(key)+"!")
fmt.Fprintf(w, "Hello "+key+"!")
}
func main() {
http.HandleFunc("/hello", hello)
l, err := net.Listen("tcp", "0.0.0.0:9000")
l, err := net.Listen("tcp", "0.0.0.0:9000") //nolint:gosec // Ignore the gosec error since it's a hello server
if err != nil {
panic(err)
}

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/go-grpc-greeter-server && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -41,7 +41,7 @@ type hwServer struct {
}
// SayHello implements helloworld.GreeterServer
func (s *hwServer) SayHello(ctx context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
func (s *hwServer) SayHello(_ context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil
}
@ -49,7 +49,7 @@ type ecServer struct {
ecpb.UnimplementedEchoServer
}
func (s *ecServer) UnaryEcho(ctx context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
func (s *ecServer) UnaryEcho(_ context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
return &ecpb.EchoResponse{Message: req.Message}, nil
}

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/httpbun && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "master"

View file

@ -21,8 +21,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -32,6 +30,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/kube-webhook-certgen && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "main"

View file

@ -11,7 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM alpine:3.18.0 as builder
FROM alpine:3.18.2 as builder
COPY . /
@ -21,7 +21,7 @@ RUN apk update \
&& /build.sh
# Use a multi-stage build
FROM alpine:3.18.0
FROM alpine:3.18.2
ENV PATH=$PATH:/usr/local/luajit/bin:/usr/local/nginx/sbin:/usr/local/nginx/bin

View file

@ -20,14 +20,14 @@ set -o pipefail
export NGINX_VERSION=1.21.6
# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.1...master
export NDK_VERSION=0.3.1
# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.2...master
export NDK_VERSION=0.3.2
# Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master
export SETMISC_VERSION=0.33
# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.33...master
export MORE_HEADERS_VERSION=0.33
# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.34...master
export MORE_HEADERS_VERSION=0.34
# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master
export NGINX_DIGEST_AUTH=1.0.0
@ -65,32 +65,32 @@ export MODSECURITY_LIB_VERSION=e9a7ba4a60be48f761e0328c6dfcc668d70e35a0
# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master
export OWASP_MODSECURITY_CRS_VERSION=v3.3.4
# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.21...master
export LUA_NGX_VERSION=0.10.21
# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.25...master
export LUA_NGX_VERSION=0.10.25
# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.11...master
export LUA_STREAM_NGX_VERSION=0.0.11
# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.13...master
export LUA_STREAM_NGX_VERSION=0.0.13
# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master
export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf
# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.10...openresty:master
export LUA_CJSON_VERSION=2.1.0.10
# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.11...openresty:master
export LUA_CJSON_VERSION=2.1.0.11
# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.3...master
export GEOIP2_VERSION=a26c6beed77e81553686852dceb6c7fdacc5970d
# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20220411...v2.1-agentzh
export LUAJIT_VERSION=2.1-20220411
# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20230410...v2.1-agentzh
export LUAJIT_VERSION=2.1-20230410
# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master
export LUA_RESTY_BALANCER=0.04
# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.11...master
export LUA_RESTY_CACHE=0.11
# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.13...master
export LUA_RESTY_CACHE=0.13
# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.23...master
export LUA_RESTY_CORE=0.1.23
# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.27...master
export LUA_RESTY_CORE=0.1.27
# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/v0.1.0...master
export LUA_RESTY_COOKIE_VERSION=303e32e512defced053a6484bc0745cf9dc0d39e
@ -101,17 +101,17 @@ export LUA_RESTY_DNS=0.22
# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.16.1...master
export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8
# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.08...master
export LUA_RESTY_LOCK=0.08
# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.09...master
export LUA_RESTY_LOCK=0.09
# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.10...master
export LUA_RESTY_UPLOAD_VERSION=0.10
# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.11...master
export LUA_RESTY_UPLOAD_VERSION=0.11
# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master
export LUA_RESTY_STRING_VERSION=0.15
# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.16...master
export LUA_RESTY_MEMCACHED_VERSION=0.16
# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.17...master
export LUA_RESTY_MEMCACHED_VERSION=0.17
# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master
export LUA_RESTY_REDIS_VERSION=0.30
@ -199,13 +199,13 @@ cd "$BUILD_PATH"
get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \
"https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz"
get_src 0e971105e210d272a497567fa2e2c256f4e39b845a5ba80d373e26ba1abfbd85 \
"https://github.com/simpl/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"
get_src aa961eafb8317e0eb8da37eb6e2c9ff42267edd18b56947384e719b85188f58b \
"https://github.com/vision5/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"
get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \
"https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz"
get_src a3dcbab117a9c103bc1ea5200fc00a7b7d2af97ff7fd525f16f8ac2632e30fbf \
get_src 0c0d2ced2ce895b3f45eb2b230cd90508ab2a773299f153de14a43e44c1209b3 \
"https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz"
get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \
@ -241,10 +241,10 @@ get_src 7d5f3439c8df56046d0564b5857fd8a30296ab1bd6df0f048aed7afb56a0a4c2 \
get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
else
get_src 9db756000578efaecb43bea4fc6cf631aaa80988d86ffe5d3afeb9927895ffad \
get_src bc764db42830aeaf74755754b900253c233ad57498debe7a441cee2c6f4b07c2 \
"https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz"
get_src c7924f28cb014a99636e747ea907724dd55f60e180cb92cde6e8ed48d2278f27 \
get_src 01b715754a8248cc7228e0c8f97f7488ae429d90208de0481394e35d24cef32f \
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
fi
@ -256,7 +256,7 @@ if [[ ${ARCH} == "s390x" ]]; then
get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \
"https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz"
else
get_src d3f2c870f8f88477b01726b32accab30f6e5d57ae59c5ec87374ff73d0794316 \
get_src 77bbcbb24c3c78f51560017288f3118d995fe71240aa379f5818ff6b166712ff \
"https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz"
fi
@ -266,7 +266,7 @@ get_src 8d39c6b23f941a2d11571daaccc04e69539a3fcbcc50a631837560d5861a7b96 \
get_src 4c1933434572226942c65b2f2b26c8a536ab76aa771a3c7f6c2629faa764976b \
"https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz"
get_src 5d16e623d17d4f42cc64ea9cfb69ca960d313e12f5d828f785dd227cc483fcbd \
get_src deb4ab1ffb9f3d962c4b4a2c4bdff692b86a209e3835ae71ebdf3b97189e40a9 \
"https://github.com/openresty/lua-resty-upload/archive/v$LUA_RESTY_UPLOAD_VERSION.tar.gz"
get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \
@ -279,20 +279,20 @@ if [[ ${ARCH} == "s390x" ]]; then
get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
else
get_src efd6b51520429e64b1bcc10f477d370ebed1631c190f7e4dc270d959a743ad7d \
get_src 39baab9e2b31cc48cecf896cea40ef6e80559054fd8a6e440cc804a858ea84d4 \
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
fi
get_src 0c551d6898f89f876e48730f9b55790d0ba07d5bc0aa6c76153277f63c19489f \
get_src a77b9de160d81712f2f442e1de8b78a5a7ef0d08f13430ff619f79235db974d4 \
"https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz"
get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \
"https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz"
get_src e810ed124fe788b8e4aac2c8960dda1b9a6f8d0ca94ce162f28d3f4d877df8af \
get_src 573184006b98ccee2594b0d134fa4d05e5d2afd5141cbad315051ccf7e9b6403 \
"https://github.com/openresty/lua-resty-lrucache/archive/v$LUA_RESTY_CACHE.tar.gz"
get_src 2b4683f9abe73e18ca00345c65010c9056777970907a311d6e1699f753141de2 \
get_src b4ddcd47db347e9adf5c1e1491a6279a6ae2a3aff3155ef77ea0a65c998a69c1 \
"https://github.com/openresty/lua-resty-lock/archive/v$LUA_RESTY_LOCK.tar.gz"
get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
@ -301,7 +301,7 @@ get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \
"https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz"
get_src 42893da0e3de4ec180c9bf02f82608d78787290a70c5644b538f29d243147396 \
get_src 02733575c4aed15f6cab662378e4b071c0a4a4d07940c4ef19a7319e9be943d4 \
"https://github.com/openresty/lua-resty-memcached/archive/v$LUA_RESTY_MEMCACHED_VERSION.tar.gz"
get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash
env:
- DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
# set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- |
gcloud auth configure-docker \
&& cd images/opentelemetry && make push
substitutions:
_GIT_TAG: "12345"
_PULL_BASE_REF: "main"

View file

@ -13,7 +13,7 @@
# limitations under the License.
FROM alpine:3.18.0 as base
FROM alpine:3.18.2 as base
RUN mkdir -p /opt/third_party/install
COPY . /opt/third_party/

View file

@ -43,7 +43,7 @@ image:
--pull \
--push \
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
--build-arg GOLANG_VERSION=1.20.5 \
--build-arg GOLANG_VERSION=1.20.6 \
--build-arg ETCD_VERSION=3.4.3-0 \
--build-arg K8S_RELEASE=v1.26.0 \
--build-arg RESTY_CLI_VERSION=0.27 \
@ -64,7 +64,7 @@ build: ensure-buildx
--progress=${PROGRESS} \
--pull \
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
--build-arg GOLANG_VERSION=1.20.5 \
--build-arg GOLANG_VERSION=1.20.6 \
--build-arg ETCD_VERSION=3.4.3-0 \
--build-arg K8S_RELEASE=v1.26.0 \
--build-arg RESTY_CLI_VERSION=0.27 \

View file

@ -42,19 +42,16 @@ type IngressAdmission struct {
Checker Checker
}
var (
ingressResource = metav1.GroupVersionKind{
var ingressResource = metav1.GroupVersionKind{
Group: networking.GroupName,
Version: "v1",
Kind: "Ingress",
}
)
// HandleAdmission populates the admission Response
// with Allowed=false if the Object is an ingress that would prevent nginx to reload the configuration
// with Allowed=true otherwise
func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {
review, isV1 := obj.(*admissionv1.AdmissionReview)
if !isV1 {
return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")

View file

@ -33,12 +33,12 @@ type failTestChecker struct {
t *testing.T
}
func (ftc failTestChecker) CheckIngress(ing *networking.Ingress) error {
func (ftc failTestChecker) CheckIngress(_ *networking.Ingress) error {
ftc.t.Error("checker should not be called")
return nil
}
func (ftc failTestChecker) CheckWarning(ing *networking.Ingress) ([]string, error) {
func (ftc failTestChecker) CheckWarning(_ *networking.Ingress) ([]string, error) {
ftc.t.Error("checker should not be called")
return nil, nil
}

View file

@ -26,9 +26,7 @@ import (
"k8s.io/klog/v2"
)
var (
scheme = runtime.NewScheme()
)
var scheme = runtime.NewScheme()
func init() {
if err := admissionv1.AddToScheme(scheme); err != nil {

View file

@ -27,19 +27,44 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
serverAliasAnnotation = "server-alias"
)
var aliasAnnotation = parser.Annotation{
Group: "alias",
Annotations: parser.AnnotationFields{
serverAliasAnnotation: {
Validator: parser.ValidateArrayOfServerName,
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskHigh, // High as this allows regex chars
Documentation: `this annotation can be used to define additional server
aliases for this Ingress`,
},
},
}
type alias struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new Alias annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return alias{r}
return alias{
r: r,
annotationConfig: aliasAnnotation,
}
}
func (a alias) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
// Parse parses the annotations contained in the ingress rule
// used to add an alias to the provided hosts
func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
val, err := parser.GetStringAnnotation("server-alias", ing)
val, err := parser.GetStringAnnotation(serverAliasAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
return []string{}, err
}
@ -47,7 +72,7 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
aliases := sets.NewString()
for _, alias := range strings.Split(val, ",") {
alias = strings.TrimSpace(alias)
if len(alias) == 0 {
if alias == "" {
continue
}
@ -61,3 +86,8 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
return l, nil
}
func (a alias) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, aliasAnnotation.Annotations)
}

View file

@ -27,7 +27,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
var annotation = parser.GetAnnotationWithPrefix("server-alias")
var annotation = parser.GetAnnotationWithPrefix(serverAliasAnnotation)
func TestParse(t *testing.T) {
ap := NewParser(&resolver.Mock{})
@ -38,14 +38,18 @@ func TestParse(t *testing.T) {
testCases := []struct {
annotations map[string]string
expected []string
skipValidation bool
wantErr bool
}{
{map[string]string{annotation: "a.com, b.com, , c.com"}, []string{"a.com", "b.com", "c.com"}},
{map[string]string{annotation: "www.example.com"}, []string{"www.example.com"}},
{map[string]string{annotation: "*.example.com,www.example.*"}, []string{"*.example.com", "www.example.*"}},
{map[string]string{annotation: `~^www\d+\.example\.com$`}, []string{`~^www\d+\.example\.com$`}},
{map[string]string{annotation: ""}, []string{}},
{map[string]string{}, []string{}},
{nil, []string{}},
{map[string]string{annotation: "a.com, b.com, , c.com"}, []string{"a.com", "b.com", "c.com"}, false, false},
{map[string]string{annotation: "www.example.com"}, []string{"www.example.com"}, false, false},
{map[string]string{annotation: "*.example.com,www.example.*"}, []string{"*.example.com", "www.example.*"}, false, false},
{map[string]string{annotation: `~^www\d+\.example\.com$`}, []string{`~^www\d+\.example\.com$`}, false, false},
{map[string]string{annotation: `www.xpto;lala`}, []string{}, false, true},
{map[string]string{annotation: `www.xpto;lala`}, []string{"www.xpto;lala"}, true, false}, // When we skip validation no error should happen
{map[string]string{annotation: ""}, []string{}, false, true},
{map[string]string{}, []string{}, false, true},
{nil, []string{}, false, true},
}
ing := &networking.Ingress{
@ -58,7 +62,16 @@ func TestParse(t *testing.T) {
for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations)
result, _ := ap.Parse(ing)
if testCase.skipValidation {
parser.EnableAnnotationValidation = false
}
t.Cleanup(func() {
parser.EnableAnnotationValidation = true
})
result, err := ap.Parse(ing)
if (err != nil) != testCase.wantErr {
t.Errorf("ParseAliasAnnotation() annotation: %s, error = %v, wantErr %v", testCase.annotations, err, testCase.wantErr)
}
if !reflect.DeepEqual(result, testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
}

View file

@ -44,8 +44,8 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi"
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipallowlist"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
@ -86,7 +86,6 @@ type Ingress struct {
CorsConfig cors.Config
CustomHTTPErrors []int
DefaultBackend *apiv1.Service
//TODO: Change this back into an error when https://github.com/imdario/mergo/issues/100 is resolved
FastCGI fastcgi.Config
Denied *string
ExternalAuth authreq.Config
@ -109,7 +108,6 @@ type Ingress struct {
UpstreamHashBy upstreamhashby.Config
LoadBalancing string
UpstreamVhost string
Whitelist ipwhitelist.SourceRange
Denylist ipdenylist.SourceRange
XForwardedPrefix string
SSLCipher sslcipher.Config
@ -117,6 +115,7 @@ type Ingress struct {
ModSecurity modsecurity.Config
Mirror mirror.Config
StreamSnippet string
Allowlist ipallowlist.SourceRange
}
// Extractor defines the annotation parsers to be used in the extraction of annotations
@ -159,7 +158,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"UpstreamHashBy": upstreamhashby.NewParser(cfg),
"LoadBalancing": loadbalancing.NewParser(cfg),
"UpstreamVhost": upstreamvhost.NewParser(cfg),
"Whitelist": ipwhitelist.NewParser(cfg),
"Allowlist": ipallowlist.NewParser(cfg),
"Denylist": ipdenylist.NewParser(cfg),
"XForwardedPrefix": xforwardedprefix.NewParser(cfg),
"SSLCipher": sslcipher.NewParser(cfg),
@ -173,16 +172,23 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
}
// Extract extracts the annotations from an Ingress
func (e Extractor) Extract(ing *networking.Ingress) *Ingress {
func (e Extractor) Extract(ing *networking.Ingress) (*Ingress, error) {
pia := &Ingress{
ObjectMeta: ing.ObjectMeta,
}
data := make(map[string]interface{})
for name, annotationParser := range e.annotations {
if err := annotationParser.Validate(ing.GetAnnotations()); err != nil {
return nil, errors.NewRiskyAnnotations(name)
}
val, err := annotationParser.Parse(ing)
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
if err != nil {
if errors.IsValidationError(err) {
klog.ErrorS(err, "ingress contains invalid annotation value")
return nil, err
}
if errors.IsMissingAnnotations(err) {
continue
}
@ -220,5 +226,5 @@ func (e Extractor) Extract(ing *networking.Ingress) *Ingress {
klog.ErrorS(err, "unexpected error merging extracted annotations")
}
return pia
return pia, nil
}

View file

@ -64,7 +64,11 @@ func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
}
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
if secret, _ := m.GetSecret(name); secret != nil {
secret, err := m.GetSecret(name)
if err != nil {
return nil, err
}
if secret != nil {
return &resolver.AuthSSLCert{
Secret: name,
CAFileName: "/opt/ca.pem",
@ -134,8 +138,11 @@ func TestSSLPassthrough(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SSLPassthrough
if r != foo.er {
r, err := ec.Extract(ing)
if err != nil {
t.Errorf("Errors should be null: %v", err)
}
if r.SSLPassthrough != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
@ -158,8 +165,11 @@ func TestUpstreamHashBy(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).UpstreamHashBy.UpstreamHashBy
if r != foo.er {
r, err := ec.Extract(ing)
if err != nil {
t.Errorf("error should be null: %v", err)
}
if r.UpstreamHashBy.UpstreamHashBy != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
@ -185,7 +195,11 @@ func TestAffinitySession(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SessionAffinity
rann, err := ec.Extract(ing)
if err != nil {
t.Errorf("error should be null: %v", err)
}
r := rann.SessionAffinity
t.Logf("Testing pass %v %v", foo.affinitytype, foo.cookiename)
if r.Type != foo.affinitytype {
@ -228,7 +242,11 @@ func TestCors(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).CorsConfig
rann, err := ec.Extract(ing)
if err != nil {
t.Errorf("error should be null: %v", err)
}
r := rann.CorsConfig
t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials)
if r.CorsEnabled != foo.corsenabled {
@ -256,9 +274,9 @@ func TestCors(t *testing.T) {
if r.CorsAllowCredentials != foo.credentials {
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
}
}
}
}
}
func TestCustomHTTPErrors(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
@ -277,7 +295,11 @@ func TestCustomHTTPErrors(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).CustomHTTPErrors
rann, err := ec.Extract(ing)
if err != nil {
t.Errorf("error should be null: %v", err)
}
r := rann.CustomHTTPErrors
// Check that expected codes were created
for i := range foo.er {

View file

@ -32,13 +32,56 @@ import (
"k8s.io/ingress-nginx/pkg/util/file"
)
const (
authSecretTypeAnnotation = "auth-secret-type" //#nosec G101
authRealmAnnotation = "auth-realm"
authTypeAnnotation = "auth-type"
// This should be exported as it is imported by other packages
AuthSecretAnnotation = "auth-secret" //#nosec G101
)
var (
authTypeRegex = regexp.MustCompile(`basic|digest`)
authSecretTypeRegex = regexp.MustCompile(`auth-file|auth-map`)
// AuthDirectory default directory used to store files
// to authenticate request
AuthDirectory = "/etc/ingress-controller/auth"
)
var AuthSecretConfig = parser.AnnotationConfig{
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
Documentation: `This annotation defines the name of the Secret that contains the usernames and passwords which are granted access to the paths defined in the Ingress rules. `,
}
var authSecretAnnotations = parser.Annotation{
Group: "authentication",
Annotations: parser.AnnotationFields{
AuthSecretAnnotation: AuthSecretConfig,
authSecretTypeAnnotation: {
Validator: parser.ValidateRegex(authSecretTypeRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation what is the format of auth-secret value. Can be "auth-file" that defines the content of an htpasswd file, or "auth-map" where each key
is a user and each value is the password.`,
},
authRealmAnnotation: {
Validator: parser.ValidateRegex(parser.CharsWithSpace, false),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
Documentation: `This annotation defines the realm (message) that should be shown to user when authentication is requested.`,
},
authTypeAnnotation: {
Validator: parser.ValidateRegex(authTypeRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation defines the basic authentication type. Should be "basic" or "digest"`,
},
},
}
const (
fileAuth = "auth-file"
mapAuth = "auth-map"
@ -87,11 +130,16 @@ func (bd1 *Config) Equal(bd2 *Config) bool {
type auth struct {
r resolver.Resolver
authDirectory string
annotationConfig parser.Annotation
}
// NewParser creates a new authentication annotation parser
func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotation {
return auth{r, authDirectory}
return auth{
r: r,
authDirectory: authDirectory,
annotationConfig: authSecretAnnotations,
}
}
// Parse parses the annotations contained in the ingress
@ -99,7 +147,7 @@ func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotati
// and generated an htpasswd compatible file to be used as source
// during the authentication process
func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
at, err := parser.GetStringAnnotation("auth-type", ing)
at, err := parser.GetStringAnnotation(authTypeAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
return nil, err
}
@ -109,21 +157,24 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
}
var secretType string
secretType, err = parser.GetStringAnnotation("auth-secret-type", ing)
secretType, err = parser.GetStringAnnotation(authSecretTypeAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
return nil, err
}
secretType = fileAuth
}
s, err := parser.GetStringAnnotation("auth-secret", ing)
s, err := parser.GetStringAnnotation(AuthSecretAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
return nil, ing_errors.LocationDenied{
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
}
}
sns, sname, err := cache.SplitMetaNamespaceKey(s)
if err != nil {
return nil, ing_errors.LocationDenied{
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
}
}
@ -131,16 +182,26 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
if sns == "" {
sns = ing.Namespace
}
secCfg := a.r.GetSecurityConfiguration()
// We don't accept different namespaces for secrets.
if !secCfg.AllowCrossNamespaceResources && sns != ing.Namespace {
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
}
}
name := fmt.Sprintf("%v/%v", sns, sname)
secret, err := a.r.GetSecret(name)
if err != nil {
return nil, ing_errors.LocationDenied{
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error reading secret %s: %w", name, err),
}
}
realm, _ := parser.GetStringAnnotation("auth-realm", ing)
realm, err := parser.GetStringAnnotation(authRealmAnnotation, ing, a.annotationConfig.Annotations)
if ing_errors.IsValidationError(err) {
return nil, err
}
passFilename := fmt.Sprintf("%v/%v-%v-%v.passwd", a.authDirectory, ing.GetNamespace(), ing.UID, secret.UID)
@ -156,7 +217,7 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
return nil, err
}
default:
return nil, ing_errors.LocationDenied{
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("invalid auth-secret-type in annotation, must be 'auth-file' or 'auth-map': %w", err),
}
}
@ -177,14 +238,14 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
func dumpSecretAuthFile(filename string, secret *api.Secret) error {
val, ok := secret.Data["auth"]
if !ok {
return ing_errors.LocationDenied{
return ing_errors.LocationDeniedError{
Reason: fmt.Errorf("the secret %s does not contain a key with value auth", secret.Name),
}
}
err := os.WriteFile(filename, val, file.ReadWriteByUser)
if err != nil {
return ing_errors.LocationDenied{
return ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
}
}
@ -203,10 +264,19 @@ func dumpSecretAuthMap(filename string, secret *api.Secret) error {
err := os.WriteFile(filename, []byte(builder.String()), file.ReadWriteByUser)
if err != nil {
return ing_errors.LocationDenied{
return ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
}
}
return nil
}
func (a auth) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
func (a auth) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, authSecretAnnotations.Annotations)
}

View file

@ -26,11 +26,21 @@ import (
api "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
//nolint:gosec // Ignore hardcoded credentials error in testing
const (
authType = "basic"
authRealm = "-realm-"
defaultDemoSecret = "default/demo-secret"
othernsDemoSecret = "otherns/demo-secret"
demoSecret = "demo-secret"
)
func buildIngress() *networking.Ingress {
defaultBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
@ -79,14 +89,19 @@ type mockSecret struct {
}
func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
if name != "default/demo-secret" {
if name != defaultDemoSecret && name != othernsDemoSecret {
return nil, fmt.Errorf("there is no secret with name %v", name)
}
ns, _, err := cache.SplitMetaNamespaceKey(name)
if err != nil {
return nil, err
}
return &api.Secret{
ObjectMeta: meta_v1.ObjectMeta{
Namespace: api.NamespaceDefault,
Name: "demo-secret",
Namespace: ns,
Name: demoSecret,
},
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
}, nil
@ -106,13 +121,91 @@ func TestIngressAuthBadAuthType(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "invalid"
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "invalid"
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
expected := ing_errors.NewLocationDenied("invalid authentication type")
expected := ing_errors.NewValidationError("nginx.ingress.kubernetes.io/auth-type")
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
if err.Error() != expected.Error() {
t.Errorf("expected '%v' but got '%v'", expected, err)
}
}
func TestIngressInvalidRealm(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "something weird ; location trying to { break }"
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
expected := ing_errors.NewValidationError("nginx.ingress.kubernetes.io/auth-realm")
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
if err.Error() != expected.Error() {
t.Errorf("expected '%v' but got '%v'", expected, err)
}
}
func TestIngressInvalidDifferentNamespace(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
expected := ing_errors.LocationDeniedError{
Reason: errors.New("cross namespace usage of secrets is not allowed"),
}
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
if err.Error() != expected.Error() {
t.Errorf("expected '%v' but got '%v'", expected, err)
}
}
func TestIngressInvalidDifferentNamespaceAllowed(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
r := mockSecret{}
r.AllowCrossNamespace = true
_, err := NewParser(dir, r).Parse(ing)
if err != nil {
t.Errorf("not expecting an error")
}
}
func TestIngressInvalidSecretName(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "demo-secret;xpto"
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
expected := ing_errors.LocationDeniedError{
Reason: errors.New("error reading secret name from annotation: annotation nginx.ingress.kubernetes.io/auth-secret contains invalid value"),
}
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
if err.Error() != expected.Error() {
t.Errorf("expected '%v' but got '%v'", expected, err)
@ -123,13 +216,13 @@ func TestInvalidIngressAuthNoSecret(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir)
expected := ing_errors.LocationDenied{
expected := ing_errors.LocationDeniedError{
Reason: errors.New("error reading secret name from annotation: ingress rule without annotations"),
}
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
@ -142,9 +235,9 @@ func TestIngressAuth(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret"
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
@ -158,10 +251,10 @@ func TestIngressAuth(t *testing.T) {
if !ok {
t.Errorf("expected a BasicDigest type")
}
if auth.Type != "basic" {
if auth.Type != authType {
t.Errorf("Expected basic as auth type but returned %s", auth.Type)
}
if auth.Realm != "-realm-" {
if auth.Realm != authRealm {
t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
}
if !auth.Secured {
@ -173,9 +266,9 @@ func TestIngressAuthWithoutSecret(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
data[parser.GetAnnotationWithPrefix("auth-secret")] = "invalid-secret"
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "invalid-secret"
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
@ -191,10 +284,10 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret"
data[parser.GetAnnotationWithPrefix("auth-secret-type")] = "invalid-type"
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
data[parser.GetAnnotationWithPrefix(authSecretTypeAnnotation)] = "invalid-type"
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t)
@ -206,7 +299,7 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
}
}
func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
func dummySecretContent(t *testing.T) (fileName, dir string, s *api.Secret) {
dir, err := os.MkdirTemp("", fmt.Sprintf("%v", time.Now().Unix()))
if err != nil {
t.Error(err)
@ -217,7 +310,10 @@ func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
t.Error(err)
}
defer tmpfile.Close()
s, _ := mockSecret{}.GetSecret("default/demo-secret")
s, err = mockSecret{}.GetSecret(defaultDemoSecret)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
return tmpfile.Name(), dir, s
}

View file

@ -24,6 +24,7 @@ import (
"k8s.io/klog/v2"
networking "k8s.io/api/networking/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
@ -31,6 +32,125 @@ import (
"k8s.io/ingress-nginx/pkg/util/sets"
)
const (
authReqURLAnnotation = "auth-url"
authReqMethodAnnotation = "auth-method"
authReqSigninAnnotation = "auth-signin"
authReqSigninRedirParamAnnotation = "auth-signin-redirect-param"
authReqSnippetAnnotation = "auth-snippet"
authReqCacheKeyAnnotation = "auth-cache-key"
authReqKeepaliveAnnotation = "auth-keepalive"
authReqKeepaliveShareVarsAnnotation = "auth-keepalive-share-vars"
authReqKeepaliveRequestsAnnotation = "auth-keepalive-requests"
authReqKeepaliveTimeout = "auth-keepalive-timeout"
authReqCacheDuration = "auth-cache-duration"
authReqResponseHeadersAnnotation = "auth-response-headers"
authReqProxySetHeadersAnnotation = "auth-proxy-set-headers"
authReqRequestRedirectAnnotation = "auth-request-redirect"
authReqAlwaysSetCookieAnnotation = "auth-always-set-cookie"
// This should be exported as it is imported by other packages
AuthSecretAnnotation = "auth-secret"
)
var authReqAnnotations = parser.Annotation{
Group: "authentication",
Annotations: parser.AnnotationFields{
authReqURLAnnotation: {
Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskHigh,
Documentation: `This annotation allows to indicate the URL where the HTTP request should be sent`,
},
authReqMethodAnnotation: {
Validator: parser.ValidateRegex(methodsRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation allows to specify the HTTP method to use`,
},
authReqSigninAnnotation: {
Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskHigh,
Documentation: `This annotation allows to specify the location of the error page`,
},
authReqSigninRedirParamAnnotation: {
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation allows to specify the URL parameter in the error page which should contain the original URL for a failed signin request`,
},
authReqSnippetAnnotation: {
Validator: parser.ValidateNull,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskCritical,
Documentation: `This annotation allows to specify a custom snippet to use with external authentication`,
},
authReqCacheKeyAnnotation: {
Validator: parser.ValidateRegex(parser.NGINXVariable, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation enables caching for auth requests.`,
},
authReqKeepaliveAnnotation: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation specifies the maximum number of keepalive connections to auth-url. Only takes effect when no variables are used in the host part of the URL`,
},
authReqKeepaliveShareVarsAnnotation: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation specifies whether to share Nginx variables among the current request and the auth request`,
},
authReqKeepaliveRequestsAnnotation: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation defines the maximum number of requests that can be served through one keepalive connection`,
},
authReqKeepaliveTimeout: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation specifies a duration in seconds which an idle keepalive connection to an upstream server will stay open`,
},
authReqCacheDuration: {
Validator: parser.ValidateRegex(parser.ExtendedCharsRegex, false),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation allows to specify a caching time for auth responses based on their response codes, e.g. 200 202 30m`,
},
authReqResponseHeadersAnnotation: {
Validator: parser.ValidateRegex(parser.HeadersVariable, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation sets the headers to pass to backend once authentication request completes. They should be separated by comma.`,
},
authReqProxySetHeadersAnnotation: {
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation sets the name of a ConfigMap that specifies headers to pass to the authentication service.
Only ConfigMaps on the same namespace are allowed`,
},
authReqRequestRedirectAnnotation: {
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation allows to specify the X-Auth-Request-Redirect header value`,
},
authReqAlwaysSetCookieAnnotation: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation enables setting a cookie returned by auth request.
By default, the cookie will be set only if an upstream reports with the code 200, 201, 204, 206, 301, 302, 303, 304, 307, or 308`,
},
},
}
// Config returns external authentication configuration for an Ingress rule
type Config struct {
URL string `json:"url"`
@ -45,6 +165,7 @@ type Config struct {
AuthCacheKey string `json:"authCacheKey"`
AuthCacheDuration []string `json:"authCacheDuration"`
KeepaliveConnections int `json:"keepaliveConnections"`
KeepaliveShareVars bool `json:"keepaliveShareVars"`
KeepaliveRequests int `json:"keepaliveRequests"`
KeepaliveTimeout int `json:"keepaliveTimeout"`
ProxySetHeaders map[string]string `json:"proxySetHeaders,omitempty"`
@ -57,6 +178,7 @@ const DefaultCacheDuration = "200 202 401 5m"
// fallback values when no keepalive parameters are set
const (
defaultKeepaliveConnections = 0
defaultKeepaliveShareVars = false
defaultKeepaliveRequests = 1000
defaultKeepaliveTimeout = 60
)
@ -105,6 +227,10 @@ func (e1 *Config) Equal(e2 *Config) bool {
return false
}
if e1.KeepaliveShareVars != e2.KeepaliveShareVars {
return false
}
if e1.KeepaliveRequests != e2.KeepaliveRequests {
return false
}
@ -121,24 +247,15 @@ func (e1 *Config) Equal(e2 *Config) bool {
}
var (
methods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "CONNECT", "OPTIONS", "TRACE"}
methodsRegex = regexp.MustCompile("(GET|HEAD|POST|PUT|PATCH|DELETE|CONNECT|OPTIONS|TRACE)")
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
statusCodeRegex = regexp.MustCompile(`^[\d]{3}$`)
durationRegex = regexp.MustCompile(`^[\d]+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
statusCodeRegex = regexp.MustCompile(`^\d{3}$`)
durationRegex = regexp.MustCompile(`^\d+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
)
// ValidMethod checks is the provided string a valid HTTP method
func ValidMethod(method string) bool {
if len(method) == 0 {
return false
}
for _, m := range methods {
if method == m {
return true
}
}
return false
return methodsRegex.MatchString(method)
}
// ValidHeader checks is the provided string satisfies the header's name regex
@ -156,7 +273,7 @@ func ValidCacheDuration(duration string) bool {
seenDuration := false
for _, element := range elements {
if len(element) == 0 {
if element == "" {
continue
}
if statusCodeRegex.MatchString(element) {
@ -174,54 +291,71 @@ func ValidCacheDuration(duration string) bool {
type authReq struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new authentication request annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authReq{r}
return authReq{
r: r,
annotationConfig: authReqAnnotations,
}
}
// ParseAnnotations parses the annotations contained in the ingress
// rule used to use an Config URL as source for authentication
//
//nolint:gocyclo // Ignore function complexity error
func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
// Required Parameters
urlString, err := parser.GetStringAnnotation("auth-url", ing)
urlString, err := parser.GetStringAnnotation(authReqURLAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
return nil, err
}
authURL, err := parser.StringToURL(urlString)
if err != nil {
return nil, ing_errors.LocationDenied{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
return nil, ing_errors.LocationDeniedError{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
}
authMethod, _ := parser.GetStringAnnotation("auth-method", ing)
if len(authMethod) != 0 && !ValidMethod(authMethod) {
authMethod, err := parser.GetStringAnnotation(authReqMethodAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
return nil, ing_errors.NewLocationDenied("invalid HTTP method")
}
}
// Optional Parameters
signIn, err := parser.GetStringAnnotation("auth-signin", ing)
signIn, err := parser.GetStringAnnotation(authReqSigninAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
klog.Warningf("%s value is invalid: %s", authReqSigninAnnotation, err)
}
klog.V(3).InfoS("auth-signin annotation is undefined and will not be set")
}
signInRedirectParam, err := parser.GetStringAnnotation("auth-signin-redirect-param", ing)
signInRedirectParam, err := parser.GetStringAnnotation(authReqSigninRedirParamAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
klog.Warningf("%s value is invalid: %s", authReqSigninRedirParamAnnotation, err)
}
klog.V(3).Infof("auth-signin-redirect-param annotation is undefined and will not be set")
}
authSnippet, err := parser.GetStringAnnotation("auth-snippet", ing)
authSnippet, err := parser.GetStringAnnotation(authReqSnippetAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-snippet annotation is undefined and will not be set")
}
authCacheKey, err := parser.GetStringAnnotation("auth-cache-key", ing)
authCacheKey, err := parser.GetStringAnnotation(authReqCacheKeyAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
klog.Warningf("%s value is invalid: %s", authReqCacheKeyAnnotation, err)
}
klog.V(3).InfoS("auth-cache-key annotation is undefined and will not be set")
}
keepaliveConnections, err := parser.GetIntAnnotation("auth-keepalive", ing)
keepaliveConnections, err := parser.GetIntAnnotation(authReqKeepaliveAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-keepalive annotation is undefined and will be set to its default value")
keepaliveConnections = defaultKeepaliveConnections
@ -238,9 +372,15 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
}
}
keepaliveRequests, err := parser.GetIntAnnotation("auth-keepalive-requests", ing)
keepaliveShareVars, err := parser.GetBoolAnnotation(authReqKeepaliveShareVarsAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-keepalive-requests annotation is undefined and will be set to its default value")
klog.V(3).InfoS("auth-keepalive-share-vars annotation is undefined and will be set to its default value")
keepaliveShareVars = defaultKeepaliveShareVars
}
keepaliveRequests, err := parser.GetIntAnnotation(authReqKeepaliveRequestsAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-keepalive-requests annotation is undefined or invalid and will be set to its default value")
keepaliveRequests = defaultKeepaliveRequests
}
if keepaliveRequests <= 0 {
@ -248,7 +388,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
keepaliveConnections = 0
}
keepaliveTimeout, err := parser.GetIntAnnotation("auth-keepalive-timeout", ing)
keepaliveTimeout, err := parser.GetIntAnnotation(authReqKeepaliveTimeout, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-keepalive-timeout annotation is undefined and will be set to its default value")
keepaliveTimeout = defaultKeepaliveTimeout
@ -258,15 +398,21 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
keepaliveConnections = 0
}
durstr, _ := parser.GetStringAnnotation("auth-cache-duration", ing)
durstr, err := parser.GetStringAnnotation(authReqCacheDuration, ing, a.annotationConfig.Annotations)
if err != nil && ing_errors.IsValidationError(err) {
return nil, fmt.Errorf("%s contains invalid value", authReqCacheDuration)
}
authCacheDuration, err := ParseStringToCacheDurations(durstr)
if err != nil {
return nil, err
}
responseHeaders := []string{}
hstr, _ := parser.GetStringAnnotation("auth-response-headers", ing)
if len(hstr) != 0 {
hstr, err := parser.GetStringAnnotation(authReqResponseHeadersAnnotation, ing, a.annotationConfig.Annotations)
if err != nil && ing_errors.IsValidationError(err) {
return nil, ing_errors.NewLocationDenied("validation error")
}
if hstr != "" {
harr := strings.Split(hstr, ",")
for _, header := range harr {
header = strings.TrimSpace(header)
@ -279,9 +425,28 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
}
}
proxySetHeaderMap, err := parser.GetStringAnnotation("auth-proxy-set-headers", ing)
proxySetHeaderMap, err := parser.GetStringAnnotation(authReqProxySetHeadersAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
klog.V(3).InfoS("auth-set-proxy-headers annotation is undefined and will not be set")
klog.V(3).InfoS("auth-set-proxy-headers annotation is undefined and will not be set", "err", err)
}
cns, _, err := cache.SplitMetaNamespaceKey(proxySetHeaderMap)
if err != nil {
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("error reading configmap name %s from annotation: %w", proxySetHeaderMap, err),
}
}
if cns == "" {
cns = ing.Namespace
}
secCfg := a.r.GetSecurityConfiguration()
// We don't accept different namespaces for secrets.
if !secCfg.AllowCrossNamespaceResources && cns != ing.Namespace {
return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
}
}
var proxySetHeaders map[string]string
@ -301,9 +466,15 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
proxySetHeaders = proxySetHeadersMapContents.Data
}
requestRedirect, _ := parser.GetStringAnnotation("auth-request-redirect", ing)
requestRedirect, err := parser.GetStringAnnotation(authReqRequestRedirectAnnotation, ing, a.annotationConfig.Annotations)
if err != nil && ing_errors.IsValidationError(err) {
return nil, fmt.Errorf("%s is invalid: %w", authReqRequestRedirectAnnotation, err)
}
alwaysSetCookie, _ := parser.GetBoolAnnotation("auth-always-set-cookie", ing)
alwaysSetCookie, err := parser.GetBoolAnnotation(authReqAlwaysSetCookieAnnotation, ing, a.annotationConfig.Annotations)
if err != nil && ing_errors.IsValidationError(err) {
return nil, fmt.Errorf("%s is invalid: %w", authReqAlwaysSetCookieAnnotation, err)
}
return &Config{
URL: urlString,
@ -317,6 +488,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
AuthCacheKey: authCacheKey,
AuthCacheDuration: authCacheDuration,
KeepaliveConnections: keepaliveConnections,
KeepaliveShareVars: keepaliveShareVars,
KeepaliveRequests: keepaliveRequests,
KeepaliveTimeout: keepaliveTimeout,
ProxySetHeaders: proxySetHeaders,
@ -329,7 +501,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
// It will always return at least one duration (the default duration)
func ParseStringToCacheDurations(input string) ([]string, error) {
authCacheDuration := []string{}
if len(input) != 0 {
if input != "" {
arr := strings.Split(input, ",")
for _, duration := range arr {
duration = strings.TrimSpace(duration)
@ -348,3 +520,12 @@ func ParseStringToCacheDurations(input string) ([]string, error) {
}
return authCacheDuration, nil
}
func (a authReq) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
func (a authReq) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, authReqAnnotations.Annotations)
}

View file

@ -17,7 +17,6 @@ limitations under the License.
package authreq
import (
"fmt"
"reflect"
"testing"
@ -113,7 +112,7 @@ func TestAnnotations(t *testing.T) {
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
data[parser.GetAnnotationWithPrefix("auth-signin-redirect-param")] = test.signinURLRedirectParam
data[parser.GetAnnotationWithPrefix("auth-method")] = fmt.Sprintf("%v", test.method)
data[parser.GetAnnotationWithPrefix("auth-method")] = test.method
data[parser.GetAnnotationWithPrefix("auth-request-redirect")] = test.requestRedirect
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet
data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey
@ -192,11 +191,13 @@ func TestHeaderAnnotations(t *testing.T) {
i, err := NewParser(&resolver.Mock{}).Parse(ing)
if test.expErr {
if err == nil {
t.Error("expected error but retuned nil")
t.Errorf("%v expected error but retuned nil", test.title)
}
continue
}
if err != nil {
t.Errorf("no error was expected but %v happened in %s", err, test.title)
}
u, ok := i.(*Config)
if !ok {
t.Errorf("%v: expected an External type", test.title)
@ -266,28 +267,31 @@ func TestKeepaliveAnnotations(t *testing.T) {
title string
url string
keepaliveConnections string
keepaliveShareVars string
keepaliveRequests string
keepaliveTimeout string
expectedConnections int
expectedShareVars bool
expectedRequests int
expectedTimeout int
}{
{"all set", "http://goog.url", "5", "500", "50", 5, 500, 50},
{"no annotation", "http://goog.url", "", "", "", defaultKeepaliveConnections, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"default for connections", "http://goog.url", "x", "500", "50", defaultKeepaliveConnections, 500, 50},
{"default for requests", "http://goog.url", "5", "x", "50", 5, defaultKeepaliveRequests, 50},
{"default for invalid timeout", "http://goog.url", "5", "500", "x", 5, 500, defaultKeepaliveTimeout},
{"variable in host", "http://$host:5000/a/b", "5", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"variable in path", "http://goog.url:5000/$path", "5", "", "", 5, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative connections", "http://goog.url", "-2", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative requests", "http://goog.url", "5", "-1", "", 0, -1, defaultKeepaliveTimeout},
{"negative timeout", "http://goog.url", "5", "", "-1", 0, defaultKeepaliveRequests, -1},
{"negative request and timeout", "http://goog.url", "5", "-2", "-3", 0, -2, -3},
{"all set", "http://goog.url", "5", "false", "500", "50", 5, false, 500, 50},
{"no annotation", "http://goog.url", "", "", "", "", defaultKeepaliveConnections, defaultKeepaliveShareVars, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"default for connections", "http://goog.url", "x", "true", "500", "50", defaultKeepaliveConnections, true, 500, 50},
{"default for requests", "http://goog.url", "5", "x", "dummy", "50", 5, defaultKeepaliveShareVars, defaultKeepaliveRequests, 50},
{"default for invalid timeout", "http://goog.url", "5", "t", "500", "x", 5, true, 500, defaultKeepaliveTimeout},
{"variable in host", "http://$host:5000/a/b", "5", "1", "", "", 0, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"variable in path", "http://goog.url:5000/$path", "5", "t", "", "", 5, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative connections", "http://goog.url", "-2", "f", "", "", 0, false, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative requests", "http://goog.url", "5", "True", "-1", "", 0, true, -1, defaultKeepaliveTimeout},
{"negative timeout", "http://goog.url", "5", "0", "", "-1", 0, false, defaultKeepaliveRequests, -1},
{"negative request and timeout", "http://goog.url", "5", "False", "-2", "-3", 0, false, -2, -3},
}
for _, test := range tests {
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
data[parser.GetAnnotationWithPrefix("auth-keepalive")] = test.keepaliveConnections
data[parser.GetAnnotationWithPrefix("auth-keepalive-share-vars")] = test.keepaliveShareVars
data[parser.GetAnnotationWithPrefix("auth-keepalive-timeout")] = test.keepaliveTimeout
data[parser.GetAnnotationWithPrefix("auth-keepalive-requests")] = test.keepaliveRequests
@ -311,6 +315,10 @@ func TestKeepaliveAnnotations(t *testing.T) {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedConnections, u.KeepaliveConnections)
}
if u.KeepaliveShareVars != test.expectedShareVars {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedShareVars, u.KeepaliveShareVars)
}
if u.KeepaliveRequests != test.expectedRequests {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedRequests, u.KeepaliveRequests)
}
@ -322,7 +330,6 @@ func TestKeepaliveAnnotations(t *testing.T) {
}
func TestParseStringToCacheDurations(t *testing.T) {
tests := []struct {
title string
duration string
@ -337,7 +344,6 @@ func TestParseStringToCacheDurations(t *testing.T) {
}
for _, test := range tests {
dur, err := ParseStringToCacheDurations(test.duration)
if test.expErr {
if err == nil {

View file

@ -23,23 +23,51 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
enableGlobalAuthAnnotation = "enable-global-auth"
)
var globalAuthAnnotations = parser.Annotation{
Group: "authentication",
Annotations: parser.AnnotationFields{
enableGlobalAuthAnnotation: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `Defines if the global external authentication should be enabled.`,
},
},
}
type authReqGlobal struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new authentication request annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authReqGlobal{r}
return authReqGlobal{
r: r,
annotationConfig: globalAuthAnnotations,
}
}
// ParseAnnotations parses the annotations contained in the ingress
// rule used to enable or disable global external authentication
func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
enableGlobalAuth, err := parser.GetBoolAnnotation("enable-global-auth", ing)
enableGlobalAuth, err := parser.GetBoolAnnotation(enableGlobalAuthAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
enableGlobalAuth = true
}
return enableGlobalAuth, nil
}
func (a authReqGlobal) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
func (a authReqGlobal) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, globalAuthAnnotations.Annotations)
}

View file

@ -77,7 +77,10 @@ func TestAnnotation(t *testing.T) {
data[parser.GetAnnotationWithPrefix("enable-global-auth")] = "false"
ing.SetAnnotations(data)
i, _ := NewParser(&resolver.Mock{}).Parse(ing)
i, err := NewParser(&resolver.Mock{}).Parse(ing)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
u, ok := i.(bool)
if !ok {
t.Errorf("expected a Config type")

View file

@ -18,11 +18,10 @@ package authtls
import (
"fmt"
"regexp"
networking "k8s.io/api/networking/v1"
"regexp"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
@ -32,13 +31,64 @@ import (
const (
defaultAuthTLSDepth = 1
defaultAuthVerifyClient = "on"
annotationAuthTLSSecret = "auth-tls-secret" //#nosec G101
annotationAuthTLSVerifyClient = "auth-tls-verify-client"
annotationAuthTLSVerifyDepth = "auth-tls-verify-depth"
annotationAuthTLSErrorPage = "auth-tls-error-page"
annotationAuthTLSPassCertToUpstream = "auth-tls-pass-certificate-to-upstream" //#nosec G101
annotationAuthTLSMatchCN = "auth-tls-match-cn"
)
var (
regexChars = regexp.QuoteMeta(`()|=`)
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
commonNameRegex = regexp.MustCompile(`CN=`)
commonNameRegex = regexp.MustCompile(`^CN=[/\-.\_\~a-zA-Z0-9` + regexChars + `]*$`)
redirectRegex = regexp.MustCompile(`^((https?://)?[A-Za-z0-9\-.]*(:\d+)?/[A-Za-z0-9\-.]*)?$`)
)
var authTLSAnnotations = parser.Annotation{
Group: "authentication",
Annotations: parser.AnnotationFields{
annotationAuthTLSSecret: {
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
Documentation: `This annotation defines the secret that contains the certificate chain of allowed certs`,
},
annotationAuthTLSVerifyClient: {
Validator: parser.ValidateRegex(authVerifyClientRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
Documentation: `This annotation enables verification of client certificates. Can be "on", "off", "optional" or "optional_no_ca"`,
},
annotationAuthTLSVerifyDepth: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation defines validation depth between the provided client certificate and the Certification Authority chain.`,
},
annotationAuthTLSErrorPage: {
Validator: parser.ValidateRegex(redirectRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskHigh,
Documentation: `This annotation defines the URL/Page that user should be redirected in case of a Certificate Authentication Error`,
},
annotationAuthTLSPassCertToUpstream: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation defines if the received certificates should be passed or not to the upstream server in the header "ssl-client-cert"`,
},
annotationAuthTLSMatchCN: {
Validator: parser.ValidateRegex(commonNameRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskHigh,
Documentation: `This annotation adds a sanity check for the CN of the client certificate that is sent over using a string / regex starting with "CN="`,
},
},
}
// Config contains the AuthSSLCert used for mutual authentication
// and the configured ValidationDepth
type Config struct {
@ -79,12 +129,16 @@ func (assl1 *Config) Equal(assl2 *Config) bool {
}
// NewParser creates a new TLS authentication annotation parser
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
return authTLS{resolver}
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authTLS{
r: r,
annotationConfig: authTLSAnnotations,
}
}
type authTLS struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// Parse parses the annotations contained in the ingress
@ -93,47 +147,75 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) {
var err error
config := &Config{}
tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing, a.annotationConfig.Annotations)
if err != nil {
return &Config{}, err
}
_, _, err = k8s.ParseNameNS(tlsauthsecret)
ns, _, err := k8s.ParseNameNS(tlsauthsecret)
if err != nil {
return &Config{}, ing_errors.NewLocationDenied(err.Error())
}
if ns == "" {
ns = ing.Namespace
}
secCfg := a.r.GetSecurityConfiguration()
// We don't accept different namespaces for secrets.
if !secCfg.AllowCrossNamespaceResources && ns != ing.Namespace {
return &Config{}, ing_errors.NewLocationDenied("cross namespace secrets are not supported")
}
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
if err != nil {
e := fmt.Errorf("error obtaining certificate: %w", err)
return &Config{}, ing_errors.LocationDenied{Reason: e}
return &Config{}, ing_errors.LocationDeniedError{Reason: e}
}
config.AuthSSLCert = *authCert
config.VerifyClient, err = parser.GetStringAnnotation("auth-tls-verify-client", ing)
config.VerifyClient, err = parser.GetStringAnnotation(annotationAuthTLSVerifyClient, ing, a.annotationConfig.Annotations)
// We can set a default value here in case of validation error
if err != nil || !authVerifyClientRegex.MatchString(config.VerifyClient) {
config.VerifyClient = defaultAuthVerifyClient
}
config.ValidationDepth, err = parser.GetIntAnnotation("auth-tls-verify-depth", ing)
config.ValidationDepth, err = parser.GetIntAnnotation(annotationAuthTLSVerifyDepth, ing, a.annotationConfig.Annotations)
// We can set a default value here in case of validation error
if err != nil || config.ValidationDepth == 0 {
config.ValidationDepth = defaultAuthTLSDepth
}
config.ErrorPage, err = parser.GetStringAnnotation("auth-tls-error-page", ing)
config.ErrorPage, err = parser.GetStringAnnotation(annotationAuthTLSErrorPage, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.ErrorPage = ""
}
config.PassCertToUpstream, err = parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
config.PassCertToUpstream, err = parser.GetBoolAnnotation(annotationAuthTLSPassCertToUpstream, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.PassCertToUpstream = false
}
config.MatchCN, err = parser.GetStringAnnotation("auth-tls-match-cn", ing)
if err != nil || !commonNameRegex.MatchString(config.MatchCN) {
config.MatchCN, err = parser.GetStringAnnotation(annotationAuthTLSMatchCN, ing, a.annotationConfig.Annotations)
if err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.MatchCN = ""
}
return config, nil
}
func (a authTLS) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
func (a authTLS) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, authTLSAnnotations.Annotations)
}

View file

@ -27,6 +27,11 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
defaultDemoSecret = "default/demo-secret"
off = "off"
)
func buildIngress() *networking.Ingress {
defaultBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
@ -77,23 +82,22 @@ type mockSecret struct {
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
if name != "default/demo-secret" {
if name != defaultDemoSecret {
return nil, errors.Errorf("there is no secret with name %v", name)
}
return &resolver.AuthSSLCert{
Secret: "default/demo-secret",
Secret: defaultDemoSecret,
CAFileName: "/ssl/ca.crt",
CASHA: "abc",
}, nil
}
func TestAnnotations(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = defaultDemoSecret
ing.SetAnnotations(data)
@ -108,7 +112,7 @@ func TestAnnotations(t *testing.T) {
t.Errorf("expected *Config but got %v", u)
}
secret, err := fakeSecret.GetAuthCertificate("default/demo-secret")
secret, err := fakeSecret.GetAuthCertificate(defaultDemoSecret)
if err != nil {
t.Errorf("unexpected error getting secret %v", err)
}
@ -132,11 +136,11 @@ func TestAnnotations(t *testing.T) {
t.Errorf("expected empty string, but got %v", u.MatchCN)
}
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "off"
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "2"
data[parser.GetAnnotationWithPrefix("auth-tls-error-page")] = "ok.com/error"
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "true"
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "CN=hello-app"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = off
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "2"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSErrorPage)] = "ok.com/error"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "true"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "CN=(hello-app|ok|goodbye)"
ing.SetAnnotations(data)
@ -153,8 +157,8 @@ func TestAnnotations(t *testing.T) {
if u.AuthSSLCert.Secret != secret.Secret {
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
}
if u.VerifyClient != "off" {
t.Errorf("expected %v but got %v", "off", u.VerifyClient)
if u.VerifyClient != off {
t.Errorf("expected %v but got %v", off, u.VerifyClient)
}
if u.ValidationDepth != 2 {
t.Errorf("expected %v but got %v", 2, u.ValidationDepth)
@ -165,8 +169,8 @@ func TestAnnotations(t *testing.T) {
if u.PassCertToUpstream != true {
t.Errorf("expected %v but got %v", true, u.PassCertToUpstream)
}
if u.MatchCN != "CN=hello-app" {
t.Errorf("expected %v but got %v", "CN=hello-app", u.MatchCN)
if u.MatchCN != "CN=(hello-app|ok|goodbye)" {
t.Errorf("expected %v but got %v", "CN=(hello-app|ok|goodbye)", u.MatchCN)
}
}
@ -182,15 +186,24 @@ func TestInvalidAnnotations(t *testing.T) {
}
// Invalid NameSpace
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "demo-secret"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "demo-secret"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err == nil {
t.Errorf("Expected error with ingress but got nil")
}
// Invalid Cross NameSpace
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "nondefault/demo-secret"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
expErr := errors.NewLocationDenied("cross namespace secrets are not supported")
if err.Error() != expErr.Error() {
t.Errorf("received error is different from cross namespace error: %s Expected %s", err, expErr)
}
// Invalid Auth Certificate
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/invalid-demo-secret"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/invalid-demo-secret"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err == nil {
@ -198,11 +211,38 @@ func TestInvalidAnnotations(t *testing.T) {
}
// Invalid optional Annotations
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret"
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "w00t"
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "abcd"
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "nahh"
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "<script>nope</script>"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/demo-secret"
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = "w00t"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err != nil {
t.Errorf("Error should be nil and verify client should be defaulted")
}
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "abcd"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err != nil {
t.Errorf("Error should be nil and verify depth should be defaulted")
}
data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "nahh"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err == nil {
t.Errorf("Expected error with ingress but got nil")
}
delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream))
data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "<script>nope</script>"
ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing)
if err == nil {
t.Errorf("Expected error with ingress CN but got nil")
}
delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN))
ing.SetAnnotations(data)
i, err := NewParser(fakeSecret).Parse(ing)
@ -226,28 +266,21 @@ func TestInvalidAnnotations(t *testing.T) {
if u.MatchCN != "" {
t.Errorf("expected empty string but got %v", u.MatchCN)
}
}
func TestEquals(t *testing.T) {
cfg1 := &Config{}
cfg2 := &Config{}
// Same config
result := cfg1.Equal(cfg1)
if result != true {
t.Errorf("Expected true")
}
// compare nil
result = cfg1.Equal(nil)
result := cfg1.Equal(nil)
if result != false {
t.Errorf("Expected false")
}
// Different Certs
sslCert1 := resolver.AuthSSLCert{
Secret: "default/demo-secret",
Secret: defaultDemoSecret,
CAFileName: "/ssl/ca.crt",
CASHA: "abc",
}
@ -266,7 +299,7 @@ func TestEquals(t *testing.T) {
// Different Verify Client
cfg1.VerifyClient = "on"
cfg2.VerifyClient = "off"
cfg2.VerifyClient = off
result = cfg1.Equal(cfg2)
if result != false {
t.Errorf("Expected false")

View file

@ -17,49 +17,70 @@ limitations under the License.
package backendprotocol
import (
"regexp"
"strings"
networking "k8s.io/api/networking/v1"
"k8s.io/klog/v2"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
// HTTP protocol
const HTTP = "HTTP"
var validProtocols = []string{"auto_http", "http", "https", "grpc", "grpcs", "fcgi"}
var (
validProtocols = regexp.MustCompile(`^(AUTO_HTTP|HTTP|HTTPS|GRPC|GRPCS|FCGI)$`)
const (
http = "HTTP"
backendProtocolAnnotation = "backend-protocol"
)
var backendProtocolConfig = parser.Annotation{
Group: "backend",
Annotations: parser.AnnotationFields{
backendProtocolAnnotation: {
Validator: parser.ValidateOptions(validProtocols, false, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
Documentation: `this annotation can be used to define which protocol should
be used to communicate with backends`,
},
},
}
type backendProtocol struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new backend protocol annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return backendProtocol{r}
return backendProtocol{
r: r,
annotationConfig: backendProtocolConfig,
}
}
func (a backendProtocol) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
// ParseAnnotations parses the annotations contained in the ingress
// rule used to indicate the backend protocol.
func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) {
if ing.GetAnnotations() == nil {
return HTTP, nil
return http, nil
}
proto, err := parser.GetStringAnnotation("backend-protocol", ing)
proto, err := parser.GetStringAnnotation(backendProtocolAnnotation, ing, a.annotationConfig.Annotations)
if err != nil {
return HTTP, nil
if errors.IsValidationError(err) {
klog.Warningf("validation error %s. Using HTTP as protocol", err)
}
proto = strings.TrimSpace(strings.ToUpper(proto))
if !validProtocols.MatchString(proto) {
klog.Warningf("Protocol %v is not a valid value for the backend-protocol annotation. Using HTTP as protocol", proto)
return HTTP, nil
return http, nil
}
return proto, nil
}
func (a backendProtocol) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, backendProtocolConfig.Annotations)
}

View file

@ -44,6 +44,7 @@ func buildIngress() *networking.Ingress {
},
}
}
func TestParseInvalidAnnotations(t *testing.T) {
ing := buildIngress()
@ -56,7 +57,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok {
t.Errorf("expected a string type")
}
if val != "HTTP" {
if val != http {
t.Errorf("expected HTTPS but %v returned", val)
}
@ -72,12 +73,12 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok {
t.Errorf("expected a string type")
}
if val != "HTTP" {
if val != http {
t.Errorf("expected HTTPS but %v returned", val)
}
// Test invalid annotation set
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "INVALID"
data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = "INVALID"
ing.SetAnnotations(data)
i, err = NewParser(&resolver.Mock{}).Parse(ing)
@ -88,7 +89,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok {
t.Errorf("expected a string type")
}
if val != "HTTP" {
if val != http {
t.Errorf("expected HTTPS but %v returned", val)
}
}
@ -97,7 +98,7 @@ func TestParseAnnotations(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS"
data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = " HTTPS "
ing.SetAnnotations(data)
i, err := NewParser(&resolver.Mock{}).Parse(ing)

View file

@ -18,14 +18,82 @@ package canary
import (
networking "k8s.io/api/networking/v1"
"k8s.io/klog/v2"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
canaryAnnotation = "canary"
canaryWeightAnnotation = "canary-weight"
canaryWeightTotalAnnotation = "canary-weight-total"
canaryByHeaderAnnotation = "canary-by-header"
canaryByHeaderValueAnnotation = "canary-by-header-value"
canaryByHeaderPatternAnnotation = "canary-by-header-pattern"
canaryByCookieAnnotation = "canary-by-cookie"
)
var CanaryAnnotations = parser.Annotation{
Group: "canary",
Annotations: parser.AnnotationFields{
canaryAnnotation: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation enables the Ingress spec to act as an alternative service for requests to route to depending on the rules applied`,
},
canaryWeightAnnotation: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation defines the integer based (0 - ) percent of random requests that should be routed to the service specified in the canary Ingress`,
},
canaryWeightTotalAnnotation: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskLow,
Documentation: `This annotation The total weight of traffic. If unspecified, it defaults to 100`,
},
canaryByHeaderAnnotation: {
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation defines the header that should be used for notifying the Ingress to route the request to the service specified in the Canary Ingress.
When the request header is set to 'always', it will be routed to the canary. When the header is set to 'never', it will never be routed to the canary.
For any other value, the header will be ignored and the request compared against the other canary rules by precedence`,
},
canaryByHeaderValueAnnotation: {
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation defines the header value to match for notifying the Ingress to route the request to the service specified in the Canary Ingress.
When the request header is set to this value, it will be routed to the canary. For any other header value, the header will be ignored and the request compared against the other canary rules by precedence.
This annotation has to be used together with 'canary-by-header'. The annotation is an extension of the 'canary-by-header' to allow customizing the header value instead of using hardcoded values.
It doesn't have any effect if the 'canary-by-header' annotation is not defined`,
},
canaryByHeaderPatternAnnotation: {
Validator: parser.ValidateRegex(parser.IsValidRegex, false),
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation works the same way as canary-by-header-value except it does PCRE Regex matching.
Note that when 'canary-by-header-value' is set this annotation will be ignored.
When the given Regex causes error during request processing, the request will be considered as not matching.`,
},
canaryByCookieAnnotation: {
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
Scope: parser.AnnotationScopeIngress,
Risk: parser.AnnotationRiskMedium,
Documentation: `This annotation defines the cookie that should be used for notifying the Ingress to route the request to the service specified in the Canary Ingress.
When the cookie is set to 'always', it will be routed to the canary. When the cookie is set to 'never', it will never be routed to the canary`,
},
},
}
type canary struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// Config returns the configuration rules for setting up the Canary
@ -41,7 +109,10 @@ type Config struct {
// NewParser parses the ingress for canary related annotations
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return canary{r}
return canary{
r: r,
annotationConfig: CanaryAnnotations,
}
}
// Parse parses the annotations contained in the ingress
@ -50,45 +121,75 @@ func (c canary) Parse(ing *networking.Ingress) (interface{}, error) {
config := &Config{}
var err error
config.Enabled, err = parser.GetBoolAnnotation("canary", ing)
config.Enabled, err = parser.GetBoolAnnotation(canaryAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to 'false'", canaryAnnotation)
}
config.Enabled = false
}
config.Weight, err = parser.GetIntAnnotation("canary-weight", ing)
config.Weight, err = parser.GetIntAnnotation(canaryWeightAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to '0'", canaryWeightAnnotation)
}
config.Weight = 0
}
config.WeightTotal, err = parser.GetIntAnnotation("canary-weight-total", ing)
config.WeightTotal, err = parser.GetIntAnnotation(canaryWeightTotalAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to '100'", canaryWeightTotalAnnotation)
}
config.WeightTotal = 100
}
config.Header, err = parser.GetStringAnnotation("canary-by-header", ing)
config.Header, err = parser.GetStringAnnotation(canaryByHeaderAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderAnnotation)
}
config.Header = ""
}
config.HeaderValue, err = parser.GetStringAnnotation("canary-by-header-value", ing)
config.HeaderValue, err = parser.GetStringAnnotation(canaryByHeaderValueAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderValueAnnotation)
}
config.HeaderValue = ""
}
config.HeaderPattern, err = parser.GetStringAnnotation("canary-by-header-pattern", ing)
config.HeaderPattern, err = parser.GetStringAnnotation(canaryByHeaderPatternAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderPatternAnnotation)
}
config.HeaderPattern = ""
}
config.Cookie, err = parser.GetStringAnnotation("canary-by-cookie", ing)
config.Cookie, err = parser.GetStringAnnotation(canaryByCookieAnnotation, ing, c.annotationConfig.Annotations)
if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByCookieAnnotation)
}
config.Cookie = ""
}
if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0 ||
len(config.HeaderPattern) > 0) {
return nil, errors.NewInvalidAnnotationConfiguration("canary", "configured but not enabled")
return nil, errors.NewInvalidAnnotationConfiguration(canaryAnnotation, "configured but not enabled")
}
return config, nil
}
func (c canary) GetDocumentation() parser.AnnotationFields {
return c.annotationConfig.Annotations
}
func (c canary) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(c.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, CanaryAnnotations.Annotations)
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package canary
import (
"strconv"
"testing"
api "k8s.io/api/core/v1"
@ -24,8 +25,6 @@ import (
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"strconv"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
@ -93,7 +92,6 @@ func TestCanaryInvalid(t *testing.T) {
if val.Weight != 0 {
t.Errorf("Expected %v but got %v", 0, val.Weight)
}
}
func TestAnnotations(t *testing.T) {
@ -133,11 +131,10 @@ func TestAnnotations(t *testing.T) {
}
continue
} else {
}
if err != nil {
t.Errorf("%v: expected nil but returned error %v", test.title, err)
}
}
canaryConfig, ok := i.(*Config)
if !ok {

View file

@ -23,17 +23,49 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
clientBodyBufferSizeAnnotation = "client-body-buffer-size"
)
var clientBodyBufferSizeConfig = parser.Annotation{
Group: "backend",
Annotations: parser.AnnotationFields{
clientBodyBufferSizeAnnotation: {
Validator: parser.ValidateRegex(parser.SizeRegex, true),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
Documentation: `Sets buffer size for reading client request body per location.
In case the request body is larger than the buffer, the whole body or only its part is written to a temporary file.
By default, buffer size is equal to two memory pages. This is 8K on x86, other 32-bit platforms, and x86-64.
It is usually 16K on other 64-bit platforms. This annotation is applied to each location provided in the ingress rule.`,
},
},
}
type clientBodyBufferSize struct {
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new clientBodyBufferSize annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return clientBodyBufferSize{r}
return clientBodyBufferSize{
r: r,
annotationConfig: clientBodyBufferSizeConfig,
}
}
func (cbbs clientBodyBufferSize) GetDocumentation() parser.AnnotationFields {
return cbbs.annotationConfig.Annotations
}
// Parse parses the annotations contained in the ingress rule
// used to add an client-body-buffer-size to the provided locations
func (cbbs clientBodyBufferSize) Parse(ing *networking.Ingress) (interface{}, error) {
return parser.GetStringAnnotation("client-body-buffer-size", ing)
return parser.GetStringAnnotation(clientBodyBufferSizeAnnotation, ing, cbbs.annotationConfig.Annotations)
}
func (cbbs clientBodyBufferSize) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(cbbs.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, clientBodyBufferSizeConfig.Annotations)
}

Some files were not shown because too many files have changed in this diff Show more