Merge branch 'main' into feature/topology_zones
This commit is contained in:
commit
81148e7b3e
37 changed files with 3839 additions and 64 deletions
24
.github/workflows/stale.yaml
vendored
Normal file
24
.github/workflows/stale.yaml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: 'Stale Issues and PRs'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@6f05e4244c9a0b2ed3401882b05d701dd0a7289b # v7.0.0
|
||||
with:
|
||||
stale-issue-message: 'This is stale, but we won't close it automatically, just bare in mind the maintainers may be busy with other tasks and will reach your issue ASAP. If you have any question or request to prioritize this, please reach `#ingress-nginx-dev` on Kubernetes Slack.'
|
||||
stale-pr-message: 'This is stale, but we won't close it automatically, just bare in mind the maintainers may be busy with other tasks and will reach your issue ASAP. If you have any question or request to prioritize this, please reach `#ingress-nginx-dev` on Kubernetes Slack.'
|
||||
stale-issue-label: lifecycle/frozen
|
||||
stale-pr-label: lifecycle/frozen
|
||||
days-before-issue-stale: 30
|
||||
days-before-pr-stale: 45
|
||||
days-before-close: -1 # dont not close issues/prs
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -59,3 +59,4 @@ images/fastcgi-helloserver/rootfs/fastcgi-helloserver
|
|||
cmd/plugin/release/ingress-nginx.yaml
|
||||
cmd/plugin/release/*.tar.gz
|
||||
cmd/plugin/release/LICENSE
|
||||
tmp/
|
||||
|
|
|
@ -19,20 +19,26 @@ if [ "$DEBUG" == "true" ]; then
|
|||
set -x
|
||||
fi
|
||||
|
||||
RUNTIME=${RUNTIME:-"docker"}
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# temporal directory for the /etc/ingress-controller directory
|
||||
INGRESS_VOLUME=$(mktemp -d)
|
||||
if [[ "$OSTYPE" == darwin* ]] && [[ "$RUNTIME" == podman ]]; then
|
||||
mkdir -p "tmp"
|
||||
INGRESS_VOLUME=$(pwd)/$(mktemp -d tmp/XXXXXX)
|
||||
else
|
||||
INGRESS_VOLUME=$(mktemp -d)
|
||||
if [[ "$OSTYPE" == darwin* ]]; then
|
||||
INGRESS_VOLUME=/private$INGRESS_VOLUME
|
||||
fi
|
||||
fi
|
||||
|
||||
# make sure directory for SSL cert storage exists under ingress volume
|
||||
mkdir "${INGRESS_VOLUME}/ssl"
|
||||
|
||||
if [[ "$OSTYPE" == darwin* ]]; then
|
||||
INGRESS_VOLUME=/private$INGRESS_VOLUME
|
||||
fi
|
||||
|
||||
function cleanup {
|
||||
rm -rf "${INGRESS_VOLUME}"
|
||||
}
|
||||
|
@ -40,6 +46,11 @@ trap cleanup EXIT
|
|||
|
||||
E2E_IMAGE=${E2E_IMAGE:-registry.k8s.io/ingress-nginx/e2e-test-runner:v20221221-controller-v1.5.1-62-g6ffaef32a@sha256:8f025472964cd15ae2d379503aba150565a8d78eb36b41ddfc5f1e3b1ca81a8e}
|
||||
|
||||
if [[ "$RUNTIME" == podman ]]; then
|
||||
# Podman does not support both tag and digest
|
||||
E2E_IMAGE=$(echo $E2E_IMAGE | awk -F "@sha" '{print $1}')
|
||||
fi
|
||||
|
||||
DOCKER_OPTS=${DOCKER_OPTS:-}
|
||||
DOCKER_IN_DOCKER_ENABLED=${DOCKER_IN_DOCKER_ENABLED:-}
|
||||
|
||||
|
@ -82,20 +93,12 @@ if [[ "$DOCKER_IN_DOCKER_ENABLED" == "true" ]]; then
|
|||
/bin/bash -c "${FLAGS}"
|
||||
else
|
||||
echo "Reached DIND check ELSE block, inside run-in-docker.sh"
|
||||
docker run \
|
||||
${PLATFORM_FLAG} ${PLATFORM} \
|
||||
--tty \
|
||||
--rm \
|
||||
${DOCKER_OPTS} \
|
||||
-e DEBUG=${DEBUG} \
|
||||
-e GOCACHE="/go/src/${PKG}/.cache" \
|
||||
-e GOMODCACHE="/go/src/${PKG}/.modcache" \
|
||||
-e DOCKER_IN_DOCKER_ENABLED="true" \
|
||||
-v "${HOME}/.kube:${HOME}/.kube" \
|
||||
-v "${KUBE_ROOT}:/go/src/${PKG}" \
|
||||
-v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" \
|
||||
-v "/var/run/docker.sock:/var/run/docker.sock" \
|
||||
-v "${INGRESS_VOLUME}:/etc/ingress-controller/" \
|
||||
-w "/go/src/${PKG}" \
|
||||
${E2E_IMAGE} /bin/bash -c "${FLAGS}"
|
||||
|
||||
args="${PLATFORM_FLAG} ${PLATFORM} --tty --rm ${DOCKER_OPTS} -e DEBUG=${DEBUG} -e GOCACHE="/go/src/${PKG}/.cache" -e GOMODCACHE="/go/src/${PKG}/.modcache" -e DOCKER_IN_DOCKER_ENABLED="true" -v "${HOME}/.kube:${HOME}/.kube" -v "${KUBE_ROOT}:/go/src/${PKG}" -v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" -v "${INGRESS_VOLUME}:/etc/ingress-controller/" -w "/go/src/${PKG}""
|
||||
|
||||
if [[ "$RUNTIME" == "docker" ]]; then
|
||||
args="$args -v /var/run/docker.sock:/var/run/docker.sock"
|
||||
fi
|
||||
|
||||
${RUNTIME} run $args ${E2E_IMAGE} /bin/bash -c "${FLAGS}"
|
||||
fi
|
||||
|
|
|
@ -394,7 +394,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/user-guide/node-selection/ # |
|
||||
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
|
||||
| controller.opentelemetry.enabled | bool | `false` | |
|
||||
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20221114-controller-v1.5.1-6-ga66ee73c5@sha256:41076fd9fb4255677c1a3da1ac3fc41477f06eba3c7ebf37ffc8f734dad51d7c"` | |
|
||||
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230107-helm-chart-4.4.2-2-g96b3d2165@sha256:331b9bebd6acfcd2d3048abbdd86555f5be76b7e3d0b5af4300b04235c6056c9"` | |
|
||||
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
|
||||
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
|
||||
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
|
||||
|
@ -482,6 +482,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| defaultBackend.livenessProbe.successThreshold | int | `1` | |
|
||||
| defaultBackend.livenessProbe.timeoutSeconds | int | `5` | |
|
||||
| defaultBackend.minAvailable | int | `1` | |
|
||||
| defaultBackend.minReadySeconds | int | `0` | `minReadySeconds` to avoid killing pods before we are ready # |
|
||||
| defaultBackend.name | string | `"defaultbackend"` | |
|
||||
| defaultBackend.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for default backend pod assignment # Ref: https://kubernetes.io/docs/user-guide/node-selection/ # |
|
||||
| defaultBackend.podAnnotations | object | `{}` | Annotations to be added to default backend pods # |
|
||||
|
@ -505,6 +506,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| defaultBackend.serviceAccount.create | bool | `true` | |
|
||||
| defaultBackend.serviceAccount.name | string | `""` | |
|
||||
| defaultBackend.tolerations | list | `[]` | Node tolerations for server scheduling to nodes with taints # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ # |
|
||||
| defaultBackend.updateStrategy | object | `{}` | The update strategy to apply to the Deployment or DaemonSet # |
|
||||
| dhParam | string | `nil` | A base64-encoded Diffie-Hellman parameter. This can be generated with: `openssl dhparam 4096 2> /dev/null | base64` # Ref: https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples/customization/ssl-dh-param |
|
||||
| imagePullSecrets | list | `[]` | Optional array of imagePullSecrets containing private registry credentials # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ |
|
||||
| podSecurityPolicy.enabled | bool | `false` | |
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "ingress-nginx.fullname" . }}-admission
|
||||
name: {{ include "ingress-nginx.fullname" . }}-admission
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.networkPolicyEnabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "ingress-nginx.fullname" . }}-admission
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
{{- include "ingress-nginx.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: admission-webhook
|
||||
{{- with .Values.controller.admissionWebhooks.patch.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "ingress-nginx.labels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: admission-webhook
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
egress:
|
||||
- {}
|
||||
{{- end }}
|
|
@ -2,7 +2,7 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "ingress-nginx.fullname" . }}-admission
|
||||
name: {{ include "ingress-nginx.fullname" . }}-admission
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
|
|
|
@ -19,6 +19,11 @@ spec:
|
|||
replicas: {{ .Values.defaultBackend.replicaCount }}
|
||||
{{- end }}
|
||||
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
||||
{{- if .Values.defaultBackend.updateStrategy }}
|
||||
strategy:
|
||||
{{ toYaml .Values.defaultBackend.updateStrategy | nindent 4 }}
|
||||
{{- end }}
|
||||
minReadySeconds: {{ .Values.defaultBackend.minReadySeconds }}
|
||||
template:
|
||||
metadata:
|
||||
{{- if .Values.defaultBackend.podAnnotations }}
|
||||
|
|
|
@ -597,7 +597,7 @@ controller:
|
|||
|
||||
opentelemetry:
|
||||
enabled: false
|
||||
image: registry.k8s.io/ingress-nginx/opentelemetry:v20221114-controller-v1.5.1-6-ga66ee73c5@sha256:41076fd9fb4255677c1a3da1ac3fc41477f06eba3c7ebf37ffc8f734dad51d7c
|
||||
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230107-helm-chart-4.4.2-2-g96b3d2165@sha256:331b9bebd6acfcd2d3048abbdd86555f5be76b7e3d0b5af4300b04235c6056c9
|
||||
containerSecurityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
|
||||
|
@ -845,6 +845,17 @@ defaultBackend:
|
|||
successThreshold: 1
|
||||
timeoutSeconds: 5
|
||||
|
||||
# -- The update strategy to apply to the Deployment or DaemonSet
|
||||
##
|
||||
updateStrategy: {}
|
||||
# rollingUpdate:
|
||||
# maxUnavailable: 1
|
||||
# type: RollingUpdate
|
||||
|
||||
# -- `minReadySeconds` to avoid killing pods before we are ready
|
||||
##
|
||||
minReadySeconds: 0
|
||||
|
||||
# -- Node tolerations for server scheduling to nodes with taints
|
||||
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
|
||||
##
|
||||
|
|
|
@ -18,6 +18,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
|
|||
| `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) |
|
||||
| `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). |
|
||||
| `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) |
|
||||
| `--disable-sync-events` | Disables the creation of 'Sync' Event resources, but still logs them |
|
||||
| `--dynamic-configuration-retries` | Number of times to retry failed dynamic configuration before failing to sync an ingress. (default 15) |
|
||||
| `--election-id` | Election id to use for Ingress status updates. (default "ingress-controller-leader") |
|
||||
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
|
||||
|
|
|
@ -357,7 +357,7 @@ Prometheus metrics are exposed on port 10254.
|
|||
|
||||
* `nginx_ingress_controller_request_duration_seconds` Histogram
|
||||
|
||||
The request processing time in milliseconds (affected by client speed)
|
||||
The request processing time in seconds (affected by client speed)
|
||||
|
||||
nginx var: `request_time`
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|
|||
|[nginx.ingress.kubernetes.io/x-forwarded-prefix](#x-forwarded-prefix-header)|string|
|
||||
|[nginx.ingress.kubernetes.io/load-balance](#custom-nginx-load-balancing)|string|
|
||||
|[nginx.ingress.kubernetes.io/upstream-vhost](#custom-nginx-upstream-vhost)|string|
|
||||
|[nginx.ingress.kubernetes.io/denylist-source-range](#denylist-source-range)|CIDR|
|
||||
|[nginx.ingress.kubernetes.io/whitelist-source-range](#whitelist-source-range)|CIDR|
|
||||
|[nginx.ingress.kubernetes.io/proxy-buffering](#proxy-buffering)|string|
|
||||
|[nginx.ingress.kubernetes.io/proxy-buffers-number](#proxy-buffers-number)|number|
|
||||
|
@ -638,6 +639,17 @@ To enable this feature use the annotation `nginx.ingress.kubernetes.io/from-to-w
|
|||
!!! attention
|
||||
For HTTPS to HTTPS redirects is mandatory the SSL Certificate defined in the Secret, located in the TLS section of Ingress, contains both FQDN in the common name of the certificate.
|
||||
|
||||
### Denylist source range
|
||||
|
||||
You can specify blocked client IP source ranges through the `nginx.ingress.kubernetes.io/denylist-source-range` annotation.
|
||||
The value is a comma separated list of [CIDRs](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing), e.g. `10.0.0.0/24,172.10.0.1`.
|
||||
|
||||
To configure this setting globally for all Ingress rules, the `denylist-source-range` value may be set in the [NGINX ConfigMap](./configmap.md#denylist-source-range).
|
||||
|
||||
!!! note
|
||||
Adding an annotation to an Ingress rule overrides any global restriction.
|
||||
|
||||
|
||||
### Whitelist source range
|
||||
|
||||
You can specify allowed client IP source ranges through the `nginx.ingress.kubernetes.io/whitelist-source-range` annotation.
|
||||
|
|
|
@ -176,6 +176,7 @@ The following table shows a configuration option's name, type, and the default v
|
|||
|[proxy-request-buffering](#proxy-request-buffering)|string|"on"|
|
||||
|[ssl-redirect](#ssl-redirect)|bool|"true"|
|
||||
|[force-ssl-redirect](#force-ssl-redirect)|bool|"false"|
|
||||
|[denylist-source-range](#denylist-source-range)|[]string|[]string{}|
|
||||
|[whitelist-source-range](#whitelist-source-range)|[]string|[]string{}|
|
||||
|[skip-access-log-urls](#skip-access-log-urls)|[]string|[]string{}|
|
||||
|[limit-rate](#limit-rate)|int|0|
|
||||
|
@ -1096,6 +1097,11 @@ _**default:**_ "true"
|
|||
Sets the global value of redirects (308) to HTTPS if the server has a default TLS certificate (defined in extra-args).
|
||||
_**default:**_ "false"
|
||||
|
||||
## denylist-source-range
|
||||
|
||||
Sets the default denylisted IPs for each `server` block. This can be overwritten by an annotation on an Ingress rule.
|
||||
See [ngx_http_access_module](https://nginx.org/en/docs/http/ngx_http_access_module.html).
|
||||
|
||||
## whitelist-source-range
|
||||
|
||||
Sets the default whitelisted IPs for each `server` block. This can be overwritten by an annotation on an Ingress rule.
|
||||
|
|
10
go.mod
10
go.mod
|
@ -25,7 +25,7 @@ require (
|
|||
github.com/stretchr/testify v1.8.1
|
||||
github.com/yudai/gojsondiff v1.0.0
|
||||
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
|
||||
golang.org/x/crypto v0.4.0
|
||||
golang.org/x/crypto v0.5.0
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
|
||||
gopkg.in/go-playground/pool.v3 v3.1.1
|
||||
|
@ -109,11 +109,11 @@ require (
|
|||
github.com/yudai/pp v2.0.1+incompatible // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/oauth2 v0.3.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/term v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
golang.org/x/tools v0.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
|
20
go.sum
20
go.sum
|
@ -423,8 +423,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -491,8 +491,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -558,19 +558,19 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/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.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
@ -21,7 +21,7 @@ project(
|
|||
LANGUAGES CXX
|
||||
VERSION 0.0.1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_FLAGS "-O2")
|
||||
|
|
|
@ -26,12 +26,12 @@ RUN apk update \
|
|||
|
||||
# install gRPC
|
||||
FROM base as grpc
|
||||
RUN bash /opt/third_party/build.sh -g v1.43.2
|
||||
RUN bash /opt/third_party/build.sh -g v1.49.2
|
||||
|
||||
# install OpenTelemetry-cpp
|
||||
FROM base as otel-cpp
|
||||
COPY --from=grpc /opt/third_party/install/ /usr
|
||||
RUN bash /opt/third_party/build.sh -o v1.3.0
|
||||
RUN bash /opt/third_party/build.sh -o v1.8.1
|
||||
|
||||
# install otel_ngx_module.so
|
||||
FROM base as nginx
|
||||
|
|
|
@ -100,9 +100,9 @@ install_otel()
|
|||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DWITH_OTLP=ON \
|
||||
-DWITH_OTLP_GRPC=ON \
|
||||
-DWITH_EXAMPLES=OFF \
|
||||
-DWITH_ABSEIL=ON \
|
||||
-DWITH_OTLP_HTTP=OFF \
|
||||
-DWITH_ABSEIL=OFF \
|
||||
-DWITH_EXAMPLES=OFF \
|
||||
..
|
||||
cmake --build . -j ${CORES} --target install
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ install_nginx()
|
|||
export NGINX_VERSION=1.21.6
|
||||
|
||||
# Check for recent changes: https://github.com/open-telemetry/opentelemetry-cpp-contrib/compare/2656a4...main
|
||||
export OPENTELEMETRY_CONTRIB_COMMIT=6467ec2e4d67b08b44580b7eb7a298786f4eef91
|
||||
export OPENTELEMETRY_CONTRIB_COMMIT=1ec94c82095bab61f06c7393b6f3272469d285af
|
||||
|
||||
mkdir -p /etc/nginx
|
||||
cd "$BUILD_PATH"
|
||||
|
|
|
@ -44,6 +44,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||
|
@ -110,6 +111,7 @@ type Ingress struct {
|
|||
LoadBalancing string
|
||||
UpstreamVhost string
|
||||
Whitelist ipwhitelist.SourceRange
|
||||
Denylist ipdenylist.SourceRange
|
||||
XForwardedPrefix string
|
||||
SSLCipher sslcipher.Config
|
||||
Logs log.Config
|
||||
|
@ -160,6 +162,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
|
|||
"LoadBalancing": loadbalancing.NewParser(cfg),
|
||||
"UpstreamVhost": upstreamvhost.NewParser(cfg),
|
||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
||||
"Denylist": ipdenylist.NewParser(cfg),
|
||||
"XForwardedPrefix": xforwardedprefix.NewParser(cfg),
|
||||
"SSLCipher": sslcipher.NewParser(cfg),
|
||||
"Logs": log.NewParser(cfg),
|
||||
|
|
95
internal/ingress/annotations/ipdenylist/main.go
Normal file
95
internal/ingress/annotations/ipdenylist/main.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ipdenylist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/ingress-nginx/internal/net"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/util/sets"
|
||||
)
|
||||
|
||||
// SourceRange returns the CIDR
|
||||
type SourceRange struct {
|
||||
CIDR []string `json:"cidr,omitempty"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two SourceRange types
|
||||
func (sr1 *SourceRange) Equal(sr2 *SourceRange) bool {
|
||||
if sr1 == sr2 {
|
||||
return true
|
||||
}
|
||||
if sr1 == nil || sr2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return sets.StringElementsMatch(sr1.CIDR, sr2.CIDR)
|
||||
}
|
||||
|
||||
type ipdenylist struct {
|
||||
r resolver.Resolver
|
||||
}
|
||||
|
||||
// NewParser creates a new denylist annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return ipdenylist{r}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to limit access to certain client addresses or networks.
|
||||
// Multiple ranges can specified using commas as separator
|
||||
// e.g. `18.0.0.0/8,56.0.0.0/8`
|
||||
func (a ipdenylist) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||
defBackend := a.r.GetDefaultBackend()
|
||||
|
||||
defaultDenylistSourceRange := make([]string, len(defBackend.DenylistSourceRange))
|
||||
copy(defaultDenylistSourceRange, defBackend.DenylistSourceRange)
|
||||
sort.Strings(defaultDenylistSourceRange)
|
||||
|
||||
val, err := parser.GetStringAnnotation("denylist-source-range", ing)
|
||||
// A missing annotation is not a problem, just use the default
|
||||
if err == ing_errors.ErrMissingAnnotations {
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, nil
|
||||
}
|
||||
|
||||
values := strings.Split(val, ",")
|
||||
ipnets, ips, err := net.ParseIPNets(values...)
|
||||
if err != nil && len(ips) == 0 {
|
||||
return &SourceRange{CIDR: defaultDenylistSourceRange}, ing_errors.LocationDenied{
|
||||
Reason: fmt.Errorf("the annotation does not contain a valid IP address or network: %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
cidrs := []string{}
|
||||
for k := range ipnets {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
for k := range ips {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
|
||||
sort.Strings(cidrs)
|
||||
|
||||
return &SourceRange{cidrs}, nil
|
||||
}
|
216
internal/ingress/annotations/ipdenylist/main_test.go
Normal file
216
internal/ingress/annotations/ipdenylist/main_test.go
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ipdenylist
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
networking "k8s.io/api/networking/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
func buildIngress() *networking.Ingress {
|
||||
defaultBackend := networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
Name: "default-backend",
|
||||
Port: networking.ServiceBackendPort{
|
||||
Number: 80,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &networking.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
DefaultBackend: &networking.IngressBackend{
|
||||
Service: &networking.IngressServiceBackend{
|
||||
Name: "default-backend",
|
||||
Port: networking.ServiceBackendPort{
|
||||
Number: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
tests := map[string]struct {
|
||||
net string
|
||||
expectCidr []string
|
||||
expectErr bool
|
||||
errOut string
|
||||
}{
|
||||
"test parse a valid net": {
|
||||
net: "10.0.0.0/24",
|
||||
expectCidr: []string{"10.0.0.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
"test parse a invalid net": {
|
||||
net: "ww",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ww",
|
||||
},
|
||||
"test parse a empty net": {
|
||||
net: "",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ",
|
||||
},
|
||||
"test parse a malicious escaped string": {
|
||||
net: `10.0.0.0/8"rm /tmp",11.0.0.0/8`,
|
||||
expectErr: true,
|
||||
errOut: `the annotation does not contain a valid IP address or network: invalid CIDR address: 10.0.0.0/8"rm /tmp"`,
|
||||
},
|
||||
"test parse multiple valid cidr": {
|
||||
net: "2.2.2.2/32,1.1.1.1/32,3.3.3.0/24",
|
||||
expectCidr: []string{"1.1.1.1/32", "2.2.2.2/32", "3.3.3.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix("denylist-source-range")] = test.net
|
||||
ing.SetAnnotations(data)
|
||||
p := NewParser(&resolver.Mock{})
|
||||
i, err := p.Parse(ing)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("%v:unexpected error: %v", testName, err)
|
||||
}
|
||||
if test.expectErr {
|
||||
if err.Error() != test.errOut {
|
||||
t.Errorf("%v:expected error: %v but %v return", testName, test.errOut, err.Error())
|
||||
}
|
||||
}
|
||||
if !test.expectErr {
|
||||
sr, ok := i.(*SourceRange)
|
||||
if !ok {
|
||||
t.Errorf("%v:expected a SourceRange type", testName)
|
||||
}
|
||||
if !strsEquals(sr.CIDR, test.expectCidr) {
|
||||
t.Errorf("%v:expected %v CIDR but %v returned", testName, test.expectCidr, sr.CIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
resolver.Mock
|
||||
}
|
||||
|
||||
// GetDefaultBackend returns the backend that must be used as default
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{
|
||||
DenylistSourceRange: []string{"4.4.4.0/24", "1.2.3.4/32"},
|
||||
}
|
||||
}
|
||||
|
||||
// Test that when we have a denylist set on the Backend that is used when we
|
||||
// don't have the annotation
|
||||
func TestParseAnnotationsWithDefaultConfig(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
mockBackend := mockBackend{}
|
||||
|
||||
tests := map[string]struct {
|
||||
net string
|
||||
expectCidr []string
|
||||
expectErr bool
|
||||
errOut string
|
||||
}{
|
||||
"test parse a valid net": {
|
||||
net: "10.0.0.0/24",
|
||||
expectCidr: []string{"10.0.0.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
"test parse a invalid net": {
|
||||
net: "ww",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ww",
|
||||
},
|
||||
"test parse a empty net": {
|
||||
net: "",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ",
|
||||
},
|
||||
"test parse multiple valid cidr": {
|
||||
net: "2.2.2.2/32,1.1.1.1/32,3.3.3.0/24",
|
||||
expectCidr: []string{"1.1.1.1/32", "2.2.2.2/32", "3.3.3.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix("denylist-source-range")] = test.net
|
||||
ing.SetAnnotations(data)
|
||||
p := NewParser(mockBackend)
|
||||
i, err := p.Parse(ing)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("%v:unexpected error: %v", testName, err)
|
||||
}
|
||||
if test.expectErr {
|
||||
if err.Error() != test.errOut {
|
||||
t.Errorf("%v:expected error: %v but %v return", testName, test.errOut, err.Error())
|
||||
}
|
||||
}
|
||||
if !test.expectErr {
|
||||
sr, ok := i.(*SourceRange)
|
||||
if !ok {
|
||||
t.Errorf("%v:expected a SourceRange type", testName)
|
||||
}
|
||||
if !strsEquals(sr.CIDR, test.expectCidr) {
|
||||
t.Errorf("%v:expected %v CIDR but %v returned", testName, test.expectCidr, sr.CIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strsEquals(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -895,6 +895,7 @@ func NewDefault() Configuration {
|
|||
PreserveTrailingSlash: false,
|
||||
SSLRedirect: true,
|
||||
CustomHTTPErrors: []int{},
|
||||
DenylistSourceRange: []string{},
|
||||
WhitelistSourceRange: []string{},
|
||||
SkipAccessLogURLs: []string{},
|
||||
LimitRate: 0,
|
||||
|
|
|
@ -131,6 +131,8 @@ type Configuration struct {
|
|||
|
||||
DynamicConfigurationRetries int
|
||||
|
||||
DisableSyncEvents bool
|
||||
|
||||
EnableTopologyAwareRouting bool
|
||||
}
|
||||
|
||||
|
@ -1451,6 +1453,7 @@ func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress)
|
|||
loc.Redirect = anns.Redirect
|
||||
loc.Rewrite = anns.Rewrite
|
||||
loc.UpstreamVhost = anns.UpstreamVhost
|
||||
loc.Denylist = anns.Denylist
|
||||
loc.Whitelist = anns.Whitelist
|
||||
loc.Denied = anns.Denied
|
||||
loc.XForwardedPrefix = anns.XForwardedPrefix
|
||||
|
|
|
@ -2404,6 +2404,7 @@ func newNGINXController(t *testing.T) *NGINXController {
|
|||
Controller: "k8s.io/ingress-nginx",
|
||||
AnnotationValue: "nginx",
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
sslCert := ssl.GetFakeSSLCert()
|
||||
|
@ -2468,7 +2469,8 @@ func newDynamicNginxController(t *testing.T, setConfigMap func(string) *v1.Confi
|
|||
&ingressclass.IngressClassConfiguration{
|
||||
Controller: "k8s.io/ingress-nginx",
|
||||
AnnotationValue: "nginx",
|
||||
})
|
||||
},
|
||||
false)
|
||||
|
||||
sslCert := ssl.GetFakeSSLCert()
|
||||
config := &Configuration{
|
||||
|
|
|
@ -136,7 +136,8 @@ func NewNGINXController(config *Configuration, mc metric.Collector) *NGINXContro
|
|||
n.updateCh,
|
||||
config.DisableCatchAll,
|
||||
config.DeepInspector,
|
||||
config.IngressClassConfiguration)
|
||||
config.IngressClassConfiguration,
|
||||
config.DisableSyncEvents)
|
||||
|
||||
n.syncQueue = task.NewTaskQueue(n.syncIngress)
|
||||
|
||||
|
|
|
@ -251,7 +251,8 @@ func New(
|
|||
updateCh *channels.RingChannel,
|
||||
disableCatchAll bool,
|
||||
deepInspector bool,
|
||||
icConfig *ingressclass.IngressClassConfiguration) Storer {
|
||||
icConfig *ingressclass.IngressClassConfiguration,
|
||||
disableSyncEvents bool) Storer {
|
||||
|
||||
store := &k8sStore{
|
||||
informers: &Informer{},
|
||||
|
@ -267,9 +268,11 @@ func New(
|
|||
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(klog.Infof)
|
||||
eventBroadcaster.StartRecordingToSink(&clientcorev1.EventSinkImpl{
|
||||
Interface: client.CoreV1().Events(namespace),
|
||||
})
|
||||
if !disableSyncEvents {
|
||||
eventBroadcaster.StartRecordingToSink(&clientcorev1.EventSinkImpl{
|
||||
Interface: client.CoreV1().Events(namespace),
|
||||
})
|
||||
}
|
||||
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{
|
||||
Component: "nginx-ingress-controller",
|
||||
})
|
||||
|
|
|
@ -125,7 +125,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -206,7 +207,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
ic := createIngressClass(clientSet, t, "not-k8s.io/not-ingress-nginx")
|
||||
|
@ -310,7 +312,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
validSpec := commonIngressSpec
|
||||
|
@ -426,7 +429,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
ingressClassconfig)
|
||||
ingressClassconfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -556,7 +560,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
ingressClassconfig)
|
||||
ingressClassconfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
validSpec := commonIngressSpec
|
||||
|
@ -656,7 +661,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -750,7 +756,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
invalidSpec := commonIngressSpec
|
||||
|
@ -836,7 +843,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -932,7 +940,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -1056,7 +1065,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
@ -1177,7 +1187,8 @@ func TestStore(t *testing.T) {
|
|||
updateCh,
|
||||
false,
|
||||
true,
|
||||
DefaultClassConfig)
|
||||
DefaultClassConfig,
|
||||
false)
|
||||
|
||||
storer.Run(stopCh)
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ const (
|
|||
customHTTPErrors = "custom-http-errors"
|
||||
skipAccessLogUrls = "skip-access-log-urls"
|
||||
whitelistSourceRange = "whitelist-source-range"
|
||||
denylistSourceRange = "denylist-source-range"
|
||||
proxyRealIPCIDR = "proxy-real-ip-cidr"
|
||||
bindAddress = "bind-address"
|
||||
httpRedirectCode = "http-redirect-code"
|
||||
|
@ -100,6 +101,7 @@ func ReadConfig(src map[string]string) config.Configuration {
|
|||
to := config.NewDefault()
|
||||
errors := make([]int, 0)
|
||||
skipUrls := make([]string, 0)
|
||||
denyList := make([]string, 0)
|
||||
whiteList := make([]string, 0)
|
||||
proxyList := make([]string, 0)
|
||||
hideHeadersList := make([]string, 0)
|
||||
|
@ -169,6 +171,11 @@ func ReadConfig(src map[string]string) config.Configuration {
|
|||
skipUrls = splitAndTrimSpace(val, ",")
|
||||
}
|
||||
|
||||
if val, ok := conf[denylistSourceRange]; ok {
|
||||
delete(conf, denylistSourceRange)
|
||||
denyList = append(denyList, splitAndTrimSpace(val, ",")...)
|
||||
}
|
||||
|
||||
if val, ok := conf[whitelistSourceRange]; ok {
|
||||
delete(conf, whitelistSourceRange)
|
||||
whiteList = append(whiteList, splitAndTrimSpace(val, ",")...)
|
||||
|
@ -395,6 +402,7 @@ func ReadConfig(src map[string]string) config.Configuration {
|
|||
|
||||
to.CustomHTTPErrors = filterErrors(errors)
|
||||
to.SkipAccessLogURLs = skipUrls
|
||||
to.DenylistSourceRange = denyList
|
||||
to.WhitelistSourceRange = whiteList
|
||||
to.ProxyRealIPCIDR = proxyList
|
||||
to.BindAddressIpv4 = bindAddressIpv4List
|
||||
|
|
|
@ -149,6 +149,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
|||
|
||||
def = config.NewDefault()
|
||||
def.LuaSharedDicts = defaultLuaSharedDicts
|
||||
def.DenylistSourceRange = []string{"2.2.2.2/32"}
|
||||
def.WhitelistSourceRange = []string{"1.1.1.1/32"}
|
||||
def.DisableIpv6DNS = true
|
||||
|
||||
|
@ -161,6 +162,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
|||
def.Checksum = fmt.Sprintf("%v", hash)
|
||||
|
||||
to = ReadConfig(map[string]string{
|
||||
"denylist-source-range": "2.2.2.2/32",
|
||||
"whitelist-source-range": "1.1.1.1/32",
|
||||
"disable-ipv6-dns": "true",
|
||||
})
|
||||
|
|
|
@ -139,6 +139,10 @@ type Backend struct {
|
|||
// http://nginx.org/en/docs/http/ngx_http_access_module.html
|
||||
WhitelistSourceRange []string `json:"whitelist-source-range"`
|
||||
|
||||
// DenylistSourceRange allows limiting access to certain client addresses
|
||||
// http://nginx.org/en/docs/http/ngx_http_access_module.html
|
||||
DenylistSourceRange []string `json:"denylist-source-range"`
|
||||
|
||||
// Limits the rate of response transmission to a client.
|
||||
// The rate is specified in bytes per second. The zero value disables rate limiting.
|
||||
// The limit is set per a request, and so if a client simultaneously opens two connections,
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
|
||||
|
@ -222,6 +223,7 @@ type Server struct {
|
|||
// In some cases when more than one annotations is defined a particular order in the execution
|
||||
// is required.
|
||||
// The chain in the execution order of annotations should be:
|
||||
// - Denylist
|
||||
// - Whitelist
|
||||
// - RateLimit
|
||||
// - BasicDigestAuth
|
||||
|
@ -292,6 +294,10 @@ type Location struct {
|
|||
// Rewrite describes the redirection this location.
|
||||
// +optional
|
||||
Rewrite rewrite.Config `json:"rewrite,omitempty"`
|
||||
// Denylist indicates only connections from certain client
|
||||
// addresses or networks are allowed.
|
||||
// +optional
|
||||
Denylist ipdenylist.SourceRange `json:"denylist,omitempty"`
|
||||
// Whitelist indicates only connections from certain client
|
||||
// addresses or networks are allowed.
|
||||
// +optional
|
||||
|
|
|
@ -401,6 +401,9 @@ func (l1 *Location) Equal(l2 *Location) bool {
|
|||
if !(&l1.Rewrite).Equal(&l2.Rewrite) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Denylist).Equal(&l2.Denylist) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Whitelist).Equal(&l2.Whitelist) {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -215,7 +215,10 @@ Takes the form "<host>:port". If not provided, no admission controller is starte
|
|||
|
||||
dynamicConfigurationRetries = flags.Int("dynamic-configuration-retries", 15, "Number of times to retry failed dynamic configuration before failing to sync an ingress.")
|
||||
|
||||
disableSyncEvents = flags.Bool("disable-sync-events", false, "Disables the creation of 'Sync' event resources")
|
||||
|
||||
enableTopologyAwareRouting = flags.Bool("enable-topology-aware-routing", false, "Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto.")
|
||||
|
||||
)
|
||||
|
||||
flags.StringVar(&nginx.MaxmindMirror, "maxmind-mirror", "", `Maxmind mirror url (example: http://geoip.local/databases.`)
|
||||
|
@ -367,6 +370,7 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
|
|||
ValidationWebhookCertPath: *validationWebhookCert,
|
||||
ValidationWebhookKeyPath: *validationWebhookKey,
|
||||
InternalLoggerAddress: *internalLoggerAddress,
|
||||
DisableSyncEvents: *disableSyncEvents,
|
||||
}
|
||||
|
||||
if *apiserverHost != "" {
|
||||
|
|
|
@ -736,6 +736,8 @@ stream {
|
|||
lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;;";
|
||||
|
||||
lua_shared_dict tcp_udp_configuration_data 5M;
|
||||
|
||||
{{ buildResolvers $cfg.Resolver $cfg.DisableIpv6DNS }}
|
||||
|
||||
init_by_lua_block {
|
||||
collectgarbage("collect")
|
||||
|
@ -1058,6 +1060,8 @@ stream {
|
|||
opentracing_propagate_context;
|
||||
{{ end }}
|
||||
|
||||
access_log off;
|
||||
|
||||
# Ensure that modsecurity will not run on an internal location as this is not accessible from outside
|
||||
{{ if $all.Cfg.EnableModsecurity }}
|
||||
modsecurity off;
|
||||
|
@ -1262,6 +1266,10 @@ stream {
|
|||
{{ buildModSecurityForLocation $all.Cfg $location }}
|
||||
|
||||
{{ if isLocationAllowed $location }}
|
||||
{{ if gt (len $location.Denylist.CIDR) 0 }}
|
||||
{{ range $ip := $location.Denylist.CIDR }}
|
||||
deny {{ $ip }};{{ end }}
|
||||
{{ end }}
|
||||
{{ if gt (len $location.Whitelist.CIDR) 0 }}
|
||||
{{ range $ip := $location.Whitelist.CIDR }}
|
||||
allow {{ $ip }};{{ end }}
|
||||
|
|
File diff suppressed because it is too large
Load diff
147
test/e2e/annotations/ipdenylist.go
Normal file
147
test/e2e/annotations/ipdenylist.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.DescribeAnnotation("denylist-source-range", func() {
|
||||
f := framework.NewDefaultFramework("ipdenylist")
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeployment()
|
||||
})
|
||||
|
||||
ginkgo.It("only deny explicitly denied IPs, allow all others", func() {
|
||||
host := "ipdenylist.foo.com"
|
||||
namespace := f.Namespace
|
||||
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/denylist-source-range": "18.0.0.0/8, 56.0.0.1",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, namespace, framework.EchoService, 80, annotations)
|
||||
|
||||
// Temporarily trust forwarded headers so we can test IP based access control
|
||||
f.UpdateNginxConfigMapData("use-forwarded-headers", "true")
|
||||
defer func() {
|
||||
// Return to the original value
|
||||
f.UpdateNginxConfigMapData("use-forwarded-headers", "false")
|
||||
}()
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, "deny 18.0.0.0/8;") &&
|
||||
strings.Contains(server, "deny 56.0.0.1;") &&
|
||||
!strings.Contains(server, "deny all;")
|
||||
})
|
||||
|
||||
ginkgo.By("sending request from an explicitly denied IP range")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "18.0.0.1").
|
||||
Expect().
|
||||
Status(http.StatusForbidden)
|
||||
|
||||
ginkgo.By("sending request from an explicitly denied IP address")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "56.0.0.1").
|
||||
Expect().
|
||||
Status(http.StatusForbidden)
|
||||
|
||||
ginkgo.By("sending request from an implicitly allowed IP range")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "56.0.0.2").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
})
|
||||
|
||||
ginkgo.It("only allow explicitly allowed IPs, deny all others", func() {
|
||||
host := "ipdenylist.foo.com"
|
||||
namespace := f.Namespace
|
||||
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/denylist-source-range": "18.1.0.0/16, 56.0.0.0/8",
|
||||
"nginx.ingress.kubernetes.io/whitelist-source-range": "18.0.0.0/8, 55.0.0.0/8",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, namespace, framework.EchoService, 80, annotations)
|
||||
|
||||
// Temporarily trust forwarded headers so we can test IP based access control
|
||||
f.UpdateNginxConfigMapData("use-forwarded-headers", "true")
|
||||
defer func() {
|
||||
// Return to the original value
|
||||
f.UpdateNginxConfigMapData("use-forwarded-headers", "false")
|
||||
}()
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, "deny 18.1.0.0/16;") &&
|
||||
strings.Contains(server, "deny 56.0.0.0/8;") &&
|
||||
strings.Contains(server, "allow 18.0.0.0/8;") &&
|
||||
strings.Contains(server, "allow 55.0.0.0/8;") &&
|
||||
strings.Contains(server, "deny all;")
|
||||
})
|
||||
|
||||
ginkgo.By("sending request from an explicitly denied IP range")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "18.1.0.1").
|
||||
Expect().
|
||||
Status(http.StatusForbidden)
|
||||
|
||||
ginkgo.By("sending request from an implicitly denied IP")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "10.10.10.10").
|
||||
Expect().
|
||||
Status(http.StatusForbidden)
|
||||
|
||||
ginkgo.By("sending request from an explicitly allowed IP range")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "18.4.0.1").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
ginkgo.By("sending request from an explicitly allowed IP range")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("X-Forwarded-For", "55.55.55.55").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
})
|
||||
})
|
107
test/e2e/settings/disable_sync_events.go
Normal file
107
test/e2e/settings/disable_sync_events.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.IngressNginxDescribe("[Flag] disable-sync-events", func() {
|
||||
f := framework.NewDefaultFramework("disable-sync-events")
|
||||
|
||||
ginkgo.It("should create sync events (default)", func() {
|
||||
host := "sync-events-default"
|
||||
f.NewEchoDeployment(framework.WithDeploymentReplicas(1))
|
||||
|
||||
ing := framework.NewSingleIngressWithIngressClass(host, "/", host, f.Namespace, framework.EchoService, f.IngressClass, 80, nil)
|
||||
ing = f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %v", host))
|
||||
})
|
||||
|
||||
events, err := f.KubeClientSet.CoreV1().Events(ing.Namespace).List(context.TODO(), metav1.ListOptions{FieldSelector: "reason=Sync,involvedObject.name=" + host})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "listing events")
|
||||
|
||||
assert.NotEmpty(ginkgo.GinkgoT(), events.Items, "got events")
|
||||
})
|
||||
|
||||
ginkgo.It("should create sync events", func() {
|
||||
host := "disable-sync-events-false"
|
||||
f.NewEchoDeployment(framework.WithDeploymentReplicas(1))
|
||||
|
||||
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
|
||||
args := deployment.Spec.Template.Spec.Containers[0].Args
|
||||
args = append(args, "--disable-sync-events=false")
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = args
|
||||
_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||
return err
|
||||
})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
|
||||
|
||||
ing := framework.NewSingleIngressWithIngressClass(host, "/", host, f.Namespace, framework.EchoService, f.IngressClass, 80, nil)
|
||||
ing = f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %v", host))
|
||||
})
|
||||
|
||||
events, err := f.KubeClientSet.CoreV1().Events(ing.Namespace).List(context.TODO(), metav1.ListOptions{FieldSelector: "reason=Sync,involvedObject.name=" + host})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "listing events")
|
||||
|
||||
assert.NotEmpty(ginkgo.GinkgoT(), events.Items, "got events")
|
||||
})
|
||||
|
||||
ginkgo.It("should not create sync events", func() {
|
||||
host := "disable-sync-events-true"
|
||||
f.NewEchoDeployment(framework.WithDeploymentReplicas(1))
|
||||
|
||||
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
|
||||
args := deployment.Spec.Template.Spec.Containers[0].Args
|
||||
args = append(args, "--disable-sync-events=true")
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = args
|
||||
_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||
return err
|
||||
})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
|
||||
|
||||
ing := framework.NewSingleIngressWithIngressClass(host, "/", host, f.Namespace, framework.EchoService, f.IngressClass, 80, nil)
|
||||
ing = f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %v", host))
|
||||
})
|
||||
|
||||
events, err := f.KubeClientSet.CoreV1().Events(ing.Namespace).List(context.TODO(), metav1.ListOptions{FieldSelector: "reason=Sync,involvedObject.name=" + host})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "listing events")
|
||||
|
||||
assert.Empty(ginkgo.GinkgoT(), events.Items, "got events")
|
||||
})
|
||||
|
||||
})
|
Loading…
Reference in a new issue