Merge remote-tracking branch 'upstream/master'
8
Makefile
|
@ -232,11 +232,15 @@ dep-ensure: check-go-version ## Update and vendo go dependencies.
|
||||||
|
|
||||||
.PHONY: dev-env
|
.PHONY: dev-env
|
||||||
dev-env: check-go-version ## Starts a local Kubernetes cluster using minikube, building and deploying the ingress controller.
|
dev-env: check-go-version ## Starts a local Kubernetes cluster using minikube, building and deploying the ingress controller.
|
||||||
@DIND_TASKS=0 USE_DOCKER=false build/dev-env.sh
|
@build/dev-env.sh
|
||||||
|
|
||||||
.PHONY: live-docs
|
.PHONY: live-docs
|
||||||
live-docs: ## Build and launch a local copy of the documentation website in http://localhost:3000
|
live-docs: ## Build and launch a local copy of the documentation website in http://localhost:3000
|
||||||
@docker build --pull -t ingress-nginx/mkdocs images/mkdocs
|
@docker buildx build \
|
||||||
|
--pull \
|
||||||
|
--load \
|
||||||
|
--progress plain \
|
||||||
|
-t ingress-nginx/mkdocs images/mkdocs
|
||||||
@docker run --rm -it -p 3000:3000 -v ${PWD}:/docs ingress-nginx/mkdocs
|
@docker run --rm -it -p 3000:3000 -v ${PWD}:/docs ingress-nginx/mkdocs
|
||||||
|
|
||||||
.PHONY: build-docs
|
.PHONY: build-docs
|
||||||
|
|
100
build/dev-env.sh
|
@ -22,10 +22,7 @@ set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
NAMESPACE="${NAMESPACE:-ingress-nginx}"
|
DIR=$(cd $(dirname "${BASH_SOURCE}") && pwd -P)
|
||||||
echo "NAMESPACE is set to ${NAMESPACE}"
|
|
||||||
|
|
||||||
kubectl config use-context minikube
|
|
||||||
|
|
||||||
export TAG=dev
|
export TAG=dev
|
||||||
export ARCH=amd64
|
export ARCH=amd64
|
||||||
|
@ -33,46 +30,77 @@ export REGISTRY=${REGISTRY:-ingress-controller}
|
||||||
|
|
||||||
DEV_IMAGE=${REGISTRY}/nginx-ingress-controller:${TAG}
|
DEV_IMAGE=${REGISTRY}/nginx-ingress-controller:${TAG}
|
||||||
|
|
||||||
{ [ "$(minikube status | grep -c Running)" -ge 2 ] && minikube status | grep -qE ': Configured$|Correctly Configured'; } \
|
if ! command -v kind &> /dev/null; then
|
||||||
|| minikube start \
|
echo "kind is not installed"
|
||||||
--extra-config=kubelet.sync-frequency=1s \
|
echo "Use a package manager or visit the official site https://kind.sigs.k8s.io"
|
||||||
--extra-config=apiserver.authorization-mode=RBAC
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC2046
|
if ! command -v kubectl &> /dev/null; then
|
||||||
eval $(minikube docker-env --shell bash)
|
echo "Please install kubectl 1.15 or higher"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KUBE_CLIENT_VERSION=$(kubectl version --client --short | awk '{print $3}' | cut -d. -f2) || true
|
||||||
|
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then
|
||||||
|
echo "Please update kubectl to 1.15 or higher"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[dev-env] building container"
|
echo "[dev-env] building container"
|
||||||
make build container
|
make build container
|
||||||
docker tag "${REGISTRY}/nginx-ingress-controller-${ARCH}:${TAG}" "${DEV_IMAGE}"
|
docker tag "${REGISTRY}/nginx-ingress-controller-${ARCH}:${TAG}" "${DEV_IMAGE}"
|
||||||
|
|
||||||
# kubectl >= 1.14 includes Kustomize via "apply -k". Makes it easier to use on Linux as well, assuming kubectl installed
|
export K8S_VERSION=${K8S_VERSION:-v1.17.2@sha256:59df31fc61d1da5f46e8a61ef612fa53d3f9140f82419d1ef1a6b9656c6b737c}
|
||||||
KUBE_CLIENT_VERSION=$(kubectl version --client --short | awk '{print $3}' | cut -d. -f2) || true
|
|
||||||
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then
|
|
||||||
for tool in kubectl kustomize; do
|
|
||||||
echo "[dev-env] installing $tool"
|
|
||||||
$tool version || brew install $tool
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! kubectl get namespace "${NAMESPACE}"; then
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
kubectl create namespace "${NAMESPACE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
kubectl get deploy nginx-ingress-controller -n "${NAMESPACE}" && kubectl delete deploy nginx-ingress-controller -n "${NAMESPACE}"
|
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
||||||
|
|
||||||
ROOT=./deploy/minikube
|
if ! kind get clusters -q | grep -q ${KIND_CLUSTER_NAME}; then
|
||||||
|
echo "[dev-env] creating Kubernetes cluster with kind"
|
||||||
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then
|
cat <<EOF | kind create cluster --name ${KIND_CLUSTER_NAME} --config=-
|
||||||
pushd $ROOT
|
kind: Cluster
|
||||||
kustomize edit set namespace "${NAMESPACE}"
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
kustomize edit set image "quay.io/kubernetes-ingress-controller/nginx-ingress-controller=${DEV_IMAGE}"
|
nodes:
|
||||||
popd
|
- role: control-plane
|
||||||
|
kubeadmConfigPatches:
|
||||||
echo "[dev-env] deploying NGINX Ingress controller in namespace $NAMESPACE"
|
- |
|
||||||
kustomize build $ROOT | kubectl apply -f -
|
kind: InitConfiguration
|
||||||
|
nodeRegistration:
|
||||||
|
kubeletExtraArgs:
|
||||||
|
node-labels: "ingress-ready=true"
|
||||||
|
authorization-mode: "AlwaysAllow"
|
||||||
|
extraPortMappings:
|
||||||
|
- containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- containerPort: 443
|
||||||
|
hostPort: 443
|
||||||
|
protocol: TCP
|
||||||
|
EOF
|
||||||
else
|
else
|
||||||
sed -i -e "s|^namespace: .*|namespace: ${NAMESPACE}|g" "${ROOT}/kustomization.yaml"
|
echo "[dev-env] using existing Kubernetes kind cluster"
|
||||||
|
|
||||||
echo "[dev-env] deploying NGINX Ingress controller in namespace $NAMESPACE"
|
|
||||||
kubectl apply -k "${ROOT}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "[dev-env] copying docker images to cluster..."
|
||||||
|
kind load docker-image --name="${KIND_CLUSTER_NAME}" "${DEV_IMAGE}"
|
||||||
|
|
||||||
|
echo "[dev-env] deploying NGINX Ingress controller..."
|
||||||
|
kubectl create namespace ingress-nginx || true
|
||||||
|
kubectl apply -k ${DIR}/../deploy/kind
|
||||||
|
|
||||||
|
echo "[dev-env] deleting old ingress-nginx pods..."
|
||||||
|
MINUTE_AGO=$(python -c "from datetime import datetime,timedelta; print((datetime.utcnow()-timedelta(seconds=60)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
||||||
|
kubectl get pods --namespace ingress-nginx -o go-template \
|
||||||
|
--template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}' | \
|
||||||
|
awk -v MINUTE_AGO=$MINUTE_AGO '$2 <= MINUTE_AGO { print $1 }' | \
|
||||||
|
xargs kubectl delete pod --namespace ingress-nginx
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Kubernetes cluster ready and ingress-nginx listening in localhost using ports 80 and 443
|
||||||
|
|
||||||
|
To delete the dev cluster execute: 'kind delete cluster --name ingress-nginx-dev'
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
|
@ -45,13 +45,6 @@ FLAGS=$@
|
||||||
PKG=k8s.io/ingress-nginx
|
PKG=k8s.io/ingress-nginx
|
||||||
ARCH=$(go env GOARCH)
|
ARCH=$(go env GOARCH)
|
||||||
|
|
||||||
MINIKUBE_PATH=${HOME}/.minikube
|
|
||||||
MINIKUBE_VOLUME="-v ${MINIKUBE_PATH}:${MINIKUBE_PATH}"
|
|
||||||
if [ ! -d "${MINIKUBE_PATH}" ]; then
|
|
||||||
echo "Minikube directory not found! Volume will be excluded from docker build."
|
|
||||||
MINIKUBE_VOLUME=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# create output directory as current user to avoid problem with docker.
|
# create output directory as current user to avoid problem with docker.
|
||||||
mkdir -p "${KUBE_ROOT}/bin" "${KUBE_ROOT}/bin/${ARCH}"
|
mkdir -p "${KUBE_ROOT}/bin" "${KUBE_ROOT}/bin/${ARCH}"
|
||||||
|
|
||||||
|
@ -67,7 +60,6 @@ docker run \
|
||||||
-v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" \
|
-v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" \
|
||||||
-v "/var/run/docker.sock:/var/run/docker.sock" \
|
-v "/var/run/docker.sock:/var/run/docker.sock" \
|
||||||
-v "${INGRESS_VOLUME}:/etc/ingress-controller/" \
|
-v "${INGRESS_VOLUME}:/etc/ingress-controller/" \
|
||||||
${MINIKUBE_VOLUME} \
|
|
||||||
-w "/go/src/${PKG}" \
|
-w "/go/src/${PKG}" \
|
||||||
-u $(id -u ${USER}):$(id -g ${USER}) \
|
-u $(id -u ${USER}):$(id -g ${USER}) \
|
||||||
${E2E_IMAGE} /bin/bash -c "${FLAGS}"
|
${E2E_IMAGE} /bin/bash -c "${FLAGS}"
|
||||||
|
|
|
@ -94,11 +94,6 @@ until curl --output /dev/null -fsSL http://localhost:8001/; do
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
MINIKUBE_VOLUME=
|
|
||||||
if [[ -d "${HOME}/.minikube" ]]; then
|
|
||||||
MINIKUBE_VOLUME=" -v ${HOME}/.minikube:${HOME}/.minikube "
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if we run as user we cannot bind to port 80 and 443
|
# if we run as user we cannot bind to port 80 and 443
|
||||||
docker run \
|
docker run \
|
||||||
--rm \
|
--rm \
|
||||||
|
@ -109,7 +104,6 @@ docker run \
|
||||||
-e POD_NAME="${POD_NAME}" \
|
-e POD_NAME="${POD_NAME}" \
|
||||||
-v "${SSL_VOLUME}:/etc/ingress-controller/ssl/" \
|
-v "${SSL_VOLUME}:/etc/ingress-controller/ssl/" \
|
||||||
-v "${HOME}/.kube:${HOME}/.kube:ro" \
|
-v "${HOME}/.kube:${HOME}/.kube:ro" \
|
||||||
${MINIKUBE_VOLUME} \
|
|
||||||
"${IMAGE}-${ARCH}:${TAG}" /nginx-ingress-controller \
|
"${IMAGE}-${ARCH}:${TAG}" /nginx-ingress-controller \
|
||||||
--update-status=false \
|
--update-status=false \
|
||||||
--v=2 \
|
--v=2 \
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/controller"
|
"k8s.io/ingress-nginx/internal/ingress/controller"
|
||||||
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||||
|
"k8s.io/ingress-nginx/internal/ingress/status"
|
||||||
ing_net "k8s.io/ingress-nginx/internal/net"
|
ing_net "k8s.io/ingress-nginx/internal/net"
|
||||||
"k8s.io/ingress-nginx/internal/nginx"
|
"k8s.io/ingress-nginx/internal/nginx"
|
||||||
)
|
)
|
||||||
|
@ -175,6 +176,8 @@ Takes the form "<host>:port". If not provided, no admission controller is starte
|
||||||
streamPort = flags.Int("stream-port", 10247, "Port to use for the lua TCP/UDP endpoint configuration.")
|
streamPort = flags.Int("stream-port", 10247, "Port to use for the lua TCP/UDP endpoint configuration.")
|
||||||
|
|
||||||
profilerPort = flags.Int("profiler-port", 10245, "Port to use for expose the ingress controller Go profiler when it is enabled.")
|
profilerPort = flags.Int("profiler-port", 10245, "Port to use for expose the ingress controller Go profiler when it is enabled.")
|
||||||
|
|
||||||
|
statusUpdateInterval = flags.Int("status-update-interval", status.UpdateInterval, "Time interval in seconds in which the status should check if an update is required. Default is 60 seconds")
|
||||||
)
|
)
|
||||||
|
|
||||||
flags.MarkDeprecated("force-namespace-isolation", `This flag doesn't do anything.`)
|
flags.MarkDeprecated("force-namespace-isolation", `This flag doesn't do anything.`)
|
||||||
|
@ -201,6 +204,13 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *statusUpdateInterval < 5 {
|
||||||
|
klog.Warningf("The defined time to update the Ingress status too low (%v seconds). Adjusting to 5 seconds", *statusUpdateInterval)
|
||||||
|
status.UpdateInterval = 5
|
||||||
|
} else {
|
||||||
|
status.UpdateInterval = *statusUpdateInterval
|
||||||
|
}
|
||||||
|
|
||||||
if *ingressClass != "" {
|
if *ingressClass != "" {
|
||||||
klog.Infof("Watching for Ingress class: %s", *ingressClass)
|
klog.Infof("Watching for Ingress class: %s", *ingressClass)
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 606 KiB After Width: | Height: | Size: 329 KiB |
|
@ -7,3 +7,5 @@ bases:
|
||||||
images:
|
images:
|
||||||
- name: quay.io/kubernetes-ingress-controller/nginx-ingress-controller
|
- name: quay.io/kubernetes-ingress-controller/nginx-ingress-controller
|
||||||
newTag: dev
|
newTag: dev
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- service-hostport.yaml
|
25
deploy/kind/service-hostport.yaml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-ingress-controller
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/port: "10254"
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx-ingress-controller
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
- containerPort: 443
|
||||||
|
hostPort: 443
|
||||||
|
nodeSelector:
|
||||||
|
ingress-ready: "true"
|
||||||
|
tolerations:
|
||||||
|
- key: node-role.kubernetes.io/master
|
||||||
|
operator: Equal
|
||||||
|
effect: NoSchedule
|
|
@ -78,7 +78,6 @@ minikube addons disable ingress
|
||||||
```console
|
```console
|
||||||
$ kubectl get pods -n ingress-nginx
|
$ kubectl get pods -n ingress-nginx
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
default-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s
|
|
||||||
nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s
|
nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,6 @@ cd ingress-nginx
|
||||||
|
|
||||||
### Initial developer environment build
|
### Initial developer environment build
|
||||||
|
|
||||||
>**Prequisites**: Minikube must be installed.
|
|
||||||
See [releases](https://github.com/kubernetes/minikube/releases) for installation instructions.
|
|
||||||
|
|
||||||
If you are using **MacOS** and deploying to **minikube**, the following command will build the local nginx controller container image and deploy the ingress controller onto a minikube cluster with RBAC enabled in the namespace `ingress-nginx`:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ make dev-env
|
$ make dev-env
|
||||||
```
|
```
|
||||||
|
|
|
@ -40,7 +40,7 @@ If you do not already have an instance of the NGINX Ingress controller running,
|
||||||
ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m
|
ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Note
|
!!! note
|
||||||
The `ingress-nginx` Service is of type `ClusterIP` in this example. This may vary depending on your environment.
|
The `ingress-nginx` Service is of type `ClusterIP` in this example. This may vary depending on your environment.
|
||||||
Make sure you can use the Service to reach NGINX before proceeding with the rest of this example.
|
Make sure you can use the Service to reach NGINX before proceeding with the rest of this example.
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/exam
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
Running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.
|
Running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.
|
||||||
|
|
||||||
Please check [deploy a plain http registry](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry)
|
Please check [deploy a plain http registry](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry)
|
||||||
|
|
||||||
### With TLS
|
### With TLS
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: fortune-teller-app
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 60 KiB |
|
@ -44,6 +44,7 @@ They are set in the container spec of the `nginx-ingress-controller` Deployment
|
||||||
| `--udp-services-configmap string` | Name of the ConfigMap containing the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is a reference to a Service in the form "namespace/name:port", where "port" can either be a port name or number. |
|
| `--udp-services-configmap string` | Name of the ConfigMap containing the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is a reference to a Service in the form "namespace/name:port", where "port" can either be a port name or number. |
|
||||||
| `--update-status` | Update the load-balancer status of Ingress objects this controller satisfies. Requires setting the publish-service parameter to a valid Service reference. (default true) |
|
| `--update-status` | Update the load-balancer status of Ingress objects this controller satisfies. Requires setting the publish-service parameter to a valid Service reference. (default true) |
|
||||||
| `--update-status-on-shutdown` | Update the load-balancer status of Ingress objects when the controller shuts down. Requires the update-status parameter. (default true) |
|
| `--update-status-on-shutdown` | Update the load-balancer status of Ingress objects when the controller shuts down. Requires the update-status parameter. (default true) |
|
||||||
|
| `--status-update-interval` | Time interval in seconds in which the status should check if an update is required. (default 60 seconds) |
|
||||||
| `-v`, `--v Level` | log level for V logs |
|
| `-v`, `--v Level` | log level for V logs |
|
||||||
| `--version` | Show release information about the NGINX Ingress controller and exit. |
|
| `--version` | Show release information about the NGINX Ingress controller and exit. |
|
||||||
| `--vmodule moduleSpec` | comma-separated list of pattern=N settings for file-filtered logging |
|
| `--vmodule moduleSpec` | comma-separated list of pattern=N settings for file-filtered logging |
|
||||||
|
|
|
@ -79,15 +79,13 @@ spec:
|
||||||
servicePort: fastcgi
|
servicePort: fastcgi
|
||||||
```
|
```
|
||||||
|
|
||||||
## The FastCGI Ingress Annotations
|
## FastCGI Ingress Annotations
|
||||||
|
|
||||||
### The `nginx.ingress.kubernetes.io/backend-protocol` Annotation
|
To enable FastCGI, the `nginx.ingress.kubernetes.io/backend-protocol` annotation needs to be set to `FCGI`, which overrides the default `HTTP` value.
|
||||||
|
|
||||||
To enable FastCGI, the `backend-protocol` annotation needs to be set to `FCGI`, which overrides the default `HTTP` value.
|
|
||||||
|
|
||||||
> `nginx.ingress.kubernetes.io/backend-protocol: "FCGI"`
|
> `nginx.ingress.kubernetes.io/backend-protocol: "FCGI"`
|
||||||
|
|
||||||
This enables the _FastCGI_ mode for the whole _Ingress_ object.
|
**This enables the _FastCGI_ mode for all paths defined in the _Ingress_ object**
|
||||||
|
|
||||||
### The `nginx.ingress.kubernetes.io/fastcgi-index` Annotation
|
### The `nginx.ingress.kubernetes.io/fastcgi-index` Annotation
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ The ingress controller supports **case insensitive** regular expressions in the
|
||||||
This can be enabled by setting the `nginx.ingress.kubernetes.io/use-regex` annotation to `true` (the default is false).
|
This can be enabled by setting the `nginx.ingress.kubernetes.io/use-regex` annotation to `true` (the default is false).
|
||||||
|
|
||||||
!!! hint
|
!!! hint
|
||||||
Kubernetes only accept expressions that comply with the RE2 engine syntax. It is possible that valid expressions accepted by NGINX cannot be used with ingress-nginx, because the PCRE library (used in NGINX) supports a wider syntax than RE2.
|
Kubernetes only accept expressions that comply with the RE2 engine syntax. It is possible that valid expressions accepted by NGINX cannot be used with ingress-nginx, because the PCRE library (used in NGINX) supports a wider syntax than RE2.
|
||||||
See the [RE2 Syntax](https://github.com/google/re2/wiki/Syntax) documentation for differences.
|
See the [RE2 Syntax](https://github.com/google/re2/wiki/Syntax) documentation for differences.
|
||||||
|
|
||||||
See the [description](./nginx-configuration/annotations.md#use-regex) of the `use-regex` annotation for more details.
|
See the [description](./nginx-configuration/annotations.md#use-regex) of the `use-regex` annotation for more details.
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ If you use the ``cookie`` affinity type you can also specify the name of the coo
|
||||||
|
|
||||||
The NGINX annotation `nginx.ingress.kubernetes.io/session-cookie-path` defines the path that will be set on the cookie. This is optional unless the annotation `nginx.ingress.kubernetes.io/use-regex` is set to true; Session cookie paths do not support regex.
|
The NGINX annotation `nginx.ingress.kubernetes.io/session-cookie-path` defines the path that will be set on the cookie. This is optional unless the annotation `nginx.ingress.kubernetes.io/use-regex` is set to true; Session cookie paths do not support regex.
|
||||||
|
|
||||||
Use `nginx.ingress.kubernetes.io/session-cookie-samesite` to apply a `SameSite` attribute to the sticky cookie. Browser accepted values are `None`, `Lax`, and `Strict`. Some older browsers reject cookies with the more-recently-defined `SameSite=None`. To omit `SameSite=None` from these older browsers, add the annotation `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"`.
|
Use `nginx.ingress.kubernetes.io/session-cookie-samesite` to apply a `SameSite` attribute to the sticky cookie. Browser accepted values are `None`, `Lax`, and `Strict`. Some browsers reject cookies with `SameSite=None`, including those created before the `SameSite=None` specification (e.g. Chrome 5X). Other browsers mistakenly treat `SameSite=None` cookies as `SameSite=Strict` (e.g. Safari running on OSX 14). To omit `SameSite=None` from browsers with these incompatibilities, add the annotation `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"`.
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ Enables automatic conversion of preload links specified in the “Link” respon
|
||||||
Allows the definition of one or more aliases in the server definition of the NGINX configuration using the annotation `nginx.ingress.kubernetes.io/server-alias: "<alias 1>,<alias 2>"`.
|
Allows the definition of one or more aliases in the server definition of the NGINX configuration using the annotation `nginx.ingress.kubernetes.io/server-alias: "<alias 1>,<alias 2>"`.
|
||||||
This will create a server with the same configuration, but adding new values to the `server_name` directive.
|
This will create a server with the same configuration, but adding new values to the `server_name` directive.
|
||||||
|
|
||||||
!!! Note
|
!!! note
|
||||||
A server-alias name cannot conflict with the hostname of an existing server. If it does, the server-alias annotation will be ignored.
|
A server-alias name cannot conflict with the hostname of an existing server. If it does, the server-alias annotation will be ignored.
|
||||||
If a server-alias is created and later a new server with the same hostname is created, the new server configuration will take
|
If a server-alias is created and later a new server with the same hostname is created, the new server configuration will take
|
||||||
place over the alias configuration.
|
place over the alias configuration.
|
||||||
|
@ -446,7 +446,8 @@ By default the controller redirects all requests to an existing service that pro
|
||||||
`nginx.ingress.kubernetes.io/enable-global-auth`:
|
`nginx.ingress.kubernetes.io/enable-global-auth`:
|
||||||
indicates if GlobalExternalAuth configuration should be applied or not to this Ingress rule. Default values is set to `"true"`.
|
indicates if GlobalExternalAuth configuration should be applied or not to this Ingress rule. Default values is set to `"true"`.
|
||||||
|
|
||||||
!!! note For more information please see [global-auth-url](./configmap.md#global-auth-url).
|
!!! note
|
||||||
|
For more information please see [global-auth-url](./configmap.md#global-auth-url).
|
||||||
|
|
||||||
### Rate limiting
|
### Rate limiting
|
||||||
|
|
||||||
|
@ -837,7 +838,7 @@ nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
||||||
### Use Regex
|
### Use Regex
|
||||||
|
|
||||||
!!! attention
|
!!! attention
|
||||||
When using this annotation with the NGINX annotation `nginx.ingress.kubernetes.io/affinity` of type `cookie`, `nginx.ingress.kubernetes.io/session-cookie-path` must be also set; Session cookie paths do not support regex.
|
When using this annotation with the NGINX annotation `nginx.ingress.kubernetes.io/affinity` of type `cookie`, `nginx.ingress.kubernetes.io/session-cookie-path` must be also set; Session cookie paths do not support regex.
|
||||||
|
|
||||||
Using the `nginx.ingress.kubernetes.io/use-regex` annotation will indicate whether or not the paths defined on an Ingress use regular expressions. The default value is `false`.
|
Using the `nginx.ingress.kubernetes.io/use-regex` annotation will indicate whether or not the paths defined on an Ingress use regular expressions. The default value is `false`.
|
||||||
|
|
||||||
|
@ -885,4 +886,4 @@ nginx.ingress.kubernetes.io/mirror-request-body: "off"
|
||||||
|
|
||||||
The request sent to the mirror is linked to the orignial request. If you have a slow mirror backend, then the orignial request will throttle.
|
The request sent to the mirror is linked to the orignial request. If you have a slow mirror backend, then the orignial request will throttle.
|
||||||
|
|
||||||
For more information on the mirror module see https://nginx.org/en/docs/http/ngx_http_mirror_module.html
|
For more information on the mirror module see [ngx_http_mirror_module](https://nginx.org/en/docs/http/ngx_http_mirror_module.html)
|
||||||
|
|
|
@ -14,7 +14,7 @@ data:
|
||||||
ssl-protocols: SSLv2
|
ssl-protocols: SSLv2
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Important
|
!!! important
|
||||||
The key and values in a ConfigMap can only be strings.
|
The key and values in a ConfigMap can only be strings.
|
||||||
This means that we want a value with boolean values we need to quote the values, like "true" or "false".
|
This means that we want a value with boolean values we need to quote the values, like "true" or "false".
|
||||||
Same for numbers, like "100".
|
Same for numbers, like "100".
|
||||||
|
@ -567,7 +567,7 @@ Since `0.27.0` and due to a [change in the MaxMind databases](https://blog.maxmi
|
||||||
For this reason, it is required to define a new flag `--maxmind-license-key` in the ingress controller deployment to download the databases needed during the initialization of the ingress controller.
|
For this reason, it is required to define a new flag `--maxmind-license-key` in the ingress controller deployment to download the databases needed during the initialization of the ingress controller.
|
||||||
Alternatively, it is possible to use a volume to mount the files `/etc/nginx/geoip/GeoLite2-City.mmdb` and `/etc/nginx/geoip/GeoLite2-ASN.mmdb`, avoiding the overhead of the download.
|
Alternatively, it is possible to use a volume to mount the files `/etc/nginx/geoip/GeoLite2-City.mmdb` and `/etc/nginx/geoip/GeoLite2-ASN.mmdb`, avoiding the overhead of the download.
|
||||||
|
|
||||||
!!! Important
|
!!! important
|
||||||
If the feature is enabled but the files are missing, GeoIP2 will not be enabled.
|
If the feature is enabled but the files are missing, GeoIP2 will not be enabled.
|
||||||
|
|
||||||
_**default:**_ false
|
_**default:**_ false
|
||||||
|
|
|
@ -100,8 +100,7 @@ All these options (including host) allow environment variables, such as `$HOSTNA
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
The following examples show how to deploy and test different distributed tracing systems. These example can be performed
|
The following examples show how to deploy and test different distributed tracing systems. These example can be performed using Minikube.
|
||||||
using Minikube.
|
|
||||||
|
|
||||||
### Zipkin
|
### Zipkin
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ or per-Ingress with the `nginx.ingress.kubernetes.io/ssl-redirect: "false"`
|
||||||
annotation in the particular resource.
|
annotation in the particular resource.
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
|
|
||||||
When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a
|
When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a
|
||||||
redirect to HTTPS even when there is no TLS certificate available.
|
redirect to HTTPS even when there is no TLS certificate available.
|
||||||
This can be achieved by using the `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"`
|
This can be achieved by using the `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"`
|
||||||
|
|
|
@ -218,8 +218,8 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
return nil, ing_errors.NewLocationDenied(fmt.Sprintf("unable to find configMap %q", proxySetHeaderMap))
|
return nil, ing_errors.NewLocationDenied(fmt.Sprintf("unable to find configMap %q", proxySetHeaderMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
for header, value := range proxySetHeadersMapContents.Data {
|
for header := range proxySetHeadersMapContents.Data {
|
||||||
if !ValidHeader(header) || !ValidHeader(value) {
|
if !ValidHeader(header) {
|
||||||
return nil, ing_errors.NewLocationDenied("invalid proxy-set-headers in configmap")
|
return nil, ing_errors.NewLocationDenied("invalid proxy-set-headers in configmap")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,8 +276,8 @@ func TestProxySetHeaders(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"single header", "http://goog.url", map[string]string{"header": "h1"}, false},
|
{"single header", "http://goog.url", map[string]string{"header": "h1"}, false},
|
||||||
{"no header map", "http://goog.url", nil, true},
|
{"no header map", "http://goog.url", nil, true},
|
||||||
{"header with spaces", "http://goog.url", map[string]string{"header": "bad value"}, true},
|
{"header with spaces", "http://goog.url", map[string]string{"header": "bad value"}, false},
|
||||||
{"header with other bad symbols", "http://goog.url", map[string]string{"header": "bad+value"}, true},
|
{"header with other bad symbols", "http://goog.url", map[string]string{"header": "bad+value"}, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
@ -82,6 +82,7 @@ func (a mirror) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
config.Target, err = parser.GetStringAnnotation("mirror-target", ing)
|
config.Target, err = parser.GetStringAnnotation("mirror-target", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
config.Target = ""
|
config.Target = ""
|
||||||
|
config.Source = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|
|
@ -47,7 +47,7 @@ func TestParse(t *testing.T) {
|
||||||
Target: "https://test.env.com/$request_uri",
|
Target: "https://test.env.com/$request_uri",
|
||||||
}},
|
}},
|
||||||
{map[string]string{requestBody: "off"}, &Config{
|
{map[string]string{requestBody: "off"}, &Config{
|
||||||
Source: ngxURI,
|
Source: "",
|
||||||
RequestBody: "off",
|
RequestBody: "off",
|
||||||
Target: "",
|
Target: "",
|
||||||
}},
|
}},
|
||||||
|
|
|
@ -535,18 +535,39 @@ func New(
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
cm := obj.(*corev1.ConfigMap)
|
cm := obj.(*corev1.ConfigMap)
|
||||||
key := k8s.MetaNamespaceKey(cm)
|
key := k8s.MetaNamespaceKey(cm)
|
||||||
|
|
||||||
|
triggerUpdate := false
|
||||||
|
|
||||||
// updates to configuration configmaps can trigger an update
|
// updates to configuration configmaps can trigger an update
|
||||||
if changeTriggerUpdate(key) {
|
if changeTriggerUpdate(key) {
|
||||||
recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key))
|
recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key))
|
||||||
|
triggerUpdate = true
|
||||||
if key == configmap {
|
if key == configmap {
|
||||||
store.setConfig(cm)
|
store.setConfig(cm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCh.In() <- Event{
|
ings := store.listers.IngressWithAnnotation.List()
|
||||||
Type: ConfigurationEvent,
|
for _, ingKey := range ings {
|
||||||
Obj: obj,
|
key := k8s.MetaNamespaceKey(ingKey)
|
||||||
|
ing, err := store.getIngress(key)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("could not find Ingress %v in local store: %v", key, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if parser.AnnotationsReferencesConfigmap(ing) {
|
||||||
|
recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key))
|
||||||
|
store.syncIngress(ing)
|
||||||
|
triggerUpdate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if triggerUpdate {
|
||||||
|
updateCh.In() <- Event{
|
||||||
|
Type: ConfigurationEvent,
|
||||||
|
Obj: obj,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UpdateFunc: func(old, cur interface{}) {
|
UpdateFunc: func(old, cur interface{}) {
|
||||||
|
|
|
@ -275,6 +275,7 @@ func configForLua(input interface{}) string {
|
||||||
|
|
||||||
return fmt.Sprintf(`{
|
return fmt.Sprintf(`{
|
||||||
use_forwarded_headers = %t,
|
use_forwarded_headers = %t,
|
||||||
|
use_proxy_protocol = %t,
|
||||||
is_ssl_passthrough_enabled = %t,
|
is_ssl_passthrough_enabled = %t,
|
||||||
http_redirect_code = %v,
|
http_redirect_code = %v,
|
||||||
listen_ports = { ssl_proxy = "%v", https = "%v" },
|
listen_ports = { ssl_proxy = "%v", https = "%v" },
|
||||||
|
@ -285,6 +286,7 @@ func configForLua(input interface{}) string {
|
||||||
hsts_preload = %t,
|
hsts_preload = %t,
|
||||||
}`,
|
}`,
|
||||||
all.Cfg.UseForwardedHeaders,
|
all.Cfg.UseForwardedHeaders,
|
||||||
|
all.Cfg.UseProxyProtocol,
|
||||||
all.IsSSLPassthroughEnabled,
|
all.IsSSLPassthroughEnabled,
|
||||||
all.Cfg.HTTPRedirectCode,
|
all.Cfg.HTTPRedirectCode,
|
||||||
all.ListenPorts.SSLProxy,
|
all.ListenPorts.SSLProxy,
|
||||||
|
|
|
@ -40,9 +40,9 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/task"
|
"k8s.io/ingress-nginx/internal/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// UpdateInterval defines the time interval, in seconds, in
|
||||||
updateInterval = 60 * time.Second
|
// which the status should check if an update is required.
|
||||||
)
|
var UpdateInterval = 60
|
||||||
|
|
||||||
// Syncer ...
|
// Syncer ...
|
||||||
type Syncer interface {
|
type Syncer interface {
|
||||||
|
@ -98,7 +98,7 @@ func (s statusSync) Run(stopCh chan struct{}) {
|
||||||
|
|
||||||
// when this instance is the leader we need to enqueue
|
// when this instance is the leader we need to enqueue
|
||||||
// an item to trigger the update of the Ingress status.
|
// an item to trigger the update of the Ingress status.
|
||||||
wait.PollUntil(updateInterval, func() (bool, error) {
|
wait.PollUntil(time.Duration(UpdateInterval)*time.Second, func() (bool, error) {
|
||||||
s.syncQueue.EnqueueTask(task.GetDummyObject("sync status"))
|
s.syncQueue.EnqueueTask(task.GetDummyObject("sync status"))
|
||||||
return false, nil
|
return false, nil
|
||||||
}, stopCh)
|
}, stopCh)
|
||||||
|
|
34
labels.yaml
|
@ -1,34 +0,0 @@
|
||||||
repo: kubernetes/ingress
|
|
||||||
labels:
|
|
||||||
- name: area/api
|
|
||||||
color: ededed
|
|
||||||
- name: area/docs
|
|
||||||
color: 1d76db
|
|
||||||
- name: area/infra
|
|
||||||
color: bfdadc
|
|
||||||
- name: backend/gce
|
|
||||||
color: "5319e7"
|
|
||||||
- name: backend/generic
|
|
||||||
color: c2e0c6
|
|
||||||
- name: backend/nginx
|
|
||||||
color: c5def5
|
|
||||||
- name: bug
|
|
||||||
color: ee0701
|
|
||||||
- name: 'cncf-cla: no'
|
|
||||||
color: ededed
|
|
||||||
- name: 'cncf-cla: yes'
|
|
||||||
color: ededed
|
|
||||||
- name: duplicate
|
|
||||||
color: cccccc
|
|
||||||
- name: enhancement
|
|
||||||
color: 84b6eb
|
|
||||||
- name: help wanted
|
|
||||||
color: 128A0C
|
|
||||||
- name: invalid
|
|
||||||
color: e6e6e6
|
|
||||||
- name: lgtm
|
|
||||||
color: 15dd18
|
|
||||||
- name: question
|
|
||||||
color: cc317c
|
|
||||||
- name: wontfix
|
|
||||||
color: ffffff
|
|
|
@ -1,4 +1,4 @@
|
||||||
mkdocs-material~=4.4.0
|
mkdocs-material~=4.6.2
|
||||||
mkdocs~=1.0.4
|
mkdocs~=1.0.4
|
||||||
pymdown-extensions~=6.0
|
pymdown-extensions~=6.3
|
||||||
pygments~=2.3.1
|
pygments~=2.5.2
|
||||||
|
|
|
@ -54,15 +54,12 @@ function _M.set_cookie(self, value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if cookie_samesite then
|
|
||||||
cookie_path = cookie_path .. "; SameSite=" .. cookie_samesite
|
|
||||||
end
|
|
||||||
|
|
||||||
local cookie_data = {
|
local cookie_data = {
|
||||||
key = self:cookie_name(),
|
key = self:cookie_name(),
|
||||||
value = value,
|
value = value,
|
||||||
path = cookie_path,
|
path = cookie_path,
|
||||||
httponly = true,
|
httponly = true,
|
||||||
|
samesite = cookie_samesite,
|
||||||
secure = ngx.var.https == "on",
|
secure = ngx.var.https == "on",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,12 @@ function _M.rewrite(location_config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if config.use_proxy_protocol then
|
||||||
|
if ngx.var.proxy_protocol_server_port == "443" then
|
||||||
|
ngx.var.pass_access_scheme = "https"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
ngx.var.pass_port = ngx.var.pass_server_port
|
ngx.var.pass_port = ngx.var.pass_server_port
|
||||||
if config.is_ssl_passthrough_enabled then
|
if config.is_ssl_passthrough_enabled then
|
||||||
if ngx.var.pass_server_port == config.listen_ports.ssl_proxy then
|
if ngx.var.pass_server_port == config.listen_ports.ssl_proxy then
|
||||||
|
|
|
@ -114,6 +114,7 @@ describe("Sticky", function()
|
||||||
set = function(self, payload)
|
set = function(self, payload)
|
||||||
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
||||||
assert.equal(payload.path, ngx.var.location_path)
|
assert.equal(payload.path, ngx.var.location_path)
|
||||||
|
assert.equal(payload.samesite, nil)
|
||||||
assert.equal(payload.domain, nil)
|
assert.equal(payload.domain, nil)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
assert.equal(payload.secure, false)
|
assert.equal(payload.secure, false)
|
||||||
|
@ -143,6 +144,7 @@ describe("Sticky", function()
|
||||||
set = function(self, payload)
|
set = function(self, payload)
|
||||||
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
||||||
assert.equal(payload.path, ngx.var.location_path)
|
assert.equal(payload.path, ngx.var.location_path)
|
||||||
|
assert.equal(payload.samesite, nil)
|
||||||
assert.equal(payload.domain, nil)
|
assert.equal(payload.domain, nil)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
assert.equal(payload.secure, true)
|
assert.equal(payload.secure, true)
|
||||||
|
@ -185,6 +187,7 @@ describe("Sticky", function()
|
||||||
set = function(self, payload)
|
set = function(self, payload)
|
||||||
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
||||||
assert.equal(payload.path, ngx.var.location_path)
|
assert.equal(payload.path, ngx.var.location_path)
|
||||||
|
assert.equal(payload.samesite, nil)
|
||||||
assert.equal(payload.domain, nil)
|
assert.equal(payload.domain, nil)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
assert.equal(payload.secure, false)
|
assert.equal(payload.secure, false)
|
||||||
|
@ -228,6 +231,7 @@ describe("Sticky", function()
|
||||||
assert.equal(payload.path, ngx.var.location_path)
|
assert.equal(payload.path, ngx.var.location_path)
|
||||||
assert.equal(payload.domain, ngx.var.host)
|
assert.equal(payload.domain, ngx.var.host)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
|
assert.equal(payload.samesite, nil)
|
||||||
return true, nil
|
return true, nil
|
||||||
end,
|
end,
|
||||||
get = function(k) return false end,
|
get = function(k) return false end,
|
||||||
|
@ -368,6 +372,7 @@ describe("Sticky", function()
|
||||||
set = function(self, payload)
|
set = function(self, payload)
|
||||||
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
||||||
assert.equal(payload.path, ngx.var.location_path)
|
assert.equal(payload.path, ngx.var.location_path)
|
||||||
|
assert.equal(payload.samesite, nil)
|
||||||
assert.equal(payload.domain, nil)
|
assert.equal(payload.domain, nil)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
assert.equal(payload.secure, false)
|
assert.equal(payload.secure, false)
|
||||||
|
@ -405,13 +410,14 @@ describe("Sticky", function()
|
||||||
cookie.new = mocked_cookie_new
|
cookie.new = mocked_cookie_new
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local function test_set_cookie(sticky, samesite, conditional_samesite_none, expected_path)
|
local function test_set_cookie(sticky, samesite, conditional_samesite_none, expected_path, expected_samesite)
|
||||||
local s = {}
|
local s = {}
|
||||||
cookie.new = function(self)
|
cookie.new = function(self)
|
||||||
local cookie_instance = {
|
local cookie_instance = {
|
||||||
set = function(self, payload)
|
set = function(self, payload)
|
||||||
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
|
||||||
assert.equal(payload.path, expected_path)
|
assert.equal(payload.path, expected_path)
|
||||||
|
assert.equal(payload.samesite, expected_samesite)
|
||||||
assert.equal(payload.domain, nil)
|
assert.equal(payload.domain, nil)
|
||||||
assert.equal(payload.httponly, true)
|
assert.equal(payload.httponly, true)
|
||||||
assert.equal(payload.secure, false)
|
assert.equal(payload.secure, false)
|
||||||
|
@ -433,27 +439,27 @@ describe("Sticky", function()
|
||||||
end
|
end
|
||||||
|
|
||||||
it("returns a cookie with SameSite=Strict when user specifies samesite strict", function()
|
it("returns a cookie with SameSite=Strict when user specifies samesite strict", function()
|
||||||
test_set_cookie(sticky_balanced, "Strict", false, "/; SameSite=Strict")
|
test_set_cookie(sticky_balanced, "Strict", false, "/", "Strict")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function()
|
it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function()
|
||||||
test_set_cookie(sticky_balanced, "Strict", true, "/; SameSite=Strict")
|
test_set_cookie(sticky_balanced, "Strict", true, "/", "Strict")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie with SameSite=Lax when user specifies samesite lax", function()
|
it("returns a cookie with SameSite=Lax when user specifies samesite lax", function()
|
||||||
test_set_cookie(sticky_balanced, "Lax", false, "/; SameSite=Lax")
|
test_set_cookie(sticky_balanced, "Lax", false, "/", "Lax")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function()
|
it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function()
|
||||||
test_set_cookie(sticky_balanced, "Lax", true, "/; SameSite=Lax")
|
test_set_cookie(sticky_balanced, "Lax", true, "/", "Lax")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie with SameSite=None when user specifies samesite None", function()
|
it("returns a cookie with SameSite=None when user specifies samesite None", function()
|
||||||
test_set_cookie(sticky_balanced, "None", false, "/; SameSite=None")
|
test_set_cookie(sticky_balanced, "None", false, "/", "None")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function()
|
it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function()
|
||||||
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} })
|
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} })
|
||||||
test_set_cookie(sticky_balanced, "None", true, "/; SameSite=None")
|
test_set_cookie(sticky_balanced, "None", true, "/", "None")
|
||||||
end)
|
end)
|
||||||
it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function()
|
it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function()
|
||||||
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} })
|
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} })
|
||||||
test_set_cookie(sticky_balanced, "None", true, "/")
|
test_set_cookie(sticky_balanced, "None", true, "/", nil)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -69,7 +69,7 @@ var _ = framework.IngressNginxDescribe("Annotations - Mirror", func() {
|
||||||
|
|
||||||
It("should disable mirror-request-body", func() {
|
It("should disable mirror-request-body", func() {
|
||||||
annotations := map[string]string{
|
annotations := map[string]string{
|
||||||
"nginx.ingress.kubernetes.io/mirror-uri": "http://localhost/mirror",
|
"nginx.ingress.kubernetes.io/mirror-target": "http://localhost/mirror",
|
||||||
"nginx.ingress.kubernetes.io/mirror-request-body": "off",
|
"nginx.ingress.kubernetes.io/mirror-request-body": "off",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,11 @@ if ! command -v parallel &> /dev/null; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! command -v kind --version &> /dev/null; then
|
||||||
|
echo "kind is not installed. Use the package manager or visit the official site https://kind.sigs.k8s.io/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
export TAG=dev
|
export TAG=dev
|
||||||
|
@ -59,8 +64,6 @@ export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
|
||||||
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
||||||
|
|
||||||
kind --version || $(echo "Please install kind before running e2e tests";exit 1)
|
|
||||||
|
|
||||||
echo "[dev-env] creating Kubernetes cluster with kind"
|
echo "[dev-env] creating Kubernetes cluster with kind"
|
||||||
|
|
||||||
export KUBECONFIG="${HOME}/.kube/kind-config-${KIND_CLUSTER_NAME}"
|
export KUBECONFIG="${HOME}/.kube/kind-config-${KIND_CLUSTER_NAME}"
|
||||||
|
|
|
@ -69,6 +69,39 @@ var _ = framework.IngressNginxDescribe("Proxy Protocol", func() {
|
||||||
body := string(data)
|
body := string(data)
|
||||||
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol")))
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol")))
|
||||||
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=1234")))
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=1234")))
|
||||||
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-proto=http")))
|
||||||
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1")))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should respect proto passed by the PROXY Protocol server port", func() {
|
||||||
|
host := "proxy-protocol"
|
||||||
|
|
||||||
|
f.UpdateNginxConfigMapData(setting, "true")
|
||||||
|
|
||||||
|
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
|
||||||
|
|
||||||
|
f.WaitForNginxServer(host,
|
||||||
|
func(server string) bool {
|
||||||
|
return strings.Contains(server, "server_name proxy-protocol") &&
|
||||||
|
strings.Contains(server, "listen 80 proxy_protocol")
|
||||||
|
})
|
||||||
|
|
||||||
|
ip := f.GetNginxIP()
|
||||||
|
|
||||||
|
conn, err := net.Dial("tcp", net.JoinHostPort(ip, "80"))
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "unexpected error creating connection to %s:80", ip)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
header := "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n"
|
||||||
|
conn.Write([]byte(header))
|
||||||
|
conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(conn)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "unexpected error reading connection data")
|
||||||
|
body := string(data)
|
||||||
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol")))
|
||||||
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=443")))
|
||||||
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-proto=https")))
|
||||||
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1")))
|
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1")))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|