diff --git a/docs/operator_guide.md b/docs/operator_guide.md index 93ac51de..c57823a7 100644 --- a/docs/operator_guide.md +++ b/docs/operator_guide.md @@ -146,6 +146,7 @@ Used to configure how the ingress will be annotated for issuing a TLS certificat * `tls-certificate-issuer` sets the _value_ of the annotation, for example to decide between production and staging versions of an issuer in different namespaces * `tls-certificate-issuer-type-default` sets the default for the _key_ of the annotation, for example to use either `certmanager.k8s.io/cluster-issuer` (the default) or `certmanager.k8s.io/issuer` * `tls-certificate-issuer-type-overrides` allows specifying a mapping between the suffix of a domain and the issuer-type, to override the default. For example, assuming the 'cluster-issuer' type as the default, then specifying `--tls-certificate-issuer-type-overrides foo.example.com=certmanager.k8s.io/issuer` would mean that foo.example.com and any of its subdomains will use the 'issuer' type instead. In the case of multiple matching suffixes, the more specific (i.e. longest) will be used. +* `tls-certificate-issuer-disable-for-domain-suffixes` disable tls for specified domain suffixes when `use-ingress-tls` is set to `default_on`. for example if you to enable tls for all domain suffixes except `internal.example.com` set `tls-certificate-issuer-disable-for-domain-suffixes internal.example.com` . ### use-in-memory-emptydirs diff --git a/fiaas_deploy_daemon/config.py b/fiaas_deploy_daemon/config.py index 7286f80f..63890798 100644 --- a/fiaas_deploy_daemon/config.py +++ b/fiaas_deploy_daemon/config.py @@ -74,7 +74,7 @@ Enable fiaas-deploy-daemon to extend ingress objects to support https. Option `default_on` will, when creating ingress objects for an application, enable https unless explicitly set to -disabled in the configuration for an application. +disabled in the configuration for an application. You can also disable https for specific domains by setting --tls-certificate-issuer-disable-for-domain-suffixes. Option `default_off` will, when creating ingress objects for an application, not enable https unless explicitly set to enabled in the configuration for an application. @@ -267,6 +267,9 @@ def _parse_args(self, args): tls_parser.add_argument("--tls-certificate-issuer-type-overrides", help="Issuers to use for specified domain suffixes", default=[], action="append", type=KeyValue, dest="tls_certificate_issuer_type_overrides") + tls_parser.add_argument("--tls-certificate-issuer-disable-for-domain-suffixes", help="Disable tls for specified domain suffixes when --use-ingress-tls is set to default_on", + default=[], + action="append", dest="tls_certificate_issuer_disable_for_domain_suffixes") parser.parse_args(args, namespace=self) self.global_env = {env_var.key: env_var.value for env_var in self.global_env} diff --git a/fiaas_deploy_daemon/deployer/kubernetes/ingress.py b/fiaas_deploy_daemon/deployer/kubernetes/ingress.py index 03e2b350..7d366ec3 100644 --- a/fiaas_deploy_daemon/deployer/kubernetes/ingress.py +++ b/fiaas_deploy_daemon/deployer/kubernetes/ingress.py @@ -122,29 +122,39 @@ def _group_ingresses(self, app_spec): default=True) ingresses = [default_ingress] override_issuer_ingresses = {} + notls_ingresses = {} for ingress_item in ingress_items: issuer_type = self._get_issuer_type(ingress_item.host) next_name = "{}-{}".format(app_spec.name, len(ingresses)) if ingress_item.annotations: annotated_ingresses = AnnotatedIngress(name=next_name, ingress_items=[ingress_item], - annotations=ingress_item.annotations, - explicit_host=True, issuer_type=issuer_type, - default=False) + annotations=ingress_item.annotations, + explicit_host=True, issuer_type=issuer_type, + default=False) ingresses.append(annotated_ingresses) + elif self._ingress_tls._should_disable_ingress_tls([ingress_item.host]) is True: + notls_ingress = notls_ingresses.setdefault("no_tls", + AnnotatedIngress(name=next_name, + ingress_items=[], + annotations={}, + explicit_host=explicit_host, + issuer_type=issuer_type, + default=False)) + notls_ingress.ingress_items.append(ingress_item) elif issuer_type != self._tls_issuer_type_default: annotated_ingress = override_issuer_ingresses.setdefault(issuer_type, - AnnotatedIngress(name=next_name, - ingress_items=[], - annotations={}, - explicit_host=explicit_host, - issuer_type=issuer_type, - default=False)) + AnnotatedIngress(name=next_name, + ingress_items=[], + annotations={}, + explicit_host=explicit_host, + issuer_type=issuer_type, + default=False)) annotated_ingress.ingress_items.append(ingress_item) else: default_ingress.ingress_items.append(ingress_item) ingresses.extend(i for i in override_issuer_ingresses.values()) - + ingresses.extend(i for i in notls_ingresses.values()) return ingresses @retry_on_upsert_conflict @@ -240,11 +250,12 @@ class IngressTls(object): def __init__(self, config): self._use_ingress_tls = config.use_ingress_tls self._cert_issuer = config.tls_certificate_issuer + self._tls_certificate_issuer_disable_for_domain_suffixes = config.tls_certificate_issuer_disable_for_domain_suffixes self._shortest_suffix = sorted(config.ingress_suffixes, key=len)[0] if config.ingress_suffixes else None self.enable_deprecated_tls_entry_per_host = config.enable_deprecated_tls_entry_per_host def apply(self, ingress, app_spec, hosts, issuer_type, use_suffixes=True): - if self._should_have_ingress_tls(app_spec): + if self._should_have_ingress_tls(app_spec,hosts): tls_annotations = {} if self._cert_issuer or app_spec.ingress_tls.certificate_issuer: issuer = app_spec.ingress_tls.certificate_issuer if app_spec.ingress_tls.certificate_issuer else self._cert_issuer @@ -279,11 +290,23 @@ def _collapse_hosts(self, app_spec, hosts): LOG.error("Failed to generate a short name to use as Common Name") return hosts - def _should_have_ingress_tls(self, app_spec): + def _should_have_ingress_tls(self, app_spec, hosts): if self._use_ingress_tls == 'disabled' or app_spec.ingress_tls.enabled is False: return False - else: - return self._use_ingress_tls == 'default_on' or app_spec.ingress_tls.enabled is True + elif app_spec.ingress_tls.enabled is True: + return True + elif self._should_disable_ingress_tls(hosts) is True: + return False + else: + return self._use_ingress_tls == 'default_on' + + def _should_disable_ingress_tls(self, hosts): + #Check if any ingress host is part of atleast one domain suffix that shoudln't have tls + for suffix in self._tls_certificate_issuer_disable_for_domain_suffixes: + for host in hosts: + if host == suffix or host.endswith("." + suffix): + return True + return False def _generate_short_host(self, app_spec): h = hashlib.sha1() diff --git a/tests/fiaas_deploy_daemon/deployer/kubernetes/test_ingress_deploy.py b/tests/fiaas_deploy_daemon/deployer/kubernetes/test_ingress_deploy.py index 2ff9a1b2..9552d8bb 100644 --- a/tests/fiaas_deploy_daemon/deployer/kubernetes/test_ingress_deploy.py +++ b/tests/fiaas_deploy_daemon/deployer/kubernetes/test_ingress_deploy.py @@ -656,7 +656,11 @@ def deployer_issuer_overrides(self, config, ingress_tls, owner_references, defau "foo.bar.example.com": "certmanager.k8s.io/issuer" } return IngressDeployer(config, ingress_tls, owner_references, default_app_spec, extension_hook) - + + @pytest.fixture + def ingress_tls(self, config): + return mock.create_autospec(IngressTls(config), spec_set=True, instance=True) + @pytest.mark.usefixtures("delete") def test_applies_ingress_tls_issuser_overrides(self, post, deployer_issuer_overrides, ingress_tls, app_spec): with mock.patch("k8s.models.ingress.Ingress.get_or_create") as get_or_create: @@ -687,6 +691,47 @@ def test_applies_ingress_tls_issuser_overrides(self, post, deployer_issuer_overr assert ingress_tls.apply.call_count == 3 assert expected_host_groups == sorted(host_groups) + @pytest.fixture + def ingress_tls_disable_tls_for_domain_suffixes(self, config, capsys): + config.tls_certificate_issuer_disable_for_domain_suffixes = ["foo.example.com","xip.io"] + ingress_tls = IngressTls(config) + return ingress_tls + + @pytest.fixture + def deployer_disable_tls_for_domain_suffixes(self, config, ingress_tls_disable_tls_for_domain_suffixes, owner_references, default_app_spec, extension_hook): + return IngressDeployer(config, ingress_tls_disable_tls_for_domain_suffixes, owner_references, default_app_spec, extension_hook) + + @pytest.mark.usefixtures("delete") + def test_applies_tls_certificate_issuer_disable_for_domain_suffixes(self, deployer_disable_tls_for_domain_suffixes, ingress_tls_disable_tls_for_domain_suffixes, app_spec): + with mock.patch("k8s.models.ingress.Ingress.get_or_create") as get_or_create: + get_or_create.return_value = mock.create_autospec(Ingress, spec_set=True) + app_spec.ingresses[:] = [ + # tls disabled for foo.example.com + IngressItemSpec(host="foo.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], annotations={}), + # tls enabled + IngressItemSpec(host="bar.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], annotations={}), + IngressItemSpec(host="foo.bar.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], annotations={}), + IngressItemSpec(host="other.cloud.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], annotations={}), + # tls disabled for suffix foo.example.com + IngressItemSpec(host="sub.foo.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], annotations={}), + # has annotations and tls disabled + IngressItemSpec(host="ann.foo.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], + annotations={"some": "annotation"}), + # has annotations and tls enabled + IngressItemSpec(host="ann.sub.example.com", pathmappings=[IngressPathMappingSpec(path="/", port=80)], + annotations={"some": "annotation"}) + ] + with mock.patch.object(ingress_tls_disable_tls_for_domain_suffixes, "apply",spec_set=True): + deployer_disable_tls_for_domain_suffixes.deploy(app_spec, LABELS) + host_groups = [sorted(call.args[2]) for call in ingress_tls_disable_tls_for_domain_suffixes.apply.call_args_list] + expected_host_groups = [ + ["ann.foo.example.com"], #annotation disable tls + ["ann.sub.example.com"], #annotation enable tls + ["bar.example.com", "foo.bar.example.com","other.cloud.com","testapp.svc.test.example.com"], #tls enabled + ["foo.example.com","sub.foo.example.com","testapp.127.0.0.1.xip.io"] #tls disabled + ] + assert ingress_tls_disable_tls_for_domain_suffixes.apply.call_count == 4 + assert expected_host_groups == sorted(host_groups) class TestIngressTls(object): HOSTS = ["host1", "host2", "host3", "this.host.is.so.long.that.it.is.impossible.to.use.as.the.common.name"] @@ -712,56 +757,66 @@ def tls(self, request, config): config.tls_certificate_issuer = request.param["cert_issuer"] config.ingress_suffixes = ["short.suffix", "really.quite.long.suffix"] config.enable_deprecated_tls_entry_per_host = request.param["enable_deprecated_tls_entry_per_host"] + config.tls_certificate_issuer_disable_for_domain_suffixes = request.param["tls_certificate_issuer_disable_for_domain_suffixes"] return IngressTls(config) @pytest.mark.parametrize("tls, app_spec, spec_tls, issuer_type, tls_annotations", [ - ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": ["common.name"]}, + app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), + [], DEFAULT_TLS_ISSUER, None), + ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": ["common.name"]}, + app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), + [], DEFAULT_TLS_ISSUER, None), + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": ["common.name"]}, + app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), + INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, {"kubernetes.io/tls-acme": "true"}), + ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, {"kubernetes.io/tls-acme": "true"}), - ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, {"kubernetes.io/tls-acme": "true"}), - ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS, "overwrite-issuer", {"overwrite-issuer": "letsencrypt"}), - ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, DEFAULT_TLS_ANNOTATIONS), - ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_off", "cert_issuer": "letsencrypt", "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer="myoverwrite")), INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, {"certmanager.k8s.io/cluster-issuer": "myoverwrite"}), - ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True}, + ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": True, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer="myoverwrite")), INGRESS_SPEC_TLS, DEFAULT_TLS_ISSUER, {"certmanager.k8s.io/cluster-issuer": "myoverwrite"}), - ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS_COLLAPSED_ONLY, DEFAULT_TLS_ISSUER, {"kubernetes.io/tls-acme": "true"}), - ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "default_off", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), INGRESS_SPEC_TLS_COLLAPSED_ONLY, DEFAULT_TLS_ISSUER, {"kubernetes.io/tls-acme": "true"}), - ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "default_on", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=True, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), - ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False}, + ({"use_ingress_tls": "disabled", "cert_issuer": None, "enable_deprecated_tls_entry_per_host": False, "tls_certificate_issuer_disable_for_domain_suffixes": []}, app_spec(ingress_tls=IngressTlsSpec(enabled=False, certificate_issuer=None)), [], DEFAULT_TLS_ISSUER, None), ], indirect=['tls']) def test_apply_tls(self, tls, app_spec, spec_tls, issuer_type, tls_annotations): diff --git a/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host1.yml b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host1.yml new file mode 100644 index 00000000..62164ae6 --- /dev/null +++ b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host1.yml @@ -0,0 +1,57 @@ + +# Copyright 2017-2019 The FIAAS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + fiaas/expose: "true" + labels: + app: v3-data-examples-tls-disable-tls-for-one-default-host + fiaas/deployed_by: "" + fiaas/deployment_id: DEPLOYMENT_ID + fiaas/version: VERSION + name: v3-data-examples-tls-disable-tls-for-one-default-host + namespace: default + ownerReferences: + - apiVersion: fiaas.schibsted.io/v1 + blockOwnerDeletion: true + controller: true + kind: Application + name: v3-data-examples-tls-disable-tls-for-one-default-host + finalizers: [] +spec: + tls: [] + rules: + - host: internal.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-default-host + servicePort: '80' + path: / + - host: www.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-default-host + servicePort: '80' + path: / + - host: v3-data-examples-tls-disable-tls-for-one-default-host.svc.test.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-default-host + servicePort: '80' + path: / diff --git a/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host2.yml b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host2.yml new file mode 100644 index 00000000..4f488031 --- /dev/null +++ b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_default_host2.yml @@ -0,0 +1,43 @@ + +# Copyright 2017-2019 The FIAAS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + fiaas/expose: "true" + labels: + app: v3-data-examples-tls-disable-tls-for-one-default-host + fiaas/deployed_by: "" + fiaas/deployment_id: DEPLOYMENT_ID + fiaas/version: VERSION + name: v3-data-examples-tls-disable-tls-for-one-default-host-1 + namespace: default + ownerReferences: + - apiVersion: fiaas.schibsted.io/v1 + blockOwnerDeletion: true + controller: true + kind: Application + name: v3-data-examples-tls-disable-tls-for-one-default-host + finalizers: [] +spec: + tls: [] + rules: + - host: v3-data-examples-tls-disable-tls-for-one-default-host.svc.notls.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-default-host + servicePort: '80' + path: / diff --git a/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host1.yml b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host1.yml new file mode 100644 index 00000000..6f70f8fc --- /dev/null +++ b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host1.yml @@ -0,0 +1,57 @@ + +# Copyright 2017-2019 The FIAAS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + fiaas/expose: "true" + labels: + app: v3-data-examples-tls-disable-tls-for-one-host + fiaas/deployed_by: "" + fiaas/deployment_id: DEPLOYMENT_ID + fiaas/version: VERSION + name: v3-data-examples-tls-disable-tls-for-one-host + namespace: default + ownerReferences: + - apiVersion: fiaas.schibsted.io/v1 + blockOwnerDeletion: true + controller: true + kind: Application + name: v3-data-examples-tls-disable-tls-for-one-host + finalizers: [] +spec: + tls: [] + rules: + - host: www.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-host + servicePort: '80' + path: / + - host: v3-data-examples-tls-disable-tls-for-one-host.svc.tls.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-host + servicePort: '80' + path: / + - host: v3-data-examples-tls-disable-tls-for-one-host.svc.test.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-host + servicePort: '80' + path: / \ No newline at end of file diff --git a/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host2.yml b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host2.yml new file mode 100644 index 00000000..a4068398 --- /dev/null +++ b/tests/fiaas_deploy_daemon/e2e_expected/tls_disable_tls_for_one_host2.yml @@ -0,0 +1,43 @@ + +# Copyright 2017-2019 The FIAAS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + fiaas/expose: "true" + labels: + app: v3-data-examples-tls-disable-tls-for-one-host + fiaas/deployed_by: "" + fiaas/deployment_id: DEPLOYMENT_ID + fiaas/version: VERSION + name: v3-data-examples-tls-disable-tls-for-one-host-1 + namespace: default + ownerReferences: + - apiVersion: fiaas.schibsted.io/v1 + blockOwnerDeletion: true + controller: true + kind: Application + name: v3-data-examples-tls-disable-tls-for-one-host + finalizers: [] +spec: + tls: [] + rules: + - host: internal.example.com + http: + paths: + - backend: + serviceName: v3-data-examples-tls-disable-tls-for-one-host + servicePort: '80' + path: / diff --git a/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_default_host.yml b/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_default_host.yml new file mode 100644 index 00000000..0b5d384d --- /dev/null +++ b/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_default_host.yml @@ -0,0 +1,4 @@ +version: 3 +ingress: + - host: internal.example.com + - host: www.example.com \ No newline at end of file diff --git a/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_host.yml b/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_host.yml new file mode 100644 index 00000000..0b5d384d --- /dev/null +++ b/tests/fiaas_deploy_daemon/specs/v3/data/examples/tls_disable_tls_for_one_host.yml @@ -0,0 +1,4 @@ +version: 3 +ingress: + - host: internal.example.com + - host: www.example.com \ No newline at end of file diff --git a/tests/fiaas_deploy_daemon/test_config.py b/tests/fiaas_deploy_daemon/test_config.py index 9328bf05..2114f2c9 100644 --- a/tests/fiaas_deploy_daemon/test_config.py +++ b/tests/fiaas_deploy_daemon/test_config.py @@ -167,6 +167,14 @@ def test_tls_issuers(self): "foo.bar.com": "issuer", "woo.foo.bar.com": "other" } + def test_tls_certificate_issuer_disable_for_domain_suffixes(self): + tls_certificate_issuer_disable_for_domain_suffixes = ["foo.bar.com", "example.foo.bar.org"] + args = ["--tls-certificate-issuer-disable-for-domain-suffixes=%s" % suffix for suffix in tls_certificate_issuer_disable_for_domain_suffixes] + config = Configuration(args) + assert config.tls_certificate_issuer_disable_for_domain_suffixes == [ + "foo.bar.com", + "example.foo.bar.org" + ] class TestHostRewriteRule(object): diff --git a/tests/fiaas_deploy_daemon/test_e2e.py b/tests/fiaas_deploy_daemon/test_e2e.py index 1fe84014..77ee029f 100644 --- a/tests/fiaas_deploy_daemon/test_e2e.py +++ b/tests/fiaas_deploy_daemon/test_e2e.py @@ -127,29 +127,42 @@ def prepare_k8s_client(self, kubernetes): def fdd(self, request, kubernetes, service_type, k8s_version, use_docker_for_e2e): args, port, ready = self.prepare_fdd(request, kubernetes, k8s_version, use_docker_for_e2e, service_type) try: - daemon = subprocess.Popen(args, stdout=sys.stderr, env=merge_dicts(os.environ, {"NAMESPACE": "default"})) - time.sleep(1) - if daemon.poll() is not None: - pytest.fail("fiaas-deploy-daemon has crashed after startup, inspect logs") - self.wait_until_fdd_ready(k8s_version, kubernetes, ready) + daemon=self.start_fdd(args,port,ready,k8s_version,kubernetes) yield "http://localhost:{}/fiaas".format(port) finally: self._end_popen(daemon) + + @pytest.fixture(scope="module") def fdd_service_account(self, request, kubernetes_per_app_service_account, k8s_version, use_docker_for_e2e): args, port, ready = self.prepare_fdd(request, kubernetes_per_app_service_account, k8s_version, use_docker_for_e2e, "ClusterIP", service_account=True) try: - daemon = subprocess.Popen(args, stdout=sys.stderr, env=merge_dicts(os.environ, {"NAMESPACE": "default"})) - time.sleep(1) - if daemon.poll() is not None: - pytest.fail("fiaas-deploy-daemon has crashed after startup, inspect logs") - self.wait_until_fdd_ready(k8s_version, kubernetes_per_app_service_account, ready) + daemon=self.start_fdd(args,port,ready,k8s_version,kubernetes_per_app_service_account) yield "http://localhost:{}/fiaas".format(port) finally: self._end_popen(daemon) + @pytest.fixture(scope="module") + def fdd_disable_tls_for_doamin_suffixes(self, request, kubernetes, service_type, k8s_version, use_docker_for_e2e): + args, port, ready = self.prepare_fdd(request, kubernetes, k8s_version, use_docker_for_e2e, service_type,disable_tls_for_doamin_suffixes=request.param["disable_tls"],extra_args=request.param["extra_args"]) + try: + daemon=self.start_fdd(args,port,ready,k8s_version,kubernetes) + yield "http://localhost:{}/fiaas".format(port) + finally: + self._end_popen(daemon) + + def start_fdd(self,args,port,ready,k8s_version,kubernetes): + daemon = subprocess.Popen(args, stdout=sys.stderr, env=merge_dicts(os.environ, {"NAMESPACE": "default"})) + time.sleep(1) + if daemon.poll() is not None: + pytest.fail("fiaas-deploy-daemon has crashed after startup, inspect logs") + self.wait_until_fdd_ready(k8s_version, kubernetes, ready) + return daemon + + + def wait_until_fdd_ready(self, k8s_version, kubernetes, ready): wait_until(ready, "web-interface healthy", RuntimeError, patience=PATIENCE) if crd_supported(k8s_version): @@ -157,8 +170,7 @@ def wait_until_fdd_ready(self, k8s_version, kubernetes, ready): crd_available(kubernetes, timeout=TIMEOUT), "CRD available", RuntimeError, patience=PATIENCE ) - - def prepare_fdd(self, request, kubernetes, k8s_version, use_docker_for_e2e, service_type, service_account=False): + def prepare_fdd(self, request, kubernetes, k8s_version, use_docker_for_e2e, service_type, service_account=False, disable_tls_for_doamin_suffixes=False, extra_args=[]): port = get_unbound_port() cert_path = os.path.dirname(kubernetes["api-cert"]) docker_args = use_docker_for_e2e(request, cert_path, service_type, k8s_version, port, @@ -172,19 +184,21 @@ def prepare_fdd(self, request, kubernetes, k8s_version, use_docker_for_e2e, serv "--client-cert", kubernetes["client-cert"], "--client-key", kubernetes["client-key"], "--service-type", service_type, - "--ingress-suffix", "svc.test.example.com", "--environment", "test", "--datadog-container-image", "DATADOG_IMAGE:tag", "--strongbox-init-container-image", "STRONGBOX_IMAGE", "--secret-init-containers", "parameter-store=PARAM_STORE_IMAGE", "--tls-certificate-issuer-type-overrides", "use-issuer.example.com=certmanager.k8s.io/issuer", - "--use-ingress-tls", "default_off", + "--use-ingress-tls", "default_off" ] if service_account: args.append("--enable-service-account-per-app") if crd_supported(k8s_version): args.append("--enable-crd-support") - args = docker_args + args + if disable_tls_for_doamin_suffixes is False: + args.append("--ingress-suffix") + args.append("svc.test.example.com") + args = docker_args + args + extra_args def ready(): resp = requests.get("http://localhost:{}/healthz".format(port), timeout=TIMEOUT) @@ -459,22 +473,37 @@ def test_custom_resource_definition_deploy_with_service_account(self, with kind_logger_per_app_service_account(): self.run_crd_deploy(custom_resource_definition_service_account, service_type, service_account=True) - @pytest.mark.usefixtures("fdd", "k8s_client") - @pytest.mark.parametrize("input, expected", [ + @pytest.mark.usefixtures("k8s_client") + @pytest.mark.parametrize("input, expected, fdd_disable_tls_for_doamin_suffixes", [ + ("tls_disable_tls_for_one_default_host", + { + "v3-data-examples-tls-disable-tls-for-one-default-host": "e2e_expected/tls_disable_tls_for_one_default_host1.yml", + "v3-data-examples-tls-disable-tls--one-default-host-1": "e2e_expected/tls_disable_tls_for_one_default_host2.yml" + },{"disable_tls": True,"extra_args": ["--ingress-suffix", "svc.notls.example.com","--ingress-suffix", "svc.test.example.com", "--tls-certificate-issuer-disable-for-domain-suffixes","notls.example.com"]} + ), + ("tls_disable_tls_for_one_host", + { + "v3-data-examples-tls-disable-tls-for-one-host": "e2e_expected/tls_disable_tls_for_one_host1.yml", + "v3-data-examples-tls-disable-tls--one-host-1": "e2e_expected/tls_disable_tls_for_one_host2.yml" + },{"disable_tls": True,"extra_args": ["--ingress-suffix", "svc.tls.example.com","--ingress-suffix", "svc.test.example.com", "--tls-certificate-issuer-disable-for-domain-suffixes","internal.example.com"]} + ), ("multiple_ingress", { "v3-data-examples-multiple-ingress": "e2e_expected/multiple_ingress1.yml", "v3-data-examples-multiple-ingress-1": "e2e_expected/multiple_ingress2.yml" - }), + },{"disable_tls": False,"extra_args": [] } + ), ("multiple_ingress_default_host", { "v3-data-examples-multiple-ingress-default-host": "e2e_expected/multiple_ingress_default_host1.yml", "v3-data-examples-multiple-ingress-default-host-1": "e2e_expected/multiple_ingress_default_host2.yml" - }), + },{"disable_tls": False,"extra_args": [] } + ), ("tls_issuer_override", { "v3-data-examples-tls-issuer-override": "e2e_expected/tls_issuer_override1.yml", "v3-data-examples-tls-issuer-override-1": "e2e_expected/tls_issuer_override2.yml" - }) - ]) - def test_multiple_ingresses(self, request, kind_logger, input, expected): + },{"disable_tls": False,"extra_args": [] } + ) + ],indirect=['fdd_disable_tls_for_doamin_suffixes']) + def test_multiple_ingresses(self, request, kind_logger, input, expected,fdd_disable_tls_for_doamin_suffixes,capsys): with kind_logger(): fiaas_path = "v3/data/examples/%s.yml" % input fiaas_yml = read_yml(request.fspath.dirpath().join("specs").join(fiaas_path).strpath) @@ -497,7 +526,8 @@ def _assert_status(): assert any("Saving result RUNNING for default/{}".format(name) in line for line in status.logs) wait_until(_assert_status, patience=PATIENCE) - + with capsys.disabled(): + print("check two ingress") def _check_two_ingresses(): assert Ingress.get(name) assert Ingress.get("{}-1".format(name)) @@ -506,8 +536,9 @@ def _check_two_ingresses(): actual = Ingress.get(ingress_name) assert_k8s_resource_matches(actual, expected_dict, IMAGE1, None, DEPLOYMENT_ID1, None, app_uid) - wait_until(_check_two_ingresses, patience=PATIENCE) - + wait_until(_check_two_ingresses, patience=PATIENCE) + with capsys.disabled(): + print("Remove 2nd ingress to make sure cleanup works") # Remove 2nd ingress to make sure cleanup works fiaas_application.spec.config["ingress"].pop() if not fiaas_application.spec.config["ingress"]: @@ -517,13 +548,14 @@ def _check_two_ingresses(): fiaas_application.metadata.labels["fiaas/deployment_id"] = DEPLOYMENT_ID2 fiaas_application.save() - def _check_one_ingress(): + def _check_one_ingress(): assert Ingress.get(name) with pytest.raises(NotFound): Ingress.get("{}-1".format(name)) wait_until(_check_one_ingress, patience=PATIENCE) - + with capsys.disabled(): + print("Cleaning up") # Cleanup FiaasApplication.delete(name) @@ -533,7 +565,8 @@ def cleanup_complete(): Ingress.get(name) wait_until(cleanup_complete, patience=PATIENCE) - + with capsys.disabled(): + print("Done!") def _deploy_success(name, service_type, image, expected, deployment_id, strongbox_groups=None, app_uid=None): def action():