Enable security features by default (#11819)

This commit is contained in:
Ricardo Katz 2024-08-23 00:45:51 -03:00 committed by GitHub
parent b79551287e
commit 7b4e4e2fa1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 103 additions and 262 deletions

View file

@ -258,7 +258,7 @@ jobs:
strategy: strategy:
matrix: matrix:
k8s: [v1.26.15, v1.27.13, v1.28.9, v1.29.4, v1.30.0] k8s: [v1.28.13, v1.29.8, v1.30.4, v1.31.0]
steps: steps:
- name: Checkout - name: Checkout
@ -309,26 +309,11 @@ jobs:
(needs.changes.outputs.go == 'true') || (needs.changes.outputs.baseimage == 'true') || ${{ github.event.workflow_dispatch.run_e2e == 'true' }} (needs.changes.outputs.go == 'true') || (needs.changes.outputs.baseimage == 'true') || ${{ github.event.workflow_dispatch.run_e2e == 'true' }}
strategy: strategy:
matrix: matrix:
k8s: [v1.26.15, v1.27.13, v1.28.9, v1.29.4, v1.30.0] k8s: [v1.28.13, v1.29.8, v1.30.4, v1.31.0]
uses: ./.github/workflows/zz-tmpl-k8s-e2e.yaml uses: ./.github/workflows/zz-tmpl-k8s-e2e.yaml
with: with:
k8s-version: ${{ matrix.k8s }} k8s-version: ${{ matrix.k8s }}
kubernetes-validations:
name: Kubernetes with Validations
needs:
- changes
- build
if: |
(needs.changes.outputs.go == 'true') || (needs.changes.outputs.baseimage == 'true') || ${{ github.event.workflow_dispatch.run_e2e == 'true' }}
strategy:
matrix:
k8s: [v1.26.15, v1.27.13, v1.28.9, v1.29.4, v1.30.0]
uses: ./.github/workflows/zz-tmpl-k8s-e2e.yaml
with:
k8s-version: ${{ matrix.k8s }}
variation: "VALIDATIONS"
kubernetes-chroot: kubernetes-chroot:
name: Kubernetes chroot name: Kubernetes chroot
needs: needs:
@ -338,7 +323,7 @@ jobs:
(needs.changes.outputs.go == 'true') || (needs.changes.outputs.baseimage == 'true') || ${{ github.event.workflow_dispatch.run_e2e == 'true' }} (needs.changes.outputs.go == 'true') || (needs.changes.outputs.baseimage == 'true') || ${{ github.event.workflow_dispatch.run_e2e == 'true' }}
strategy: strategy:
matrix: matrix:
k8s: [v1.26.15, v1.27.13, v1.28.9, v1.29.4, v1.30.0] k8s: [v1.28.13, v1.29.8, v1.30.4, v1.31.0]
uses: ./.github/workflows/zz-tmpl-k8s-e2e.yaml uses: ./.github/workflows/zz-tmpl-k8s-e2e.yaml
with: with:
k8s-version: ${{ matrix.k8s }} k8s-version: ${{ matrix.k8s }}

View file

@ -43,7 +43,6 @@ jobs:
SKIP_CLUSTER_CREATION: true SKIP_CLUSTER_CREATION: true
SKIP_INGRESS_IMAGE_CREATION: true SKIP_INGRESS_IMAGE_CREATION: true
SKIP_E2E_IMAGE_CREATION: true SKIP_E2E_IMAGE_CREATION: true
ENABLE_VALIDATIONS: ${{ inputs.variation == 'VALIDATIONS' }}
IS_CHROOT: ${{ inputs.variation == 'CHROOT' }} IS_CHROOT: ${{ inputs.variation == 'CHROOT' }}
run: | run: |
kind get kubeconfig > $HOME/.kube/kind-config-kind kind get kubeconfig > $HOME/.kube/kind-config-kind

View file

@ -304,7 +304,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. | | controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' | | controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
| controller.electionTTL | string | `""` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) | | controller.electionTTL | string | `""` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) |
| controller.enableAnnotationValidations | bool | `false` | | | controller.enableAnnotationValidations | bool | `true` | |
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # | | controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false | | controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one | | controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |

View file

@ -17,7 +17,7 @@ commonLabels: {}
controller: controller:
name: controller name: controller
enableAnnotationValidations: false enableAnnotationValidations: true
image: image:
## Keep false as default for now! ## Keep false as default for now!
chroot: false chroot: false

View file

@ -15,7 +15,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
| `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. | | `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. |
| `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) | | `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) |
| `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". | | `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". |
| `--enable-annotation-validation` | If true, will enable the annotation validation feature. This value will be defaulted to true on a future release. | | `--enable-annotation-validation` | If true, will enable the annotation validation feature. Defaults to true |
| `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) | | `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) |
| `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). | | `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). |
| `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) | | `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) |

View file

@ -776,10 +776,10 @@ func NewDefault() Configuration {
cfg := Configuration{ cfg := Configuration{
AllowSnippetAnnotations: false, AllowSnippetAnnotations: false,
AllowCrossNamespaceResources: true, AllowCrossNamespaceResources: false,
AllowBackendServerHeader: false, AllowBackendServerHeader: false,
AnnotationValueWordBlocklist: "", AnnotationValueWordBlocklist: "",
AnnotationsRiskLevel: "Critical", AnnotationsRiskLevel: "High",
AccessLogPath: "/var/log/nginx/access.log", AccessLogPath: "/var/log/nginx/access.log",
AccessLogParams: "", AccessLogParams: "",
EnableAccessLogForDefaultBackend: false, EnableAccessLogForDefaultBackend: false,
@ -924,7 +924,7 @@ func NewDefault() Configuration {
GlobalRateLimitMemcachedPoolSize: 50, GlobalRateLimitMemcachedPoolSize: 50,
GlobalRateLimitStatusCode: 429, GlobalRateLimitStatusCode: 429,
DebugConnections: []string{}, DebugConnections: []string{},
StrictValidatePathType: false, // TODO: This will be true in future releases StrictValidatePathType: true,
GRPCBufferSizeKb: 0, GRPCBufferSizeKb: 0,
} }

View file

@ -158,7 +158,7 @@ Requires the update-status parameter.`)
annotationsPrefix = flags.String("annotations-prefix", parser.DefaultAnnotationsPrefix, annotationsPrefix = flags.String("annotations-prefix", parser.DefaultAnnotationsPrefix,
`Prefix of the Ingress annotations specific to the NGINX controller.`) `Prefix of the Ingress annotations specific to the NGINX controller.`)
enableAnnotationValidation = flags.Bool("enable-annotation-validation", false, enableAnnotationValidation = flags.Bool("enable-annotation-validation", true,
`If true, will enable the annotation validation feature. This value will be defaulted to true on a future release`) `If true, will enable the annotation validation feature. This value will be defaulted to true on a future release`)
enableSSLChainCompletion = flags.Bool("enable-ssl-chain-completion", false, enableSSLChainCompletion = flags.Bool("enable-ssl-chain-completion", false,

View file

@ -127,14 +127,8 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller",
}) })
ginkgo.It("should return an error if there is an error validating the ingress definition", func() { ginkgo.It("should return an error if there is an error validating the ingress definition", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := admissionTestHost host := admissionTestHost
@ -241,14 +235,8 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller",
}) })
ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() { ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
out, err := createIngress(f.Namespace, invalidV1Ingress) out, err := createIngress(f.Namespace, invalidV1Ingress)
assert.Empty(ginkgo.GinkgoT(), out) assert.Empty(ginkgo.GinkgoT(), out)
@ -261,14 +249,8 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller",
}) })
ginkgo.It("should not return an error for an invalid Ingress when it has unknown class", func() { ginkgo.It("should not return an error for an invalid Ingress when it has unknown class", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
out, err := createIngress(f.Namespace, invalidV1IngressWithOtherClass) out, err := createIngress(f.Namespace, invalidV1IngressWithOtherClass)
assert.Equal(ginkgo.GinkgoT(), "ingress.networking.k8s.io/extensions-invalid-other created\n", out) assert.Equal(ginkgo.GinkgoT(), "ingress.networking.k8s.io/extensions-invalid-other created\n", out)
assert.Nil(ginkgo.GinkgoT(), err, "creating an invalid ingress with unknown class using kubectl") assert.Nil(ginkgo.GinkgoT(), err, "creating an invalid ingress with unknown class using kubectl")

View file

@ -277,14 +277,8 @@ var _ = framework.DescribeAnnotation("auth-*", func() {
"nginx.ingress.kubernetes.io/auth-snippet": ` "nginx.ingress.kubernetes.io/auth-snippet": `
proxy_set_header My-Custom-Header 42;`, proxy_set_header My-Custom-Header 42;`,
} }
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.EnsureIngress(ing) f.EnsureIngress(ing)
@ -297,15 +291,8 @@ var _ = framework.DescribeAnnotation("auth-*", func() {
ginkgo.It(`should not set snippet "proxy_set_header My-Custom-Header 42;" when external auth is not configured`, func() { ginkgo.It(`should not set snippet "proxy_set_header My-Custom-Header 42;" when external auth is not configured`, func() {
host := authHost host := authHost
disableSnippet := f.AllowSnippetConfiguration()
f.SetNginxConfigMapData(map[string]string{ defer disableSnippet()
"allow-snippet-annotations": "true",
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-snippet": ` "nginx.ingress.kubernetes.io/auth-snippet": `

View file

@ -62,14 +62,8 @@ var _ = framework.DescribeAnnotation("from-to-www-redirect", func() {
}) })
ginkgo.It("should redirect from www HTTPS to HTTPS", func() { ginkgo.It("should redirect from www HTTPS to HTTPS", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
ginkgo.By("setting up server for redirect from www") ginkgo.By("setting up server for redirect from www")

View file

@ -193,14 +193,8 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
ginkgo.It("should return OK for service with backend protocol GRPCS", func() { ginkgo.It("should return OK for service with backend protocol GRPCS", func() {
f.NewGRPCBinDeployment() f.NewGRPCBinDeployment()
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := echoHost host := echoHost

View file

@ -100,14 +100,8 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should enable modsecurity with snippet", func() { ginkgo.It("should enable modsecurity with snippet", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
@ -173,14 +167,8 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should enable modsecurity with snippet and block requests", func() { ginkgo.It("should enable modsecurity with snippet and block requests", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
@ -212,14 +200,8 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should enable modsecurity globally and with modsecurity-snippet block requests", func() { ginkgo.It("should enable modsecurity globally and with modsecurity-snippet block requests", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
@ -251,16 +233,11 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should enable modsecurity when enable-owasp-modsecurity-crs is set to true", func() { ginkgo.It("should enable modsecurity when enable-owasp-modsecurity-crs is set to true", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
"enable-modsecurity": "true",
"enable-owasp-modsecurity-crs": "true", f.UpdateNginxConfigMapData("enable-modsecurity", "true")
}) f.UpdateNginxConfigMapData("enable-owasp-modsecurity-crs", "true")
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
@ -290,6 +267,8 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should enable modsecurity through the config map", func() { ginkgo.It("should enable modsecurity through the config map", func() {
disableSnippet := f.AllowSnippetConfiguration()
defer disableSnippet()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
@ -310,17 +289,9 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
f.EnsureIngress(ing) f.EnsureIngress(ing)
expectedComment := "SecRuleEngine On" expectedComment := "SecRuleEngine On"
f.SetNginxConfigMapData(map[string]string{ f.UpdateNginxConfigMapData("enable-modsecurity", "true")
"allow-snippet-annotations": "true", f.UpdateNginxConfigMapData("enable-owasp-modsecurity-crs", "true")
"enable-modsecurity": "true", f.UpdateNginxConfigMapData("modsecurity-snippet", expectedComment)
"enable-owasp-modsecurity-crs": "true",
"modsecurity-snippet": expectedComment,
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
f.WaitForNginxServer(host, f.WaitForNginxServer(host,
func(server string) bool { func(server string) bool {
@ -339,6 +310,9 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace
f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations
defer f.UpdateNginxConfigMapData("annotations-risk-level", "High")
snippet := `SecRequestBodyAccess On snippet := `SecRequestBodyAccess On
SecAuditEngine RelevantOnly SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ SecAuditLogParts ABIJDEFHZ
@ -378,14 +352,9 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() {
}) })
ginkgo.It("should disable default modsecurity conf setting when modsecurity-snippet is specified", func() { ginkgo.It("should disable default modsecurity conf setting when modsecurity-snippet is specified", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := modSecurityFooHost host := modSecurityFooHost
nameSpace := f.Namespace nameSpace := f.Namespace

View file

@ -33,14 +33,8 @@ var _ = framework.DescribeAnnotation("server-snippet", func() {
}) })
ginkgo.It(`add valid directives to server via server snippet`, func() { ginkgo.It(`add valid directives to server via server snippet`, func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "serversnippet.foo.com" host := "serversnippet.foo.com"
annotations := map[string]string{ annotations := map[string]string{
@ -68,14 +62,8 @@ var _ = framework.DescribeAnnotation("server-snippet", func() {
}) })
ginkgo.It(`drops server snippet if disabled by the administrator`, func() { ginkgo.It(`drops server snippet if disabled by the administrator`, func() {
f.SetNginxConfigMapData(map[string]string{ f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations
"allow-snippet-annotations": "true", defer f.UpdateNginxConfigMapData("annotations-risk-level", "High")
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "noserversnippet.foo.com" host := "noserversnippet.foo.com"
annotations := map[string]string{ annotations := map[string]string{
@ -85,11 +73,6 @@ var _ = framework.DescribeAnnotation("server-snippet", func() {
} }
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.UpdateNginxConfigMapData("allow-snippet-annotations", "false")
defer func() {
// Return to the original value
f.UpdateNginxConfigMapData("allow-snippet-annotations", "true")
}()
// Sleep a while just to guarantee that the configmap is applied // Sleep a while just to guarantee that the configmap is applied
framework.Sleep() framework.Sleep()
f.EnsureIngress(ing) f.EnsureIngress(ing)

View file

@ -33,15 +33,8 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() {
ginkgo.It("set snippet more_set_headers in all locations", func() { ginkgo.It("set snippet more_set_headers in all locations", func() {
host := "configurationsnippet.foo.com" host := "configurationsnippet.foo.com"
disableSnippet := f.AllowSnippetConfiguration()
f.SetNginxConfigMapData(map[string]string{ defer disableSnippet()
"allow-snippet-annotations": "true",
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`, "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`,
@ -71,6 +64,8 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() {
}) })
ginkgo.It("drops snippet more_set_header in all locations if disabled by admin", func() { ginkgo.It("drops snippet more_set_header in all locations if disabled by admin", func() {
f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations
defer f.UpdateNginxConfigMapData("annotations-risk-level", "High")
host := "noconfigurationsnippet.foo.com" host := "noconfigurationsnippet.foo.com"
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`, "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`,

View file

@ -39,14 +39,8 @@ var _ = framework.DescribeSetting("stream-snippet", func() {
}) })
ginkgo.It("should add value of stream-snippet to nginx config", func() { ginkgo.It("should add value of stream-snippet to nginx config", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "foo.com" host := "foo.com"

View file

@ -117,11 +117,7 @@ func (f *Framework) newIngressController(namespace, namespaceOverlay string) err
isChroot = "false" isChroot = "false"
} }
enableAnnotationValidations, ok := os.LookupEnv("ENABLE_VALIDATIONS") cmd := exec.Command("./wait-for-nginx.sh", namespace, namespaceOverlay, isChroot)
if !ok {
enableAnnotationValidations = "false"
}
cmd := exec.Command("./wait-for-nginx.sh", namespace, namespaceOverlay, isChroot, enableAnnotationValidations)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("unexpected error waiting for ingress controller deployment: %v.\nLogs:\n%v", err, string(out)) return fmt.Errorf("unexpected error waiting for ingress controller deployment: %v.\nLogs:\n%v", err, string(out))

View file

@ -383,6 +383,20 @@ func (f *Framework) SetNginxConfigMapData(cmData map[string]string) {
f.WaitForReload(fn) f.WaitForReload(fn)
} }
// SetNginxConfigMapData sets ingress-nginx's nginx-ingress-controller configMap data
func (f *Framework) AllowSnippetConfiguration() func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "true",
"annotations-risk-level": "Critical", // To enable snippet configurations
})
return func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
"annotations-risk-level": "High",
})
}
}
// CreateConfigMap creates a new configmap in the current namespace // CreateConfigMap creates a new configmap in the current namespace
func (f *Framework) CreateConfigMap(name string, data map[string]string) { func (f *Framework) CreateConfigMap(name string, data map[string]string) {
_, err := f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Create(context.TODO(), &v1.ConfigMap{ _, err := f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Create(context.TODO(), &v1.ConfigMap{

View file

@ -36,14 +36,8 @@ var _ = framework.IngressNginxDescribe("single ingress - multiple hosts", func()
}) })
ginkgo.It("should set the correct $service_name NGINX variable", func() { ginkgo.It("should set the correct $service_name NGINX variable", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "service-name: $service_name";`, "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "service-name: $service_name";`,

View file

@ -35,14 +35,8 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() {
}) })
ginkgo.It("should choose exact location for /exact", func() { ginkgo.It("should choose exact location for /exact", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "exact.path" host := "exact.path"

View file

@ -37,14 +37,8 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] mix Exact and Prefi
exactPathType := networking.PathTypeExact exactPathType := networking.PathTypeExact
ginkgo.It("should choose the correct location", func() { ginkgo.It("should choose the correct location", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "mixed.path" host := "mixed.path"

View file

@ -78,7 +78,6 @@ kubectl run --rm \
--env="E2E_NODES=${E2E_NODES}" \ --env="E2E_NODES=${E2E_NODES}" \
--env="FOCUS=${FOCUS}" \ --env="FOCUS=${FOCUS}" \
--env="IS_CHROOT=${IS_CHROOT:-false}"\ --env="IS_CHROOT=${IS_CHROOT:-false}"\
--env="ENABLE_VALIDATIONS=${ENABLE_VALIDATIONS:-false}"\
--env="SKIP_OPENTELEMETRY_TESTS=${SKIP_OPENTELEMETRY_TESTS:-false}"\ --env="SKIP_OPENTELEMETRY_TESTS=${SKIP_OPENTELEMETRY_TESTS:-false}"\
--env="E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS}" \ --env="E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS}" \
--env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \ --env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \

View file

@ -39,7 +39,6 @@ fi
KIND_LOG_LEVEL="1" KIND_LOG_LEVEL="1"
IS_CHROOT="${IS_CHROOT:-false}" IS_CHROOT="${IS_CHROOT:-false}"
ENABLE_VALIDATIONS="${ENABLE_VALIDATIONS:-false}"
export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev} export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev}
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Use 1.0.0-dev to make sure we use the latest configuration in the helm template # Use 1.0.0-dev to make sure we use the latest configuration in the helm template

View file

@ -34,14 +34,8 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
}) })
ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is an invalid character in some annotation", func() { ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is an invalid character in some annotation", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "invalid-value-test" host := "invalid-value-test"
annotations := map[string]string{ annotations := map[string]string{
@ -50,7 +44,6 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
} }
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.UpdateNginxConfigMapData("allow-snippet-annotations", "true")
f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,{") f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,{")
f.EnsureIngress(ing) f.EnsureIngress(ing)
@ -73,14 +66,8 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
}) })
ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a forbidden word in some annotation", func() { ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a forbidden word in some annotation", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "forbidden-value-test" host := "forbidden-value-test"
@ -93,7 +80,6 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
} }
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.UpdateNginxConfigMapData("allow-snippet-annotations", "true")
f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,content_by_lua_block") f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,content_by_lua_block")
// Sleep a while just to guarantee that the configmap is applied // Sleep a while just to guarantee that the configmap is applied
framework.Sleep() framework.Sleep()
@ -117,14 +103,9 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
}) })
ginkgo.It("[BAD_ANNOTATIONS] should allow an ingress if there is a default blocklist config in place", func() { ginkgo.It("[BAD_ANNOTATIONS] should allow an ingress if there is a default blocklist config in place", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
hostValid := "custom-allowed-value-test" hostValid := "custom-allowed-value-test"
annotationsValid := map[string]string{ annotationsValid := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": ` "nginx.ingress.kubernetes.io/configuration-snippet": `
@ -155,14 +136,8 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() {
}) })
ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a custom blocklist config in place and allow others to pass", func() { ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a custom blocklist config in place and allow others to pass", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
host := "custom-forbidden-value-test" host := "custom-forbidden-value-test"
annotations := map[string]string{ annotations := map[string]string{

View file

@ -69,15 +69,9 @@ var _ = framework.DescribeSetting("Geoip2", func() {
ginkgo.It("should only allow requests from specific countries", func() { ginkgo.It("should only allow requests from specific countries", func() {
ginkgo.Skip("GeoIP test are temporarily disabled") ginkgo.Skip("GeoIP test are temporarily disabled")
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
"use-geoip2": "true", f.UpdateNginxConfigMapData("use-geoip2", "true")
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
httpSnippetAllowingOnlyAustralia := `map $geoip2_city_country_code $blocked_country { httpSnippetAllowingOnlyAustralia := `map $geoip2_city_country_code $blocked_country {
default 1; default 1;

View file

@ -34,14 +34,9 @@ var _ = framework.IngressNginxDescribe("Dynamic $proxy_host", func() {
}) })
ginkgo.It("should exist a proxy_host", func() { ginkgo.It("should exist a proxy_host", func() {
f.SetNginxConfigMapData(map[string]string{ disableSnippet := f.AllowSnippetConfiguration()
"allow-snippet-annotations": "true", defer disableSnippet()
})
defer func() {
f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false",
})
}()
upstreamName := fmt.Sprintf("%v-%v-80", f.Namespace, framework.EchoService) upstreamName := fmt.Sprintf("%v-%v-80", f.Namespace, framework.EchoService)
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Custom-Header: $proxy_host"`, "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Custom-Header: $proxy_host"`,
@ -65,10 +60,12 @@ var _ = framework.IngressNginxDescribe("Dynamic $proxy_host", func() {
ginkgo.It("should exist a proxy_host using the upstream-vhost annotation value", func() { ginkgo.It("should exist a proxy_host using the upstream-vhost annotation value", func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "true", "allow-snippet-annotations": "true",
"annotations-risk-level": "Critical", // To allow Configuration Snippet
}) })
defer func() { defer func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false", "allow-snippet-annotations": "false",
"annotations-risk-level": "High",
}) })
}() }()

View file

@ -38,6 +38,7 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "true", "allow-snippet-annotations": "true",
"annotations-risk-level": "Critical",
"server-snippet": ` "server-snippet": `
more_set_headers "Globalfoo: Foooo";`, more_set_headers "Globalfoo: Foooo";`,
}) })
@ -45,6 +46,7 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() {
defer func() { defer func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false", "allow-snippet-annotations": "false",
"annotations-risk-level": "High",
}) })
}() }()
annotations := map[string]string{ annotations := map[string]string{
@ -101,6 +103,7 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false", "allow-snippet-annotations": "false",
"annotations-risk-level": "Critical", // To allow Configuration Snippet
"server-snippet": ` "server-snippet": `
more_set_headers "Globalfoo: Foooo";`, more_set_headers "Globalfoo: Foooo";`,
}) })
@ -108,6 +111,7 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() {
defer func() { defer func() {
f.SetNginxConfigMapData(map[string]string{ f.SetNginxConfigMapData(map[string]string{
"allow-snippet-annotations": "false", "allow-snippet-annotations": "false",
"annotations-risk-level": "High",
}) })
}() }()
annotations := map[string]string{ annotations := map[string]string{

View file

@ -48,8 +48,8 @@ var _ = framework.IngressNginxDescribeSerial("annotation validations", func() {
framework.Sleep() framework.Sleep()
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/default-backend": "default/bla", // low risk "nginx.ingress.kubernetes.io/default-backend": "bla", // low risk
"nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk
} }
ginkgo.By("allow ingress with low/medium risk annotations") ginkgo.By("allow ingress with low/medium risk annotations")
@ -82,8 +82,8 @@ var _ = framework.IngressNginxDescribeSerial("annotation validations", func() {
framework.Sleep() framework.Sleep()
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/default-backend": "default/bla", // low risk "nginx.ingress.kubernetes.io/default-backend": "bla", // low risk
"nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk
} }
ginkgo.By("allow ingress with low/medium risk annotations") ginkgo.By("allow ingress with low/medium risk annotations")

View file

@ -24,7 +24,6 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export NAMESPACE=$1 export NAMESPACE=$1
export NAMESPACE_OVERLAY=$2 export NAMESPACE_OVERLAY=$2
export IS_CHROOT=$3 export IS_CHROOT=$3
export ENABLE_VALIDATIONS=$4
echo "deploying NGINX Ingress controller in namespace $NAMESPACE" echo "deploying NGINX Ingress controller in namespace $NAMESPACE"
@ -59,7 +58,7 @@ else
# TODO: remove the need to use fullnameOverride # TODO: remove the need to use fullnameOverride
fullnameOverride: nginx-ingress fullnameOverride: nginx-ingress
controller: controller:
enableAnnotationValidations: ${ENABLE_VALIDATIONS} enableAnnotationValidations: true
image: image:
repository: ingress-controller/controller repository: ingress-controller/controller
chroot: ${IS_CHROOT} chroot: ${IS_CHROOT}