diff --git a/LICENSES b/LICENSES index da1276d5b..5d99224cb 100644 --- a/LICENSES +++ b/LICENSES @@ -15993,6 +15993,426 @@ limitations under the License. ================================================================================ +================================================================================ += vendor/istio.io/api licensed under: = + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2020 Istio 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. + += vendor/istio.io/api/LICENSE c4d266576c16d0427812c22cafa149c1 +================================================================================ + + +================================================================================ += vendor/istio.io/gogo-genproto licensed under: = + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2019 Istio 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. + += vendor/istio.io/gogo-genproto/LICENSE 7f1c1dda4011e02cc15ed3f4777e1358 +================================================================================ + + ================================================================================ = vendor/k8s.io/api licensed under: = diff --git a/cmd/controller/app/BUILD.bazel b/cmd/controller/app/BUILD.bazel index be43dc990..5c8efc42b 100644 --- a/cmd/controller/app/BUILD.bazel +++ b/cmd/controller/app/BUILD.bazel @@ -23,6 +23,7 @@ go_library( "//pkg/controller/issuers:go_default_library", "//pkg/issuer/acme:go_default_library", "//pkg/issuer/acme/dns/util:go_default_library", + "//pkg/issuer/acme/http/internal/istio:go_default_library", "//pkg/issuer/ca:go_default_library", "//pkg/issuer/selfsigned:go_default_library", "//pkg/issuer/vault:go_default_library", @@ -33,9 +34,12 @@ go_library( "//pkg/util/feature:go_default_library", "@com_github_spf13_cobra//:go_default_library", "@io_k8s_api//core/v1:go_default_library", + "@io_k8s_apimachinery//pkg/api/errors:go_default_library", "@io_k8s_apimachinery//pkg/api/resource:go_default_library", "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library", "@io_k8s_apimachinery//pkg/util/errors:go_default_library", + "@io_k8s_client_go//dynamic:go_default_library", + "@io_k8s_client_go//dynamic/dynamicinformer:go_default_library", "@io_k8s_client_go//informers:go_default_library", "@io_k8s_client_go//kubernetes:go_default_library", "@io_k8s_client_go//kubernetes/scheme:go_default_library", diff --git a/cmd/controller/app/controller.go b/cmd/controller/app/controller.go index d5e6e09a7..7c1305853 100644 --- a/cmd/controller/app/controller.go +++ b/cmd/controller/app/controller.go @@ -24,8 +24,11 @@ import ( "time" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + dynamicclient "k8s.io/client-go/dynamic" + dynamicinformers "k8s.io/client-go/dynamic/dynamicinformer" kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" @@ -45,6 +48,7 @@ import ( "github.com/jetstack/cert-manager/pkg/controller" "github.com/jetstack/cert-manager/pkg/controller/clusterissuers" dnsutil "github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util" + "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio" logf "github.com/jetstack/cert-manager/pkg/logs" "github.com/jetstack/cert-manager/pkg/metrics" "github.com/jetstack/cert-manager/pkg/util" @@ -68,6 +72,26 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) { os.Exit(1) } + ctx.IstioEnabled, err = isIstioInstalled(ctx) + if err != nil { + log.Error(err, "failed to discover if Istio is available") + os.Exit(1) + } + + if ctx.IstioEnabled { + ctx.IstioEnabled, err = canListVirtualService(rootCtx, ctx, opts.Namespace) + if err != nil { + log.Error(err, "failed to list Istio VirtualServices") + os.Exit(1) + } + } + + if ctx.IstioEnabled { + log.Info("Istio support is enabled") + } else { + log.Info("Istio support is disabled") + } + enabledControllers := opts.EnabledControllers() log.Info(fmt.Sprintf("enabled controllers: %s", enabledControllers.List())) @@ -117,6 +141,9 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) { log.V(logf.DebugLevel).Info("starting shared informer factories") ctx.SharedInformerFactory.Start(stopCh) ctx.KubeSharedInformerFactory.Start(stopCh) + if ctx.IstioEnabled { + ctx.DynamicSharedInformerFactory.Start(stopCh) + } wg.Wait() log.V(logf.InfoLevel).Info("control loops exited") ctx.Metrics.Shutdown(metricsServer) @@ -138,6 +165,33 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) { startLeaderElection(rootCtx, opts, leaderElectionClient, ctx.Recorder, run) } +func isIstioInstalled(ctx *controller.Context) (bool, error) { + groups, err := ctx.Client.Discovery().ServerGroups() + if err != nil { + return false, err + } + + for _, group := range groups.Groups { + if group.Name == istio.VirtualServiceGvr().Group { + return true, nil + } + } + return false, nil +} + +func canListVirtualService(rootCtx context.Context, ctx *controller.Context, namespace string) (bool, error) { + // Check if sa has permissions to list virtualservice + _, err := ctx.DynamicClient.Resource(istio.VirtualServiceGvr()).Namespace(namespace).List(rootCtx, metav1.ListOptions{}) + if errors.IsForbidden(err) { + return false, nil + } + if err != nil { + return false, err + } + + return true, nil +} + func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *options.ControllerOptions) (*controller.Context, *rest.Config, error) { log := logf.FromContext(ctx, "build-context") // Load the users Kubernetes config @@ -164,6 +218,11 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o return nil, nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) } + dyncl, err := dynamicclient.NewForConfig(kubeCfg) + if err != nil { + return nil, nil, fmt.Errorf("error creating dynamic client: %s", err.Error()) + } + nameservers := opts.DNS01RecursiveNameservers if len(nameservers) == 0 { nameservers = dnsutil.RecursiveNameservers @@ -202,21 +261,24 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o sharedInformerFactory := informers.NewSharedInformerFactoryWithOptions(intcl, resyncPeriod, informers.WithNamespace(opts.Namespace)) kubeSharedInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(cl, resyncPeriod, kubeinformers.WithNamespace(opts.Namespace)) + dynamicSharedInformerFactory := dynamicinformers.NewFilteredDynamicSharedInformerFactory(dyncl, resyncPeriod, opts.Namespace, nil) acmeAccountRegistry := accounts.NewDefaultRegistry() return &controller.Context{ - RootContext: ctx, - StopCh: stopCh, - RESTConfig: kubeCfg, - Client: cl, - CMClient: intcl, - Recorder: recorder, - KubeSharedInformerFactory: kubeSharedInformerFactory, - SharedInformerFactory: sharedInformerFactory, - Namespace: opts.Namespace, - Clock: clock.RealClock{}, - Metrics: metrics.New(log), + RootContext: ctx, + StopCh: stopCh, + RESTConfig: kubeCfg, + Client: cl, + DynamicClient: dyncl, + CMClient: intcl, + Recorder: recorder, + KubeSharedInformerFactory: kubeSharedInformerFactory, + DynamicSharedInformerFactory: dynamicSharedInformerFactory, + SharedInformerFactory: sharedInformerFactory, + Namespace: opts.Namespace, + Clock: clock.RealClock{}, + Metrics: metrics.New(log), ACMEOptions: controller.ACMEOptions{ HTTP01SolverImage: opts.ACMEHTTP01SolverImage, HTTP01SolverResourceRequestCPU: HTTP01SolverResourceRequestCPU, diff --git a/deploy/charts/cert-manager/templates/rbac.yaml b/deploy/charts/cert-manager/templates/rbac.yaml index f5a549922..66a87624a 100644 --- a/deploy/charts/cert-manager/templates/rbac.yaml +++ b/deploy/charts/cert-manager/templates/rbac.yaml @@ -223,6 +223,12 @@ rules: - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "watch", "create", "delete", "update"] + # HTTP01 Istio rules + # Need to be able to create and update Istio virtualservices that are used + # to route HTTP01 requests to the challenge solver pod + - apiGroups: ["networking.istio.io"] + resources: ["virtualservices"] + verbs: ["get", "list", "watch", "create", "delete", "update"] # We require the ability to specify a custom hostname when we are creating # new ingress resources. # See: https://github.com/openshift/origin/blob/21f191775636f9acadb44fa42beeb4f75b255532/pkg/route/apiserver/admission/ingress_admission.go#L84-L148 diff --git a/deploy/crds/crd-challenges.yaml b/deploy/crds/crd-challenges.yaml index 9b8127929..6e526013a 100644 --- a/deploy/crds/crd-challenges.yaml +++ b/deploy/crds/crd-challenges.yaml @@ -797,6 +797,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -1622,6 +2032,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -2448,6 +3268,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -3274,6 +4504,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object diff --git a/deploy/crds/crd-clusterissuers.yaml b/deploy/crds/crd-clusterissuers.yaml index ef5bb7816..1f7d30001 100644 --- a/deploy/crds/crd-clusterissuers.yaml +++ b/deploy/crds/crd-clusterissuers.yaml @@ -831,6 +831,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -1868,6 +2278,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -2907,6 +3727,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -3946,6 +5176,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object diff --git a/deploy/crds/crd-issuers.yaml b/deploy/crds/crd-issuers.yaml index 040901865..ab5d0cf91 100644 --- a/deploy/crds/crd-issuers.yaml +++ b/deploy/crds/crd-issuers.yaml @@ -831,6 +831,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -1868,6 +2278,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -2907,6 +3727,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object @@ -3946,6 +5176,416 @@ spec: serviceType: description: Optional service type for Kubernetes solver service type: string + istio: + description: The Istio virtualservice based HTTP01 challenge solver will solve challenges by creating an Istio virtualservice resource that is connected to the specified Istio gateway in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. + type: object + required: + - gatewayName + - gatewayNamespace + properties: + gatewayName: + description: Name of the gateway that is used to generate the virtualservice for. + type: string + gatewayNamespace: + description: Namespace of the gateway that is used to generate the virtualservice for. + type: string + podTemplate: + description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges + type: object + properties: + metadata: + description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. + type: object + properties: + annotations: + description: Annotations that should be added to the create ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + labels: + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + additionalProperties: + type: string + spec: + description: PodSpec defines overrides for the HTTP01 challenge solver pod. Only the 'priorityClassName', 'nodeSelector', 'affinity', 'serviceAccountName' and 'tolerations' fields are supported currently. All other fields will be ignored. + type: object + properties: + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace" + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string selector: description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. type: object diff --git a/devel/addon/bind/manifests/configmap.yaml b/devel/addon/bind/manifests/configmap.yaml index 460c1ccad..fddd5700c 100644 --- a/devel/addon/bind/manifests/configmap.yaml +++ b/devel/addon/bind/manifests/configmap.yaml @@ -37,6 +37,8 @@ data: @ IN NS localhost. *.ingress-nginx IN A {SERVICE_IP_PREFIX}.15 ingress-nginx IN A {SERVICE_IP_PREFIX}.15 + *.istio IN A {SERVICE_IP_PREFIX}.14 + istio IN A {SERVICE_IP_PREFIX}.14 db.dns01.example.com: | ; diff --git a/devel/addon/istio/install.sh b/devel/addon/istio/install.sh new file mode 100755 index 000000000..6a9742eaa --- /dev/null +++ b/devel/addon/istio/install.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Copyright 2021 The cert-manager 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. + +set -o nounset +set -o errexit +set -o pipefail + +# Installs Istio using istioctl and the manifests located in manifests/ +# Configure the cluster to target using the KUBECONFIG environment variable. +# Additional parameters can be configured by overriding the variables below. + +SCRIPT_ROOT=$(dirname "${BASH_SOURCE}") +source "${SCRIPT_ROOT}/../../lib/lib.sh" +SCRIPT_ROOT=$(dirname "${BASH_SOURCE}") + +check_tool kubectl +check_tool istioctl + +# Namespace to deploy into +NAMESPACE="${NAMESPACE:-istio-system}" + +SERVICE_IP_PREFIX="${SERVICE_IP_PREFIX:-10.0.0}" + +istioctl install \ + --skip-confirmation \ + --set profile=default \ + --set values.global.jwtPolicy=first-party-jwt \ + --set components.ingressGateways[0].name="istio-ingressgateway" \ + --set components.ingressGateways[0].k8s.service.type="ClusterIP" \ + --set components.ingressGateways[0].k8s.service.clusterIP="${SERVICE_IP_PREFIX}.14" + +kubectl --namespace "${NAMESPACE}" apply -f "${SCRIPT_ROOT}/manifests/gateway.yaml" diff --git a/devel/addon/istio/manifests/gateway.yaml b/devel/addon/istio/manifests/gateway.yaml new file mode 100644 index 000000000..8f8cb3c0e --- /dev/null +++ b/devel/addon/istio/manifests/gateway.yaml @@ -0,0 +1,14 @@ +apiVersion: networking.istio.io/v1beta1 +kind: Gateway +metadata: + name: ingress +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - '*' + port: + name: http + number: 80 + protocol: HTTP diff --git a/devel/bin/istioctl b/devel/bin/istioctl new file mode 100755 index 000000000..e06ee34fd --- /dev/null +++ b/devel/bin/istioctl @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Copyright 2021 The cert-manager 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. + +set -o nounset +set -o errexit +set -o pipefail + +if ! command -v bazel &>/dev/null; then + echo "Install bazel at https://bazel.build" >&2 + exit 1 +fi + +if [ -z "${ISTIOCTL:-}" ]; then + bazel build //hack/bin:istioctl + export ISTIOCTL="$(bazel info bazel-genfiles)/hack/bin/istioctl" +fi + +"${ISTIOCTL}" "$@" diff --git a/devel/lib/lib.sh b/devel/lib/lib.sh index 218ccc39a..014811da2 100644 --- a/devel/lib/lib.sh +++ b/devel/lib/lib.sh @@ -34,12 +34,13 @@ export OPENSHIFT_VERSION="${OPENSHIFT_VERSION:-"3.11"}" export SERVICE_IP_PREFIX="${SERVICE_IP_PREFIX:-10.0.0}" export DNS_SERVER="${SERVICE_IP_PREFIX}.16" export INGRESS_IP="${SERVICE_IP_PREFIX}.15" +export ISTIO_IP="${SERVICE_IP_PREFIX}.14" # setup_tools will build and set up the environment to use bazel-provided # versions of the tools required for development setup_tools() { check_bazel - bazel build //hack/bin:helm //hack/bin:kind //hack/bin:kubectl //hack/bin:kustomize //devel/bin:ginkgo + bazel build //hack/bin:helm //hack/bin:kind //hack/bin:kubectl //hack/bin:kustomize //devel/bin:ginkgo //hack/bin:istioctl if [[ "$IS_OPENSHIFT" == "true" ]] ; then bazel build //hack/bin:oc3 fi @@ -48,6 +49,7 @@ setup_tools() { export KIND="${bindir}/hack/bin/kind" export OC3="${bindir}/hack/bin/oc3" export KUBECTL="${bindir}/hack/bin/kubectl" + export ISTIOCTL="${bindir}/hack/bin/istioctl" export KUSTOMIZE="${bindir}/hack/bin/kustomize" export GINKGO="${bindir}/devel/bin/ginkgo" # Configure PATH to use bazel provided e2e tools diff --git a/devel/run-e2e.sh b/devel/run-e2e.sh index d347db47f..073206f85 100755 --- a/devel/run-e2e.sh +++ b/devel/run-e2e.sh @@ -46,4 +46,5 @@ ginkgo -nodes 10 -flakeAttempts ${FLAKE_ATTEMPTS:-1} \ --report-dir="${ARTIFACTS:-$REPO_ROOT/_artifacts}" \ --acme-dns-server="$DNS_SERVER" \ --acme-ingress-ip="$INGRESS_IP" \ + --acme-istio-ip="$ISTIO_IP" \ "$@" diff --git a/devel/setup-e2e-deps.sh b/devel/setup-e2e-deps.sh index 5508235f7..6eaff501b 100755 --- a/devel/setup-e2e-deps.sh +++ b/devel/setup-e2e-deps.sh @@ -31,6 +31,9 @@ source "${SCRIPT_ROOT}/lib/lib.sh" # Configure PATH to use bazel provided e2e tools setup_tools +echo "Installing istio into the kind cluster..." +"${SCRIPT_ROOT}/addon/istio/install.sh" + echo "Installing cert-manager into the cluster..." "${SCRIPT_ROOT}/addon/certmanager/install.sh" diff --git a/go.mod b/go.mod index 42f35884f..c3e159e73 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( gopkg.in/ini.v1 v1.52.0 // indirect gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c // indirect + istio.io/api v0.0.0-20210114003959-328c3a371318 k8s.io/api v0.19.0 k8s.io/apiextensions-apiserver v0.19.0 k8s.io/apimachinery v0.19.0 diff --git a/go.sum b/go.sum index a1f852946..2a75e92dc 100644 --- a/go.sum +++ b/go.sum @@ -124,6 +124,8 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.13.2 h1:bhMGoNhAg21DuqJjU9jQepRRft6vYfo6pejT3NN4V6A= github.com/cloudflare/cloudflare-go v0.13.2/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= @@ -184,8 +186,10 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -291,6 +295,7 @@ github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -939,9 +944,11 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1004,6 +1011,10 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +istio.io/api v0.0.0-20210114003959-328c3a371318 h1:U0KZYCOKILJw51SWV5vpcR4FMTXl1CmA70aFy4zMKrU= +istio.io/api v0.0.0-20210114003959-328c3a371318/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64= +istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a h1:w7zILua2dnYo9CxImhpNW4NE/8ZxEoc/wfBfHrhUhrE= +istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs= k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc= @@ -1013,6 +1024,7 @@ k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKi k8s.io/apiextensions-apiserver v0.19.0 h1:jlY13lvZp+0p9fRX2khHFdiT9PYzT7zUrANz6R1NKtY= k8s.io/apiextensions-apiserver v0.19.0/go.mod h1:znfQxNpjqz/ZehvbfMg5N6fvBJW5Lqu5HVLTJQdP4Fs= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.1/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ= k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= diff --git a/hack/bin/BUILD.bazel b/hack/bin/BUILD.bazel index 531b8d9f2..58405eb63 100644 --- a/hack/bin/BUILD.bazel +++ b/hack/bin/BUILD.bazel @@ -80,6 +80,18 @@ genrule( visibility = ["//visibility:public"], ) +genrule( + name = "fetch_istioctl", + srcs = select({ + ":darwin": ["@istioctl_darwin//:file"], + ":k8": ["@istioctl_linux//:file"], + }), + outs = ["istioctl"], + cmd = "cp $(SRCS) $@", + tags = ["manual"], + visibility = ["//visibility:public"], +) + genrule( name = "fetch_oc3", srcs = select({ diff --git a/hack/bin/deps.bzl b/hack/bin/deps.bzl index 6fde49ce5..bad89dcee 100644 --- a/hack/bin/deps.bzl +++ b/hack/bin/deps.bzl @@ -23,6 +23,7 @@ def install(): install_staticcheck() install_helm() install_kubectl() + install_istioctl() install_oc3() install_kind() install_kustomize() @@ -232,6 +233,38 @@ def install_kubectl(): urls = ["https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl"], ) +def install_istioctl(): + http_archive( + name = "istioctl_darwin", + sha256 = "fa0cca95e5c4b1d1084946a8d7953d4a1e830d80c36ef10bbbfae8ce4480ccc8", + urls = ["https://github.com/istio/istio/releases/download/1.9.3/istioctl-1.9.3-osx.tar.gz"], + build_file_content = + """ +filegroup( + name = "file", + srcs = [ + "istioctl", + ], + visibility = ["//visibility:public"], +) +""", + ) + + http_archive( + name = "istioctl_linux", + sha256 = "f820aa0e0e85a5c5a5b20c1409f03e58d9783646b5976db2ef85ddac12b43848", + urls = ["https://github.com/istio/istio/releases/download/1.9.3/istioctl-1.9.3-linux-amd64.tar.gz"], + build_file_content = + """ +filegroup( + name = "file", + srcs = [ + "istioctl", + ], + visibility = ["//visibility:public"], +) +""", + ) # Define rules for different oc versions def install_oc3(): diff --git a/hack/build/repos.bzl b/hack/build/repos.bzl index 4c97fb539..94f8e4de4 100644 --- a/hack/build/repos.bzl +++ b/hack/build/repos.bzl @@ -719,8 +719,8 @@ def go_repositories(): build_file_generation = "on", build_file_proto_mode = "disable", importpath = "github.com/envoyproxy/go-control-plane", - sum = "h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=", - version = "v0.9.1-0.20191026205805-5f8ba28d4473", + sum = "h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=", + version = "v0.9.4", ) go_repository( name = "com_github_envoyproxy_protoc_gen_validate", @@ -3063,6 +3063,23 @@ def go_repositories(): sum = "h1:Gqga3zA9tdAcfqobUGjSoCob5L3f8Dt5EuOp3ihNZko=", version = "v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5", ) + go_repository( + name = "io_istio_api", + build_file_generation = "on", + build_file_proto_mode = "disable", + importpath = "istio.io/api", + sum = "h1:U0KZYCOKILJw51SWV5vpcR4FMTXl1CmA70aFy4zMKrU=", + version = "v0.0.0-20210114003959-328c3a371318", + ) + go_repository( + name = "io_istio_gogo_genproto", + build_file_generation = "on", + build_file_proto_mode = "disable", + importpath = "istio.io/gogo-genproto", + sum = "h1:w7zILua2dnYo9CxImhpNW4NE/8ZxEoc/wfBfHrhUhrE=", + version = "v0.0.0-20190930162913-45029607206a", + ) + go_repository( name = "io_k8s_api", build_file_generation = "on", @@ -3356,8 +3373,8 @@ def go_repositories(): build_file_generation = "on", build_file_proto_mode = "disable", importpath = "google.golang.org/grpc", - sum = "h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=", - version = "v1.27.0", + sum = "h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k=", + version = "v1.28.1", ) go_repository( name = "org_golang_google_grpc_examples", diff --git a/pkg/apis/acme/v1/types_issuer.go b/pkg/apis/acme/v1/types_issuer.go index 76691fb4d..2dc96de99 100644 --- a/pkg/apis/acme/v1/types_issuer.go +++ b/pkg/apis/acme/v1/types_issuer.go @@ -204,6 +204,14 @@ type ACMEChallengeSolverHTTP01 struct { // provisioned by cert-manager for each Challenge to be completed. // +optional Ingress *ACMEChallengeSolverHTTP01Ingress `json:"ingress,omitempty"` + + // The Istio virtualservice based HTTP01 challenge solver will solve + // challenges by creating an Istio virtualservice resource that is connected + // to the specified Istio gateway in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Istio *ACMEChallengeSolverHTTP01Istio `json:"istio,omitempty"` } type ACMEChallengeSolverHTTP01Ingress struct { @@ -305,6 +313,19 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct { Labels map[string]string `json:"labels,omitempty"` } +type ACMEChallengeSolverHTTP01Istio struct { + // Namespace of the gateway that is used to generate the virtualservice for. + GatewayNamespace string `json:"gatewayNamespace"` + + // Name of the gateway that is used to generate the virtualservice for. + GatewayName string `json:"gatewayName"` + + // Optional pod template used to configure the ACME challenge solver pods + // used for HTTP01 challenges + // +optional + PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"` +} + // Used to configure a DNS01 challenge provider to be used when solving DNS01 // challenges. // Only one DNS provider may be configured per solver. diff --git a/pkg/apis/acme/v1/zz_generated.deepcopy.go b/pkg/apis/acme/v1/zz_generated.deepcopy.go index 40c190234..5e062bb5d 100644 --- a/pkg/apis/acme/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1/zz_generated.deepcopy.go @@ -170,6 +170,11 @@ func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01 *out = new(ACMEChallengeSolverHTTP01Ingress) (*in).DeepCopyInto(*out) } + if in.Istio != nil { + in, out := &in.Istio, &out.Istio + *out = new(ACMEChallengeSolverHTTP01Istio) + (*in).DeepCopyInto(*out) + } return } @@ -344,6 +349,27 @@ func (in *ACMEChallengeSolverHTTP01IngressTemplate) DeepCopy() *ACMEChallengeSol return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopyInto(out *ACMEChallengeSolverHTTP01Istio) { + *out = *in + if in.PodTemplate != nil { + in, out := &in.PodTemplate, &out.PodTemplate + *out = new(ACMEChallengeSolverHTTP01IngressPodTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Istio. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopy() *ACMEChallengeSolverHTTP01Istio { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Istio) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEExternalAccountBinding) DeepCopyInto(out *ACMEExternalAccountBinding) { *out = *in diff --git a/pkg/apis/acme/v1alpha2/types_issuer.go b/pkg/apis/acme/v1alpha2/types_issuer.go index 21b268894..8601f6960 100644 --- a/pkg/apis/acme/v1alpha2/types_issuer.go +++ b/pkg/apis/acme/v1alpha2/types_issuer.go @@ -204,6 +204,14 @@ type ACMEChallengeSolverHTTP01 struct { // provisioned by cert-manager for each Challenge to be completed. // +optional Ingress *ACMEChallengeSolverHTTP01Ingress `json:"ingress,omitempty"` + + // The Istio virtualservice based HTTP01 challenge solver will solve + // challenges by creating an Istio virtualservice resource that is connected + // to the specified Istio gateway in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Istio *ACMEChallengeSolverHTTP01Istio `json:"istio,omitempty"` } type ACMEChallengeSolverHTTP01Ingress struct { @@ -305,6 +313,19 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct { Labels map[string]string `json:"labels,omitempty"` } +type ACMEChallengeSolverHTTP01Istio struct { + // Namespace of the gateway that is used to generate the virtualservice for. + GatewayNamespace string `json:"gatewayNamespace"` + + // Name of the gateway that is used to generate the virtualservice for. + GatewayName string `json:"gatewayName"` + + // Optional pod template used to configure the ACME challenge solver pods + // used for HTTP01 challenges + // +optional + PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"` +} + // Used to configure a DNS01 challenge provider to be used when solving DNS01 // challenges. // Only one DNS provider may be configured per solver. diff --git a/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go index a0772368a..2a15e1c57 100644 --- a/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go @@ -170,6 +170,11 @@ func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01 *out = new(ACMEChallengeSolverHTTP01Ingress) (*in).DeepCopyInto(*out) } + if in.Istio != nil { + in, out := &in.Istio, &out.Istio + *out = new(ACMEChallengeSolverHTTP01Istio) + (*in).DeepCopyInto(*out) + } return } @@ -344,6 +349,27 @@ func (in *ACMEChallengeSolverHTTP01IngressTemplate) DeepCopy() *ACMEChallengeSol return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopyInto(out *ACMEChallengeSolverHTTP01Istio) { + *out = *in + if in.PodTemplate != nil { + in, out := &in.PodTemplate, &out.PodTemplate + *out = new(ACMEChallengeSolverHTTP01IngressPodTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Istio. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopy() *ACMEChallengeSolverHTTP01Istio { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Istio) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEExternalAccountBinding) DeepCopyInto(out *ACMEExternalAccountBinding) { *out = *in diff --git a/pkg/apis/acme/v1alpha3/types_issuer.go b/pkg/apis/acme/v1alpha3/types_issuer.go index ca132658e..7fab268e5 100644 --- a/pkg/apis/acme/v1alpha3/types_issuer.go +++ b/pkg/apis/acme/v1alpha3/types_issuer.go @@ -204,6 +204,14 @@ type ACMEChallengeSolverHTTP01 struct { // provisioned by cert-manager for each Challenge to be completed. // +optional Ingress *ACMEChallengeSolverHTTP01Ingress `json:"ingress,omitempty"` + + // The Istio virtualservice based HTTP01 challenge solver will solve + // challenges by creating an Istio virtualservice resource that is connected + // to the specified Istio gateway in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Istio *ACMEChallengeSolverHTTP01Istio `json:"istio,omitempty"` } type ACMEChallengeSolverHTTP01Ingress struct { @@ -305,6 +313,19 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct { Labels map[string]string `json:"labels,omitempty"` } +type ACMEChallengeSolverHTTP01Istio struct { + // Namespace of the gateway that is used to generate the virtualservice for. + GatewayNamespace string `json:"gatewayNamespace"` + + // Name of the gateway that is used to generate the virtualservice for. + GatewayName string `json:"gatewayName"` + + // Optional pod template used to configure the ACME challenge solver pods + // used for HTTP01 challenges + // +optional + PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"` +} + // Used to configure a DNS01 challenge provider to be used when solving DNS01 // challenges. // Only one DNS provider may be configured per solver. diff --git a/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go index 4b3f51f4a..affd75882 100644 --- a/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go @@ -170,6 +170,11 @@ func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01 *out = new(ACMEChallengeSolverHTTP01Ingress) (*in).DeepCopyInto(*out) } + if in.Istio != nil { + in, out := &in.Istio, &out.Istio + *out = new(ACMEChallengeSolverHTTP01Istio) + (*in).DeepCopyInto(*out) + } return } @@ -344,6 +349,27 @@ func (in *ACMEChallengeSolverHTTP01IngressTemplate) DeepCopy() *ACMEChallengeSol return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopyInto(out *ACMEChallengeSolverHTTP01Istio) { + *out = *in + if in.PodTemplate != nil { + in, out := &in.PodTemplate, &out.PodTemplate + *out = new(ACMEChallengeSolverHTTP01IngressPodTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Istio. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopy() *ACMEChallengeSolverHTTP01Istio { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Istio) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEExternalAccountBinding) DeepCopyInto(out *ACMEExternalAccountBinding) { *out = *in diff --git a/pkg/apis/acme/v1beta1/types_issuer.go b/pkg/apis/acme/v1beta1/types_issuer.go index b08260a9e..b99b960b5 100644 --- a/pkg/apis/acme/v1beta1/types_issuer.go +++ b/pkg/apis/acme/v1beta1/types_issuer.go @@ -204,6 +204,14 @@ type ACMEChallengeSolverHTTP01 struct { // provisioned by cert-manager for each Challenge to be completed. // +optional Ingress *ACMEChallengeSolverHTTP01Ingress `json:"ingress,omitempty"` + + // The Istio virtualservice based HTTP01 challenge solver will solve + // challenges by creating an Istio virtualservice resource that is connected + // to the specified Istio gateway in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Istio *ACMEChallengeSolverHTTP01Istio `json:"istio,omitempty"` } type ACMEChallengeSolverHTTP01Ingress struct { @@ -305,6 +313,19 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct { Labels map[string]string `json:"labels,omitempty"` } +type ACMEChallengeSolverHTTP01Istio struct { + // Namespace of the gateway that is used to generate the virtualservice for. + GatewayNamespace string `json:"gatewayNamespace"` + + // Name of the gateway that is used to generate the virtualservice for. + GatewayName string `json:"gatewayName"` + + // Optional pod template used to configure the ACME challenge solver pods + // used for HTTP01 challenges + // +optional + PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"` +} + // Used to configure a DNS01 challenge provider to be used when solving DNS01 // challenges. // Only one DNS provider may be configured per solver. diff --git a/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go b/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go index 9b090025a..9f92e77f2 100644 --- a/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go @@ -170,6 +170,11 @@ func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01 *out = new(ACMEChallengeSolverHTTP01Ingress) (*in).DeepCopyInto(*out) } + if in.Istio != nil { + in, out := &in.Istio, &out.Istio + *out = new(ACMEChallengeSolverHTTP01Istio) + (*in).DeepCopyInto(*out) + } return } @@ -344,6 +349,27 @@ func (in *ACMEChallengeSolverHTTP01IngressTemplate) DeepCopy() *ACMEChallengeSol return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopyInto(out *ACMEChallengeSolverHTTP01Istio) { + *out = *in + if in.PodTemplate != nil { + in, out := &in.PodTemplate, &out.PodTemplate + *out = new(ACMEChallengeSolverHTTP01IngressPodTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Istio. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopy() *ACMEChallengeSolverHTTP01Istio { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Istio) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEExternalAccountBinding) DeepCopyInto(out *ACMEExternalAccountBinding) { *out = *in diff --git a/pkg/controller/BUILD.bazel b/pkg/controller/BUILD.bazel index 2a6ef952a..ac57fce39 100644 --- a/pkg/controller/BUILD.bazel +++ b/pkg/controller/BUILD.bazel @@ -25,6 +25,8 @@ go_library( "@io_k8s_apimachinery//pkg/runtime/schema:go_default_library", "@io_k8s_apimachinery//pkg/util/runtime:go_default_library", "@io_k8s_apimachinery//pkg/util/wait:go_default_library", + "@io_k8s_client_go//dynamic:go_default_library", + "@io_k8s_client_go//dynamic/dynamicinformer:go_default_library", "@io_k8s_client_go//informers:go_default_library", "@io_k8s_client_go//kubernetes:go_default_library", "@io_k8s_client_go//rest:go_default_library", diff --git a/pkg/controller/acmechallenges/BUILD.bazel b/pkg/controller/acmechallenges/BUILD.bazel index e24244f84..53358a259 100644 --- a/pkg/controller/acmechallenges/BUILD.bazel +++ b/pkg/controller/acmechallenges/BUILD.bazel @@ -25,6 +25,7 @@ go_library( "//pkg/issuer/acme/dns:go_default_library", "//pkg/issuer/acme/dns/util:go_default_library", "//pkg/issuer/acme/http:go_default_library", + "//pkg/issuer/acme/http/internal/istio:go_default_library", "//pkg/logs:go_default_library", "//pkg/util/feature:go_default_library", "@com_github_go_logr_logr//:go_default_library", diff --git a/pkg/controller/acmechallenges/controller.go b/pkg/controller/acmechallenges/controller.go index 9359a3cb8..dac14fd0b 100644 --- a/pkg/controller/acmechallenges/controller.go +++ b/pkg/controller/acmechallenges/controller.go @@ -38,6 +38,7 @@ import ( "github.com/jetstack/cert-manager/pkg/issuer" "github.com/jetstack/cert-manager/pkg/issuer/acme/dns" "github.com/jetstack/cert-manager/pkg/issuer/acme/http" + "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio" logf "github.com/jetstack/cert-manager/pkg/logs" ) @@ -97,6 +98,7 @@ func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin podInformer := ctx.KubeSharedInformerFactory.Core().V1().Pods() serviceInformer := ctx.KubeSharedInformerFactory.Core().V1().Services() ingressInformer := ctx.KubeSharedInformerFactory.Networking().V1beta1().Ingresses() + // build a list of InformerSynced functions that will be returned by the Register method. // the controller will only begin processing items once all of these informers have synced. mustSync := []cache.InformerSynced{ @@ -108,6 +110,11 @@ func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin ingressInformer.Informer().HasSynced, } + if ctx.IstioEnabled { + virtualServiceInformer := ctx.DynamicSharedInformerFactory.ForResource(istio.VirtualServiceGvr()) + mustSync = append(mustSync, virtualServiceInformer.Informer().HasSynced) + } + // set all the references to the listers for used by the Sync function c.challengeLister = challengeInformer.Lister() c.issuerLister = issuerInformer.Lister() diff --git a/pkg/controller/context.go b/pkg/controller/context.go index 05f9cde92..ff8c5272e 100644 --- a/pkg/controller/context.go +++ b/pkg/controller/context.go @@ -21,6 +21,8 @@ import ( "time" "k8s.io/apimachinery/pkg/api/resource" + dynamicclient "k8s.io/client-go/dynamic" + dynamicinformers "k8s.io/client-go/dynamic/dynamicinformer" kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -48,6 +50,8 @@ type Context struct { RESTConfig *rest.Config // Client is a Kubernetes clientset Client kubernetes.Interface + // DynamicClient is a Dynamic clientset + DynamicClient dynamicclient.Interface // CMClient is a cert-manager clientset CMClient clientset.Interface // Recorder to record events to @@ -56,10 +60,16 @@ type Context struct { // KubeSharedInformerFactory can be used to obtain shared // SharedIndexInformer instances for Kubernetes types KubeSharedInformerFactory kubeinformers.SharedInformerFactory + // DynamicSharedInformerFactory can be used to obtain shared + // SharedIndexInformer instances for Dynamic types + DynamicSharedInformerFactory dynamicinformers.DynamicSharedInformerFactory // SharedInformerFactory can be used to obtain shared SharedIndexInformer // instances SharedInformerFactory informers.SharedInformerFactory + // IstioEnabled is true if Istio support is enabled + IstioEnabled bool + // Namespace is the namespace to operate within. // If unset, operates on all namespaces Namespace string diff --git a/pkg/controller/test/BUILD.bazel b/pkg/controller/test/BUILD.bazel index 680a537a6..570415be8 100644 --- a/pkg/controller/test/BUILD.bazel +++ b/pkg/controller/test/BUILD.bazel @@ -23,7 +23,10 @@ go_library( "@com_github_kr_pretty//:go_default_library", "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library", "@io_k8s_apimachinery//pkg/runtime:go_default_library", + "@io_k8s_apimachinery//pkg/runtime/schema:go_default_library", "@io_k8s_apimachinery//pkg/util/errors:go_default_library", + "@io_k8s_client_go//dynamic/dynamicinformer:go_default_library", + "@io_k8s_client_go//dynamic/fake:go_default_library", "@io_k8s_client_go//informers:go_default_library", "@io_k8s_client_go//kubernetes/fake:go_default_library", "@io_k8s_client_go//testing:go_default_library", diff --git a/pkg/controller/test/context_builder.go b/pkg/controller/test/context_builder.go index d3928f340..75dc55e4e 100644 --- a/pkg/controller/test/context_builder.go +++ b/pkg/controller/test/context_builder.go @@ -26,7 +26,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + dynamicinformers "k8s.io/client-go/dynamic/dynamicinformer" + dynamicfake "k8s.io/client-go/dynamic/fake" kubeinformers "k8s.io/client-go/informers" kubefake "k8s.io/client-go/kubernetes/fake" coretesting "k8s.io/client-go/testing" @@ -57,6 +61,7 @@ type Builder struct { T *testing.T KubeObjects []runtime.Object + DynamicObjects []runtime.Object CertManagerObjects []runtime.Object ExpectedActions []Action ExpectedEvents []string @@ -106,12 +111,15 @@ func (b *Builder) Init() { } b.requiredReactors = make(map[string]bool) b.Client = kubefake.NewSimpleClientset(b.KubeObjects...) + b.DynamicClient = dynamicfake.NewSimpleDynamicClient(runtime.NewScheme(), b.DynamicObjects...) b.CMClient = cmfake.NewSimpleClientset(b.CertManagerObjects...) b.Recorder = new(FakeRecorder) b.FakeKubeClient().PrependReactor("create", "*", b.generateNameReactor) + b.FakeDynamicClient().PrependReactor("create", "*", b.generateNameReactor) b.FakeCMClient().PrependReactor("create", "*", b.generateNameReactor) b.KubeSharedInformerFactory = kubeinformers.NewSharedInformerFactory(b.Client, informerResyncPeriod) + b.DynamicSharedInformerFactory = dynamicinformers.NewDynamicSharedInformerFactory(b.DynamicClient, informerResyncPeriod) b.SharedInformerFactory = informers.NewSharedInformerFactory(b.CMClient, informerResyncPeriod) b.stopCh = make(chan struct{}) b.Metrics = metrics.New(logs.Log) @@ -135,6 +143,14 @@ func (b *Builder) FakeKubeInformerFactory() kubeinformers.SharedInformerFactory return b.Context.KubeSharedInformerFactory } +func (b *Builder) FakeDynamicClient() *dynamicfake.FakeDynamicClient { + return b.Context.DynamicClient.(*dynamicfake.FakeDynamicClient) +} + +func (b *Builder) FakeDynamicSharedInformerFactory() dynamicinformers.DynamicSharedInformerFactory { + return b.Context.DynamicSharedInformerFactory +} + func (b *Builder) FakeCMClient() *cmfake.Clientset { return b.Context.CMClient.(*cmfake.Clientset) } @@ -269,6 +285,7 @@ func (b *Builder) Stop() { func (b *Builder) Start() { b.KubeSharedInformerFactory.Start(b.stopCh) + b.DynamicSharedInformerFactory.Start(b.stopCh) b.SharedInformerFactory.Start(b.stopCh) // wait for caches to sync b.Sync() @@ -278,6 +295,9 @@ func (b *Builder) Sync() { if err := mustAllSync(b.KubeSharedInformerFactory.WaitForCacheSync(b.stopCh)); err != nil { panic("Error waiting for kubeSharedInformerFactory to sync: " + err.Error()) } + if err := mustAllSyncDynamic(b.DynamicSharedInformerFactory.WaitForCacheSync(b.stopCh)); err != nil { + panic("Error waiting for dynamicSharedInformerFactory to sync: " + err.Error()) + } if err := mustAllSync(b.SharedInformerFactory.WaitForCacheSync(b.stopCh)); err != nil { panic("Error waiting for SharedInformerFactory to sync: " + err.Error()) } @@ -304,6 +324,16 @@ func (b *Builder) Events() []string { return nil } +func mustAllSyncDynamic(in map[schema.GroupVersionResource]bool) error { + var errs []error + for t, started := range in { + if !started { + errs = append(errs, fmt.Errorf("informer for %v not synced", t)) + } + } + return utilerrors.NewAggregate(errs) +} + func mustAllSync(in map[reflect.Type]bool) error { var errs []error for t, started := range in { diff --git a/pkg/internal/apis/acme/types_issuer.go b/pkg/internal/apis/acme/types_issuer.go index 1bbdde545..73171b102 100644 --- a/pkg/internal/apis/acme/types_issuer.go +++ b/pkg/internal/apis/acme/types_issuer.go @@ -186,6 +186,14 @@ type ACMEChallengeSolverHTTP01 struct { // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are // provisioned by cert-manager for each Challenge to be completed. Ingress *ACMEChallengeSolverHTTP01Ingress + + // The Istio virtualservice based HTTP01 challenge solver will solve + // challenges by creating an Istio virtualservice resource that is connected + // to the specified Istio gateway in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Istio *ACMEChallengeSolverHTTP01Istio `json:"istio,omitempty"` } type ACMEChallengeSolverHTTP01Ingress struct { @@ -272,6 +280,19 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct { Labels map[string]string } +type ACMEChallengeSolverHTTP01Istio struct { + // Namespace of the gateway that is used to generate the virtualservice for. + GatewayNamespace string + + // Name of the gateway that is used to generate the virtualservice for. + GatewayName string + + // Optional pod template used to configure the ACME challenge solver pods + // used for HTTP01 challenges + // +optional + PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"` +} + // Used to configure a DNS01 challenge provider to be used when solving DNS01 // challenges. // Only one DNS provider may be configured per solver. diff --git a/pkg/internal/apis/acme/v1/zz_generated.conversion.go b/pkg/internal/apis/acme/v1/zz_generated.conversion.go index fe9012ffb..2c4dab231 100644 --- a/pkg/internal/apis/acme/v1/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1/zz_generated.conversion.go @@ -151,6 +151,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1.ACMEChallengeSolverHTTP01Istio)(nil), (*acme.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(a.(*v1.ACMEChallengeSolverHTTP01Istio), b.(*acme.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*acme.ACMEChallengeSolverHTTP01Istio)(nil), (*v1.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1_ACMEChallengeSolverHTTP01Istio(a.(*acme.ACMEChallengeSolverHTTP01Istio), b.(*v1.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1.ACMEExternalAccountBinding)(nil), (*acme.ACMEExternalAccountBinding)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(a.(*v1.ACMEExternalAccountBinding), b.(*acme.ACMEExternalAccountBinding), scope) }); err != nil { @@ -480,6 +490,7 @@ func Convert_acme_ACMEChallengeSolverDNS01_To_v1_ACMEChallengeSolverDNS01(in *ac func autoConvert_v1_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01(in *v1.ACMEChallengeSolverHTTP01, out *acme.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*acme.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*acme.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -490,6 +501,7 @@ func Convert_v1_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01(in * func autoConvert_acme_ACMEChallengeSolverHTTP01_To_v1_ACMEChallengeSolverHTTP01(in *acme.ACMEChallengeSolverHTTP01, out *v1.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*v1.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*v1.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -652,6 +664,30 @@ func Convert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1_ACMEChallengeSo return autoConvert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1_ACMEChallengeSolverHTTP01IngressTemplate(in, out, s) } +func autoConvert_v1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*acme.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_v1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_v1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_v1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + +func autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*v1.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + func autoConvert_v1_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(in *v1.ACMEExternalAccountBinding, out *acme.ACMEExternalAccountBinding, s conversion.Scope) error { out.KeyID = in.KeyID // TODO: Inefficient conversion - can we improve it? diff --git a/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go b/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go index 5987bf751..6311b919e 100644 --- a/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go @@ -151,6 +151,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha2.ACMEChallengeSolverHTTP01Istio)(nil), (*acme.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(a.(*v1alpha2.ACMEChallengeSolverHTTP01Istio), b.(*acme.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*acme.ACMEChallengeSolverHTTP01Istio)(nil), (*v1alpha2.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha2_ACMEChallengeSolverHTTP01Istio(a.(*acme.ACMEChallengeSolverHTTP01Istio), b.(*v1alpha2.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha2.ACMEExternalAccountBinding)(nil), (*acme.ACMEExternalAccountBinding)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha2_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(a.(*v1alpha2.ACMEExternalAccountBinding), b.(*acme.ACMEExternalAccountBinding), scope) }); err != nil { @@ -480,6 +490,7 @@ func Convert_acme_ACMEChallengeSolverDNS01_To_v1alpha2_ACMEChallengeSolverDNS01( func autoConvert_v1alpha2_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01(in *v1alpha2.ACMEChallengeSolverHTTP01, out *acme.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*acme.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*acme.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -490,6 +501,7 @@ func Convert_v1alpha2_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP0 func autoConvert_acme_ACMEChallengeSolverHTTP01_To_v1alpha2_ACMEChallengeSolverHTTP01(in *acme.ACMEChallengeSolverHTTP01, out *v1alpha2.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*v1alpha2.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*v1alpha2.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -652,6 +664,30 @@ func Convert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1alpha2_ACMEChall return autoConvert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1alpha2_ACMEChallengeSolverHTTP01IngressTemplate(in, out, s) } +func autoConvert_v1alpha2_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1alpha2.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*acme.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_v1alpha2_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_v1alpha2_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1alpha2.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_v1alpha2_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + +func autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha2_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1alpha2.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*v1alpha2.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha2_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha2_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1alpha2.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha2_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + func autoConvert_v1alpha2_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(in *v1alpha2.ACMEExternalAccountBinding, out *acme.ACMEExternalAccountBinding, s conversion.Scope) error { out.KeyID = in.KeyID // TODO: Inefficient conversion - can we improve it? diff --git a/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go b/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go index 0f45570b0..b39aca80a 100644 --- a/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go @@ -151,6 +151,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha3.ACMEChallengeSolverHTTP01Istio)(nil), (*acme.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha3_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(a.(*v1alpha3.ACMEChallengeSolverHTTP01Istio), b.(*acme.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*acme.ACMEChallengeSolverHTTP01Istio)(nil), (*v1alpha3.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha3_ACMEChallengeSolverHTTP01Istio(a.(*acme.ACMEChallengeSolverHTTP01Istio), b.(*v1alpha3.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha3.ACMEExternalAccountBinding)(nil), (*acme.ACMEExternalAccountBinding)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(a.(*v1alpha3.ACMEExternalAccountBinding), b.(*acme.ACMEExternalAccountBinding), scope) }); err != nil { @@ -480,6 +490,7 @@ func Convert_acme_ACMEChallengeSolverDNS01_To_v1alpha3_ACMEChallengeSolverDNS01( func autoConvert_v1alpha3_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01(in *v1alpha3.ACMEChallengeSolverHTTP01, out *acme.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*acme.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*acme.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -490,6 +501,7 @@ func Convert_v1alpha3_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP0 func autoConvert_acme_ACMEChallengeSolverHTTP01_To_v1alpha3_ACMEChallengeSolverHTTP01(in *acme.ACMEChallengeSolverHTTP01, out *v1alpha3.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*v1alpha3.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*v1alpha3.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -652,6 +664,30 @@ func Convert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1alpha3_ACMEChall return autoConvert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1alpha3_ACMEChallengeSolverHTTP01IngressTemplate(in, out, s) } +func autoConvert_v1alpha3_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1alpha3.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*acme.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_v1alpha3_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_v1alpha3_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1alpha3.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_v1alpha3_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + +func autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha3_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1alpha3.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*v1alpha3.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha3_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha3_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1alpha3.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1alpha3_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + func autoConvert_v1alpha3_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(in *v1alpha3.ACMEExternalAccountBinding, out *acme.ACMEExternalAccountBinding, s conversion.Scope) error { out.KeyID = in.KeyID // TODO: Inefficient conversion - can we improve it? diff --git a/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go b/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go index 602bc326d..0a070b48d 100644 --- a/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go @@ -151,6 +151,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1beta1.ACMEChallengeSolverHTTP01Istio)(nil), (*acme.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(a.(*v1beta1.ACMEChallengeSolverHTTP01Istio), b.(*acme.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*acme.ACMEChallengeSolverHTTP01Istio)(nil), (*v1beta1.ACMEChallengeSolverHTTP01Istio)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1beta1_ACMEChallengeSolverHTTP01Istio(a.(*acme.ACMEChallengeSolverHTTP01Istio), b.(*v1beta1.ACMEChallengeSolverHTTP01Istio), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta1.ACMEExternalAccountBinding)(nil), (*acme.ACMEExternalAccountBinding)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(a.(*v1beta1.ACMEExternalAccountBinding), b.(*acme.ACMEExternalAccountBinding), scope) }); err != nil { @@ -480,6 +490,7 @@ func Convert_acme_ACMEChallengeSolverDNS01_To_v1beta1_ACMEChallengeSolverDNS01(i func autoConvert_v1beta1_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01(in *v1beta1.ACMEChallengeSolverHTTP01, out *acme.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*acme.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*acme.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -490,6 +501,7 @@ func Convert_v1beta1_ACMEChallengeSolverHTTP01_To_acme_ACMEChallengeSolverHTTP01 func autoConvert_acme_ACMEChallengeSolverHTTP01_To_v1beta1_ACMEChallengeSolverHTTP01(in *acme.ACMEChallengeSolverHTTP01, out *v1beta1.ACMEChallengeSolverHTTP01, s conversion.Scope) error { out.Ingress = (*v1beta1.ACMEChallengeSolverHTTP01Ingress)(unsafe.Pointer(in.Ingress)) + out.Istio = (*v1beta1.ACMEChallengeSolverHTTP01Istio)(unsafe.Pointer(in.Istio)) return nil } @@ -652,6 +664,30 @@ func Convert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1beta1_ACMEChalle return autoConvert_acme_ACMEChallengeSolverHTTP01IngressTemplate_To_v1beta1_ACMEChallengeSolverHTTP01IngressTemplate(in, out, s) } +func autoConvert_v1beta1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1beta1.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*acme.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_v1beta1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_v1beta1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in *v1beta1.ACMEChallengeSolverHTTP01Istio, out *acme.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_v1beta1_ACMEChallengeSolverHTTP01Istio_To_acme_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + +func autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1beta1_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1beta1.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + out.GatewayNamespace = in.GatewayNamespace + out.GatewayName = in.GatewayName + out.PodTemplate = (*v1beta1.ACMEChallengeSolverHTTP01IngressPodTemplate)(unsafe.Pointer(in.PodTemplate)) + return nil +} + +// Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1beta1_ACMEChallengeSolverHTTP01Istio is an autogenerated conversion function. +func Convert_acme_ACMEChallengeSolverHTTP01Istio_To_v1beta1_ACMEChallengeSolverHTTP01Istio(in *acme.ACMEChallengeSolverHTTP01Istio, out *v1beta1.ACMEChallengeSolverHTTP01Istio, s conversion.Scope) error { + return autoConvert_acme_ACMEChallengeSolverHTTP01Istio_To_v1beta1_ACMEChallengeSolverHTTP01Istio(in, out, s) +} + func autoConvert_v1beta1_ACMEExternalAccountBinding_To_acme_ACMEExternalAccountBinding(in *v1beta1.ACMEExternalAccountBinding, out *acme.ACMEExternalAccountBinding, s conversion.Scope) error { out.KeyID = in.KeyID // TODO: Inefficient conversion - can we improve it? diff --git a/pkg/internal/apis/acme/zz_generated.deepcopy.go b/pkg/internal/apis/acme/zz_generated.deepcopy.go index cfef98f6b..4bd664837 100644 --- a/pkg/internal/apis/acme/zz_generated.deepcopy.go +++ b/pkg/internal/apis/acme/zz_generated.deepcopy.go @@ -170,6 +170,11 @@ func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01 *out = new(ACMEChallengeSolverHTTP01Ingress) (*in).DeepCopyInto(*out) } + if in.Istio != nil { + in, out := &in.Istio, &out.Istio + *out = new(ACMEChallengeSolverHTTP01Istio) + (*in).DeepCopyInto(*out) + } return } @@ -344,6 +349,27 @@ func (in *ACMEChallengeSolverHTTP01IngressTemplate) DeepCopy() *ACMEChallengeSol return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopyInto(out *ACMEChallengeSolverHTTP01Istio) { + *out = *in + if in.PodTemplate != nil { + in, out := &in.PodTemplate, &out.PodTemplate + *out = new(ACMEChallengeSolverHTTP01IngressPodTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Istio. +func (in *ACMEChallengeSolverHTTP01Istio) DeepCopy() *ACMEChallengeSolverHTTP01Istio { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Istio) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEExternalAccountBinding) DeepCopyInto(out *ACMEExternalAccountBinding) { *out = *in diff --git a/pkg/internal/apis/certmanager/validation/issuer.go b/pkg/internal/apis/certmanager/validation/issuer.go index f50cca666..b5d987812 100644 --- a/pkg/internal/apis/certmanager/validation/issuer.go +++ b/pkg/internal/apis/certmanager/validation/issuer.go @@ -156,8 +156,11 @@ func ValidateACMEIssuerChallengeSolverHTTP01Config(http01 *cmacme.ACMEChallengeS numDefined++ el = append(el, ValidateACMEIssuerChallengeSolverHTTP01IngressConfig(http01.Ingress, fldPath.Child("ingress"))...) } - if numDefined == 0 { - el = append(el, field.Required(fldPath, "no HTTP01 solver type configured")) + if http01.Istio != nil { + numDefined++ + } + if numDefined != 1 { + el = append(el, field.Required(fldPath, "exactly 1 HTTP01 solver type has to be configured")) } return el diff --git a/pkg/internal/apis/certmanager/validation/issuer_test.go b/pkg/internal/apis/certmanager/validation/issuer_test.go index 6ca7a2ca8..d81b62f94 100644 --- a/pkg/internal/apis/certmanager/validation/issuer_test.go +++ b/pkg/internal/apis/certmanager/validation/issuer_test.go @@ -215,7 +215,7 @@ func TestValidateACMEIssuerConfig(t *testing.T) { }, }, errs: []*field.Error{ - field.Required(fldPath.Child("solvers").Index(0).Child("http01"), "no HTTP01 solver type configured"), + field.Required(fldPath.Child("solvers").Index(0).Child("http01"), "exactly 1 HTTP01 solver type has to be configured"), }, }, "acme solver with valid http01 config": { @@ -458,7 +458,7 @@ func TestValidateACMEIssuerHTTP01Config(t *testing.T) { "no solver config type specified": { cfg: &cmacme.ACMEChallengeSolverHTTP01{}, errs: []*field.Error{ - field.Required(fldPath, "no HTTP01 solver type configured"), + field.Required(fldPath, "exactly 1 HTTP01 solver type has to be configured"), }, }, "both fields specified": { diff --git a/pkg/issuer/acme/http/BUILD.bazel b/pkg/issuer/acme/http/BUILD.bazel index 515ce5f4d..aee60641e 100644 --- a/pkg/issuer/acme/http/BUILD.bazel +++ b/pkg/issuer/acme/http/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "http.go", "ingress.go", + "istio.go", "pod.go", "service.go", ], @@ -14,9 +15,11 @@ go_library( "//pkg/apis/acme/v1:go_default_library", "//pkg/apis/certmanager/v1:go_default_library", "//pkg/controller:go_default_library", + "//pkg/issuer/acme/http/internal/istio:go_default_library", "//pkg/issuer/acme/http/solver:go_default_library", "//pkg/logs:go_default_library", "//pkg/util:go_default_library", + "@io_istio_api//networking/v1beta1:go_default_library", "@io_k8s_api//core/v1:go_default_library", "@io_k8s_api//networking/v1beta1:go_default_library", "@io_k8s_apimachinery//pkg/api/errors:go_default_library", @@ -25,6 +28,7 @@ go_library( "@io_k8s_apimachinery//pkg/selection:go_default_library", "@io_k8s_apimachinery//pkg/util/errors:go_default_library", "@io_k8s_apimachinery//pkg/util/intstr:go_default_library", + "@io_k8s_client_go//dynamic/dynamiclister:go_default_library", "@io_k8s_client_go//listers/core/v1:go_default_library", "@io_k8s_client_go//listers/networking/v1beta1:go_default_library", "@io_k8s_utils//net:go_default_library", @@ -36,6 +40,7 @@ go_test( srcs = [ "http_test.go", "ingress_test.go", + "istio_test.go", "pod_test.go", "service_test.go", "util_test.go", @@ -44,6 +49,7 @@ go_test( deps = [ "//pkg/apis/acme/v1:go_default_library", "//pkg/controller/test:go_default_library", + "//pkg/issuer/acme/http/internal/istio:go_default_library", "//test/unit/gen:go_default_library", "@io_k8s_api//core/v1:go_default_library", "@io_k8s_api//networking/v1beta1:go_default_library", @@ -68,6 +74,7 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", + "//pkg/issuer/acme/http/internal/istio:all-srcs", "//pkg/issuer/acme/http/solver:all-srcs", ], tags = ["automanaged"], diff --git a/pkg/issuer/acme/http/http.go b/pkg/issuer/acme/http/http.go index a91ba4dfb..5f3a7745b 100644 --- a/pkg/issuer/acme/http/http.go +++ b/pkg/issuer/acme/http/http.go @@ -19,6 +19,7 @@ package http import ( "context" "crypto/tls" + "errors" "fmt" "io/ioutil" "net" @@ -29,13 +30,16 @@ import ( k8snet "k8s.io/utils/net" + corev1 "k8s.io/api/core/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/client-go/dynamic/dynamiclister" corev1listers "k8s.io/client-go/listers/core/v1" networkingv1beta1listers "k8s.io/client-go/listers/networking/v1beta1" cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" "github.com/jetstack/cert-manager/pkg/controller" + "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio" "github.com/jetstack/cert-manager/pkg/issuer/acme/http/solver" logf "github.com/jetstack/cert-manager/pkg/logs" pkgutil "github.com/jetstack/cert-manager/pkg/util" @@ -57,9 +61,10 @@ var ( type Solver struct { *controller.Context - podLister corev1listers.PodLister - serviceLister corev1listers.ServiceLister - ingressLister networkingv1beta1listers.IngressLister + podLister corev1listers.PodLister + serviceLister corev1listers.ServiceLister + ingressLister networkingv1beta1listers.IngressLister + virtualServiceLister dynamiclister.Lister testReachability reachabilityTest requiredPasses int @@ -70,13 +75,15 @@ type reachabilityTest func(ctx context.Context, url *url.URL, key string) error // NewSolver returns a new ACME HTTP01 solver for the given Issuer and client. // TODO: refactor this to have fewer args func NewSolver(ctx *controller.Context) *Solver { + dynamicInformer := ctx.DynamicSharedInformerFactory.ForResource(istio.VirtualServiceGvr()) return &Solver{ - Context: ctx, - podLister: ctx.KubeSharedInformerFactory.Core().V1().Pods().Lister(), - serviceLister: ctx.KubeSharedInformerFactory.Core().V1().Services().Lister(), - ingressLister: ctx.KubeSharedInformerFactory.Networking().V1beta1().Ingresses().Lister(), - testReachability: testReachability, - requiredPasses: 5, + Context: ctx, + podLister: ctx.KubeSharedInformerFactory.Core().V1().Pods().Lister(), + serviceLister: ctx.KubeSharedInformerFactory.Core().V1().Services().Lister(), + ingressLister: ctx.KubeSharedInformerFactory.Networking().V1beta1().Ingresses().Lister(), + virtualServiceLister: dynamiclister.New(dynamicInformer.Informer().GetIndexer(), istio.VirtualServiceGvr()), + testReachability: testReachability, + requiredPasses: 5, } } @@ -84,14 +91,27 @@ func http01LogCtx(ctx context.Context) context.Context { return logf.NewContext(ctx, nil, "http01") } -func httpDomainCfgForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) { +func httpIngressForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) { if ch.Spec.Solver.HTTP01 == nil || ch.Spec.Solver.HTTP01.Ingress == nil { - return nil, fmt.Errorf("challenge's 'solver' field is specified but no HTTP01 ingress config provided. " + + return nil, errors.New("challenge's 'solver' field is specified but no HTTP01 ingress config provided. " + "Ensure solvers[].http01.ingress is specified on your issuer resource") } return ch.Spec.Solver.HTTP01.Ingress, nil } +func serviceTypeForChallenge(ch *cmacme.Challenge) (corev1.ServiceType, error) { + if ch.Spec.Solver.HTTP01 != nil { + if ch.Spec.Solver.HTTP01.Ingress != nil { + return ch.Spec.Solver.HTTP01.Ingress.ServiceType, nil + } + if ch.Spec.Solver.HTTP01.Istio != nil { + return corev1.ServiceTypeClusterIP, nil + } + } + + return "", errors.New("could not determine service type for challenge") +} + // Present will realise the resources required to solve the given HTTP01 // challenge validation in the apiserver. If those resources already exist, it // will return nil (i.e. this function is idempotent). @@ -103,8 +123,22 @@ func (s *Solver) Present(ctx context.Context, issuer v1.GenericIssuer, ch *cmacm if svcErr != nil { return utilerrors.NewAggregate([]error{podErr, svcErr}) } - _, ingressErr := s.ensureIngress(ctx, ch, svc.Name) - return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr}) + + var ingressErr error + if ch.Spec.Solver.HTTP01.Ingress != nil { + _, ingressErr = s.ensureIngress(ctx, ch, svc.Name) + } + + var istioErr error + if ch.Spec.Solver.HTTP01.Istio != nil { + if s.IstioEnabled { + _, istioErr = s.ensureIstio(ctx, ch, svc.Name) + } else { + istioErr = errors.New("Istio support was not detected on startup, try restarting cert-manager") + } + } + + return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr, istioErr}) } func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error { @@ -116,7 +150,7 @@ func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme. // Call present again to be certain. // if the listers are nil, that means we're in the present checks // test - if s.podLister != nil && s.serviceLister != nil && s.ingressLister != nil { + if s.podLister != nil && s.serviceLister != nil && s.ingressLister != nil && s.virtualServiceLister != nil { log.V(logf.DebugLevel).Info("calling Present function before running self check to ensure required resources exist") err := s.Present(ctx, issuer, ch) if err != nil { @@ -153,6 +187,7 @@ func (s *Solver) CleanUp(ctx context.Context, issuer v1.GenericIssuer, ch *cmacm errs = append(errs, s.cleanupPods(ctx, ch)) errs = append(errs, s.cleanupServices(ctx, ch)) errs = append(errs, s.cleanupIngresses(ctx, ch)) + errs = append(errs, s.cleanupVirtualServices(ctx, ch)) return utilerrors.NewAggregate(errs) } diff --git a/pkg/issuer/acme/http/ingress.go b/pkg/issuer/acme/http/ingress.go index 5573daf49..1252305b3 100644 --- a/pkg/issuer/acme/http/ingress.go +++ b/pkg/issuer/acme/http/ingress.go @@ -74,7 +74,7 @@ func (s *Solver) getIngressesForChallenge(ctx context.Context, ch *cmacme.Challe // that the ingress has an appropriate challenge path configured func (s *Solver) ensureIngress(ctx context.Context, ch *cmacme.Challenge, svcName string) (ing *networkingv1beta1.Ingress, err error) { log := logf.FromContext(ctx).WithName("ensureIngress") - httpDomainCfg, err := httpDomainCfgForChallenge(ch) + httpDomainCfg, err := httpIngressForChallenge(ch) if err != nil { return nil, err } @@ -135,7 +135,7 @@ func (s *Solver) createIngress(ctx context.Context, ch *cmacme.Challenge, svcNam } func buildIngressResource(ch *cmacme.Challenge, svcName string) (*networkingv1beta1.Ingress, error) { - httpDomainCfg, err := httpDomainCfgForChallenge(ch) + httpDomainCfg, err := httpIngressForChallenge(ch) if err != nil { return nil, err } @@ -211,7 +211,7 @@ func (s *Solver) mergeIngressObjectMetaWithIngressResourceTemplate(ingress *netw } func (s *Solver) addChallengePathToIngress(ctx context.Context, ch *cmacme.Challenge, svcName string) (*networkingv1beta1.Ingress, error) { - httpDomainCfg, err := httpDomainCfgForChallenge(ch) + httpDomainCfg, err := httpIngressForChallenge(ch) if err != nil { return nil, err } @@ -265,7 +265,12 @@ func (s *Solver) addChallengePathToIngress(ctx context.Context, ch *cmacme.Chall func (s *Solver) cleanupIngresses(ctx context.Context, ch *cmacme.Challenge) error { log := logf.FromContext(ctx, "cleanupPods") - httpDomainCfg, err := httpDomainCfgForChallenge(ch) + // Only do cleanup if HTTP01 and Ingress are set + if ch.Spec.Solver.HTTP01 == nil || ch.Spec.Solver.HTTP01.Ingress == nil { + return nil + } + + httpDomainCfg, err := httpIngressForChallenge(ch) if err != nil { return err } diff --git a/pkg/issuer/acme/http/internal/istio/BUILD.bazel b/pkg/issuer/acme/http/internal/istio/BUILD.bazel new file mode 100644 index 000000000..e73bacf7d --- /dev/null +++ b/pkg/issuer/acme/http/internal/istio/BUILD.bazel @@ -0,0 +1,33 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "istio.go", + "istio_deepcopy.gen.go", + ], + importpath = "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio", + visibility = ["//:__subpackages__"], + deps = [ + "@io_istio_api//meta/v1alpha1:go_default_library", + "@io_istio_api//networking/v1beta1:go_default_library", + "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library", + "@io_k8s_apimachinery//pkg/apis/meta/v1/unstructured:go_default_library", + "@io_k8s_apimachinery//pkg/runtime:go_default_library", + "@io_k8s_apimachinery//pkg/runtime/schema:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/pkg/issuer/acme/http/internal/istio/istio.go b/pkg/issuer/acme/http/internal/istio/istio.go new file mode 100644 index 000000000..b91344ef4 --- /dev/null +++ b/pkg/issuer/acme/http/internal/istio/istio.go @@ -0,0 +1,74 @@ +/* +Copyright 2021 The cert-manager 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. +*/ + +// By utilising this file, no dependance on `istio.io/client-go` is +// required. Used in combination with a dynamic client, it is possible +// to create a client for these CRDs without adding a client-go dependency. + +package istio + +import ( + v1alpha1 "istio.io/api/meta/v1alpha1" + networkingv1beta1 "istio.io/api/networking/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + virtualServiceGvk = schema.GroupVersionKind{Group: "networking.istio.io", Version: "v1beta1", Kind: "VirtualService"} + virtualServiceGvr = schema.GroupVersionResource{Group: "networking.istio.io", Version: "v1beta1", Resource: "virtualservices"} +) + +func VirtualServiceGvr() schema.GroupVersionResource { + return virtualServiceGvr +} + +type VirtualService struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the implementation of this definition. + Spec networkingv1beta1.VirtualService `json:"spec,omitempty"` + + Status v1alpha1.IstioStatus `json:"status"` +} + +// VirtualServiceList is a collection of VirtualServices. +type VirtualServiceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VirtualService `json:"items"` +} + +func (virtualService *VirtualService) ToUnstructured() (*unstructured.Unstructured, error) { + virtualService.TypeMeta.SetGroupVersionKind(virtualServiceGvk) + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(virtualService) + if err != nil { + return nil, err + } + return &unstructured.Unstructured{Object: unstructuredObj}, nil +} + +func VirtualServiceFromUnstructured(unstr *unstructured.Unstructured) (*VirtualService, error) { + var virtualService VirtualService + err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.UnstructuredContent(), &virtualService) + if err != nil { + return nil, err + } + return &virtualService, nil +} diff --git a/pkg/issuer/acme/http/internal/istio/istio_deepcopy.gen.go b/pkg/issuer/acme/http/internal/istio/istio_deepcopy.gen.go new file mode 100644 index 000000000..c0cc55cb1 --- /dev/null +++ b/pkg/issuer/acme/http/internal/istio/istio_deepcopy.gen.go @@ -0,0 +1,86 @@ +/* +Copyright 2021 The cert-manager 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. +*/ + +// By utilising this file, no dependance on `istio.io/client-go` is +// required. Used in combination with a dynamic client, it is possible +// to create a client for these CRDs without adding a client-go dependency. + +package istio + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualService) DeepCopyInto(out *VirtualService) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualService. +func (in *VirtualService) DeepCopy() *VirtualService { + if in == nil { + return nil + } + out := new(VirtualService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualService) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualServiceList) DeepCopyInto(out *VirtualServiceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VirtualService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualServiceList. +func (in *VirtualServiceList) DeepCopy() *VirtualServiceList { + if in == nil { + return nil + } + out := new(VirtualServiceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualServiceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/issuer/acme/http/istio.go b/pkg/issuer/acme/http/istio.go new file mode 100644 index 000000000..e69bd3678 --- /dev/null +++ b/pkg/issuer/acme/http/istio.go @@ -0,0 +1,175 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package http + +import ( + "context" + "fmt" + "reflect" + + networkingv1beta1 "istio.io/api/networking/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + + cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" + "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio" + logf "github.com/jetstack/cert-manager/pkg/logs" +) + +func (s *Solver) ensureIstio(ctx context.Context, ch *cmacme.Challenge, svcName string) (*istio.VirtualService, error) { + log := logf.FromContext(ctx).WithName("ensureIstio") + + virtualService, err := s.getVirtualService(ctx, ch) + if err != nil { + return nil, err + } + + if virtualService == nil { + log.Info("creating VirtualService") + virtualService, err = s.createVirtualService(ctx, ch, svcName) + if err != nil { + return nil, err + } + log.Info("created VirtualService successfully") + + return virtualService, nil + } + + log.Info("found VirtualService") + + virtualService, err = s.checkAndUpdateVirtualService(ctx, ch, svcName, virtualService) + if err != nil { + return nil, err + } + + return virtualService, nil +} + +func (s *Solver) cleanupVirtualServices(_ context.Context, _ *cmacme.Challenge) error { + // Nothing to do, GC will take care of deleting the VirtualServices when the Challenge is deleted + return nil +} + +func (s *Solver) getVirtualService(ctx context.Context, ch *cmacme.Challenge) (*istio.VirtualService, error) { + log := logf.FromContext(ctx, "getVirtualService") + + selector := labels.Set(podLabels(ch)).AsSelector() + vsList, err := s.virtualServiceLister.Namespace(ch.Namespace).List(selector) + if err != nil { + return nil, err + } + switch len(vsList) { + case 0: + return nil, nil + case 1: + virtualService, err := istio.VirtualServiceFromUnstructured(vsList[0]) + if err != nil { + return nil, err + } + return virtualService, nil + default: + for _, vs := range vsList[1:] { + log.Info("deleting VirtualService") + err := s.DynamicClient.Resource(istio.VirtualServiceGvr()).Namespace(ch.Namespace).Delete(ctx, vs.GetName(), metav1.DeleteOptions{}) + if err != nil { + return nil, err + } + } + return nil, fmt.Errorf("multiple VirtualServices found") + } +} + +func (s *Solver) createVirtualService(ctx context.Context, ch *cmacme.Challenge, svcName string) (*istio.VirtualService, error) { + expectedSpec := createVirtualServiceSpec(ch, svcName) + + vs := istio.VirtualService{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "cm-acme-http-solver-", + Namespace: ch.Namespace, + Labels: podLabels(ch), + OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(ch, challengeGvk)}, + }, + Spec: *expectedSpec, + } + + unstr, err := vs.ToUnstructured() + if err != nil { + return nil, err + } + val, err := s.DynamicClient.Resource(istio.VirtualServiceGvr()).Namespace(ch.Namespace).Create(ctx, unstr, metav1.CreateOptions{}) + if err != nil { + return nil, err + } + virtualService, err := istio.VirtualServiceFromUnstructured(val) + if err != nil { + return nil, err + } + return virtualService, nil +} + +func (s *Solver) checkAndUpdateVirtualService(ctx context.Context, ch *cmacme.Challenge, svcName string, virtualservice *istio.VirtualService) (*istio.VirtualService, error) { + log := logf.FromContext(ctx, "checkAndUpdateVirtualService") + + expectedSpec := createVirtualServiceSpec(ch, svcName) + + spec := &virtualservice.Spec + if reflect.DeepEqual(spec, expectedSpec) { + return virtualservice, nil + } + + log.Info("updating VirtualService") + + virtualservice.Spec = *expectedSpec + unstr, err := virtualservice.ToUnstructured() + if err != nil { + return nil, err + } + val, err := s.DynamicClient.Resource(istio.VirtualServiceGvr()).Namespace(ch.Namespace).Update(ctx, unstr, metav1.UpdateOptions{}) + if err != nil { + return nil, err + } + virtualService, err := istio.VirtualServiceFromUnstructured(val) + if err != nil { + return nil, err + } + return virtualService, nil +} + +func createVirtualServiceSpec(ch *cmacme.Challenge, svcName string) *networkingv1beta1.VirtualService { + http01Istio := ch.Spec.Solver.HTTP01.Istio + + return &networkingv1beta1.VirtualService{ + ExportTo: []string{"*"}, + Hosts: []string{ch.Spec.DNSName}, + Gateways: []string{http01Istio.GatewayNamespace + "/" + http01Istio.GatewayName}, + Http: []*networkingv1beta1.HTTPRoute{ + { + Match: []*networkingv1beta1.HTTPMatchRequest{ + {Uri: &networkingv1beta1.StringMatch{MatchType: &networkingv1beta1.StringMatch_Exact{Exact: solverPathFn(ch.Spec.Token)}}}, + }, + Route: []*networkingv1beta1.HTTPRouteDestination{ + { + Destination: &networkingv1beta1.Destination{ + Host: svcName, + Port: &networkingv1beta1.PortSelector{Number: acmeSolverListenPort}, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/issuer/acme/http/istio_test.go b/pkg/issuer/acme/http/istio_test.go new file mode 100644 index 000000000..7a88d739e --- /dev/null +++ b/pkg/issuer/acme/http/istio_test.go @@ -0,0 +1,181 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package http + +import ( + "context" + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + + cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" + "github.com/jetstack/cert-manager/pkg/issuer/acme/http/internal/istio" +) + +func TestEnsureIstio(t *testing.T) { + const svcName = "fakeservice" + + const virtualServiceSpecKey = "virtualservicespec" + + virtualServiceGvr := istio.VirtualServiceGvr() + + testChallenge := cmacme.Challenge{ + Spec: cmacme.ChallengeSpec{ + DNSName: "example.com", + Solver: cmacme.ACMEChallengeSolver{ + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Istio: &cmacme.ACMEChallengeSolverHTTP01Istio{ + GatewayNamespace: defaultTestNamespace, + GatewayName: "test-gateway", + }, + }, + }, + }, + } + + tests := map[string]solverFixture{ + "should create VirtualService": { + Challenge: &testChallenge, + CheckFn: func(t *testing.T, s *solverFixture, args ...interface{}) { + vss, err := s.Solver.virtualServiceLister.List(labels.NewSelector()) + if err != nil { + t.Errorf("error listing VirtualServices: %v", err) + return + } + if len(vss) != 1 { + t.Errorf("expected one VirtualService to be created, but %d VirtualServices were found", len(vss)) + } + }, + }, + "should not modify correct VirtualService": { + Challenge: &testChallenge, + PreFn: func(t *testing.T, s *solverFixture) { + virtualServiceSpec := createVirtualServiceSpec(&testChallenge, svcName) + s.testResources[virtualServiceSpecKey] = virtualServiceSpec + virtualService := istio.VirtualService{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-gateway-", + Namespace: testChallenge.Namespace, + Labels: podLabels(&testChallenge), + OwnerReferences: []metav1.OwnerReference{}, + }, + Spec: *virtualServiceSpec, + } + unstr, err := virtualService.ToUnstructured() + if err != nil { + t.Errorf("error converting to unstructured: %v", err) + } + _, err = s.FakeDynamicClient().Resource(virtualServiceGvr).Namespace(testChallenge.Namespace).Create(context.Background(), unstr, metav1.CreateOptions{}) + if err != nil { + t.Errorf("error preparing test: %v", err) + } + }, + CheckFn: func(t *testing.T, s *solverFixture, args ...interface{}) { + vss, err := s.Solver.virtualServiceLister.List(labels.NewSelector()) + if err != nil { + t.Errorf("error listing VirtualServices: %v", err) + return + } + if len(vss) != 1 { + t.Errorf("expected one VirtualService to be created, but %d VirtualServices were found", len(vss)) + return + } + newVirtualService, err := istio.VirtualServiceFromUnstructured(vss[0]) + if err != nil { + t.Errorf("could not decode retrieved VirtualService: %v", err) + return + } + + oldVirtualServiceSpec := s.testResources[virtualServiceSpecKey] + newVirtualServiceSpec := &newVirtualService.Spec + if reflect.TypeOf(oldVirtualServiceSpec) != reflect.TypeOf(newVirtualServiceSpec) { + t.Errorf("types should be equal (error in test)") + } + if !reflect.DeepEqual(oldVirtualServiceSpec, newVirtualServiceSpec) { + t.Errorf("did not expect correct virtualservice to be modified") + } + }, + }, + "should fix existing VirtualService": { + Challenge: &testChallenge, + PreFn: func(t *testing.T, s *solverFixture) { + virtualServiceSpec := createVirtualServiceSpec(&testChallenge, svcName+"-needs-fixing") + s.testResources[virtualServiceSpecKey] = virtualServiceSpec + virtualService := istio.VirtualService{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-gateway-", + Namespace: testChallenge.Namespace, + Labels: podLabels(&testChallenge), + OwnerReferences: []metav1.OwnerReference{}, + }, + Spec: *virtualServiceSpec, + } + unstr, err := virtualService.ToUnstructured() + if err != nil { + t.Errorf("error converting to unstructured: %v", err) + } + _, err = s.FakeDynamicClient().Resource(virtualServiceGvr).Namespace(testChallenge.Namespace).Create(context.Background(), unstr, metav1.CreateOptions{}) + if err != nil { + t.Errorf("error preparing test: %v", err) + } + }, + CheckFn: func(t *testing.T, s *solverFixture, args ...interface{}) { + vss, err := s.Solver.virtualServiceLister.List(labels.NewSelector()) + if err != nil { + t.Errorf("error listing VirtualServices: %v", err) + return + } + if len(vss) != 1 { + t.Errorf("expected one VirtualService to be created, but %d VirtualServices were found", len(vss)) + return + } + newVirtualService, err := istio.VirtualServiceFromUnstructured(vss[0]) + if err != nil { + t.Errorf("could not decode retrieved VirtualService: %v", err) + return + } + + oldVirtualServiceSpec := s.testResources[virtualServiceSpecKey] + newVirtualServiceSpec := &newVirtualService.Spec + if reflect.TypeOf(oldVirtualServiceSpec) != reflect.TypeOf(newVirtualServiceSpec) { + t.Errorf("types should be equal (error in test)") + } + if reflect.DeepEqual(oldVirtualServiceSpec, newVirtualServiceSpec) { + t.Errorf("expected existing VirtualService spec to be fixed") + } + if newVirtualServiceSpec.Http[0].Route[0].Destination.Host != svcName { + t.Errorf("expected virtualservice destination service to be fixed") + } + }, + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + test.Setup(t) + resp, err := test.Solver.ensureIstio(context.TODO(), test.Challenge, svcName) + if err != nil && !test.Err { + t.Errorf("Expected function to not error, but got: %v", err) + } + if err == nil && test.Err { + t.Errorf("Expected function to get an error, but got: %v", err) + } + test.Finish(t, resp, err) + }) + } +} diff --git a/pkg/issuer/acme/http/pod.go b/pkg/issuer/acme/http/pod.go index 80aca1f53..b5700ba79 100644 --- a/pkg/issuer/acme/http/pod.go +++ b/pkg/issuer/acme/http/pod.go @@ -144,10 +144,12 @@ func (s *Solver) buildPod(ch *cmacme.Challenge) *corev1.Pod { pod := s.buildDefaultPod(ch) // Override defaults if they have changed in the pod template. - if ch.Spec.Solver.HTTP01 != nil && - ch.Spec.Solver.HTTP01.Ingress != nil { - pod = s.mergePodObjectMetaWithPodTemplate(pod, - ch.Spec.Solver.HTTP01.Ingress.PodTemplate) + if ch.Spec.Solver.HTTP01 != nil { + if ch.Spec.Solver.HTTP01.Ingress != nil { + pod = s.mergePodObjectMetaWithPodTemplate(pod, ch.Spec.Solver.HTTP01.Ingress.PodTemplate) + } else if ch.Spec.Solver.HTTP01.Istio != nil { + pod = s.mergePodObjectMetaWithPodTemplate(pod, ch.Spec.Solver.HTTP01.Istio.PodTemplate) + } } return pod diff --git a/pkg/issuer/acme/http/service.go b/pkg/issuer/acme/http/service.go index 3adf7a450..7215e9d17 100644 --- a/pkg/issuer/acme/http/service.go +++ b/pkg/issuer/acme/http/service.go @@ -125,12 +125,12 @@ func buildService(ch *cmacme.Challenge) (*corev1.Service, error) { } // checking for presence of http01 config and if set serviceType is set, override our default (NodePort) - httpDomainCfg, err := httpDomainCfgForChallenge(ch) + serviceType, err := serviceTypeForChallenge(ch) if err != nil { return nil, err } - if httpDomainCfg.ServiceType != "" { - service.Spec.Type = httpDomainCfg.ServiceType + if serviceType != "" { + service.Spec.Type = serviceType } return service, nil diff --git a/test/e2e/framework/config/BUILD.bazel b/test/e2e/framework/config/BUILD.bazel index 247e11ee4..7827f96dd 100644 --- a/test/e2e/framework/config/BUILD.bazel +++ b/test/e2e/framework/config/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "ginkgo.go", "helm.go", "ingress_controller.go", + "istio.go", "samplewebhook.go", "suite.go", "tiller.go", diff --git a/test/e2e/framework/config/acme.go b/test/e2e/framework/config/acme.go index 4c3b34f40..d19c9fa63 100644 --- a/test/e2e/framework/config/acme.go +++ b/test/e2e/framework/config/acme.go @@ -24,12 +24,14 @@ type ACMEServer struct { URL string DNSServer string IngressIP string + IstioIP string } func (p *ACMEServer) AddFlags(fs *flag.FlagSet) { fs.StringVar(&p.URL, "acme-server-url", "https://pebble.pebble.svc.cluster.local/dir", "URL for the ACME server used during end-to-end tests") fs.StringVar(&p.DNSServer, "acme-dns-server", "10.0.0.16", "DNS server for ACME DNS01 tests to run against using RFC2136") - fs.StringVar(&p.IngressIP, "acme-ingress-ip", "10.0.0.15", "IP of the ingress server that solves HTTP01 ACME challenges") + fs.StringVar(&p.IngressIP, "acme-ingress-ip", "10.0.0.15", "IP of the ingress server that solves HTTP01 ACME Ingress challenges") + fs.StringVar(&p.IstioIP, "acme-istio-ip", "10.0.0.14", "IP of the ingress server that solves HTTP01 ACME Istio challenges") } func (p *ACMEServer) Validate() []error { diff --git a/test/e2e/framework/config/addons.go b/test/e2e/framework/config/addons.go index b69a17ee1..415b76bb6 100644 --- a/test/e2e/framework/config/addons.go +++ b/test/e2e/framework/config/addons.go @@ -33,9 +33,13 @@ type Addons struct { ACMEServer ACMEServer // IngressController contains configuration for the ingress controller - // being used during ACME HTTP01 tests. + // being used during ACME HTTP01 Ingress tests. IngressController IngressController + // Istio contains configuration for the istio virtualservice controller + // being used during ACME HTTP01 Istio tests. + Istio Istio + // Venafi describes global configuration variables for the Venafi tests. // This includes credentials for the Venafi TPP server to use during runs. Venafi Venafi @@ -52,6 +56,7 @@ func (a *Addons) AddFlags(fs *flag.FlagSet) { a.Helm.AddFlags(fs) a.ACMEServer.AddFlags(fs) a.IngressController.AddFlags(fs) + a.Istio.AddFlags(fs) a.Venafi.AddFlags(fs) a.CertManager.AddFlags(fs) a.DNS01Webhook.AddFlags(fs) @@ -63,6 +68,7 @@ func (c *Addons) Validate() []error { errs = append(errs, c.Helm.Validate()...) errs = append(errs, c.ACMEServer.Validate()...) errs = append(errs, c.IngressController.Validate()...) + errs = append(errs, c.Istio.Validate()...) errs = append(errs, c.Venafi.Validate()...) errs = append(errs, c.CertManager.Validate()...) errs = append(errs, c.DNS01Webhook.Validate()...) diff --git a/test/e2e/framework/config/istio.go b/test/e2e/framework/config/istio.go new file mode 100644 index 000000000..1e7f21113 --- /dev/null +++ b/test/e2e/framework/config/istio.go @@ -0,0 +1,45 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "flag" +) + +type Istio struct { + // Domain is a domain name that can be used during e2e tests. + // This domain should have records for *.example.com and example.com pointing + // to the IP of the Istio ingress gateway's Service resource. + Domain string + + // GatewayNamespace is the namespace of the gateway resource used for the HTTP01 ACME validation tests. + GatewayNamespace string + + // GatewayName is the name of the gateway resource used for the HTTP01 ACME validation tests. + GatewayName string +} + +func (n *Istio) AddFlags(fs *flag.FlagSet) { + fs.StringVar(&n.Domain, "istio-ingress-domain", "istio.http01.example.com", "The domain name used during ACME DNS01 validation tests. "+ + "All subdomains of this domain must also resolve to the IP of the Istio ingress gateway's Service.") + fs.StringVar(&n.GatewayNamespace, "istio-gateway-namespace", "istio-system", "The namespace of the gateway resource used for the HTTP01 ACME validation tests") + fs.StringVar(&n.GatewayName, "istio-gateway-name", "ingress", "The name of the gateway resource used for the HTTP01 ACME validation tests") +} + +func (n *Istio) Validate() []error { + return nil +} diff --git a/test/e2e/framework/helper/secret.go b/test/e2e/framework/helper/secret.go index a462cb0d2..648410f98 100644 --- a/test/e2e/framework/helper/secret.go +++ b/test/e2e/framework/helper/secret.go @@ -18,6 +18,8 @@ package helper import ( "context" + "crypto/tls" + "crypto/x509" "fmt" "time" @@ -57,3 +59,27 @@ func (h *Helper) WaitForSecretCertificateData(ns, name string, timeout time.Dura return secret, nil } + +// GetSecretDNSNames decodes and returns the dns names (SANs) contained in a +// certificate secret. +func (h *Helper) GetSecretDNSNames(s *corev1.Secret) ([]string, error) { + if s.Data == nil { + return nil, fmt.Errorf("secret contains no data") + } + pkData := s.Data[corev1.TLSPrivateKeyKey] + certData := s.Data[corev1.TLSCertKey] + if len(pkData) == 0 || len(certData) == 0 { + return nil, fmt.Errorf("missing data in CA secret") + } + cert, err := tls.X509KeyPair(certData, pkData) + if err != nil { + return nil, fmt.Errorf("failed to parse data in CA secret: %w", err) + } + + x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return nil, fmt.Errorf("internal error parsing x509 certificate: %w", err) + } + + return x509Cert.DNSNames, nil +} diff --git a/test/e2e/suite/conformance/certificates/acme/acme.go b/test/e2e/suite/conformance/certificates/acme/acme.go index 43a48b4ba..cfa0e45e8 100644 --- a/test/e2e/suite/conformance/certificates/acme/acme.go +++ b/test/e2e/suite/conformance/certificates/acme/acme.go @@ -79,11 +79,20 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) { (&certificates.Suite{ Name: "ACME HTTP01 Issuer", + DomainSuffixType: certificates.IngressDomainSuffixType, CreateIssuerFunc: provisionerHTTP01.createHTTP01Issuer, DeleteIssuerFunc: provisionerHTTP01.delete, UnsupportedFeatures: unsupportedHTTP01Features, }).Define() + (&certificates.Suite{ + Name: "ACME HTTP01 Issuer on Istio", + DomainSuffixType: certificates.IstioDomainSuffixType, + CreateIssuerFunc: provisionerHTTP01.createHTTP01IssuerOnIstio, + DeleteIssuerFunc: provisionerHTTP01.delete, + UnsupportedFeatures: unsupportedHTTP01Features, + }).Define() + (&certificates.Suite{ Name: "ACME DNS01 Issuer", DomainSuffix: "dns01.example.com", @@ -94,6 +103,7 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) { (&certificates.Suite{ Name: "ACME HTTP01 ClusterIssuer", + DomainSuffixType: certificates.IngressDomainSuffixType, CreateIssuerFunc: provisionerHTTP01.createHTTP01ClusterIssuer, DeleteIssuerFunc: provisionerHTTP01.delete, UnsupportedFeatures: unsupportedHTTP01Features, @@ -152,6 +162,27 @@ func (a *acmeIssuerProvisioner) createHTTP01Issuer(f *framework.Framework) cmmet } } +func (a *acmeIssuerProvisioner) createHTTP01IssuerOnIstio(f *framework.Framework) cmmeta.ObjectReference { + a.ensureEABSecret(f, "") + + By("Creating an ACME HTTP01 Istio Issuer") + issuer := &cmapi.Issuer{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "acme-issuer-http01-", + }, + Spec: a.createHTTP01IssuerOnIstioSpec(f.Config.Addons.ACMEServer.URL), + } + + issuer, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred(), "failed to create acme HTTP01 Istio issuer") + + return cmmeta.ObjectReference{ + Group: cmapi.SchemeGroupVersion.Group, + Kind: cmapi.IssuerKind, + Name: issuer.Name, + } +} + func (a *acmeIssuerProvisioner) createHTTP01ClusterIssuer(f *framework.Framework) cmmeta.ObjectReference { a.ensureEABSecret(f, f.Config.Addons.CertManager.ClusterResourceNamespace) @@ -200,6 +231,36 @@ func (a *acmeIssuerProvisioner) createHTTP01IssuerSpec(serverURL string) cmapi.I } } +func (a *acmeIssuerProvisioner) createHTTP01IssuerOnIstioSpec(serverURL string) cmapi.IssuerSpec { + const TestGatewayNamespace = "istio-system" + const TestGatewayName = "ingress" + + return cmapi.IssuerSpec{ + IssuerConfig: cmapi.IssuerConfig{ + ACME: &cmacme.ACMEIssuer{ + Server: serverURL, + SkipTLSVerify: true, + PrivateKey: cmmeta.SecretKeySelector{ + LocalObjectReference: cmmeta.LocalObjectReference{ + Name: "acme-private-key-http01", + }, + }, + ExternalAccountBinding: a.eab, + Solvers: []cmacme.ACMEChallengeSolver{ + { + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Istio: &cmacme.ACMEChallengeSolverHTTP01Istio{ + GatewayNamespace: TestGatewayNamespace, + GatewayName: TestGatewayName, + }, + }, + }, + }, + }, + }, + } +} + func (a *acmeIssuerProvisioner) createDNS01Issuer(f *framework.Framework) cmmeta.ObjectReference { a.ensureEABSecret(f, f.Namespace.Name) diff --git a/test/e2e/suite/conformance/certificates/suite.go b/test/e2e/suite/conformance/certificates/suite.go index 7f8ae9601..17383af3d 100644 --- a/test/e2e/suite/conformance/certificates/suite.go +++ b/test/e2e/suite/conformance/certificates/suite.go @@ -28,6 +28,11 @@ import ( "github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset" ) +const ( + IstioDomainSuffixType = "istio" + IngressDomainSuffixType = "ingress" +) + // Suite defines a reusable conformance test suite that can be used against any // Issuer implementation. type Suite struct { @@ -56,6 +61,10 @@ type Suite struct { // nginx-ingress addon. DomainSuffix string + // DomainSuffixType is a string used to detect what DomainSuffix to use + // in case DomainSuffix is left empty. + DomainSuffixType string + // UnsupportedFeatures is a list of features that are not supported by this // invocation of the test suite. // This is useful if a particular issuers explicitly does not support @@ -68,12 +77,23 @@ type Suite struct { // complete will validate configuration and set default values. func (s *Suite) complete(f *framework.Framework) { - // TODO: work out how to fail an entire 'Describe' block so we can validate these are correctly set - //Expect(s.Name).NotTo(Equal(""), "Name must be set") - //Expect(s.CreateIssuerFunc).NotTo(BeNil(), "CreateIssuerFunc must be set") + if s.Name == "" { + Fail("Name must be set") + } + + if s.CreateIssuerFunc == nil { + Fail("CreateIssuerFunc must be set") + } if s.DomainSuffix == "" { - s.DomainSuffix = f.Config.Addons.IngressController.Domain + switch s.DomainSuffixType { + case IngressDomainSuffixType, "": + s.DomainSuffix = f.Config.Addons.IngressController.Domain + case IstioDomainSuffixType: + s.DomainSuffix = f.Config.Addons.Istio.Domain + default: + Fail("Domain suffix type not recognised") + } } if s.UnsupportedFeatures == nil { @@ -138,3 +158,7 @@ func (s *Suite) newDomainDepth(depth int) string { } return strings.Join(append(subdomains, s.DomainSuffix), ".") } + +func (s *Suite) newDomainLength(length int) string { + return fmt.Sprintf("%s.%s", util.RandStringRunes(length), s.DomainSuffix) +} diff --git a/test/e2e/suite/conformance/certificates/tests.go b/test/e2e/suite/conformance/certificates/tests.go index e334fbf21..81e4aef7d 100644 --- a/test/e2e/suite/conformance/certificates/tests.go +++ b/test/e2e/suite/conformance/certificates/tests.go @@ -574,5 +574,86 @@ func (s *Suite) Define() { err = f.Helper().ValidateCertificate(f.Namespace.Name, certName, f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...) Expect(err).NotTo(HaveOccurred()) }) + + s.it(f, "should allow updating an existing certificate with a new dns name", func(issuerRef cmmeta.ObjectReference) { + testCertificate := &cmapi.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testcert", + Namespace: f.Namespace.Name, + }, + Spec: cmapi.CertificateSpec{ + SecretName: "testcert-tls", + DNSNames: []string{s.newDomain()}, + IssuerRef: issuerRef, + }, + } + validations := f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures) + + By("Creating a Certificate") + err := f.CRClient.Create(ctx, testCertificate) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, "testcert", validations...) + Expect(err).NotTo(HaveOccurred()) + + By("Getting the latest version of the Certificate") + cert, err := f.Helper().CMClient.CertmanagerV1().Certificates(f.Namespace.Name).Get(context.TODO(), "testcert", metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Adding an additional dnsName to the Certificate") + newDNSName := s.newDomain() + cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName) + + By("Updating the Certificate in the apiserver") + err = f.CRClient.Update(context.TODO(), cert) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be not ready") + _, err = f.Helper().WaitForCertificateNotReady(f.Namespace.Name, "testcert", time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, "testcert", validations...) + Expect(err).NotTo(HaveOccurred()) + }, featureset.OnlySAN) + + s.it(f, "should obtain a signed certificate for a long domain", func(issuerRef cmmeta.ObjectReference) { + // the maximum length of a single segment of the domain being requested + const maxLengthOfDomainSegment = 63 + + testCertificate := &cmapi.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testcert", + Namespace: f.Namespace.Name, + }, + Spec: cmapi.CertificateSpec{ + SecretName: "testcert-tls", + DNSNames: []string{s.newDomainLength(maxLengthOfDomainSegment)}, + IssuerRef: issuerRef, + }, + } + validations := f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures) + + By("Creating a Certificate") + err := f.CRClient.Create(ctx, testCertificate) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, "testcert", validations...) + Expect(err).NotTo(HaveOccurred()) + }, featureset.OnlySAN) }) } diff --git a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel index 4a81e1687..328e89d67 100644 --- a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel +++ b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel @@ -4,7 +4,8 @@ go_library( name = "go_default_library", srcs = [ "dns01.go", - "http01.go", + "http01_ingress.go", + "http01_istio.go", "notafter.go", "webhook.go", ], diff --git a/test/e2e/suite/issuers/acme/certificate/http01.go b/test/e2e/suite/issuers/acme/certificate/http01_ingress.go similarity index 76% rename from test/e2e/suite/issuers/acme/certificate/http01.go rename to test/e2e/suite/issuers/acme/certificate/http01_ingress.go index 934dc13ae..efafe881b 100644 --- a/test/e2e/suite/issuers/acme/certificate/http01.go +++ b/test/e2e/suite/issuers/acme/certificate/http01_ingress.go @@ -18,8 +18,6 @@ package certificate import ( "context" - "crypto/tls" - "crypto/x509" "fmt" "strings" "time" @@ -49,9 +47,8 @@ const testingACMEEmail = "e2e@cert-manager.io" const testingACMEPrivateKey = "test-acme-private-key" const foreverTestTimeout = time.Second * 60 -var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { - f := framework.NewDefaultFramework("create-acme-certificate-http01") - h := f.Helper() +var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01) Ingress", func() { + f := framework.NewDefaultFramework("create-acme-certificate-http01-ingress") var acmeIngressDomain string issuerName := "test-acme-issuer" @@ -183,33 +180,6 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { Expect(err).NotTo(HaveOccurred()) }) - It("should obtain a signed certificate for a long domain using http01 validation", func() { - certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) - - // the maximum length of a single segment of the domain being requested - const maxLengthOfDomainSegment = 63 - By("Creating a Certificate") - - By("Creating a Certificate") - cert := gen.Certificate(certificateName, - gen.SetCertificateSecretName(certificateSecretName), - gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), - gen.SetCertificateDNSNames(acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)), - ) - cert.Namespace = f.Namespace.Name - - _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to be issued...") - err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Validating the issued Certificate...") - err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) - Expect(err).NotTo(HaveOccurred()) - }) - It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() { certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) @@ -234,57 +204,6 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { Expect(err).NotTo(HaveOccurred()) }) - It("should allow updating an existing certificate with a new dns name", func() { - certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) - - By("Creating a Certificate") - cert := gen.Certificate(certificateName, - gen.SetCertificateSecretName(certificateSecretName), - gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), - gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)), - ) - cert.Namespace = f.Namespace.Name - - _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Verifying the Certificate is valid") - - By("Waiting for the Certificate to be issued...") - err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Validating the issued Certificate...") - err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) - Expect(err).NotTo(HaveOccurred()) - - By("Getting the latest version of the Certificate") - cert, err = certClient.Get(context.TODO(), certificateName, metav1.GetOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Adding an additional dnsName to the Certificate") - newDNSName := fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain) - cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName) - - By("Updating the Certificate in the apiserver") - cert, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to be not ready") - _, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to become ready & valid") - - By("Waiting for the Certificate to be issued...") - err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Validating the issued Certificate...") - err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) - Expect(err).NotTo(HaveOccurred()) - }) - It("should allow updating the dns name of a failing certificate that had an incorrect dns name", func() { certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) @@ -322,7 +241,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for the Certificate to be not ready") - _, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, 30*time.Second) + _, err = f.Helper().WaitForCertificateNotReady(f.Namespace.Name, certificateName, 30*time.Second) Expect(err).NotTo(HaveOccurred()) By("Getting the latest version of the Certificate") @@ -344,7 +263,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { By("Checking that the secret contains this dns name") err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, func(cert *v1.Certificate, secret *corev1.Secret) error { - dnsnames, err := findDNSNames(secret) + dnsnames, err := f.Helper().GetSecretDNSNames(secret) if err != nil { return err } @@ -399,7 +318,6 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { }) It("should obtain a signed certificate with a single CN from the ACME server when redirected", func() { - certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) // force-ssl-redirect should make every request turn into a redirect, @@ -602,76 +520,4 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() { err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) Expect(err).NotTo(HaveOccurred()) }) - - It("should allow updating an existing certificate with a new dns name", func() { - certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) - - By("Creating a Certificate") - cert := gen.Certificate(certificateName, - gen.SetCertificateSecretName(certificateSecretName), - gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), - gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)), - ) - cert.Namespace = f.Namespace.Name - - _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to be issued...") - err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Validating the issued Certificate...") - err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) - Expect(err).NotTo(HaveOccurred()) - - By("Getting the latest version of the Certificate") - cert, err = certClient.Get(context.TODO(), certificateName, metav1.GetOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Adding an additional dnsName to the Certificate") - newDNSName := fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain) - cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName) - - By("Updating the Certificate in the apiserver") - cert, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{}) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to be not ready") - _, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Waiting for the Certificate to be issued...") - err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) - Expect(err).NotTo(HaveOccurred()) - - By("Validating the issued Certificate...") - err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) - Expect(err).NotTo(HaveOccurred()) - }) - }) - -// findDNSNames decodes and returns the dns names (SANs) contained in a -// certificate secret. -func findDNSNames(s *corev1.Secret) ([]string, error) { - if s.Data == nil { - return nil, fmt.Errorf("secret contains no data") - } - pkData := s.Data[corev1.TLSPrivateKeyKey] - certData := s.Data[corev1.TLSCertKey] - if len(pkData) == 0 || len(certData) == 0 { - return nil, fmt.Errorf("missing data in CA secret") - } - cert, err := tls.X509KeyPair(certData, pkData) - if err != nil { - return nil, fmt.Errorf("failed to parse data in CA secret: %w", err) - } - - x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return nil, fmt.Errorf("internal error parsing x509 certificate: %w", err) - } - - return x509Cert.DNSNames, nil -} diff --git a/test/e2e/suite/issuers/acme/certificate/http01_istio.go b/test/e2e/suite/issuers/acme/certificate/http01_istio.go new file mode 100644 index 000000000..22156b06b --- /dev/null +++ b/test/e2e/suite/issuers/acme/certificate/http01_istio.go @@ -0,0 +1,380 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certificate + +import ( + "context" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" + v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + cmutil "github.com/jetstack/cert-manager/pkg/util" + "github.com/jetstack/cert-manager/test/e2e/framework" + "github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset" + "github.com/jetstack/cert-manager/test/e2e/framework/log" + . "github.com/jetstack/cert-manager/test/e2e/framework/matcher" + frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util" + "github.com/jetstack/cert-manager/test/e2e/util" + "github.com/jetstack/cert-manager/test/unit/gen" +) + +const istioTestingACMEEmail = "e2e@cert-manager.io" +const istioTestingACMEPrivateKey = "test-acme-private-key" +const istioForeverTestTimeout = time.Second * 60 + +var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01) Istio", func() { + f := framework.NewDefaultFramework("create-acme-certificate-http01-istio") + + var acmeIngressDomain string + issuerName := "test-acme-issuer" + certificateName := "test-acme-certificate" + certificateSecretName := "test-acme-certificate" + + // ACME Issuer does not return a ca.crt. See: + // https://github.com/jetstack/cert-manager/issues/1571 + unsupportedFeatures := featureset.NewFeatureSet(featureset.SaveCAToSecret) + validations := f.Helper().ValidationSetForUnsupportedFeatureSet(unsupportedFeatures) + + BeforeEach(func() { + solvers := []cmacme.ACMEChallengeSolver{ + { + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Istio: &cmacme.ACMEChallengeSolverHTTP01Istio{ + GatewayNamespace: f.Config.Addons.Istio.GatewayNamespace, + GatewayName: f.Config.Addons.Istio.GatewayName, + }, + }, + }, + } + acmeIssuer := gen.Issuer(issuerName, + gen.SetIssuerNamespace(f.Namespace.Name), + gen.SetIssuerACMEEmail(istioTestingACMEEmail), + gen.SetIssuerACMEURL(f.Config.Addons.ACMEServer.URL), + gen.SetIssuerACMEPrivKeyRef(istioTestingACMEPrivateKey), + gen.SetIssuerACMESkipTLSVerify(true), + gen.SetIssuerACMESolvers(solvers)) + By("Creating an Issuer") + _, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), acmeIssuer, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Waiting for Issuer to become Ready") + err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + v1.IssuerCondition{ + Type: v1.IssuerConditionReady, + Status: cmmeta.ConditionTrue, + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the ACME account URI is set") + err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + func(i *v1.Issuer) (bool, error) { + if i.GetStatus().ACMEStatus().URI == "" { + return false, nil + } + return true, nil + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying ACME account private key exists") + secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), istioTestingACMEPrivateKey, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + if len(secret.Data) != 1 { + Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data)) + } + }) + + JustBeforeEach(func() { + acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.Istio.Domain) + }) + + AfterEach(func() { + By("Cleaning up") + f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{}) + f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), istioTestingACMEPrivateKey, metav1.DeleteOptions{}) + }) + + It("should obtain a signed certificate with a single CN from the ACME server", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames(acmeIngressDomain), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed ecdsa certificate with a single CN from the ACME server", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{ + Name: issuerName, + }), + gen.SetCertificateDNSNames(acmeIngressDomain), + gen.SetCertificateKeyAlgorithm(v1.ECDSAKeyAlgorithm), + ) + cert.Namespace = f.Namespace.Name + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the Certificate is valid") + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should allow updating the dns name of a failing certificate that had an incorrect dns name", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a failing Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames("google.com"), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Making sure the Order failed with a 400 since google.com is invalid") + order := &cmacme.Order{} + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (done bool, err error) { + orders, err := listOwnedOrders(f.CertManagerClientSet, cert) + Expect(err).NotTo(HaveOccurred()) + + if len(orders) == 0 || len(orders) > 1 { + log.Logf("Waiting as one Order should exist, but we found %d", len(orders)) + return false, nil + } + order = orders[0] + + expected := `400 urn:ietf:params:acme:error:rejectedIdentifier` + if !strings.Contains(order.Status.Reason, expected) { + log.Logf("Waiting for Order's reason, current: %s, should contain: %s", order.Status.Reason, expected) + return false, nil + } + + return true, nil + }) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be not ready") + _, err = f.Helper().WaitForCertificateNotReady(f.Namespace.Name, certificateName, 30*time.Second) + Expect(err).NotTo(HaveOccurred()) + + By("Getting the latest version of the Certificate") + cert, err = certClient.Get(context.TODO(), certificateName, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Replacing dnsNames with a valid dns name") + cert.Spec.DNSNames = []string{fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)} + _, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to have the Ready=True condition") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Sanity checking the issued Certificate") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + + By("Checking that the secret contains this dns name") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, func(cert *v1.Certificate, secret *corev1.Secret) error { + dnsnames, err := f.Helper().GetSecretDNSNames(secret) + if err != nil { + return err + } + Expect(cert.Spec.DNSNames).To(ContainElements(dnsnames)) + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should fail to obtain a certificate for an invalid ACME dns name", func() { + // create test fixture + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames("google.com"), + ) + cert.Namespace = f.Namespace.Name + + cert, err := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name).Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + notReadyCondition := v1.CertificateCondition{ + Type: v1.CertificateConditionReady, + Status: cmmeta.ConditionFalse, + } + Eventually(cert, "30s", "1s").Should(HaveCondition(f, notReadyCondition)) + Consistently(cert, "1m", "10s").Should(HaveCondition(f, notReadyCondition)) + }) + + It("should automatically recreate challenge pod and still obtain a certificate if it is manually deleted", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames(acmeIngressDomain), + ) + cert.Namespace = f.Namespace.Name + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("killing the solver pod") + podClient := f.KubeClientSet.CoreV1().Pods(f.Namespace.Name) + var pod corev1.Pod + err = wait.PollImmediate(1*time.Second, time.Minute, + func() (bool, error) { + log.Logf("Waiting for solver pod to exist") + podlist, err := podClient.List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return false, err + } + + for _, p := range podlist.Items { + log.Logf("solver pod %s", p.Name) + // TODO(dmo): make this cleaner instead of just going by name + if strings.Contains(p.Name, "http-solver") { + pod = p + return true, nil + } + } + return false, nil + + }, + ) + Expect(err).NotTo(HaveOccurred()) + + err = podClient.Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + + // The pod should get remade and the certificate should be made valid. + // Killing the pod could potentially make the validation invalid if pebble + // were to ask us for the challenge after the pod was killed, but because + // we kill it so early, we should always be in the self-check phase + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed certificate with a single IP Address from the ACME server", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateIPs(f.Config.Addons.ACMEServer.IngressIP), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed certificate with an IP and DNS names from the ACME server", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(2), acmeIngressDomain)), + gen.SetCertificateIPs(f.Config.Addons.ACMEServer.IstioIP), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...) + Expect(err).NotTo(HaveOccurred()) + }) +}) diff --git a/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel b/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel index 240797a5e..e08f7be3c 100644 --- a/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel +++ b/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel @@ -4,7 +4,8 @@ go_library( name = "go_default_library", srcs = [ "dns01.go", - "http01.go", + "http01_ingress.go", + "http01_istio.go", ], importpath = "github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/certificaterequest", visibility = ["//visibility:public"], diff --git a/test/e2e/suite/issuers/acme/certificaterequest/http01.go b/test/e2e/suite/issuers/acme/certificaterequest/http01_ingress.go similarity index 99% rename from test/e2e/suite/issuers/acme/certificaterequest/http01.go rename to test/e2e/suite/issuers/acme/certificaterequest/http01_ingress.go index d7047ca16..4155356d5 100644 --- a/test/e2e/suite/issuers/acme/certificaterequest/http01.go +++ b/test/e2e/suite/issuers/acme/certificaterequest/http01_ingress.go @@ -41,8 +41,8 @@ import ( "github.com/jetstack/cert-manager/test/unit/gen" ) -var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01)", func() { - f := framework.NewDefaultFramework("create-acme-certificate-request-http01") +var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01) Ingress", func() { + f := framework.NewDefaultFramework("create-acme-certificate-request-http01-ingress") h := f.Helper() var acmeIngressDomain string diff --git a/test/e2e/suite/issuers/acme/certificaterequest/http01_istio.go b/test/e2e/suite/issuers/acme/certificaterequest/http01_istio.go new file mode 100644 index 000000000..22d00152b --- /dev/null +++ b/test/e2e/suite/issuers/acme/certificaterequest/http01_istio.go @@ -0,0 +1,238 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certificate + +import ( + "context" + "crypto/x509" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" + v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + cmutil "github.com/jetstack/cert-manager/pkg/util" + "github.com/jetstack/cert-manager/test/e2e/framework" + "github.com/jetstack/cert-manager/test/e2e/framework/log" + . "github.com/jetstack/cert-manager/test/e2e/framework/matcher" + frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util" + "github.com/jetstack/cert-manager/test/e2e/util" + "github.com/jetstack/cert-manager/test/unit/gen" +) + +var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01) Istio", func() { + f := framework.NewDefaultFramework("create-acme-certificate-request-http01-istio") + h := f.Helper() + + var acmeIngressDomain string + issuerName := "test-acme-issuer" + certificateRequestName := "test-acme-certificate-request" + + BeforeEach(func() { + solvers := []cmacme.ACMEChallengeSolver{ + { + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Istio: &cmacme.ACMEChallengeSolverHTTP01Istio{ + GatewayNamespace: f.Config.Addons.Istio.GatewayNamespace, + GatewayName: f.Config.Addons.Istio.GatewayName, + }, + }, + }, + } + acmeIssuer := gen.Issuer(issuerName, + gen.SetIssuerNamespace(f.Namespace.Name), + gen.SetIssuerACMEEmail(testingACMEEmail), + gen.SetIssuerACMEURL(f.Config.Addons.ACMEServer.URL), + gen.SetIssuerACMEPrivKeyRef(testingACMEPrivateKey), + gen.SetIssuerACMESkipTLSVerify(true), + gen.SetIssuerACMESolvers(solvers)) + By("Creating an Issuer") + _, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), acmeIssuer, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Waiting for Issuer to become Ready") + err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + v1.IssuerCondition{ + Type: v1.IssuerConditionReady, + Status: cmmeta.ConditionTrue, + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the ACME account URI is set") + err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + func(i *v1.Issuer) (bool, error) { + if i.GetStatus().ACMEStatus().URI == "" { + return false, nil + } + return true, nil + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying ACME account private key exists") + secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + if len(secret.Data) != 1 { + Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data)) + } + }) + + JustBeforeEach(func() { + acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.Istio.Domain) + }) + + AfterEach(func() { + By("Cleaning up") + f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{}) + f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{}) + }) + + It("should obtain a signed certificate with a single CN from the ACME server", func() { + crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name) + + By("Creating a CertificateRequest") + cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{acmeIngressDomain}, nil, nil, x509.RSA) + Expect(err).NotTo(HaveOccurred()) + + cr, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Verifying the Certificate is valid") + err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed ecdsa certificate with a single CN from the ACME server", func() { + crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name) + + By("Creating a CertificateRequest") + cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{acmeIngressDomain}, nil, nil, x509.ECDSA) + Expect(err).NotTo(HaveOccurred()) + + _, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the Certificate is valid and of type ECDSA") + err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed certificate for a long domain using http01 validation", func() { + crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name) + + // the maximum length of a single segment of the domain being requested + const maxLengthOfDomainSegment = 63 + By("Creating a CertificateRequest") + cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)}, + nil, nil, x509.RSA) + Expect(err).NotTo(HaveOccurred()) + + _, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() { + crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name) + + By("Creating a CertificateRequest") + cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)}, + nil, nil, x509.RSA) + Expect(err).NotTo(HaveOccurred()) + + _, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the CertificateRequest is valid") + err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should fail to obtain a certificate for an invalid ACME dns name", func() { + // create test fixture + By("Creating a CertificateRequest") + cr, _, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{"google.com"}, nil, nil, x509.RSA) + Expect(err).NotTo(HaveOccurred()) + + cr, err = f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name).Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + notReadyCondition := v1.CertificateRequestCondition{ + Type: v1.CertificateRequestConditionReady, + Status: cmmeta.ConditionFalse, + } + Eventually(cr, "30s", "1s").Should(HaveCondition(f, notReadyCondition)) + Consistently(cr, "1m", "10s").Should(HaveCondition(f, notReadyCondition)) + }) + + It("should automatically recreate challenge pod and still obtain a certificate if it is manually deleted", func() { + crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name) + + By("Creating a CertificateRequest") + cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil, + []string{acmeIngressDomain}, nil, nil, x509.RSA) + Expect(err).NotTo(HaveOccurred()) + + _, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("killing the solver pod") + podClient := f.KubeClientSet.CoreV1().Pods(f.Namespace.Name) + var pod corev1.Pod + err = wait.PollImmediate(1*time.Second, time.Minute, + func() (bool, error) { + log.Logf("Waiting for solver pod to exist") + podlist, err := podClient.List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return false, err + } + + for _, p := range podlist.Items { + log.Logf("solver pod %s", p.Name) + // TODO(dmo): make this cleaner instead of just going by name + if strings.Contains(p.Name, "http-solver") { + pod = p + return true, nil + } + } + return false, nil + + }, + ) + Expect(err).NotTo(HaveOccurred()) + + err = podClient.Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + + // The pod should get remade and the certificate should be made valid. + // Killing the pod could potentially make the validation invalid if pebble + // were to ask us for the challenge after the pod was killed, but because + // we kill it so early, we should always be in the self-check phase + By("Verifying the CertificateRequest is valid") + err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key) + Expect(err).NotTo(HaveOccurred()) + }) +})