synced with upstream
This commit is contained in:
commit
c18544ad03
274 changed files with 2701 additions and 2292 deletions
62
.github/workflows/ci.yaml
vendored
62
.github/workflows/ci.yaml
vendored
|
@ -42,7 +42,7 @@ jobs:
|
|||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||
id: filter
|
||||
|
@ -68,10 +68,10 @@ jobs:
|
|||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Run Gosec Security Scanner
|
||||
uses: securego/gosec@c5ea1b7bdd9efc3792e513258853552b0ae31e06 # v2.16.0
|
||||
uses: securego/gosec@a89e9d5a7acb4457f3891ac18532b142b1bf9221 # v2.17.0
|
||||
with:
|
||||
# G601 for zz_generated.deepcopy.go
|
||||
# G306 TODO: Expect WriteFile permissions to be 0600 or less
|
||||
|
@ -85,11 +85,11 @@ jobs:
|
|||
(needs.changes.outputs.go == 'true')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
@ -104,11 +104,11 @@ jobs:
|
|||
(needs.changes.outputs.go == 'true')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
@ -123,11 +123,11 @@ jobs:
|
|||
(needs.changes.outputs.go == 'true')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
@ -144,11 +144,11 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
@ -158,7 +158,7 @@ jobs:
|
|||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2.9.1
|
||||
uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0
|
||||
with:
|
||||
version: latest
|
||||
|
||||
|
@ -167,8 +167,6 @@ jobs:
|
|||
|
||||
- name: Prepare Host
|
||||
run: |
|
||||
sudo apt-get -qq update || true
|
||||
sudo apt-get install -y pigz
|
||||
curl -LO https://dl.k8s.io/release/v1.25.5/bin/linux/amd64/kubectl
|
||||
chmod +x ./kubectl
|
||||
sudo mv ./kubectl /usr/local/bin/kubectl
|
||||
|
@ -188,7 +186,7 @@ jobs:
|
|||
nginx-ingress-controller:e2e \
|
||||
ingress-controller/controller:1.0.0-dev \
|
||||
ingress-controller/controller-chroot:1.0.0-dev \
|
||||
| pigz > docker.tar.gz
|
||||
| gzip > docker.tar.gz
|
||||
|
||||
- name: cache
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
|
@ -207,14 +205,14 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
||||
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
@ -260,7 +258,7 @@ jobs:
|
|||
- name: Load images from cache
|
||||
run: |
|
||||
echo "loading docker images..."
|
||||
pigz -dc docker.tar.gz | docker load
|
||||
gzip -dc docker.tar.gz | docker load
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
|
@ -282,11 +280,11 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
||||
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: cache
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
|
@ -301,7 +299,7 @@ jobs:
|
|||
- name: Load images from cache
|
||||
run: |
|
||||
echo "loading docker images..."
|
||||
pigz -dc docker.tar.gz | docker load
|
||||
gzip -dc docker.tar.gz | docker load
|
||||
|
||||
- name: Run e2e tests
|
||||
env:
|
||||
|
@ -330,11 +328,11 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
k8s: [v1.27.1]
|
||||
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: cache
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
|
@ -349,7 +347,7 @@ jobs:
|
|||
- name: Load images from cache
|
||||
run: |
|
||||
echo "loading docker images..."
|
||||
pigz -dc docker.tar.gz | docker load
|
||||
gzip -dc docker.tar.gz | docker load
|
||||
|
||||
- name: Run e2e tests
|
||||
env:
|
||||
|
@ -380,12 +378,12 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
||||
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: cache
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
|
@ -400,7 +398,7 @@ jobs:
|
|||
- name: Load images from cache
|
||||
run: |
|
||||
echo "loading docker images..."
|
||||
pigz -dc docker.tar.gz | docker load
|
||||
gzip -dc docker.tar.gz | docker load
|
||||
|
||||
- name: Run e2e tests
|
||||
env:
|
||||
|
@ -429,7 +427,7 @@ jobs:
|
|||
PLATFORMS: linux/amd64,linux/arm64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||
id: filter-images
|
||||
|
@ -498,11 +496,11 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
||||
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||
id: filter-images
|
||||
|
@ -521,7 +519,7 @@ jobs:
|
|||
- name: Set up Go
|
||||
id: go
|
||||
if: ${{ steps.filter-images.outputs.kube-webhook-certgen == 'true' }}
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
|
4
.github/workflows/depreview.yaml
vendored
4
.github/workflows/depreview.yaml
vendored
|
@ -9,6 +9,6 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6
|
||||
uses: actions/dependency-review-action@f6fff72a3217f580d5afd49a46826795305b63c7 # v3.0.8
|
||||
|
|
4
.github/workflows/docs.yaml
vendored
4
.github/workflows/docs.yaml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||
id: filter
|
||||
|
@ -47,7 +47,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout master
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Deploy
|
||||
uses: ./.github/actions/mkdocs
|
||||
|
|
6
.github/workflows/helm.yaml
vendored
6
.github/workflows/helm.yaml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Run Artifact Hub lint
|
||||
run: |
|
||||
|
@ -61,7 +61,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout master
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
with:
|
||||
# Fetch entire history. Required for chart-releaser; see https://github.com/helm/chart-releaser-action/issues/13#issuecomment-602063896
|
||||
fetch-depth: 0
|
||||
|
@ -75,7 +75,7 @@ jobs:
|
|||
- name: Helm Chart Releaser
|
||||
uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0
|
||||
env:
|
||||
CR_SKIP_EXISTING: "false"
|
||||
CR_SKIP_EXISTING: true
|
||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}"
|
||||
with:
|
||||
|
|
2
.github/workflows/perftest.yaml
vendored
2
.github/workflows/perftest.yaml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Install K6
|
||||
run: |
|
||||
|
|
14
.github/workflows/plugin.yaml
vendored
14
.github/workflows/plugin.yaml
vendored
|
@ -4,10 +4,8 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- "cmd/plugin/**"
|
||||
tags:
|
||||
- "v*"
|
||||
- 'v*.*.*\+plugin'
|
||||
|
||||
permissions:
|
||||
contents: write # for goreleaser/goreleaser-action
|
||||
|
@ -17,21 +15,21 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20
|
||||
go-version: '1.20'
|
||||
check-latest: true
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0
|
||||
uses: goreleaser/goreleaser-action@3fa32b8bb5620a2c1afe798654bbad59f9da4906 # v4.4.0
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
4
.github/workflows/vulnerability-scans.yaml
vendored
4
.github/workflows/vulnerability-scans.yaml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
|||
versions: ${{ steps.version.outputs.TAGS }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
@ -52,7 +52,7 @@ jobs:
|
|||
versions: ${{ fromJSON(needs.version.outputs.versions) }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- shell: bash
|
||||
id: test
|
||||
|
|
|
@ -45,14 +45,16 @@ if ! command -v helm &> /dev/null; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
function ver { printf "%d%03d%03d" $(echo "$1" | tr '.' ' '); }
|
||||
|
||||
HELM_VERSION=$(helm version 2>&1 | cut -f1 -d"," | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || true
|
||||
echo $HELM_VERSION
|
||||
if [[ ${HELM_VERSION} -lt 3.10.0 ]]; then
|
||||
if [[ $(ver $HELM_VERSION) -lt $(ver "3.10.0") ]]; then
|
||||
echo "Please upgrade helm to v3.10.0 or higher"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KUBE_CLIENT_VERSION=$(kubectl version --client --short 2>/dev/null | grep Client | awk '{print $3}' | cut -d. -f2) || true
|
||||
KUBE_CLIENT_VERSION=$(kubectl version --client -oyaml 2>/dev/null | grep "minor:" | awk '{print $2}' | tr -d '"') || true
|
||||
if [[ ${KUBE_CLIENT_VERSION} -lt 24 ]]; then
|
||||
echo "Please update kubectl to 1.24.2 or higher"
|
||||
exit 1
|
||||
|
|
|
@ -296,7 +296,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
|||
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
|
||||
| controller.enableAnnotationValidations | bool | `false` | |
|
||||
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
|
||||
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto" Defaults to false |
|
||||
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
|
||||
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
|
||||
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
|
||||
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
|
||||
|
@ -307,6 +307,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
|||
| controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
|
||||
| controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
|
||||
| controller.healthCheckPath | string | `"/healthz"` | Path of the health check endpoint. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. |
|
||||
| controller.hostAliases | object | `{}` | Optionally customize the pod hostAliases. |
|
||||
| controller.hostNetwork | bool | `false` | Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged |
|
||||
| controller.hostPort.enabled | bool | `false` | Enable 'hostPort' or not |
|
||||
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port |
|
||||
|
@ -376,7 +377,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
|||
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
|
||||
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
|
||||
| controller.opentelemetry.enabled | bool | `false` | |
|
||||
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0"` | |
|
||||
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472"` | |
|
||||
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
|
||||
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
|
||||
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
|
||||
|
|
|
@ -49,6 +49,9 @@ spec:
|
|||
{{- if .Values.controller.dnsConfig }}
|
||||
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.controller.hostAliases }}
|
||||
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.controller.hostname }}
|
||||
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -190,7 +193,7 @@ spec:
|
|||
{{- end }}
|
||||
{{- if .Values.controller.opentelemetry.enabled}}
|
||||
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
|
||||
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" false) | nindent 8}}
|
||||
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true) | nindent 8}}
|
||||
{{- end}}
|
||||
{{- end }}
|
||||
{{- if .Values.controller.hostNetwork }}
|
||||
|
|
|
@ -5,6 +5,8 @@ metadata:
|
|||
name: {{ include "ingress-nginx.controller.fullname" . }}
|
||||
{{- if .Values.controller.metrics.serviceMonitor.namespace }}
|
||||
namespace: {{ .Values.controller.metrics.serviceMonitor.namespace | quote }}
|
||||
{{- else }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
||||
|
|
|
@ -49,6 +49,8 @@ controller:
|
|||
addHeaders: {}
|
||||
# -- Optionally customize the pod dnsConfig.
|
||||
dnsConfig: {}
|
||||
# -- Optionally customize the pod hostAliases.
|
||||
hostAliases: {}
|
||||
# -- Optionally customize the pod hostname.
|
||||
hostname: {}
|
||||
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
|
||||
|
@ -64,7 +66,7 @@ controller:
|
|||
watchIngressWithoutClass: false
|
||||
# -- Process IngressClass per name (additionally as per spec.controller).
|
||||
ingressClassByName: false
|
||||
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto"
|
||||
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto"
|
||||
# Defaults to false
|
||||
enableTopologyAwareRouting: false
|
||||
# -- This configuration defines if Ingress Controller should allow users to set
|
||||
|
@ -554,7 +556,7 @@ controller:
|
|||
|
||||
opentelemetry:
|
||||
enabled: false
|
||||
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0
|
||||
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
|
||||
containerSecurityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
admissionWebhooks:
|
||||
|
|
|
@ -18,11 +18,12 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/controller"
|
||||
|
|
|
@ -114,7 +114,6 @@ func main() {
|
|||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func backendsAll() {
|
||||
|
@ -155,10 +154,16 @@ func backendsList() {
|
|||
fmt.Println(unmarshalErr)
|
||||
return
|
||||
}
|
||||
backends := f.([]interface{})
|
||||
backends, ok := f.([]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("unexpected type: %T", f)
|
||||
}
|
||||
|
||||
for _, backendi := range backends {
|
||||
backend := backendi.(map[string]interface{})
|
||||
backend, ok := backendi.(map[string]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("unexpected type: %T", backendi)
|
||||
}
|
||||
fmt.Println(backend["name"].(string))
|
||||
}
|
||||
}
|
||||
|
@ -180,12 +185,22 @@ func backendsGet(name string) {
|
|||
fmt.Println(unmarshalErr)
|
||||
return
|
||||
}
|
||||
backends := f.([]interface{})
|
||||
backends, ok := f.([]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("unexpected type: %T", f)
|
||||
}
|
||||
|
||||
for _, backendi := range backends {
|
||||
backend := backendi.(map[string]interface{})
|
||||
backend, ok := backendi.(map[string]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("unexpected type: %T", backendi)
|
||||
}
|
||||
if backend["name"].(string) == name {
|
||||
printed, _ := json.MarshalIndent(backend, "", " ")
|
||||
printed, err := json.MarshalIndent(backend, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(printed))
|
||||
return
|
||||
}
|
||||
|
@ -213,18 +228,7 @@ func certGet(host string) {
|
|||
}
|
||||
|
||||
func general() {
|
||||
//TODO: refactor to obtain ingress-nginx pod count from the api server
|
||||
/*
|
||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(generalPath)
|
||||
if requestErr != nil {
|
||||
fmt.Println(requestErr)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
fmt.Printf("Nginx returned code %v\n", statusCode)
|
||||
return
|
||||
}
|
||||
*/
|
||||
// TODO: refactor to obtain ingress-nginx pod count from the api server
|
||||
|
||||
var prettyBuffer bytes.Buffer
|
||||
indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ")
|
||||
|
|
|
@ -47,5 +47,4 @@ func logger(address string) {
|
|||
|
||||
server.Wait()
|
||||
klog.Infof("Stopping logger")
|
||||
|
||||
}
|
||||
|
|
|
@ -153,7 +153,6 @@ func main() {
|
|||
if errExists == nil {
|
||||
conf.IsChroot = true
|
||||
go logger(conf.InternalLoggerAddress)
|
||||
|
||||
}
|
||||
|
||||
go metrics.StartHTTPServer(conf.HealthCheckHost, conf.ListenPorts.Health, mux)
|
||||
|
@ -282,10 +281,10 @@ func checkService(key string, kubeClient *kubernetes.Clientset) error {
|
|||
}
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
return fmt.Errorf("No service with name %v found in namespace %v: %v", name, ns, err)
|
||||
return fmt.Errorf("no service with name %v found in namespace %v: %v", name, ns, err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
|
||||
return fmt.Errorf("unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -47,7 +47,7 @@ func TestCreateApiserverClient(t *testing.T) {
|
|||
func init() {
|
||||
// the default value of nginx.TemplatePath assumes the template exists in
|
||||
// the root filesystem and not in the rootfs directory
|
||||
path, err := filepath.Abs(filepath.Join("../../rootfs/", nginx.TemplatePath))
|
||||
path, err := filepath.Abs(filepath.Join("..", "..", "rootfs", nginx.TemplatePath))
|
||||
if err == nil {
|
||||
nginx.TemplatePath = path
|
||||
}
|
||||
|
@ -87,14 +87,14 @@ func TestHandleSigterm(t *testing.T) {
|
|||
|
||||
ingressflags.ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
|
||||
os.Setenv("POD_NAME", podName)
|
||||
os.Setenv("POD_NAMESPACE", namespace)
|
||||
t.Setenv("POD_NAME", podName)
|
||||
t.Setenv("POD_NAMESPACE", namespace)
|
||||
|
||||
oldArgs := os.Args
|
||||
|
||||
defer func() {
|
||||
os.Setenv("POD_NAME", "")
|
||||
os.Setenv("POD_NAMESPACE", "")
|
||||
t.Setenv("POD_NAME", "")
|
||||
t.Setenv("POD_NAMESPACE", "")
|
||||
os.Args = oldArgs
|
||||
}()
|
||||
|
||||
|
|
|
@ -63,13 +63,14 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func backends(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, backend string, onlyList bool) error {
|
||||
func backends(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, backend string, onlyList bool) error {
|
||||
var command []string
|
||||
if onlyList {
|
||||
switch {
|
||||
case onlyList:
|
||||
command = []string{"/dbg", "backends", "list"}
|
||||
} else if backend != "" {
|
||||
case backend != "":
|
||||
command = []string{"/dbg", "backends", "get", backend}
|
||||
} else {
|
||||
default:
|
||||
command = []string{"/dbg", "backends", "all"}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func certs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, host string) error {
|
||||
func certs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, host string) error {
|
||||
command := []string{"/dbg", "certs", "get", host}
|
||||
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
|
|
|
@ -55,7 +55,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func conf(flags *genericclioptions.ConfigFlags, host string, podName string, deployment string, selector string, container string) error {
|
||||
func conf(flags *genericclioptions.ConfigFlags, host, podName, deployment, selector, container string) error {
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -55,7 +55,7 @@ type execFlags struct {
|
|||
Stdin bool
|
||||
}
|
||||
|
||||
func exec(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, cmd []string, opts execFlags) error {
|
||||
func exec(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, cmd []string, opts execFlags) error {
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -47,7 +47,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func general(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
|
||||
func general(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -74,9 +74,9 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
|
|||
|
||||
if host != "" {
|
||||
rowsWithHost := make([]ingressRow, 0)
|
||||
for _, row := range rows {
|
||||
if row.Host == host {
|
||||
rowsWithHost = append(rowsWithHost, row)
|
||||
for i := range rows {
|
||||
if rows[i].Host == host {
|
||||
rowsWithHost = append(rowsWithHost, rows[i])
|
||||
}
|
||||
}
|
||||
rows = rowsWithHost
|
||||
|
@ -91,7 +91,8 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
|
|||
fmt.Fprintln(printer, "INGRESS NAME\tHOST+PATH\tADDRESSES\tTLS\tSERVICE\tSERVICE PORT\tENDPOINTS")
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
for i := range rows {
|
||||
row := &rows[i]
|
||||
var tlsMsg string
|
||||
if row.TLS {
|
||||
tlsMsg = "YES"
|
||||
|
@ -134,8 +135,8 @@ type ingressRow struct {
|
|||
func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
|
||||
rows := make([]ingressRow, 0)
|
||||
|
||||
for _, ing := range *ingresses {
|
||||
|
||||
for i := range *ingresses {
|
||||
ing := &(*ingresses)[i]
|
||||
address := ""
|
||||
for _, lbIng := range ing.Status.LoadBalancer.Ingress {
|
||||
if len(lbIng.IP) > 0 {
|
||||
|
@ -182,7 +183,7 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
|
|||
for _, rule := range ing.Spec.Rules {
|
||||
_, hasTLS := tlsHosts[rule.Host]
|
||||
|
||||
//Handle ingress with no paths
|
||||
// Handle ingress with no paths
|
||||
if rule.HTTP == nil {
|
||||
row := ingressRow{
|
||||
Namespace: ing.Namespace,
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
)
|
||||
|
||||
func TestGetIngressInformation(t *testing.T) {
|
||||
|
||||
testcases := map[string]struct {
|
||||
ServiceBackend *networking.IngressServiceBackend
|
||||
wantName string
|
||||
|
|
|
@ -111,11 +111,13 @@ type lintOptions struct {
|
|||
}
|
||||
|
||||
func (opts *lintOptions) Validate() error {
|
||||
//nolint:dogsled // Ignore 3 blank identifiers
|
||||
_, _, _, err := util.ParseVersionString(opts.versionFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:dogsled // Ignore 3 blank identifiers
|
||||
_, _, _, err = util.ParseVersionString(opts.versionTo)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -131,9 +133,9 @@ type lint interface {
|
|||
Version() string
|
||||
}
|
||||
|
||||
func checkObjectArray(lints []lint, objects []kmeta.Object, opts lintOptions) {
|
||||
func checkObjectArray(allLints []lint, objects []kmeta.Object, opts lintOptions) {
|
||||
usedLints := make([]lint, 0)
|
||||
for _, lint := range lints {
|
||||
for _, lint := range allLints {
|
||||
lintVersion := lint.Version()
|
||||
if lint.Version() == "" {
|
||||
lintVersion = "0.0.0"
|
||||
|
@ -189,7 +191,7 @@ func ingresses(opts lintOptions) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var iLints []lints.IngressLint = lints.GetIngressLints()
|
||||
iLints := lints.GetIngressLints()
|
||||
genericLints := make([]lint, len(iLints))
|
||||
for i := range iLints {
|
||||
genericLints[i] = iLints[i]
|
||||
|
@ -216,7 +218,7 @@ func deployments(opts lintOptions) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var iLints []lints.DeploymentLint = lints.GetDeploymentLints()
|
||||
iLints := lints.GetDeploymentLints()
|
||||
genericLints := make([]lint, len(iLints))
|
||||
for i := range iLints {
|
||||
genericLints[i] = iLints[i]
|
||||
|
|
|
@ -95,7 +95,7 @@ func (o *logsFlags) toStrings() []string {
|
|||
return r
|
||||
}
|
||||
|
||||
func logs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, opts logsFlags) error {
|
||||
func logs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, opts logsFlags) error {
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -45,7 +45,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func ssh(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
|
||||
func ssh(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
|
||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -38,11 +38,11 @@ func PodExecString(flags *genericclioptions.ConfigFlags, pod *apiv1.Pod, contain
|
|||
|
||||
// ExecToString runs a kubectl subcommand and returns stdout as a string
|
||||
func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) {
|
||||
kArgs := getKubectlConfigFlags(flags)
|
||||
kArgs = append(kArgs, args...)
|
||||
kubectlArgs := getKubectlConfigFlags(flags)
|
||||
kubectlArgs = append(kubectlArgs, args...)
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0))
|
||||
err := execToWriter(append([]string{"kubectl"}, kArgs...), buf)
|
||||
err := execToWriter(append([]string{"kubectl"}, kubectlArgs...), buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string,
|
|||
|
||||
// Exec replaces the current process with a kubectl invocation
|
||||
func Exec(flags *genericclioptions.ConfigFlags, args []string) error {
|
||||
kArgs := getKubectlConfigFlags(flags)
|
||||
kArgs = append(kArgs, args...)
|
||||
return execCommand(append([]string{"kubectl"}, kArgs...))
|
||||
kubectlArgs := getKubectlConfigFlags(flags)
|
||||
kubectlArgs = append(kubectlArgs, args...)
|
||||
return execCommand(append([]string{"kubectl"}, kubectlArgs...))
|
||||
}
|
||||
|
||||
// Replaces the currently running process with the given command
|
||||
|
@ -70,6 +70,7 @@ func execCommand(args []string) error {
|
|||
|
||||
// Runs a command and returns stdout
|
||||
func execToWriter(args []string, writer io.Writer) error {
|
||||
//nolint:gosec // Ignore G204 error
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
|
||||
op, err := cmd.StdoutPipe()
|
||||
|
@ -78,7 +79,7 @@ func execToWriter(args []string, writer io.Writer) error {
|
|||
}
|
||||
|
||||
go func() {
|
||||
io.Copy(writer, op) //nolint:errcheck
|
||||
io.Copy(writer, op) //nolint:errcheck // Ignore the error
|
||||
}()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
|
@ -106,7 +107,6 @@ func getKubectlConfigFlags(flags *genericclioptions.ConfigFlags) []string {
|
|||
appendStringFlag(o, flags.Password, "password")
|
||||
appendStringFlag(o, flags.ClusterName, "cluster")
|
||||
appendStringFlag(o, flags.AuthInfoName, "user")
|
||||
//appendStringFlag(o, flags.Namespace, "namespace")
|
||||
appendStringFlag(o, flags.Context, "context")
|
||||
appendStringFlag(o, flags.APIServer, "server")
|
||||
appendBoolFlag(o, flags.Insecure, "insecure-skip-tls-verify")
|
||||
|
@ -128,7 +128,7 @@ func appendBoolFlag(out *[]string, in *bool, flag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func appendStringArrayFlag(out *[]string, in *[]string, flag string) {
|
||||
func appendStringArrayFlag(out, in *[]string, flag string) {
|
||||
if in != nil && len(*in) > 0 {
|
||||
*out = append(*out, fmt.Sprintf("--%v=%v'", flag, strings.Join(*in, ",")))
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ type DeploymentLint struct {
|
|||
|
||||
// Check returns true if the lint detects an issue
|
||||
func (lint DeploymentLint) Check(obj kmeta.Object) bool {
|
||||
cmp := obj.(*v1.Deployment)
|
||||
cmp, ok := obj.(*v1.Deployment)
|
||||
if !ok {
|
||||
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
|
||||
}
|
||||
return lint.f(*cmp)
|
||||
}
|
||||
|
||||
|
@ -72,11 +75,11 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
|
|||
issue: issueNumber,
|
||||
version: version,
|
||||
f: func(dep v1.Deployment) bool {
|
||||
if !isIngressNginxDeployment(dep) {
|
||||
if !isIngressNginxDeployment(&dep) {
|
||||
return false
|
||||
}
|
||||
|
||||
args := getNginxArgs(dep)
|
||||
args := getNginxArgs(&dep)
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) {
|
||||
return true
|
||||
|
@ -88,8 +91,9 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
|
|||
}
|
||||
}
|
||||
|
||||
func getNginxArgs(dep v1.Deployment) []string {
|
||||
for _, container := range dep.Spec.Template.Spec.Containers {
|
||||
func getNginxArgs(dep *v1.Deployment) []string {
|
||||
for i := range dep.Spec.Template.Spec.Containers {
|
||||
container := &dep.Spec.Template.Spec.Containers[i]
|
||||
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
|
||||
return container.Args
|
||||
}
|
||||
|
@ -97,10 +101,10 @@ func getNginxArgs(dep v1.Deployment) []string {
|
|||
return make([]string, 0)
|
||||
}
|
||||
|
||||
func isIngressNginxDeployment(dep v1.Deployment) bool {
|
||||
func isIngressNginxDeployment(dep *v1.Deployment) bool {
|
||||
containers := dep.Spec.Template.Spec.Containers
|
||||
for _, container := range containers {
|
||||
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
|
||||
for i := range containers {
|
||||
if len(containers[i].Args) > 0 && containers[i].Args[0] == "/nginx-ingress-controller" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,16 @@ type IngressLint struct {
|
|||
message string
|
||||
issue int
|
||||
version string
|
||||
f func(ing networking.Ingress) bool
|
||||
f func(ing *networking.Ingress) bool
|
||||
}
|
||||
|
||||
// Check returns true if the lint detects an issue
|
||||
func (lint IngressLint) Check(obj kmeta.Object) bool {
|
||||
ing := obj.(*networking.Ingress)
|
||||
return lint.f(*ing)
|
||||
ing, ok := obj.(*networking.Ingress)
|
||||
if !ok {
|
||||
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
|
||||
}
|
||||
return lint.f(ing)
|
||||
}
|
||||
|
||||
// Message is a description of the lint
|
||||
|
@ -94,7 +97,7 @@ func GetIngressLints() []IngressLint {
|
|||
}
|
||||
}
|
||||
|
||||
func xForwardedPrefixIsBool(ing networking.Ingress) bool {
|
||||
func xForwardedPrefixIsBool(ing *networking.Ingress) bool {
|
||||
for name, val := range ing.Annotations {
|
||||
if strings.HasSuffix(name, "/x-forwarded-prefix") && (val == "true" || val == "false") {
|
||||
return true
|
||||
|
@ -103,7 +106,7 @@ func xForwardedPrefixIsBool(ing networking.Ingress) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
|
||||
func annotationPrefixIsNginxCom(ing *networking.Ingress) bool {
|
||||
for name := range ing.Annotations {
|
||||
if strings.HasPrefix(name, "nginx.com/") {
|
||||
return true
|
||||
|
@ -112,7 +115,7 @@ func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
|
||||
func annotationPrefixIsNginxOrg(ing *networking.Ingress) bool {
|
||||
for name := range ing.Annotations {
|
||||
if strings.HasPrefix(name, "nginx.org/") {
|
||||
return true
|
||||
|
@ -121,7 +124,7 @@ func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func rewriteTargetWithoutCaptureGroup(ing networking.Ingress) bool {
|
||||
func rewriteTargetWithoutCaptureGroup(ing *networking.Ingress) bool {
|
||||
for name, val := range ing.Annotations {
|
||||
if strings.HasSuffix(name, "/rewrite-target") && !strings.Contains(val, "$1") {
|
||||
return true
|
||||
|
@ -135,7 +138,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
|
|||
message: fmt.Sprintf("Contains the removed %v annotation.", annotationName),
|
||||
issue: issueNumber,
|
||||
version: version,
|
||||
f: func(ing networking.Ingress) bool {
|
||||
f: func(ing *networking.Ingress) bool {
|
||||
for annotation := range ing.Annotations {
|
||||
if strings.HasSuffix(annotation, "/"+annotationName) {
|
||||
return true
|
||||
|
@ -146,7 +149,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
|
|||
}
|
||||
}
|
||||
|
||||
func satisfyDirective(ing networking.Ingress) bool {
|
||||
func satisfyDirective(ing *networking.Ingress) bool {
|
||||
for name, val := range ing.Annotations {
|
||||
if strings.HasSuffix(name, "/configuration-snippet") {
|
||||
return strings.Contains(val, "satisfy")
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
"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 ...
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import (
|
|||
)
|
||||
|
||||
// ChoosePod finds a pod either by deployment or by name
|
||||
func ChoosePod(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) (apiv1.Pod, error) {
|
||||
func ChoosePod(flags *genericclioptions.ConfigFlags, podName, deployment, selector string) (apiv1.Pod, error) {
|
||||
if podName != "" {
|
||||
return GetNamedPod(flags, podName)
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ func GetNamedPod(flags *genericclioptions.ConfigFlags, name string) (apiv1.Pod,
|
|||
return apiv1.Pod{}, err
|
||||
}
|
||||
|
||||
for _, pod := range allPods {
|
||||
if pod.Name == name {
|
||||
return pod, nil
|
||||
for i := range allPods {
|
||||
if allPods[i].Name == name {
|
||||
return allPods[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ func GetIngressDefinitions(flags *genericclioptions.ConfigFlags, namespace strin
|
|||
}
|
||||
|
||||
// GetNumEndpoints counts the number of endpointslices adresses for the service with the given name
|
||||
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, serviceName string) (*int, error) {
|
||||
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace, serviceName string) (*int, error) {
|
||||
epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -143,25 +143,26 @@ func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, ser
|
|||
}
|
||||
|
||||
ret := 0
|
||||
for _, eps := range epss {
|
||||
for _, ep := range eps.Endpoints {
|
||||
ret += len(ep.Addresses)
|
||||
for i := range epss {
|
||||
eps := &epss[i]
|
||||
for j := range eps.Endpoints {
|
||||
ret += len(eps.Endpoints[j].Addresses)
|
||||
}
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
// GetEndpointSlicesByName returns the endpointSlices for the service with the given name
|
||||
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace string, name string) ([]discoveryv1.EndpointSlice, error) {
|
||||
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace, name string) ([]discoveryv1.EndpointSlice, error) {
|
||||
allEndpointsSlices, err := getEndpointSlices(flags, namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var eps []discoveryv1.EndpointSlice
|
||||
for _, slice := range allEndpointsSlices {
|
||||
if svcName, ok := slice.ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
|
||||
for i := range allEndpointsSlices {
|
||||
if svcName, ok := allEndpointsSlices[i].ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
|
||||
if svcName == name {
|
||||
eps = append(eps, slice)
|
||||
eps = append(eps, allEndpointsSlices[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +183,7 @@ func getEndpointSlices(flags *genericclioptions.ConfigFlags, namespace string) (
|
|||
tryAllNamespacesEndpointSlicesCache(flags)
|
||||
}
|
||||
|
||||
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(flags, namespace)
|
||||
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(namespace)
|
||||
|
||||
if cachedEndpointSlices != nil {
|
||||
return *cachedEndpointSlices, nil
|
||||
|
@ -217,13 +218,13 @@ func tryAllNamespacesEndpointSlicesCache(flags *genericclioptions.ConfigFlags) {
|
|||
}
|
||||
}
|
||||
|
||||
func tryFilteringEndpointSlicesFromAllNamespacesCache(flags *genericclioptions.ConfigFlags, namespace string) *[]discoveryv1.EndpointSlice {
|
||||
func tryFilteringEndpointSlicesFromAllNamespacesCache(namespace string) *[]discoveryv1.EndpointSlice {
|
||||
allEndpointSlices := endpointSlicesCache[""]
|
||||
if allEndpointSlices != nil {
|
||||
endpointSlices := make([]discoveryv1.EndpointSlice, 0)
|
||||
for _, slice := range *allEndpointSlices {
|
||||
if slice.Namespace == namespace {
|
||||
endpointSlices = append(endpointSlices, slice)
|
||||
for i := range *allEndpointSlices {
|
||||
if (*allEndpointSlices)[i].Namespace == namespace {
|
||||
endpointSlices = append(endpointSlices, (*allEndpointSlices)[i])
|
||||
}
|
||||
}
|
||||
endpointSlicesCache[namespace] = &endpointSlices
|
||||
|
@ -242,9 +243,9 @@ func GetServiceByName(flags *genericclioptions.ConfigFlags, name string, service
|
|||
services = &servicesArray
|
||||
}
|
||||
|
||||
for _, svc := range *services {
|
||||
if svc.Name == name {
|
||||
return svc, nil
|
||||
for i := range *services {
|
||||
if (*services)[i].Name == name {
|
||||
return (*services)[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,7 +289,6 @@ func getLabeledPods(flags *genericclioptions.ConfigFlags, label string) ([]apiv1
|
|||
pods, err := api.Pods(namespace).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: label,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return make([]apiv1.Pod, 0), err
|
||||
}
|
||||
|
@ -303,9 +303,9 @@ func getDeploymentPods(flags *genericclioptions.ConfigFlags, deployment string)
|
|||
}
|
||||
|
||||
ingressPods := make([]apiv1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if util.PodInDeployment(pod, deployment) {
|
||||
ingressPods = append(ingressPods, pod)
|
||||
for i := range pods {
|
||||
if util.PodInDeployment(&pods[i], deployment) {
|
||||
ingressPods = append(ingressPods, pods[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,5 +331,4 @@ func getServices(flags *genericclioptions.ConfigFlags) ([]apiv1.Service, error)
|
|||
}
|
||||
|
||||
return services.Items, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -47,17 +47,25 @@ func PrintError(e error) {
|
|||
}
|
||||
|
||||
// ParseVersionString returns the major, minor, and patch numbers of a version string
|
||||
func ParseVersionString(v string) (int, int, int, error) {
|
||||
func ParseVersionString(v string) (major, minor, patch int, err error) {
|
||||
parts := versionRegex.FindStringSubmatch(v)
|
||||
|
||||
if len(parts) != 4 {
|
||||
return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v)
|
||||
}
|
||||
|
||||
major, _ := strconv.Atoi(parts[1])
|
||||
minor, _ := strconv.Atoi(parts[2])
|
||||
patch, _ := strconv.Atoi(parts[3])
|
||||
|
||||
major, err = strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
minor, err = strconv.Atoi(parts[2])
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
patch, err = strconv.Atoi(parts[3])
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
return major, minor, patch, nil
|
||||
}
|
||||
|
||||
|
@ -90,7 +98,7 @@ func isVersionLessThan(a, b string) bool {
|
|||
|
||||
// PodInDeployment returns whether a pod is part of a deployment with the given name
|
||||
// a pod is considered to be in {deployment} if it is owned by a replicaset with a name of format {deployment}-otherchars
|
||||
func PodInDeployment(pod apiv1.Pod, deployment string) bool {
|
||||
func PodInDeployment(pod *apiv1.Pod, deployment string) bool {
|
||||
for _, owner := range pod.OwnerReferences {
|
||||
if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" {
|
||||
continue
|
||||
|
@ -138,7 +146,7 @@ func AddContainerFlag(cmd *cobra.Command) *string {
|
|||
// GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in
|
||||
func GetNamespace(flags *genericclioptions.ConfigFlags) string {
|
||||
namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil || len(namespace) == 0 {
|
||||
if err != nil || namespace == "" {
|
||||
namespace = apiv1.NamespaceDefault
|
||||
}
|
||||
return namespace
|
||||
|
|
|
@ -80,6 +80,12 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont
|
|||
Because of api deprecations, the default manifest may not work on your cluster.
|
||||
Specific manifests for supported Kubernetes versions are available within a sub-folder of each provider.
|
||||
|
||||
### Firewall configuration
|
||||
|
||||
To check which ports are used by your installation of ingress-nginx, look at the output of `kubectl -n ingress-nginx get pod -o yaml`. In general, you need:
|
||||
- Port 8443 open between all hosts on which the kubernetes nodes are running. This is used for the ingress-nginx [admission controller](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/).
|
||||
- Port 80 (for HTTP) and/or 443 (for HTTPS) open to the public on the kubernetes nodes to which the DNS of your apps are pointing.
|
||||
|
||||
### Pre-flight check
|
||||
|
||||
A few pods should start in the `ingress-nginx` namespace:
|
||||
|
|
|
@ -716,7 +716,7 @@ Do not try to edit it manually.
|
|||
|
||||
### [[Flag] watch namespace selector](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L30)
|
||||
|
||||
- [should ingore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
|
||||
- [should ignore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
|
||||
|
||||
### [[Security] no-auth-locations](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/no_auth_locations.go#L33)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Customization | [External authentication with response header propagation](custo
|
|||
Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO
|
||||
Features | [Rewrite](rewrite/README.md) | TODO | TODO
|
||||
Features | [Session stickiness](affinity/cookie/README.md) | route requests consistently to the same endpoint | Advanced
|
||||
Features | [Canary Deployments](canary/README.md) | weigthed canary routing to a seperate deployment | Intermediate
|
||||
Features | [Canary Deployments](canary/README.md) | weighted canary routing to a seperate deployment | Intermediate
|
||||
Scaling | [Static IP](static-ip/README.md) | a single ingress gets a single static IP | Intermediate
|
||||
TLS | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO
|
||||
TLS | [TLS termination](tls-termination/README.md) | TODO | TODO
|
||||
|
|
|
@ -25,7 +25,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
|
|||
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
|
||||
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
|
||||
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |
|
||||
| `--enable-topology-aware-routing` | Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto. (default false) |
|
||||
| `--enable-topology-aware-routing` | Enable topology aware routing feature, needs service object annotation service.kubernetes.io/topology-mode sets to auto. (default false) |
|
||||
| `--exclude-socket-metrics` | Set of socket request metrics to exclude which won't be exported nor being calculated. The possible socket request metrics to exclude are documented in the monitoring guide e.g. 'nginx_ingress_controller_request_duration_seconds,nginx_ingress_controller_response_size'|
|
||||
| `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") |
|
||||
| `--health-check-timeout` | Time limit, in seconds, for a probe to health-check-path to succeed. (default 10) |
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
While the Kubernetes Ingress resource only officially supports routing external HTTP(s) traffic to services, ingress-nginx can be configured to receive external TCP/UDP traffic from non-HTTP protocols and route them to internal services using TCP/UDP port mappings that are specified within a ConfigMap.
|
||||
|
||||
To support this, the `--tcp-services-configmap` and `--udp-services-configmap` flags can be used to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:
|
||||
`<namespace/service name>:<service port>:[PROXY]:[PROXY]`
|
||||
`<service port>:<namespace/service name>:[PROXY]:[PROXY]`
|
||||
|
||||
It is also possible to use a number or the name of the port. The two last fields are optional.
|
||||
Adding `PROXY` in either or both of the two last fields we can use [Proxy Protocol](https://www.nginx.com/resources/admin-guide/proxy-protocol) decoding (listen) and/or encoding (proxy_pass) in a TCP service.
|
||||
|
|
|
@ -33,6 +33,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|
|||
|[nginx.ingress.kubernetes.io/auth-cache-key](#external-authentication)|string|
|
||||
|[nginx.ingress.kubernetes.io/auth-cache-duration](#external-authentication)|string|
|
||||
|[nginx.ingress.kubernetes.io/auth-keepalive](#external-authentication)|number|
|
||||
|[nginx.ingress.kubernetes.io/auth-keepalive-share-vars](#external-authentication)|"true" or "false"|
|
||||
|[nginx.ingress.kubernetes.io/auth-keepalive-requests](#external-authentication)|number|
|
||||
|[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number|
|
||||
|[nginx.ingress.kubernetes.io/auth-proxy-set-headers](#external-authentication)|string|
|
||||
|
@ -479,6 +480,9 @@ Additionally it is possible to set:
|
|||
> Note: does not work with HTTP/2 listener because of a limitation in Lua [subrequests](https://github.com/openresty/lua-nginx-module#spdy-mode-not-fully-supported).
|
||||
> [UseHTTP2](./configmap.md#use-http2) configuration should be disabled!
|
||||
|
||||
* `nginx.ingress.kubernetes.io/auth-keepalive-share-vars`:
|
||||
Whether to share Nginx variables among the current request and the auth request. Example use case is to track requests: when set to "true" X-Request-ID HTTP header will be the same for the backend and the auth request.
|
||||
Defaults to "false".
|
||||
* `nginx.ingress.kubernetes.io/auth-keepalive-requests`:
|
||||
`<Requests>` to specify the maximum number of requests that can be served through one keepalive connection.
|
||||
Defaults to `1000` and only applied if `auth-keepalive` is set to higher than `0`.
|
||||
|
|
38
go.mod
38
go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/moul/pb v0.0.0-20220425114252-bca18df4138c
|
||||
github.com/ncabatoff/process-exporter v0.7.10
|
||||
github.com/onsi/ginkgo/v2 v2.9.5
|
||||
github.com/opencontainers/runc v1.1.8
|
||||
github.com/opencontainers/runc v1.1.9
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
|
@ -25,19 +25,19 @@ require (
|
|||
github.com/stretchr/testify v1.8.4
|
||||
github.com/yudai/gojsondiff v1.0.0
|
||||
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
|
||||
golang.org/x/crypto v0.11.0
|
||||
google.golang.org/grpc v1.56.2
|
||||
golang.org/x/crypto v0.12.0
|
||||
google.golang.org/grpc v1.57.0
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
|
||||
gopkg.in/go-playground/pool.v3 v3.1.1
|
||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
||||
k8s.io/api v0.26.4
|
||||
k8s.io/api v0.27.4
|
||||
k8s.io/apiextensions-apiserver v0.26.4
|
||||
k8s.io/apimachinery v0.26.4
|
||||
k8s.io/apimachinery v0.27.4
|
||||
k8s.io/apiserver v0.26.4
|
||||
k8s.io/cli-runtime v0.26.4
|
||||
k8s.io/client-go v0.26.4
|
||||
k8s.io/client-go v0.27.4
|
||||
k8s.io/code-generator v0.26.4
|
||||
k8s.io/component-base v0.26.4
|
||||
k8s.io/component-base v0.27.4
|
||||
k8s.io/klog/v2 v2.100.1
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
|
||||
sigs.k8s.io/controller-runtime v0.14.6
|
||||
|
@ -59,9 +59,9 @@ require (
|
|||
github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.6 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
|
@ -72,14 +72,14 @@ require (
|
|||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
|
||||
|
@ -103,22 +103,22 @@ require (
|
|||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/term v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.9.1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/kustomize/api v0.12.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
|
|
89
go.sum
89
go.sum
|
@ -103,14 +103,12 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
|||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
|
@ -184,8 +182,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
|
@ -235,10 +233,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
|||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
|
@ -276,7 +272,6 @@ github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 h1:t4WWQ9I797y7QU
|
|||
github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag=
|
||||
github.com/ncabatoff/process-exporter v0.7.10 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
|
||||
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
|
@ -289,8 +284,8 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro
|
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/opencontainers/runc v1.1.8 h1:zICRlc+C1XzivLc3nzE+cbJV4LIi8tib6YG0MqC6OqA=
|
||||
github.com/opencontainers/runc v1.1.8/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
|
||||
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||
|
@ -331,7 +326,7 @@ github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPH
|
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
|
@ -347,7 +342,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.1.3/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
@ -355,6 +352,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/urfave/cli v1.17.1-0.20160602030128-01a33823596e/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
|
@ -390,8 +390,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -524,19 +524,19 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -647,8 +647,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -661,8 +661,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
@ -683,7 +683,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
|
@ -717,31 +716,31 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.26.4 h1:qSG2PmtcD23BkYiWfoYAcak870eF/hE7NNYBYavTT94=
|
||||
k8s.io/api v0.26.4/go.mod h1:WwKEXU3R1rgCZ77AYa7DFksd9/BAIKyOmRlbVxgvjCk=
|
||||
k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
|
||||
k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
|
||||
k8s.io/apiextensions-apiserver v0.26.4 h1:9D2RTxYGxrG5uYg6D7QZRcykXvavBvcA59j5kTaedQI=
|
||||
k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw=
|
||||
k8s.io/apimachinery v0.26.4 h1:rZccKdBLg9vP6J09JD+z8Yr99Ce8gk3Lbi9TCx05Jzs=
|
||||
k8s.io/apimachinery v0.26.4/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
|
||||
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
|
||||
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||
k8s.io/apiserver v0.26.4 h1:3Oq4mnJv0mzVX7BR/Nod+8KjlELf/3Ljvu9ZWDyLUoA=
|
||||
k8s.io/apiserver v0.26.4/go.mod h1:yAY3O1vBM4/0OIGAGeWcdfzQvgdwJ188VirLcuSAVnw=
|
||||
k8s.io/cli-runtime v0.26.4 h1:MgSU871KDzBDX7V9GtuqS6Ai9lhQCHgRzkurnXOWtZ0=
|
||||
k8s.io/cli-runtime v0.26.4/go.mod h1:MjJ2DXMChw2zcG0/agzm17xwKpfVxOfuoCdfY9iOCOE=
|
||||
k8s.io/client-go v0.26.4 h1:/7P/IbGBuT73A+G97trf44NTPSNqvuBREpOfdLbHvD4=
|
||||
k8s.io/client-go v0.26.4/go.mod h1:6qOItWm3EwxJdl/8p5t7FWtWUOwyMdA8N9ekbW4idpI=
|
||||
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
|
||||
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||
k8s.io/code-generator v0.26.4 h1:zgDD0qX13p/jtrAoYRRiYeQ5ibnriwmo2cMkMZAtJxc=
|
||||
k8s.io/code-generator v0.26.4/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI=
|
||||
k8s.io/component-base v0.26.4 h1:Bg2xzyXNKL3eAuiTEu3XE198d6z22ENgFgGQv2GGOUk=
|
||||
k8s.io/component-base v0.26.4/go.mod h1:lTuWL1Xz/a4e80gmIC3YZG2JCO4xNwtKWHJWeJmsq20=
|
||||
k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c=
|
||||
k8s.io/component-base v0.27.4/go.mod h1:hoiEETnLc0ioLv6WPeDt8vD34DDeB35MfQnxCARq3kY=
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
@ -749,8 +748,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
|
||||
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
|
||||
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
|
||||
|
|
|
@ -32,6 +32,7 @@ FROM gcr.io/distroless/static:nonroot
|
|||
|
||||
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/nginx-errors /
|
||||
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/www /www
|
||||
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/etc /etc
|
||||
USER nonroot:nonroot
|
||||
|
||||
CMD ["/nginx-errors"]
|
||||
|
|
|
@ -16,13 +16,13 @@ func hello(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
key := keys[0]
|
||||
fmt.Fprintf(w, "Hello "+string(key)+"!")
|
||||
fmt.Fprintf(w, "Hello "+key+"!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/hello", hello)
|
||||
|
||||
l, err := net.Listen("tcp", "0.0.0.0:9000")
|
||||
l, err := net.Listen("tcp", "0.0.0.0:9000") //nolint:gosec // Ignore the gosec error since it's a hello server
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ type hwServer struct {
|
|||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *hwServer) SayHello(ctx context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
|
||||
func (s *hwServer) SayHello(_ context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
|
||||
return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ type ecServer struct {
|
|||
ecpb.UnimplementedEchoServer
|
||||
}
|
||||
|
||||
func (s *ecServer) UnaryEcho(ctx context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
|
||||
func (s *ecServer) UnaryEcho(_ context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
|
||||
return &ecpb.EchoResponse{Message: req.Message}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -42,19 +42,16 @@ type IngressAdmission struct {
|
|||
Checker Checker
|
||||
}
|
||||
|
||||
var (
|
||||
ingressResource = metav1.GroupVersionKind{
|
||||
Group: networking.GroupName,
|
||||
Version: "v1",
|
||||
Kind: "Ingress",
|
||||
}
|
||||
)
|
||||
var ingressResource = metav1.GroupVersionKind{
|
||||
Group: networking.GroupName,
|
||||
Version: "v1",
|
||||
Kind: "Ingress",
|
||||
}
|
||||
|
||||
// HandleAdmission populates the admission Response
|
||||
// with Allowed=false if the Object is an ingress that would prevent nginx to reload the configuration
|
||||
// with Allowed=true otherwise
|
||||
func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {
|
||||
|
||||
review, isV1 := obj.(*admissionv1.AdmissionReview)
|
||||
if !isV1 {
|
||||
return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")
|
||||
|
|
|
@ -33,12 +33,12 @@ type failTestChecker struct {
|
|||
t *testing.T
|
||||
}
|
||||
|
||||
func (ftc failTestChecker) CheckIngress(ing *networking.Ingress) error {
|
||||
func (ftc failTestChecker) CheckIngress(_ *networking.Ingress) error {
|
||||
ftc.t.Error("checker should not be called")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc failTestChecker) CheckWarning(ing *networking.Ingress) ([]string, error) {
|
||||
func (ftc failTestChecker) CheckWarning(_ *networking.Ingress) ([]string, error) {
|
||||
ftc.t.Error("checker should not be called")
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -26,9 +26,7 @@ import (
|
|||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
scheme = runtime.NewScheme()
|
||||
)
|
||||
var scheme = runtime.NewScheme()
|
||||
|
||||
func init() {
|
||||
if err := admissionv1.AddToScheme(scheme); err != nil {
|
||||
|
|
|
@ -72,7 +72,7 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
aliases := sets.NewString()
|
||||
for _, alias := range strings.Split(val, ",") {
|
||||
alias = strings.TrimSpace(alias)
|
||||
if len(alias) == 0 {
|
||||
if alias == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -65,9 +65,9 @@ func TestParse(t *testing.T) {
|
|||
if testCase.skipValidation {
|
||||
parser.EnableAnnotationValidation = false
|
||||
}
|
||||
defer func() {
|
||||
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)
|
||||
|
|
|
@ -88,37 +88,36 @@ type Ingress struct {
|
|||
CustomHTTPErrors []int
|
||||
DisableProxyInterceptErrors bool
|
||||
DefaultBackend *apiv1.Service
|
||||
//TODO: Change this back into an error when https://github.com/imdario/mergo/issues/100 is resolved
|
||||
FastCGI fastcgi.Config
|
||||
Denied *string
|
||||
ExternalAuth authreq.Config
|
||||
EnableGlobalAuth bool
|
||||
HTTP2PushPreload bool
|
||||
Opentracing opentracing.Config
|
||||
Opentelemetry opentelemetry.Config
|
||||
Proxy proxy.Config
|
||||
ProxySSL proxyssl.Config
|
||||
RateLimit ratelimit.Config
|
||||
GlobalRateLimit globalratelimit.Config
|
||||
Redirect redirect.Config
|
||||
Rewrite rewrite.Config
|
||||
Satisfy string
|
||||
ServerSnippet string
|
||||
ServiceUpstream bool
|
||||
SessionAffinity sessionaffinity.Config
|
||||
SSLPassthrough bool
|
||||
UsePortInRedirects bool
|
||||
UpstreamHashBy upstreamhashby.Config
|
||||
LoadBalancing string
|
||||
UpstreamVhost string
|
||||
Denylist ipdenylist.SourceRange
|
||||
XForwardedPrefix string
|
||||
SSLCipher sslcipher.Config
|
||||
Logs log.Config
|
||||
ModSecurity modsecurity.Config
|
||||
Mirror mirror.Config
|
||||
StreamSnippet string
|
||||
Allowlist ipallowlist.SourceRange
|
||||
FastCGI fastcgi.Config
|
||||
Denied *string
|
||||
ExternalAuth authreq.Config
|
||||
EnableGlobalAuth bool
|
||||
HTTP2PushPreload bool
|
||||
Opentracing opentracing.Config
|
||||
Opentelemetry opentelemetry.Config
|
||||
Proxy proxy.Config
|
||||
ProxySSL proxyssl.Config
|
||||
RateLimit ratelimit.Config
|
||||
GlobalRateLimit globalratelimit.Config
|
||||
Redirect redirect.Config
|
||||
Rewrite rewrite.Config
|
||||
Satisfy string
|
||||
ServerSnippet string
|
||||
ServiceUpstream bool
|
||||
SessionAffinity sessionaffinity.Config
|
||||
SSLPassthrough bool
|
||||
UsePortInRedirects bool
|
||||
UpstreamHashBy upstreamhashby.Config
|
||||
LoadBalancing string
|
||||
UpstreamVhost string
|
||||
Denylist ipdenylist.SourceRange
|
||||
XForwardedPrefix string
|
||||
SSLCipher sslcipher.Config
|
||||
Logs log.Config
|
||||
ModSecurity modsecurity.Config
|
||||
Mirror mirror.Config
|
||||
StreamSnippet string
|
||||
Allowlist ipallowlist.SourceRange
|
||||
}
|
||||
|
||||
// Extractor defines the annotation parsers to be used in the extraction of annotations
|
||||
|
|
|
@ -64,7 +64,11 @@ func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
|
|||
}
|
||||
|
||||
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||
if secret, _ := m.GetSecret(name); secret != nil {
|
||||
secret, err := m.GetSecret(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret != nil {
|
||||
return &resolver.AuthSSLCert{
|
||||
Secret: name,
|
||||
CAFileName: "/opt/ca.pem",
|
||||
|
@ -270,9 +274,9 @@ func TestCors(t *testing.T) {
|
|||
if r.CorsAllowCredentials != foo.credentials {
|
||||
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomHTTPErrors(t *testing.T) {
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
|
|
@ -50,7 +50,7 @@ var (
|
|||
)
|
||||
|
||||
var AuthSecretConfig = parser.AnnotationConfig{
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
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. `,
|
||||
|
@ -61,20 +61,20 @@ var authSecretAnnotations = parser.Annotation{
|
|||
Annotations: parser.AnnotationFields{
|
||||
AuthSecretAnnotation: AuthSecretConfig,
|
||||
authSecretTypeAnnotation: {
|
||||
Validator: parser.ValidateRegex(*authSecretTypeRegex, true),
|
||||
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),
|
||||
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),
|
||||
Validator: parser.ValidateRegex(authTypeRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation defines the basic authentication type. Should be "basic" or "digest"`,
|
||||
|
@ -167,14 +167,14 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
s, err := parser.GetStringAnnotation(AuthSecretAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
sns, sname, err := cache.SplitMetaNamespaceKey(s)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
secCfg := a.r.GetSecurityConfiguration()
|
||||
// We don't accept different namespaces for secrets.
|
||||
if !secCfg.AllowCrossNamespaceResources && sns != ing.Namespace {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
name := fmt.Sprintf("%v/%v", sns, sname)
|
||||
secret, err := a.r.GetSecret(name)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("unexpected error reading secret %s: %w", name, err),
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("invalid auth-secret-type in annotation, must be 'auth-file' or 'auth-map': %w", err),
|
||||
}
|
||||
}
|
||||
|
@ -238,14 +238,14 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
func dumpSecretAuthFile(filename string, secret *api.Secret) error {
|
||||
val, ok := secret.Data["auth"]
|
||||
if !ok {
|
||||
return ing_errors.LocationDenied{
|
||||
return ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("the secret %s does not contain a key with value auth", secret.Name),
|
||||
}
|
||||
}
|
||||
|
||||
err := os.WriteFile(filename, val, file.ReadWriteByUser)
|
||||
if err != nil {
|
||||
return ing_errors.LocationDenied{
|
||||
return ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func dumpSecretAuthMap(filename string, secret *api.Secret) error {
|
|||
|
||||
err := os.WriteFile(filename, []byte(builder.String()), file.ReadWriteByUser)
|
||||
if err != nil {
|
||||
return ing_errors.LocationDenied{
|
||||
return ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,15 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
//nolint:gosec // Ignore hardcoded credentials error in testing
|
||||
const (
|
||||
authType = "basic"
|
||||
authRealm = "-realm-"
|
||||
defaultDemoSecret = "default/demo-secret"
|
||||
othernsDemoSecret = "otherns/demo-secret"
|
||||
demoSecret = "demo-secret"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -80,7 +89,7 @@ type mockSecret struct {
|
|||
}
|
||||
|
||||
func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
|
||||
if name != "default/demo-secret" && name != "otherns/demo-secret" {
|
||||
if name != defaultDemoSecret && name != othernsDemoSecret {
|
||||
return nil, fmt.Errorf("there is no secret with name %v", name)
|
||||
}
|
||||
|
||||
|
@ -92,7 +101,7 @@ func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
|
|||
return &api.Secret{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: "demo-secret",
|
||||
Name: demoSecret,
|
||||
},
|
||||
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
|
||||
}, nil
|
||||
|
@ -129,9 +138,9 @@ func TestIngressInvalidRealm(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "something weird ; location trying to { break }"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
|
@ -148,14 +157,14 @@ func TestIngressInvalidDifferentNamespace(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "otherns/demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
expected := ing_errors.LocationDenied{
|
||||
expected := ing_errors.LocationDeniedError{
|
||||
Reason: errors.New("cross namespace usage of secrets is not allowed"),
|
||||
}
|
||||
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||
|
@ -168,8 +177,8 @@ func TestIngressInvalidDifferentNamespaceAllowed(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "otherns/demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
|
@ -187,14 +196,14 @@ func TestIngressInvalidSecretName(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
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.LocationDenied{
|
||||
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)
|
||||
|
@ -207,13 +216,13 @@ func TestInvalidIngressAuthNoSecret(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
expected := ing_errors.LocationDenied{
|
||||
expected := ing_errors.LocationDeniedError{
|
||||
Reason: errors.New("error reading secret name from annotation: ingress rule without annotations"),
|
||||
}
|
||||
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||
|
@ -226,9 +235,9 @@ func TestIngressAuth(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "-realm-"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
|
@ -242,10 +251,10 @@ func TestIngressAuth(t *testing.T) {
|
|||
if !ok {
|
||||
t.Errorf("expected a BasicDigest type")
|
||||
}
|
||||
if auth.Type != "basic" {
|
||||
if auth.Type != authType {
|
||||
t.Errorf("Expected basic as auth type but returned %s", auth.Type)
|
||||
}
|
||||
if auth.Realm != "-realm-" {
|
||||
if auth.Realm != authRealm {
|
||||
t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
|
||||
}
|
||||
if !auth.Secured {
|
||||
|
@ -257,9 +266,9 @@ func TestIngressAuthWithoutSecret(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "invalid-secret"
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "-realm-"
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
|
@ -275,10 +284,10 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "basic"
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||
data[parser.GetAnnotationWithPrefix(authSecretTypeAnnotation)] = "invalid-type"
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "-realm-"
|
||||
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
|
@ -290,7 +299,7 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
|
||||
func dummySecretContent(t *testing.T) (fileName, dir string, s *api.Secret) {
|
||||
dir, err := os.MkdirTemp("", fmt.Sprintf("%v", time.Now().Unix()))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -301,7 +310,10 @@ func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
|
|||
t.Error(err)
|
||||
}
|
||||
defer tmpfile.Close()
|
||||
s, _ := mockSecret{}.GetSecret("default/demo-secret")
|
||||
s, err = mockSecret{}.GetSecret(defaultDemoSecret)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
return tmpfile.Name(), dir, s
|
||||
}
|
||||
|
||||
|
|
|
@ -33,20 +33,21 @@ import (
|
|||
)
|
||||
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
|
@ -56,25 +57,25 @@ var authReqAnnotations = parser.Annotation{
|
|||
Group: "authentication",
|
||||
Annotations: parser.AnnotationFields{
|
||||
authReqURLAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLWithNginxVariableRegex, true),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
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`,
|
||||
|
@ -86,7 +87,7 @@ var authReqAnnotations = parser.Annotation{
|
|||
Documentation: `This annotation allows to specify a custom snippet to use with external authentication`,
|
||||
},
|
||||
authReqCacheKeyAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.NGINXVariable, true),
|
||||
Validator: parser.ValidateRegex(parser.NGINXVariable, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation enables caching for auth requests.`,
|
||||
|
@ -97,6 +98,12 @@ var authReqAnnotations = parser.Annotation{
|
|||
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,
|
||||
|
@ -110,26 +117,26 @@ var authReqAnnotations = parser.Annotation{
|
|||
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),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
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`,
|
||||
|
@ -158,6 +165,7 @@ type Config struct {
|
|||
AuthCacheKey string `json:"authCacheKey"`
|
||||
AuthCacheDuration []string `json:"authCacheDuration"`
|
||||
KeepaliveConnections int `json:"keepaliveConnections"`
|
||||
KeepaliveShareVars bool `json:"keepaliveShareVars"`
|
||||
KeepaliveRequests int `json:"keepaliveRequests"`
|
||||
KeepaliveTimeout int `json:"keepaliveTimeout"`
|
||||
ProxySetHeaders map[string]string `json:"proxySetHeaders,omitempty"`
|
||||
|
@ -170,6 +178,7 @@ const DefaultCacheDuration = "200 202 401 5m"
|
|||
// fallback values when no keepalive parameters are set
|
||||
const (
|
||||
defaultKeepaliveConnections = 0
|
||||
defaultKeepaliveShareVars = false
|
||||
defaultKeepaliveRequests = 1000
|
||||
defaultKeepaliveTimeout = 60
|
||||
)
|
||||
|
@ -218,6 +227,10 @@ func (e1 *Config) Equal(e2 *Config) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if e1.KeepaliveShareVars != e2.KeepaliveShareVars {
|
||||
return false
|
||||
}
|
||||
|
||||
if e1.KeepaliveRequests != e2.KeepaliveRequests {
|
||||
return false
|
||||
}
|
||||
|
@ -236,8 +249,8 @@ func (e1 *Config) Equal(e2 *Config) bool {
|
|||
var (
|
||||
methodsRegex = regexp.MustCompile("(GET|HEAD|POST|PUT|PATCH|DELETE|CONNECT|OPTIONS|TRACE)")
|
||||
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
|
||||
statusCodeRegex = regexp.MustCompile(`^[\d]{3}$`)
|
||||
durationRegex = regexp.MustCompile(`^[\d]+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
|
||||
statusCodeRegex = regexp.MustCompile(`^\d{3}$`)
|
||||
durationRegex = regexp.MustCompile(`^\d+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
|
||||
)
|
||||
|
||||
// ValidMethod checks is the provided string a valid HTTP method
|
||||
|
@ -260,7 +273,7 @@ func ValidCacheDuration(duration string) bool {
|
|||
seenDuration := false
|
||||
|
||||
for _, element := range elements {
|
||||
if len(element) == 0 {
|
||||
if element == "" {
|
||||
continue
|
||||
}
|
||||
if statusCodeRegex.MatchString(element) {
|
||||
|
@ -291,6 +304,8 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
|||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to use an Config URL as source for authentication
|
||||
//
|
||||
//nolint:gocyclo // Ignore function complexity error
|
||||
func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
// Required Parameters
|
||||
urlString, err := parser.GetStringAnnotation(authReqURLAnnotation, ing, a.annotationConfig.Annotations)
|
||||
|
@ -300,7 +315,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
authURL, err := parser.StringToURL(urlString)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
|
||||
return nil, ing_errors.LocationDeniedError{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
|
||||
}
|
||||
|
||||
authMethod, err := parser.GetStringAnnotation(authReqMethodAnnotation, ing, a.annotationConfig.Annotations)
|
||||
|
@ -357,6 +372,12 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
keepaliveShareVars, err := parser.GetBoolAnnotation(authReqKeepaliveShareVarsAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
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")
|
||||
|
@ -391,7 +412,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
if err != nil && ing_errors.IsValidationError(err) {
|
||||
return nil, ing_errors.NewLocationDenied("validation error")
|
||||
}
|
||||
if len(hstr) != 0 {
|
||||
if hstr != "" {
|
||||
harr := strings.Split(hstr, ",")
|
||||
for _, header := range harr {
|
||||
header = strings.TrimSpace(header)
|
||||
|
@ -411,7 +432,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
cns, _, err := cache.SplitMetaNamespaceKey(proxySetHeaderMap)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("error reading configmap name %s from annotation: %w", proxySetHeaderMap, err),
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +444,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
secCfg := a.r.GetSecurityConfiguration()
|
||||
// We don't accept different namespaces for secrets.
|
||||
if !secCfg.AllowCrossNamespaceResources && cns != ing.Namespace {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
return nil, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
|
||||
}
|
||||
}
|
||||
|
@ -467,6 +488,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
AuthCacheKey: authCacheKey,
|
||||
AuthCacheDuration: authCacheDuration,
|
||||
KeepaliveConnections: keepaliveConnections,
|
||||
KeepaliveShareVars: keepaliveShareVars,
|
||||
KeepaliveRequests: keepaliveRequests,
|
||||
KeepaliveTimeout: keepaliveTimeout,
|
||||
ProxySetHeaders: proxySetHeaders,
|
||||
|
@ -479,7 +501,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
// It will always return at least one duration (the default duration)
|
||||
func ParseStringToCacheDurations(input string) ([]string, error) {
|
||||
authCacheDuration := []string{}
|
||||
if len(input) != 0 {
|
||||
if input != "" {
|
||||
arr := strings.Split(input, ",")
|
||||
for _, duration := range arr {
|
||||
duration = strings.TrimSpace(duration)
|
||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package authreq
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -113,7 +112,7 @@ func TestAnnotations(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
||||
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
|
||||
data[parser.GetAnnotationWithPrefix("auth-signin-redirect-param")] = test.signinURLRedirectParam
|
||||
data[parser.GetAnnotationWithPrefix("auth-method")] = fmt.Sprintf("%v", test.method)
|
||||
data[parser.GetAnnotationWithPrefix("auth-method")] = test.method
|
||||
data[parser.GetAnnotationWithPrefix("auth-request-redirect")] = test.requestRedirect
|
||||
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet
|
||||
data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey
|
||||
|
@ -268,28 +267,31 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
|||
title string
|
||||
url string
|
||||
keepaliveConnections string
|
||||
keepaliveShareVars string
|
||||
keepaliveRequests string
|
||||
keepaliveTimeout string
|
||||
expectedConnections int
|
||||
expectedShareVars bool
|
||||
expectedRequests int
|
||||
expectedTimeout int
|
||||
}{
|
||||
{"all set", "http://goog.url", "5", "500", "50", 5, 500, 50},
|
||||
{"no annotation", "http://goog.url", "", "", "", defaultKeepaliveConnections, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"default for connections", "http://goog.url", "x", "500", "50", defaultKeepaliveConnections, 500, 50},
|
||||
{"default for requests", "http://goog.url", "5", "x", "50", 5, defaultKeepaliveRequests, 50},
|
||||
{"default for invalid timeout", "http://goog.url", "5", "500", "x", 5, 500, defaultKeepaliveTimeout},
|
||||
{"variable in host", "http://$host:5000/a/b", "5", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"variable in path", "http://goog.url:5000/$path", "5", "", "", 5, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"negative connections", "http://goog.url", "-2", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"negative requests", "http://goog.url", "5", "-1", "", 0, -1, defaultKeepaliveTimeout},
|
||||
{"negative timeout", "http://goog.url", "5", "", "-1", 0, defaultKeepaliveRequests, -1},
|
||||
{"negative request and timeout", "http://goog.url", "5", "-2", "-3", 0, -2, -3},
|
||||
{"all set", "http://goog.url", "5", "false", "500", "50", 5, false, 500, 50},
|
||||
{"no annotation", "http://goog.url", "", "", "", "", defaultKeepaliveConnections, defaultKeepaliveShareVars, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"default for connections", "http://goog.url", "x", "true", "500", "50", defaultKeepaliveConnections, true, 500, 50},
|
||||
{"default for requests", "http://goog.url", "5", "x", "dummy", "50", 5, defaultKeepaliveShareVars, defaultKeepaliveRequests, 50},
|
||||
{"default for invalid timeout", "http://goog.url", "5", "t", "500", "x", 5, true, 500, defaultKeepaliveTimeout},
|
||||
{"variable in host", "http://$host:5000/a/b", "5", "1", "", "", 0, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"variable in path", "http://goog.url:5000/$path", "5", "t", "", "", 5, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"negative connections", "http://goog.url", "-2", "f", "", "", 0, false, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||
{"negative requests", "http://goog.url", "5", "True", "-1", "", 0, true, -1, defaultKeepaliveTimeout},
|
||||
{"negative timeout", "http://goog.url", "5", "0", "", "-1", 0, false, defaultKeepaliveRequests, -1},
|
||||
{"negative request and timeout", "http://goog.url", "5", "False", "-2", "-3", 0, false, -2, -3},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
||||
data[parser.GetAnnotationWithPrefix("auth-keepalive")] = test.keepaliveConnections
|
||||
data[parser.GetAnnotationWithPrefix("auth-keepalive-share-vars")] = test.keepaliveShareVars
|
||||
data[parser.GetAnnotationWithPrefix("auth-keepalive-timeout")] = test.keepaliveTimeout
|
||||
data[parser.GetAnnotationWithPrefix("auth-keepalive-requests")] = test.keepaliveRequests
|
||||
|
||||
|
@ -313,6 +315,10 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
|||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedConnections, u.KeepaliveConnections)
|
||||
}
|
||||
|
||||
if u.KeepaliveShareVars != test.expectedShareVars {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedShareVars, u.KeepaliveShareVars)
|
||||
}
|
||||
|
||||
if u.KeepaliveRequests != test.expectedRequests {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedRequests, u.KeepaliveRequests)
|
||||
}
|
||||
|
@ -324,7 +330,6 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseStringToCacheDurations(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
title string
|
||||
duration string
|
||||
|
@ -339,7 +344,6 @@ func TestParseStringToCacheDurations(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
dur, err := ParseStringToCacheDurations(test.duration)
|
||||
if test.expErr {
|
||||
if err == nil {
|
||||
|
|
|
@ -55,7 +55,6 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
|||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to enable or disable global external authentication
|
||||
func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
|
||||
enableGlobalAuth, err := parser.GetBoolAnnotation(enableGlobalAuthAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
enableGlobalAuth = true
|
||||
|
|
|
@ -77,7 +77,10 @@ func TestAnnotation(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix("enable-global-auth")] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
u, ok := i.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
|
|
@ -18,11 +18,10 @@ package authtls
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
|
||||
"regexp"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
|
@ -45,20 +44,20 @@ var (
|
|||
regexChars = regexp.QuoteMeta(`()|=`)
|
||||
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
|
||||
commonNameRegex = regexp.MustCompile(`^CN=[/\-.\_\~a-zA-Z0-9` + regexChars + `]*$`)
|
||||
redirectRegex = regexp.MustCompile(`^((https?://)?[A-Za-z0-9\-\.]*(:[0-9]+)?/[A-Za-z0-9\-\.]*)?$`)
|
||||
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),
|
||||
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),
|
||||
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"`,
|
||||
|
@ -70,7 +69,7 @@ var authTLSAnnotations = parser.Annotation{
|
|||
Documentation: `This annotation defines validation depth between the provided client certificate and the Certification Authority chain.`,
|
||||
},
|
||||
annotationAuthTLSErrorPage: {
|
||||
Validator: parser.ValidateRegex(*redirectRegex, true),
|
||||
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`,
|
||||
|
@ -82,7 +81,7 @@ var authTLSAnnotations = parser.Annotation{
|
|||
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),
|
||||
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="`,
|
||||
|
@ -130,9 +129,9 @@ func (assl1 *Config) Equal(assl2 *Config) bool {
|
|||
}
|
||||
|
||||
// NewParser creates a new TLS authentication annotation parser
|
||||
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return authTLS{
|
||||
r: resolver,
|
||||
r: r,
|
||||
annotationConfig: authTLSAnnotations,
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +168,7 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("error obtaining certificate: %w", err)
|
||||
return &Config{}, ing_errors.LocationDenied{Reason: e}
|
||||
return &Config{}, ing_errors.LocationDeniedError{Reason: e}
|
||||
}
|
||||
config.AuthSSLCert = *authCert
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDemoSecret = "default/demo-secret"
|
||||
off = "off"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -77,23 +82,22 @@ type mockSecret struct {
|
|||
|
||||
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS
|
||||
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||
if name != "default/demo-secret" {
|
||||
if name != defaultDemoSecret {
|
||||
return nil, errors.Errorf("there is no secret with name %v", name)
|
||||
}
|
||||
|
||||
return &resolver.AuthSSLCert{
|
||||
Secret: "default/demo-secret",
|
||||
Secret: defaultDemoSecret,
|
||||
CAFileName: "/ssl/ca.crt",
|
||||
CASHA: "abc",
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
data := map[string]string{}
|
||||
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = defaultDemoSecret
|
||||
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
|
@ -108,7 +112,7 @@ func TestAnnotations(t *testing.T) {
|
|||
t.Errorf("expected *Config but got %v", u)
|
||||
}
|
||||
|
||||
secret, err := fakeSecret.GetAuthCertificate("default/demo-secret")
|
||||
secret, err := fakeSecret.GetAuthCertificate(defaultDemoSecret)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error getting secret %v", err)
|
||||
}
|
||||
|
@ -132,7 +136,7 @@ func TestAnnotations(t *testing.T) {
|
|||
t.Errorf("expected empty string, but got %v", u.MatchCN)
|
||||
}
|
||||
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = "off"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = off
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "2"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSErrorPage)] = "ok.com/error"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "true"
|
||||
|
@ -153,8 +157,8 @@ func TestAnnotations(t *testing.T) {
|
|||
if u.AuthSSLCert.Secret != secret.Secret {
|
||||
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
|
||||
}
|
||||
if u.VerifyClient != "off" {
|
||||
t.Errorf("expected %v but got %v", "off", u.VerifyClient)
|
||||
if u.VerifyClient != off {
|
||||
t.Errorf("expected %v but got %v", off, u.VerifyClient)
|
||||
}
|
||||
if u.ValidationDepth != 2 {
|
||||
t.Errorf("expected %v but got %v", 2, u.ValidationDepth)
|
||||
|
@ -262,28 +266,21 @@ func TestInvalidAnnotations(t *testing.T) {
|
|||
if u.MatchCN != "" {
|
||||
t.Errorf("expected empty string but got %v", u.MatchCN)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEquals(t *testing.T) {
|
||||
cfg1 := &Config{}
|
||||
cfg2 := &Config{}
|
||||
|
||||
// Same config
|
||||
result := cfg1.Equal(cfg1)
|
||||
if result != true {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
|
||||
// compare nil
|
||||
result = cfg1.Equal(nil)
|
||||
result := cfg1.Equal(nil)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
|
||||
// Different Certs
|
||||
sslCert1 := resolver.AuthSSLCert{
|
||||
Secret: "default/demo-secret",
|
||||
Secret: defaultDemoSecret,
|
||||
CAFileName: "/ssl/ca.crt",
|
||||
CASHA: "abc",
|
||||
}
|
||||
|
@ -302,7 +299,7 @@ func TestEquals(t *testing.T) {
|
|||
|
||||
// Different Verify Client
|
||||
cfg1.VerifyClient = "on"
|
||||
cfg2.VerifyClient = "off"
|
||||
cfg2.VerifyClient = off
|
||||
result = cfg1.Equal(cfg2)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
|
|
|
@ -25,9 +25,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
var (
|
||||
validProtocols = []string{"auto_http", "http", "https", "grpc", "grpcs", "fcgi"}
|
||||
)
|
||||
var validProtocols = []string{"auto_http", "http", "https", "grpc", "grpcs", "fcgi"}
|
||||
|
||||
const (
|
||||
http = "HTTP"
|
||||
|
|
|
@ -44,6 +44,7 @@ func buildIngress() *networking.Ingress {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInvalidAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
|
@ -56,7 +57,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
|||
if !ok {
|
||||
t.Errorf("expected a string type")
|
||||
}
|
||||
if val != "HTTP" {
|
||||
if val != http {
|
||||
t.Errorf("expected HTTPS but %v returned", val)
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
|||
if !ok {
|
||||
t.Errorf("expected a string type")
|
||||
}
|
||||
if val != "HTTP" {
|
||||
if val != http {
|
||||
t.Errorf("expected HTTPS but %v returned", val)
|
||||
}
|
||||
|
||||
|
@ -88,7 +89,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
|||
if !ok {
|
||||
t.Errorf("expected a string type")
|
||||
}
|
||||
if val != "HTTP" {
|
||||
if val != http {
|
||||
t.Errorf("expected HTTPS but %v returned", val)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ var CanaryAnnotations = parser.Annotation{
|
|||
Documentation: `This annotation The total weight of traffic. If unspecified, it defaults to 100`,
|
||||
},
|
||||
canaryByHeaderAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
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.
|
||||
|
@ -65,7 +65,7 @@ var CanaryAnnotations = parser.Annotation{
|
|||
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),
|
||||
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.
|
||||
|
@ -74,7 +74,7 @@ var CanaryAnnotations = parser.Annotation{
|
|||
It doesn't have any effect if the 'canary-by-header' annotation is not defined`,
|
||||
},
|
||||
canaryByHeaderPatternAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.IsValidRegex, false),
|
||||
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.
|
||||
|
@ -82,7 +82,7 @@ var CanaryAnnotations = parser.Annotation{
|
|||
When the given Regex causes error during request processing, the request will be considered as not matching.`,
|
||||
},
|
||||
canaryByCookieAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
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.
|
||||
|
@ -189,7 +189,7 @@ func (c canary) GetDocumentation() parser.AnnotationFields {
|
|||
return c.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a canary) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (c canary) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(c.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, CanaryAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package canary
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
|
@ -24,8 +25,6 @@ import (
|
|||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
|
||||
"strconv"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
|
@ -93,7 +92,6 @@ func TestCanaryInvalid(t *testing.T) {
|
|||
if val.Weight != 0 {
|
||||
t.Errorf("Expected %v but got %v", 0, val.Weight)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
|
@ -133,10 +131,9 @@ func TestAnnotations(t *testing.T) {
|
|||
}
|
||||
|
||||
continue
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("%v: expected nil but returned error %v", test.title, err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("%v: expected nil but returned error %v", test.title, err)
|
||||
}
|
||||
|
||||
canaryConfig, ok := i.(*Config)
|
||||
|
|
|
@ -31,7 +31,7 @@ var clientBodyBufferSizeConfig = parser.Annotation{
|
|||
Group: "backend",
|
||||
Annotations: parser.AnnotationFields{
|
||||
clientBodyBufferSizeAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.SizeRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.SizeRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
|
||||
Documentation: `Sets buffer size for reading client request body per location.
|
||||
|
@ -65,7 +65,7 @@ func (cbbs clientBodyBufferSize) Parse(ing *networking.Ingress) (interface{}, er
|
|||
return parser.GetStringAnnotation(clientBodyBufferSizeAnnotation, ing, cbbs.annotationConfig.Annotations)
|
||||
}
|
||||
|
||||
func (a clientBodyBufferSize) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (cbbs clientBodyBufferSize) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(cbbs.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, clientBodyBufferSizeConfig.Annotations)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ func TestParse(t *testing.T) {
|
|||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
//nolint:errcheck // Ignore the error since invalid cases will be checked with expected results
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
|
|
|
@ -29,15 +29,13 @@ const (
|
|||
connectionProxyHeaderAnnotation = "connection-proxy-header"
|
||||
)
|
||||
|
||||
var (
|
||||
validConnectionHeaderValue = regexp.MustCompile(`^(close|keep-alive)$`)
|
||||
)
|
||||
var validConnectionHeaderValue = regexp.MustCompile(`^(close|keep-alive)$`)
|
||||
|
||||
var connectionHeadersAnnotations = parser.Annotation{
|
||||
Group: "backend",
|
||||
Annotations: parser.AnnotationFields{
|
||||
connectionProxyHeaderAnnotation: {
|
||||
Validator: parser.ValidateRegex(*validConnectionHeaderValue, true),
|
||||
Validator: parser.ValidateRegex(validConnectionHeaderValue, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation allows setting a specific value for "proxy_set_header Connection" directive. Right now it is restricted to "close" or "keep-alive"`,
|
||||
|
|
|
@ -66,6 +66,5 @@ func TestParse(t *testing.T) {
|
|||
if !p.Equal(testCase.expected) {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, p, testCase.annotations)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,9 +43,9 @@ var (
|
|||
// * Sets a group that can be (https?://)?*?.something.com:port?
|
||||
// * Allows this to be repeated as much as possible, and separated by comma
|
||||
// Otherwise it should be '*'
|
||||
corsOriginRegexValidator = regexp.MustCompile(`^((((https?://)?(\*\.)?[A-Za-z0-9\-\.]*(:[0-9]+)?,?)+)|\*)?$`)
|
||||
corsOriginRegexValidator = regexp.MustCompile(`^((((https?://)?(\*\.)?[A-Za-z0-9\-.]*(:\d+)?,?)+)|\*)?$`)
|
||||
// corsOriginRegex defines the regex for validation inside Parse
|
||||
corsOriginRegex = regexp.MustCompile(`^(https?://(\*\.)?[A-Za-z0-9\-\.]*(:[0-9]+)?|\*)?$`)
|
||||
corsOriginRegex = regexp.MustCompile(`^(https?://(\*\.)?[A-Za-z0-9\-.]*(:\d+)?|\*)?$`)
|
||||
// Method must contain valid methods list (PUT, GET, POST, BLA)
|
||||
// May contain or not spaces between each verb
|
||||
corsMethodsRegex = regexp.MustCompile(`^([A-Za-z]+,?\s?)+$`)
|
||||
|
@ -74,7 +74,7 @@ var corsAnnotation = parser.Annotation{
|
|||
Documentation: `This annotation enables Cross-Origin Resource Sharing (CORS) in an Ingress rule`,
|
||||
},
|
||||
corsAllowOriginAnnotation: {
|
||||
Validator: parser.ValidateRegex(*corsOriginRegexValidator, true),
|
||||
Validator: parser.ValidateRegex(corsOriginRegexValidator, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation controls what's the accepted Origin for CORS.
|
||||
|
@ -82,14 +82,14 @@ var corsAnnotation = parser.Annotation{
|
|||
It also supports single level wildcard subdomains and follows this format: http(s)://*.foo.bar, http(s)://*.bar.foo:8080 or http(s)://*.abc.bar.foo:9000`,
|
||||
},
|
||||
corsAllowHeadersAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.HeadersVariable, true),
|
||||
Validator: parser.ValidateRegex(parser.HeadersVariable, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation controls which headers are accepted.
|
||||
This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -`,
|
||||
},
|
||||
corsAllowMethodsAnnotation: {
|
||||
Validator: parser.ValidateRegex(*corsMethodsRegex, true),
|
||||
Validator: parser.ValidateRegex(corsMethodsRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation controls which methods are accepted.
|
||||
|
@ -102,7 +102,7 @@ var corsAnnotation = parser.Annotation{
|
|||
Documentation: `This annotation controls if credentials can be passed during CORS operations.`,
|
||||
},
|
||||
corsExposeHeadersAnnotation: {
|
||||
Validator: parser.ValidateRegex(*corsExposeHeadersRegex, true),
|
||||
Validator: parser.ValidateRegex(corsExposeHeadersRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation controls which headers are exposed to response.
|
||||
|
@ -260,7 +260,7 @@ func (c cors) GetDocumentation() parser.AnnotationFields {
|
|||
return c.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a cors) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (c cors) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(c.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, corsAnnotation.Annotations)
|
||||
}
|
||||
|
|
|
@ -31,16 +31,14 @@ const (
|
|||
customHTTPErrorsAnnotation = "custom-http-errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// We accept anything between 400 and 599, on a comma separated.
|
||||
arrayOfHTTPErrors = regexp.MustCompile(`^(?:[4,5][0-9][0-9],?)*$`)
|
||||
)
|
||||
// We accept anything between 400 and 599, on a comma separated.
|
||||
var arrayOfHTTPErrors = regexp.MustCompile(`^(?:[4,5]\d{2},?)*$`)
|
||||
|
||||
var customHTTPErrorsAnnotations = parser.Annotation{
|
||||
Group: "backend",
|
||||
Annotations: parser.AnnotationFields{
|
||||
customHTTPErrorsAnnotation: {
|
||||
Validator: parser.ValidateRegex(*arrayOfHTTPErrors, true),
|
||||
Validator: parser.ValidateRegex(arrayOfHTTPErrors, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `If a default backend annotation is specified on the ingress, the errors code specified on this annotation
|
||||
|
@ -72,7 +70,7 @@ func (e customhttperrors) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
}
|
||||
|
||||
cSplit := strings.Split(c, ",")
|
||||
var codes []int
|
||||
codes := make([]int, 0, len(cSplit))
|
||||
for _, i := range cSplit {
|
||||
num, err := strconv.Atoi(i)
|
||||
if err != nil {
|
||||
|
@ -88,7 +86,7 @@ func (e customhttperrors) GetDocumentation() parser.AnnotationFields {
|
|||
return e.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a customhttperrors) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (e customhttperrors) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(e.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, customHTTPErrorsAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -57,14 +57,14 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
|||
|
||||
// Parse parses the annotations contained in the ingress to use
|
||||
// a custom default backend
|
||||
func (db backend) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
s, err := parser.GetStringAnnotation(defaultBackendAnnotation, ing, db.annotationConfig.Annotations)
|
||||
func (b backend) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
s, err := parser.GetStringAnnotation(defaultBackendAnnotation, ing, b.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%v/%v", ing.Namespace, s)
|
||||
svc, err := db.r.GetService(name)
|
||||
svc, err := b.r.GetService(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected error reading service %s: %w", name, err)
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ func (db backend) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return svc, nil
|
||||
}
|
||||
|
||||
func (db backend) GetDocumentation() parser.AnnotationFields {
|
||||
return db.annotationConfig.Annotations
|
||||
func (b backend) GetDocumentation() parser.AnnotationFields {
|
||||
return b.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a backend) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (b backend) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(b.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, defaultBackendAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -35,22 +35,20 @@ const (
|
|||
fastCGIParamsAnnotation = "fastcgi-params-configmap"
|
||||
)
|
||||
|
||||
var (
|
||||
// fast-cgi valid parameters is just a single file name (like index.php)
|
||||
regexValidIndexAnnotationAndKey = regexp.MustCompile(`^[A-Za-z0-9\.\-\_]+$`)
|
||||
)
|
||||
// fast-cgi valid parameters is just a single file name (like index.php)
|
||||
var regexValidIndexAnnotationAndKey = regexp.MustCompile(`^[A-Za-z0-9.\-\_]+$`)
|
||||
|
||||
var fastCGIAnnotations = parser.Annotation{
|
||||
Group: "fastcgi",
|
||||
Annotations: parser.AnnotationFields{
|
||||
fastCGIIndexAnnotation: {
|
||||
Validator: parser.ValidateRegex(*regexValidIndexAnnotationAndKey, true),
|
||||
Validator: parser.ValidateRegex(regexValidIndexAnnotationAndKey, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation can be used to specify an index file`,
|
||||
},
|
||||
fastCGIParamsAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation can be used to specify a ConfigMap containing the fastcgi parameters as a key/value.
|
||||
|
@ -98,7 +96,6 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
|||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to indicate the fastcgiConfig.
|
||||
func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
|
||||
fcgiConfig := Config{}
|
||||
|
||||
if ing.GetAnnotations() == nil {
|
||||
|
@ -125,7 +122,7 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
cmns, cmn, err := cache.SplitMetaNamespaceKey(cm)
|
||||
if err != nil {
|
||||
return fcgiConfig, ing_errors.LocationDenied{
|
||||
return fcgiConfig, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("error reading configmap name from annotation: %w", err),
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +136,7 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
cm = fmt.Sprintf("%v/%v", ing.Namespace, cmn)
|
||||
cmap, err := a.r.GetConfigMap(cm)
|
||||
if err != nil {
|
||||
return fcgiConfig, ing_errors.LocationDenied{
|
||||
return fcgiConfig, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("unexpected error reading configmap %s: %w", cm, err),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,6 @@ func TestParseFastCGIInvalidParamsConfigMapAnnotation(t *testing.T) {
|
|||
|
||||
invalidConfigMapList := []string{"unknown/configMap", "unknown/config/map"}
|
||||
for _, configmap := range invalidConfigMapList {
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix("fastcgi-params-configmap")] = configmap
|
||||
ing.SetAnnotations(data)
|
||||
|
@ -239,11 +238,9 @@ func TestParseFastCGIParamsConfigMapAnnotationWithDifferentNS(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Errorf("Different namespace configmap should return an error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestConfigEquality(t *testing.T) {
|
||||
|
||||
var nilConfig *Config
|
||||
|
||||
config := Config{
|
||||
|
@ -297,7 +294,6 @@ func TestConfigEquality(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_fastcgi_Parse(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
index string
|
||||
|
@ -378,7 +374,6 @@ func Test_fastcgi_Parse(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"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/net"
|
||||
|
@ -57,7 +56,7 @@ var globalRateLimitAnnotationConfig = parser.Annotation{
|
|||
Documentation: `Configures a time window (i.e 1m) that the limit is applied`,
|
||||
},
|
||||
globalRateLimitKeyAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.NGINXVariable, true),
|
||||
Validator: parser.ValidateRegex(parser.NGINXVariable, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskHigh,
|
||||
Documentation: `This annotation Configures a key for counting the samples. Defaults to $remote_addr.
|
||||
|
@ -123,23 +122,23 @@ func (a globalratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
config := &Config{}
|
||||
|
||||
limit, err := parser.GetIntAnnotation(globalRateLimitAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil && errors.IsInvalidContent(err) {
|
||||
if err != nil && ing_errors.IsInvalidContent(err) {
|
||||
return nil, err
|
||||
}
|
||||
rawWindowSize, err := parser.GetStringAnnotation(globalRateLimitWindowAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil && errors.IsValidationError(err) {
|
||||
return config, ing_errors.LocationDenied{
|
||||
if err != nil && ing_errors.IsValidationError(err) {
|
||||
return config, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("failed to parse 'global-rate-limit-window' value: %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
if limit == 0 || len(rawWindowSize) == 0 {
|
||||
if limit == 0 || rawWindowSize == "" {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
windowSize, err := time.ParseDuration(rawWindowSize)
|
||||
if err != nil {
|
||||
return config, ing_errors.LocationDenied{
|
||||
return config, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("failed to parse 'global-rate-limit-window' value: %w", err),
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +147,12 @@ func (a globalratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
if err != nil {
|
||||
klog.Warningf("invalid %s, defaulting to %s", globalRateLimitKeyAnnotation, defaultKey)
|
||||
}
|
||||
if len(key) == 0 {
|
||||
if key == "" {
|
||||
key = defaultKey
|
||||
}
|
||||
|
||||
rawIgnoredCIDRs, err := parser.GetStringAnnotation(globalRateLimitIgnoredCidrsAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil && errors.IsInvalidContent(err) {
|
||||
if err != nil && ing_errors.IsInvalidContent(err) {
|
||||
return nil, err
|
||||
}
|
||||
ignoredCIDRs, err := net.ParseCIDRs(rawIgnoredCIDRs)
|
||||
|
@ -161,7 +160,7 @@ func (a globalratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
config.Namespace = strings.Replace(string(ing.UID), "-", "", -1)
|
||||
config.Namespace = strings.ReplaceAll(string(ing.UID), "-", "")
|
||||
config.Limit = limit
|
||||
config.WindowSize = int(windowSize.Seconds())
|
||||
config.Key = key
|
||||
|
|
|
@ -30,8 +30,10 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const UID = "31285d47-b150-4dcf-bd6f-12c46d769f6e"
|
||||
const expectedUID = "31285d47b1504dcfbd6f12c46d769f6e"
|
||||
const (
|
||||
UID = "31285d47-b150-4dcf-bd6f-12c46d769f6e"
|
||||
expectedUID = "31285d47b1504dcfbd6f12c46d769f6e"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
|
@ -190,10 +192,19 @@ func TestGlobalRateLimiting(t *testing.T) {
|
|||
t.Errorf("expected error '%v' but got '%v'", testCase.expectedErr, actualErr)
|
||||
}
|
||||
|
||||
actualConfig := i.(*Config)
|
||||
actualConfig, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected Config type but got %T", i)
|
||||
}
|
||||
if !testCase.expectedConfig.Equal(actualConfig) {
|
||||
expectedJSON, _ := json.Marshal(testCase.expectedConfig)
|
||||
actualJSON, _ := json.Marshal(actualConfig)
|
||||
expectedJSON, err := json.Marshal(testCase.expectedConfig)
|
||||
if err != nil {
|
||||
t.Errorf("failed to marshal expected config: %v", err)
|
||||
}
|
||||
actualJSON, err := json.Marshal(actualConfig)
|
||||
if err != nil {
|
||||
t.Errorf("failed to marshal actual config: %v", err)
|
||||
}
|
||||
t.Errorf("%v: expected config '%s' but got '%s'", testCase.title, expectedJSON, actualJSON)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func (h2pp http2PushPreload) GetDocumentation() parser.AnnotationFields {
|
|||
return h2pp.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a http2PushPreload) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (h2pp http2PushPreload) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(h2pp.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, http2PushPreloadAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -96,16 +96,15 @@ func (a ipallowlist) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return &SourceRange{CIDR: defaultAllowlistSourceRange}, nil
|
||||
}
|
||||
|
||||
return &SourceRange{CIDR: defaultAllowlistSourceRange}, ing_errors.LocationDenied{
|
||||
return &SourceRange{CIDR: defaultAllowlistSourceRange}, ing_errors.LocationDeniedError{
|
||||
Reason: err,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
values := strings.Split(val, ",")
|
||||
ipnets, ips, err := net.ParseIPNets(values...)
|
||||
if err != nil && len(ips) == 0 {
|
||||
return &SourceRange{CIDR: defaultAllowlistSourceRange}, ing_errors.LocationDenied{
|
||||
return &SourceRange{CIDR: defaultAllowlistSourceRange}, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("the annotation does not contain a valid IP address or network: %w", err),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,16 +93,15 @@ func (a ipdenylist) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return &SourceRange{CIDR: defaultDenylistSourceRange}, nil
|
||||
}
|
||||
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, ing_errors.LocationDenied{
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, ing_errors.LocationDeniedError{
|
||||
Reason: err,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
values := strings.Split(val, ",")
|
||||
ipnets, ips, err := net.ParseIPNets(values...)
|
||||
if err != nil && len(ips) == 0 {
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, ing_errors.LocationDenied{
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, ing_errors.LocationDeniedError{
|
||||
Reason: fmt.Errorf("the annotation does not contain a valid IP address or network: %w", err),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ func TestParse(t *testing.T) {
|
|||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
//nolint:errcheck // Ignore the error since invalid cases will be checked with expected results
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
|
|
|
@ -101,7 +101,7 @@ func (l log) GetDocumentation() parser.AnnotationFields {
|
|||
return l.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a log) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (l log) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(l.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, logAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -76,7 +76,10 @@ func TestIngressAccessLogConfig(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(enableAccessLogAnnotation)] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
log, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
log, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
nginxLogs, ok := log.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -94,7 +97,10 @@ func TestIngressRewriteLogConfig(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(enableRewriteLogAnnotation)] = "true"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
log, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
log, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error parsing annotations %v", err)
|
||||
}
|
||||
nginxLogs, ok := log.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -112,7 +118,10 @@ func TestInvalidBoolConfig(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(enableRewriteLogAnnotation)] = "blo"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
log, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
log, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
nginxLogs, ok := log.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
|
|
@ -34,15 +34,13 @@ const (
|
|||
mirrorHostAnnotation = "mirror-host"
|
||||
)
|
||||
|
||||
var (
|
||||
OnOffRegex = regexp.MustCompile(`^(on|off)$`)
|
||||
)
|
||||
var OnOffRegex = regexp.MustCompile(`^(on|off)$`)
|
||||
|
||||
var mirrorAnnotation = parser.Annotation{
|
||||
Group: "mirror",
|
||||
Annotations: parser.AnnotationFields{
|
||||
mirrorRequestBodyAnnotation: {
|
||||
Validator: parser.ValidateRegex(*OnOffRegex, true),
|
||||
Validator: parser.ValidateRegex(OnOffRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation defines if the request-body should be sent to the mirror backend. Can be 'on' or 'off'`,
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
const (
|
||||
modsecEnableAnnotation = "enable-modsecurity"
|
||||
modsecEnableOwaspCoreAnnotation = "enable-owasp-core-rules"
|
||||
modesecTransactionIdAnnotation = "modsecurity-transaction-id"
|
||||
modesecTransactionIDAnnotation = "modsecurity-transaction-id"
|
||||
modsecSnippetAnnotation = "modsecurity-snippet"
|
||||
)
|
||||
|
||||
|
@ -46,8 +46,8 @@ var modsecurityAnnotation = parser.Annotation{
|
|||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation enables the OWASP Core Rule Set`,
|
||||
},
|
||||
modesecTransactionIdAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.NGINXVariable, true),
|
||||
modesecTransactionIDAnnotation: {
|
||||
Validator: parser.ValidateRegex(parser.NGINXVariable, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskHigh,
|
||||
Documentation: `This annotation enables passing an NGINX variable to ModSecurity.`,
|
||||
|
@ -98,9 +98,9 @@ func (modsec1 *Config) Equal(modsec2 *Config) bool {
|
|||
}
|
||||
|
||||
// NewParser creates a new ModSecurity annotation parser
|
||||
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return modSecurity{
|
||||
r: resolver,
|
||||
r: r,
|
||||
annotationConfig: modsecurityAnnotation,
|
||||
}
|
||||
}
|
||||
|
@ -134,10 +134,10 @@ func (a modSecurity) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
config.OWASPRules = false
|
||||
}
|
||||
|
||||
config.TransactionID, err = parser.GetStringAnnotation(modesecTransactionIdAnnotation, ing, a.annotationConfig.Annotations)
|
||||
config.TransactionID, err = parser.GetStringAnnotation(modesecTransactionIDAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if errors.IsInvalidContent(err) {
|
||||
klog.Warningf("annotation %s contains invalid directive, defaulting", modesecTransactionIdAnnotation)
|
||||
klog.Warningf("annotation %s contains invalid directive, defaulting", modesecTransactionIDAnnotation)
|
||||
}
|
||||
config.TransactionID = ""
|
||||
}
|
||||
|
|
|
@ -69,8 +69,14 @@ func TestParse(t *testing.T) {
|
|||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
config := result.(*Config)
|
||||
result, err := ap.Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
config, ok := result.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("unexpected type: %T", result)
|
||||
}
|
||||
if !config.Equal(&testCase.expected) {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ var otelAnnotations = parser.Annotation{
|
|||
Documentation: `This annotation enables or disables using spans from incoming requests as parent for created ones`,
|
||||
},
|
||||
otelOperationNameAnnotation: {
|
||||
Validator: parser.ValidateRegex(*regexOperationName, true),
|
||||
Validator: parser.ValidateRegex(regexOperationName, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation defines what operation name should be added to the span`,
|
||||
|
@ -75,7 +75,6 @@ type Config struct {
|
|||
|
||||
// Equal tests for equality between two Config types
|
||||
func (bd1 *Config) Equal(bd2 *Config) bool {
|
||||
|
||||
if bd1.Set != bd2.Set {
|
||||
return false
|
||||
}
|
||||
|
@ -150,7 +149,7 @@ func (c opentelemetry) GetDocumentation() parser.AnnotationFields {
|
|||
return c.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a opentelemetry) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (c opentelemetry) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(c.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, otelAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const enableAnnotation = "true"
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -73,10 +75,13 @@ func TestIngressAnnotationOpentelemetrySetTrue(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = enableAnnotation
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
openTelemetry, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -103,7 +108,10 @@ func TestIngressAnnotationOpentelemetrySetFalse(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
openTelemetry, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -123,8 +131,8 @@ func TestIngressAnnotationOpentelemetryTrustSetTrue(t *testing.T) {
|
|||
|
||||
data := map[string]string{}
|
||||
opName := "foo-op"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(otelTrustSpanAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = enableAnnotation
|
||||
data[parser.GetAnnotationWithPrefix(otelTrustSpanAnnotation)] = enableAnnotation
|
||||
data[parser.GetAnnotationWithPrefix(otelOperationNameAnnotation)] = opName
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
|
@ -163,7 +171,7 @@ func TestIngressAnnotationOpentelemetryWithBadOpName(t *testing.T) {
|
|||
|
||||
data := map[string]string{}
|
||||
opName := "fooxpto_123$la;"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpenTelemetryAnnotation)] = enableAnnotation
|
||||
data[parser.GetAnnotationWithPrefix(otelOperationNameAnnotation)] = opName
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
|
@ -180,7 +188,10 @@ func TestIngressAnnotationOpentelemetryUnset(t *testing.T) {
|
|||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
_, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
|
|
@ -89,13 +89,13 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
|||
}
|
||||
}
|
||||
|
||||
func (s opentracing) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
enabled, err := parser.GetBoolAnnotation(enableOpentracingAnnotation, ing, s.annotationConfig.Annotations)
|
||||
func (o opentracing) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
enabled, err := parser.GetBoolAnnotation(enableOpentracingAnnotation, ing, o.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
return &Config{}, nil
|
||||
}
|
||||
|
||||
trustSpan, err := parser.GetBoolAnnotation(opentracingTrustSpanAnnotation, ing, s.annotationConfig.Annotations)
|
||||
trustSpan, err := parser.GetBoolAnnotation(opentracingTrustSpanAnnotation, ing, o.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
return &Config{Set: true, Enabled: enabled}, nil
|
||||
}
|
||||
|
@ -103,11 +103,11 @@ func (s opentracing) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return &Config{Set: true, Enabled: enabled, TrustSet: true, TrustEnabled: trustSpan}, nil
|
||||
}
|
||||
|
||||
func (s opentracing) GetDocumentation() parser.AnnotationFields {
|
||||
return s.annotationConfig.Annotations
|
||||
func (o opentracing) GetDocumentation() parser.AnnotationFields {
|
||||
return o.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a opentracing) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (o opentracing) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(o.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, opentracingAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const enableAnnotation = "true"
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -73,10 +75,13 @@ func TestIngressAnnotationOpentracingSetTrue(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(enableOpentracingAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpentracingAnnotation)] = enableAnnotation
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error %v", err)
|
||||
}
|
||||
openTracing, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -95,7 +100,10 @@ func TestIngressAnnotationOpentracingSetFalse(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(enableOpentracingAnnotation)] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error %v", err)
|
||||
}
|
||||
openTracing, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -110,11 +118,14 @@ func TestIngressAnnotationOpentracingTrustSetTrue(t *testing.T) {
|
|||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix(enableOpentracingAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(opentracingTrustSpanAnnotation)] = "true"
|
||||
data[parser.GetAnnotationWithPrefix(enableOpentracingAnnotation)] = enableAnnotation
|
||||
data[parser.GetAnnotationWithPrefix(opentracingTrustSpanAnnotation)] = enableAnnotation
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error %v", err)
|
||||
}
|
||||
openTracing, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
@ -136,7 +147,11 @@ func TestIngressAnnotationOpentracingUnset(t *testing.T) {
|
|||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
val, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, ok := val.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
|
|
|
@ -118,7 +118,7 @@ func (a ingAnnotations) parseString(name string) (string, error) {
|
|||
val, ok := a[name]
|
||||
if ok {
|
||||
s := normalizeString(val)
|
||||
if len(s) == 0 {
|
||||
if s == "" {
|
||||
return "", errors.NewInvalidAnnotationContent(name, val)
|
||||
}
|
||||
|
||||
|
@ -248,13 +248,14 @@ func StringToURL(input string) (*url.URL, error) {
|
|||
return nil, fmt.Errorf("%v is not a valid URL: %v", input, err)
|
||||
}
|
||||
|
||||
if parsedURL.Scheme == "" {
|
||||
switch {
|
||||
case parsedURL.Scheme == "":
|
||||
return nil, fmt.Errorf("url scheme is empty")
|
||||
} else if parsedURL.Host == "" {
|
||||
case parsedURL.Host == "":
|
||||
return nil, fmt.Errorf("url host is empty")
|
||||
} else if strings.Contains(parsedURL.Host, "..") {
|
||||
case strings.Contains(parsedURL.Host, ".."):
|
||||
return nil, fmt.Errorf("invalid url host")
|
||||
default:
|
||||
return parsedURL, nil
|
||||
}
|
||||
|
||||
return parsedURL, nil
|
||||
}
|
||||
|
|
|
@ -93,14 +93,16 @@ func TestGetStringAnnotation(t *testing.T) {
|
|||
{"valid - A", "string", "A ", "A", false},
|
||||
{"valid - B", "string", " B", "B", false},
|
||||
{"empty", "string", " ", "", true},
|
||||
{"valid multiline", "string", `
|
||||
{
|
||||
"valid multiline", "string", `
|
||||
rewrite (?i)/arcgis/rest/services/Utilities/Geometry/GeometryServer(.*)$ /arcgis/rest/services/Utilities/Geometry/GeometryServer$1 break;
|
||||
rewrite (?i)/arcgis/services/Utilities/Geometry/GeometryServer(.*)$ /arcgis/services/Utilities/Geometry/GeometryServer$1 break;
|
||||
`, `
|
||||
rewrite (?i)/arcgis/rest/services/Utilities/Geometry/GeometryServer(.*)$ /arcgis/rest/services/Utilities/Geometry/GeometryServer$1 break;
|
||||
rewrite (?i)/arcgis/services/Utilities/Geometry/GeometryServer(.*)$ /arcgis/services/Utilities/Geometry/GeometryServer$1 break;
|
||||
`,
|
||||
false},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
data := map[string]string{}
|
||||
|
@ -213,8 +215,10 @@ func TestGetIntAnnotation(t *testing.T) {
|
|||
|
||||
func TestStringToURL(t *testing.T) {
|
||||
validURL := "http://bar.foo.com/external-auth"
|
||||
validParsedURL, _ := url.Parse(validURL)
|
||||
|
||||
validParsedURL, err := url.Parse(validURL)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
tests := []struct {
|
||||
title string
|
||||
url string
|
||||
|
|
|
@ -52,7 +52,7 @@ var (
|
|||
var IsValidRegex = regexp.MustCompile("^[/" + alphaNumericChars + regexEnabledChars + "]*$")
|
||||
|
||||
// SizeRegex validates sizes understood by NGINX, like 1000, 100k, 1000M
|
||||
var SizeRegex = regexp.MustCompile("^(?i)[0-9]+[bkmg]?$")
|
||||
var SizeRegex = regexp.MustCompile(`^(?i)\d+[bkmg]?$`)
|
||||
|
||||
// URLRegex is used to validate a URL but with only a specific set of characters:
|
||||
// It is alphanumericChar + ":", "?", "&"
|
||||
|
@ -103,7 +103,7 @@ func ValidateServerName(value string) error {
|
|||
// ValidateRegex receives a regex as an argument and uses it to validate
|
||||
// the value of the field.
|
||||
// Annotation can define if the spaces should be trimmed before validating the value
|
||||
func ValidateRegex(regex regexp.Regexp, removeSpace bool) AnnotationValidator {
|
||||
func ValidateRegex(regex *regexp.Regexp, removeSpace bool) AnnotationValidator {
|
||||
return func(s string) error {
|
||||
if removeSpace {
|
||||
s = strings.ReplaceAll(s, " ", "")
|
||||
|
@ -117,7 +117,7 @@ func ValidateRegex(regex regexp.Regexp, removeSpace bool) AnnotationValidator {
|
|||
|
||||
// ValidateOptions receives an array of valid options that can be the value of annotation.
|
||||
// If no valid option is found, it will return an error
|
||||
func ValidateOptions(options []string, caseSensitive bool, trimSpace bool) AnnotationValidator {
|
||||
func ValidateOptions(options []string, caseSensitive, trimSpace bool) AnnotationValidator {
|
||||
return func(s string) error {
|
||||
if trimSpace {
|
||||
s = strings.TrimSpace(s)
|
||||
|
@ -161,7 +161,7 @@ func ValidateDuration(value string) error {
|
|||
// ValidateNull always return null values and should not be widely used.
|
||||
// It is used on the "snippet" annotations, as it is up to the admin to allow its
|
||||
// usage, knowing it can be critical!
|
||||
func ValidateNull(value string) error {
|
||||
func ValidateNull(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,6 @@ func Test_checkAnnotation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCheckAnnotationRisk(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
annotations map[string]string
|
||||
|
|
|
@ -45,9 +45,7 @@ const (
|
|||
proxyMaxTempFileSizeAnnotation = "proxy-max-temp-file-size"
|
||||
)
|
||||
|
||||
var (
|
||||
validUpstreamAnnotation = regexp.MustCompile(`^((error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_403|http_404|http_429|non_idempotent|off)\s?)+$`)
|
||||
)
|
||||
var validUpstreamAnnotation = regexp.MustCompile(`^((error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_403|http_404|http_429|non_idempotent|off)\s?)+$`)
|
||||
|
||||
var proxyAnnotations = parser.Annotation{
|
||||
Group: "backend",
|
||||
|
@ -78,32 +76,32 @@ var proxyAnnotations = parser.Annotation{
|
|||
By default proxy buffers number is set as 4`,
|
||||
},
|
||||
proxyBufferSizeAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.SizeRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.SizeRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation sets the size of the buffer proxy_buffer_size used for reading the first part of the response received from the proxied server.
|
||||
By default proxy buffer size is set as "4k".`,
|
||||
},
|
||||
proxyCookiePathAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation sets a text that should be changed in the path attribute of the "Set-Cookie" header fields of a proxied server response.`,
|
||||
},
|
||||
proxyCookieDomainAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation ets a text that should be changed in the domain attribute of the "Set-Cookie" header fields of a proxied server response.`,
|
||||
},
|
||||
proxyBodySizeAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.SizeRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.SizeRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation allows setting the maximum allowed size of a client request body.`,
|
||||
},
|
||||
proxyNextUpstreamAnnotation: {
|
||||
Validator: parser.ValidateRegex(*validUpstreamAnnotation, false),
|
||||
Validator: parser.ValidateRegex(validUpstreamAnnotation, false),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation defines when the next upstream should be used.
|
||||
|
@ -129,13 +127,13 @@ var proxyAnnotations = parser.Annotation{
|
|||
Documentation: `This annotation enables or disables buffering of a client request body.`,
|
||||
},
|
||||
proxyRedirectFromAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `The annotations proxy-redirect-from and proxy-redirect-to will set the first and second parameters of NGINX's proxy_redirect directive respectively`,
|
||||
},
|
||||
proxyRedirectToAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `The annotations proxy-redirect-from and proxy-redirect-to will set the first and second parameters of NGINX's proxy_redirect directive respectively`,
|
||||
|
@ -153,7 +151,7 @@ var proxyAnnotations = parser.Annotation{
|
|||
Documentation: `This annotations sets the HTTP protocol version for proxying. Can be "1.0" or "1.1".`,
|
||||
},
|
||||
proxyMaxTempFileSizeAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.SizeRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.SizeRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation defines the maximum size of a temporary file when buffering responses.`,
|
||||
|
@ -253,7 +251,8 @@ type proxy struct {
|
|||
|
||||
// NewParser creates a new reverse proxy configuration annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return proxy{r: r,
|
||||
return proxy{
|
||||
r: r,
|
||||
annotationConfig: proxyAnnotations,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,12 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
off = "off"
|
||||
proxyHTTPVersion = "1.0"
|
||||
proxyMaxTempFileSize = "128k"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -87,7 +93,7 @@ func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
|||
ProxyNextUpstreamTimeout: 0,
|
||||
ProxyNextUpstreamTries: 3,
|
||||
ProxyRequestBuffering: "on",
|
||||
ProxyBuffering: "off",
|
||||
ProxyBuffering: off,
|
||||
ProxyHTTPVersion: "1.1",
|
||||
ProxyMaxTempFileSize: "1024m",
|
||||
}
|
||||
|
@ -103,13 +109,13 @@ func TestProxy(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix("proxy-buffers-number")] = "8"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-buffer-size")] = "1k"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-body-size")] = "2k"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-next-upstream")] = "off"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-next-upstream")] = off
|
||||
data[parser.GetAnnotationWithPrefix("proxy-next-upstream-timeout")] = "5"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-next-upstream-tries")] = "3"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-request-buffering")] = "off"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-request-buffering")] = off
|
||||
data[parser.GetAnnotationWithPrefix("proxy-buffering")] = "on"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-http-version")] = "1.0"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-max-temp-file-size")] = "128k"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-http-version")] = proxyHTTPVersion
|
||||
data[parser.GetAnnotationWithPrefix("proxy-max-temp-file-size")] = proxyMaxTempFileSize
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
|
@ -138,7 +144,7 @@ func TestProxy(t *testing.T) {
|
|||
if p.BodySize != "2k" {
|
||||
t.Errorf("expected 2k as body-size but returned %v", p.BodySize)
|
||||
}
|
||||
if p.NextUpstream != "off" {
|
||||
if p.NextUpstream != off {
|
||||
t.Errorf("expected off as next-upstream but returned %v", p.NextUpstream)
|
||||
}
|
||||
if p.NextUpstreamTimeout != 5 {
|
||||
|
@ -147,16 +153,16 @@ func TestProxy(t *testing.T) {
|
|||
if p.NextUpstreamTries != 3 {
|
||||
t.Errorf("expected 3 as next-upstream-tries but returned %v", p.NextUpstreamTries)
|
||||
}
|
||||
if p.RequestBuffering != "off" {
|
||||
if p.RequestBuffering != off {
|
||||
t.Errorf("expected off as request-buffering but returned %v", p.RequestBuffering)
|
||||
}
|
||||
if p.ProxyBuffering != "on" {
|
||||
t.Errorf("expected on as proxy-buffering but returned %v", p.ProxyBuffering)
|
||||
}
|
||||
if p.ProxyHTTPVersion != "1.0" {
|
||||
if p.ProxyHTTPVersion != proxyHTTPVersion {
|
||||
t.Errorf("expected 1.0 as proxy-http-version but returned %v", p.ProxyHTTPVersion)
|
||||
}
|
||||
if p.ProxyMaxTempFileSize != "128k" {
|
||||
if p.ProxyMaxTempFileSize != proxyMaxTempFileSize {
|
||||
t.Errorf("expected 128k as proxy-max-temp-file-size but returned %v", p.ProxyMaxTempFileSize)
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +182,8 @@ func TestProxyComplex(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix("proxy-next-upstream-tries")] = "3"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-request-buffering")] = "off"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-buffering")] = "on"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-http-version")] = "1.0"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-max-temp-file-size")] = "128k"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-http-version")] = proxyHTTPVersion
|
||||
data[parser.GetAnnotationWithPrefix("proxy-max-temp-file-size")] = proxyMaxTempFileSize
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
|
@ -221,10 +227,10 @@ func TestProxyComplex(t *testing.T) {
|
|||
if p.ProxyBuffering != "on" {
|
||||
t.Errorf("expected on as proxy-buffering but returned %v", p.ProxyBuffering)
|
||||
}
|
||||
if p.ProxyHTTPVersion != "1.0" {
|
||||
if p.ProxyHTTPVersion != proxyHTTPVersion {
|
||||
t.Errorf("expected 1.0 as proxy-http-version but returned %v", p.ProxyHTTPVersion)
|
||||
}
|
||||
if p.ProxyMaxTempFileSize != "128k" {
|
||||
if p.ProxyMaxTempFileSize != proxyMaxTempFileSize {
|
||||
t.Errorf("expected 128k as proxy-max-temp-file-size but returned %v", p.ProxyMaxTempFileSize)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"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/k8s"
|
||||
|
@ -42,7 +41,7 @@ const (
|
|||
var (
|
||||
proxySSLOnOffRegex = regexp.MustCompile(`^(on|off)$`)
|
||||
proxySSLProtocolRegex = regexp.MustCompile(`^(SSLv2|SSLv3|TLSv1|TLSv1\.1|TLSv1\.2|TLSv1\.3| )*$`)
|
||||
proxySSLCiphersRegex = regexp.MustCompile(`^[A-Za-z0-9\+\:\_\-\!]*$`)
|
||||
proxySSLCiphersRegex = regexp.MustCompile(`^[A-Za-z0-9\+:\_\-!]*$`)
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -59,7 +58,7 @@ var proxySSLAnnotation = parser.Annotation{
|
|||
Group: "proxy",
|
||||
Annotations: parser.AnnotationFields{
|
||||
proxySSLSecretAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation specifies a Secret with the certificate tls.crt, key tls.key in PEM format used for authentication to a proxied HTTPS server.
|
||||
|
@ -68,14 +67,14 @@ var proxySSLAnnotation = parser.Annotation{
|
|||
Just secrets on the same namespace of the ingress can be used.`,
|
||||
},
|
||||
proxySSLCiphersAnnotation: {
|
||||
Validator: parser.ValidateRegex(*proxySSLCiphersRegex, true),
|
||||
Validator: parser.ValidateRegex(proxySSLCiphersRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation Specifies the enabled ciphers for requests to a proxied HTTPS server.
|
||||
The ciphers are specified in the format understood by the OpenSSL library.`,
|
||||
},
|
||||
proxySSLProtocolsAnnotation: {
|
||||
Validator: parser.ValidateRegex(*proxySSLProtocolRegex, true),
|
||||
Validator: parser.ValidateRegex(proxySSLProtocolRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation enables the specified protocols for requests to a proxied HTTPS server.`,
|
||||
|
@ -88,7 +87,7 @@ var proxySSLAnnotation = parser.Annotation{
|
|||
This value is also passed through SNI when a connection is established to the proxied HTTPS server.`,
|
||||
},
|
||||
proxySSLVerifyAnnotation: {
|
||||
Validator: parser.ValidateRegex(*proxySSLOnOffRegex, true),
|
||||
Validator: parser.ValidateRegex(proxySSLOnOffRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation enables or disables verification of the proxied HTTPS server certificate. (default: off)`,
|
||||
|
@ -100,7 +99,7 @@ var proxySSLAnnotation = parser.Annotation{
|
|||
Documentation: `This annotation Sets the verification depth in the proxied HTTPS server certificates chain. (default: 1).`,
|
||||
},
|
||||
proxySSLServerNameAnnotation: {
|
||||
Validator: parser.ValidateRegex(*proxySSLOnOffRegex, true),
|
||||
Validator: parser.ValidateRegex(proxySSLOnOffRegex, true),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskLow,
|
||||
Documentation: `This annotation enables passing of the server name through TLS Server Name Indication extension (SNI, RFC 6066) when establishing a connection with the proxied HTTPS server.`,
|
||||
|
@ -150,10 +149,11 @@ func (pssl1 *Config) Equal(pssl2 *Config) bool {
|
|||
}
|
||||
|
||||
// NewParser creates a new TLS authentication annotation parser
|
||||
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return proxySSL{
|
||||
r: resolver,
|
||||
annotationConfig: proxySSLAnnotation}
|
||||
r: r,
|
||||
annotationConfig: proxySSLAnnotation,
|
||||
}
|
||||
}
|
||||
|
||||
type proxySSL struct {
|
||||
|
@ -208,13 +208,13 @@ func (p proxySSL) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
proxyCert, err := p.r.GetAuthCertificate(proxysslsecret)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("error obtaining certificate: %w", err)
|
||||
return &Config{}, ing_errors.LocationDenied{Reason: e}
|
||||
return &Config{}, ing_errors.LocationDeniedError{Reason: e}
|
||||
}
|
||||
config.AuthSSLCert = *proxyCert
|
||||
|
||||
config.Ciphers, err = parser.GetStringAnnotation(proxySSLCiphersAnnotation, ing, p.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if errors.IsValidationError(err) {
|
||||
if ing_errors.IsValidationError(err) {
|
||||
klog.Warningf("invalid value passed to proxy-ssl-ciphers, defaulting to %s", defaultProxySSLCiphers)
|
||||
}
|
||||
config.Ciphers = defaultProxySSLCiphers
|
||||
|
@ -222,7 +222,7 @@ func (p proxySSL) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
config.Protocols, err = parser.GetStringAnnotation(proxySSLProtocolsAnnotation, ing, p.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if errors.IsValidationError(err) {
|
||||
if ing_errors.IsValidationError(err) {
|
||||
klog.Warningf("invalid value passed to proxy-ssl-protocols, defaulting to %s", defaultProxySSLProtocols)
|
||||
}
|
||||
config.Protocols = defaultProxySSLProtocols
|
||||
|
@ -232,7 +232,7 @@ func (p proxySSL) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
config.ProxySSLName, err = parser.GetStringAnnotation(proxySSLNameAnnotation, ing, p.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if errors.IsValidationError(err) {
|
||||
if ing_errors.IsValidationError(err) {
|
||||
klog.Warningf("invalid value passed to proxy-ssl-name, defaulting to empty")
|
||||
}
|
||||
config.ProxySSLName = ""
|
||||
|
@ -260,7 +260,7 @@ func (p proxySSL) GetDocumentation() parser.AnnotationFields {
|
|||
return p.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a proxySSL) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (p proxySSL) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(p.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, proxySSLAnnotation.Annotations)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,14 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDemoSecret = "default/demo-secret"
|
||||
proxySslCiphers = "HIGH:-SHA"
|
||||
off = "off"
|
||||
sslServerName = "w00t"
|
||||
defaultProtocol = "SSLv2 TLSv1 TLSv1.2 TLSv1.3"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
|
@ -77,28 +85,27 @@ type mockSecret struct {
|
|||
|
||||
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for backend certificate authentication
|
||||
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||
if name != "default/demo-secret" {
|
||||
if name != defaultDemoSecret {
|
||||
return nil, errors.Errorf("there is no secret with name %v", name)
|
||||
}
|
||||
|
||||
return &resolver.AuthSSLCert{
|
||||
Secret: "default/demo-secret",
|
||||
Secret: defaultDemoSecret,
|
||||
CAFileName: "/ssl/ca.crt",
|
||||
CASHA: "abc",
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
data := map[string]string{}
|
||||
|
||||
data[parser.GetAnnotationWithPrefix(proxySSLSecretAnnotation)] = "default/demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-ciphers")] = "HIGH:-SHA"
|
||||
data[parser.GetAnnotationWithPrefix(proxySSLSecretAnnotation)] = defaultDemoSecret
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-ciphers")] = proxySslCiphers
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-name")] = "$host"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-protocols")] = "TLSv1.3 SSLv2 TLSv1 TLSv1.2"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-server-name")] = "on"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-session-reuse")] = "off"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-session-reuse")] = off
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-verify")] = "on"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-verify-depth")] = "3"
|
||||
|
||||
|
@ -115,7 +122,7 @@ func TestAnnotations(t *testing.T) {
|
|||
t.Errorf("expected *Config but got %v", u)
|
||||
}
|
||||
|
||||
secret, err := fakeSecret.GetAuthCertificate("default/demo-secret")
|
||||
secret, err := fakeSecret.GetAuthCertificate(defaultDemoSecret)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error getting secret %v", err)
|
||||
}
|
||||
|
@ -123,11 +130,11 @@ func TestAnnotations(t *testing.T) {
|
|||
if u.AuthSSLCert.Secret != secret.Secret {
|
||||
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
|
||||
}
|
||||
if u.Ciphers != "HIGH:-SHA" {
|
||||
t.Errorf("expected %v but got %v", "HIGH:-SHA", u.Ciphers)
|
||||
if u.Ciphers != proxySslCiphers {
|
||||
t.Errorf("expected %v but got %v", proxySslCiphers, u.Ciphers)
|
||||
}
|
||||
if u.Protocols != "SSLv2 TLSv1 TLSv1.2 TLSv1.3" {
|
||||
t.Errorf("expected %v but got %v", "SSLv2 TLSv1 TLSv1.2 TLSv1.3", u.Protocols)
|
||||
if u.Protocols != defaultProtocol {
|
||||
t.Errorf("expected %v but got %v", defaultProtocol, u.Protocols)
|
||||
}
|
||||
if u.Verify != "on" {
|
||||
t.Errorf("expected %v but got %v", "on", u.Verify)
|
||||
|
@ -141,7 +148,6 @@ func TestAnnotations(t *testing.T) {
|
|||
if u.ProxySSLServerName != "on" {
|
||||
t.Errorf("expected %v but got %v", "on", u.ProxySSLServerName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInvalidAnnotations(t *testing.T) {
|
||||
|
@ -172,11 +178,11 @@ func TestInvalidAnnotations(t *testing.T) {
|
|||
}
|
||||
|
||||
// Invalid optional Annotations
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-secret")] = "default/demo-secret"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-secret")] = defaultDemoSecret
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-protocols")] = "TLSv111 SSLv1"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-server-name")] = "w00t"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-session-reuse")] = "w00t"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-verify")] = "w00t"
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-server-name")] = sslServerName
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-session-reuse")] = sslServerName
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-verify")] = sslServerName
|
||||
data[parser.GetAnnotationWithPrefix("proxy-ssl-verify-depth")] = "abcd"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
|
@ -207,21 +213,15 @@ func TestEquals(t *testing.T) {
|
|||
cfg1 := &Config{}
|
||||
cfg2 := &Config{}
|
||||
|
||||
// Same config
|
||||
result := cfg1.Equal(cfg1)
|
||||
if result != true {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
|
||||
// compare nil
|
||||
result = cfg1.Equal(nil)
|
||||
result := cfg1.Equal(nil)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
|
||||
// Different Certs
|
||||
sslCert1 := resolver.AuthSSLCert{
|
||||
Secret: "default/demo-secret",
|
||||
Secret: defaultDemoSecret,
|
||||
CAFileName: "/ssl/ca.crt",
|
||||
CASHA: "abc",
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ func TestEquals(t *testing.T) {
|
|||
|
||||
// Different Ciphers
|
||||
cfg1.Ciphers = "DEFAULT"
|
||||
cfg2.Ciphers = "HIGH:-SHA"
|
||||
cfg2.Ciphers = proxySslCiphers
|
||||
result = cfg1.Equal(cfg2)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
|
@ -248,22 +248,22 @@ func TestEquals(t *testing.T) {
|
|||
cfg2.Ciphers = "DEFAULT"
|
||||
|
||||
// Different Protocols
|
||||
cfg1.Protocols = "SSLv2 TLSv1 TLSv1.2 TLSv1.3"
|
||||
cfg1.Protocols = defaultProtocol
|
||||
cfg2.Protocols = "SSLv3 TLSv1 TLSv1.2 TLSv1.3"
|
||||
result = cfg1.Equal(cfg2)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
cfg2.Protocols = "SSLv2 TLSv1 TLSv1.2 TLSv1.3"
|
||||
cfg2.Protocols = defaultProtocol
|
||||
|
||||
// Different Verify
|
||||
cfg1.Verify = "off"
|
||||
cfg1.Verify = off
|
||||
cfg2.Verify = "on"
|
||||
result = cfg1.Equal(cfg2)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
cfg2.Verify = "off"
|
||||
cfg2.Verify = off
|
||||
|
||||
// Different VerifyDepth
|
||||
cfg1.VerifyDepth = 1
|
||||
|
@ -275,13 +275,13 @@ func TestEquals(t *testing.T) {
|
|||
cfg2.VerifyDepth = 1
|
||||
|
||||
// Different ProxySSLServerName
|
||||
cfg1.ProxySSLServerName = "off"
|
||||
cfg1.ProxySSLServerName = off
|
||||
cfg2.ProxySSLServerName = "on"
|
||||
result = cfg1.Equal(cfg2)
|
||||
if result != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
cfg2.ProxySSLServerName = "off"
|
||||
cfg2.ProxySSLServerName = off
|
||||
|
||||
// Equal Configs
|
||||
result = cfg1.Equal(cfg2)
|
||||
|
|
|
@ -288,7 +288,7 @@ func (a ratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
|
||||
func encode(s string) string {
|
||||
str := base64.URLEncoding.EncodeToString([]byte(s))
|
||||
return strings.Replace(str, "=", "", -1)
|
||||
return strings.ReplaceAll(str, "=", "")
|
||||
}
|
||||
|
||||
func (a ratelimit) GetDocumentation() parser.AnnotationFields {
|
||||
|
|
|
@ -54,14 +54,14 @@ var redirectAnnotations = parser.Annotation{
|
|||
Documentation: `In some scenarios is required to redirect from www.domain.com to domain.com or vice versa. To enable this feature use this annotation.`,
|
||||
},
|
||||
temporalRedirectAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, false),
|
||||
Validator: parser.ValidateRegex(parser.URLIsValidRegex, false),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium, // Medium, as it allows arbitrary URLs that needs to be validated
|
||||
Documentation: `This annotation allows you to return a temporal redirect (Return Code 302) instead of sending data to the upstream.
|
||||
For example setting this annotation to https://www.google.com would redirect everything to Google with a Return Code of 302 (Moved Temporarily).`,
|
||||
},
|
||||
permanentRedirectAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, false),
|
||||
Validator: parser.ValidateRegex(parser.URLIsValidRegex, false),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium, // Medium, as it allows arbitrary URLs that needs to be validated
|
||||
Documentation: `This annotation allows to return a permanent redirect (Return Code 301) instead of sending data to the upstream.
|
||||
|
@ -174,11 +174,11 @@ func isValidURL(s string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a redirect) GetDocumentation() parser.AnnotationFields {
|
||||
return a.annotationConfig.Annotations
|
||||
func (r redirect) GetDocumentation() parser.AnnotationFields {
|
||||
return r.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a redirect) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
func (r redirect) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(r.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, redirectAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
@ -136,7 +136,6 @@ func TestTemporalRedirect(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsValidURL(t *testing.T) {
|
||||
|
||||
invalid := "ok.com"
|
||||
urlParse, err := url.Parse(invalid)
|
||||
if err != nil {
|
||||
|
|
|
@ -40,7 +40,7 @@ var rewriteAnnotations = parser.Annotation{
|
|||
Group: "rewrite",
|
||||
Annotations: parser.AnnotationFields{
|
||||
rewriteTargetAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.RegexPathWithCapture, false),
|
||||
Validator: parser.ValidateRegex(parser.RegexPathWithCapture, false),
|
||||
Scope: parser.AnnotationScopeIngress,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation allows to specify the target URI where the traffic must be redirected. It can contain regular characters and captured
|
||||
|
@ -72,7 +72,7 @@ var rewriteAnnotations = parser.Annotation{
|
|||
the pathType should also be defined as 'ImplementationSpecific'.`,
|
||||
},
|
||||
appRootAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.RegexPathWithCapture, false),
|
||||
Validator: parser.ValidateRegex(parser.RegexPathWithCapture, false),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation defines the Application Root that the Controller must redirect if it's in / context`,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue