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

View file

@ -9,6 +9,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: 'Dependency Review' - 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: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter id: filter
@ -47,7 +47,7 @@ jobs:
steps: steps:
- name: Checkout master - name: Checkout master
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Deploy - name: Deploy
uses: ./.github/actions/mkdocs uses: ./.github/actions/mkdocs

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -45,14 +45,16 @@ if ! command -v helm &> /dev/null; then
exit 1 exit 1
fi 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 HELM_VERSION=$(helm version 2>&1 | cut -f1 -d"," | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || true
echo $HELM_VERSION 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" echo "Please upgrade helm to v3.10.0 or higher"
exit 1 exit 1
fi 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 if [[ ${KUBE_CLIENT_VERSION} -lt 24 ]]; then
echo "Please update kubectl to 1.24.2 or higher" echo "Please update kubectl to 1.24.2 or higher"
exit 1 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.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.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.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.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.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.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. | | 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.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.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.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.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.enabled | bool | `false` | Enable 'hostPort' or not |
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port | | 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.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.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
| controller.opentelemetry.enabled | 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.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata | | controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods | | 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.enabled | bool | `false` | Enable 'scope' or not |
| controller.scope.namespace | string | `""` | Namespace to limit the controller to; defaults to $(POD_NAMESPACE) | | 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.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.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.enableHttp | bool | `true` | |
| controller.service.enableHttps | bool | `true` | | | controller.service.enableHttps | bool | `true` | |
| controller.service.enabled | bool | `true` | | | controller.service.enabled | bool | `true` | |
| controller.service.external.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.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.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.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. | | 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" -}} {{- define "ingress-nginx.params" -}}
- /nginx-ingress-controller - /nginx-ingress-controller
{{- if .Values.controller.enableAnnotationValidations }}
- --enable-annotation-validation=true
{{- end }}
{{- if .Values.defaultBackend.enabled }} {{- if .Values.defaultBackend.enabled }}
- --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }} - --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
{{- end }} {{- end }}

View file

@ -19,7 +19,7 @@ spec:
matchLabels: matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }} {{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: controller 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 }} replicas: {{ .Values.controller.replicaCount }}
{{- end }} {{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
@ -49,6 +49,9 @@ spec:
{{- if .Values.controller.dnsConfig }} {{- if .Values.controller.dnsConfig }}
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }} dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
{{- end }} {{- end }}
{{- if .Values.controller.hostAliases }}
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostname }} {{- if .Values.controller.hostname }}
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }} hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
{{- end }} {{- end }}
@ -190,7 +193,7 @@ spec:
{{- end }} {{- end }}
{{- if .Values.controller.opentelemetry.enabled}} {{- if .Values.controller.opentelemetry.enabled}}
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }} {{ $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}}
{{- end }} {{- end }}
{{- if .Values.controller.hostNetwork }} {{- if .Values.controller.hostNetwork }}

View file

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

View file

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

View file

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

View file

@ -15,6 +15,7 @@ commonLabels: {}
controller: controller:
name: controller name: controller
enableAnnotationValidations: false
image: image:
## Keep false as default for now! ## Keep false as default for now!
chroot: false chroot: false
@ -48,6 +49,8 @@ controller:
addHeaders: {} addHeaders: {}
# -- Optionally customize the pod dnsConfig. # -- Optionally customize the pod dnsConfig.
dnsConfig: {} dnsConfig: {}
# -- Optionally customize the pod hostAliases.
hostAliases: {}
# -- Optionally customize the pod hostname. # -- Optionally customize the pod hostname.
hostname: {} hostname: {}
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. # -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
@ -63,7 +66,7 @@ controller:
watchIngressWithoutClass: false watchIngressWithoutClass: false
# -- Process IngressClass per name (additionally as per spec.controller). # -- Process IngressClass per name (additionally as per spec.controller).
ingressClassByName: false 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 # Defaults to false
enableTopologyAwareRouting: false enableTopologyAwareRouting: false
# -- This configuration defines if Ingress Controller should allow users to set # -- 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 # Will be ignored for Kubernetes versions older than 1.20
## ##
appProtocol: true appProtocol: true
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
annotations: {} annotations: {}
labels: {} labels: {}
# clusterIP: "" # clusterIP: ""
@ -476,7 +480,7 @@ controller:
internal: internal:
# -- Enables an additional internal load balancer (besides the external one). # -- Enables an additional internal load balancer (besides the external one).
enabled: false 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: {} 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. # -- 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: "" loadBalancerIP: ""
@ -552,7 +556,7 @@ controller:
opentelemetry: opentelemetry:
enabled: false enabled: false
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0 image: registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
containerSecurityContext: containerSecurityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
admissionWebhooks: admissionWebhooks:

View file

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

View file

@ -114,7 +114,6 @@ func main() {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
} }
func backendsAll() { func backendsAll() {
@ -155,10 +154,16 @@ func backendsList() {
fmt.Println(unmarshalErr) fmt.Println(unmarshalErr)
return return
} }
backends := f.([]interface{}) backends, ok := f.([]interface{})
if !ok {
fmt.Printf("unexpected type: %T", f)
}
for _, backendi := range backends { 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)) fmt.Println(backend["name"].(string))
} }
} }
@ -180,12 +185,22 @@ func backendsGet(name string) {
fmt.Println(unmarshalErr) fmt.Println(unmarshalErr)
return return
} }
backends := f.([]interface{}) backends, ok := f.([]interface{})
if !ok {
fmt.Printf("unexpected type: %T", f)
}
for _, backendi := range backends { 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 { 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)) fmt.Println(string(printed))
return return
} }
@ -213,18 +228,7 @@ func certGet(host string) {
} }
func general() { func general() {
//TODO: refactor to obtain ingress-nginx pod count from the api server // 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 var prettyBuffer bytes.Buffer
indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ") indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ")

View file

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

View file

@ -153,7 +153,6 @@ func main() {
if errExists == nil { if errExists == nil {
conf.IsChroot = true conf.IsChroot = true
go logger(conf.InternalLoggerAddress) go logger(conf.InternalLoggerAddress)
} }
go metrics.StartHTTPServer(conf.HealthCheckHost, conf.ListenPorts.Health, mux) 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) { 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 return nil

View file

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

View file

@ -63,13 +63,14 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd 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 var command []string
if onlyList { switch {
case onlyList:
command = []string{"/dbg", "backends", "list"} command = []string{"/dbg", "backends", "list"}
} else if backend != "" { case backend != "":
command = []string{"/dbg", "backends", "get", backend} command = []string{"/dbg", "backends", "get", backend}
} else { default:
command = []string{"/dbg", "backends", "all"} command = []string{"/dbg", "backends", "all"}
} }

View file

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

View file

@ -55,7 +55,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd 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) pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil { if err != nil {
return err return err

View file

@ -55,7 +55,7 @@ type execFlags struct {
Stdin bool 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) pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil { if err != nil {
return err return err

View file

@ -47,7 +47,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd 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) pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil { if err != nil {
return err return err

View file

@ -74,9 +74,9 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
if host != "" { if host != "" {
rowsWithHost := make([]ingressRow, 0) rowsWithHost := make([]ingressRow, 0)
for _, row := range rows { for i := range rows {
if row.Host == host { if rows[i].Host == host {
rowsWithHost = append(rowsWithHost, row) rowsWithHost = append(rowsWithHost, rows[i])
} }
} }
rows = rowsWithHost 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") 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 var tlsMsg string
if row.TLS { if row.TLS {
tlsMsg = "YES" tlsMsg = "YES"
@ -134,8 +135,8 @@ type ingressRow struct {
func getIngressRows(ingresses *[]networking.Ingress) []ingressRow { func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
rows := make([]ingressRow, 0) rows := make([]ingressRow, 0)
for _, ing := range *ingresses { for i := range *ingresses {
ing := &(*ingresses)[i]
address := "" address := ""
for _, lbIng := range ing.Status.LoadBalancer.Ingress { for _, lbIng := range ing.Status.LoadBalancer.Ingress {
if len(lbIng.IP) > 0 { if len(lbIng.IP) > 0 {
@ -182,7 +183,7 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
for _, rule := range ing.Spec.Rules { for _, rule := range ing.Spec.Rules {
_, hasTLS := tlsHosts[rule.Host] _, hasTLS := tlsHosts[rule.Host]
//Handle ingress with no paths // Handle ingress with no paths
if rule.HTTP == nil { if rule.HTTP == nil {
row := ingressRow{ row := ingressRow{
Namespace: ing.Namespace, Namespace: ing.Namespace,

View file

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

View file

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

View file

@ -95,7 +95,7 @@ func (o *logsFlags) toStrings() []string {
return r 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) pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil { if err != nil {
return err return err

View file

@ -45,7 +45,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
return cmd 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) pod, err := request.ChoosePod(flags, podName, deployment, selector)
if err != nil { if err != nil {
return err 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 // ExecToString runs a kubectl subcommand and returns stdout as a string
func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) { func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) {
kArgs := getKubectlConfigFlags(flags) kubectlArgs := getKubectlConfigFlags(flags)
kArgs = append(kArgs, args...) kubectlArgs = append(kubectlArgs, args...)
buf := bytes.NewBuffer(make([]byte, 0)) buf := bytes.NewBuffer(make([]byte, 0))
err := execToWriter(append([]string{"kubectl"}, kArgs...), buf) err := execToWriter(append([]string{"kubectl"}, kubectlArgs...), buf)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -51,9 +51,9 @@ func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string,
// Exec replaces the current process with a kubectl invocation // Exec replaces the current process with a kubectl invocation
func Exec(flags *genericclioptions.ConfigFlags, args []string) error { func Exec(flags *genericclioptions.ConfigFlags, args []string) error {
kArgs := getKubectlConfigFlags(flags) kubectlArgs := getKubectlConfigFlags(flags)
kArgs = append(kArgs, args...) kubectlArgs = append(kubectlArgs, args...)
return execCommand(append([]string{"kubectl"}, kArgs...)) return execCommand(append([]string{"kubectl"}, kubectlArgs...))
} }
// Replaces the currently running process with the given command // Replaces the currently running process with the given command
@ -70,6 +70,7 @@ func execCommand(args []string) error {
// Runs a command and returns stdout // Runs a command and returns stdout
func execToWriter(args []string, writer io.Writer) error { func execToWriter(args []string, writer io.Writer) error {
//nolint:gosec // Ignore G204 error
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
op, err := cmd.StdoutPipe() op, err := cmd.StdoutPipe()
@ -78,7 +79,7 @@ func execToWriter(args []string, writer io.Writer) error {
} }
go func() { go func() {
io.Copy(writer, op) //nolint:errcheck io.Copy(writer, op) //nolint:errcheck // Ignore the error
}() }()
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
@ -106,7 +107,6 @@ func getKubectlConfigFlags(flags *genericclioptions.ConfigFlags) []string {
appendStringFlag(o, flags.Password, "password") appendStringFlag(o, flags.Password, "password")
appendStringFlag(o, flags.ClusterName, "cluster") appendStringFlag(o, flags.ClusterName, "cluster")
appendStringFlag(o, flags.AuthInfoName, "user") appendStringFlag(o, flags.AuthInfoName, "user")
//appendStringFlag(o, flags.Namespace, "namespace")
appendStringFlag(o, flags.Context, "context") appendStringFlag(o, flags.Context, "context")
appendStringFlag(o, flags.APIServer, "server") appendStringFlag(o, flags.APIServer, "server")
appendBoolFlag(o, flags.Insecure, "insecure-skip-tls-verify") 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 { if in != nil && len(*in) > 0 {
*out = append(*out, fmt.Sprintf("--%v=%v'", flag, strings.Join(*in, ","))) *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 // Check returns true if the lint detects an issue
func (lint DeploymentLint) Check(obj kmeta.Object) bool { 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) return lint.f(*cmp)
} }
@ -72,11 +75,11 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
issue: issueNumber, issue: issueNumber,
version: version, version: version,
f: func(dep v1.Deployment) bool { f: func(dep v1.Deployment) bool {
if !isIngressNginxDeployment(dep) { if !isIngressNginxDeployment(&dep) {
return false return false
} }
args := getNginxArgs(dep) args := getNginxArgs(&dep)
for _, arg := range args { for _, arg := range args {
if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) { if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) {
return true return true
@ -88,8 +91,9 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
} }
} }
func getNginxArgs(dep v1.Deployment) []string { func getNginxArgs(dep *v1.Deployment) []string {
for _, container := range dep.Spec.Template.Spec.Containers { 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" { if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
return container.Args return container.Args
} }
@ -97,10 +101,10 @@ func getNginxArgs(dep v1.Deployment) []string {
return make([]string, 0) return make([]string, 0)
} }
func isIngressNginxDeployment(dep v1.Deployment) bool { func isIngressNginxDeployment(dep *v1.Deployment) bool {
containers := dep.Spec.Template.Spec.Containers containers := dep.Spec.Template.Spec.Containers
for _, container := range containers { for i := range containers {
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" { if len(containers[i].Args) > 0 && containers[i].Args[0] == "/nginx-ingress-controller" {
return true return true
} }
} }

View file

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

View file

@ -24,7 +24,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
//Just importing this is supposed to allow cloud authentication // Just importing this is supposed to allow cloud authentication
// eg GCP, AWS, Azure ... // eg GCP, AWS, Azure ...
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"

View file

@ -35,7 +35,7 @@ import (
) )
// ChoosePod finds a pod either by deployment or by name // 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 != "" { if podName != "" {
return GetNamedPod(flags, podName) return GetNamedPod(flags, podName)
} }
@ -54,9 +54,9 @@ func GetNamedPod(flags *genericclioptions.ConfigFlags, name string) (apiv1.Pod,
return apiv1.Pod{}, err return apiv1.Pod{}, err
} }
for _, pod := range allPods { for i := range allPods {
if pod.Name == name { if allPods[i].Name == name {
return pod, nil 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 // 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) epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -143,25 +143,26 @@ func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, ser
} }
ret := 0 ret := 0
for _, eps := range epss { for i := range epss {
for _, ep := range eps.Endpoints { eps := &epss[i]
ret += len(ep.Addresses) for j := range eps.Endpoints {
ret += len(eps.Endpoints[j].Addresses)
} }
} }
return &ret, nil return &ret, nil
} }
// GetEndpointSlicesByName returns the endpointSlices for the service with the given name // 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) allEndpointsSlices, err := getEndpointSlices(flags, namespace)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var eps []discoveryv1.EndpointSlice var eps []discoveryv1.EndpointSlice
for _, slice := range allEndpointsSlices { for i := range allEndpointsSlices {
if svcName, ok := slice.ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok { if svcName, ok := allEndpointsSlices[i].ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
if svcName == name { 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) tryAllNamespacesEndpointSlicesCache(flags)
} }
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(flags, namespace) cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(namespace)
if cachedEndpointSlices != nil { if cachedEndpointSlices != nil {
return *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[""] allEndpointSlices := endpointSlicesCache[""]
if allEndpointSlices != nil { if allEndpointSlices != nil {
endpointSlices := make([]discoveryv1.EndpointSlice, 0) endpointSlices := make([]discoveryv1.EndpointSlice, 0)
for _, slice := range *allEndpointSlices { for i := range *allEndpointSlices {
if slice.Namespace == namespace { if (*allEndpointSlices)[i].Namespace == namespace {
endpointSlices = append(endpointSlices, slice) endpointSlices = append(endpointSlices, (*allEndpointSlices)[i])
} }
} }
endpointSlicesCache[namespace] = &endpointSlices endpointSlicesCache[namespace] = &endpointSlices
@ -242,9 +243,9 @@ func GetServiceByName(flags *genericclioptions.ConfigFlags, name string, service
services = &servicesArray services = &servicesArray
} }
for _, svc := range *services { for i := range *services {
if svc.Name == name { if (*services)[i].Name == name {
return svc, nil 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{ pods, err := api.Pods(namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: label, LabelSelector: label,
}) })
if err != nil { if err != nil {
return make([]apiv1.Pod, 0), err return make([]apiv1.Pod, 0), err
} }
@ -303,9 +303,9 @@ func getDeploymentPods(flags *genericclioptions.ConfigFlags, deployment string)
} }
ingressPods := make([]apiv1.Pod, 0) ingressPods := make([]apiv1.Pod, 0)
for _, pod := range pods { for i := range pods {
if util.PodInDeployment(pod, deployment) { if util.PodInDeployment(&pods[i], deployment) {
ingressPods = append(ingressPods, pod) ingressPods = append(ingressPods, pods[i])
} }
} }
@ -331,5 +331,4 @@ func getServices(flags *genericclioptions.ConfigFlags) ([]apiv1.Service, error)
} }
return services.Items, nil 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 // 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) parts := versionRegex.FindStringSubmatch(v)
if len(parts) != 4 { if len(parts) != 4 {
return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v) return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v)
} }
major, _ := strconv.Atoi(parts[1]) major, err = strconv.Atoi(parts[1])
minor, _ := strconv.Atoi(parts[2]) if err != nil {
patch, _ := strconv.Atoi(parts[3]) 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 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 // 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 // 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 { for _, owner := range pod.OwnerReferences {
if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" { if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" {
continue 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 // GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in
func GetNamespace(flags *genericclioptions.ConfigFlags) string { func GetNamespace(flags *genericclioptions.ConfigFlags) string {
namespace, _, err := flags.ToRawKubeConfigLoader().Namespace() namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()
if err != nil || len(namespace) == 0 { if err != nil || namespace == "" {
namespace = apiv1.NamespaceDefault namespace = apiv1.NamespaceDefault
} }
return namespace return namespace

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -410,6 +410,10 @@ spec:
app.kubernetes.io/component: controller app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template: template:
metadata: metadata:
labels: 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. 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. 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 ### Pre-flight check
A few pods should start in the `ingress-nginx` namespace: 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) ### [[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) ### [[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 Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO
Features | [Rewrite](rewrite/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 | [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 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 | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO
TLS | [TLS termination](tls-termination/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-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-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". | | `--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-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-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) | | `--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-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-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-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'| | `--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-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) | | `--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 # 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: 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.
`<namespace/service name>:<service port>:[PROXY]:[PROXY]`
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. 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. 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-key](#external-authentication)|string|
|[nginx.ingress.kubernetes.io/auth-cache-duration](#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](#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-requests](#external-authentication)|number|
|[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number| |[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number|
|[nginx.ingress.kubernetes.io/auth-proxy-set-headers](#external-authentication)|string| |[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). > 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! > [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`: * `nginx.ingress.kubernetes.io/auth-keepalive-requests`:
`<Requests>` to specify the maximum number of requests that can be served through one keepalive connection. `<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`. 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|""|| |[add-headers](#add-headers)|string|""||
|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"|| |[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|| |[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|""|| |[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""||
|[hide-headers](#hide-headers)|string array|empty|| |[hide-headers](#hide-headers)|string array|empty||
|[access-log-params](#access-log-params)|string|""|| |[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 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 ## allow-snippet-annotations
Enables Ingress to parse and add *-snippet annotations/directives created by the user. _**default:**_ `true` 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 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 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 ## annotation-value-word-blocklist
Contains a comma-separated value of chars/words that are well known of being used to abuse Ingress configuration 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/moul/pb v0.0.0-20220425114252-bca18df4138c
github.com/ncabatoff/process-exporter v0.7.10 github.com/ncabatoff/process-exporter v0.7.10
github.com/onsi/ginkgo/v2 v2.9.5 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/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_golang v1.16.0
github.com/prometheus/client_model v0.4.0 github.com/prometheus/client_model v0.4.0
@ -25,19 +25,19 @@ require (
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/yudai/gojsondiff v1.0.0 github.com/yudai/gojsondiff v1.0.0
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
golang.org/x/crypto v0.10.0 golang.org/x/crypto v0.12.0
google.golang.org/grpc v1.56.1 google.golang.org/grpc v1.57.0
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
gopkg.in/go-playground/pool.v3 v3.1.1 gopkg.in/go-playground/pool.v3 v3.1.1
gopkg.in/mcuadros/go-syslog.v2 v2.3.0 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/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/apiserver v0.26.4
k8s.io/cli-runtime 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/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 k8s.io/klog/v2 v2.100.1
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
sigs.k8s.io/controller-runtime v0.14.6 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/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b // indirect
github.com/go-errors/errors v1.0.1 // indirect github.com/go-errors/errors v1.0.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/logr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.19.14 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/godbus/dbus/v5 v5.0.6 // indirect
github.com/gogo/protobuf v1.3.2 // 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/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.1.0 // 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/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // 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/mattn/go-colorable v0.1.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mmarkdown/mmark v2.0.40+incompatible // 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/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.9.0 // indirect golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.9.0 // indirect golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.10.0 // indirect golang.org/x/text v0.12.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.1 // indirect golang.org/x/tools v0.9.1 // indirect
google.golang.org/appengine v1.6.7 // 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 google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // 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 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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-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.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 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-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 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-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-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-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-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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/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 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 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/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 h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= 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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 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-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 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/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 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek= 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.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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.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.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= 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.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= 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 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 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= 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.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.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.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/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 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 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/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.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.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 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.1.3/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/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= 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.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.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.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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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= 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-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-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.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.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 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-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-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.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= 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.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.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.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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-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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-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-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-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
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/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 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.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 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.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.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.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= 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 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI= 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= 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 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-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-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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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= 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-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.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/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.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
k8s.io/api v0.26.4/go.mod h1:WwKEXU3R1rgCZ77AYa7DFksd9/BAIKyOmRlbVxgvjCk= 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 h1:9D2RTxYGxrG5uYg6D7QZRcykXvavBvcA59j5kTaedQI=
k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw= k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw=
k8s.io/apimachinery v0.26.4 h1:rZccKdBLg9vP6J09JD+z8Yr99Ce8gk3Lbi9TCx05Jzs= k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
k8s.io/apimachinery v0.26.4/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= 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 h1:3Oq4mnJv0mzVX7BR/Nod+8KjlELf/3Ljvu9ZWDyLUoA=
k8s.io/apiserver v0.26.4/go.mod h1:yAY3O1vBM4/0OIGAGeWcdfzQvgdwJ188VirLcuSAVnw= 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 h1:MgSU871KDzBDX7V9GtuqS6Ai9lhQCHgRzkurnXOWtZ0=
k8s.io/cli-runtime v0.26.4/go.mod h1:MjJ2DXMChw2zcG0/agzm17xwKpfVxOfuoCdfY9iOCOE= 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.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
k8s.io/client-go v0.26.4/go.mod h1:6qOItWm3EwxJdl/8p5t7FWtWUOwyMdA8N9ekbW4idpI= 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 h1:zgDD0qX13p/jtrAoYRRiYeQ5ibnriwmo2cMkMZAtJxc=
k8s.io/code-generator v0.26.4/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI= 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.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c=
k8s.io/component-base v0.26.4/go.mod h1:lTuWL1Xz/a4e80gmIC3YZG2JCO4xNwtKWHJWeJmsq20= 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 h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= 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.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 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= 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-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 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 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg= 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= 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= 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 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= 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-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= 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 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/cfssl && make push && 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 # See the License for the specific language governing permissions and
# limitations under the License. # 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 RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/custom-error-pages && make push && 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/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/www /www
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/etc /etc
USER nonroot:nonroot USER nonroot:nonroot
CMD ["/nginx-errors"] CMD ["/nginx-errors"]

View file

@ -6,8 +6,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -17,6 +15,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/echo && make push && 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))))) DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh 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 REGISTRY ?= local
IMAGE = $(REGISTRY)/ext-auth-example-authsvc IMAGE = $(REGISTRY)/ext-auth-example-authsvc

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/ext-auth-example-authsvc && make push && 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 entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -17,6 +15,4 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/fastcgi-helloserver && make push && 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] key := keys[0]
fmt.Fprintf(w, "Hello "+string(key)+"!") fmt.Fprintf(w, "Hello "+key+"!")
} }
func main() { func main() {
http.HandleFunc("/hello", hello) 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 { if err != nil {
panic(err) panic(err)
} }

View file

@ -8,8 +8,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -19,6 +17,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/go-grpc-greeter-server && make push && 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 // 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 return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil
} }
@ -49,7 +49,7 @@ type ecServer struct {
ecpb.UnimplementedEchoServer 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 return &ecpb.EchoResponse{Message: req.Message}, nil
} }

View file

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

View file

@ -21,8 +21,6 @@ steps:
entrypoint: bash entrypoint: bash
env: env:
- DOCKER_CLI_EXPERIMENTAL=enabled - DOCKER_CLI_EXPERIMENTAL=enabled
- SHORT_SHA=$SHORT_SHA
- BASE_REF=$_PULL_BASE_REF
- REGISTRY=gcr.io/k8s-staging-ingress-nginx - REGISTRY=gcr.io/k8s-staging-ingress-nginx
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx # 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 # set the home to /root explicitly to if using docker buildx
@ -32,6 +30,3 @@ steps:
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& cd images/kube-webhook-certgen && make push && 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. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
FROM alpine:3.18.0 as builder FROM alpine:3.18.2 as builder
COPY . / COPY . /
@ -21,7 +21,7 @@ RUN apk update \
&& /build.sh && /build.sh
# Use a multi-stage build # 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 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 export NGINX_VERSION=1.21.6
# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.1...master # Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.2...master
export NDK_VERSION=0.3.1 export NDK_VERSION=0.3.2
# Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master # Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master
export SETMISC_VERSION=0.33 export SETMISC_VERSION=0.33
# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.33...master # Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.34...master
export MORE_HEADERS_VERSION=0.33 export MORE_HEADERS_VERSION=0.34
# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master # 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 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 # Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master
export OWASP_MODSECURITY_CRS_VERSION=v3.3.4 export OWASP_MODSECURITY_CRS_VERSION=v3.3.4
# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.21...master # Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.25...master
export LUA_NGX_VERSION=0.10.21 export LUA_NGX_VERSION=0.10.25
# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.11...master # Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.13...master
export LUA_STREAM_NGX_VERSION=0.0.11 export LUA_STREAM_NGX_VERSION=0.0.13
# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master # Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master
export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf
# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.10...openresty:master # Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.11...openresty:master
export LUA_CJSON_VERSION=2.1.0.10 export LUA_CJSON_VERSION=2.1.0.11
# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.3...master # Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.3...master
export GEOIP2_VERSION=a26c6beed77e81553686852dceb6c7fdacc5970d export GEOIP2_VERSION=a26c6beed77e81553686852dceb6c7fdacc5970d
# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20220411...v2.1-agentzh # Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20230410...v2.1-agentzh
export LUAJIT_VERSION=2.1-20220411 export LUAJIT_VERSION=2.1-20230410
# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master # Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master
export LUA_RESTY_BALANCER=0.04 export LUA_RESTY_BALANCER=0.04
# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.11...master # Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.13...master
export LUA_RESTY_CACHE=0.11 export LUA_RESTY_CACHE=0.13
# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.23...master # Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.27...master
export LUA_RESTY_CORE=0.1.23 export LUA_RESTY_CORE=0.1.27
# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/v0.1.0...master # Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/v0.1.0...master
export LUA_RESTY_COOKIE_VERSION=303e32e512defced053a6484bc0745cf9dc0d39e 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 # Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.16.1...master
export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8 export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8
# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.08...master # Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.09...master
export LUA_RESTY_LOCK=0.08 export LUA_RESTY_LOCK=0.09
# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.10...master # Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.11...master
export LUA_RESTY_UPLOAD_VERSION=0.10 export LUA_RESTY_UPLOAD_VERSION=0.11
# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master # Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master
export LUA_RESTY_STRING_VERSION=0.15 export LUA_RESTY_STRING_VERSION=0.15
# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.16...master # Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.17...master
export LUA_RESTY_MEMCACHED_VERSION=0.16 export LUA_RESTY_MEMCACHED_VERSION=0.17
# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master # Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master
export LUA_RESTY_REDIS_VERSION=0.30 export LUA_RESTY_REDIS_VERSION=0.30
@ -199,13 +199,13 @@ cd "$BUILD_PATH"
get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \ get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \
"https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz" "https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz"
get_src 0e971105e210d272a497567fa2e2c256f4e39b845a5ba80d373e26ba1abfbd85 \ get_src aa961eafb8317e0eb8da37eb6e2c9ff42267edd18b56947384e719b85188f58b \
"https://github.com/simpl/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz" "https://github.com/vision5/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"
get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \ get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \
"https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz" "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" "https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz"
get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \ get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \
@ -241,10 +241,10 @@ get_src 7d5f3439c8df56046d0564b5857fd8a30296ab1bd6df0f048aed7afb56a0a4c2 \
get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \ get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz" "https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
else else
get_src 9db756000578efaecb43bea4fc6cf631aaa80988d86ffe5d3afeb9927895ffad \ get_src bc764db42830aeaf74755754b900253c233ad57498debe7a441cee2c6f4b07c2 \
"https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz" "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" "https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
fi fi
@ -256,7 +256,7 @@ if [[ ${ARCH} == "s390x" ]]; then
get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \ get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \
"https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz" "https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz"
else else
get_src d3f2c870f8f88477b01726b32accab30f6e5d57ae59c5ec87374ff73d0794316 \ get_src 77bbcbb24c3c78f51560017288f3118d995fe71240aa379f5818ff6b166712ff \
"https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz" "https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz"
fi fi
@ -266,7 +266,7 @@ get_src 8d39c6b23f941a2d11571daaccc04e69539a3fcbcc50a631837560d5861a7b96 \
get_src 4c1933434572226942c65b2f2b26c8a536ab76aa771a3c7f6c2629faa764976b \ get_src 4c1933434572226942c65b2f2b26c8a536ab76aa771a3c7f6c2629faa764976b \
"https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz" "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" "https://github.com/openresty/lua-resty-upload/archive/v$LUA_RESTY_UPLOAD_VERSION.tar.gz"
get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \ get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \
@ -279,20 +279,20 @@ if [[ ${ARCH} == "s390x" ]]; then
get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \ get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz" "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
else else
get_src efd6b51520429e64b1bcc10f477d370ebed1631c190f7e4dc270d959a743ad7d \ get_src 39baab9e2b31cc48cecf896cea40ef6e80559054fd8a6e440cc804a858ea84d4 \
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz" "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
fi fi
get_src 0c551d6898f89f876e48730f9b55790d0ba07d5bc0aa6c76153277f63c19489f \ get_src a77b9de160d81712f2f442e1de8b78a5a7ef0d08f13430ff619f79235db974d4 \
"https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz" "https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz"
get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \ get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \
"https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz" "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" "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" "https://github.com/openresty/lua-resty-lock/archive/v$LUA_RESTY_LOCK.tar.gz"
get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \ get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
@ -301,7 +301,7 @@ get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \ get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \
"https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz" "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" "https://github.com/openresty/lua-resty-memcached/archive/v$LUA_RESTY_MEMCACHED_VERSION.tar.gz"
get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \ get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \

View file

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

View file

@ -13,7 +13,7 @@
# limitations under the License. # 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 RUN mkdir -p /opt/third_party/install
COPY . /opt/third_party/ COPY . /opt/third_party/

View file

@ -43,7 +43,7 @@ image:
--pull \ --pull \
--push \ --push \
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \ --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 ETCD_VERSION=3.4.3-0 \
--build-arg K8S_RELEASE=v1.26.0 \ --build-arg K8S_RELEASE=v1.26.0 \
--build-arg RESTY_CLI_VERSION=0.27 \ --build-arg RESTY_CLI_VERSION=0.27 \
@ -64,7 +64,7 @@ build: ensure-buildx
--progress=${PROGRESS} \ --progress=${PROGRESS} \
--pull \ --pull \
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \ --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 ETCD_VERSION=3.4.3-0 \
--build-arg K8S_RELEASE=v1.26.0 \ --build-arg K8S_RELEASE=v1.26.0 \
--build-arg RESTY_CLI_VERSION=0.27 \ --build-arg RESTY_CLI_VERSION=0.27 \

View file

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

View file

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

View file

@ -27,19 +27,44 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver" "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 { type alias struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// NewParser creates a new Alias annotation parser // NewParser creates a new Alias annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation { 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 // Parse parses the annotations contained in the ingress rule
// used to add an alias to the provided hosts // used to add an alias to the provided hosts
func (a alias) Parse(ing *networking.Ingress) (interface{}, error) { 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 { if err != nil {
return []string{}, err return []string{}, err
} }
@ -47,7 +72,7 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
aliases := sets.NewString() aliases := sets.NewString()
for _, alias := range strings.Split(val, ",") { for _, alias := range strings.Split(val, ",") {
alias = strings.TrimSpace(alias) alias = strings.TrimSpace(alias)
if len(alias) == 0 { if alias == "" {
continue continue
} }
@ -61,3 +86,8 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
return l, nil 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" "k8s.io/ingress-nginx/internal/ingress/resolver"
) )
var annotation = parser.GetAnnotationWithPrefix("server-alias") var annotation = parser.GetAnnotationWithPrefix(serverAliasAnnotation)
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
ap := NewParser(&resolver.Mock{}) ap := NewParser(&resolver.Mock{})
@ -36,16 +36,20 @@ func TestParse(t *testing.T) {
} }
testCases := []struct { testCases := []struct {
annotations map[string]string annotations map[string]string
expected []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: "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"}}, {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.*"}}, {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$`}}, {map[string]string{annotation: `~^www\d+\.example\.com$`}, []string{`~^www\d+\.example\.com$`}, false, false},
{map[string]string{annotation: ""}, []string{}}, {map[string]string{annotation: `www.xpto;lala`}, []string{}, false, true},
{map[string]string{}, []string{}}, {map[string]string{annotation: `www.xpto;lala`}, []string{"www.xpto;lala"}, true, false}, // When we skip validation no error should happen
{nil, []string{}}, {map[string]string{annotation: ""}, []string{}, false, true},
{map[string]string{}, []string{}, false, true},
{nil, []string{}, false, true},
} }
ing := &networking.Ingress{ ing := &networking.Ingress{
@ -58,7 +62,16 @@ func TestParse(t *testing.T) {
for _, testCase := range testCases { for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations) 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) { if !reflect.DeepEqual(result, testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations) 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/fastcgi"
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload" "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/ipdenylist"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing" "k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
"k8s.io/ingress-nginx/internal/ingress/annotations/log" "k8s.io/ingress-nginx/internal/ingress/annotations/log"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
@ -86,37 +86,36 @@ type Ingress struct {
CorsConfig cors.Config CorsConfig cors.Config
CustomHTTPErrors []int CustomHTTPErrors []int
DefaultBackend *apiv1.Service DefaultBackend *apiv1.Service
//TODO: Change this back into an error when https://github.com/imdario/mergo/issues/100 is resolved FastCGI fastcgi.Config
FastCGI fastcgi.Config Denied *string
Denied *string ExternalAuth authreq.Config
ExternalAuth authreq.Config EnableGlobalAuth bool
EnableGlobalAuth bool HTTP2PushPreload bool
HTTP2PushPreload bool Opentracing opentracing.Config
Opentracing opentracing.Config Opentelemetry opentelemetry.Config
Opentelemetry opentelemetry.Config Proxy proxy.Config
Proxy proxy.Config ProxySSL proxyssl.Config
ProxySSL proxyssl.Config RateLimit ratelimit.Config
RateLimit ratelimit.Config GlobalRateLimit globalratelimit.Config
GlobalRateLimit globalratelimit.Config Redirect redirect.Config
Redirect redirect.Config Rewrite rewrite.Config
Rewrite rewrite.Config Satisfy string
Satisfy string ServerSnippet string
ServerSnippet string ServiceUpstream bool
ServiceUpstream bool SessionAffinity sessionaffinity.Config
SessionAffinity sessionaffinity.Config SSLPassthrough bool
SSLPassthrough bool UsePortInRedirects bool
UsePortInRedirects bool UpstreamHashBy upstreamhashby.Config
UpstreamHashBy upstreamhashby.Config LoadBalancing string
LoadBalancing string UpstreamVhost string
UpstreamVhost string Denylist ipdenylist.SourceRange
Whitelist ipwhitelist.SourceRange XForwardedPrefix string
Denylist ipdenylist.SourceRange SSLCipher sslcipher.Config
XForwardedPrefix string Logs log.Config
SSLCipher sslcipher.Config ModSecurity modsecurity.Config
Logs log.Config Mirror mirror.Config
ModSecurity modsecurity.Config StreamSnippet string
Mirror mirror.Config Allowlist ipallowlist.SourceRange
StreamSnippet string
} }
// Extractor defines the annotation parsers to be used in the extraction of annotations // 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), "UpstreamHashBy": upstreamhashby.NewParser(cfg),
"LoadBalancing": loadbalancing.NewParser(cfg), "LoadBalancing": loadbalancing.NewParser(cfg),
"UpstreamVhost": upstreamvhost.NewParser(cfg), "UpstreamVhost": upstreamvhost.NewParser(cfg),
"Whitelist": ipwhitelist.NewParser(cfg), "Allowlist": ipallowlist.NewParser(cfg),
"Denylist": ipdenylist.NewParser(cfg), "Denylist": ipdenylist.NewParser(cfg),
"XForwardedPrefix": xforwardedprefix.NewParser(cfg), "XForwardedPrefix": xforwardedprefix.NewParser(cfg),
"SSLCipher": sslcipher.NewParser(cfg), "SSLCipher": sslcipher.NewParser(cfg),
@ -173,16 +172,23 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
} }
// Extract extracts the annotations from an Ingress // 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{ pia := &Ingress{
ObjectMeta: ing.ObjectMeta, ObjectMeta: ing.ObjectMeta,
} }
data := make(map[string]interface{}) data := make(map[string]interface{})
for name, annotationParser := range e.annotations { for name, annotationParser := range e.annotations {
if err := annotationParser.Validate(ing.GetAnnotations()); err != nil {
return nil, errors.NewRiskyAnnotations(name)
}
val, err := annotationParser.Parse(ing) val, err := annotationParser.Parse(ing)
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val) klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
if err != nil { if err != nil {
if errors.IsValidationError(err) {
klog.ErrorS(err, "ingress contains invalid annotation value")
return nil, err
}
if errors.IsMissingAnnotations(err) { if errors.IsMissingAnnotations(err) {
continue continue
} }
@ -220,5 +226,5 @@ func (e Extractor) Extract(ing *networking.Ingress) *Ingress {
klog.ErrorS(err, "unexpected error merging extracted annotations") 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) { 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{ return &resolver.AuthSSLCert{
Secret: name, Secret: name,
CAFileName: "/opt/ca.pem", CAFileName: "/opt/ca.pem",
@ -134,8 +138,11 @@ func TestSSLPassthrough(t *testing.T) {
for _, foo := range fooAnns { for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations) ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SSLPassthrough r, err := ec.Extract(ing)
if r != foo.er { 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) t.Errorf("Returned %v but expected %v", r, foo.er)
} }
} }
@ -158,8 +165,11 @@ func TestUpstreamHashBy(t *testing.T) {
for _, foo := range fooAnns { for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations) ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).UpstreamHashBy.UpstreamHashBy r, err := ec.Extract(ing)
if r != foo.er { 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) t.Errorf("Returned %v but expected %v", r, foo.er)
} }
} }
@ -185,7 +195,11 @@ func TestAffinitySession(t *testing.T) {
for _, foo := range fooAnns { for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations) 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) t.Logf("Testing pass %v %v", foo.affinitytype, foo.cookiename)
if r.Type != foo.affinitytype { if r.Type != foo.affinitytype {
@ -228,7 +242,11 @@ func TestCors(t *testing.T) {
for _, foo := range fooAnns { for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations) 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) t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials)
if r.CorsEnabled != foo.corsenabled { if r.CorsEnabled != foo.corsenabled {
@ -256,9 +274,9 @@ func TestCors(t *testing.T) {
if r.CorsAllowCredentials != foo.credentials { if r.CorsAllowCredentials != foo.credentials {
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials) t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
} }
} }
} }
func TestCustomHTTPErrors(t *testing.T) { func TestCustomHTTPErrors(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{}) ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress() ing := buildIngress()
@ -277,7 +295,11 @@ func TestCustomHTTPErrors(t *testing.T) {
for _, foo := range fooAnns { for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations) 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 // Check that expected codes were created
for i := range foo.er { for i := range foo.er {

View file

@ -32,13 +32,56 @@ import (
"k8s.io/ingress-nginx/pkg/util/file" "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 ( var (
authTypeRegex = regexp.MustCompile(`basic|digest`) authTypeRegex = regexp.MustCompile(`basic|digest`)
authSecretTypeRegex = regexp.MustCompile(`auth-file|auth-map`)
// AuthDirectory default directory used to store files // AuthDirectory default directory used to store files
// to authenticate request // to authenticate request
AuthDirectory = "/etc/ingress-controller/auth" 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 ( const (
fileAuth = "auth-file" fileAuth = "auth-file"
mapAuth = "auth-map" mapAuth = "auth-map"
@ -85,13 +128,18 @@ func (bd1 *Config) Equal(bd2 *Config) bool {
} }
type auth struct { type auth struct {
r resolver.Resolver r resolver.Resolver
authDirectory string authDirectory string
annotationConfig parser.Annotation
} }
// NewParser creates a new authentication annotation parser // NewParser creates a new authentication annotation parser
func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotation { 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 // 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 // and generated an htpasswd compatible file to be used as source
// during the authentication process // during the authentication process
func (a auth) Parse(ing *networking.Ingress) (interface{}, error) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -109,21 +157,24 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
} }
var secretType string var secretType string
secretType, err = parser.GetStringAnnotation("auth-secret-type", ing) secretType, err = parser.GetStringAnnotation(authSecretTypeAnnotation, ing, a.annotationConfig.Annotations)
if err != nil { if err != nil {
if ing_errors.IsValidationError(err) {
return nil, err
}
secretType = fileAuth secretType = fileAuth
} }
s, err := parser.GetStringAnnotation("auth-secret", ing) s, err := parser.GetStringAnnotation(AuthSecretAnnotation, ing, a.annotationConfig.Annotations)
if err != nil { if err != nil {
return nil, ing_errors.LocationDenied{ return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("error reading secret name from annotation: %w", err), Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
} }
} }
sns, sname, err := cache.SplitMetaNamespaceKey(s) sns, sname, err := cache.SplitMetaNamespaceKey(s)
if err != nil { if err != nil {
return nil, ing_errors.LocationDenied{ return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("error reading secret name from annotation: %w", err), 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 == "" { if sns == "" {
sns = ing.Namespace 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) name := fmt.Sprintf("%v/%v", sns, sname)
secret, err := a.r.GetSecret(name) secret, err := a.r.GetSecret(name)
if err != nil { if err != nil {
return nil, ing_errors.LocationDenied{ return nil, ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error reading secret %s: %w", name, err), 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) 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 return nil, err
} }
default: 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), 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 { func dumpSecretAuthFile(filename string, secret *api.Secret) error {
val, ok := secret.Data["auth"] val, ok := secret.Data["auth"]
if !ok { 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), Reason: fmt.Errorf("the secret %s does not contain a key with value auth", secret.Name),
} }
} }
err := os.WriteFile(filename, val, file.ReadWriteByUser) err := os.WriteFile(filename, val, file.ReadWriteByUser)
if err != nil { if err != nil {
return ing_errors.LocationDenied{ return ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error creating password file: %w", err), 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) err := os.WriteFile(filename, []byte(builder.String()), file.ReadWriteByUser)
if err != nil { if err != nil {
return ing_errors.LocationDenied{ return ing_errors.LocationDeniedError{
Reason: fmt.Errorf("unexpected error creating password file: %w", err), Reason: fmt.Errorf("unexpected error creating password file: %w", err),
} }
} }
return nil 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" api "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1" networking "k8s.io/api/networking/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver" "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 { func buildIngress() *networking.Ingress {
defaultBackend := networking.IngressBackend{ defaultBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{ Service: &networking.IngressServiceBackend{
@ -79,14 +89,19 @@ type mockSecret struct {
} }
func (m mockSecret) GetSecret(name string) (*api.Secret, error) { 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) 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{ return &api.Secret{
ObjectMeta: meta_v1.ObjectMeta{ ObjectMeta: meta_v1.ObjectMeta{
Namespace: api.NamespaceDefault, Namespace: ns,
Name: "demo-secret", Name: demoSecret,
}, },
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")}, Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
}, nil }, nil
@ -106,13 +121,91 @@ func TestIngressAuthBadAuthType(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "invalid" data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "invalid"
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t) _, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir) 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) _, err := NewParser(dir, &mockSecret{}).Parse(ing)
if err.Error() != expected.Error() { if err.Error() != expected.Error() {
t.Errorf("expected '%v' but got '%v'", expected, err) t.Errorf("expected '%v' but got '%v'", expected, err)
@ -123,13 +216,13 @@ func TestInvalidIngressAuthNoSecret(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic" data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t) _, dir, _ := dummySecretContent(t)
defer os.RemoveAll(dir) 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"), Reason: errors.New("error reading secret name from annotation: ingress rule without annotations"),
} }
_, err := NewParser(dir, &mockSecret{}).Parse(ing) _, err := NewParser(dir, &mockSecret{}).Parse(ing)
@ -142,9 +235,9 @@ func TestIngressAuth(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic" data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret" data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-" data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t) _, dir, _ := dummySecretContent(t)
@ -158,10 +251,10 @@ func TestIngressAuth(t *testing.T) {
if !ok { if !ok {
t.Errorf("expected a BasicDigest type") 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) 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) t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
} }
if !auth.Secured { if !auth.Secured {
@ -173,9 +266,9 @@ func TestIngressAuthWithoutSecret(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic" data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix("auth-secret")] = "invalid-secret" data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "invalid-secret"
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-" data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t) _, dir, _ := dummySecretContent(t)
@ -191,10 +284,10 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic" data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret" data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
data[parser.GetAnnotationWithPrefix("auth-secret-type")] = "invalid-type" data[parser.GetAnnotationWithPrefix(authSecretTypeAnnotation)] = "invalid-type"
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-" data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, dir, _ := dummySecretContent(t) _, 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())) dir, err := os.MkdirTemp("", fmt.Sprintf("%v", time.Now().Unix()))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -217,7 +310,10 @@ func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
t.Error(err) t.Error(err)
} }
defer tmpfile.Close() 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 return tmpfile.Name(), dir, s
} }

View file

@ -24,6 +24,7 @@ import (
"k8s.io/klog/v2" "k8s.io/klog/v2"
networking "k8s.io/api/networking/v1" networking "k8s.io/api/networking/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
@ -31,6 +32,125 @@ import (
"k8s.io/ingress-nginx/pkg/util/sets" "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 // Config returns external authentication configuration for an Ingress rule
type Config struct { type Config struct {
URL string `json:"url"` URL string `json:"url"`
@ -45,6 +165,7 @@ type Config struct {
AuthCacheKey string `json:"authCacheKey"` AuthCacheKey string `json:"authCacheKey"`
AuthCacheDuration []string `json:"authCacheDuration"` AuthCacheDuration []string `json:"authCacheDuration"`
KeepaliveConnections int `json:"keepaliveConnections"` KeepaliveConnections int `json:"keepaliveConnections"`
KeepaliveShareVars bool `json:"keepaliveShareVars"`
KeepaliveRequests int `json:"keepaliveRequests"` KeepaliveRequests int `json:"keepaliveRequests"`
KeepaliveTimeout int `json:"keepaliveTimeout"` KeepaliveTimeout int `json:"keepaliveTimeout"`
ProxySetHeaders map[string]string `json:"proxySetHeaders,omitempty"` 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 // fallback values when no keepalive parameters are set
const ( const (
defaultKeepaliveConnections = 0 defaultKeepaliveConnections = 0
defaultKeepaliveShareVars = false
defaultKeepaliveRequests = 1000 defaultKeepaliveRequests = 1000
defaultKeepaliveTimeout = 60 defaultKeepaliveTimeout = 60
) )
@ -105,6 +227,10 @@ func (e1 *Config) Equal(e2 *Config) bool {
return false return false
} }
if e1.KeepaliveShareVars != e2.KeepaliveShareVars {
return false
}
if e1.KeepaliveRequests != e2.KeepaliveRequests { if e1.KeepaliveRequests != e2.KeepaliveRequests {
return false return false
} }
@ -121,24 +247,15 @@ func (e1 *Config) Equal(e2 *Config) bool {
} }
var ( 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\-_]+$`) headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
statusCodeRegex = regexp.MustCompile(`^[\d]{3}$`) 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 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 // ValidMethod checks is the provided string a valid HTTP method
func ValidMethod(method string) bool { func ValidMethod(method string) bool {
if len(method) == 0 { return methodsRegex.MatchString(method)
return false
}
for _, m := range methods {
if method == m {
return true
}
}
return false
} }
// ValidHeader checks is the provided string satisfies the header's name regex // ValidHeader checks is the provided string satisfies the header's name regex
@ -156,7 +273,7 @@ func ValidCacheDuration(duration string) bool {
seenDuration := false seenDuration := false
for _, element := range elements { for _, element := range elements {
if len(element) == 0 { if element == "" {
continue continue
} }
if statusCodeRegex.MatchString(element) { if statusCodeRegex.MatchString(element) {
@ -173,55 +290,72 @@ func ValidCacheDuration(duration string) bool {
} }
type authReq struct { type authReq struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// NewParser creates a new authentication request annotation parser // NewParser creates a new authentication request annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation { func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authReq{r} return authReq{
r: r,
annotationConfig: authReqAnnotations,
}
} }
// ParseAnnotations parses the annotations contained in the ingress // ParseAnnotations parses the annotations contained in the ingress
// rule used to use an Config URL as source for authentication // 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) { func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
// Required Parameters // Required Parameters
urlString, err := parser.GetStringAnnotation("auth-url", ing) urlString, err := parser.GetStringAnnotation(authReqURLAnnotation, ing, a.annotationConfig.Annotations)
if err != nil { if err != nil {
return nil, err return nil, err
} }
authURL, err := parser.StringToURL(urlString) authURL, err := parser.StringToURL(urlString)
if err != nil { 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) authMethod, err := parser.GetStringAnnotation(authReqMethodAnnotation, ing, a.annotationConfig.Annotations)
if len(authMethod) != 0 && !ValidMethod(authMethod) { if err != nil {
return nil, ing_errors.NewLocationDenied("invalid HTTP method") if ing_errors.IsValidationError(err) {
return nil, ing_errors.NewLocationDenied("invalid HTTP method")
}
} }
// Optional Parameters // Optional Parameters
signIn, err := parser.GetStringAnnotation("auth-signin", ing) signIn, err := parser.GetStringAnnotation(authReqSigninAnnotation, ing, a.annotationConfig.Annotations)
if err != nil { 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") 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 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") 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 { if err != nil {
klog.V(3).InfoS("auth-snippet annotation is undefined and will not be set") 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 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") 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 { if err != nil {
klog.V(3).InfoS("auth-keepalive annotation is undefined and will be set to its default value") klog.V(3).InfoS("auth-keepalive annotation is undefined and will be set to its default value")
keepaliveConnections = defaultKeepaliveConnections 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 { 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 keepaliveRequests = defaultKeepaliveRequests
} }
if keepaliveRequests <= 0 { if keepaliveRequests <= 0 {
@ -248,7 +388,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
keepaliveConnections = 0 keepaliveConnections = 0
} }
keepaliveTimeout, err := parser.GetIntAnnotation("auth-keepalive-timeout", ing) keepaliveTimeout, err := parser.GetIntAnnotation(authReqKeepaliveTimeout, ing, a.annotationConfig.Annotations)
if err != nil { if err != nil {
klog.V(3).InfoS("auth-keepalive-timeout annotation is undefined and will be set to its default value") klog.V(3).InfoS("auth-keepalive-timeout annotation is undefined and will be set to its default value")
keepaliveTimeout = defaultKeepaliveTimeout keepaliveTimeout = defaultKeepaliveTimeout
@ -258,15 +398,21 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
keepaliveConnections = 0 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) authCacheDuration, err := ParseStringToCacheDurations(durstr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
responseHeaders := []string{} responseHeaders := []string{}
hstr, _ := parser.GetStringAnnotation("auth-response-headers", ing) hstr, err := parser.GetStringAnnotation(authReqResponseHeadersAnnotation, ing, a.annotationConfig.Annotations)
if len(hstr) != 0 { if err != nil && ing_errors.IsValidationError(err) {
return nil, ing_errors.NewLocationDenied("validation error")
}
if hstr != "" {
harr := strings.Split(hstr, ",") harr := strings.Split(hstr, ",")
for _, header := range harr { for _, header := range harr {
header = strings.TrimSpace(header) 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 { 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 var proxySetHeaders map[string]string
@ -301,9 +466,15 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
proxySetHeaders = proxySetHeadersMapContents.Data 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{ return &Config{
URL: urlString, URL: urlString,
@ -317,6 +488,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
AuthCacheKey: authCacheKey, AuthCacheKey: authCacheKey,
AuthCacheDuration: authCacheDuration, AuthCacheDuration: authCacheDuration,
KeepaliveConnections: keepaliveConnections, KeepaliveConnections: keepaliveConnections,
KeepaliveShareVars: keepaliveShareVars,
KeepaliveRequests: keepaliveRequests, KeepaliveRequests: keepaliveRequests,
KeepaliveTimeout: keepaliveTimeout, KeepaliveTimeout: keepaliveTimeout,
ProxySetHeaders: proxySetHeaders, 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) // It will always return at least one duration (the default duration)
func ParseStringToCacheDurations(input string) ([]string, error) { func ParseStringToCacheDurations(input string) ([]string, error) {
authCacheDuration := []string{} authCacheDuration := []string{}
if len(input) != 0 { if input != "" {
arr := strings.Split(input, ",") arr := strings.Split(input, ",")
for _, duration := range arr { for _, duration := range arr {
duration = strings.TrimSpace(duration) duration = strings.TrimSpace(duration)
@ -348,3 +520,12 @@ func ParseStringToCacheDurations(input string) ([]string, error) {
} }
return authCacheDuration, nil 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 package authreq
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
@ -113,7 +112,7 @@ func TestAnnotations(t *testing.T) {
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
data[parser.GetAnnotationWithPrefix("auth-signin-redirect-param")] = test.signinURLRedirectParam 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-request-redirect")] = test.requestRedirect
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet
data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey
@ -192,11 +191,13 @@ func TestHeaderAnnotations(t *testing.T) {
i, err := NewParser(&resolver.Mock{}).Parse(ing) i, err := NewParser(&resolver.Mock{}).Parse(ing)
if test.expErr { if test.expErr {
if err == nil { if err == nil {
t.Error("expected error but retuned nil") t.Errorf("%v expected error but retuned nil", test.title)
} }
continue continue
} }
if err != nil {
t.Errorf("no error was expected but %v happened in %s", err, test.title)
}
u, ok := i.(*Config) u, ok := i.(*Config)
if !ok { if !ok {
t.Errorf("%v: expected an External type", test.title) t.Errorf("%v: expected an External type", test.title)
@ -266,28 +267,31 @@ func TestKeepaliveAnnotations(t *testing.T) {
title string title string
url string url string
keepaliveConnections string keepaliveConnections string
keepaliveShareVars string
keepaliveRequests string keepaliveRequests string
keepaliveTimeout string keepaliveTimeout string
expectedConnections int expectedConnections int
expectedShareVars bool
expectedRequests int expectedRequests int
expectedTimeout int expectedTimeout int
}{ }{
{"all set", "http://goog.url", "5", "500", "50", 5, 500, 50}, {"all set", "http://goog.url", "5", "false", "500", "50", 5, false, 500, 50},
{"no annotation", "http://goog.url", "", "", "", defaultKeepaliveConnections, defaultKeepaliveRequests, defaultKeepaliveTimeout}, {"no annotation", "http://goog.url", "", "", "", "", defaultKeepaliveConnections, defaultKeepaliveShareVars, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"default for connections", "http://goog.url", "x", "500", "50", defaultKeepaliveConnections, 500, 50}, {"default for connections", "http://goog.url", "x", "true", "500", "50", defaultKeepaliveConnections, true, 500, 50},
{"default for requests", "http://goog.url", "5", "x", "50", 5, defaultKeepaliveRequests, 50}, {"default for requests", "http://goog.url", "5", "x", "dummy", "50", 5, defaultKeepaliveShareVars, defaultKeepaliveRequests, 50},
{"default for invalid timeout", "http://goog.url", "5", "500", "x", 5, 500, defaultKeepaliveTimeout}, {"default for invalid timeout", "http://goog.url", "5", "t", "500", "x", 5, true, 500, defaultKeepaliveTimeout},
{"variable in host", "http://$host:5000/a/b", "5", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout}, {"variable in host", "http://$host:5000/a/b", "5", "1", "", "", 0, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"variable in path", "http://goog.url:5000/$path", "5", "", "", 5, defaultKeepaliveRequests, defaultKeepaliveTimeout}, {"variable in path", "http://goog.url:5000/$path", "5", "t", "", "", 5, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative connections", "http://goog.url", "-2", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout}, {"negative connections", "http://goog.url", "-2", "f", "", "", 0, false, defaultKeepaliveRequests, defaultKeepaliveTimeout},
{"negative requests", "http://goog.url", "5", "-1", "", 0, -1, defaultKeepaliveTimeout}, {"negative requests", "http://goog.url", "5", "True", "-1", "", 0, true, -1, defaultKeepaliveTimeout},
{"negative timeout", "http://goog.url", "5", "", "-1", 0, defaultKeepaliveRequests, -1}, {"negative timeout", "http://goog.url", "5", "0", "", "-1", 0, false, defaultKeepaliveRequests, -1},
{"negative request and timeout", "http://goog.url", "5", "-2", "-3", 0, -2, -3}, {"negative request and timeout", "http://goog.url", "5", "False", "-2", "-3", 0, false, -2, -3},
} }
for _, test := range tests { for _, test := range tests {
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
data[parser.GetAnnotationWithPrefix("auth-keepalive")] = test.keepaliveConnections 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-timeout")] = test.keepaliveTimeout
data[parser.GetAnnotationWithPrefix("auth-keepalive-requests")] = test.keepaliveRequests 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) 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 { if u.KeepaliveRequests != test.expectedRequests {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedRequests, u.KeepaliveRequests) 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) { func TestParseStringToCacheDurations(t *testing.T) {
tests := []struct { tests := []struct {
title string title string
duration string duration string
@ -337,7 +344,6 @@ func TestParseStringToCacheDurations(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
dur, err := ParseStringToCacheDurations(test.duration) dur, err := ParseStringToCacheDurations(test.duration)
if test.expErr { if test.expErr {
if err == nil { if err == nil {

View file

@ -23,23 +23,51 @@ import (
"k8s.io/ingress-nginx/internal/ingress/resolver" "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 { type authReqGlobal struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// NewParser creates a new authentication request annotation parser // NewParser creates a new authentication request annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation { func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authReqGlobal{r} return authReqGlobal{
r: r,
annotationConfig: globalAuthAnnotations,
}
} }
// ParseAnnotations parses the annotations contained in the ingress // ParseAnnotations parses the annotations contained in the ingress
// rule used to enable or disable global external authentication // rule used to enable or disable global external authentication
func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) { func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
enableGlobalAuth, err := parser.GetBoolAnnotation(enableGlobalAuthAnnotation, ing, a.annotationConfig.Annotations)
enableGlobalAuth, err := parser.GetBoolAnnotation("enable-global-auth", ing)
if err != nil { if err != nil {
enableGlobalAuth = true enableGlobalAuth = true
} }
return enableGlobalAuth, nil 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" data[parser.GetAnnotationWithPrefix("enable-global-auth")] = "false"
ing.SetAnnotations(data) 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) u, ok := i.(bool)
if !ok { if !ok {
t.Errorf("expected a Config type") t.Errorf("expected a Config type")

View file

@ -18,11 +18,10 @@ package authtls
import ( import (
"fmt" "fmt"
"regexp"
networking "k8s.io/api/networking/v1" networking "k8s.io/api/networking/v1"
"regexp"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver" "k8s.io/ingress-nginx/internal/ingress/resolver"
@ -32,13 +31,64 @@ import (
const ( const (
defaultAuthTLSDepth = 1 defaultAuthTLSDepth = 1
defaultAuthVerifyClient = "on" 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 ( var (
regexChars = regexp.QuoteMeta(`()|=`)
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`) 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 // Config contains the AuthSSLCert used for mutual authentication
// and the configured ValidationDepth // and the configured ValidationDepth
type Config struct { type Config struct {
@ -79,12 +129,16 @@ func (assl1 *Config) Equal(assl2 *Config) bool {
} }
// NewParser creates a new TLS authentication annotation parser // NewParser creates a new TLS authentication annotation parser
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation { func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return authTLS{resolver} return authTLS{
r: r,
annotationConfig: authTLSAnnotations,
}
} }
type authTLS struct { type authTLS struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// Parse parses the annotations contained in the ingress // Parse parses the annotations contained in the ingress
@ -93,47 +147,75 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) {
var err error var err error
config := &Config{} config := &Config{}
tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing) tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing, a.annotationConfig.Annotations)
if err != nil { if err != nil {
return &Config{}, err return &Config{}, err
} }
_, _, err = k8s.ParseNameNS(tlsauthsecret) ns, _, err := k8s.ParseNameNS(tlsauthsecret)
if err != nil { if err != nil {
return &Config{}, ing_errors.NewLocationDenied(err.Error()) 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) authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
if err != nil { if err != nil {
e := fmt.Errorf("error obtaining certificate: %w", err) 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.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) { if err != nil || !authVerifyClientRegex.MatchString(config.VerifyClient) {
config.VerifyClient = defaultAuthVerifyClient 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 { if err != nil || config.ValidationDepth == 0 {
config.ValidationDepth = defaultAuthTLSDepth 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 err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.ErrorPage = "" 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 err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.PassCertToUpstream = false config.PassCertToUpstream = false
} }
config.MatchCN, err = parser.GetStringAnnotation("auth-tls-match-cn", ing) config.MatchCN, err = parser.GetStringAnnotation(annotationAuthTLSMatchCN, ing, a.annotationConfig.Annotations)
if err != nil || !commonNameRegex.MatchString(config.MatchCN) { if err != nil {
if ing_errors.IsValidationError(err) {
return &Config{}, err
}
config.MatchCN = "" config.MatchCN = ""
} }
return config, nil 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" "k8s.io/ingress-nginx/internal/ingress/resolver"
) )
const (
defaultDemoSecret = "default/demo-secret"
off = "off"
)
func buildIngress() *networking.Ingress { func buildIngress() *networking.Ingress {
defaultBackend := networking.IngressBackend{ defaultBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{ Service: &networking.IngressServiceBackend{
@ -77,23 +82,22 @@ type mockSecret struct {
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS // GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) { 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 nil, errors.Errorf("there is no secret with name %v", name)
} }
return &resolver.AuthSSLCert{ return &resolver.AuthSSLCert{
Secret: "default/demo-secret", Secret: defaultDemoSecret,
CAFileName: "/ssl/ca.crt", CAFileName: "/ssl/ca.crt",
CASHA: "abc", CASHA: "abc",
}, nil }, nil
} }
func TestAnnotations(t *testing.T) { func TestAnnotations(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret" data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = defaultDemoSecret
ing.SetAnnotations(data) ing.SetAnnotations(data)
@ -108,7 +112,7 @@ func TestAnnotations(t *testing.T) {
t.Errorf("expected *Config but got %v", u) t.Errorf("expected *Config but got %v", u)
} }
secret, err := fakeSecret.GetAuthCertificate("default/demo-secret") secret, err := fakeSecret.GetAuthCertificate(defaultDemoSecret)
if err != nil { if err != nil {
t.Errorf("unexpected error getting secret %v", err) 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) t.Errorf("expected empty string, but got %v", u.MatchCN)
} }
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "off" data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = off
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "2" data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "2"
data[parser.GetAnnotationWithPrefix("auth-tls-error-page")] = "ok.com/error" data[parser.GetAnnotationWithPrefix(annotationAuthTLSErrorPage)] = "ok.com/error"
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "true" data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "true"
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "CN=hello-app" data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "CN=(hello-app|ok|goodbye)"
ing.SetAnnotations(data) ing.SetAnnotations(data)
@ -153,8 +157,8 @@ func TestAnnotations(t *testing.T) {
if u.AuthSSLCert.Secret != secret.Secret { if u.AuthSSLCert.Secret != secret.Secret {
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret) t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
} }
if u.VerifyClient != "off" { if u.VerifyClient != off {
t.Errorf("expected %v but got %v", "off", u.VerifyClient) t.Errorf("expected %v but got %v", off, u.VerifyClient)
} }
if u.ValidationDepth != 2 { if u.ValidationDepth != 2 {
t.Errorf("expected %v but got %v", 2, u.ValidationDepth) t.Errorf("expected %v but got %v", 2, u.ValidationDepth)
@ -165,8 +169,8 @@ func TestAnnotations(t *testing.T) {
if u.PassCertToUpstream != true { if u.PassCertToUpstream != true {
t.Errorf("expected %v but got %v", true, u.PassCertToUpstream) t.Errorf("expected %v but got %v", true, u.PassCertToUpstream)
} }
if u.MatchCN != "CN=hello-app" { if u.MatchCN != "CN=(hello-app|ok|goodbye)" {
t.Errorf("expected %v but got %v", "CN=hello-app", u.MatchCN) 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 // Invalid NameSpace
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "demo-secret" data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "demo-secret"
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing) _, err = NewParser(fakeSecret).Parse(ing)
if err == nil { if err == nil {
t.Errorf("Expected error with ingress but got 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 // Invalid Auth Certificate
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/invalid-demo-secret" data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/invalid-demo-secret"
ing.SetAnnotations(data) ing.SetAnnotations(data)
_, err = NewParser(fakeSecret).Parse(ing) _, err = NewParser(fakeSecret).Parse(ing)
if err == nil { if err == nil {
@ -198,11 +211,38 @@ func TestInvalidAnnotations(t *testing.T) {
} }
// Invalid optional Annotations // Invalid optional Annotations
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret" data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/demo-secret"
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "w00t"
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "abcd" data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = "w00t"
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "nahh" ing.SetAnnotations(data)
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "<script>nope</script>" _, 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) ing.SetAnnotations(data)
i, err := NewParser(fakeSecret).Parse(ing) i, err := NewParser(fakeSecret).Parse(ing)
@ -226,28 +266,21 @@ func TestInvalidAnnotations(t *testing.T) {
if u.MatchCN != "" { if u.MatchCN != "" {
t.Errorf("expected empty string but got %v", u.MatchCN) t.Errorf("expected empty string but got %v", u.MatchCN)
} }
} }
func TestEquals(t *testing.T) { func TestEquals(t *testing.T) {
cfg1 := &Config{} cfg1 := &Config{}
cfg2 := &Config{} cfg2 := &Config{}
// Same config
result := cfg1.Equal(cfg1)
if result != true {
t.Errorf("Expected true")
}
// compare nil // compare nil
result = cfg1.Equal(nil) result := cfg1.Equal(nil)
if result != false { if result != false {
t.Errorf("Expected false") t.Errorf("Expected false")
} }
// Different Certs // Different Certs
sslCert1 := resolver.AuthSSLCert{ sslCert1 := resolver.AuthSSLCert{
Secret: "default/demo-secret", Secret: defaultDemoSecret,
CAFileName: "/ssl/ca.crt", CAFileName: "/ssl/ca.crt",
CASHA: "abc", CASHA: "abc",
} }
@ -266,7 +299,7 @@ func TestEquals(t *testing.T) {
// Different Verify Client // Different Verify Client
cfg1.VerifyClient = "on" cfg1.VerifyClient = "on"
cfg2.VerifyClient = "off" cfg2.VerifyClient = off
result = cfg1.Equal(cfg2) result = cfg1.Equal(cfg2)
if result != false { if result != false {
t.Errorf("Expected false") t.Errorf("Expected false")

View file

@ -17,49 +17,70 @@ limitations under the License.
package backendprotocol package backendprotocol
import ( import (
"regexp"
"strings"
networking "k8s.io/api/networking/v1" networking "k8s.io/api/networking/v1"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver" "k8s.io/ingress-nginx/internal/ingress/resolver"
) )
// HTTP protocol var validProtocols = []string{"auto_http", "http", "https", "grpc", "grpcs", "fcgi"}
const HTTP = "HTTP"
var ( const (
validProtocols = regexp.MustCompile(`^(AUTO_HTTP|HTTP|HTTPS|GRPC|GRPCS|FCGI)$`) 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 { type backendProtocol struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// NewParser creates a new backend protocol annotation parser // NewParser creates a new backend protocol annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation { 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 // ParseAnnotations parses the annotations contained in the ingress
// rule used to indicate the backend protocol. // rule used to indicate the backend protocol.
func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) { func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) {
if ing.GetAnnotations() == nil { 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 { 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)) return http, nil
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 proto, 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) { func TestParseInvalidAnnotations(t *testing.T) {
ing := buildIngress() ing := buildIngress()
@ -56,7 +57,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok { if !ok {
t.Errorf("expected a string type") t.Errorf("expected a string type")
} }
if val != "HTTP" { if val != http {
t.Errorf("expected HTTPS but %v returned", val) t.Errorf("expected HTTPS but %v returned", val)
} }
@ -72,12 +73,12 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok { if !ok {
t.Errorf("expected a string type") t.Errorf("expected a string type")
} }
if val != "HTTP" { if val != http {
t.Errorf("expected HTTPS but %v returned", val) t.Errorf("expected HTTPS but %v returned", val)
} }
// Test invalid annotation set // Test invalid annotation set
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "INVALID" data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = "INVALID"
ing.SetAnnotations(data) ing.SetAnnotations(data)
i, err = NewParser(&resolver.Mock{}).Parse(ing) i, err = NewParser(&resolver.Mock{}).Parse(ing)
@ -88,7 +89,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
if !ok { if !ok {
t.Errorf("expected a string type") t.Errorf("expected a string type")
} }
if val != "HTTP" { if val != http {
t.Errorf("expected HTTPS but %v returned", val) t.Errorf("expected HTTPS but %v returned", val)
} }
} }
@ -97,7 +98,7 @@ func TestParseAnnotations(t *testing.T) {
ing := buildIngress() ing := buildIngress()
data := map[string]string{} data := map[string]string{}
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS" data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = " HTTPS "
ing.SetAnnotations(data) ing.SetAnnotations(data)
i, err := NewParser(&resolver.Mock{}).Parse(ing) i, err := NewParser(&resolver.Mock{}).Parse(ing)

View file

@ -18,14 +18,82 @@ package canary
import ( import (
networking "k8s.io/api/networking/v1" networking "k8s.io/api/networking/v1"
"k8s.io/klog/v2"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors" "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver" "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 { type canary struct {
r resolver.Resolver r resolver.Resolver
annotationConfig parser.Annotation
} }
// Config returns the configuration rules for setting up the Canary // 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 // NewParser parses the ingress for canary related annotations
func NewParser(r resolver.Resolver) parser.IngressAnnotation { func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return canary{r} return canary{
r: r,
annotationConfig: CanaryAnnotations,
}
} }
// Parse parses the annotations contained in the ingress // Parse parses the annotations contained in the ingress
@ -50,45 +121,75 @@ func (c canary) Parse(ing *networking.Ingress) (interface{}, error) {
config := &Config{} config := &Config{}
var err error var err error
config.Enabled, err = parser.GetBoolAnnotation("canary", ing) config.Enabled, err = parser.GetBoolAnnotation(canaryAnnotation, ing, c.annotationConfig.Annotations)
if err != nil { if err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to 'false'", canaryAnnotation)
}
config.Enabled = false 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to '0'", canaryWeightAnnotation)
}
config.Weight = 0 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to '100'", canaryWeightTotalAnnotation)
}
config.WeightTotal = 100 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderAnnotation)
}
config.Header = "" 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderValueAnnotation)
}
config.HeaderValue = "" 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderPatternAnnotation)
}
config.HeaderPattern = "" 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 err != nil {
if errors.IsValidationError(err) {
klog.Warningf("%s is invalid, defaulting to ''", canaryByCookieAnnotation)
}
config.Cookie = "" config.Cookie = ""
} }
if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0 || if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0 ||
len(config.HeaderPattern) > 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 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 package canary
import ( import (
"strconv"
"testing" "testing"
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
@ -24,8 +25,6 @@ import (
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"strconv"
"k8s.io/ingress-nginx/internal/ingress/resolver" "k8s.io/ingress-nginx/internal/ingress/resolver"
) )
@ -93,7 +92,6 @@ func TestCanaryInvalid(t *testing.T) {
if val.Weight != 0 { if val.Weight != 0 {
t.Errorf("Expected %v but got %v", 0, val.Weight) t.Errorf("Expected %v but got %v", 0, val.Weight)
} }
} }
func TestAnnotations(t *testing.T) { func TestAnnotations(t *testing.T) {
@ -133,10 +131,9 @@ func TestAnnotations(t *testing.T) {
} }
continue continue
} else { }
if err != nil { if err != nil {
t.Errorf("%v: expected nil but returned error %v", test.title, err) t.Errorf("%v: expected nil but returned error %v", test.title, err)
}
} }
canaryConfig, ok := i.(*Config) canaryConfig, ok := i.(*Config)

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