diff --git a/deployments/common/crds/k8s.nginx.org_policies.yaml b/deployments/common/crds/k8s.nginx.org_policies.yaml index b4a24adc0c..25b15f2704 100644 --- a/deployments/common/crds/k8s.nginx.org_policies.yaml +++ b/deployments/common/crds/k8s.nginx.org_policies.yaml @@ -92,6 +92,8 @@ spec: properties: clientCertSecret: type: string + crlFileName: + type: string verifyClient: type: string verifyDepth: diff --git a/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml b/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml index b4a24adc0c..25b15f2704 100644 --- a/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml +++ b/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml @@ -92,6 +92,8 @@ spec: properties: clientCertSecret: type: string + crlFileName: + type: string verifyClient: type: string verifyDepth: diff --git a/docs/content/configuration/policy-resource.md b/docs/content/configuration/policy-resource.md index 3ed5c7b87d..60c7ab9017 100644 --- a/docs/content/configuration/policy-resource.md +++ b/docs/content/configuration/policy-resource.md @@ -262,6 +262,17 @@ ingressMTLS: verifyDepth: 1 ``` +Below is an example of the `ingress-mtls-secret` using the secret type `nginx.org/ca` +```yaml +kind: Secret +metadata: + name: ingress-mtls-secret +apiVersion: v1 +type: nginx.org/ca +data: + ca.crt: +``` + A VirtualServer that references an IngressMTLS policy must: * Enable [TLS termination](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/#virtualservertls). * Reference the policy in the VirtualServer [`spec`](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/#virtualserver-specification). It is not allowed to reference an IngressMTLS policy in a [`route `](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/#virtualserverroute) or in a VirtualServerRoute [`subroute`](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/#virtualserverroutesubroute). @@ -284,12 +295,58 @@ We use the `requestHeaders` of the [Action.Proxy](/nginx-ingress-controller/conf > Note: The feature is implemented using the NGINX [ngx_http_ssl_module](https://nginx.org/en/docs/http/ngx_http_ssl_module.html). +#### Using a Certificate Revocation List +The IngressMTLS policy supports configuring at CRL for your policy. +This can be done in one of two ways. + +> Note: Only one of these configurations options can be used at a time. + +1. Adding the `ca.crl` field to the `nginx.org/ca` secret type, which accepts a base64 encoded certificate revocation list (crl). + Example YAML: +```yaml +kind: Secret +metadata: + name: ingress-mtls-secret +apiVersion: v1 +type: nginx.org/ca +data: + ca.crt: + ca.crl: +``` + +2. Adding the `crlFileName` field to your IngressMTLS policy spec with the name of the CRL file. + +> Note: This configuration option should only be used when using a CRL that is larger than 1MiB +> Otherwise we recommend using the `nginx.org/ca` secret type for managing your CRL. + +Example YAML: +```yaml +apiVersion: k8s.nginx.org/v1 +kind: Policy +metadata: + name: ingress-mtls-policy +spec: +ingressMTLS: + clientCertSecret: ingress-mtls-secret + crlFileName: webapp.crl + verifyClient: "on" + verifyDepth: 1 +``` + +**IMPORTANT NOTE** +When configuring a CRL with the `ingressMTLS.crlFileName` field, there is additional context to keep in mind: +1. The Ingress Controller will expect the CRL, in this case `webapp.crl`, will be in `/etc/nginx/secrets`. A volume mount will need to be added to the Ingress Controller deployment add your CRL to `/etc/nginx/secrets` +2. When updating the content of your CRL (e.g a new certificate has been revoked), NGINX will need to be reloaded to pick up the latest changes. Depending on your environment this may require updating the name of your CRL and applying this update to your `ingress-mtls.yaml` policy to ensure NGINX picks up the latest CRL. + +Please refer to the Kubernetes documentation on [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) to find the best implementation for your environment. + {{% table %}} |Field | Description | Type | Required | | ---| ---| ---| --- | |``clientCertSecret`` | The name of the Kubernetes secret that stores the CA certificate. It must be in the same namespace as the Policy resource. The secret must be of the type ``nginx.org/ca``, and the certificate must be stored in the secret under the key ``ca.crt``, otherwise the secret will be rejected as invalid. | ``string`` | Yes | |``verifyClient`` | Verification for the client. Possible values are ``"on"``, ``"off"``, ``"optional"``, ``"optional_no_ca"``. The default is ``"on"``. | ``string`` | No | |``verifyDepth`` | Sets the verification depth in the client certificates chain. The default is ``1``. | ``int`` | No | +|``crlFileName`` | The file name of the Certificate Revocation List. The Ingress Controller will look for this file in `/etc/nginx/secrets` | ``string`` | No | {{% /table %}} #### IngressMTLS Merging Behavior diff --git a/examples/custom-resources/ingress-mtls/README.md b/examples/custom-resources/ingress-mtls/README.md index 85b88e1470..2f679ff2b8 100644 --- a/examples/custom-resources/ingress-mtls/README.md +++ b/examples/custom-resources/ingress-mtls/README.md @@ -2,6 +2,9 @@ In this example, we deploy a web application, configure load balancing for it via a VirtualServer, and apply an Ingress MTLS policy. +> Note: The Ingress MTLS policy supports configuring a Certificate Revocation List (CRL). +> See [Using a Certificate Revocation List](https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#using-a-certificate-revocation-list) for details on how to set this option. + ## Prerequisites 1. Follow the [installation](https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/) instructions to deploy the Ingress Controller. diff --git a/internal/configs/configurator.go b/internal/configs/configurator.go index 2e5478e3b3..e0e7ab37e5 100644 --- a/internal/configs/configurator.go +++ b/internal/configs/configurator.go @@ -59,8 +59,11 @@ const JWTKeyKey = "jwk" // HtpasswdFileKey is the key of the data field of a Secret where the HTTP basic authorization list must be stored const HtpasswdFileKey = "htpasswd" -// CAKey is the key of the data field of a Secret where the cert must be stored. -const CAKey = "ca.crt" +// CACrtKey is the key of the data field of a Secret where the cert must be stored. +const CACrtKey = "ca.crt" + +// CACrlKey is the key of the data field of a Secret where the cert revocation list must be stored. +const CACrlKey = "ca.crl" // ClientSecretKey is the key of the data field of a Secret where the OIDC client secret must be stored. const ClientSecretKey = "client-secret" @@ -727,8 +730,12 @@ func generateTLSPassthroughHostsConfig(tlsPassthroughPairs map[string]tlsPassthr func (cnf *Configurator) addOrUpdateCASecret(secret *api_v1.Secret) string { name := objectMetaToFileName(&secret.ObjectMeta) - data := GenerateCAFileContent(secret) - return cnf.nginxManager.CreateSecret(name, data, nginx.TLSSecretFileMode) + crtData, crlData := GenerateCAFileContent(secret) + crtSecretName := fmt.Sprintf("%s-%s", name, CACrtKey) + crlSecretName := fmt.Sprintf("%s-%s", name, CACrlKey) + crtFileName := cnf.nginxManager.CreateSecret(crtSecretName, crtData, nginx.TLSSecretFileMode) + crlFileName := cnf.nginxManager.CreateSecret(crlSecretName, crlData, nginx.TLSSecretFileMode) + return fmt.Sprintf("%s %s", crtFileName, crlFileName) } func (cnf *Configurator) addOrUpdateJWKSecret(secret *api_v1.Secret) string { @@ -818,12 +825,14 @@ func GenerateCertAndKeyFileContent(secret *api_v1.Secret) []byte { } // GenerateCAFileContent generates a pem file content from the TLS secret. -func GenerateCAFileContent(secret *api_v1.Secret) []byte { - var res bytes.Buffer +func GenerateCAFileContent(secret *api_v1.Secret) ([]byte, []byte) { + var caKey bytes.Buffer + var caCrl bytes.Buffer - res.Write(secret.Data[CAKey]) + caKey.Write(secret.Data[CACrtKey]) + caCrl.Write(secret.Data[CACrlKey]) - return res.Bytes() + return caKey.Bytes(), caCrl.Bytes() } // DeleteIngress deletes NGINX configuration for the Ingress resource. diff --git a/internal/configs/version2/http.go b/internal/configs/version2/http.go index 5c2e792211..29fc7310ff 100644 --- a/internal/configs/version2/http.go +++ b/internal/configs/version2/http.go @@ -91,6 +91,7 @@ type SSL struct { // IngressMTLS defines TLS configuration for a server. This is a subset of TLS specifically for clients auth. type IngressMTLS struct { ClientCert string + ClientCrl string VerifyClient string VerifyDepth int } diff --git a/internal/configs/version2/nginx-plus.virtualserver.tmpl b/internal/configs/version2/nginx-plus.virtualserver.tmpl index a40aeea15a..846320e58a 100644 --- a/internal/configs/version2/nginx-plus.virtualserver.tmpl +++ b/internal/configs/version2/nginx-plus.virtualserver.tmpl @@ -115,6 +115,9 @@ server { {{ with $s.IngressMTLS }} ssl_client_certificate {{ .ClientCert }}; + {{ if .ClientCrl }} + ssl_crl {{ .ClientCrl }}; + {{ end }} ssl_verify_client {{ .VerifyClient }}; ssl_verify_depth {{ .VerifyDepth }}; {{ end }} diff --git a/internal/configs/version2/nginx.virtualserver.tmpl b/internal/configs/version2/nginx.virtualserver.tmpl index d3de0d7022..2f2d604cb7 100644 --- a/internal/configs/version2/nginx.virtualserver.tmpl +++ b/internal/configs/version2/nginx.virtualserver.tmpl @@ -70,6 +70,9 @@ server { {{ with $s.IngressMTLS }} ssl_client_certificate {{ .ClientCert }}; + {{ if .ClientCrl }} + ssl_crl {{ .ClientCrl }}; + {{ end }} ssl_verify_client {{ .VerifyClient }}; ssl_verify_depth {{ .VerifyDepth }}; {{ end }} diff --git a/internal/configs/virtualserver.go b/internal/configs/virtualserver.go index 84b2619790..fc41497d87 100644 --- a/internal/configs/virtualserver.go +++ b/internal/configs/virtualserver.go @@ -7,15 +7,14 @@ import ( "strings" "github.com/golang/glog" + "github.com/nginxinc/kubernetes-ingress/internal/configs/version2" "github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets" "github.com/nginxinc/kubernetes-ingress/internal/nginx" + conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" api_v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" - - "github.com/nginxinc/kubernetes-ingress/internal/configs/version2" - conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" ) const ( @@ -908,10 +907,32 @@ func (p *policiesCfg) addIngressMTLSConfig( verifyClient = ingressMTLS.VerifyClient } - p.IngressMTLS = &version2.IngressMTLS{ - ClientCert: secretRef.Path, - VerifyClient: verifyClient, - VerifyDepth: verifyDepth, + caFields := strings.Fields(secretRef.Path) + + if _, hasCrlKey := secretRef.Secret.Data[CACrlKey]; hasCrlKey && ingressMTLS.CrlFileName != "" { + res.addWarningf("Both ca.crl in the Secret and ingressMTLS.crlFileName fields cannot be used. ca.crl in %s will be ignored and %s will be applied", secretKey, polKey) + } + + if ingressMTLS.CrlFileName != "" { + p.IngressMTLS = &version2.IngressMTLS{ + ClientCert: caFields[0], + ClientCrl: fmt.Sprintf("%s/%s", DefaultSecretPath, ingressMTLS.CrlFileName), + VerifyClient: verifyClient, + VerifyDepth: verifyDepth, + } + } else if _, hasCrlKey := secretRef.Secret.Data[CACrlKey]; hasCrlKey { + p.IngressMTLS = &version2.IngressMTLS{ + ClientCert: caFields[0], + ClientCrl: caFields[1], + VerifyClient: verifyClient, + VerifyDepth: verifyDepth, + } + } else { + p.IngressMTLS = &version2.IngressMTLS{ + ClientCert: caFields[0], + VerifyClient: verifyClient, + VerifyDepth: verifyDepth, + } } return res } diff --git a/internal/configs/virtualserver_test.go b/internal/configs/virtualserver_test.go index c6fc69863f..d42f538d8f 100644 --- a/internal/configs/virtualserver_test.go +++ b/internal/configs/virtualserver_test.go @@ -2691,7 +2691,9 @@ func TestGeneratePolicies(t *testing.T) { vsNamespace: "default", vsName: "test", } - ingressMTLSCertPath := "/etc/nginx/secrets/default-ingress-mtls-secret" + ingressMTLSCertPath := "/etc/nginx/secrets/default-ingress-mtls-secret-ca.crt" + ingressMTLSCrlPath := "/etc/nginx/secrets/default-ingress-mtls-secret-ca.crl" + ingressMTLSCertAndCrlPath := fmt.Sprintf("%s %s", ingressMTLSCertPath, ingressMTLSCrlPath) policyOpts := policyOptions{ tls: true, secretRefs: map[string]*secrets.SecretReference{ @@ -2701,6 +2703,15 @@ func TestGeneratePolicies(t *testing.T) { }, Path: ingressMTLSCertPath, }, + "default/ingress-mtls-secret-crl": { + Secret: &api_v1.Secret{ + Type: secrets.SecretTypeCA, + Data: map[string][]byte{ + "ca.crl": []byte("base64crl"), + }, + }, + Path: ingressMTLSCertAndCrlPath, + }, "default/egress-mtls-secret": { Secret: &api_v1.Secret{ Type: api_v1.SecretTypeTLS, @@ -3085,6 +3096,71 @@ func TestGeneratePolicies(t *testing.T) { }, msg: "ingressMTLS reference", }, + { + policyRefs: []conf_v1.PolicyReference{ + { + Name: "ingress-mtls-policy-crl", + Namespace: "default", + }, + }, + policies: map[string]*conf_v1.Policy{ + "default/ingress-mtls-policy-crl": { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "ingress-mtls-policy-crl", + Namespace: "default", + }, + Spec: conf_v1.PolicySpec{ + IngressMTLS: &conf_v1.IngressMTLS{ + ClientCertSecret: "ingress-mtls-secret-crl", + VerifyClient: "off", + }, + }, + }, + }, + context: "spec", + expected: policiesCfg{ + IngressMTLS: &version2.IngressMTLS{ + ClientCert: ingressMTLSCertPath, + ClientCrl: ingressMTLSCrlPath, + VerifyClient: "off", + VerifyDepth: 1, + }, + }, + msg: "ingressMTLS reference with ca.crl field in secret", + }, + { + policyRefs: []conf_v1.PolicyReference{ + { + Name: "ingress-mtls-policy-crl", + Namespace: "default", + }, + }, + policies: map[string]*conf_v1.Policy{ + "default/ingress-mtls-policy-crl": { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "ingress-mtls-policy-crl", + Namespace: "default", + }, + Spec: conf_v1.PolicySpec{ + IngressMTLS: &conf_v1.IngressMTLS{ + ClientCertSecret: "ingress-mtls-secret", + CrlFileName: "default-ingress-mtls-secret-ca.crl", + VerifyClient: "off", + }, + }, + }, + }, + context: "spec", + expected: policiesCfg{ + IngressMTLS: &version2.IngressMTLS{ + ClientCert: ingressMTLSCertPath, + ClientCrl: ingressMTLSCrlPath, + VerifyClient: "off", + VerifyDepth: 1, + }, + }, + msg: "ingressMTLS reference with crl field in policy", + }, { policyRefs: []conf_v1.PolicyReference{ { @@ -3263,6 +3339,9 @@ func TestGeneratePoliciesFails(t *testing.T) { dryRunOverride := true rejectCodeOverride := 505 + ingressMTLSCertPath := "/etc/nginx/secrets/default-ingress-mtls-secret-ca.crt" + ingressMTLSCrlPath := "/etc/nginx/secrets/default-ingress-mtls-secret-ca.crl" + tests := []struct { policyRefs []conf_v1.PolicyReference policies map[string]*conf_v1.Policy @@ -3840,14 +3919,14 @@ func TestGeneratePoliciesFails(t *testing.T) { Secret: &api_v1.Secret{ Type: secrets.SecretTypeCA, }, - Path: "/etc/nginx/secrets/default-ingress-mtls-secret", + Path: ingressMTLSCertPath, }, }, }, context: "spec", expected: policiesCfg{ IngressMTLS: &version2.IngressMTLS{ - ClientCert: "/etc/nginx/secrets/default-ingress-mtls-secret", + ClientCert: ingressMTLSCertPath, VerifyClient: "on", VerifyDepth: 1, }, @@ -3887,7 +3966,7 @@ func TestGeneratePoliciesFails(t *testing.T) { Secret: &api_v1.Secret{ Type: secrets.SecretTypeCA, }, - Path: "/etc/nginx/secrets/default-ingress-mtls-secret", + Path: ingressMTLSCertPath, }, }, }, @@ -3932,7 +4011,7 @@ func TestGeneratePoliciesFails(t *testing.T) { Secret: &api_v1.Secret{ Type: secrets.SecretTypeCA, }, - Path: "/etc/nginx/secrets/default-ingress-mtls-secret", + Path: ingressMTLSCertPath, }, }, }, @@ -3950,6 +4029,59 @@ func TestGeneratePoliciesFails(t *testing.T) { expectedOidc: &oidcPolicyCfg{}, msg: "ingress mtls missing TLS config", }, + { + policyRefs: []conf_v1.PolicyReference{ + { + Name: "ingress-mtls-policy", + Namespace: "default", + }, + }, + policies: map[string]*conf_v1.Policy{ + "default/ingress-mtls-policy": { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "ingress-mtls-policy", + Namespace: "default", + }, + Spec: conf_v1.PolicySpec{ + IngressMTLS: &conf_v1.IngressMTLS{ + ClientCertSecret: "ingress-mtls-secret", + CrlFileName: "default-ingress-mtls-secret-ca.crl", + }, + }, + }, + }, + policyOpts: policyOptions{ + tls: true, + secretRefs: map[string]*secrets.SecretReference{ + "default/ingress-mtls-secret": { + Secret: &api_v1.Secret{ + Type: secrets.SecretTypeCA, + Data: map[string][]byte{ + "ca.crl": []byte("base64crl"), + }, + }, + Path: ingressMTLSCertPath, + }, + }, + }, + context: "spec", + expected: policiesCfg{ + IngressMTLS: &version2.IngressMTLS{ + ClientCert: ingressMTLSCertPath, + ClientCrl: ingressMTLSCrlPath, + VerifyClient: "on", + VerifyDepth: 1, + }, + ErrorReturn: nil, + }, + expectedWarnings: Warnings{ + nil: { + `Both ca.crl in the Secret and ingressMTLS.crlFileName fields cannot be used. ca.crl in default/ingress-mtls-secret will be ignored and default/ingress-mtls-policy will be applied`, + }, + }, + expectedOidc: &oidcPolicyCfg{}, + msg: "ingress mtls ca.crl and ingressMTLS.Crl set", + }, { policyRefs: []conf_v1.PolicyReference{ { diff --git a/pkg/apis/configuration/v1/types.go b/pkg/apis/configuration/v1/types.go index e1a3465a95..f994afcda3 100644 --- a/pkg/apis/configuration/v1/types.go +++ b/pkg/apis/configuration/v1/types.go @@ -456,6 +456,7 @@ type BasicAuth struct { // IngressMTLS defines an Ingress MTLS policy. type IngressMTLS struct { ClientCertSecret string `json:"clientCertSecret"` + CrlFileName string `json:"crlFileName"` VerifyClient string `json:"verifyClient"` VerifyDepth *int `json:"verifyDepth"` } diff --git a/tests/data/ingress-mtls/client-auth/crl/webapp.crl b/tests/data/ingress-mtls/client-auth/crl/webapp.crl new file mode 100644 index 0000000000..a836c07e04 --- /dev/null +++ b/tests/data/ingress-mtls/client-auth/crl/webapp.crl @@ -0,0 +1,19 @@ +-----BEGIN X509 CRL----- +MIIDBDCB7TANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMxETAPBgNVBAgM +CE1hcnlsYW5kMRIwEAYDVQQHDAlCYWx0aW1vcmUxGTAXBgNVBAoMEFRlc3QgQ0Es +IExpbWl0ZWQxIzAhBgNVBAsMGlNlcnZlciBSZXNlYXJjaCBEZXBhcnRtZW50MRAw +DgYDVQQDDAdUZXN0IENBMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29t +Fw0yMzAzMTMxODAyMjJaFw0yMzA0MTIxODAyMjJaMBQwEgIBAhcNMjMwMzEzMTgw +MjEyWjANBgkqhkiG9w0BAQsFAAOCAgEARsCPzIZjRkuKPej4Tu79kzENW/E6976c +Xk7h5tKhLwN54NUtt3JRLpVPApPXgO7auZ9kIbX/Di+rzK8WpPehTIx4oTlrKclZ +OXl3tPYBgvg2G5qhTw2P/N4C35O1gmZYKYqXxGzJ9AVu9ZcWRRczUB9yZfTupDh8 +6JtNwbBUZNGiR2FEyJ/XSPB1UyrAkb2VMN7A5XFHi+yYqkKlkpSKhcOcyFqzE0/q +D9WV7zrmT20uMXkeBUm9XHjXtWE20oMODPGDDA5H6FZi/NH1pSkKTcx8R7X4fehV +9BTMYyTCVpUIIHndou4v1RIvPriE/OPlxP0cDVB6euWDWogIvr2Y4izyGtstZZoN +Md0QcXWMXSR0wShBtD5Lb9r0K8LOKnyuQTUSGivncbFj6MQ4NSqM14Iw3d8z0zj0 +89oxAQXMkojvm6IeyY/aJUZqIOvNz1xdhnd5smZChAGSULxgXleaGF87W+v18nJT +8/7sUbsOQGQ+uP9tcWpf3rlx1UD5dgUoJlwkRMzgOoAv07rdqdldd8AWVbwLryFv +4DuLMNUDD+lObWq4T7A4NsoSZvPnj+Np83/uBXE/Ffozbic2R8VIoSKGcaX8thfa +joPL5JkxjFFzfFrp02/WFSMwq3slkBBjHadwjMq6bBry142aiNQn8p4lkvWWDoQ+ +igkH3EDgCVc= +-----END X509 CRL----- diff --git a/tests/data/ingress-mtls/client-auth/not-revoked/client-cert.pem b/tests/data/ingress-mtls/client-auth/not-revoked/client-cert.pem new file mode 100644 index 0000000000..0544bf1b10 --- /dev/null +++ b/tests/data/ingress-mtls/client-auth/not-revoked/client-cert.pem @@ -0,0 +1,108 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Maryland, L=Baltimore, O=Test CA, Limited, OU=Server Research Department, CN=Test CA/emailAddress=test@example.com + Validity + Not Before: Mar 13 17:58:36 2023 GMT + Not After : Mar 12 17:58:36 2024 GMT + Subject: C=US, ST=MD, L=Baltimore, O=Test Server, Limited, CN=Test Server + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a7:85:20:1a:81:39:bf:55:a7:2b:2b:c7:bf:fa: + 9f:e2:26:7e:f2:21:61:fa:d9:39:4e:ab:0e:38:6e: + fe:5d:e2:5a:fc:99:1b:42:30:b7:ee:21:50:4b:cc: + 79:bd:ee:9f:2c:5b:69:76:99:b5:00:69:4f:9c:70: + 7b:9e:4e:be:2e:63:d0:69:ec:bc:b2:4d:ba:40:f4: + 00:38:0a:75:26:8a:17:9f:e5:b6:37:9e:3e:34:da: + 1e:52:7f:e8:88:8b:30:26:3f:1e:5d:b3:0d:1a:c8: + 70:02:65:ef:ad:d1:66:a9:e3:eb:d5:2d:02:98:5c: + 54:e1:e2:91:30:57:68:7e:f3:c2:8d:14:9a:c7:19: + 0e:3f:af:03:24:e1:0f:c2:7d:22:b7:6b:36:c2:fd: + 4c:e1:a9:d9:1f:fc:ec:05:c3:95:dd:17:96:9e:d0: + 99:30:2d:07:6f:b7:6a:ea:11:63:b6:b2:09:50:1c: + 35:83:a6:90:95:c2:c1:73:6a:5d:87:ad:27:0f:b1: + 51:a3:73:c4:b5:2b:05:f8:3b:4a:63:1c:dd:dd:b7: + 2f:b4:58:49:42:3f:7e:4a:3e:89:68:7f:06:b5:52: + 04:3f:8c:db:7e:ce:5e:1e:64:39:ad:d0:93:24:f7: + 55:c8:aa:4e:85:a1:5b:a5:8d:44:cf:15:1e:6a:b1: + 00:ff + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 60:B1:14:DA:79:DA:4E:5C:A7:8F:C9:E1:4F:53:E4:0A:03:71:0F:22 + X509v3 Authority Key Identifier: + keyid:90:AA:F8:42:B6:84:01:09:18:39:76:A1:59:BF:19:29:04:94:6C:2B + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:example.com, DNS:webapp.example.com, DNS:mail.example.com, DNS:ftp.example.com + Netscape Comment: + OpenSSL Generated Certificate + Signature Algorithm: sha256WithRSAEncryption + 44:6a:06:f7:ba:cb:1d:fa:c9:bf:ab:62:7c:f0:e3:2c:a3:11: + 2a:aa:17:85:3a:b7:ba:0f:ab:03:65:63:a8:a8:d4:33:a6:85: + 16:ce:b6:96:3b:dc:d2:c2:8a:36:75:f5:7b:e6:a8:9b:1d:e7: + c6:fb:24:97:51:47:df:e2:ae:7b:76:0f:ef:29:aa:f5:1f:14: + b4:89:2f:16:51:f8:19:05:35:43:c4:ea:2b:69:7d:07:56:39: + 73:56:bf:86:6b:5a:90:32:2b:0a:3a:26:92:f9:01:37:30:4d: + 13:4f:f5:c6:3b:dc:23:f6:cb:4e:f0:0a:25:75:0b:26:92:70: + 12:ec:af:1b:1b:21:25:bf:5b:0c:81:97:2b:22:57:c2:5a:c7: + 6a:c6:1d:e8:f9:b9:ae:8e:ca:51:14:4f:7e:d4:21:43:a9:f7: + 43:87:53:83:7e:6e:e5:04:65:72:09:f6:b0:f6:45:c7:9c:31: + 03:88:bb:56:3d:c6:a8:fa:2f:f3:4c:92:5a:89:a1:5c:2e:14: + dd:8f:1b:7f:67:a3:63:52:11:20:1a:5b:a9:a4:68:80:ec:4b: + ee:40:f6:b2:c8:a1:d5:d1:af:eb:de:3d:c8:cb:f2:75:6e:12: + 53:1b:70:f9:db:ef:4d:e4:76:17:80:7a:4f:be:5f:b2:dc:33: + 85:81:fc:27:8f:da:cd:dd:4c:bd:31:50:eb:4a:cb:db:9b:c2: + 1c:db:43:86:e1:ca:15:1d:58:47:33:14:9a:80:7e:53:8b:52: + 1d:f9:98:84:10:df:5a:d7:0e:ef:c7:6d:aa:14:f0:09:fa:67: + 94:50:8f:d5:e1:07:5c:8b:bb:2f:73:49:50:ef:1e:d9:12:27: + 20:fb:bb:52:70:0c:d6:00:d2:bd:62:ff:1d:8c:07:91:c4:34: + 65:dd:9b:f1:40:67:db:d7:ad:d1:7a:96:f4:61:91:42:f4:9d: + a4:70:a8:31:70:97:1a:19:9d:ca:0d:41:b4:cc:95:0d:00:0b: + 6b:a0:28:ce:74:ee:69:73:b3:fc:58:13:7b:40:9b:29:99:94: + ba:26:91:20:33:89:44:46:58:b3:36:be:e3:18:20:6b:52:3c: + 7a:90:5f:82:a5:aa:f0:cc:6e:4d:26:9d:6e:2d:b6:2c:a6:7c: + 80:a9:d6:9d:34:e3:ac:bb:f0:e8:78:8d:93:2f:6f:31:3f:5f: + 91:5c:fc:d8:8c:bc:5a:8e:f0:67:c1:df:6b:08:5e:34:56:93: + 19:6a:c0:51:a4:9b:b3:3f:38:2e:c1:17:45:00:74:d9:3d:45: + b2:1b:76:e8:52:4f:e6:1f:7e:62:c7:b6:82:78:4e:40:56:cf: + 6b:93:f8:7d:be:27:0a:f2 +-----BEGIN CERTIFICATE----- +MIIFXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx +ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQHDAlCYWx0aW1vcmUxGTAXBgNVBAoM +EFRlc3QgQ0EsIExpbWl0ZWQxIzAhBgNVBAsMGlNlcnZlciBSZXNlYXJjaCBEZXBh +cnRtZW50MRAwDgYDVQQDDAdUZXN0IENBMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4 +YW1wbGUuY29tMB4XDTIzMDMxMzE3NTgzNloXDTI0MDMxMjE3NTgzNlowYzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgMAk1EMRIwEAYDVQQHDAlCYWx0aW1vcmUxHTAbBgNV +BAoMFFRlc3QgU2VydmVyLCBMaW1pdGVkMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKeFIBqBOb9Vpysrx7/6n+Im +fvIhYfrZOU6rDjhu/l3iWvyZG0Iwt+4hUEvMeb3unyxbaXaZtQBpT5xwe55Ovi5j +0GnsvLJNukD0ADgKdSaKF5/ltjeePjTaHlJ/6IiLMCY/Hl2zDRrIcAJl763RZqnj +69UtAphcVOHikTBXaH7zwo0UmscZDj+vAyThD8J9IrdrNsL9TOGp2R/87AXDld0X +lp7QmTAtB2+3auoRY7ayCVAcNYOmkJXCwXNqXYetJw+xUaNzxLUrBfg7SmMc3d23 +L7RYSUI/fko+iWh/BrVSBD+M237OXh5kOa3QkyT3VciqToWhW6WNRM8VHmqxAP8C +AwEAAaOB2DCB1TAdBgNVHQ4EFgQUYLEU2nnaTlynj8nhT1PkCgNxDyIwHwYDVR0j +BBgwFoAUkKr4QraEAQkYOXahWb8ZKQSUbCswCQYDVR0TBAIwADALBgNVHQ8EBAMC +BaAwTQYDVR0RBEYwRIILZXhhbXBsZS5jb22CEndlYmFwcC5leGFtcGxlLmNvbYIQ +bWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQf +Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOC +AgEARGoG97rLHfrJv6tifPDjLKMRKqoXhTq3ug+rA2VjqKjUM6aFFs62ljvc0sKK +NnX1e+aomx3nxvskl1FH3+Kue3YP7ymq9R8UtIkvFlH4GQU1Q8TqK2l9B1Y5c1a/ +hmtakDIrCjomkvkBNzBNE0/1xjvcI/bLTvAKJXULJpJwEuyvGxshJb9bDIGXKyJX +wlrHasYd6Pm5ro7KURRPftQhQ6n3Q4dTg35u5QRlcgn2sPZFx5wxA4i7Vj3GqPov +80ySWomhXC4U3Y8bf2ejY1IRIBpbqaRogOxL7kD2ssih1dGv6949yMvydW4SUxtw ++dvvTeR2F4B6T75fstwzhYH8J4/azd1MvTFQ60rL25vCHNtDhuHKFR1YRzMUmoB+ +U4tSHfmYhBDfWtcO78dtqhTwCfpnlFCP1eEHXIu7L3NJUO8e2RInIPu7UnAM1gDS +vWL/HYwHkcQ0Zd2b8UBn29et0XqW9GGRQvSdpHCoMXCXGhmdyg1BtMyVDQALa6Ao +znTuaXOz/FgTe0CbKZmUuiaRIDOJREZYsza+4xgga1I8epBfgqWq8MxuTSadbi22 +LKZ8gKnWnTTjrLvw6HiNky9vMT9fkVz82Iy8Wo7wZ8HfawheNFaTGWrAUaSbsz84 +LsEXRQB02T1Fsht26FJP5h9+Yse2gnhOQFbPa5P4fb4nCvI= +-----END CERTIFICATE----- diff --git a/tests/data/ingress-mtls/client-auth/not-revoked/client-key.pem b/tests/data/ingress-mtls/client-auth/not-revoked/client-key.pem new file mode 100644 index 0000000000..bbef35f917 --- /dev/null +++ b/tests/data/ingress-mtls/client-auth/not-revoked/client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCnhSAagTm/Vacr +K8e/+p/iJn7yIWH62TlOqw44bv5d4lr8mRtCMLfuIVBLzHm97p8sW2l2mbUAaU+c +cHueTr4uY9Bp7LyyTbpA9AA4CnUmihef5bY3nj402h5Sf+iIizAmPx5dsw0ayHAC +Ze+t0Wap4+vVLQKYXFTh4pEwV2h+88KNFJrHGQ4/rwMk4Q/CfSK3azbC/Uzhqdkf +/OwFw5XdF5ae0JkwLQdvt2rqEWO2sglQHDWDppCVwsFzal2HrScPsVGjc8S1KwX4 +O0pjHN3dty+0WElCP35KPolofwa1UgQ/jNt+zl4eZDmt0JMk91XIqk6FoVuljUTP +FR5qsQD/AgMBAAECggEAAnGSslBIQ15AfgS5eTdytZ3SJD4Qa9RXXappHrGfzEbN +BPpGx4RmanbZ8QEelYKxl7gNpclANq1Sl/mcFAcaBxs1oxXs+rzfhqsIhcjBRLqm +9ZIoQk9woNy9rH5pKfS90xEApGVEP6vE1oQeJu7zDG9itU1eyFIwessPSyE7SP7H +Pae6gTgb0KUyobs2IwER+2e8vwnb2wZXgiazIemPo6RKpydBVpKSgI+pR4Yr5NrY +ZhGCKs0U9EyeT5JwFNYsbU2noaw9Anty7i2BU5Im/6NyJC5Q59QvqFyWGf7RG7Mq +blz+uvnuooWUoSp4FT7sPZNCHRcHbsS1Y0Kol/RHwQKBgQDdTb2wkEvnJPNs8Hlk +ouE2LXuvtwB0DopLN0W1TIazOeN6yPFlVC61E98GeVZO4DLrINrbTyED1fgtCioM +6Qbh4BhJHCG8PQPLug2TjLZs3f4kADey2jTfkvdD2yYdDFK5jv001NBG86mjIFOb +5pShh+Pb/NMTAkuYpZX4QNpnmQKBgQDByLhYSWHDSZdcpoWyBy95zPTXtZmHLqbo +0rOoGXQrJviVBY/OrweskNKLOBujjxGG6R8DXFrFJjLZ+8unk1WY38bXb8paN8M7 +8xU2A4b1VuagsMqbMAzmVb2B6kooLtCpnF0D3CiBFlHYOi5wW5KBxsz1HnU9cfJd ++lrFD+WsVwKBgQDDRamvdmPDXZN9+OLkreRTTebpsWyw+3OD0w2rYA8rblUPLufy +JUnhddtBdyd1CddkKeVzxmq3W8JU27cnFSeBf59uQ2hxFNWYml8IZw1BGtD5K0f6 +hRhKfv+33FPRJeKI4WcDixUMxkxVKF0eH2Pe9G1W28vT5h6WXuXp3C/bYQKBgGM3 +tQMnF1IY1NHQRPXA7hLr2JS1W1U2kqj0cJ3p4mvRuUb7oQTO4xv8zoAPiz80GmI7 +6/AZkjQM+c5YOI6lRhdOxA08JJwKnwCL1llgdvIYu16dBi9s673nOm9RGQT360hc +UdePGoH1fpQ6PdqzWBDwS7JZFOgP9msdquno2MxjAoGAIvW6rXq5WVNjs2bOIpL3 +SI9QxZ9dlhCyRf14T2+2h4GoenkSaiQoLhJ5BHy2ydQUUM4u0EEjkLz/xLxmh6uS +n8b2suXTBdHCp6C73FVc8JvBUWEfj4W8a1tLO53DcbW0YVmk6mL7otw8WBi6LqJz +nCrwLitwRCcXPXDcA32ZpU4= +-----END PRIVATE KEY----- diff --git a/tests/data/ingress-mtls/client-auth/revoked/client-cert.pem b/tests/data/ingress-mtls/client-auth/revoked/client-cert.pem new file mode 100644 index 0000000000..52161ec1cd --- /dev/null +++ b/tests/data/ingress-mtls/client-auth/revoked/client-cert.pem @@ -0,0 +1,108 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Maryland, L=Baltimore, O=Test CA, Limited, OU=Server Research Department, CN=Test CA/emailAddress=test@example.com + Validity + Not Before: Mar 13 17:58:49 2023 GMT + Not After : Mar 12 17:58:49 2024 GMT + Subject: C=US, ST=MD, L=Baltimore, O=Test Server, Limited, CN=Test Server + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:0f:05:bb:7a:78:62:15:44:db:ae:fc:c1:4a: + 84:94:dc:04:2e:47:64:f3:16:f1:db:d6:87:25:72: + ac:3d:75:d1:66:4c:6a:7b:b6:40:6b:83:41:c1:0d: + 35:08:11:23:a0:e1:60:17:41:0f:98:28:aa:06:28: + bc:06:3b:70:49:4d:93:09:84:0e:7b:83:ee:2e:51: + 93:5f:c3:d6:8c:4a:c9:7b:88:08:2e:58:1a:d4:01: + 2c:e9:35:9d:37:57:28:54:ff:10:95:47:d6:e4:4d: + 4d:5f:ea:eb:4e:59:15:d7:df:83:1d:78:f7:97:96: + 69:84:61:ff:ed:b9:b9:ab:b5:51:aa:f1:29:87:07: + 4e:f2:40:d6:dd:07:e8:1b:38:fb:01:90:a5:91:dd: + 20:a5:23:7c:2a:ad:d0:06:12:b4:d2:8f:14:9b:95: + 79:38:54:27:62:1f:7a:27:d7:39:11:fe:ec:43:04: + 1e:58:fe:1b:98:0a:78:f1:2e:fc:9f:aa:3a:ea:c4: + b4:c1:e2:9c:97:23:59:29:dc:ae:e4:42:d8:0b:6d: + d3:f5:ee:7b:70:48:22:79:c4:12:cf:b1:9e:32:47: + c0:e0:77:c9:52:59:0d:54:7f:0c:36:e8:ee:7e:1a: + 13:f1:cd:6b:4a:56:63:0a:b2:1b:b2:55:64:0c:45: + 1f:81 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 32:E3:A1:81:20:9D:8A:37:D3:F4:04:A4:18:20:3E:97:29:A3:D6:9B + X509v3 Authority Key Identifier: + keyid:90:AA:F8:42:B6:84:01:09:18:39:76:A1:59:BF:19:29:04:94:6C:2B + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:example.com, DNS:webapp.example.com, DNS:mail.example.com, DNS:ftp.example.com + Netscape Comment: + OpenSSL Generated Certificate + Signature Algorithm: sha256WithRSAEncryption + 50:37:17:f3:ee:44:32:55:d7:29:5e:79:d2:f7:c2:12:f2:dd: + 5f:63:5e:fb:2d:97:0f:69:0a:f9:62:7f:2e:b0:e7:d5:00:3e: + f4:78:03:0d:fa:ac:de:c1:cb:69:c0:f3:c8:15:b0:71:1e:79: + f7:b8:0a:b9:76:e9:54:da:5e:20:04:7a:4b:f1:99:e1:fa:2b: + 3c:63:4a:67:a8:ef:7b:99:0d:95:fc:65:c4:b3:ff:25:25:97: + fc:33:45:a7:07:94:2f:09:9a:24:82:24:27:09:66:31:fe:cd: + 04:7c:4d:e1:2e:82:b0:a8:e9:37:e4:7b:6c:4c:06:19:04:0f: + 82:2d:8b:91:4c:4e:fd:87:ac:56:77:02:da:3f:36:08:0d:57: + 78:f0:14:2f:31:a0:74:30:cd:6a:58:de:9e:fa:a7:ce:a8:f5: + 7f:f4:2c:70:3c:a7:86:3d:2e:49:c8:06:a2:91:88:5e:98:d2: + d6:13:97:13:2f:53:e0:42:16:e1:e0:1e:09:e8:39:d7:4f:0b: + 14:d0:c6:33:28:08:f7:01:7c:69:a3:21:cf:8f:2d:bf:08:64: + 1a:fd:88:34:f9:7a:fd:b2:71:ba:9e:32:37:44:bb:6e:e3:a0: + 35:6a:e8:bf:cb:20:35:53:95:4d:46:ae:f6:a5:ab:d6:a1:13: + e2:ab:55:8e:eb:a2:25:d0:e0:ff:d3:d5:d5:7f:15:d2:72:b1: + a9:27:05:f5:fa:20:4c:74:f2:e4:af:8f:cf:a0:c4:03:86:f7: + f2:90:1f:77:87:92:1e:80:2c:8f:e9:26:a3:39:d7:04:9e:e5: + 2d:04:bb:05:43:a4:53:2b:b0:ec:f1:d0:5e:4a:81:64:84:3f: + ff:0a:32:74:d7:39:a7:54:83:ac:61:54:77:5f:fc:a2:5c:a3: + 98:9f:0c:fe:82:aa:40:3e:b2:93:f2:cf:4e:d8:21:d1:e0:16: + ac:cd:3c:57:88:e4:43:77:1a:1b:b8:d4:2b:fa:a6:93:60:d1: + b5:7f:ce:e0:6d:2d:21:cf:e2:2e:17:3b:d9:7a:62:78:9f:8f: + 26:1e:3e:e4:c6:13:22:12:9c:cc:9d:ad:34:6f:ac:bb:91:35: + e1:5e:22:fb:fe:db:5f:32:96:3b:e1:e2:e1:e1:6f:b6:29:20: + a4:df:9b:21:13:5c:88:5c:f6:f6:22:8f:a7:35:f4:3c:0c:e0: + 10:88:35:72:4f:ff:38:44:3e:4f:7f:4b:e6:54:c0:41:2c:1c: + aa:28:92:a9:78:11:c9:31:99:b2:2f:6f:2b:b1:34:01:8c:f2: + 92:44:7b:a5:a4:9a:31:96:12:24:02:bd:43:69:2a:a9:71:ff: + bc:90:b0:d0:c4:fe:0c:6d +-----BEGIN CERTIFICATE----- +MIIFXzCCA0egAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx +ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQHDAlCYWx0aW1vcmUxGTAXBgNVBAoM +EFRlc3QgQ0EsIExpbWl0ZWQxIzAhBgNVBAsMGlNlcnZlciBSZXNlYXJjaCBEZXBh +cnRtZW50MRAwDgYDVQQDDAdUZXN0IENBMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4 +YW1wbGUuY29tMB4XDTIzMDMxMzE3NTg0OVoXDTI0MDMxMjE3NTg0OVowYzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgMAk1EMRIwEAYDVQQHDAlCYWx0aW1vcmUxHTAbBgNV +BAoMFFRlc3QgU2VydmVyLCBMaW1pdGVkMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALIPBbt6eGIVRNuu/MFKhJTc +BC5HZPMW8dvWhyVyrD110WZManu2QGuDQcENNQgRI6DhYBdBD5goqgYovAY7cElN +kwmEDnuD7i5Rk1/D1oxKyXuICC5YGtQBLOk1nTdXKFT/EJVH1uRNTV/q605ZFdff +gx1495eWaYRh/+25uau1UarxKYcHTvJA1t0H6Bs4+wGQpZHdIKUjfCqt0AYStNKP +FJuVeThUJ2IfeifXORH+7EMEHlj+G5gKePEu/J+qOurEtMHinJcjWSncruRC2Att +0/Xue3BIInnEEs+xnjJHwOB3yVJZDVR/DDbo7n4aE/HNa0pWYwqyG7JVZAxFH4EC +AwEAAaOB2DCB1TAdBgNVHQ4EFgQUMuOhgSCdijfT9ASkGCA+lymj1pswHwYDVR0j +BBgwFoAUkKr4QraEAQkYOXahWb8ZKQSUbCswCQYDVR0TBAIwADALBgNVHQ8EBAMC +BaAwTQYDVR0RBEYwRIILZXhhbXBsZS5jb22CEndlYmFwcC5leGFtcGxlLmNvbYIQ +bWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQf +Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOC +AgEAUDcX8+5EMlXXKV550vfCEvLdX2Ne+y2XD2kK+WJ/LrDn1QA+9HgDDfqs3sHL +acDzyBWwcR5597gKuXbpVNpeIAR6S/GZ4forPGNKZ6jve5kNlfxlxLP/JSWX/DNF +pweULwmaJIIkJwlmMf7NBHxN4S6CsKjpN+R7bEwGGQQPgi2LkUxO/YesVncC2j82 +CA1XePAULzGgdDDNaljenvqnzqj1f/QscDynhj0uScgGopGIXpjS1hOXEy9T4EIW +4eAeCeg5108LFNDGMygI9wF8aaMhz48tvwhkGv2INPl6/bJxup4yN0S7buOgNWro +v8sgNVOVTUau9qWr1qET4qtVjuuiJdDg/9PV1X8V0nKxqScF9fogTHTy5K+Pz6DE +A4b38pAfd4eSHoAsj+kmoznXBJ7lLQS7BUOkUyuw7PHQXkqBZIQ//woydNc5p1SD +rGFUd1/8olyjmJ8M/oKqQD6yk/LPTtgh0eAWrM08V4jkQ3caG7jUK/qmk2DRtX/O +4G0tIc/iLhc72XpieJ+PJh4+5MYTIhKczJ2tNG+su5E14V4i+/7bXzKWO+Hi4eFv +tikgpN+bIRNciFz29iKPpzX0PAzgEIg1ck//OEQ+T39L5lTAQSwcqiiSqXgRyTGZ +si9vK7E0AYzykkR7paSaMZYSJAK9Q2kqqXH/vJCw0MT+DG0= +-----END CERTIFICATE----- diff --git a/tests/data/ingress-mtls/client-auth/revoked/client-key.pem b/tests/data/ingress-mtls/client-auth/revoked/client-key.pem new file mode 100644 index 0000000000..29aa3cb919 --- /dev/null +++ b/tests/data/ingress-mtls/client-auth/revoked/client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCyDwW7enhiFUTb +rvzBSoSU3AQuR2TzFvHb1oclcqw9ddFmTGp7tkBrg0HBDTUIESOg4WAXQQ+YKKoG +KLwGO3BJTZMJhA57g+4uUZNfw9aMSsl7iAguWBrUASzpNZ03VyhU/xCVR9bkTU1f +6utOWRXX34MdePeXlmmEYf/tubmrtVGq8SmHB07yQNbdB+gbOPsBkKWR3SClI3wq +rdAGErTSjxSblXk4VCdiH3on1zkR/uxDBB5Y/huYCnjxLvyfqjrqxLTB4pyXI1kp +3K7kQtgLbdP17ntwSCJ5xBLPsZ4yR8Dgd8lSWQ1Ufww26O5+GhPxzWtKVmMKshuy +VWQMRR+BAgMBAAECggEBAKR2la/d5hWKWaikD1elsaIhOkdYsFiL5+dLVlbzfT3j +df+MM4qDAyuK+BANV99UnVj68ptn/7RmUu0PcOQ8wHEkktxmOk5BxJzJwlrg82lv +pnxQYGYWAOmzED1zxPwZp+oiEboguc7zy7T9skwSosda7qspUV+VkW6yaga01ldO +v1TKrmWjgF/ENIAdbSQnlw+Be1Kn9Giw7IXz/euGzEA+UXEH1wVuwSuTsb6u+z7+ +sAE0N9bSCQbWeA+8xsL0d09g5l3y82Gu3ZOcCYguCWn9pruu5WKkwGix/kKAvMPd +6rXtNr9XzgTtiKW2G7IdSm+L/gbXf40UKCeYfq2vTMECgYEA2p924rQiQoT0SG5M +w0olh4GqOQzQjc4Z6ZvvC5CxJa+SN3X+94PdC+hbFQMyk2Xb3DLTtylwZwkPgfK7 +XZJAieuKNG5q6iUUExof8s2PHdwiEIrZ3q2f5n+Xqjv/2E7EfYhA2tAG2FQBw7av +BWmhaBOZZNffHx4rtg2/fMIziskCgYEA0IArzPttRIquLO79zlZv//XSbNuDCNq+ +sgXJsz5wFkb/AU7xbYXEvQNbcttD5fwCC9Jo0sLbl9+CO6K0zndIe7/C9VvH118Q +1DH6R7p1c4iHlt8s0K/r80xdQk5D7N634h9c9gr/vx3vK56MxPvR7JUTecIoIyIf +IC5XacTZEvkCgYBUkwYB05/BTf/WmVz225NDJaU9ZrizcvzRQ7KpLbNqGc6dx/b3 +t7pmpd++dDs3jFsOh1ch71T9dyLZqZZUL4TqFgWkHOcdZ3Spoxyi6GSqL4O6FI0O +OOq317pLb+ScwHQBABnezEUpoO4B0YVJucBoK9TWjzBQsHJGfnEKiXI5CQKBgQDD +B9Fw6ZL5NVvdjiR9eR9E5zXRO7gjdTJBpeZZM0N3oytvlt+AmktAnr5Q/sdRftyP +IF+LHlh4hMr2a6kDJFL55pNAHX0eeb9tLd62b7TjwEdMmi/6eUSVjc4CcuFY1bBd +5QZ45Cr8I80QGTwGGqPv0DaqgzI2QvmoiZCc0FRZSQKBgQDVzkBadKdbl3C0o+SH +oPqzbhO4ZnuEpCh39IXa7GsWpdHh5YrvO/W/6xOD3cAnkjNAYspW6k59QCVWy+QH +816ZeJH0/tWudGyNyTjbv05K5/UvKrWKFtUgEgdDLYS+/az4FOHmZ1I78wXYQ3cZ +k8y6CD0kDPyOEUiADfrwGdjfiw== +-----END PRIVATE KEY----- diff --git a/tests/data/ingress-mtls/policies/ingress-mtls-crl.yaml b/tests/data/ingress-mtls/policies/ingress-mtls-crl.yaml new file mode 100644 index 0000000000..b47db9c7de --- /dev/null +++ b/tests/data/ingress-mtls/policies/ingress-mtls-crl.yaml @@ -0,0 +1,10 @@ +apiVersion: k8s.nginx.org/v1 +kind: Policy +metadata: + name: ingress-mtls-policy +spec: + ingressMTLS: + clientCertSecret: ingress-mtls-secret + verifyClient: "on" + verifyDepth: 1 + crlFileName: webapp.crl diff --git a/tests/data/ingress-mtls/secret/ingress-mtls-secret-crl.yaml b/tests/data/ingress-mtls/secret/ingress-mtls-secret-crl.yaml new file mode 100644 index 0000000000..0df25da297 --- /dev/null +++ b/tests/data/ingress-mtls/secret/ingress-mtls-secret-crl.yaml @@ -0,0 +1,8 @@ +kind: Secret +metadata: + name: ingress-mtls-secret +apiVersion: v1 +type: nginx.org/ca +data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdNekNDQkJ1Z0F3SUJBZ0lKQU51ZlJyMkJoLzliTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUduTVFzd0NRWUQKVlFRR0V3SlZVekVSTUE4R0ExVUVDQXdJVFdGeWVXeGhibVF4RWpBUUJnTlZCQWNNQ1VKaGJIUnBiVzl5WlRFWgpNQmNHQTFVRUNnd1FWR1Z6ZENCRFFTd2dUR2x0YVhSbFpERWpNQ0VHQTFVRUN3d2FVMlZ5ZG1WeUlGSmxjMlZoCmNtTm9JRVJsY0dGeWRHMWxiblF4RURBT0JnTlZCQU1NQjFSbGMzUWdRMEV4SHpBZEJna3Foa2lHOXcwQkNRRVcKRUhSbGMzUkFaWGhoYlhCc1pTNWpiMjB3SGhjTk1qTXdNekV6TVRjMU5UQTJXaGNOTWpRd016RXlNVGMxTlRBMgpXakNCcHpFTE1Ba0dBMVVFQmhNQ1ZWTXhFVEFQQmdOVkJBZ01DRTFoY25sc1lXNWtNUkl3RUFZRFZRUUhEQWxDCllXeDBhVzF2Y21VeEdUQVhCZ05WQkFvTUVGUmxjM1FnUTBFc0lFeHBiV2wwWldReEl6QWhCZ05WQkFzTUdsTmwKY25abGNpQlNaWE5sWVhKamFDQkVaWEJoY25SdFpXNTBNUkF3RGdZRFZRUUREQWRVWlhOMElFTkJNUjh3SFFZSgpLb1pJaHZjTkFRa0JGaEIwWlhOMFFHVjRZVzF3YkdVdVkyOXRNSUlDSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DCkFnOEFNSUlDQ2dLQ0FnRUEyeU5QNHRoWjBzY1V0cDZ5SVArUGdXU3lucEIybWE3WkRlNzBobDY3OFdvRkZITXkKbUNyczJPNzhwV2wxZVFNcTBoZDA4UUNJTGErY1V4bmMwS3BQWkw4Um1BUUo3SnZHN3BuN1Mwb2tnMVBiTU82Zwo1ZWVldDBJdEh4Tkt1YWVGTTVKS0pLdFhmN0p6TWkwMTdDZTBXZ3V5ZHZWVUxENXFkM2ZLdW5UNlRTOUZ5blpLCjlmSE5MdGdBaFZnMHg2bWJGUlFBYXBUejFMaGhUaEt4eDRNbHI1WGpBS01la1d5T0d4am9WbUZubFNocXdqTWsKMVAyaCtiWlRrZnRxQWh4VzVwaGlGRmRrTW15dnIvYUQyRW9aU2xGa1RtSmtnQnhJaysvRzhZQWtjZXFOelo5eQpMLzRvWWU1VTdrV0lYZTlPT0k5djFpZW02ODE5bVNOU3dpVFZhOFRQcWR0elcwUHplYW1QZG9TckVWV0JlL3hZCk9ZWDhaaWF1NlVCU3U2bGQ1VUxBTGJYUlp6RHUxYzVvelZzdkN0cE1HV1oxZWtDVDhVNEdwRzhQUyszcUJkUGwKWUhxeWR0TnhGeFZ5OE1odU1IWnhacVY4dXpMTlRlakpram03V3dERHpBd1RIbm1uMVREdHZrVlBCQWZGenhuTgoreGRKdmZvQ21EUEsraHZmMUVRRGF4RU5sSHVYYnZpclNqL2FDaXJqTTdhb0UxR2VRSXo2MEk5QWpuTHc1a29tCmFCcjZadU1ET1ZFSmhBMnRnZXJOOGYzMFJHOGtBTWZTRUYwdUExWTVteEw2b0hueWw5SStmNlBmc2diSlIzMnQKM2s1S2RNQ2xSTTc1YmpaUDNIeVpWdGZVQ09iRnJPMlRVT2NUd29zUUlScXh5dVFJd0JYWHVFdTNBdEVDQXdFQQpBYU5nTUY0d0hRWURWUjBPQkJZRUZKQ3ErRUsyaEFFSkdEbDJvVm0vR1NrRWxHd3JNQjhHQTFVZEl3UVlNQmFBCkZKQ3ErRUsyaEFFSkdEbDJvVm0vR1NrRWxHd3JNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdDd1lEVlIwUEJBUUQKQWdFR01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQ0FRQzhLRWg5ZVZFSmFneFU2dS9BcTJPR3dhQVlwc2hDdU1vTwpTRVhiRkhDWWI1VEIyUnUzOXJPQ21TTmljZVlUMnJTenZLenF2bzM4aW9Pc3ZsdUFxTUF5VzRJVG53R1FPZ2ZPCitpUG1FS1V0RERjQ2VOQWY0OTZacjR4R25XS2l3RE9SVEI5N001SndaTnRpTGRReTU3S05wUC9nM3BXVHo4Y3QKODA3VEJ0T25kVFhhWkhBV0RaU0lCMXFaUEZWMHhvRUtPdS9TWXh5c2U4ZDBaNGhtZDE0TWVrQzFCZ2w4Y1NRagowajhrdUhXb2pIaUdVcW1ZRTdYd0hMMzRkeGxzb3RIVWhiNHhkREdGYTJlKzBZUVpzSlhFQW9pclcxbkRVektyCk5uOUlpUlR4eHUraXBYR0ZqLzVFbFFGTjRlUmE4dFZrYzJjODlUZUtBYjVkZ2ZCM0tNTUlKM0NwMExKQ2hva2wKdWhLbXptL0xuZ3FYL0dSQXFSWDRIaE82ZmZKbldDb2NsUGVFeFA0MnQ3a21EMXRlZzkrRGhVbGxnRk1RS3JnYwpaUUlMZW9CNWw2NlBPeVFVdWZjUzRJN2VzaHNlWXI4bWtSelRJTDM3cmxURWR1bWtpYmNXYVE5TjhGdFBHbUVxCnhuVFZBeEQ5TlE0WWJkUjNub1RIbkREYm1XUWJIbmc4ZWtzeGpUTHcrdDVsWGxtQ09Mb2VWZ3VxZnVnSzhMTUsKTSs4MWNUNHp6bkhkU0pxcVBSYitBUlFDZ3ArZzYwRGtpTUx1NzdCbzZQQ2o5NzRtYnZwQnpPaVlIdThkak52Sgp0L1dMcWdPU25reithUGRwVGE5M0Q5YUlBS3V6WURPbmp3OW9TUytnZUd0TmRoWUdPeWxLdDE4ZndZMGsrUTJ2CkNMT1pYZEYrWmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + ca.crl: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSURCRENCN1RBTkJna3Foa2lHOXcwQkFRc0ZBRENCcHpFTE1Ba0dBMVVFQmhNQ1ZWTXhFVEFQQmdOVkJBZ00KQ0UxaGNubHNZVzVrTVJJd0VBWURWUVFIREFsQ1lXeDBhVzF2Y21VeEdUQVhCZ05WQkFvTUVGUmxjM1FnUTBFcwpJRXhwYldsMFpXUXhJekFoQmdOVkJBc01HbE5sY25abGNpQlNaWE5sWVhKamFDQkVaWEJoY25SdFpXNTBNUkF3CkRnWURWUVFEREFkVVpYTjBJRU5CTVI4d0hRWUpLb1pJaHZjTkFRa0JGaEIwWlhOMFFHVjRZVzF3YkdVdVkyOXQKRncweU16QXpNVE14T0RBeU1qSmFGdzB5TXpBME1USXhPREF5TWpKYU1CUXdFZ0lCQWhjTk1qTXdNekV6TVRndwpNakV5V2pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQVJzQ1B6SVpqUmt1S1BlajRUdTc5a3pFTlcvRTY5NzZjClhrN2g1dEtoTHdONTROVXR0M0pSTHBWUEFwUFhnTzdhdVo5a0liWC9EaStyeks4V3BQZWhUSXg0b1RscktjbFoKT1hsM3RQWUJndmcyRzVxaFR3MlAvTjRDMzVPMWdtWllLWXFYeEd6SjlBVnU5WmNXUlJjelVCOXlaZlR1cERoOAo2SnROd2JCVVpOR2lSMkZFeUovWFNQQjFVeXJBa2IyVk1ON0E1WEZIaSt5WXFrS2xrcFNLaGNPY3lGcXpFMC9xCkQ5V1Y3enJtVDIwdU1Ya2VCVW05WEhqWHRXRTIwb01PRFBHRERBNUg2RlppL05IMXBTa0tUY3g4UjdYNGZlaFYKOUJUTVl5VENWcFVJSUhuZG91NHYxUkl2UHJpRS9PUGx4UDBjRFZCNmV1V0RXb2dJdnIyWTRpenlHdHN0WlpvTgpNZDBRY1hXTVhTUjB3U2hCdEQ1TGI5cjBLOExPS255dVFUVVNHaXZuY2JGajZNUTROU3FNMTRJdzNkOHowemowCjg5b3hBUVhNa29qdm02SWV5WS9hSlVacUlPdk56MXhkaG5kNXNtWkNoQUdTVUx4Z1hsZWFHRjg3Vyt2MThuSlQKOC83c1Vic09RR1ErdVA5dGNXcGYzcmx4MVVENWRnVW9KbHdrUk16Z09vQXYwN3JkcWRsZGQ4QVdWYndMcnlGdgo0RHVMTU5VREQrbE9iV3E0VDdBNE5zb1NadlBuaitOcDgzL3VCWEUvRmZvemJpYzJSOFZJb1NLR2NhWDh0aGZhCmpvUEw1Smt4akZGemZGcnAwMi9XRlNNd3Ezc2xrQkJqSGFkd2pNcTZiQnJ5MTQyYWlOUW44cDRsa3ZXV0RvUSsKaWdrSDNFRGdDVmM9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K diff --git a/tests/suite/test_ingress_mtls.py b/tests/suite/test_ingress_mtls.py index 170af4ab57..0993e4c345 100644 --- a/tests/suite/test_ingress_mtls.py +++ b/tests/suite/test_ingress_mtls.py @@ -7,6 +7,7 @@ from suite.utils.resources_utils import create_secret_from_yaml, delete_secret, wait_before_test from suite.utils.ssl_utils import create_sni_session from suite.utils.vs_vsr_resources_utils import ( + delete_and_create_vs_from_yaml, patch_v_s_route_from_yaml, patch_virtual_server_from_yaml, read_vs, @@ -33,6 +34,14 @@ invalid_crt = f"{TEST_DATA}/ingress-mtls/client-auth/invalid/client-cert.pem" invalid_key = f"{TEST_DATA}/ingress-mtls/client-auth/invalid/client-cert.pem" +mtls_secret_crl = f"{TEST_DATA}/ingress-mtls/secret/ingress-mtls-secret-crl.yaml" +mtls_pol_crl = f"{TEST_DATA}/ingress-mtls/policies/ingress-mtls-crl.yaml" + +crt_not_revoked = f"{TEST_DATA}/ingress-mtls/client-auth/not-revoked/client-cert.pem" +key_not_revoked = f"{TEST_DATA}/ingress-mtls/client-auth/not-revoked/client-key.pem" +crt_revoked = f"{TEST_DATA}/ingress-mtls/client-auth/revoked/client-cert.pem" +key_revoked = f"{TEST_DATA}/ingress-mtls/client-auth/revoked/client-key.pem" + def setup_policy(kube_apis, test_namespace, mtls_secret, tls_secret, policy): print(f"Create ingress-mtls secret") @@ -225,6 +234,158 @@ def test_ingress_mtls_policy_cert( ) assert resp.status_code == expected_code and expected_text in resp.text and exception in ssl_exception + @pytest.mark.smoke + @pytest.mark.parametrize( + "policy_src, vs_src, mtls_secret_in, expected_code, expected_text, vs_message, vs_state", + [ + ( + mtls_pol_valid_src, + mtls_vs_spec_src, + mtls_secret_crl, + 200, + "Server address:", + "added or updated", + "Valid", + ), + ( + mtls_pol_crl, + mtls_vs_spec_src, + mtls_sec_valid_src, + 404, + "Not Found", + "added or updated", + "Invalid", + ), + ( + mtls_pol_crl, + mtls_vs_spec_src, + mtls_secret_crl, + 404, + "Not Found", + "added or updated ; with warning(s)", + "Invalid", + ), + ], + ) + def test_ingress_mtls_polciy_crl( + self, + kube_apis, + crd_ingress_controller, + virtual_server_setup, + test_namespace, + policy_src, + mtls_secret_in, + vs_src, + expected_code, + expected_text, + vs_message, + vs_state, + ): + session = create_sni_session() + mtls_secret, tls_secret, pol_name = setup_policy( + kube_apis, + test_namespace, + mtls_secret_in, + tls_sec_valid_src, + policy_src, + ) + + delete_and_create_vs_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + vs_src, + virtual_server_setup.namespace, + ) + wait_before_test() + resp = session.get( + virtual_server_setup.backend_1_url_ssl, + cert=(crt_not_revoked, key_not_revoked), + headers={"host": virtual_server_setup.vs_host}, + allow_redirects=False, + verify=False, + ) + vs_res = read_vs(kube_apis.custom_objects, test_namespace, virtual_server_setup.vs_name) + teardown_policy(kube_apis, test_namespace, tls_secret, pol_name, mtls_secret) + + delete_and_create_vs_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + std_vs_src, + virtual_server_setup.namespace, + ) + assert ( + resp.status_code == expected_code + and expected_text in resp.text + and vs_message in vs_res["status"]["message"] + and vs_res["status"]["state"] == vs_state + ) + + @pytest.mark.parametrize( + "certificate, expected_code, expected_text, exception", + [ + ((crt_not_revoked, key_not_revoked), 200, "Server address:", ""), + ("", 400, "No required SSL certificate was sent", ""), + ((crt_revoked, key_revoked), 400, "The SSL certificate error", ""), + ], + ) + def test_ingress_mtls_policy_cert_crl( + self, + kube_apis, + crd_ingress_controller, + virtual_server_setup, + test_namespace, + certificate, + expected_code, + expected_text, + exception, + ): + """ + Test ingress-mtls with valid and invalid policy + """ + session = create_sni_session() + mtls_secret, tls_secret, pol_name = setup_policy( + kube_apis, + test_namespace, + mtls_secret_crl, + tls_sec_valid_src, + mtls_pol_valid_src, + ) + + print(f"Patch vs with policy: {mtls_pol_valid_src}") + patch_virtual_server_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + mtls_vs_spec_src, + virtual_server_setup.namespace, + ) + wait_before_test() + ssl_exception = "" + resp = "" + try: + resp = session.get( + virtual_server_setup.backend_1_url_ssl, + cert=certificate, + headers={"host": virtual_server_setup.vs_host}, + allow_redirects=False, + verify=False, + ) + except requests.exceptions.SSLError as e: + print(f"SSL certificate exception: {e}") + ssl_exception = str(e) + resp = mock.Mock() + resp.status_code = "None" + resp.text = "None" + + teardown_policy(kube_apis, test_namespace, tls_secret, pol_name, mtls_secret) + + patch_virtual_server_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + std_vs_src, + virtual_server_setup.namespace, + ) + assert resp.status_code == expected_code and expected_text in resp.text and exception in ssl_exception + @pytest.mark.policies @pytest.mark.parametrize(