Merge branch 'main' into hotfix/avoid-creating-executable-files
This commit is contained in:
commit
cef9014ace
339 changed files with 6986 additions and 2801 deletions
105
.github/workflows/ci.yaml
vendored
105
.github/workflows/ci.yaml
vendored
|
@ -42,7 +42,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||||
id: filter
|
id: filter
|
||||||
|
@ -68,10 +68,10 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Run Gosec Security Scanner
|
- name: Run Gosec Security Scanner
|
||||||
uses: securego/gosec@c5ea1b7bdd9efc3792e513258853552b0ae31e06 # v2.16.0
|
uses: securego/gosec@a89e9d5a7acb4457f3891ac18532b142b1bf9221 # v2.17.0
|
||||||
with:
|
with:
|
||||||
# G601 for zz_generated.deepcopy.go
|
# G601 for zz_generated.deepcopy.go
|
||||||
# G306 TODO: Expect WriteFile permissions to be 0600 or less
|
# G306 TODO: Expect WriteFile permissions to be 0600 or less
|
||||||
|
@ -85,11 +85,11 @@ jobs:
|
||||||
(needs.changes.outputs.go == 'true')
|
(needs.changes.outputs.go == 'true')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: go
|
id: go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -104,11 +104,11 @@ jobs:
|
||||||
(needs.changes.outputs.go == 'true')
|
(needs.changes.outputs.go == 'true')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: go
|
id: go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -123,11 +123,11 @@ jobs:
|
||||||
(needs.changes.outputs.go == 'true')
|
(needs.changes.outputs.go == 'true')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: go
|
id: go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -144,11 +144,11 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: go
|
id: go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -158,7 +158,7 @@ jobs:
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2.8.0
|
uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
|
|
||||||
|
@ -167,8 +167,6 @@ jobs:
|
||||||
|
|
||||||
- name: Prepare Host
|
- name: Prepare Host
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update || true
|
|
||||||
sudo apt-get install -y pigz
|
|
||||||
curl -LO https://dl.k8s.io/release/v1.25.5/bin/linux/amd64/kubectl
|
curl -LO https://dl.k8s.io/release/v1.25.5/bin/linux/amd64/kubectl
|
||||||
chmod +x ./kubectl
|
chmod +x ./kubectl
|
||||||
sudo mv ./kubectl /usr/local/bin/kubectl
|
sudo mv ./kubectl /usr/local/bin/kubectl
|
||||||
|
@ -188,7 +186,7 @@ jobs:
|
||||||
nginx-ingress-controller:e2e \
|
nginx-ingress-controller:e2e \
|
||||||
ingress-controller/controller:1.0.0-dev \
|
ingress-controller/controller:1.0.0-dev \
|
||||||
ingress-controller/controller-chroot:1.0.0-dev \
|
ingress-controller/controller-chroot:1.0.0-dev \
|
||||||
| pigz > docker.tar.gz
|
| gzip > docker.tar.gz
|
||||||
|
|
||||||
- name: cache
|
- name: cache
|
||||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||||
|
@ -207,14 +205,14 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -260,7 +258,7 @@ jobs:
|
||||||
- name: Load images from cache
|
- name: Load images from cache
|
||||||
run: |
|
run: |
|
||||||
echo "loading docker images..."
|
echo "loading docker images..."
|
||||||
pigz -dc docker.tar.gz | docker load
|
gzip -dc docker.tar.gz | docker load
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
env:
|
env:
|
||||||
|
@ -282,11 +280,11 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: cache
|
- name: cache
|
||||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||||
|
@ -301,7 +299,7 @@ jobs:
|
||||||
- name: Load images from cache
|
- name: Load images from cache
|
||||||
run: |
|
run: |
|
||||||
echo "loading docker images..."
|
echo "loading docker images..."
|
||||||
pigz -dc docker.tar.gz | docker load
|
gzip -dc docker.tar.gz | docker load
|
||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
env:
|
env:
|
||||||
|
@ -319,6 +317,55 @@ jobs:
|
||||||
name: e2e-test-reports-${{ matrix.k8s }}
|
name: e2e-test-reports-${{ matrix.k8s }}
|
||||||
path: 'test/junitreports/report*.xml'
|
path: 'test/junitreports/report*.xml'
|
||||||
|
|
||||||
|
kubernetes-validations:
|
||||||
|
name: Kubernetes with Validations
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- changes
|
||||||
|
- build
|
||||||
|
if: |
|
||||||
|
(needs.changes.outputs.go == 'true') || ${{ inputs.run_e2e }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
|
- name: cache
|
||||||
|
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||||
|
with:
|
||||||
|
name: docker.tar.gz
|
||||||
|
|
||||||
|
- name: Create Kubernetes ${{ matrix.k8s }} cluster
|
||||||
|
id: kind
|
||||||
|
run: |
|
||||||
|
kind create cluster --image=kindest/node:${{ matrix.k8s }} --config test/e2e/kind.yaml
|
||||||
|
|
||||||
|
- name: Load images from cache
|
||||||
|
run: |
|
||||||
|
echo "loading docker images..."
|
||||||
|
gzip -dc docker.tar.gz | docker load
|
||||||
|
|
||||||
|
- name: Run e2e tests
|
||||||
|
env:
|
||||||
|
KIND_CLUSTER_NAME: kind
|
||||||
|
SKIP_CLUSTER_CREATION: true
|
||||||
|
SKIP_IMAGE_CREATION: true
|
||||||
|
ENABLE_VALIDATIONS: true
|
||||||
|
run: |
|
||||||
|
kind get kubeconfig > $HOME/.kube/kind-config-kind
|
||||||
|
make kind-e2e-test
|
||||||
|
|
||||||
|
- name: Upload e2e junit-reports
|
||||||
|
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||||
|
if: success() || failure()
|
||||||
|
with:
|
||||||
|
name: e2e-test-reports-${{ matrix.k8s }}
|
||||||
|
path: 'test/junitreports/report*.xml'
|
||||||
|
|
||||||
|
|
||||||
kubernetes-chroot:
|
kubernetes-chroot:
|
||||||
name: Kubernetes chroot
|
name: Kubernetes chroot
|
||||||
|
@ -331,12 +378,12 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: cache
|
- name: cache
|
||||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||||
|
@ -351,7 +398,7 @@ jobs:
|
||||||
- name: Load images from cache
|
- name: Load images from cache
|
||||||
run: |
|
run: |
|
||||||
echo "loading docker images..."
|
echo "loading docker images..."
|
||||||
pigz -dc docker.tar.gz | docker load
|
gzip -dc docker.tar.gz | docker load
|
||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
env:
|
env:
|
||||||
|
@ -380,7 +427,7 @@ jobs:
|
||||||
PLATFORMS: linux/amd64,linux/arm64
|
PLATFORMS: linux/amd64,linux/arm64
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||||
id: filter-images
|
id: filter-images
|
||||||
|
@ -449,11 +496,11 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1]
|
k8s: [v1.24.15, v1.25.11, v1.26.6, v1.27.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||||
id: filter-images
|
id: filter-images
|
||||||
|
@ -472,7 +519,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: go
|
id: go
|
||||||
if: ${{ steps.filter-images.outputs.kube-webhook-certgen == 'true' }}
|
if: ${{ steps.filter-images.outputs.kube-webhook-certgen == 'true' }}
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
4
.github/workflows/depreview.yaml
vendored
4
.github/workflows/depreview.yaml
vendored
|
@ -9,6 +9,6 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
- name: 'Dependency Review'
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6
|
uses: actions/dependency-review-action@f6fff72a3217f580d5afd49a46826795305b63c7 # v3.0.8
|
||||||
|
|
4
.github/workflows/docs.yaml
vendored
4
.github/workflows/docs.yaml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||||
id: filter
|
id: filter
|
||||||
|
@ -47,7 +47,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout master
|
- name: Checkout master
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: ./.github/actions/mkdocs
|
uses: ./.github/actions/mkdocs
|
||||||
|
|
6
.github/workflows/helm.yaml
vendored
6
.github/workflows/helm.yaml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Run Artifact Hub lint
|
- name: Run Artifact Hub lint
|
||||||
run: |
|
run: |
|
||||||
|
@ -61,7 +61,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout master
|
- name: Checkout master
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
with:
|
with:
|
||||||
# Fetch entire history. Required for chart-releaser; see https://github.com/helm/chart-releaser-action/issues/13#issuecomment-602063896
|
# Fetch entire history. Required for chart-releaser; see https://github.com/helm/chart-releaser-action/issues/13#issuecomment-602063896
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
- name: Helm Chart Releaser
|
- name: Helm Chart Releaser
|
||||||
uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0
|
uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0
|
||||||
env:
|
env:
|
||||||
CR_SKIP_EXISTING: "false"
|
CR_SKIP_EXISTING: true
|
||||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}"
|
CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}"
|
||||||
with:
|
with:
|
||||||
|
|
2
.github/workflows/perftest.yaml
vendored
2
.github/workflows/perftest.yaml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- name: Install K6
|
- name: Install K6
|
||||||
run: |
|
run: |
|
||||||
|
|
14
.github/workflows/plugin.yaml
vendored
14
.github/workflows/plugin.yaml
vendored
|
@ -4,10 +4,8 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
paths:
|
|
||||||
- "cmd/plugin/**"
|
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- 'v*.*.*\+plugin'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # for goreleaser/goreleaser-action
|
contents: write # for goreleaser/goreleaser-action
|
||||||
|
@ -17,21 +15,21 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||||
with:
|
with:
|
||||||
go-version: 1.20
|
go-version: '1.20'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0
|
uses: goreleaser/goreleaser-action@3fa32b8bb5620a2c1afe798654bbad59f9da4906 # v4.4.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: release --rm-dist
|
args: release --clean
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
|
@ -27,7 +27,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|
4
.github/workflows/vulnerability-scans.yaml
vendored
4
.github/workflows/vulnerability-scans.yaml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
versions: ${{ steps.version.outputs.TAGS }}
|
versions: ${{ steps.version.outputs.TAGS }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ jobs:
|
||||||
versions: ${{ fromJSON(needs.version.outputs.versions) }}
|
versions: ${{ fromJSON(needs.version.outputs.versions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||||
|
|
||||||
- shell: bash
|
- shell: bash
|
||||||
id: test
|
id: test
|
||||||
|
|
|
@ -45,14 +45,16 @@ if ! command -v helm &> /dev/null; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
function ver { printf "%d%03d%03d" $(echo "$1" | tr '.' ' '); }
|
||||||
|
|
||||||
HELM_VERSION=$(helm version 2>&1 | cut -f1 -d"," | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || true
|
HELM_VERSION=$(helm version 2>&1 | cut -f1 -d"," | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || true
|
||||||
echo $HELM_VERSION
|
echo $HELM_VERSION
|
||||||
if [[ ${HELM_VERSION} -lt 3.10.0 ]]; then
|
if [[ $(ver $HELM_VERSION) -lt $(ver "3.10.0") ]]; then
|
||||||
echo "Please upgrade helm to v3.10.0 or higher"
|
echo "Please upgrade helm to v3.10.0 or higher"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
KUBE_CLIENT_VERSION=$(kubectl version --client --short 2>/dev/null | grep Client | awk '{print $3}' | cut -d. -f2) || true
|
KUBE_CLIENT_VERSION=$(kubectl version --client -oyaml 2>/dev/null | grep "minor:" | awk '{print $2}' | tr -d '"') || true
|
||||||
if [[ ${KUBE_CLIENT_VERSION} -lt 24 ]]; then
|
if [[ ${KUBE_CLIENT_VERSION} -lt 24 ]]; then
|
||||||
echo "Please update kubectl to 1.24.2 or higher"
|
echo "Please update kubectl to 1.24.2 or higher"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -294,8 +294,9 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
||||||
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
|
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
|
||||||
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
|
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
|
||||||
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
|
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
|
||||||
|
| controller.enableAnnotationValidations | bool | `false` | |
|
||||||
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
|
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
|
||||||
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto" Defaults to false |
|
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
|
||||||
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
|
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
|
||||||
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
|
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
|
||||||
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
|
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
|
||||||
|
@ -306,6 +307,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
||||||
| controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
|
| controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
|
||||||
| controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
|
| controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
|
||||||
| controller.healthCheckPath | string | `"/healthz"` | Path of the health check endpoint. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. |
|
| controller.healthCheckPath | string | `"/healthz"` | Path of the health check endpoint. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. |
|
||||||
|
| controller.hostAliases | object | `{}` | Optionally customize the pod hostAliases. |
|
||||||
| controller.hostNetwork | bool | `false` | Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged |
|
| controller.hostNetwork | bool | `false` | Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged |
|
||||||
| controller.hostPort.enabled | bool | `false` | Enable 'hostPort' or not |
|
| controller.hostPort.enabled | bool | `false` | Enable 'hostPort' or not |
|
||||||
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port |
|
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port |
|
||||||
|
@ -375,7 +377,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
||||||
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
|
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
|
||||||
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
|
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
|
||||||
| controller.opentelemetry.enabled | bool | `false` | |
|
| controller.opentelemetry.enabled | bool | `false` | |
|
||||||
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0"` | |
|
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472"` | |
|
||||||
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
|
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
|
||||||
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
|
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
|
||||||
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
|
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
|
||||||
|
@ -399,14 +401,14 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
|
||||||
| controller.scope.enabled | bool | `false` | Enable 'scope' or not |
|
| controller.scope.enabled | bool | `false` | Enable 'scope' or not |
|
||||||
| controller.scope.namespace | string | `""` | Namespace to limit the controller to; defaults to $(POD_NAMESPACE) |
|
| controller.scope.namespace | string | `""` | Namespace to limit the controller to; defaults to $(POD_NAMESPACE) |
|
||||||
| controller.scope.namespaceSelector | string | `""` | When scope.enabled == false, instead of watching all namespaces, we watching namespaces whose labels only match with namespaceSelector. Format like foo=bar. Defaults to empty, means watching all namespaces. |
|
| controller.scope.namespaceSelector | string | `""` | When scope.enabled == false, instead of watching all namespaces, we watching namespaces whose labels only match with namespaceSelector. Format like foo=bar. Defaults to empty, means watching all namespaces. |
|
||||||
| controller.service.annotations | object | `{}` | |
|
| controller.service.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
|
||||||
| controller.service.appProtocol | bool | `true` | If enabled is adding an appProtocol option for Kubernetes service. An appProtocol field replacing annotations that were using for setting a backend protocol. Here is an example for AWS: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http It allows choosing the protocol for each backend specified in the Kubernetes service. See the following GitHub issue for more details about the purpose: https://github.com/kubernetes/kubernetes/issues/40244 Will be ignored for Kubernetes versions older than 1.20 # |
|
| controller.service.appProtocol | bool | `true` | If enabled is adding an appProtocol option for Kubernetes service. An appProtocol field replacing annotations that were using for setting a backend protocol. Here is an example for AWS: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http It allows choosing the protocol for each backend specified in the Kubernetes service. See the following GitHub issue for more details about the purpose: https://github.com/kubernetes/kubernetes/issues/40244 Will be ignored for Kubernetes versions older than 1.20 # |
|
||||||
| controller.service.enableHttp | bool | `true` | |
|
| controller.service.enableHttp | bool | `true` | |
|
||||||
| controller.service.enableHttps | bool | `true` | |
|
| controller.service.enableHttps | bool | `true` | |
|
||||||
| controller.service.enabled | bool | `true` | |
|
| controller.service.enabled | bool | `true` | |
|
||||||
| controller.service.external.enabled | bool | `true` | |
|
| controller.service.external.enabled | bool | `true` | |
|
||||||
| controller.service.externalIPs | list | `[]` | List of IP addresses at which the controller services are available # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips # |
|
| controller.service.externalIPs | list | `[]` | List of IP addresses at which the controller services are available # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips # |
|
||||||
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. |
|
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
|
||||||
| controller.service.internal.enabled | bool | `false` | Enables an additional internal load balancer (besides the external one). |
|
| controller.service.internal.enabled | bool | `false` | Enables an additional internal load balancer (besides the external one). |
|
||||||
| controller.service.internal.loadBalancerIP | string | `""` | Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS. |
|
| controller.service.internal.loadBalancerIP | string | `""` | Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS. |
|
||||||
| controller.service.internal.loadBalancerSourceRanges | list | `[]` | Restrict access For LoadBalancer service. Defaults to 0.0.0.0/0. |
|
| controller.service.internal.loadBalancerSourceRanges | list | `[]` | Restrict access For LoadBalancer service. Defaults to 0.0.0.0/0. |
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{{- define "ingress-nginx.params" -}}
|
{{- define "ingress-nginx.params" -}}
|
||||||
- /nginx-ingress-controller
|
- /nginx-ingress-controller
|
||||||
|
{{- if .Values.controller.enableAnnotationValidations }}
|
||||||
|
- --enable-annotation-validation=true
|
||||||
|
{{- end }}
|
||||||
{{- if .Values.defaultBackend.enabled }}
|
{{- if .Values.defaultBackend.enabled }}
|
||||||
- --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
|
- --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -19,7 +19,7 @@ spec:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
|
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
{{- if not .Values.controller.autoscaling.enabled }}
|
{{- if not (or .Values.controller.autoscaling.enabled .Values.controller.keda.enabled) }}
|
||||||
replicas: {{ .Values.controller.replicaCount }}
|
replicas: {{ .Values.controller.replicaCount }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
||||||
|
@ -49,6 +49,9 @@ spec:
|
||||||
{{- if .Values.controller.dnsConfig }}
|
{{- if .Values.controller.dnsConfig }}
|
||||||
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
|
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.controller.hostAliases }}
|
||||||
|
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
{{- if .Values.controller.hostname }}
|
{{- if .Values.controller.hostname }}
|
||||||
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
|
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
@ -190,7 +193,7 @@ spec:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.controller.opentelemetry.enabled}}
|
{{- if .Values.controller.opentelemetry.enabled}}
|
||||||
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
|
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
|
||||||
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" false) | nindent 8}}
|
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true) | nindent 8}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.controller.hostNetwork }}
|
{{- if .Values.controller.hostNetwork }}
|
||||||
|
|
|
@ -4,7 +4,7 @@ kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
{{- range $key, $value := .Values.controller.service.internal.annotations }}
|
{{- range $key, $value := .Values.controller.service.internal.annotations }}
|
||||||
{{ $key }}: {{ $value | quote }}
|
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
||||||
|
|
|
@ -4,7 +4,7 @@ kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
{{- range $key, $value := .Values.controller.service.annotations }}
|
{{- range $key, $value := .Values.controller.service.annotations }}
|
||||||
{{ $key }}: {{ $value | quote }}
|
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
||||||
|
|
|
@ -5,6 +5,8 @@ metadata:
|
||||||
name: {{ include "ingress-nginx.controller.fullname" . }}
|
name: {{ include "ingress-nginx.controller.fullname" . }}
|
||||||
{{- if .Values.controller.metrics.serviceMonitor.namespace }}
|
{{- if .Values.controller.metrics.serviceMonitor.namespace }}
|
||||||
namespace: {{ .Values.controller.metrics.serviceMonitor.namespace | quote }}
|
namespace: {{ .Values.controller.metrics.serviceMonitor.namespace | quote }}
|
||||||
|
{{- else }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
||||||
|
|
|
@ -15,6 +15,7 @@ commonLabels: {}
|
||||||
|
|
||||||
controller:
|
controller:
|
||||||
name: controller
|
name: controller
|
||||||
|
enableAnnotationValidations: false
|
||||||
image:
|
image:
|
||||||
## Keep false as default for now!
|
## Keep false as default for now!
|
||||||
chroot: false
|
chroot: false
|
||||||
|
@ -48,6 +49,8 @@ controller:
|
||||||
addHeaders: {}
|
addHeaders: {}
|
||||||
# -- Optionally customize the pod dnsConfig.
|
# -- Optionally customize the pod dnsConfig.
|
||||||
dnsConfig: {}
|
dnsConfig: {}
|
||||||
|
# -- Optionally customize the pod hostAliases.
|
||||||
|
hostAliases: {}
|
||||||
# -- Optionally customize the pod hostname.
|
# -- Optionally customize the pod hostname.
|
||||||
hostname: {}
|
hostname: {}
|
||||||
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
|
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
|
||||||
|
@ -63,7 +66,7 @@ controller:
|
||||||
watchIngressWithoutClass: false
|
watchIngressWithoutClass: false
|
||||||
# -- Process IngressClass per name (additionally as per spec.controller).
|
# -- Process IngressClass per name (additionally as per spec.controller).
|
||||||
ingressClassByName: false
|
ingressClassByName: false
|
||||||
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto"
|
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto"
|
||||||
# Defaults to false
|
# Defaults to false
|
||||||
enableTopologyAwareRouting: false
|
enableTopologyAwareRouting: false
|
||||||
# -- This configuration defines if Ingress Controller should allow users to set
|
# -- This configuration defines if Ingress Controller should allow users to set
|
||||||
|
@ -415,6 +418,7 @@ controller:
|
||||||
# Will be ignored for Kubernetes versions older than 1.20
|
# Will be ignored for Kubernetes versions older than 1.20
|
||||||
##
|
##
|
||||||
appProtocol: true
|
appProtocol: true
|
||||||
|
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
|
||||||
annotations: {}
|
annotations: {}
|
||||||
labels: {}
|
labels: {}
|
||||||
# clusterIP: ""
|
# clusterIP: ""
|
||||||
|
@ -476,7 +480,7 @@ controller:
|
||||||
internal:
|
internal:
|
||||||
# -- Enables an additional internal load balancer (besides the external one).
|
# -- Enables an additional internal load balancer (besides the external one).
|
||||||
enabled: false
|
enabled: false
|
||||||
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service.
|
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
|
||||||
annotations: {}
|
annotations: {}
|
||||||
# -- Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS.
|
# -- Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS.
|
||||||
loadBalancerIP: ""
|
loadBalancerIP: ""
|
||||||
|
@ -552,7 +556,7 @@ controller:
|
||||||
|
|
||||||
opentelemetry:
|
opentelemetry:
|
||||||
enabled: false
|
enabled: false
|
||||||
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0
|
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
|
||||||
containerSecurityContext:
|
containerSecurityContext:
|
||||||
allowPrivilegeEscalation: false
|
allowPrivilegeEscalation: false
|
||||||
admissionWebhooks:
|
admissionWebhooks:
|
||||||
|
|
|
@ -18,11 +18,12 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/controller"
|
"k8s.io/ingress-nginx/internal/ingress/controller"
|
||||||
|
|
|
@ -114,7 +114,6 @@ func main() {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func backendsAll() {
|
func backendsAll() {
|
||||||
|
@ -155,10 +154,16 @@ func backendsList() {
|
||||||
fmt.Println(unmarshalErr)
|
fmt.Println(unmarshalErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
backends := f.([]interface{})
|
backends, ok := f.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
fmt.Printf("unexpected type: %T", f)
|
||||||
|
}
|
||||||
|
|
||||||
for _, backendi := range backends {
|
for _, backendi := range backends {
|
||||||
backend := backendi.(map[string]interface{})
|
backend, ok := backendi.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
fmt.Printf("unexpected type: %T", backendi)
|
||||||
|
}
|
||||||
fmt.Println(backend["name"].(string))
|
fmt.Println(backend["name"].(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,12 +185,22 @@ func backendsGet(name string) {
|
||||||
fmt.Println(unmarshalErr)
|
fmt.Println(unmarshalErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
backends := f.([]interface{})
|
backends, ok := f.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
fmt.Printf("unexpected type: %T", f)
|
||||||
|
}
|
||||||
|
|
||||||
for _, backendi := range backends {
|
for _, backendi := range backends {
|
||||||
backend := backendi.(map[string]interface{})
|
backend, ok := backendi.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
fmt.Printf("unexpected type: %T", backendi)
|
||||||
|
}
|
||||||
if backend["name"].(string) == name {
|
if backend["name"].(string) == name {
|
||||||
printed, _ := json.MarshalIndent(backend, "", " ")
|
printed, err := json.MarshalIndent(backend, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
fmt.Println(string(printed))
|
fmt.Println(string(printed))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -213,18 +228,7 @@ func certGet(host string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func general() {
|
func general() {
|
||||||
//TODO: refactor to obtain ingress-nginx pod count from the api server
|
// TODO: refactor to obtain ingress-nginx pod count from the api server
|
||||||
/*
|
|
||||||
statusCode, body, requestErr := nginx.NewGetStatusRequest(generalPath)
|
|
||||||
if requestErr != nil {
|
|
||||||
fmt.Println(requestErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if statusCode != 200 {
|
|
||||||
fmt.Printf("Nginx returned code %v\n", statusCode)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var prettyBuffer bytes.Buffer
|
var prettyBuffer bytes.Buffer
|
||||||
indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ")
|
indentErr := json.Indent(&prettyBuffer, []byte("{}"), "", " ")
|
||||||
|
|
|
@ -47,5 +47,4 @@ func logger(address string) {
|
||||||
|
|
||||||
server.Wait()
|
server.Wait()
|
||||||
klog.Infof("Stopping logger")
|
klog.Infof("Stopping logger")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,6 @@ func main() {
|
||||||
if errExists == nil {
|
if errExists == nil {
|
||||||
conf.IsChroot = true
|
conf.IsChroot = true
|
||||||
go logger(conf.InternalLoggerAddress)
|
go logger(conf.InternalLoggerAddress)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go metrics.StartHTTPServer(conf.HealthCheckHost, conf.ListenPorts.Health, mux)
|
go metrics.StartHTTPServer(conf.HealthCheckHost, conf.ListenPorts.Health, mux)
|
||||||
|
@ -282,10 +281,10 @@ func checkService(key string, kubeClient *kubernetes.Clientset) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
return fmt.Errorf("No service with name %v found in namespace %v: %v", name, ns, err)
|
return fmt.Errorf("no service with name %v found in namespace %v: %v", name, ns, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
|
return fmt.Errorf("unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -47,7 +47,7 @@ func TestCreateApiserverClient(t *testing.T) {
|
||||||
func init() {
|
func init() {
|
||||||
// the default value of nginx.TemplatePath assumes the template exists in
|
// the default value of nginx.TemplatePath assumes the template exists in
|
||||||
// the root filesystem and not in the rootfs directory
|
// the root filesystem and not in the rootfs directory
|
||||||
path, err := filepath.Abs(filepath.Join("../../rootfs/", nginx.TemplatePath))
|
path, err := filepath.Abs(filepath.Join("..", "..", "rootfs", nginx.TemplatePath))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
nginx.TemplatePath = path
|
nginx.TemplatePath = path
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,14 @@ func TestHandleSigterm(t *testing.T) {
|
||||||
|
|
||||||
ingressflags.ResetForTesting(func() { t.Fatal("bad parse") })
|
ingressflags.ResetForTesting(func() { t.Fatal("bad parse") })
|
||||||
|
|
||||||
os.Setenv("POD_NAME", podName)
|
t.Setenv("POD_NAME", podName)
|
||||||
os.Setenv("POD_NAMESPACE", namespace)
|
t.Setenv("POD_NAMESPACE", namespace)
|
||||||
|
|
||||||
oldArgs := os.Args
|
oldArgs := os.Args
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
os.Setenv("POD_NAME", "")
|
t.Setenv("POD_NAME", "")
|
||||||
os.Setenv("POD_NAMESPACE", "")
|
t.Setenv("POD_NAMESPACE", "")
|
||||||
os.Args = oldArgs
|
os.Args = oldArgs
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -63,13 +63,14 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func backends(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, backend string, onlyList bool) error {
|
func backends(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, backend string, onlyList bool) error {
|
||||||
var command []string
|
var command []string
|
||||||
if onlyList {
|
switch {
|
||||||
|
case onlyList:
|
||||||
command = []string{"/dbg", "backends", "list"}
|
command = []string{"/dbg", "backends", "list"}
|
||||||
} else if backend != "" {
|
case backend != "":
|
||||||
command = []string{"/dbg", "backends", "get", backend}
|
command = []string{"/dbg", "backends", "get", backend}
|
||||||
} else {
|
default:
|
||||||
command = []string{"/dbg", "backends", "all"}
|
command = []string{"/dbg", "backends", "all"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func certs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, host string) error {
|
func certs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container, host string) error {
|
||||||
command := []string{"/dbg", "certs", "get", host}
|
command := []string{"/dbg", "certs", "get", host}
|
||||||
|
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
|
|
|
@ -55,7 +55,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func conf(flags *genericclioptions.ConfigFlags, host string, podName string, deployment string, selector string, container string) error {
|
func conf(flags *genericclioptions.ConfigFlags, host, podName, deployment, selector, container string) error {
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -55,7 +55,7 @@ type execFlags struct {
|
||||||
Stdin bool
|
Stdin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func exec(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, cmd []string, opts execFlags) error {
|
func exec(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, cmd []string, opts execFlags) error {
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -47,7 +47,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func general(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
|
func general(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -74,9 +74,9 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
|
||||||
|
|
||||||
if host != "" {
|
if host != "" {
|
||||||
rowsWithHost := make([]ingressRow, 0)
|
rowsWithHost := make([]ingressRow, 0)
|
||||||
for _, row := range rows {
|
for i := range rows {
|
||||||
if row.Host == host {
|
if rows[i].Host == host {
|
||||||
rowsWithHost = append(rowsWithHost, row)
|
rowsWithHost = append(rowsWithHost, rows[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = rowsWithHost
|
rows = rowsWithHost
|
||||||
|
@ -91,7 +91,8 @@ func ingresses(flags *genericclioptions.ConfigFlags, host string, allNamespaces
|
||||||
fmt.Fprintln(printer, "INGRESS NAME\tHOST+PATH\tADDRESSES\tTLS\tSERVICE\tSERVICE PORT\tENDPOINTS")
|
fmt.Fprintln(printer, "INGRESS NAME\tHOST+PATH\tADDRESSES\tTLS\tSERVICE\tSERVICE PORT\tENDPOINTS")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, row := range rows {
|
for i := range rows {
|
||||||
|
row := &rows[i]
|
||||||
var tlsMsg string
|
var tlsMsg string
|
||||||
if row.TLS {
|
if row.TLS {
|
||||||
tlsMsg = "YES"
|
tlsMsg = "YES"
|
||||||
|
@ -134,8 +135,8 @@ type ingressRow struct {
|
||||||
func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
|
func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
|
||||||
rows := make([]ingressRow, 0)
|
rows := make([]ingressRow, 0)
|
||||||
|
|
||||||
for _, ing := range *ingresses {
|
for i := range *ingresses {
|
||||||
|
ing := &(*ingresses)[i]
|
||||||
address := ""
|
address := ""
|
||||||
for _, lbIng := range ing.Status.LoadBalancer.Ingress {
|
for _, lbIng := range ing.Status.LoadBalancer.Ingress {
|
||||||
if len(lbIng.IP) > 0 {
|
if len(lbIng.IP) > 0 {
|
||||||
|
@ -182,7 +183,7 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
|
||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
_, hasTLS := tlsHosts[rule.Host]
|
_, hasTLS := tlsHosts[rule.Host]
|
||||||
|
|
||||||
//Handle ingress with no paths
|
// Handle ingress with no paths
|
||||||
if rule.HTTP == nil {
|
if rule.HTTP == nil {
|
||||||
row := ingressRow{
|
row := ingressRow{
|
||||||
Namespace: ing.Namespace,
|
Namespace: ing.Namespace,
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetIngressInformation(t *testing.T) {
|
func TestGetIngressInformation(t *testing.T) {
|
||||||
|
|
||||||
testcases := map[string]struct {
|
testcases := map[string]struct {
|
||||||
ServiceBackend *networking.IngressServiceBackend
|
ServiceBackend *networking.IngressServiceBackend
|
||||||
wantName string
|
wantName string
|
||||||
|
|
|
@ -111,11 +111,13 @@ type lintOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts *lintOptions) Validate() error {
|
func (opts *lintOptions) Validate() error {
|
||||||
|
//nolint:dogsled // Ignore 3 blank identifiers
|
||||||
_, _, _, err := util.ParseVersionString(opts.versionFrom)
|
_, _, _, err := util.ParseVersionString(opts.versionFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:dogsled // Ignore 3 blank identifiers
|
||||||
_, _, _, err = util.ParseVersionString(opts.versionTo)
|
_, _, _, err = util.ParseVersionString(opts.versionTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -131,9 +133,9 @@ type lint interface {
|
||||||
Version() string
|
Version() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkObjectArray(lints []lint, objects []kmeta.Object, opts lintOptions) {
|
func checkObjectArray(allLints []lint, objects []kmeta.Object, opts lintOptions) {
|
||||||
usedLints := make([]lint, 0)
|
usedLints := make([]lint, 0)
|
||||||
for _, lint := range lints {
|
for _, lint := range allLints {
|
||||||
lintVersion := lint.Version()
|
lintVersion := lint.Version()
|
||||||
if lint.Version() == "" {
|
if lint.Version() == "" {
|
||||||
lintVersion = "0.0.0"
|
lintVersion = "0.0.0"
|
||||||
|
@ -189,7 +191,7 @@ func ingresses(opts lintOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var iLints []lints.IngressLint = lints.GetIngressLints()
|
iLints := lints.GetIngressLints()
|
||||||
genericLints := make([]lint, len(iLints))
|
genericLints := make([]lint, len(iLints))
|
||||||
for i := range iLints {
|
for i := range iLints {
|
||||||
genericLints[i] = iLints[i]
|
genericLints[i] = iLints[i]
|
||||||
|
@ -216,7 +218,7 @@ func deployments(opts lintOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var iLints []lints.DeploymentLint = lints.GetDeploymentLints()
|
iLints := lints.GetDeploymentLints()
|
||||||
genericLints := make([]lint, len(iLints))
|
genericLints := make([]lint, len(iLints))
|
||||||
for i := range iLints {
|
for i := range iLints {
|
||||||
genericLints[i] = iLints[i]
|
genericLints[i] = iLints[i]
|
||||||
|
|
|
@ -95,7 +95,7 @@ func (o *logsFlags) toStrings() []string {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func logs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string, opts logsFlags) error {
|
func logs(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string, opts logsFlags) error {
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -45,7 +45,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func ssh(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, container string) error {
|
func ssh(flags *genericclioptions.ConfigFlags, podName, deployment, selector, container string) error {
|
||||||
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
pod, err := request.ChoosePod(flags, podName, deployment, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -38,11 +38,11 @@ func PodExecString(flags *genericclioptions.ConfigFlags, pod *apiv1.Pod, contain
|
||||||
|
|
||||||
// ExecToString runs a kubectl subcommand and returns stdout as a string
|
// ExecToString runs a kubectl subcommand and returns stdout as a string
|
||||||
func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) {
|
func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string, error) {
|
||||||
kArgs := getKubectlConfigFlags(flags)
|
kubectlArgs := getKubectlConfigFlags(flags)
|
||||||
kArgs = append(kArgs, args...)
|
kubectlArgs = append(kubectlArgs, args...)
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0))
|
buf := bytes.NewBuffer(make([]byte, 0))
|
||||||
err := execToWriter(append([]string{"kubectl"}, kArgs...), buf)
|
err := execToWriter(append([]string{"kubectl"}, kubectlArgs...), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -51,9 +51,9 @@ func ExecToString(flags *genericclioptions.ConfigFlags, args []string) (string,
|
||||||
|
|
||||||
// Exec replaces the current process with a kubectl invocation
|
// Exec replaces the current process with a kubectl invocation
|
||||||
func Exec(flags *genericclioptions.ConfigFlags, args []string) error {
|
func Exec(flags *genericclioptions.ConfigFlags, args []string) error {
|
||||||
kArgs := getKubectlConfigFlags(flags)
|
kubectlArgs := getKubectlConfigFlags(flags)
|
||||||
kArgs = append(kArgs, args...)
|
kubectlArgs = append(kubectlArgs, args...)
|
||||||
return execCommand(append([]string{"kubectl"}, kArgs...))
|
return execCommand(append([]string{"kubectl"}, kubectlArgs...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces the currently running process with the given command
|
// Replaces the currently running process with the given command
|
||||||
|
@ -70,6 +70,7 @@ func execCommand(args []string) error {
|
||||||
|
|
||||||
// Runs a command and returns stdout
|
// Runs a command and returns stdout
|
||||||
func execToWriter(args []string, writer io.Writer) error {
|
func execToWriter(args []string, writer io.Writer) error {
|
||||||
|
//nolint:gosec // Ignore G204 error
|
||||||
cmd := exec.Command(args[0], args[1:]...)
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
|
||||||
op, err := cmd.StdoutPipe()
|
op, err := cmd.StdoutPipe()
|
||||||
|
@ -78,7 +79,7 @@ func execToWriter(args []string, writer io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
io.Copy(writer, op) //nolint:errcheck
|
io.Copy(writer, op) //nolint:errcheck // Ignore the error
|
||||||
}()
|
}()
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -106,7 +107,6 @@ func getKubectlConfigFlags(flags *genericclioptions.ConfigFlags) []string {
|
||||||
appendStringFlag(o, flags.Password, "password")
|
appendStringFlag(o, flags.Password, "password")
|
||||||
appendStringFlag(o, flags.ClusterName, "cluster")
|
appendStringFlag(o, flags.ClusterName, "cluster")
|
||||||
appendStringFlag(o, flags.AuthInfoName, "user")
|
appendStringFlag(o, flags.AuthInfoName, "user")
|
||||||
//appendStringFlag(o, flags.Namespace, "namespace")
|
|
||||||
appendStringFlag(o, flags.Context, "context")
|
appendStringFlag(o, flags.Context, "context")
|
||||||
appendStringFlag(o, flags.APIServer, "server")
|
appendStringFlag(o, flags.APIServer, "server")
|
||||||
appendBoolFlag(o, flags.Insecure, "insecure-skip-tls-verify")
|
appendBoolFlag(o, flags.Insecure, "insecure-skip-tls-verify")
|
||||||
|
@ -128,7 +128,7 @@ func appendBoolFlag(out *[]string, in *bool, flag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStringArrayFlag(out *[]string, in *[]string, flag string) {
|
func appendStringArrayFlag(out, in *[]string, flag string) {
|
||||||
if in != nil && len(*in) > 0 {
|
if in != nil && len(*in) > 0 {
|
||||||
*out = append(*out, fmt.Sprintf("--%v=%v'", flag, strings.Join(*in, ",")))
|
*out = append(*out, fmt.Sprintf("--%v=%v'", flag, strings.Join(*in, ",")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,10 @@ type DeploymentLint struct {
|
||||||
|
|
||||||
// Check returns true if the lint detects an issue
|
// Check returns true if the lint detects an issue
|
||||||
func (lint DeploymentLint) Check(obj kmeta.Object) bool {
|
func (lint DeploymentLint) Check(obj kmeta.Object) bool {
|
||||||
cmp := obj.(*v1.Deployment)
|
cmp, ok := obj.(*v1.Deployment)
|
||||||
|
if !ok {
|
||||||
|
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
|
||||||
|
}
|
||||||
return lint.f(*cmp)
|
return lint.f(*cmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +75,11 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
|
||||||
issue: issueNumber,
|
issue: issueNumber,
|
||||||
version: version,
|
version: version,
|
||||||
f: func(dep v1.Deployment) bool {
|
f: func(dep v1.Deployment) bool {
|
||||||
if !isIngressNginxDeployment(dep) {
|
if !isIngressNginxDeployment(&dep) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
args := getNginxArgs(dep)
|
args := getNginxArgs(&dep)
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) {
|
if strings.HasPrefix(arg, fmt.Sprintf("--%v", flag)) {
|
||||||
return true
|
return true
|
||||||
|
@ -88,8 +91,9 @@ func removedFlag(flag string, issueNumber int, version string) DeploymentLint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNginxArgs(dep v1.Deployment) []string {
|
func getNginxArgs(dep *v1.Deployment) []string {
|
||||||
for _, container := range dep.Spec.Template.Spec.Containers {
|
for i := range dep.Spec.Template.Spec.Containers {
|
||||||
|
container := &dep.Spec.Template.Spec.Containers[i]
|
||||||
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
|
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
|
||||||
return container.Args
|
return container.Args
|
||||||
}
|
}
|
||||||
|
@ -97,10 +101,10 @@ func getNginxArgs(dep v1.Deployment) []string {
|
||||||
return make([]string, 0)
|
return make([]string, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIngressNginxDeployment(dep v1.Deployment) bool {
|
func isIngressNginxDeployment(dep *v1.Deployment) bool {
|
||||||
containers := dep.Spec.Template.Spec.Containers
|
containers := dep.Spec.Template.Spec.Containers
|
||||||
for _, container := range containers {
|
for i := range containers {
|
||||||
if len(container.Args) > 0 && container.Args[0] == "/nginx-ingress-controller" {
|
if len(containers[i].Args) > 0 && containers[i].Args[0] == "/nginx-ingress-controller" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,16 @@ type IngressLint struct {
|
||||||
message string
|
message string
|
||||||
issue int
|
issue int
|
||||||
version string
|
version string
|
||||||
f func(ing networking.Ingress) bool
|
f func(ing *networking.Ingress) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check returns true if the lint detects an issue
|
// Check returns true if the lint detects an issue
|
||||||
func (lint IngressLint) Check(obj kmeta.Object) bool {
|
func (lint IngressLint) Check(obj kmeta.Object) bool {
|
||||||
ing := obj.(*networking.Ingress)
|
ing, ok := obj.(*networking.Ingress)
|
||||||
return lint.f(*ing)
|
if !ok {
|
||||||
|
util.PrintError(fmt.Errorf("unexpected type: %T", obj))
|
||||||
|
}
|
||||||
|
return lint.f(ing)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is a description of the lint
|
// Message is a description of the lint
|
||||||
|
@ -94,7 +97,7 @@ func GetIngressLints() []IngressLint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func xForwardedPrefixIsBool(ing networking.Ingress) bool {
|
func xForwardedPrefixIsBool(ing *networking.Ingress) bool {
|
||||||
for name, val := range ing.Annotations {
|
for name, val := range ing.Annotations {
|
||||||
if strings.HasSuffix(name, "/x-forwarded-prefix") && (val == "true" || val == "false") {
|
if strings.HasSuffix(name, "/x-forwarded-prefix") && (val == "true" || val == "false") {
|
||||||
return true
|
return true
|
||||||
|
@ -103,7 +106,7 @@ func xForwardedPrefixIsBool(ing networking.Ingress) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
|
func annotationPrefixIsNginxCom(ing *networking.Ingress) bool {
|
||||||
for name := range ing.Annotations {
|
for name := range ing.Annotations {
|
||||||
if strings.HasPrefix(name, "nginx.com/") {
|
if strings.HasPrefix(name, "nginx.com/") {
|
||||||
return true
|
return true
|
||||||
|
@ -112,7 +115,7 @@ func annotationPrefixIsNginxCom(ing networking.Ingress) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
|
func annotationPrefixIsNginxOrg(ing *networking.Ingress) bool {
|
||||||
for name := range ing.Annotations {
|
for name := range ing.Annotations {
|
||||||
if strings.HasPrefix(name, "nginx.org/") {
|
if strings.HasPrefix(name, "nginx.org/") {
|
||||||
return true
|
return true
|
||||||
|
@ -121,7 +124,7 @@ func annotationPrefixIsNginxOrg(ing networking.Ingress) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteTargetWithoutCaptureGroup(ing networking.Ingress) bool {
|
func rewriteTargetWithoutCaptureGroup(ing *networking.Ingress) bool {
|
||||||
for name, val := range ing.Annotations {
|
for name, val := range ing.Annotations {
|
||||||
if strings.HasSuffix(name, "/rewrite-target") && !strings.Contains(val, "$1") {
|
if strings.HasSuffix(name, "/rewrite-target") && !strings.Contains(val, "$1") {
|
||||||
return true
|
return true
|
||||||
|
@ -135,7 +138,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
|
||||||
message: fmt.Sprintf("Contains the removed %v annotation.", annotationName),
|
message: fmt.Sprintf("Contains the removed %v annotation.", annotationName),
|
||||||
issue: issueNumber,
|
issue: issueNumber,
|
||||||
version: version,
|
version: version,
|
||||||
f: func(ing networking.Ingress) bool {
|
f: func(ing *networking.Ingress) bool {
|
||||||
for annotation := range ing.Annotations {
|
for annotation := range ing.Annotations {
|
||||||
if strings.HasSuffix(annotation, "/"+annotationName) {
|
if strings.HasSuffix(annotation, "/"+annotationName) {
|
||||||
return true
|
return true
|
||||||
|
@ -146,7 +149,7 @@ func removedAnnotation(annotationName string, issueNumber int, version string) I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func satisfyDirective(ing networking.Ingress) bool {
|
func satisfyDirective(ing *networking.Ingress) bool {
|
||||||
for name, val := range ing.Annotations {
|
for name, val := range ing.Annotations {
|
||||||
if strings.HasSuffix(name, "/configuration-snippet") {
|
if strings.HasSuffix(name, "/configuration-snippet") {
|
||||||
return strings.Contains(val, "satisfy")
|
return strings.Contains(val, "satisfy")
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
|
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
|
|
||||||
//Just importing this is supposed to allow cloud authentication
|
// Just importing this is supposed to allow cloud authentication
|
||||||
// eg GCP, AWS, Azure ...
|
// eg GCP, AWS, Azure ...
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChoosePod finds a pod either by deployment or by name
|
// ChoosePod finds a pod either by deployment or by name
|
||||||
func ChoosePod(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) (apiv1.Pod, error) {
|
func ChoosePod(flags *genericclioptions.ConfigFlags, podName, deployment, selector string) (apiv1.Pod, error) {
|
||||||
if podName != "" {
|
if podName != "" {
|
||||||
return GetNamedPod(flags, podName)
|
return GetNamedPod(flags, podName)
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ func GetNamedPod(flags *genericclioptions.ConfigFlags, name string) (apiv1.Pod,
|
||||||
return apiv1.Pod{}, err
|
return apiv1.Pod{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pod := range allPods {
|
for i := range allPods {
|
||||||
if pod.Name == name {
|
if allPods[i].Name == name {
|
||||||
return pod, nil
|
return allPods[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ func GetIngressDefinitions(flags *genericclioptions.ConfigFlags, namespace strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumEndpoints counts the number of endpointslices adresses for the service with the given name
|
// GetNumEndpoints counts the number of endpointslices adresses for the service with the given name
|
||||||
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, serviceName string) (*int, error) {
|
func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace, serviceName string) (*int, error) {
|
||||||
epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
|
epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -143,25 +143,26 @@ func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, ser
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := 0
|
ret := 0
|
||||||
for _, eps := range epss {
|
for i := range epss {
|
||||||
for _, ep := range eps.Endpoints {
|
eps := &epss[i]
|
||||||
ret += len(ep.Addresses)
|
for j := range eps.Endpoints {
|
||||||
|
ret += len(eps.Endpoints[j].Addresses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEndpointSlicesByName returns the endpointSlices for the service with the given name
|
// GetEndpointSlicesByName returns the endpointSlices for the service with the given name
|
||||||
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace string, name string) ([]discoveryv1.EndpointSlice, error) {
|
func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace, name string) ([]discoveryv1.EndpointSlice, error) {
|
||||||
allEndpointsSlices, err := getEndpointSlices(flags, namespace)
|
allEndpointsSlices, err := getEndpointSlices(flags, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var eps []discoveryv1.EndpointSlice
|
var eps []discoveryv1.EndpointSlice
|
||||||
for _, slice := range allEndpointsSlices {
|
for i := range allEndpointsSlices {
|
||||||
if svcName, ok := slice.ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
|
if svcName, ok := allEndpointsSlices[i].ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
|
||||||
if svcName == name {
|
if svcName == name {
|
||||||
eps = append(eps, slice)
|
eps = append(eps, allEndpointsSlices[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +183,7 @@ func getEndpointSlices(flags *genericclioptions.ConfigFlags, namespace string) (
|
||||||
tryAllNamespacesEndpointSlicesCache(flags)
|
tryAllNamespacesEndpointSlicesCache(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(flags, namespace)
|
cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(namespace)
|
||||||
|
|
||||||
if cachedEndpointSlices != nil {
|
if cachedEndpointSlices != nil {
|
||||||
return *cachedEndpointSlices, nil
|
return *cachedEndpointSlices, nil
|
||||||
|
@ -217,13 +218,13 @@ func tryAllNamespacesEndpointSlicesCache(flags *genericclioptions.ConfigFlags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryFilteringEndpointSlicesFromAllNamespacesCache(flags *genericclioptions.ConfigFlags, namespace string) *[]discoveryv1.EndpointSlice {
|
func tryFilteringEndpointSlicesFromAllNamespacesCache(namespace string) *[]discoveryv1.EndpointSlice {
|
||||||
allEndpointSlices := endpointSlicesCache[""]
|
allEndpointSlices := endpointSlicesCache[""]
|
||||||
if allEndpointSlices != nil {
|
if allEndpointSlices != nil {
|
||||||
endpointSlices := make([]discoveryv1.EndpointSlice, 0)
|
endpointSlices := make([]discoveryv1.EndpointSlice, 0)
|
||||||
for _, slice := range *allEndpointSlices {
|
for i := range *allEndpointSlices {
|
||||||
if slice.Namespace == namespace {
|
if (*allEndpointSlices)[i].Namespace == namespace {
|
||||||
endpointSlices = append(endpointSlices, slice)
|
endpointSlices = append(endpointSlices, (*allEndpointSlices)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endpointSlicesCache[namespace] = &endpointSlices
|
endpointSlicesCache[namespace] = &endpointSlices
|
||||||
|
@ -242,9 +243,9 @@ func GetServiceByName(flags *genericclioptions.ConfigFlags, name string, service
|
||||||
services = &servicesArray
|
services = &servicesArray
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, svc := range *services {
|
for i := range *services {
|
||||||
if svc.Name == name {
|
if (*services)[i].Name == name {
|
||||||
return svc, nil
|
return (*services)[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +289,6 @@ func getLabeledPods(flags *genericclioptions.ConfigFlags, label string) ([]apiv1
|
||||||
pods, err := api.Pods(namespace).List(context.TODO(), metav1.ListOptions{
|
pods, err := api.Pods(namespace).List(context.TODO(), metav1.ListOptions{
|
||||||
LabelSelector: label,
|
LabelSelector: label,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]apiv1.Pod, 0), err
|
return make([]apiv1.Pod, 0), err
|
||||||
}
|
}
|
||||||
|
@ -303,9 +303,9 @@ func getDeploymentPods(flags *genericclioptions.ConfigFlags, deployment string)
|
||||||
}
|
}
|
||||||
|
|
||||||
ingressPods := make([]apiv1.Pod, 0)
|
ingressPods := make([]apiv1.Pod, 0)
|
||||||
for _, pod := range pods {
|
for i := range pods {
|
||||||
if util.PodInDeployment(pod, deployment) {
|
if util.PodInDeployment(&pods[i], deployment) {
|
||||||
ingressPods = append(ingressPods, pod)
|
ingressPods = append(ingressPods, pods[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,5 +331,4 @@ func getServices(flags *genericclioptions.ConfigFlags) ([]apiv1.Service, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return services.Items, nil
|
return services.Items, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,17 +47,25 @@ func PrintError(e error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseVersionString returns the major, minor, and patch numbers of a version string
|
// ParseVersionString returns the major, minor, and patch numbers of a version string
|
||||||
func ParseVersionString(v string) (int, int, int, error) {
|
func ParseVersionString(v string) (major, minor, patch int, err error) {
|
||||||
parts := versionRegex.FindStringSubmatch(v)
|
parts := versionRegex.FindStringSubmatch(v)
|
||||||
|
|
||||||
if len(parts) != 4 {
|
if len(parts) != 4 {
|
||||||
return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v)
|
return 0, 0, 0, fmt.Errorf("could not parse %v as a version string (like 0.20.3)", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
major, _ := strconv.Atoi(parts[1])
|
major, err = strconv.Atoi(parts[1])
|
||||||
minor, _ := strconv.Atoi(parts[2])
|
if err != nil {
|
||||||
patch, _ := strconv.Atoi(parts[3])
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
minor, err = strconv.Atoi(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
patch, err = strconv.Atoi(parts[3])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
return major, minor, patch, nil
|
return major, minor, patch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +98,7 @@ func isVersionLessThan(a, b string) bool {
|
||||||
|
|
||||||
// PodInDeployment returns whether a pod is part of a deployment with the given name
|
// PodInDeployment returns whether a pod is part of a deployment with the given name
|
||||||
// a pod is considered to be in {deployment} if it is owned by a replicaset with a name of format {deployment}-otherchars
|
// a pod is considered to be in {deployment} if it is owned by a replicaset with a name of format {deployment}-otherchars
|
||||||
func PodInDeployment(pod apiv1.Pod, deployment string) bool {
|
func PodInDeployment(pod *apiv1.Pod, deployment string) bool {
|
||||||
for _, owner := range pod.OwnerReferences {
|
for _, owner := range pod.OwnerReferences {
|
||||||
if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" {
|
if owner.Controller == nil || !*owner.Controller || owner.Kind != "ReplicaSet" {
|
||||||
continue
|
continue
|
||||||
|
@ -138,7 +146,7 @@ func AddContainerFlag(cmd *cobra.Command) *string {
|
||||||
// GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in
|
// GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in
|
||||||
func GetNamespace(flags *genericclioptions.ConfigFlags) string {
|
func GetNamespace(flags *genericclioptions.ConfigFlags) string {
|
||||||
namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()
|
namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()
|
||||||
if err != nil || len(namespace) == 0 {
|
if err != nil || namespace == "" {
|
||||||
namespace = apiv1.NamespaceDefault
|
namespace = apiv1.NamespaceDefault
|
||||||
}
|
}
|
||||||
return namespace
|
return namespace
|
||||||
|
|
|
@ -411,6 +411,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -420,6 +420,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -406,6 +406,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -407,6 +407,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -410,6 +410,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -510,6 +510,10 @@ spec:
|
||||||
- name: webhook-cert
|
- name: webhook-cert
|
||||||
secret:
|
secret:
|
||||||
secretName: ingress-nginx-admission
|
secretName: ingress-nginx-admission
|
||||||
|
updateStrategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
---
|
---
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
|
|
|
@ -411,6 +411,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -410,6 +410,10 @@ spec:
|
||||||
app.kubernetes.io/component: controller
|
app.kubernetes.io/component: controller
|
||||||
app.kubernetes.io/instance: ingress-nginx
|
app.kubernetes.io/instance: ingress-nginx
|
||||||
app.kubernetes.io/name: ingress-nginx
|
app.kubernetes.io/name: ingress-nginx
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
type: RollingUpdate
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -80,6 +80,12 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont
|
||||||
Because of api deprecations, the default manifest may not work on your cluster.
|
Because of api deprecations, the default manifest may not work on your cluster.
|
||||||
Specific manifests for supported Kubernetes versions are available within a sub-folder of each provider.
|
Specific manifests for supported Kubernetes versions are available within a sub-folder of each provider.
|
||||||
|
|
||||||
|
### Firewall configuration
|
||||||
|
|
||||||
|
To check which ports are used by your installation of ingress-nginx, look at the output of `kubectl -n ingress-nginx get pod -o yaml`. In general, you need:
|
||||||
|
- Port 8443 open between all hosts on which the kubernetes nodes are running. This is used for the ingress-nginx [admission controller](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/).
|
||||||
|
- Port 80 (for HTTP) and/or 443 (for HTTPS) open to the public on the kubernetes nodes to which the DNS of your apps are pointing.
|
||||||
|
|
||||||
### Pre-flight check
|
### Pre-flight check
|
||||||
|
|
||||||
A few pods should start in the `ingress-nginx` namespace:
|
A few pods should start in the `ingress-nginx` namespace:
|
||||||
|
|
|
@ -716,7 +716,7 @@ Do not try to edit it manually.
|
||||||
|
|
||||||
### [[Flag] watch namespace selector](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L30)
|
### [[Flag] watch namespace selector](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L30)
|
||||||
|
|
||||||
- [should ingore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
|
- [should ignore Ingress of namespace without label foo=bar and accept those of namespace with label foo=bar](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/namespace_selector.go#L63)
|
||||||
|
|
||||||
### [[Security] no-auth-locations](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/no_auth_locations.go#L33)
|
### [[Security] no-auth-locations](https://github.com/kubernetes/ingress-nginx/tree/main/test/e2e/settings/no_auth_locations.go#L33)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ Customization | [External authentication with response header propagation](custo
|
||||||
Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO
|
Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO
|
||||||
Features | [Rewrite](rewrite/README.md) | TODO | TODO
|
Features | [Rewrite](rewrite/README.md) | TODO | TODO
|
||||||
Features | [Session stickiness](affinity/cookie/README.md) | route requests consistently to the same endpoint | Advanced
|
Features | [Session stickiness](affinity/cookie/README.md) | route requests consistently to the same endpoint | Advanced
|
||||||
Features | [Canary Deployments](canary/README.md) | weigthed canary routing to a seperate deployment | Intermediate
|
Features | [Canary Deployments](canary/README.md) | weighted canary routing to a seperate deployment | Intermediate
|
||||||
Scaling | [Static IP](static-ip/README.md) | a single ingress gets a single static IP | Intermediate
|
Scaling | [Static IP](static-ip/README.md) | a single ingress gets a single static IP | Intermediate
|
||||||
TLS | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO
|
TLS | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO
|
||||||
TLS | [TLS termination](tls-termination/README.md) | TODO | TODO
|
TLS | [TLS termination](tls-termination/README.md) | TODO | TODO
|
||||||
|
|
|
@ -15,6 +15,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
|
||||||
| `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. |
|
| `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. |
|
||||||
| `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) |
|
| `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) |
|
||||||
| `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". |
|
| `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". |
|
||||||
|
| `--enable-annotation-validation` | If true, will enable the annotation validation feature. This value will be defaulted to true on a future release. |
|
||||||
| `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) |
|
| `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) |
|
||||||
| `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). |
|
| `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). |
|
||||||
| `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) |
|
| `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) |
|
||||||
|
@ -24,7 +25,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
|
||||||
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
|
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
|
||||||
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
|
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
|
||||||
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |
|
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |
|
||||||
| `--enable-topology-aware-routing` | Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto. (default false) |
|
| `--enable-topology-aware-routing` | Enable topology aware routing feature, needs service object annotation service.kubernetes.io/topology-mode sets to auto. (default false) |
|
||||||
| `--exclude-socket-metrics` | Set of socket request metrics to exclude which won't be exported nor being calculated. The possible socket request metrics to exclude are documented in the monitoring guide e.g. 'nginx_ingress_controller_request_duration_seconds,nginx_ingress_controller_response_size'|
|
| `--exclude-socket-metrics` | Set of socket request metrics to exclude which won't be exported nor being calculated. The possible socket request metrics to exclude are documented in the monitoring guide e.g. 'nginx_ingress_controller_request_duration_seconds,nginx_ingress_controller_response_size'|
|
||||||
| `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") |
|
| `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") |
|
||||||
| `--health-check-timeout` | Time limit, in seconds, for a probe to health-check-path to succeed. (default 10) |
|
| `--health-check-timeout` | Time limit, in seconds, for a probe to health-check-path to succeed. (default 10) |
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Exposing TCP and UDP services
|
# Exposing TCP and UDP services
|
||||||
|
|
||||||
Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags `--tcp-services-configmap` and `--udp-services-configmap` to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:
|
While the Kubernetes Ingress resource only officially supports routing external HTTP(s) traffic to services, ingress-nginx can be configured to receive external TCP/UDP traffic from non-HTTP protocols and route them to internal services using TCP/UDP port mappings that are specified within a ConfigMap.
|
||||||
`<namespace/service name>:<service port>:[PROXY]:[PROXY]`
|
|
||||||
|
To support this, the `--tcp-services-configmap` and `--udp-services-configmap` flags can be used to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:
|
||||||
|
`<service port>:<namespace/service name>:[PROXY]:[PROXY]`
|
||||||
|
|
||||||
It is also possible to use a number or the name of the port. The two last fields are optional.
|
It is also possible to use a number or the name of the port. The two last fields are optional.
|
||||||
Adding `PROXY` in either or both of the two last fields we can use [Proxy Protocol](https://www.nginx.com/resources/admin-guide/proxy-protocol) decoding (listen) and/or encoding (proxy_pass) in a TCP service.
|
Adding `PROXY` in either or both of the two last fields we can use [Proxy Protocol](https://www.nginx.com/resources/admin-guide/proxy-protocol) decoding (listen) and/or encoding (proxy_pass) in a TCP service.
|
||||||
|
|
|
@ -33,6 +33,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|
||||||
|[nginx.ingress.kubernetes.io/auth-cache-key](#external-authentication)|string|
|
|[nginx.ingress.kubernetes.io/auth-cache-key](#external-authentication)|string|
|
||||||
|[nginx.ingress.kubernetes.io/auth-cache-duration](#external-authentication)|string|
|
|[nginx.ingress.kubernetes.io/auth-cache-duration](#external-authentication)|string|
|
||||||
|[nginx.ingress.kubernetes.io/auth-keepalive](#external-authentication)|number|
|
|[nginx.ingress.kubernetes.io/auth-keepalive](#external-authentication)|number|
|
||||||
|
|[nginx.ingress.kubernetes.io/auth-keepalive-share-vars](#external-authentication)|"true" or "false"|
|
||||||
|[nginx.ingress.kubernetes.io/auth-keepalive-requests](#external-authentication)|number|
|
|[nginx.ingress.kubernetes.io/auth-keepalive-requests](#external-authentication)|number|
|
||||||
|[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number|
|
|[nginx.ingress.kubernetes.io/auth-keepalive-timeout](#external-authentication)|number|
|
||||||
|[nginx.ingress.kubernetes.io/auth-proxy-set-headers](#external-authentication)|string|
|
|[nginx.ingress.kubernetes.io/auth-proxy-set-headers](#external-authentication)|string|
|
||||||
|
@ -467,6 +468,9 @@ Additionally it is possible to set:
|
||||||
> Note: does not work with HTTP/2 listener because of a limitation in Lua [subrequests](https://github.com/openresty/lua-nginx-module#spdy-mode-not-fully-supported).
|
> Note: does not work with HTTP/2 listener because of a limitation in Lua [subrequests](https://github.com/openresty/lua-nginx-module#spdy-mode-not-fully-supported).
|
||||||
> [UseHTTP2](./configmap.md#use-http2) configuration should be disabled!
|
> [UseHTTP2](./configmap.md#use-http2) configuration should be disabled!
|
||||||
|
|
||||||
|
* `nginx.ingress.kubernetes.io/auth-keepalive-share-vars`:
|
||||||
|
Whether to share Nginx variables among the current request and the auth request. Example use case is to track requests: when set to "true" X-Request-ID HTTP header will be the same for the backend and the auth request.
|
||||||
|
Defaults to "false".
|
||||||
* `nginx.ingress.kubernetes.io/auth-keepalive-requests`:
|
* `nginx.ingress.kubernetes.io/auth-keepalive-requests`:
|
||||||
`<Requests>` to specify the maximum number of requests that can be served through one keepalive connection.
|
`<Requests>` to specify the maximum number of requests that can be served through one keepalive connection.
|
||||||
Defaults to `1000` and only applied if `auth-keepalive` is set to higher than `0`.
|
Defaults to `1000` and only applied if `auth-keepalive` is set to higher than `0`.
|
||||||
|
|
|
@ -29,7 +29,9 @@ The following table shows a configuration option's name, type, and the default v
|
||||||
|:---|:---|:------|:----|
|
|:---|:---|:------|:----|
|
||||||
|[add-headers](#add-headers)|string|""||
|
|[add-headers](#add-headers)|string|""||
|
||||||
|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"||
|
|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"||
|
||||||
|
|[allow-cross-namespace-resources](#allow-cross-namespace-resources)|bool|"true"||
|
||||||
|[allow-snippet-annotations](#allow-snippet-annotations)|bool|true||
|
|[allow-snippet-annotations](#allow-snippet-annotations)|bool|true||
|
||||||
|
|[annotations-risk-level](#annotations-risk-level)|string|Critical||
|
||||||
|[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""||
|
|[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""||
|
||||||
|[hide-headers](#hide-headers)|string array|empty||
|
|[hide-headers](#hide-headers)|string array|empty||
|
||||||
|[access-log-params](#access-log-params)|string|""||
|
|[access-log-params](#access-log-params)|string|""||
|
||||||
|
@ -239,6 +241,20 @@ Sets custom headers from named configmap before sending traffic to the client. S
|
||||||
|
|
||||||
Enables the return of the header Server from the backend instead of the generic nginx string. _**default:**_ is disabled
|
Enables the return of the header Server from the backend instead of the generic nginx string. _**default:**_ is disabled
|
||||||
|
|
||||||
|
## allow-cross-namespace-resources
|
||||||
|
|
||||||
|
Enables users to consume cross namespace resource on annotations, when was previously enabled . _**default:**_ true
|
||||||
|
|
||||||
|
**Annotations that may be impacted with this change**:
|
||||||
|
* `auth-secret`
|
||||||
|
* `auth-proxy-set-header`
|
||||||
|
* `auth-tls-secret`
|
||||||
|
* `fastcgi-params-configmap`
|
||||||
|
* `proxy-ssl-secret`
|
||||||
|
|
||||||
|
|
||||||
|
**This option will be defaulted to false in the next major release**
|
||||||
|
|
||||||
## allow-snippet-annotations
|
## allow-snippet-annotations
|
||||||
|
|
||||||
Enables Ingress to parse and add *-snippet annotations/directives created by the user. _**default:**_ `true`
|
Enables Ingress to parse and add *-snippet annotations/directives created by the user. _**default:**_ `true`
|
||||||
|
@ -246,6 +262,16 @@ Enables Ingress to parse and add *-snippet annotations/directives created by the
|
||||||
Warning: We recommend enabling this option only if you TRUST users with permission to create Ingress objects, as this
|
Warning: We recommend enabling this option only if you TRUST users with permission to create Ingress objects, as this
|
||||||
may allow a user to add restricted configurations to the final nginx.conf file
|
may allow a user to add restricted configurations to the final nginx.conf file
|
||||||
|
|
||||||
|
**This option will be defaulted to false in the next major release**
|
||||||
|
|
||||||
|
## annotations-risk-level
|
||||||
|
|
||||||
|
Represents the risk accepted on an annotation. If the risk is, for instance `Medium`, annotations with risk High and Critical will not be accepted.
|
||||||
|
|
||||||
|
Accepted values are `Critical`, `High`, `Medium` and `Low`.
|
||||||
|
|
||||||
|
Defaults to `Critical` but will be changed to `High` on the next minor release
|
||||||
|
|
||||||
## annotation-value-word-blocklist
|
## annotation-value-word-blocklist
|
||||||
|
|
||||||
Contains a comma-separated value of chars/words that are well known of being used to abuse Ingress configuration
|
Contains a comma-separated value of chars/words that are well known of being used to abuse Ingress configuration
|
||||||
|
|
38
go.mod
38
go.mod
|
@ -15,7 +15,7 @@ require (
|
||||||
github.com/moul/pb v0.0.0-20220425114252-bca18df4138c
|
github.com/moul/pb v0.0.0-20220425114252-bca18df4138c
|
||||||
github.com/ncabatoff/process-exporter v0.7.10
|
github.com/ncabatoff/process-exporter v0.7.10
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5
|
github.com/onsi/ginkgo/v2 v2.9.5
|
||||||
github.com/opencontainers/runc v1.1.7
|
github.com/opencontainers/runc v1.1.9
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/prometheus/client_golang v1.16.0
|
github.com/prometheus/client_golang v1.16.0
|
||||||
github.com/prometheus/client_model v0.4.0
|
github.com/prometheus/client_model v0.4.0
|
||||||
|
@ -25,19 +25,19 @@ require (
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/yudai/gojsondiff v1.0.0
|
github.com/yudai/gojsondiff v1.0.0
|
||||||
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
|
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
|
||||||
golang.org/x/crypto v0.10.0
|
golang.org/x/crypto v0.12.0
|
||||||
google.golang.org/grpc v1.56.1
|
google.golang.org/grpc v1.57.0
|
||||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
|
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
|
||||||
gopkg.in/go-playground/pool.v3 v3.1.1
|
gopkg.in/go-playground/pool.v3 v3.1.1
|
||||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
||||||
k8s.io/api v0.26.4
|
k8s.io/api v0.27.4
|
||||||
k8s.io/apiextensions-apiserver v0.26.4
|
k8s.io/apiextensions-apiserver v0.26.4
|
||||||
k8s.io/apimachinery v0.26.4
|
k8s.io/apimachinery v0.27.4
|
||||||
k8s.io/apiserver v0.26.4
|
k8s.io/apiserver v0.26.4
|
||||||
k8s.io/cli-runtime v0.26.4
|
k8s.io/cli-runtime v0.26.4
|
||||||
k8s.io/client-go v0.26.4
|
k8s.io/client-go v0.27.4
|
||||||
k8s.io/code-generator v0.26.4
|
k8s.io/code-generator v0.26.4
|
||||||
k8s.io/component-base v0.26.4
|
k8s.io/component-base v0.27.4
|
||||||
k8s.io/klog/v2 v2.100.1
|
k8s.io/klog/v2 v2.100.1
|
||||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
|
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
|
||||||
sigs.k8s.io/controller-runtime v0.14.6
|
sigs.k8s.io/controller-runtime v0.14.6
|
||||||
|
@ -59,9 +59,9 @@ require (
|
||||||
github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b // indirect
|
github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b // indirect
|
||||||
github.com/go-errors/errors v1.0.1 // indirect
|
github.com/go-errors/errors v1.0.1 // indirect
|
||||||
github.com/go-logr/logr v1.2.4 // indirect
|
github.com/go-logr/logr v1.2.4 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||||
github.com/go-openapi/swag v0.19.14 // indirect
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.0.6 // indirect
|
github.com/godbus/dbus/v5 v5.0.6 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
@ -72,14 +72,14 @@ require (
|
||||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/gofuzz v1.1.0 // indirect
|
github.com/google/gofuzz v1.1.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
|
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
|
||||||
|
@ -103,22 +103,22 @@ require (
|
||||||
golang.org/x/mod v0.10.0 // indirect
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/oauth2 v0.8.0 // indirect
|
golang.org/x/oauth2 v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/term v0.9.0 // indirect
|
golang.org/x/term v0.11.0 // indirect
|
||||||
golang.org/x/text v0.10.0 // indirect
|
golang.org/x/text v0.12.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.9.1 // indirect
|
golang.org/x/tools v0.9.1 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
|
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
|
||||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
sigs.k8s.io/kustomize/api v0.12.1 // indirect
|
sigs.k8s.io/kustomize/api v0.12.1 // indirect
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
|
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||||
|
|
89
go.sum
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 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
|
||||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||||
|
@ -184,8 +182,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
@ -235,10 +233,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
|
||||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
|
@ -276,7 +272,6 @@ github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 h1:t4WWQ9I797y7QU
|
||||||
github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag=
|
github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag=
|
||||||
github.com/ncabatoff/process-exporter v0.7.10 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
|
github.com/ncabatoff/process-exporter v0.7.10 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
|
||||||
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek=
|
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
@ -289,8 +284,8 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||||
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
|
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
|
||||||
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||||
|
@ -331,7 +326,7 @@ github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPH
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
@ -347,7 +342,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.1.3/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.1.3/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
@ -355,6 +352,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/urfave/cli v1.17.1-0.20160602030128-01a33823596e/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.17.1-0.20160602030128-01a33823596e/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
@ -390,8 +390,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -524,19 +524,19 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -647,8 +647,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -661,8 +661,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
|
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||||
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
|
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
|
||||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI=
|
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
@ -683,7 +683,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
@ -717,31 +716,31 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
k8s.io/api v0.26.4 h1:qSG2PmtcD23BkYiWfoYAcak870eF/hE7NNYBYavTT94=
|
k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
|
||||||
k8s.io/api v0.26.4/go.mod h1:WwKEXU3R1rgCZ77AYa7DFksd9/BAIKyOmRlbVxgvjCk=
|
k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
|
||||||
k8s.io/apiextensions-apiserver v0.26.4 h1:9D2RTxYGxrG5uYg6D7QZRcykXvavBvcA59j5kTaedQI=
|
k8s.io/apiextensions-apiserver v0.26.4 h1:9D2RTxYGxrG5uYg6D7QZRcykXvavBvcA59j5kTaedQI=
|
||||||
k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw=
|
k8s.io/apiextensions-apiserver v0.26.4/go.mod h1:cd4uGFGIgzEqUghWpRsr9KE8j2KNTjY8Ji8pnMMazyw=
|
||||||
k8s.io/apimachinery v0.26.4 h1:rZccKdBLg9vP6J09JD+z8Yr99Ce8gk3Lbi9TCx05Jzs=
|
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
|
||||||
k8s.io/apimachinery v0.26.4/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
|
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||||
k8s.io/apiserver v0.26.4 h1:3Oq4mnJv0mzVX7BR/Nod+8KjlELf/3Ljvu9ZWDyLUoA=
|
k8s.io/apiserver v0.26.4 h1:3Oq4mnJv0mzVX7BR/Nod+8KjlELf/3Ljvu9ZWDyLUoA=
|
||||||
k8s.io/apiserver v0.26.4/go.mod h1:yAY3O1vBM4/0OIGAGeWcdfzQvgdwJ188VirLcuSAVnw=
|
k8s.io/apiserver v0.26.4/go.mod h1:yAY3O1vBM4/0OIGAGeWcdfzQvgdwJ188VirLcuSAVnw=
|
||||||
k8s.io/cli-runtime v0.26.4 h1:MgSU871KDzBDX7V9GtuqS6Ai9lhQCHgRzkurnXOWtZ0=
|
k8s.io/cli-runtime v0.26.4 h1:MgSU871KDzBDX7V9GtuqS6Ai9lhQCHgRzkurnXOWtZ0=
|
||||||
k8s.io/cli-runtime v0.26.4/go.mod h1:MjJ2DXMChw2zcG0/agzm17xwKpfVxOfuoCdfY9iOCOE=
|
k8s.io/cli-runtime v0.26.4/go.mod h1:MjJ2DXMChw2zcG0/agzm17xwKpfVxOfuoCdfY9iOCOE=
|
||||||
k8s.io/client-go v0.26.4 h1:/7P/IbGBuT73A+G97trf44NTPSNqvuBREpOfdLbHvD4=
|
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
|
||||||
k8s.io/client-go v0.26.4/go.mod h1:6qOItWm3EwxJdl/8p5t7FWtWUOwyMdA8N9ekbW4idpI=
|
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||||
k8s.io/code-generator v0.26.4 h1:zgDD0qX13p/jtrAoYRRiYeQ5ibnriwmo2cMkMZAtJxc=
|
k8s.io/code-generator v0.26.4 h1:zgDD0qX13p/jtrAoYRRiYeQ5ibnriwmo2cMkMZAtJxc=
|
||||||
k8s.io/code-generator v0.26.4/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI=
|
k8s.io/code-generator v0.26.4/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI=
|
||||||
k8s.io/component-base v0.26.4 h1:Bg2xzyXNKL3eAuiTEu3XE198d6z22ENgFgGQv2GGOUk=
|
k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c=
|
||||||
k8s.io/component-base v0.26.4/go.mod h1:lTuWL1Xz/a4e80gmIC3YZG2JCO4xNwtKWHJWeJmsq20=
|
k8s.io/component-base v0.27.4/go.mod h1:hoiEETnLc0ioLv6WPeDt8vD34DDeB35MfQnxCARq3kY=
|
||||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
|
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
|
||||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
|
||||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
||||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
|
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
|
||||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg=
|
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
@ -749,8 +748,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
|
sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
|
||||||
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
|
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
|
||||||
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
|
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
|
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# AWS NLB with TLS termination
|
# AWS NLB with TLS termination
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# AWS - NLB
|
# AWS - NLB
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Baremetal
|
# Baremetal
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: NodePort
|
type: NodePort
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Digital Ocean
|
# Digital Ocean
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# Exoscale
|
# Exoscale
|
||||||
controller:
|
controller:
|
||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Scaleway
|
# Scaleway
|
||||||
controller:
|
controller:
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
service:
|
service:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
|
|
|
@ -23,8 +23,6 @@ TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA)
|
||||||
|
|
||||||
REGISTRY ?= local
|
REGISTRY ?= local
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IMAGE = $(REGISTRY)/e2e-test-cfssl
|
IMAGE = $(REGISTRY)/e2e-test-cfssl
|
||||||
|
|
||||||
# required to enable buildx
|
# required to enable buildx
|
||||||
|
|
|
@ -6,8 +6,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -17,6 +15,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/cfssl && make push
|
&& cd images/cfssl && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM alpine:3.18.0
|
FROM alpine:3.18.2
|
||||||
|
|
||||||
|
|
||||||
RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
|
RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
|
||||||
|
|
|
@ -6,8 +6,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -17,6 +15,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/custom-error-pages && make push
|
&& cd images/custom-error-pages && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ FROM gcr.io/distroless/static:nonroot
|
||||||
|
|
||||||
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/nginx-errors /
|
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/nginx-errors /
|
||||||
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/www /www
|
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/www /www
|
||||||
|
COPY --from=builder /go/src/k8s.io/ingress-nginx/images/custom-error-pages/etc /etc
|
||||||
USER nonroot:nonroot
|
USER nonroot:nonroot
|
||||||
|
|
||||||
CMD ["/nginx-errors"]
|
CMD ["/nginx-errors"]
|
||||||
|
|
|
@ -6,8 +6,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -17,6 +15,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/echo && make push
|
&& cd images/echo && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ SHELL=/bin/bash -o pipefail -o errexit
|
||||||
DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
|
DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
|
||||||
INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh
|
INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh
|
||||||
|
|
||||||
TAG ?=v1.0.0
|
SHORT_SHA ?=$(shell git rev-parse --short HEAD)
|
||||||
|
TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA)
|
||||||
|
|
||||||
REGISTRY ?= local
|
REGISTRY ?= local
|
||||||
|
|
||||||
IMAGE = $(REGISTRY)/ext-auth-example-authsvc
|
IMAGE = $(REGISTRY)/ext-auth-example-authsvc
|
||||||
|
|
|
@ -8,8 +8,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -19,6 +17,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/ext-auth-example-authsvc && make push
|
&& cd images/ext-auth-example-authsvc && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -17,6 +15,4 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/fastcgi-helloserver && make push
|
&& cd images/fastcgi-helloserver && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -16,13 +16,13 @@ func hello(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
key := keys[0]
|
key := keys[0]
|
||||||
fmt.Fprintf(w, "Hello "+string(key)+"!")
|
fmt.Fprintf(w, "Hello "+key+"!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/hello", hello)
|
http.HandleFunc("/hello", hello)
|
||||||
|
|
||||||
l, err := net.Listen("tcp", "0.0.0.0:9000")
|
l, err := net.Listen("tcp", "0.0.0.0:9000") //nolint:gosec // Ignore the gosec error since it's a hello server
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -19,6 +17,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/go-grpc-greeter-server && make push
|
&& cd images/go-grpc-greeter-server && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ type hwServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SayHello implements helloworld.GreeterServer
|
// SayHello implements helloworld.GreeterServer
|
||||||
func (s *hwServer) SayHello(ctx context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
|
func (s *hwServer) SayHello(_ context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) {
|
||||||
return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil
|
return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ type ecServer struct {
|
||||||
ecpb.UnimplementedEchoServer
|
ecpb.UnimplementedEchoServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ecServer) UnaryEcho(ctx context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
|
func (s *ecServer) UnaryEcho(_ context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) {
|
||||||
return &ecpb.EchoResponse{Message: req.Message}, nil
|
return &ecpb.EchoResponse{Message: req.Message}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -19,6 +17,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/httpbun && make push
|
&& cd images/httpbun && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "master"
|
|
||||||
|
|
|
@ -21,8 +21,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -32,6 +30,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/kube-webhook-certgen && make push
|
&& cd images/kube-webhook-certgen && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "main"
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
FROM alpine:3.18.0 as builder
|
FROM alpine:3.18.2 as builder
|
||||||
|
|
||||||
COPY . /
|
COPY . /
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ RUN apk update \
|
||||||
&& /build.sh
|
&& /build.sh
|
||||||
|
|
||||||
# Use a multi-stage build
|
# Use a multi-stage build
|
||||||
FROM alpine:3.18.0
|
FROM alpine:3.18.2
|
||||||
|
|
||||||
ENV PATH=$PATH:/usr/local/luajit/bin:/usr/local/nginx/sbin:/usr/local/nginx/bin
|
ENV PATH=$PATH:/usr/local/luajit/bin:/usr/local/nginx/sbin:/usr/local/nginx/bin
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,14 @@ set -o pipefail
|
||||||
|
|
||||||
export NGINX_VERSION=1.21.6
|
export NGINX_VERSION=1.21.6
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.1...master
|
# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.2...master
|
||||||
export NDK_VERSION=0.3.1
|
export NDK_VERSION=0.3.2
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master
|
# Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master
|
||||||
export SETMISC_VERSION=0.33
|
export SETMISC_VERSION=0.33
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.33...master
|
# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.34...master
|
||||||
export MORE_HEADERS_VERSION=0.33
|
export MORE_HEADERS_VERSION=0.34
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master
|
# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master
|
||||||
export NGINX_DIGEST_AUTH=1.0.0
|
export NGINX_DIGEST_AUTH=1.0.0
|
||||||
|
@ -65,32 +65,32 @@ export MODSECURITY_LIB_VERSION=e9a7ba4a60be48f761e0328c6dfcc668d70e35a0
|
||||||
# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master
|
# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master
|
||||||
export OWASP_MODSECURITY_CRS_VERSION=v3.3.4
|
export OWASP_MODSECURITY_CRS_VERSION=v3.3.4
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.21...master
|
# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.25...master
|
||||||
export LUA_NGX_VERSION=0.10.21
|
export LUA_NGX_VERSION=0.10.25
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.11...master
|
# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.13...master
|
||||||
export LUA_STREAM_NGX_VERSION=0.0.11
|
export LUA_STREAM_NGX_VERSION=0.0.13
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master
|
# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master
|
||||||
export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf
|
export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.10...openresty:master
|
# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.11...openresty:master
|
||||||
export LUA_CJSON_VERSION=2.1.0.10
|
export LUA_CJSON_VERSION=2.1.0.11
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.3...master
|
# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.3...master
|
||||||
export GEOIP2_VERSION=a26c6beed77e81553686852dceb6c7fdacc5970d
|
export GEOIP2_VERSION=a26c6beed77e81553686852dceb6c7fdacc5970d
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20220411...v2.1-agentzh
|
# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20230410...v2.1-agentzh
|
||||||
export LUAJIT_VERSION=2.1-20220411
|
export LUAJIT_VERSION=2.1-20230410
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master
|
||||||
export LUA_RESTY_BALANCER=0.04
|
export LUA_RESTY_BALANCER=0.04
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.11...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.13...master
|
||||||
export LUA_RESTY_CACHE=0.11
|
export LUA_RESTY_CACHE=0.13
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.23...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.27...master
|
||||||
export LUA_RESTY_CORE=0.1.23
|
export LUA_RESTY_CORE=0.1.27
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/v0.1.0...master
|
# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/v0.1.0...master
|
||||||
export LUA_RESTY_COOKIE_VERSION=303e32e512defced053a6484bc0745cf9dc0d39e
|
export LUA_RESTY_COOKIE_VERSION=303e32e512defced053a6484bc0745cf9dc0d39e
|
||||||
|
@ -101,17 +101,17 @@ export LUA_RESTY_DNS=0.22
|
||||||
# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.16.1...master
|
# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.16.1...master
|
||||||
export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8
|
export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.08...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.09...master
|
||||||
export LUA_RESTY_LOCK=0.08
|
export LUA_RESTY_LOCK=0.09
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.10...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.11...master
|
||||||
export LUA_RESTY_UPLOAD_VERSION=0.10
|
export LUA_RESTY_UPLOAD_VERSION=0.11
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master
|
||||||
export LUA_RESTY_STRING_VERSION=0.15
|
export LUA_RESTY_STRING_VERSION=0.15
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.16...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.17...master
|
||||||
export LUA_RESTY_MEMCACHED_VERSION=0.16
|
export LUA_RESTY_MEMCACHED_VERSION=0.17
|
||||||
|
|
||||||
# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master
|
# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master
|
||||||
export LUA_RESTY_REDIS_VERSION=0.30
|
export LUA_RESTY_REDIS_VERSION=0.30
|
||||||
|
@ -199,13 +199,13 @@ cd "$BUILD_PATH"
|
||||||
get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \
|
get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \
|
||||||
"https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz"
|
"https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src 0e971105e210d272a497567fa2e2c256f4e39b845a5ba80d373e26ba1abfbd85 \
|
get_src aa961eafb8317e0eb8da37eb6e2c9ff42267edd18b56947384e719b85188f58b \
|
||||||
"https://github.com/simpl/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"
|
"https://github.com/vision5/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \
|
get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \
|
||||||
"https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz"
|
"https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src a3dcbab117a9c103bc1ea5200fc00a7b7d2af97ff7fd525f16f8ac2632e30fbf \
|
get_src 0c0d2ced2ce895b3f45eb2b230cd90508ab2a773299f153de14a43e44c1209b3 \
|
||||||
"https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz"
|
"https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \
|
get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \
|
||||||
|
@ -241,10 +241,10 @@ get_src 7d5f3439c8df56046d0564b5857fd8a30296ab1bd6df0f048aed7afb56a0a4c2 \
|
||||||
get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \
|
get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \
|
||||||
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
|
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
|
||||||
else
|
else
|
||||||
get_src 9db756000578efaecb43bea4fc6cf631aaa80988d86ffe5d3afeb9927895ffad \
|
get_src bc764db42830aeaf74755754b900253c233ad57498debe7a441cee2c6f4b07c2 \
|
||||||
"https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz"
|
"https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src c7924f28cb014a99636e747ea907724dd55f60e180cb92cde6e8ed48d2278f27 \
|
get_src 01b715754a8248cc7228e0c8f97f7488ae429d90208de0481394e35d24cef32f \
|
||||||
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
|
"https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
@ -256,7 +256,7 @@ if [[ ${ARCH} == "s390x" ]]; then
|
||||||
get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \
|
get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \
|
||||||
"https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz"
|
"https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz"
|
||||||
else
|
else
|
||||||
get_src d3f2c870f8f88477b01726b32accab30f6e5d57ae59c5ec87374ff73d0794316 \
|
get_src 77bbcbb24c3c78f51560017288f3118d995fe71240aa379f5818ff6b166712ff \
|
||||||
"https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz"
|
"https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ get_src 8d39c6b23f941a2d11571daaccc04e69539a3fcbcc50a631837560d5861a7b96 \
|
||||||
get_src 4c1933434572226942c65b2f2b26c8a536ab76aa771a3c7f6c2629faa764976b \
|
get_src 4c1933434572226942c65b2f2b26c8a536ab76aa771a3c7f6c2629faa764976b \
|
||||||
"https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz"
|
"https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src 5d16e623d17d4f42cc64ea9cfb69ca960d313e12f5d828f785dd227cc483fcbd \
|
get_src deb4ab1ffb9f3d962c4b4a2c4bdff692b86a209e3835ae71ebdf3b97189e40a9 \
|
||||||
"https://github.com/openresty/lua-resty-upload/archive/v$LUA_RESTY_UPLOAD_VERSION.tar.gz"
|
"https://github.com/openresty/lua-resty-upload/archive/v$LUA_RESTY_UPLOAD_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \
|
get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \
|
||||||
|
@ -279,20 +279,20 @@ if [[ ${ARCH} == "s390x" ]]; then
|
||||||
get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \
|
get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \
|
||||||
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
|
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
|
||||||
else
|
else
|
||||||
get_src efd6b51520429e64b1bcc10f477d370ebed1631c190f7e4dc270d959a743ad7d \
|
get_src 39baab9e2b31cc48cecf896cea40ef6e80559054fd8a6e440cc804a858ea84d4 \
|
||||||
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
|
"https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
get_src 0c551d6898f89f876e48730f9b55790d0ba07d5bc0aa6c76153277f63c19489f \
|
get_src a77b9de160d81712f2f442e1de8b78a5a7ef0d08f13430ff619f79235db974d4 \
|
||||||
"https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz"
|
"https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \
|
get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \
|
||||||
"https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz"
|
"https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src e810ed124fe788b8e4aac2c8960dda1b9a6f8d0ca94ce162f28d3f4d877df8af \
|
get_src 573184006b98ccee2594b0d134fa4d05e5d2afd5141cbad315051ccf7e9b6403 \
|
||||||
"https://github.com/openresty/lua-resty-lrucache/archive/v$LUA_RESTY_CACHE.tar.gz"
|
"https://github.com/openresty/lua-resty-lrucache/archive/v$LUA_RESTY_CACHE.tar.gz"
|
||||||
|
|
||||||
get_src 2b4683f9abe73e18ca00345c65010c9056777970907a311d6e1699f753141de2 \
|
get_src b4ddcd47db347e9adf5c1e1491a6279a6ae2a3aff3155ef77ea0a65c998a69c1 \
|
||||||
"https://github.com/openresty/lua-resty-lock/archive/v$LUA_RESTY_LOCK.tar.gz"
|
"https://github.com/openresty/lua-resty-lock/archive/v$LUA_RESTY_LOCK.tar.gz"
|
||||||
|
|
||||||
get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
|
get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
|
||||||
|
@ -301,7 +301,7 @@ get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \
|
||||||
get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \
|
get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \
|
||||||
"https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz"
|
"https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz"
|
||||||
|
|
||||||
get_src 42893da0e3de4ec180c9bf02f82608d78787290a70c5644b538f29d243147396 \
|
get_src 02733575c4aed15f6cab662378e4b071c0a4a4d07940c4ef19a7319e9be943d4 \
|
||||||
"https://github.com/openresty/lua-resty-memcached/archive/v$LUA_RESTY_MEMCACHED_VERSION.tar.gz"
|
"https://github.com/openresty/lua-resty-memcached/archive/v$LUA_RESTY_MEMCACHED_VERSION.tar.gz"
|
||||||
|
|
||||||
get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \
|
get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \
|
||||||
|
|
|
@ -8,8 +8,6 @@ steps:
|
||||||
entrypoint: bash
|
entrypoint: bash
|
||||||
env:
|
env:
|
||||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
- SHORT_SHA=$SHORT_SHA
|
|
||||||
- BASE_REF=$_PULL_BASE_REF
|
|
||||||
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
- REGISTRY=gcr.io/k8s-staging-ingress-nginx
|
||||||
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
# default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx
|
||||||
# set the home to /root explicitly to if using docker buildx
|
# set the home to /root explicitly to if using docker buildx
|
||||||
|
@ -19,6 +17,3 @@ steps:
|
||||||
- |
|
- |
|
||||||
gcloud auth configure-docker \
|
gcloud auth configure-docker \
|
||||||
&& cd images/opentelemetry && make push
|
&& cd images/opentelemetry && make push
|
||||||
substitutions:
|
|
||||||
_GIT_TAG: "12345"
|
|
||||||
_PULL_BASE_REF: "main"
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.18.0 as base
|
FROM alpine:3.18.2 as base
|
||||||
|
|
||||||
RUN mkdir -p /opt/third_party/install
|
RUN mkdir -p /opt/third_party/install
|
||||||
COPY . /opt/third_party/
|
COPY . /opt/third_party/
|
||||||
|
|
|
@ -43,7 +43,7 @@ image:
|
||||||
--pull \
|
--pull \
|
||||||
--push \
|
--push \
|
||||||
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
|
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
|
||||||
--build-arg GOLANG_VERSION=1.20.5 \
|
--build-arg GOLANG_VERSION=1.20.6 \
|
||||||
--build-arg ETCD_VERSION=3.4.3-0 \
|
--build-arg ETCD_VERSION=3.4.3-0 \
|
||||||
--build-arg K8S_RELEASE=v1.26.0 \
|
--build-arg K8S_RELEASE=v1.26.0 \
|
||||||
--build-arg RESTY_CLI_VERSION=0.27 \
|
--build-arg RESTY_CLI_VERSION=0.27 \
|
||||||
|
@ -64,7 +64,7 @@ build: ensure-buildx
|
||||||
--progress=${PROGRESS} \
|
--progress=${PROGRESS} \
|
||||||
--pull \
|
--pull \
|
||||||
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
|
--build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \
|
||||||
--build-arg GOLANG_VERSION=1.20.5 \
|
--build-arg GOLANG_VERSION=1.20.6 \
|
||||||
--build-arg ETCD_VERSION=3.4.3-0 \
|
--build-arg ETCD_VERSION=3.4.3-0 \
|
||||||
--build-arg K8S_RELEASE=v1.26.0 \
|
--build-arg K8S_RELEASE=v1.26.0 \
|
||||||
--build-arg RESTY_CLI_VERSION=0.27 \
|
--build-arg RESTY_CLI_VERSION=0.27 \
|
||||||
|
|
|
@ -42,19 +42,16 @@ type IngressAdmission struct {
|
||||||
Checker Checker
|
Checker Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var ingressResource = metav1.GroupVersionKind{
|
||||||
ingressResource = metav1.GroupVersionKind{
|
Group: networking.GroupName,
|
||||||
Group: networking.GroupName,
|
Version: "v1",
|
||||||
Version: "v1",
|
Kind: "Ingress",
|
||||||
Kind: "Ingress",
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleAdmission populates the admission Response
|
// HandleAdmission populates the admission Response
|
||||||
// with Allowed=false if the Object is an ingress that would prevent nginx to reload the configuration
|
// with Allowed=false if the Object is an ingress that would prevent nginx to reload the configuration
|
||||||
// with Allowed=true otherwise
|
// with Allowed=true otherwise
|
||||||
func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {
|
func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {
|
||||||
|
|
||||||
review, isV1 := obj.(*admissionv1.AdmissionReview)
|
review, isV1 := obj.(*admissionv1.AdmissionReview)
|
||||||
if !isV1 {
|
if !isV1 {
|
||||||
return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")
|
return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")
|
||||||
|
|
|
@ -33,12 +33,12 @@ type failTestChecker struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ftc failTestChecker) CheckIngress(ing *networking.Ingress) error {
|
func (ftc failTestChecker) CheckIngress(_ *networking.Ingress) error {
|
||||||
ftc.t.Error("checker should not be called")
|
ftc.t.Error("checker should not be called")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ftc failTestChecker) CheckWarning(ing *networking.Ingress) ([]string, error) {
|
func (ftc failTestChecker) CheckWarning(_ *networking.Ingress) ([]string, error) {
|
||||||
ftc.t.Error("checker should not be called")
|
ftc.t.Error("checker should not be called")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,7 @@ import (
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var scheme = runtime.NewScheme()
|
||||||
scheme = runtime.NewScheme()
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if err := admissionv1.AddToScheme(scheme); err != nil {
|
if err := admissionv1.AddToScheme(scheme); err != nil {
|
||||||
|
|
|
@ -27,19 +27,44 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
serverAliasAnnotation = "server-alias"
|
||||||
|
)
|
||||||
|
|
||||||
|
var aliasAnnotation = parser.Annotation{
|
||||||
|
Group: "alias",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
serverAliasAnnotation: {
|
||||||
|
Validator: parser.ValidateArrayOfServerName,
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskHigh, // High as this allows regex chars
|
||||||
|
Documentation: `this annotation can be used to define additional server
|
||||||
|
aliases for this Ingress`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type alias struct {
|
type alias struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new Alias annotation parser
|
// NewParser creates a new Alias annotation parser
|
||||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return alias{r}
|
return alias{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: aliasAnnotation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a alias) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress rule
|
// Parse parses the annotations contained in the ingress rule
|
||||||
// used to add an alias to the provided hosts
|
// used to add an alias to the provided hosts
|
||||||
func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
val, err := parser.GetStringAnnotation("server-alias", ing)
|
val, err := parser.GetStringAnnotation(serverAliasAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
|
@ -47,7 +72,7 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
aliases := sets.NewString()
|
aliases := sets.NewString()
|
||||||
for _, alias := range strings.Split(val, ",") {
|
for _, alias := range strings.Split(val, ",") {
|
||||||
alias = strings.TrimSpace(alias)
|
alias = strings.TrimSpace(alias)
|
||||||
if len(alias) == 0 {
|
if alias == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,3 +86,8 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a alias) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, aliasAnnotation.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
var annotation = parser.GetAnnotationWithPrefix("server-alias")
|
var annotation = parser.GetAnnotationWithPrefix(serverAliasAnnotation)
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
ap := NewParser(&resolver.Mock{})
|
ap := NewParser(&resolver.Mock{})
|
||||||
|
@ -36,16 +36,20 @@ func TestParse(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
annotations map[string]string
|
annotations map[string]string
|
||||||
expected []string
|
expected []string
|
||||||
|
skipValidation bool
|
||||||
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{map[string]string{annotation: "a.com, b.com, , c.com"}, []string{"a.com", "b.com", "c.com"}},
|
{map[string]string{annotation: "a.com, b.com, , c.com"}, []string{"a.com", "b.com", "c.com"}, false, false},
|
||||||
{map[string]string{annotation: "www.example.com"}, []string{"www.example.com"}},
|
{map[string]string{annotation: "www.example.com"}, []string{"www.example.com"}, false, false},
|
||||||
{map[string]string{annotation: "*.example.com,www.example.*"}, []string{"*.example.com", "www.example.*"}},
|
{map[string]string{annotation: "*.example.com,www.example.*"}, []string{"*.example.com", "www.example.*"}, false, false},
|
||||||
{map[string]string{annotation: `~^www\d+\.example\.com$`}, []string{`~^www\d+\.example\.com$`}},
|
{map[string]string{annotation: `~^www\d+\.example\.com$`}, []string{`~^www\d+\.example\.com$`}, false, false},
|
||||||
{map[string]string{annotation: ""}, []string{}},
|
{map[string]string{annotation: `www.xpto;lala`}, []string{}, false, true},
|
||||||
{map[string]string{}, []string{}},
|
{map[string]string{annotation: `www.xpto;lala`}, []string{"www.xpto;lala"}, true, false}, // When we skip validation no error should happen
|
||||||
{nil, []string{}},
|
{map[string]string{annotation: ""}, []string{}, false, true},
|
||||||
|
{map[string]string{}, []string{}, false, true},
|
||||||
|
{nil, []string{}, false, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
ing := &networking.Ingress{
|
ing := &networking.Ingress{
|
||||||
|
@ -58,7 +62,16 @@ func TestParse(t *testing.T) {
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
ing.SetAnnotations(testCase.annotations)
|
ing.SetAnnotations(testCase.annotations)
|
||||||
result, _ := ap.Parse(ing)
|
if testCase.skipValidation {
|
||||||
|
parser.EnableAnnotationValidation = false
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
parser.EnableAnnotationValidation = true
|
||||||
|
})
|
||||||
|
result, err := ap.Parse(ing)
|
||||||
|
if (err != nil) != testCase.wantErr {
|
||||||
|
t.Errorf("ParseAliasAnnotation() annotation: %s, error = %v, wantErr %v", testCase.annotations, err, testCase.wantErr)
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(result, testCase.expected) {
|
if !reflect.DeepEqual(result, testCase.expected) {
|
||||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload"
|
||||||
|
"k8s.io/ingress-nginx/internal/ingress/annotations/ipallowlist"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
|
||||||
|
@ -86,37 +86,36 @@ type Ingress struct {
|
||||||
CorsConfig cors.Config
|
CorsConfig cors.Config
|
||||||
CustomHTTPErrors []int
|
CustomHTTPErrors []int
|
||||||
DefaultBackend *apiv1.Service
|
DefaultBackend *apiv1.Service
|
||||||
//TODO: Change this back into an error when https://github.com/imdario/mergo/issues/100 is resolved
|
FastCGI fastcgi.Config
|
||||||
FastCGI fastcgi.Config
|
Denied *string
|
||||||
Denied *string
|
ExternalAuth authreq.Config
|
||||||
ExternalAuth authreq.Config
|
EnableGlobalAuth bool
|
||||||
EnableGlobalAuth bool
|
HTTP2PushPreload bool
|
||||||
HTTP2PushPreload bool
|
Opentracing opentracing.Config
|
||||||
Opentracing opentracing.Config
|
Opentelemetry opentelemetry.Config
|
||||||
Opentelemetry opentelemetry.Config
|
Proxy proxy.Config
|
||||||
Proxy proxy.Config
|
ProxySSL proxyssl.Config
|
||||||
ProxySSL proxyssl.Config
|
RateLimit ratelimit.Config
|
||||||
RateLimit ratelimit.Config
|
GlobalRateLimit globalratelimit.Config
|
||||||
GlobalRateLimit globalratelimit.Config
|
Redirect redirect.Config
|
||||||
Redirect redirect.Config
|
Rewrite rewrite.Config
|
||||||
Rewrite rewrite.Config
|
Satisfy string
|
||||||
Satisfy string
|
ServerSnippet string
|
||||||
ServerSnippet string
|
ServiceUpstream bool
|
||||||
ServiceUpstream bool
|
SessionAffinity sessionaffinity.Config
|
||||||
SessionAffinity sessionaffinity.Config
|
SSLPassthrough bool
|
||||||
SSLPassthrough bool
|
UsePortInRedirects bool
|
||||||
UsePortInRedirects bool
|
UpstreamHashBy upstreamhashby.Config
|
||||||
UpstreamHashBy upstreamhashby.Config
|
LoadBalancing string
|
||||||
LoadBalancing string
|
UpstreamVhost string
|
||||||
UpstreamVhost string
|
Denylist ipdenylist.SourceRange
|
||||||
Whitelist ipwhitelist.SourceRange
|
XForwardedPrefix string
|
||||||
Denylist ipdenylist.SourceRange
|
SSLCipher sslcipher.Config
|
||||||
XForwardedPrefix string
|
Logs log.Config
|
||||||
SSLCipher sslcipher.Config
|
ModSecurity modsecurity.Config
|
||||||
Logs log.Config
|
Mirror mirror.Config
|
||||||
ModSecurity modsecurity.Config
|
StreamSnippet string
|
||||||
Mirror mirror.Config
|
Allowlist ipallowlist.SourceRange
|
||||||
StreamSnippet string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extractor defines the annotation parsers to be used in the extraction of annotations
|
// Extractor defines the annotation parsers to be used in the extraction of annotations
|
||||||
|
@ -159,7 +158,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
|
||||||
"UpstreamHashBy": upstreamhashby.NewParser(cfg),
|
"UpstreamHashBy": upstreamhashby.NewParser(cfg),
|
||||||
"LoadBalancing": loadbalancing.NewParser(cfg),
|
"LoadBalancing": loadbalancing.NewParser(cfg),
|
||||||
"UpstreamVhost": upstreamvhost.NewParser(cfg),
|
"UpstreamVhost": upstreamvhost.NewParser(cfg),
|
||||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
"Allowlist": ipallowlist.NewParser(cfg),
|
||||||
"Denylist": ipdenylist.NewParser(cfg),
|
"Denylist": ipdenylist.NewParser(cfg),
|
||||||
"XForwardedPrefix": xforwardedprefix.NewParser(cfg),
|
"XForwardedPrefix": xforwardedprefix.NewParser(cfg),
|
||||||
"SSLCipher": sslcipher.NewParser(cfg),
|
"SSLCipher": sslcipher.NewParser(cfg),
|
||||||
|
@ -173,16 +172,23 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract extracts the annotations from an Ingress
|
// Extract extracts the annotations from an Ingress
|
||||||
func (e Extractor) Extract(ing *networking.Ingress) *Ingress {
|
func (e Extractor) Extract(ing *networking.Ingress) (*Ingress, error) {
|
||||||
pia := &Ingress{
|
pia := &Ingress{
|
||||||
ObjectMeta: ing.ObjectMeta,
|
ObjectMeta: ing.ObjectMeta,
|
||||||
}
|
}
|
||||||
|
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
for name, annotationParser := range e.annotations {
|
for name, annotationParser := range e.annotations {
|
||||||
|
if err := annotationParser.Validate(ing.GetAnnotations()); err != nil {
|
||||||
|
return nil, errors.NewRiskyAnnotations(name)
|
||||||
|
}
|
||||||
val, err := annotationParser.Parse(ing)
|
val, err := annotationParser.Parse(ing)
|
||||||
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
|
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.ErrorS(err, "ingress contains invalid annotation value")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if errors.IsMissingAnnotations(err) {
|
if errors.IsMissingAnnotations(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -220,5 +226,5 @@ func (e Extractor) Extract(ing *networking.Ingress) *Ingress {
|
||||||
klog.ErrorS(err, "unexpected error merging extracted annotations")
|
klog.ErrorS(err, "unexpected error merging extracted annotations")
|
||||||
}
|
}
|
||||||
|
|
||||||
return pia
|
return pia, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,11 @@ func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||||
if secret, _ := m.GetSecret(name); secret != nil {
|
secret, err := m.GetSecret(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if secret != nil {
|
||||||
return &resolver.AuthSSLCert{
|
return &resolver.AuthSSLCert{
|
||||||
Secret: name,
|
Secret: name,
|
||||||
CAFileName: "/opt/ca.pem",
|
CAFileName: "/opt/ca.pem",
|
||||||
|
@ -134,8 +138,11 @@ func TestSSLPassthrough(t *testing.T) {
|
||||||
|
|
||||||
for _, foo := range fooAnns {
|
for _, foo := range fooAnns {
|
||||||
ing.SetAnnotations(foo.annotations)
|
ing.SetAnnotations(foo.annotations)
|
||||||
r := ec.Extract(ing).SSLPassthrough
|
r, err := ec.Extract(ing)
|
||||||
if r != foo.er {
|
if err != nil {
|
||||||
|
t.Errorf("Errors should be null: %v", err)
|
||||||
|
}
|
||||||
|
if r.SSLPassthrough != foo.er {
|
||||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +165,11 @@ func TestUpstreamHashBy(t *testing.T) {
|
||||||
|
|
||||||
for _, foo := range fooAnns {
|
for _, foo := range fooAnns {
|
||||||
ing.SetAnnotations(foo.annotations)
|
ing.SetAnnotations(foo.annotations)
|
||||||
r := ec.Extract(ing).UpstreamHashBy.UpstreamHashBy
|
r, err := ec.Extract(ing)
|
||||||
if r != foo.er {
|
if err != nil {
|
||||||
|
t.Errorf("error should be null: %v", err)
|
||||||
|
}
|
||||||
|
if r.UpstreamHashBy.UpstreamHashBy != foo.er {
|
||||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +195,11 @@ func TestAffinitySession(t *testing.T) {
|
||||||
|
|
||||||
for _, foo := range fooAnns {
|
for _, foo := range fooAnns {
|
||||||
ing.SetAnnotations(foo.annotations)
|
ing.SetAnnotations(foo.annotations)
|
||||||
r := ec.Extract(ing).SessionAffinity
|
rann, err := ec.Extract(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error should be null: %v", err)
|
||||||
|
}
|
||||||
|
r := rann.SessionAffinity
|
||||||
t.Logf("Testing pass %v %v", foo.affinitytype, foo.cookiename)
|
t.Logf("Testing pass %v %v", foo.affinitytype, foo.cookiename)
|
||||||
|
|
||||||
if r.Type != foo.affinitytype {
|
if r.Type != foo.affinitytype {
|
||||||
|
@ -228,7 +242,11 @@ func TestCors(t *testing.T) {
|
||||||
|
|
||||||
for _, foo := range fooAnns {
|
for _, foo := range fooAnns {
|
||||||
ing.SetAnnotations(foo.annotations)
|
ing.SetAnnotations(foo.annotations)
|
||||||
r := ec.Extract(ing).CorsConfig
|
rann, err := ec.Extract(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error should be null: %v", err)
|
||||||
|
}
|
||||||
|
r := rann.CorsConfig
|
||||||
t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials)
|
t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials)
|
||||||
|
|
||||||
if r.CorsEnabled != foo.corsenabled {
|
if r.CorsEnabled != foo.corsenabled {
|
||||||
|
@ -256,9 +274,9 @@ func TestCors(t *testing.T) {
|
||||||
if r.CorsAllowCredentials != foo.credentials {
|
if r.CorsAllowCredentials != foo.credentials {
|
||||||
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
|
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCustomHTTPErrors(t *testing.T) {
|
func TestCustomHTTPErrors(t *testing.T) {
|
||||||
ec := NewAnnotationExtractor(mockCfg{})
|
ec := NewAnnotationExtractor(mockCfg{})
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
@ -277,7 +295,11 @@ func TestCustomHTTPErrors(t *testing.T) {
|
||||||
|
|
||||||
for _, foo := range fooAnns {
|
for _, foo := range fooAnns {
|
||||||
ing.SetAnnotations(foo.annotations)
|
ing.SetAnnotations(foo.annotations)
|
||||||
r := ec.Extract(ing).CustomHTTPErrors
|
rann, err := ec.Extract(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error should be null: %v", err)
|
||||||
|
}
|
||||||
|
r := rann.CustomHTTPErrors
|
||||||
|
|
||||||
// Check that expected codes were created
|
// Check that expected codes were created
|
||||||
for i := range foo.er {
|
for i := range foo.er {
|
||||||
|
|
|
@ -32,13 +32,56 @@ import (
|
||||||
"k8s.io/ingress-nginx/pkg/util/file"
|
"k8s.io/ingress-nginx/pkg/util/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authSecretTypeAnnotation = "auth-secret-type" //#nosec G101
|
||||||
|
authRealmAnnotation = "auth-realm"
|
||||||
|
authTypeAnnotation = "auth-type"
|
||||||
|
// This should be exported as it is imported by other packages
|
||||||
|
AuthSecretAnnotation = "auth-secret" //#nosec G101
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
authTypeRegex = regexp.MustCompile(`basic|digest`)
|
authTypeRegex = regexp.MustCompile(`basic|digest`)
|
||||||
|
authSecretTypeRegex = regexp.MustCompile(`auth-file|auth-map`)
|
||||||
|
|
||||||
// AuthDirectory default directory used to store files
|
// AuthDirectory default directory used to store files
|
||||||
// to authenticate request
|
// to authenticate request
|
||||||
AuthDirectory = "/etc/ingress-controller/auth"
|
AuthDirectory = "/etc/ingress-controller/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var AuthSecretConfig = parser.AnnotationConfig{
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
|
||||||
|
Documentation: `This annotation defines the name of the Secret that contains the usernames and passwords which are granted access to the paths defined in the Ingress rules. `,
|
||||||
|
}
|
||||||
|
|
||||||
|
var authSecretAnnotations = parser.Annotation{
|
||||||
|
Group: "authentication",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
AuthSecretAnnotation: AuthSecretConfig,
|
||||||
|
authSecretTypeAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(authSecretTypeRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation what is the format of auth-secret value. Can be "auth-file" that defines the content of an htpasswd file, or "auth-map" where each key
|
||||||
|
is a user and each value is the password.`,
|
||||||
|
},
|
||||||
|
authRealmAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.CharsWithSpace, false),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
|
||||||
|
Documentation: `This annotation defines the realm (message) that should be shown to user when authentication is requested.`,
|
||||||
|
},
|
||||||
|
authTypeAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(authTypeRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation defines the basic authentication type. Should be "basic" or "digest"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fileAuth = "auth-file"
|
fileAuth = "auth-file"
|
||||||
mapAuth = "auth-map"
|
mapAuth = "auth-map"
|
||||||
|
@ -85,13 +128,18 @@ func (bd1 *Config) Equal(bd2 *Config) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type auth struct {
|
type auth struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
authDirectory string
|
authDirectory string
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new authentication annotation parser
|
// NewParser creates a new authentication annotation parser
|
||||||
func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return auth{r, authDirectory}
|
return auth{
|
||||||
|
r: r,
|
||||||
|
authDirectory: authDirectory,
|
||||||
|
annotationConfig: authSecretAnnotations,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
|
@ -99,7 +147,7 @@ func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotati
|
||||||
// and generated an htpasswd compatible file to be used as source
|
// and generated an htpasswd compatible file to be used as source
|
||||||
// during the authentication process
|
// during the authentication process
|
||||||
func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
at, err := parser.GetStringAnnotation("auth-type", ing)
|
at, err := parser.GetStringAnnotation(authTypeAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -109,21 +157,24 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var secretType string
|
var secretType string
|
||||||
secretType, err = parser.GetStringAnnotation("auth-secret-type", ing)
|
secretType, err = parser.GetStringAnnotation(authSecretTypeAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
secretType = fileAuth
|
secretType = fileAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := parser.GetStringAnnotation("auth-secret", ing)
|
s, err := parser.GetStringAnnotation(AuthSecretAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ing_errors.LocationDenied{
|
return nil, ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sns, sname, err := cache.SplitMetaNamespaceKey(s)
|
sns, sname, err := cache.SplitMetaNamespaceKey(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ing_errors.LocationDenied{
|
return nil, ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
Reason: fmt.Errorf("error reading secret name from annotation: %w", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,16 +182,26 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
if sns == "" {
|
if sns == "" {
|
||||||
sns = ing.Namespace
|
sns = ing.Namespace
|
||||||
}
|
}
|
||||||
|
secCfg := a.r.GetSecurityConfiguration()
|
||||||
|
// We don't accept different namespaces for secrets.
|
||||||
|
if !secCfg.AllowCrossNamespaceResources && sns != ing.Namespace {
|
||||||
|
return nil, ing_errors.LocationDeniedError{
|
||||||
|
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
name := fmt.Sprintf("%v/%v", sns, sname)
|
name := fmt.Sprintf("%v/%v", sns, sname)
|
||||||
secret, err := a.r.GetSecret(name)
|
secret, err := a.r.GetSecret(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ing_errors.LocationDenied{
|
return nil, ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("unexpected error reading secret %s: %w", name, err),
|
Reason: fmt.Errorf("unexpected error reading secret %s: %w", name, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
realm, _ := parser.GetStringAnnotation("auth-realm", ing)
|
realm, err := parser.GetStringAnnotation(authRealmAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
passFilename := fmt.Sprintf("%v/%v-%v-%v.passwd", a.authDirectory, ing.GetNamespace(), ing.UID, secret.UID)
|
passFilename := fmt.Sprintf("%v/%v-%v-%v.passwd", a.authDirectory, ing.GetNamespace(), ing.UID, secret.UID)
|
||||||
|
|
||||||
|
@ -156,7 +217,7 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, ing_errors.LocationDenied{
|
return nil, ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("invalid auth-secret-type in annotation, must be 'auth-file' or 'auth-map': %w", err),
|
Reason: fmt.Errorf("invalid auth-secret-type in annotation, must be 'auth-file' or 'auth-map': %w", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,14 +238,14 @@ func (a auth) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func dumpSecretAuthFile(filename string, secret *api.Secret) error {
|
func dumpSecretAuthFile(filename string, secret *api.Secret) error {
|
||||||
val, ok := secret.Data["auth"]
|
val, ok := secret.Data["auth"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ing_errors.LocationDenied{
|
return ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("the secret %s does not contain a key with value auth", secret.Name),
|
Reason: fmt.Errorf("the secret %s does not contain a key with value auth", secret.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := os.WriteFile(filename, val, file.ReadWriteByUser)
|
err := os.WriteFile(filename, val, file.ReadWriteByUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ing_errors.LocationDenied{
|
return ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,10 +264,19 @@ func dumpSecretAuthMap(filename string, secret *api.Secret) error {
|
||||||
|
|
||||||
err := os.WriteFile(filename, []byte(builder.String()), file.ReadWriteByUser)
|
err := os.WriteFile(filename, []byte(builder.String()), file.ReadWriteByUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ing_errors.LocationDenied{
|
return ing_errors.LocationDeniedError{
|
||||||
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
Reason: fmt.Errorf("unexpected error creating password file: %w", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a auth) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a auth) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authSecretAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -26,11 +26,21 @@ import (
|
||||||
api "k8s.io/api/core/v1"
|
api "k8s.io/api/core/v1"
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:gosec // Ignore hardcoded credentials error in testing
|
||||||
|
const (
|
||||||
|
authType = "basic"
|
||||||
|
authRealm = "-realm-"
|
||||||
|
defaultDemoSecret = "default/demo-secret"
|
||||||
|
othernsDemoSecret = "otherns/demo-secret"
|
||||||
|
demoSecret = "demo-secret"
|
||||||
|
)
|
||||||
|
|
||||||
func buildIngress() *networking.Ingress {
|
func buildIngress() *networking.Ingress {
|
||||||
defaultBackend := networking.IngressBackend{
|
defaultBackend := networking.IngressBackend{
|
||||||
Service: &networking.IngressServiceBackend{
|
Service: &networking.IngressServiceBackend{
|
||||||
|
@ -79,14 +89,19 @@ type mockSecret struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
|
func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
|
||||||
if name != "default/demo-secret" {
|
if name != defaultDemoSecret && name != othernsDemoSecret {
|
||||||
return nil, fmt.Errorf("there is no secret with name %v", name)
|
return nil, fmt.Errorf("there is no secret with name %v", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns, _, err := cache.SplitMetaNamespaceKey(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &api.Secret{
|
return &api.Secret{
|
||||||
ObjectMeta: meta_v1.ObjectMeta{
|
ObjectMeta: meta_v1.ObjectMeta{
|
||||||
Namespace: api.NamespaceDefault,
|
Namespace: ns,
|
||||||
Name: "demo-secret",
|
Name: demoSecret,
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
|
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -106,13 +121,91 @@ func TestIngressAuthBadAuthType(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("auth-type")] = "invalid"
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = "invalid"
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
_, dir, _ := dummySecretContent(t)
|
_, dir, _ := dummySecretContent(t)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
expected := ing_errors.NewLocationDenied("invalid authentication type")
|
expected := ing_errors.NewValidationError("nginx.ingress.kubernetes.io/auth-type")
|
||||||
|
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||||
|
if err.Error() != expected.Error() {
|
||||||
|
t.Errorf("expected '%v' but got '%v'", expected, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIngressInvalidRealm(t *testing.T) {
|
||||||
|
ing := buildIngress()
|
||||||
|
|
||||||
|
data := map[string]string{}
|
||||||
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
|
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = "something weird ; location trying to { break }"
|
||||||
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
expected := ing_errors.NewValidationError("nginx.ingress.kubernetes.io/auth-realm")
|
||||||
|
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||||
|
if err.Error() != expected.Error() {
|
||||||
|
t.Errorf("expected '%v' but got '%v'", expected, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIngressInvalidDifferentNamespace(t *testing.T) {
|
||||||
|
ing := buildIngress()
|
||||||
|
|
||||||
|
data := map[string]string{}
|
||||||
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
expected := ing_errors.LocationDeniedError{
|
||||||
|
Reason: errors.New("cross namespace usage of secrets is not allowed"),
|
||||||
|
}
|
||||||
|
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||||
|
if err.Error() != expected.Error() {
|
||||||
|
t.Errorf("expected '%v' but got '%v'", expected, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIngressInvalidDifferentNamespaceAllowed(t *testing.T) {
|
||||||
|
ing := buildIngress()
|
||||||
|
|
||||||
|
data := map[string]string{}
|
||||||
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = othernsDemoSecret
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
r := mockSecret{}
|
||||||
|
r.AllowCrossNamespace = true
|
||||||
|
_, err := NewParser(dir, r).Parse(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("not expecting an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIngressInvalidSecretName(t *testing.T) {
|
||||||
|
ing := buildIngress()
|
||||||
|
|
||||||
|
data := map[string]string{}
|
||||||
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "demo-secret;xpto"
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
expected := ing_errors.LocationDeniedError{
|
||||||
|
Reason: errors.New("error reading secret name from annotation: annotation nginx.ingress.kubernetes.io/auth-secret contains invalid value"),
|
||||||
|
}
|
||||||
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||||
if err.Error() != expected.Error() {
|
if err.Error() != expected.Error() {
|
||||||
t.Errorf("expected '%v' but got '%v'", expected, err)
|
t.Errorf("expected '%v' but got '%v'", expected, err)
|
||||||
|
@ -123,13 +216,13 @@ func TestInvalidIngressAuthNoSecret(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
_, dir, _ := dummySecretContent(t)
|
_, dir, _ := dummySecretContent(t)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
expected := ing_errors.LocationDenied{
|
expected := ing_errors.LocationDeniedError{
|
||||||
Reason: errors.New("error reading secret name from annotation: ingress rule without annotations"),
|
Reason: errors.New("error reading secret name from annotation: ingress rule without annotations"),
|
||||||
}
|
}
|
||||||
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
_, err := NewParser(dir, &mockSecret{}).Parse(ing)
|
||||||
|
@ -142,9 +235,9 @@ func TestIngressAuth(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret"
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||||
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
|
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
_, dir, _ := dummySecretContent(t)
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
@ -158,10 +251,10 @@ func TestIngressAuth(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected a BasicDigest type")
|
t.Errorf("expected a BasicDigest type")
|
||||||
}
|
}
|
||||||
if auth.Type != "basic" {
|
if auth.Type != authType {
|
||||||
t.Errorf("Expected basic as auth type but returned %s", auth.Type)
|
t.Errorf("Expected basic as auth type but returned %s", auth.Type)
|
||||||
}
|
}
|
||||||
if auth.Realm != "-realm-" {
|
if auth.Realm != authRealm {
|
||||||
t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
|
t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
|
||||||
}
|
}
|
||||||
if !auth.Secured {
|
if !auth.Secured {
|
||||||
|
@ -173,9 +266,9 @@ func TestIngressAuthWithoutSecret(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
data[parser.GetAnnotationWithPrefix("auth-secret")] = "invalid-secret"
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = "invalid-secret"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
|
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
_, dir, _ := dummySecretContent(t)
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
@ -191,10 +284,10 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("auth-type")] = "basic"
|
data[parser.GetAnnotationWithPrefix(authTypeAnnotation)] = authType
|
||||||
data[parser.GetAnnotationWithPrefix("auth-secret")] = "demo-secret"
|
data[parser.GetAnnotationWithPrefix(AuthSecretAnnotation)] = demoSecret
|
||||||
data[parser.GetAnnotationWithPrefix("auth-secret-type")] = "invalid-type"
|
data[parser.GetAnnotationWithPrefix(authSecretTypeAnnotation)] = "invalid-type"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-realm")] = "-realm-"
|
data[parser.GetAnnotationWithPrefix(authRealmAnnotation)] = authRealm
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
_, dir, _ := dummySecretContent(t)
|
_, dir, _ := dummySecretContent(t)
|
||||||
|
@ -206,7 +299,7 @@ func TestIngressAuthInvalidSecretKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
|
func dummySecretContent(t *testing.T) (fileName, dir string, s *api.Secret) {
|
||||||
dir, err := os.MkdirTemp("", fmt.Sprintf("%v", time.Now().Unix()))
|
dir, err := os.MkdirTemp("", fmt.Sprintf("%v", time.Now().Unix()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -217,7 +310,10 @@ func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
defer tmpfile.Close()
|
defer tmpfile.Close()
|
||||||
s, _ := mockSecret{}.GetSecret("default/demo-secret")
|
s, err = mockSecret{}.GetSecret(defaultDemoSecret)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
return tmpfile.Name(), dir, s
|
return tmpfile.Name(), dir, s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
|
@ -31,6 +32,125 @@ import (
|
||||||
"k8s.io/ingress-nginx/pkg/util/sets"
|
"k8s.io/ingress-nginx/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authReqURLAnnotation = "auth-url"
|
||||||
|
authReqMethodAnnotation = "auth-method"
|
||||||
|
authReqSigninAnnotation = "auth-signin"
|
||||||
|
authReqSigninRedirParamAnnotation = "auth-signin-redirect-param"
|
||||||
|
authReqSnippetAnnotation = "auth-snippet"
|
||||||
|
authReqCacheKeyAnnotation = "auth-cache-key"
|
||||||
|
authReqKeepaliveAnnotation = "auth-keepalive"
|
||||||
|
authReqKeepaliveShareVarsAnnotation = "auth-keepalive-share-vars"
|
||||||
|
authReqKeepaliveRequestsAnnotation = "auth-keepalive-requests"
|
||||||
|
authReqKeepaliveTimeout = "auth-keepalive-timeout"
|
||||||
|
authReqCacheDuration = "auth-cache-duration"
|
||||||
|
authReqResponseHeadersAnnotation = "auth-response-headers"
|
||||||
|
authReqProxySetHeadersAnnotation = "auth-proxy-set-headers"
|
||||||
|
authReqRequestRedirectAnnotation = "auth-request-redirect"
|
||||||
|
authReqAlwaysSetCookieAnnotation = "auth-always-set-cookie"
|
||||||
|
|
||||||
|
// This should be exported as it is imported by other packages
|
||||||
|
AuthSecretAnnotation = "auth-secret"
|
||||||
|
)
|
||||||
|
|
||||||
|
var authReqAnnotations = parser.Annotation{
|
||||||
|
Group: "authentication",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
authReqURLAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskHigh,
|
||||||
|
Documentation: `This annotation allows to indicate the URL where the HTTP request should be sent`,
|
||||||
|
},
|
||||||
|
authReqMethodAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(methodsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation allows to specify the HTTP method to use`,
|
||||||
|
},
|
||||||
|
authReqSigninAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskHigh,
|
||||||
|
Documentation: `This annotation allows to specify the location of the error page`,
|
||||||
|
},
|
||||||
|
authReqSigninRedirParamAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation allows to specify the URL parameter in the error page which should contain the original URL for a failed signin request`,
|
||||||
|
},
|
||||||
|
authReqSnippetAnnotation: {
|
||||||
|
Validator: parser.ValidateNull,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskCritical,
|
||||||
|
Documentation: `This annotation allows to specify a custom snippet to use with external authentication`,
|
||||||
|
},
|
||||||
|
authReqCacheKeyAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.NGINXVariable, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation enables caching for auth requests.`,
|
||||||
|
},
|
||||||
|
authReqKeepaliveAnnotation: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation specifies the maximum number of keepalive connections to auth-url. Only takes effect when no variables are used in the host part of the URL`,
|
||||||
|
},
|
||||||
|
authReqKeepaliveShareVarsAnnotation: {
|
||||||
|
Validator: parser.ValidateBool,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation specifies whether to share Nginx variables among the current request and the auth request`,
|
||||||
|
},
|
||||||
|
authReqKeepaliveRequestsAnnotation: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation defines the maximum number of requests that can be served through one keepalive connection`,
|
||||||
|
},
|
||||||
|
authReqKeepaliveTimeout: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation specifies a duration in seconds which an idle keepalive connection to an upstream server will stay open`,
|
||||||
|
},
|
||||||
|
authReqCacheDuration: {
|
||||||
|
Validator: parser.ValidateRegex(parser.ExtendedCharsRegex, false),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation allows to specify a caching time for auth responses based on their response codes, e.g. 200 202 30m`,
|
||||||
|
},
|
||||||
|
authReqResponseHeadersAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.HeadersVariable, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation sets the headers to pass to backend once authentication request completes. They should be separated by comma.`,
|
||||||
|
},
|
||||||
|
authReqProxySetHeadersAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation sets the name of a ConfigMap that specifies headers to pass to the authentication service.
|
||||||
|
Only ConfigMaps on the same namespace are allowed`,
|
||||||
|
},
|
||||||
|
authReqRequestRedirectAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.URLIsValidRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation allows to specify the X-Auth-Request-Redirect header value`,
|
||||||
|
},
|
||||||
|
authReqAlwaysSetCookieAnnotation: {
|
||||||
|
Validator: parser.ValidateBool,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation enables setting a cookie returned by auth request.
|
||||||
|
By default, the cookie will be set only if an upstream reports with the code 200, 201, 204, 206, 301, 302, 303, 304, 307, or 308`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Config returns external authentication configuration for an Ingress rule
|
// Config returns external authentication configuration for an Ingress rule
|
||||||
type Config struct {
|
type Config struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
@ -45,6 +165,7 @@ type Config struct {
|
||||||
AuthCacheKey string `json:"authCacheKey"`
|
AuthCacheKey string `json:"authCacheKey"`
|
||||||
AuthCacheDuration []string `json:"authCacheDuration"`
|
AuthCacheDuration []string `json:"authCacheDuration"`
|
||||||
KeepaliveConnections int `json:"keepaliveConnections"`
|
KeepaliveConnections int `json:"keepaliveConnections"`
|
||||||
|
KeepaliveShareVars bool `json:"keepaliveShareVars"`
|
||||||
KeepaliveRequests int `json:"keepaliveRequests"`
|
KeepaliveRequests int `json:"keepaliveRequests"`
|
||||||
KeepaliveTimeout int `json:"keepaliveTimeout"`
|
KeepaliveTimeout int `json:"keepaliveTimeout"`
|
||||||
ProxySetHeaders map[string]string `json:"proxySetHeaders,omitempty"`
|
ProxySetHeaders map[string]string `json:"proxySetHeaders,omitempty"`
|
||||||
|
@ -57,6 +178,7 @@ const DefaultCacheDuration = "200 202 401 5m"
|
||||||
// fallback values when no keepalive parameters are set
|
// fallback values when no keepalive parameters are set
|
||||||
const (
|
const (
|
||||||
defaultKeepaliveConnections = 0
|
defaultKeepaliveConnections = 0
|
||||||
|
defaultKeepaliveShareVars = false
|
||||||
defaultKeepaliveRequests = 1000
|
defaultKeepaliveRequests = 1000
|
||||||
defaultKeepaliveTimeout = 60
|
defaultKeepaliveTimeout = 60
|
||||||
)
|
)
|
||||||
|
@ -105,6 +227,10 @@ func (e1 *Config) Equal(e2 *Config) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e1.KeepaliveShareVars != e2.KeepaliveShareVars {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if e1.KeepaliveRequests != e2.KeepaliveRequests {
|
if e1.KeepaliveRequests != e2.KeepaliveRequests {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -121,24 +247,15 @@ func (e1 *Config) Equal(e2 *Config) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
methods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "CONNECT", "OPTIONS", "TRACE"}
|
methodsRegex = regexp.MustCompile("(GET|HEAD|POST|PUT|PATCH|DELETE|CONNECT|OPTIONS|TRACE)")
|
||||||
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
|
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
|
||||||
statusCodeRegex = regexp.MustCompile(`^[\d]{3}$`)
|
statusCodeRegex = regexp.MustCompile(`^\d{3}$`)
|
||||||
durationRegex = regexp.MustCompile(`^[\d]+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
|
durationRegex = regexp.MustCompile(`^\d+(ms|s|m|h|d|w|M|y)$`) // see http://nginx.org/en/docs/syntax.html
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidMethod checks is the provided string a valid HTTP method
|
// ValidMethod checks is the provided string a valid HTTP method
|
||||||
func ValidMethod(method string) bool {
|
func ValidMethod(method string) bool {
|
||||||
if len(method) == 0 {
|
return methodsRegex.MatchString(method)
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range methods {
|
|
||||||
if method == m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidHeader checks is the provided string satisfies the header's name regex
|
// ValidHeader checks is the provided string satisfies the header's name regex
|
||||||
|
@ -156,7 +273,7 @@ func ValidCacheDuration(duration string) bool {
|
||||||
seenDuration := false
|
seenDuration := false
|
||||||
|
|
||||||
for _, element := range elements {
|
for _, element := range elements {
|
||||||
if len(element) == 0 {
|
if element == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if statusCodeRegex.MatchString(element) {
|
if statusCodeRegex.MatchString(element) {
|
||||||
|
@ -173,55 +290,72 @@ func ValidCacheDuration(duration string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type authReq struct {
|
type authReq struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new authentication request annotation parser
|
// NewParser creates a new authentication request annotation parser
|
||||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return authReq{r}
|
return authReq{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: authReqAnnotations,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAnnotations parses the annotations contained in the ingress
|
// ParseAnnotations parses the annotations contained in the ingress
|
||||||
// rule used to use an Config URL as source for authentication
|
// rule used to use an Config URL as source for authentication
|
||||||
|
//
|
||||||
|
//nolint:gocyclo // Ignore function complexity error
|
||||||
func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
// Required Parameters
|
// Required Parameters
|
||||||
urlString, err := parser.GetStringAnnotation("auth-url", ing)
|
urlString, err := parser.GetStringAnnotation(authReqURLAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
authURL, err := parser.StringToURL(urlString)
|
authURL, err := parser.StringToURL(urlString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ing_errors.LocationDenied{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
|
return nil, ing_errors.LocationDeniedError{Reason: fmt.Errorf("could not parse auth-url annotation: %v", err)}
|
||||||
}
|
}
|
||||||
|
|
||||||
authMethod, _ := parser.GetStringAnnotation("auth-method", ing)
|
authMethod, err := parser.GetStringAnnotation(authReqMethodAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if len(authMethod) != 0 && !ValidMethod(authMethod) {
|
if err != nil {
|
||||||
return nil, ing_errors.NewLocationDenied("invalid HTTP method")
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return nil, ing_errors.NewLocationDenied("invalid HTTP method")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional Parameters
|
// Optional Parameters
|
||||||
signIn, err := parser.GetStringAnnotation("auth-signin", ing)
|
signIn, err := parser.GetStringAnnotation(authReqSigninAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s value is invalid: %s", authReqSigninAnnotation, err)
|
||||||
|
}
|
||||||
klog.V(3).InfoS("auth-signin annotation is undefined and will not be set")
|
klog.V(3).InfoS("auth-signin annotation is undefined and will not be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
signInRedirectParam, err := parser.GetStringAnnotation("auth-signin-redirect-param", ing)
|
signInRedirectParam, err := parser.GetStringAnnotation(authReqSigninRedirParamAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s value is invalid: %s", authReqSigninRedirParamAnnotation, err)
|
||||||
|
}
|
||||||
klog.V(3).Infof("auth-signin-redirect-param annotation is undefined and will not be set")
|
klog.V(3).Infof("auth-signin-redirect-param annotation is undefined and will not be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
authSnippet, err := parser.GetStringAnnotation("auth-snippet", ing)
|
authSnippet, err := parser.GetStringAnnotation(authReqSnippetAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).InfoS("auth-snippet annotation is undefined and will not be set")
|
klog.V(3).InfoS("auth-snippet annotation is undefined and will not be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
authCacheKey, err := parser.GetStringAnnotation("auth-cache-key", ing)
|
authCacheKey, err := parser.GetStringAnnotation(authReqCacheKeyAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s value is invalid: %s", authReqCacheKeyAnnotation, err)
|
||||||
|
}
|
||||||
klog.V(3).InfoS("auth-cache-key annotation is undefined and will not be set")
|
klog.V(3).InfoS("auth-cache-key annotation is undefined and will not be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
keepaliveConnections, err := parser.GetIntAnnotation("auth-keepalive", ing)
|
keepaliveConnections, err := parser.GetIntAnnotation(authReqKeepaliveAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).InfoS("auth-keepalive annotation is undefined and will be set to its default value")
|
klog.V(3).InfoS("auth-keepalive annotation is undefined and will be set to its default value")
|
||||||
keepaliveConnections = defaultKeepaliveConnections
|
keepaliveConnections = defaultKeepaliveConnections
|
||||||
|
@ -238,9 +372,15 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keepaliveRequests, err := parser.GetIntAnnotation("auth-keepalive-requests", ing)
|
keepaliveShareVars, err := parser.GetBoolAnnotation(authReqKeepaliveShareVarsAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).InfoS("auth-keepalive-requests annotation is undefined and will be set to its default value")
|
klog.V(3).InfoS("auth-keepalive-share-vars annotation is undefined and will be set to its default value")
|
||||||
|
keepaliveShareVars = defaultKeepaliveShareVars
|
||||||
|
}
|
||||||
|
|
||||||
|
keepaliveRequests, err := parser.GetIntAnnotation(authReqKeepaliveRequestsAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
|
if err != nil {
|
||||||
|
klog.V(3).InfoS("auth-keepalive-requests annotation is undefined or invalid and will be set to its default value")
|
||||||
keepaliveRequests = defaultKeepaliveRequests
|
keepaliveRequests = defaultKeepaliveRequests
|
||||||
}
|
}
|
||||||
if keepaliveRequests <= 0 {
|
if keepaliveRequests <= 0 {
|
||||||
|
@ -248,7 +388,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
keepaliveConnections = 0
|
keepaliveConnections = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
keepaliveTimeout, err := parser.GetIntAnnotation("auth-keepalive-timeout", ing)
|
keepaliveTimeout, err := parser.GetIntAnnotation(authReqKeepaliveTimeout, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).InfoS("auth-keepalive-timeout annotation is undefined and will be set to its default value")
|
klog.V(3).InfoS("auth-keepalive-timeout annotation is undefined and will be set to its default value")
|
||||||
keepaliveTimeout = defaultKeepaliveTimeout
|
keepaliveTimeout = defaultKeepaliveTimeout
|
||||||
|
@ -258,15 +398,21 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
keepaliveConnections = 0
|
keepaliveConnections = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
durstr, _ := parser.GetStringAnnotation("auth-cache-duration", ing)
|
durstr, err := parser.GetStringAnnotation(authReqCacheDuration, ing, a.annotationConfig.Annotations)
|
||||||
|
if err != nil && ing_errors.IsValidationError(err) {
|
||||||
|
return nil, fmt.Errorf("%s contains invalid value", authReqCacheDuration)
|
||||||
|
}
|
||||||
authCacheDuration, err := ParseStringToCacheDurations(durstr)
|
authCacheDuration, err := ParseStringToCacheDurations(durstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
responseHeaders := []string{}
|
responseHeaders := []string{}
|
||||||
hstr, _ := parser.GetStringAnnotation("auth-response-headers", ing)
|
hstr, err := parser.GetStringAnnotation(authReqResponseHeadersAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if len(hstr) != 0 {
|
if err != nil && ing_errors.IsValidationError(err) {
|
||||||
|
return nil, ing_errors.NewLocationDenied("validation error")
|
||||||
|
}
|
||||||
|
if hstr != "" {
|
||||||
harr := strings.Split(hstr, ",")
|
harr := strings.Split(hstr, ",")
|
||||||
for _, header := range harr {
|
for _, header := range harr {
|
||||||
header = strings.TrimSpace(header)
|
header = strings.TrimSpace(header)
|
||||||
|
@ -279,9 +425,28 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxySetHeaderMap, err := parser.GetStringAnnotation("auth-proxy-set-headers", ing)
|
proxySetHeaderMap, err := parser.GetStringAnnotation(authReqProxySetHeadersAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).InfoS("auth-set-proxy-headers annotation is undefined and will not be set")
|
klog.V(3).InfoS("auth-set-proxy-headers annotation is undefined and will not be set", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cns, _, err := cache.SplitMetaNamespaceKey(proxySetHeaderMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ing_errors.LocationDeniedError{
|
||||||
|
Reason: fmt.Errorf("error reading configmap name %s from annotation: %w", proxySetHeaderMap, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cns == "" {
|
||||||
|
cns = ing.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
secCfg := a.r.GetSecurityConfiguration()
|
||||||
|
// We don't accept different namespaces for secrets.
|
||||||
|
if !secCfg.AllowCrossNamespaceResources && cns != ing.Namespace {
|
||||||
|
return nil, ing_errors.LocationDeniedError{
|
||||||
|
Reason: fmt.Errorf("cross namespace usage of secrets is not allowed"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var proxySetHeaders map[string]string
|
var proxySetHeaders map[string]string
|
||||||
|
@ -301,9 +466,15 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
proxySetHeaders = proxySetHeadersMapContents.Data
|
proxySetHeaders = proxySetHeadersMapContents.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
requestRedirect, _ := parser.GetStringAnnotation("auth-request-redirect", ing)
|
requestRedirect, err := parser.GetStringAnnotation(authReqRequestRedirectAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
|
if err != nil && ing_errors.IsValidationError(err) {
|
||||||
|
return nil, fmt.Errorf("%s is invalid: %w", authReqRequestRedirectAnnotation, err)
|
||||||
|
}
|
||||||
|
|
||||||
alwaysSetCookie, _ := parser.GetBoolAnnotation("auth-always-set-cookie", ing)
|
alwaysSetCookie, err := parser.GetBoolAnnotation(authReqAlwaysSetCookieAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
|
if err != nil && ing_errors.IsValidationError(err) {
|
||||||
|
return nil, fmt.Errorf("%s is invalid: %w", authReqAlwaysSetCookieAnnotation, err)
|
||||||
|
}
|
||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
URL: urlString,
|
URL: urlString,
|
||||||
|
@ -317,6 +488,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
AuthCacheKey: authCacheKey,
|
AuthCacheKey: authCacheKey,
|
||||||
AuthCacheDuration: authCacheDuration,
|
AuthCacheDuration: authCacheDuration,
|
||||||
KeepaliveConnections: keepaliveConnections,
|
KeepaliveConnections: keepaliveConnections,
|
||||||
|
KeepaliveShareVars: keepaliveShareVars,
|
||||||
KeepaliveRequests: keepaliveRequests,
|
KeepaliveRequests: keepaliveRequests,
|
||||||
KeepaliveTimeout: keepaliveTimeout,
|
KeepaliveTimeout: keepaliveTimeout,
|
||||||
ProxySetHeaders: proxySetHeaders,
|
ProxySetHeaders: proxySetHeaders,
|
||||||
|
@ -329,7 +501,7 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
// It will always return at least one duration (the default duration)
|
// It will always return at least one duration (the default duration)
|
||||||
func ParseStringToCacheDurations(input string) ([]string, error) {
|
func ParseStringToCacheDurations(input string) ([]string, error) {
|
||||||
authCacheDuration := []string{}
|
authCacheDuration := []string{}
|
||||||
if len(input) != 0 {
|
if input != "" {
|
||||||
arr := strings.Split(input, ",")
|
arr := strings.Split(input, ",")
|
||||||
for _, duration := range arr {
|
for _, duration := range arr {
|
||||||
duration = strings.TrimSpace(duration)
|
duration = strings.TrimSpace(duration)
|
||||||
|
@ -348,3 +520,12 @@ func ParseStringToCacheDurations(input string) ([]string, error) {
|
||||||
}
|
}
|
||||||
return authCacheDuration, nil
|
return authCacheDuration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authReq) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a authReq) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authReqAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package authreq
|
package authreq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -113,7 +112,7 @@ func TestAnnotations(t *testing.T) {
|
||||||
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
||||||
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
|
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
|
||||||
data[parser.GetAnnotationWithPrefix("auth-signin-redirect-param")] = test.signinURLRedirectParam
|
data[parser.GetAnnotationWithPrefix("auth-signin-redirect-param")] = test.signinURLRedirectParam
|
||||||
data[parser.GetAnnotationWithPrefix("auth-method")] = fmt.Sprintf("%v", test.method)
|
data[parser.GetAnnotationWithPrefix("auth-method")] = test.method
|
||||||
data[parser.GetAnnotationWithPrefix("auth-request-redirect")] = test.requestRedirect
|
data[parser.GetAnnotationWithPrefix("auth-request-redirect")] = test.requestRedirect
|
||||||
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet
|
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet
|
||||||
data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey
|
data[parser.GetAnnotationWithPrefix("auth-cache-key")] = test.authCacheKey
|
||||||
|
@ -192,11 +191,13 @@ func TestHeaderAnnotations(t *testing.T) {
|
||||||
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||||
if test.expErr {
|
if test.expErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error but retuned nil")
|
t.Errorf("%v expected error but retuned nil", test.title)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("no error was expected but %v happened in %s", err, test.title)
|
||||||
|
}
|
||||||
u, ok := i.(*Config)
|
u, ok := i.(*Config)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("%v: expected an External type", test.title)
|
t.Errorf("%v: expected an External type", test.title)
|
||||||
|
@ -266,28 +267,31 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
||||||
title string
|
title string
|
||||||
url string
|
url string
|
||||||
keepaliveConnections string
|
keepaliveConnections string
|
||||||
|
keepaliveShareVars string
|
||||||
keepaliveRequests string
|
keepaliveRequests string
|
||||||
keepaliveTimeout string
|
keepaliveTimeout string
|
||||||
expectedConnections int
|
expectedConnections int
|
||||||
|
expectedShareVars bool
|
||||||
expectedRequests int
|
expectedRequests int
|
||||||
expectedTimeout int
|
expectedTimeout int
|
||||||
}{
|
}{
|
||||||
{"all set", "http://goog.url", "5", "500", "50", 5, 500, 50},
|
{"all set", "http://goog.url", "5", "false", "500", "50", 5, false, 500, 50},
|
||||||
{"no annotation", "http://goog.url", "", "", "", defaultKeepaliveConnections, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
{"no annotation", "http://goog.url", "", "", "", "", defaultKeepaliveConnections, defaultKeepaliveShareVars, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||||
{"default for connections", "http://goog.url", "x", "500", "50", defaultKeepaliveConnections, 500, 50},
|
{"default for connections", "http://goog.url", "x", "true", "500", "50", defaultKeepaliveConnections, true, 500, 50},
|
||||||
{"default for requests", "http://goog.url", "5", "x", "50", 5, defaultKeepaliveRequests, 50},
|
{"default for requests", "http://goog.url", "5", "x", "dummy", "50", 5, defaultKeepaliveShareVars, defaultKeepaliveRequests, 50},
|
||||||
{"default for invalid timeout", "http://goog.url", "5", "500", "x", 5, 500, defaultKeepaliveTimeout},
|
{"default for invalid timeout", "http://goog.url", "5", "t", "500", "x", 5, true, 500, defaultKeepaliveTimeout},
|
||||||
{"variable in host", "http://$host:5000/a/b", "5", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
{"variable in host", "http://$host:5000/a/b", "5", "1", "", "", 0, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||||
{"variable in path", "http://goog.url:5000/$path", "5", "", "", 5, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
{"variable in path", "http://goog.url:5000/$path", "5", "t", "", "", 5, true, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||||
{"negative connections", "http://goog.url", "-2", "", "", 0, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
{"negative connections", "http://goog.url", "-2", "f", "", "", 0, false, defaultKeepaliveRequests, defaultKeepaliveTimeout},
|
||||||
{"negative requests", "http://goog.url", "5", "-1", "", 0, -1, defaultKeepaliveTimeout},
|
{"negative requests", "http://goog.url", "5", "True", "-1", "", 0, true, -1, defaultKeepaliveTimeout},
|
||||||
{"negative timeout", "http://goog.url", "5", "", "-1", 0, defaultKeepaliveRequests, -1},
|
{"negative timeout", "http://goog.url", "5", "0", "", "-1", 0, false, defaultKeepaliveRequests, -1},
|
||||||
{"negative request and timeout", "http://goog.url", "5", "-2", "-3", 0, -2, -3},
|
{"negative request and timeout", "http://goog.url", "5", "False", "-2", "-3", 0, false, -2, -3},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
|
||||||
data[parser.GetAnnotationWithPrefix("auth-keepalive")] = test.keepaliveConnections
|
data[parser.GetAnnotationWithPrefix("auth-keepalive")] = test.keepaliveConnections
|
||||||
|
data[parser.GetAnnotationWithPrefix("auth-keepalive-share-vars")] = test.keepaliveShareVars
|
||||||
data[parser.GetAnnotationWithPrefix("auth-keepalive-timeout")] = test.keepaliveTimeout
|
data[parser.GetAnnotationWithPrefix("auth-keepalive-timeout")] = test.keepaliveTimeout
|
||||||
data[parser.GetAnnotationWithPrefix("auth-keepalive-requests")] = test.keepaliveRequests
|
data[parser.GetAnnotationWithPrefix("auth-keepalive-requests")] = test.keepaliveRequests
|
||||||
|
|
||||||
|
@ -311,6 +315,10 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
||||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedConnections, u.KeepaliveConnections)
|
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedConnections, u.KeepaliveConnections)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.KeepaliveShareVars != test.expectedShareVars {
|
||||||
|
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedShareVars, u.KeepaliveShareVars)
|
||||||
|
}
|
||||||
|
|
||||||
if u.KeepaliveRequests != test.expectedRequests {
|
if u.KeepaliveRequests != test.expectedRequests {
|
||||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedRequests, u.KeepaliveRequests)
|
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.expectedRequests, u.KeepaliveRequests)
|
||||||
}
|
}
|
||||||
|
@ -322,7 +330,6 @@ func TestKeepaliveAnnotations(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseStringToCacheDurations(t *testing.T) {
|
func TestParseStringToCacheDurations(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
title string
|
title string
|
||||||
duration string
|
duration string
|
||||||
|
@ -337,7 +344,6 @@ func TestParseStringToCacheDurations(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
||||||
dur, err := ParseStringToCacheDurations(test.duration)
|
dur, err := ParseStringToCacheDurations(test.duration)
|
||||||
if test.expErr {
|
if test.expErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -23,23 +23,51 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
enableGlobalAuthAnnotation = "enable-global-auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var globalAuthAnnotations = parser.Annotation{
|
||||||
|
Group: "authentication",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
enableGlobalAuthAnnotation: {
|
||||||
|
Validator: parser.ValidateBool,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `Defines if the global external authentication should be enabled.`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type authReqGlobal struct {
|
type authReqGlobal struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new authentication request annotation parser
|
// NewParser creates a new authentication request annotation parser
|
||||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return authReqGlobal{r}
|
return authReqGlobal{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: globalAuthAnnotations,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAnnotations parses the annotations contained in the ingress
|
// ParseAnnotations parses the annotations contained in the ingress
|
||||||
// rule used to enable or disable global external authentication
|
// rule used to enable or disable global external authentication
|
||||||
func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
|
enableGlobalAuth, err := parser.GetBoolAnnotation(enableGlobalAuthAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
enableGlobalAuth, err := parser.GetBoolAnnotation("enable-global-auth", ing)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
enableGlobalAuth = true
|
enableGlobalAuth = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return enableGlobalAuth, nil
|
return enableGlobalAuth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authReqGlobal) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a authReqGlobal) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, globalAuthAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -77,7 +77,10 @@ func TestAnnotation(t *testing.T) {
|
||||||
data[parser.GetAnnotationWithPrefix("enable-global-auth")] = "false"
|
data[parser.GetAnnotationWithPrefix("enable-global-auth")] = "false"
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
i, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
u, ok := i.(bool)
|
u, ok := i.(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected a Config type")
|
t.Errorf("expected a Config type")
|
||||||
|
|
|
@ -18,11 +18,10 @@ package authtls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
|
@ -32,13 +31,64 @@ import (
|
||||||
const (
|
const (
|
||||||
defaultAuthTLSDepth = 1
|
defaultAuthTLSDepth = 1
|
||||||
defaultAuthVerifyClient = "on"
|
defaultAuthVerifyClient = "on"
|
||||||
|
|
||||||
|
annotationAuthTLSSecret = "auth-tls-secret" //#nosec G101
|
||||||
|
annotationAuthTLSVerifyClient = "auth-tls-verify-client"
|
||||||
|
annotationAuthTLSVerifyDepth = "auth-tls-verify-depth"
|
||||||
|
annotationAuthTLSErrorPage = "auth-tls-error-page"
|
||||||
|
annotationAuthTLSPassCertToUpstream = "auth-tls-pass-certificate-to-upstream" //#nosec G101
|
||||||
|
annotationAuthTLSMatchCN = "auth-tls-match-cn"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
regexChars = regexp.QuoteMeta(`()|=`)
|
||||||
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
|
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
|
||||||
commonNameRegex = regexp.MustCompile(`CN=`)
|
commonNameRegex = regexp.MustCompile(`^CN=[/\-.\_\~a-zA-Z0-9` + regexChars + `]*$`)
|
||||||
|
redirectRegex = regexp.MustCompile(`^((https?://)?[A-Za-z0-9\-.]*(:\d+)?/[A-Za-z0-9\-.]*)?$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var authTLSAnnotations = parser.Annotation{
|
||||||
|
Group: "authentication",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
annotationAuthTLSSecret: {
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
|
||||||
|
Documentation: `This annotation defines the secret that contains the certificate chain of allowed certs`,
|
||||||
|
},
|
||||||
|
annotationAuthTLSVerifyClient: {
|
||||||
|
Validator: parser.ValidateRegex(authVerifyClientRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskMedium, // Medium as it allows a subset of chars
|
||||||
|
Documentation: `This annotation enables verification of client certificates. Can be "on", "off", "optional" or "optional_no_ca"`,
|
||||||
|
},
|
||||||
|
annotationAuthTLSVerifyDepth: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation defines validation depth between the provided client certificate and the Certification Authority chain.`,
|
||||||
|
},
|
||||||
|
annotationAuthTLSErrorPage: {
|
||||||
|
Validator: parser.ValidateRegex(redirectRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskHigh,
|
||||||
|
Documentation: `This annotation defines the URL/Page that user should be redirected in case of a Certificate Authentication Error`,
|
||||||
|
},
|
||||||
|
annotationAuthTLSPassCertToUpstream: {
|
||||||
|
Validator: parser.ValidateBool,
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation defines if the received certificates should be passed or not to the upstream server in the header "ssl-client-cert"`,
|
||||||
|
},
|
||||||
|
annotationAuthTLSMatchCN: {
|
||||||
|
Validator: parser.ValidateRegex(commonNameRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskHigh,
|
||||||
|
Documentation: `This annotation adds a sanity check for the CN of the client certificate that is sent over using a string / regex starting with "CN="`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Config contains the AuthSSLCert used for mutual authentication
|
// Config contains the AuthSSLCert used for mutual authentication
|
||||||
// and the configured ValidationDepth
|
// and the configured ValidationDepth
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -79,12 +129,16 @@ func (assl1 *Config) Equal(assl2 *Config) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new TLS authentication annotation parser
|
// NewParser creates a new TLS authentication annotation parser
|
||||||
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return authTLS{resolver}
|
return authTLS{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: authTLSAnnotations,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type authTLS struct {
|
type authTLS struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
|
@ -93,47 +147,75 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
|
|
||||||
tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
|
tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Config{}, err
|
return &Config{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = k8s.ParseNameNS(tlsauthsecret)
|
ns, _, err := k8s.ParseNameNS(tlsauthsecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Config{}, ing_errors.NewLocationDenied(err.Error())
|
return &Config{}, ing_errors.NewLocationDenied(err.Error())
|
||||||
}
|
}
|
||||||
|
if ns == "" {
|
||||||
|
ns = ing.Namespace
|
||||||
|
}
|
||||||
|
secCfg := a.r.GetSecurityConfiguration()
|
||||||
|
// We don't accept different namespaces for secrets.
|
||||||
|
if !secCfg.AllowCrossNamespaceResources && ns != ing.Namespace {
|
||||||
|
return &Config{}, ing_errors.NewLocationDenied("cross namespace secrets are not supported")
|
||||||
|
}
|
||||||
|
|
||||||
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
|
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := fmt.Errorf("error obtaining certificate: %w", err)
|
e := fmt.Errorf("error obtaining certificate: %w", err)
|
||||||
return &Config{}, ing_errors.LocationDenied{Reason: e}
|
return &Config{}, ing_errors.LocationDeniedError{Reason: e}
|
||||||
}
|
}
|
||||||
config.AuthSSLCert = *authCert
|
config.AuthSSLCert = *authCert
|
||||||
|
|
||||||
config.VerifyClient, err = parser.GetStringAnnotation("auth-tls-verify-client", ing)
|
config.VerifyClient, err = parser.GetStringAnnotation(annotationAuthTLSVerifyClient, ing, a.annotationConfig.Annotations)
|
||||||
|
// We can set a default value here in case of validation error
|
||||||
if err != nil || !authVerifyClientRegex.MatchString(config.VerifyClient) {
|
if err != nil || !authVerifyClientRegex.MatchString(config.VerifyClient) {
|
||||||
config.VerifyClient = defaultAuthVerifyClient
|
config.VerifyClient = defaultAuthVerifyClient
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ValidationDepth, err = parser.GetIntAnnotation("auth-tls-verify-depth", ing)
|
config.ValidationDepth, err = parser.GetIntAnnotation(annotationAuthTLSVerifyDepth, ing, a.annotationConfig.Annotations)
|
||||||
|
// We can set a default value here in case of validation error
|
||||||
if err != nil || config.ValidationDepth == 0 {
|
if err != nil || config.ValidationDepth == 0 {
|
||||||
config.ValidationDepth = defaultAuthTLSDepth
|
config.ValidationDepth = defaultAuthTLSDepth
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ErrorPage, err = parser.GetStringAnnotation("auth-tls-error-page", ing)
|
config.ErrorPage, err = parser.GetStringAnnotation(annotationAuthTLSErrorPage, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return &Config{}, err
|
||||||
|
}
|
||||||
config.ErrorPage = ""
|
config.ErrorPage = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
config.PassCertToUpstream, err = parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
|
config.PassCertToUpstream, err = parser.GetBoolAnnotation(annotationAuthTLSPassCertToUpstream, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return &Config{}, err
|
||||||
|
}
|
||||||
config.PassCertToUpstream = false
|
config.PassCertToUpstream = false
|
||||||
}
|
}
|
||||||
|
|
||||||
config.MatchCN, err = parser.GetStringAnnotation("auth-tls-match-cn", ing)
|
config.MatchCN, err = parser.GetStringAnnotation(annotationAuthTLSMatchCN, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil || !commonNameRegex.MatchString(config.MatchCN) {
|
if err != nil {
|
||||||
|
if ing_errors.IsValidationError(err) {
|
||||||
|
return &Config{}, err
|
||||||
|
}
|
||||||
config.MatchCN = ""
|
config.MatchCN = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authTLS) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a authTLS) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authTLSAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,11 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultDemoSecret = "default/demo-secret"
|
||||||
|
off = "off"
|
||||||
|
)
|
||||||
|
|
||||||
func buildIngress() *networking.Ingress {
|
func buildIngress() *networking.Ingress {
|
||||||
defaultBackend := networking.IngressBackend{
|
defaultBackend := networking.IngressBackend{
|
||||||
Service: &networking.IngressServiceBackend{
|
Service: &networking.IngressServiceBackend{
|
||||||
|
@ -77,23 +82,22 @@ type mockSecret struct {
|
||||||
|
|
||||||
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS
|
// GetAuthCertificate from mockSecret mocks the GetAuthCertificate for authTLS
|
||||||
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||||
if name != "default/demo-secret" {
|
if name != defaultDemoSecret {
|
||||||
return nil, errors.Errorf("there is no secret with name %v", name)
|
return nil, errors.Errorf("there is no secret with name %v", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &resolver.AuthSSLCert{
|
return &resolver.AuthSSLCert{
|
||||||
Secret: "default/demo-secret",
|
Secret: defaultDemoSecret,
|
||||||
CAFileName: "/ssl/ca.crt",
|
CAFileName: "/ssl/ca.crt",
|
||||||
CASHA: "abc",
|
CASHA: "abc",
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAnnotations(t *testing.T) {
|
func TestAnnotations(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
|
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = defaultDemoSecret
|
||||||
|
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
@ -108,7 +112,7 @@ func TestAnnotations(t *testing.T) {
|
||||||
t.Errorf("expected *Config but got %v", u)
|
t.Errorf("expected *Config but got %v", u)
|
||||||
}
|
}
|
||||||
|
|
||||||
secret, err := fakeSecret.GetAuthCertificate("default/demo-secret")
|
secret, err := fakeSecret.GetAuthCertificate(defaultDemoSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error getting secret %v", err)
|
t.Errorf("unexpected error getting secret %v", err)
|
||||||
}
|
}
|
||||||
|
@ -132,11 +136,11 @@ func TestAnnotations(t *testing.T) {
|
||||||
t.Errorf("expected empty string, but got %v", u.MatchCN)
|
t.Errorf("expected empty string, but got %v", u.MatchCN)
|
||||||
}
|
}
|
||||||
|
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "off"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = off
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "2"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "2"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-error-page")] = "ok.com/error"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSErrorPage)] = "ok.com/error"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "true"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "true"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "CN=hello-app"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "CN=(hello-app|ok|goodbye)"
|
||||||
|
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
@ -153,8 +157,8 @@ func TestAnnotations(t *testing.T) {
|
||||||
if u.AuthSSLCert.Secret != secret.Secret {
|
if u.AuthSSLCert.Secret != secret.Secret {
|
||||||
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
|
t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret)
|
||||||
}
|
}
|
||||||
if u.VerifyClient != "off" {
|
if u.VerifyClient != off {
|
||||||
t.Errorf("expected %v but got %v", "off", u.VerifyClient)
|
t.Errorf("expected %v but got %v", off, u.VerifyClient)
|
||||||
}
|
}
|
||||||
if u.ValidationDepth != 2 {
|
if u.ValidationDepth != 2 {
|
||||||
t.Errorf("expected %v but got %v", 2, u.ValidationDepth)
|
t.Errorf("expected %v but got %v", 2, u.ValidationDepth)
|
||||||
|
@ -165,8 +169,8 @@ func TestAnnotations(t *testing.T) {
|
||||||
if u.PassCertToUpstream != true {
|
if u.PassCertToUpstream != true {
|
||||||
t.Errorf("expected %v but got %v", true, u.PassCertToUpstream)
|
t.Errorf("expected %v but got %v", true, u.PassCertToUpstream)
|
||||||
}
|
}
|
||||||
if u.MatchCN != "CN=hello-app" {
|
if u.MatchCN != "CN=(hello-app|ok|goodbye)" {
|
||||||
t.Errorf("expected %v but got %v", "CN=hello-app", u.MatchCN)
|
t.Errorf("expected %v but got %v", "CN=(hello-app|ok|goodbye)", u.MatchCN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,15 +186,24 @@ func TestInvalidAnnotations(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid NameSpace
|
// Invalid NameSpace
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "demo-secret"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "demo-secret"
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
_, err = NewParser(fakeSecret).Parse(ing)
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error with ingress but got nil")
|
t.Errorf("Expected error with ingress but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalid Cross NameSpace
|
||||||
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "nondefault/demo-secret"
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
|
expErr := errors.NewLocationDenied("cross namespace secrets are not supported")
|
||||||
|
if err.Error() != expErr.Error() {
|
||||||
|
t.Errorf("received error is different from cross namespace error: %s Expected %s", err, expErr)
|
||||||
|
}
|
||||||
|
|
||||||
// Invalid Auth Certificate
|
// Invalid Auth Certificate
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/invalid-demo-secret"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/invalid-demo-secret"
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
_, err = NewParser(fakeSecret).Parse(ing)
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -198,11 +211,38 @@ func TestInvalidAnnotations(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid optional Annotations
|
// Invalid optional Annotations
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-secret")] = "default/demo-secret"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSSecret)] = "default/demo-secret"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-verify-client")] = "w00t"
|
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-verify-depth")] = "abcd"
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyClient)] = "w00t"
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-pass-certificate-to-upstream")] = "nahh"
|
ing.SetAnnotations(data)
|
||||||
data[parser.GetAnnotationWithPrefix("auth-tls-match-cn")] = "<script>nope</script>"
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error should be nil and verify client should be defaulted")
|
||||||
|
}
|
||||||
|
|
||||||
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "abcd"
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error should be nil and verify depth should be defaulted")
|
||||||
|
}
|
||||||
|
|
||||||
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "nahh"
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error with ingress but got nil")
|
||||||
|
}
|
||||||
|
delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream))
|
||||||
|
|
||||||
|
data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "<script>nope</script>"
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
_, err = NewParser(fakeSecret).Parse(ing)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error with ingress CN but got nil")
|
||||||
|
}
|
||||||
|
delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN))
|
||||||
|
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
i, err := NewParser(fakeSecret).Parse(ing)
|
i, err := NewParser(fakeSecret).Parse(ing)
|
||||||
|
@ -226,28 +266,21 @@ func TestInvalidAnnotations(t *testing.T) {
|
||||||
if u.MatchCN != "" {
|
if u.MatchCN != "" {
|
||||||
t.Errorf("expected empty string but got %v", u.MatchCN)
|
t.Errorf("expected empty string but got %v", u.MatchCN)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEquals(t *testing.T) {
|
func TestEquals(t *testing.T) {
|
||||||
cfg1 := &Config{}
|
cfg1 := &Config{}
|
||||||
cfg2 := &Config{}
|
cfg2 := &Config{}
|
||||||
|
|
||||||
// Same config
|
|
||||||
result := cfg1.Equal(cfg1)
|
|
||||||
if result != true {
|
|
||||||
t.Errorf("Expected true")
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare nil
|
// compare nil
|
||||||
result = cfg1.Equal(nil)
|
result := cfg1.Equal(nil)
|
||||||
if result != false {
|
if result != false {
|
||||||
t.Errorf("Expected false")
|
t.Errorf("Expected false")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Different Certs
|
// Different Certs
|
||||||
sslCert1 := resolver.AuthSSLCert{
|
sslCert1 := resolver.AuthSSLCert{
|
||||||
Secret: "default/demo-secret",
|
Secret: defaultDemoSecret,
|
||||||
CAFileName: "/ssl/ca.crt",
|
CAFileName: "/ssl/ca.crt",
|
||||||
CASHA: "abc",
|
CASHA: "abc",
|
||||||
}
|
}
|
||||||
|
@ -266,7 +299,7 @@ func TestEquals(t *testing.T) {
|
||||||
|
|
||||||
// Different Verify Client
|
// Different Verify Client
|
||||||
cfg1.VerifyClient = "on"
|
cfg1.VerifyClient = "on"
|
||||||
cfg2.VerifyClient = "off"
|
cfg2.VerifyClient = off
|
||||||
result = cfg1.Equal(cfg2)
|
result = cfg1.Equal(cfg2)
|
||||||
if result != false {
|
if result != false {
|
||||||
t.Errorf("Expected false")
|
t.Errorf("Expected false")
|
||||||
|
|
|
@ -17,49 +17,70 @@ limitations under the License.
|
||||||
package backendprotocol
|
package backendprotocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
|
"k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTP protocol
|
var validProtocols = []string{"auto_http", "http", "https", "grpc", "grpcs", "fcgi"}
|
||||||
const HTTP = "HTTP"
|
|
||||||
|
|
||||||
var (
|
const (
|
||||||
validProtocols = regexp.MustCompile(`^(AUTO_HTTP|HTTP|HTTPS|GRPC|GRPCS|FCGI)$`)
|
http = "HTTP"
|
||||||
|
backendProtocolAnnotation = "backend-protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var backendProtocolConfig = parser.Annotation{
|
||||||
|
Group: "backend",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
backendProtocolAnnotation: {
|
||||||
|
Validator: parser.ValidateOptions(validProtocols, false, true),
|
||||||
|
Scope: parser.AnnotationScopeLocation,
|
||||||
|
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
|
||||||
|
Documentation: `this annotation can be used to define which protocol should
|
||||||
|
be used to communicate with backends`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type backendProtocol struct {
|
type backendProtocol struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new backend protocol annotation parser
|
// NewParser creates a new backend protocol annotation parser
|
||||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return backendProtocol{r}
|
return backendProtocol{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: backendProtocolConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a backendProtocol) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAnnotations parses the annotations contained in the ingress
|
// ParseAnnotations parses the annotations contained in the ingress
|
||||||
// rule used to indicate the backend protocol.
|
// rule used to indicate the backend protocol.
|
||||||
func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
if ing.GetAnnotations() == nil {
|
if ing.GetAnnotations() == nil {
|
||||||
return HTTP, nil
|
return http, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
proto, err := parser.GetStringAnnotation("backend-protocol", ing)
|
proto, err := parser.GetStringAnnotation(backendProtocolAnnotation, ing, a.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return HTTP, nil
|
if errors.IsValidationError(err) {
|
||||||
}
|
klog.Warningf("validation error %s. Using HTTP as protocol", err)
|
||||||
|
}
|
||||||
proto = strings.TrimSpace(strings.ToUpper(proto))
|
return http, nil
|
||||||
if !validProtocols.MatchString(proto) {
|
|
||||||
klog.Warningf("Protocol %v is not a valid value for the backend-protocol annotation. Using HTTP as protocol", proto)
|
|
||||||
return HTTP, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return proto, nil
|
return proto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a backendProtocol) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, backendProtocolConfig.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ func buildIngress() *networking.Ingress {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseInvalidAnnotations(t *testing.T) {
|
func TestParseInvalidAnnotations(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected a string type")
|
t.Errorf("expected a string type")
|
||||||
}
|
}
|
||||||
if val != "HTTP" {
|
if val != http {
|
||||||
t.Errorf("expected HTTPS but %v returned", val)
|
t.Errorf("expected HTTPS but %v returned", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +73,12 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected a string type")
|
t.Errorf("expected a string type")
|
||||||
}
|
}
|
||||||
if val != "HTTP" {
|
if val != http {
|
||||||
t.Errorf("expected HTTPS but %v returned", val)
|
t.Errorf("expected HTTPS but %v returned", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test invalid annotation set
|
// Test invalid annotation set
|
||||||
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "INVALID"
|
data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = "INVALID"
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
i, err = NewParser(&resolver.Mock{}).Parse(ing)
|
i, err = NewParser(&resolver.Mock{}).Parse(ing)
|
||||||
|
@ -88,7 +89,7 @@ func TestParseInvalidAnnotations(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected a string type")
|
t.Errorf("expected a string type")
|
||||||
}
|
}
|
||||||
if val != "HTTP" {
|
if val != http {
|
||||||
t.Errorf("expected HTTPS but %v returned", val)
|
t.Errorf("expected HTTPS but %v returned", val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ func TestParseAnnotations(t *testing.T) {
|
||||||
ing := buildIngress()
|
ing := buildIngress()
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS"
|
data[parser.GetAnnotationWithPrefix(backendProtocolAnnotation)] = " HTTPS "
|
||||||
ing.SetAnnotations(data)
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||||
|
|
|
@ -18,14 +18,82 @@ package canary
|
||||||
|
|
||||||
import (
|
import (
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/errors"
|
"k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
canaryAnnotation = "canary"
|
||||||
|
canaryWeightAnnotation = "canary-weight"
|
||||||
|
canaryWeightTotalAnnotation = "canary-weight-total"
|
||||||
|
canaryByHeaderAnnotation = "canary-by-header"
|
||||||
|
canaryByHeaderValueAnnotation = "canary-by-header-value"
|
||||||
|
canaryByHeaderPatternAnnotation = "canary-by-header-pattern"
|
||||||
|
canaryByCookieAnnotation = "canary-by-cookie"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CanaryAnnotations = parser.Annotation{
|
||||||
|
Group: "canary",
|
||||||
|
Annotations: parser.AnnotationFields{
|
||||||
|
canaryAnnotation: {
|
||||||
|
Validator: parser.ValidateBool,
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation enables the Ingress spec to act as an alternative service for requests to route to depending on the rules applied`,
|
||||||
|
},
|
||||||
|
canaryWeightAnnotation: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation defines the integer based (0 - ) percent of random requests that should be routed to the service specified in the canary Ingress`,
|
||||||
|
},
|
||||||
|
canaryWeightTotalAnnotation: {
|
||||||
|
Validator: parser.ValidateInt,
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskLow,
|
||||||
|
Documentation: `This annotation The total weight of traffic. If unspecified, it defaults to 100`,
|
||||||
|
},
|
||||||
|
canaryByHeaderAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation defines the header that should be used for notifying the Ingress to route the request to the service specified in the Canary Ingress.
|
||||||
|
When the request header is set to 'always', it will be routed to the canary. When the header is set to 'never', it will never be routed to the canary.
|
||||||
|
For any other value, the header will be ignored and the request compared against the other canary rules by precedence`,
|
||||||
|
},
|
||||||
|
canaryByHeaderValueAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation defines the header value to match for notifying the Ingress to route the request to the service specified in the Canary Ingress.
|
||||||
|
When the request header is set to this value, it will be routed to the canary. For any other header value, the header will be ignored and the request compared against the other canary rules by precedence.
|
||||||
|
This annotation has to be used together with 'canary-by-header'. The annotation is an extension of the 'canary-by-header' to allow customizing the header value instead of using hardcoded values.
|
||||||
|
It doesn't have any effect if the 'canary-by-header' annotation is not defined`,
|
||||||
|
},
|
||||||
|
canaryByHeaderPatternAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.IsValidRegex, false),
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation works the same way as canary-by-header-value except it does PCRE Regex matching.
|
||||||
|
Note that when 'canary-by-header-value' is set this annotation will be ignored.
|
||||||
|
When the given Regex causes error during request processing, the request will be considered as not matching.`,
|
||||||
|
},
|
||||||
|
canaryByCookieAnnotation: {
|
||||||
|
Validator: parser.ValidateRegex(parser.BasicCharsRegex, true),
|
||||||
|
Scope: parser.AnnotationScopeIngress,
|
||||||
|
Risk: parser.AnnotationRiskMedium,
|
||||||
|
Documentation: `This annotation defines the cookie that should be used for notifying the Ingress to route the request to the service specified in the Canary Ingress.
|
||||||
|
When the cookie is set to 'always', it will be routed to the canary. When the cookie is set to 'never', it will never be routed to the canary`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type canary struct {
|
type canary struct {
|
||||||
r resolver.Resolver
|
r resolver.Resolver
|
||||||
|
annotationConfig parser.Annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config returns the configuration rules for setting up the Canary
|
// Config returns the configuration rules for setting up the Canary
|
||||||
|
@ -41,7 +109,10 @@ type Config struct {
|
||||||
|
|
||||||
// NewParser parses the ingress for canary related annotations
|
// NewParser parses the ingress for canary related annotations
|
||||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
return canary{r}
|
return canary{
|
||||||
|
r: r,
|
||||||
|
annotationConfig: CanaryAnnotations,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
|
@ -50,45 +121,75 @@ func (c canary) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
config.Enabled, err = parser.GetBoolAnnotation("canary", ing)
|
config.Enabled, err = parser.GetBoolAnnotation(canaryAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to 'false'", canaryAnnotation)
|
||||||
|
}
|
||||||
config.Enabled = false
|
config.Enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Weight, err = parser.GetIntAnnotation("canary-weight", ing)
|
config.Weight, err = parser.GetIntAnnotation(canaryWeightAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to '0'", canaryWeightAnnotation)
|
||||||
|
}
|
||||||
config.Weight = 0
|
config.Weight = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
config.WeightTotal, err = parser.GetIntAnnotation("canary-weight-total", ing)
|
config.WeightTotal, err = parser.GetIntAnnotation(canaryWeightTotalAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to '100'", canaryWeightTotalAnnotation)
|
||||||
|
}
|
||||||
config.WeightTotal = 100
|
config.WeightTotal = 100
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Header, err = parser.GetStringAnnotation("canary-by-header", ing)
|
config.Header, err = parser.GetStringAnnotation(canaryByHeaderAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderAnnotation)
|
||||||
|
}
|
||||||
config.Header = ""
|
config.Header = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
config.HeaderValue, err = parser.GetStringAnnotation("canary-by-header-value", ing)
|
config.HeaderValue, err = parser.GetStringAnnotation(canaryByHeaderValueAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderValueAnnotation)
|
||||||
|
}
|
||||||
config.HeaderValue = ""
|
config.HeaderValue = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
config.HeaderPattern, err = parser.GetStringAnnotation("canary-by-header-pattern", ing)
|
config.HeaderPattern, err = parser.GetStringAnnotation(canaryByHeaderPatternAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to ''", canaryByHeaderPatternAnnotation)
|
||||||
|
}
|
||||||
config.HeaderPattern = ""
|
config.HeaderPattern = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Cookie, err = parser.GetStringAnnotation("canary-by-cookie", ing)
|
config.Cookie, err = parser.GetStringAnnotation(canaryByCookieAnnotation, ing, c.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.IsValidationError(err) {
|
||||||
|
klog.Warningf("%s is invalid, defaulting to ''", canaryByCookieAnnotation)
|
||||||
|
}
|
||||||
config.Cookie = ""
|
config.Cookie = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0 ||
|
if !config.Enabled && (config.Weight > 0 || len(config.Header) > 0 || len(config.HeaderValue) > 0 || len(config.Cookie) > 0 ||
|
||||||
len(config.HeaderPattern) > 0) {
|
len(config.HeaderPattern) > 0) {
|
||||||
return nil, errors.NewInvalidAnnotationConfiguration("canary", "configured but not enabled")
|
return nil, errors.NewInvalidAnnotationConfiguration(canaryAnnotation, "configured but not enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c canary) GetDocumentation() parser.AnnotationFields {
|
||||||
|
return c.annotationConfig.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c canary) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(c.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, CanaryAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package canary
|
package canary
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
api "k8s.io/api/core/v1"
|
api "k8s.io/api/core/v1"
|
||||||
|
@ -24,8 +25,6 @@ import (
|
||||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -93,7 +92,6 @@ func TestCanaryInvalid(t *testing.T) {
|
||||||
if val.Weight != 0 {
|
if val.Weight != 0 {
|
||||||
t.Errorf("Expected %v but got %v", 0, val.Weight)
|
t.Errorf("Expected %v but got %v", 0, val.Weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAnnotations(t *testing.T) {
|
func TestAnnotations(t *testing.T) {
|
||||||
|
@ -133,10 +131,9 @@ func TestAnnotations(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
} else {
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%v: expected nil but returned error %v", test.title, err)
|
t.Errorf("%v: expected nil but returned error %v", test.title, err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canaryConfig, ok := i.(*Config)
|
canaryConfig, ok := i.(*Config)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue