Merge branch 'main' into feature/topology_zones

This commit is contained in:
Tomas Hulata 2023-01-09 19:35:32 +01:00 committed by GitHub
commit 81148e7b3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 3839 additions and 64 deletions

24
.github/workflows/stale.yaml vendored Normal file
View 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
View file

@ -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/

View file

@ -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

View file

@ -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` | |

View file

@ -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

View file

@ -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 }}

View file

@ -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

View file

@ -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 }}

View file

@ -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/
##

View file

@ -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) |

View file

@ -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`

View file

@ -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.

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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")

View file

@ -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

View file

@ -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"

View file

@ -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),

View 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
}

View 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
}

View file

@ -895,6 +895,7 @@ func NewDefault() Configuration {
PreserveTrailingSlash: false,
SSLRedirect: true,
CustomHTTPErrors: []int{},
DenylistSourceRange: []string{},
WhitelistSourceRange: []string{},
SkipAccessLogURLs: []string{},
LimitRate: 0,

View file

@ -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

View file

@ -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{

View file

@ -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)

View file

@ -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",
})

View file

@ -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)

View file

@ -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

View file

@ -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",
})

View file

@ -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,

View file

@ -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

View file

@ -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
}

View file

@ -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 != "" {

View file

@ -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

View 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)
})
})

View 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")
})
})