Revert "Merge pull request #3724 from inteon/istio-virtualservice-for-http01"

This reverts commit 80f27739b5, reversing
changes made to 96604d02a3.

Signed-off-by: Jake Sanders <i@am.so-aweso.me>
This commit is contained in:
Jake Sanders
2021-05-11 14:50:25 +01:00
parent 423e82b65b
commit 79d8d9cb7b
84 changed files with 1301 additions and 7556 deletions
-420
View File
@@ -15993,426 +15993,6 @@ 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: =
-4
View File
@@ -23,7 +23,6 @@ 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",
@@ -34,12 +33,9 @@ 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",
+11 -71
View File
@@ -24,11 +24,8 @@ 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"
@@ -48,7 +45,6 @@ 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"
@@ -72,26 +68,6 @@ 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()))
@@ -141,7 +117,6 @@ 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)
ctx.DynamicSharedInformerFactory.Start(stopCh)
wg.Wait()
log.V(logf.InfoLevel).Info("control loops exited")
ctx.Metrics.Shutdown(metricsServer)
@@ -163,33 +138,6 @@ 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
@@ -216,11 +164,6 @@ 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
@@ -259,24 +202,21 @@ 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,
DynamicClient: dyncl,
CMClient: intcl,
Recorder: recorder,
KubeSharedInformerFactory: kubeSharedInformerFactory,
DynamicSharedInformerFactory: dynamicSharedInformerFactory,
SharedInformerFactory: sharedInformerFactory,
Namespace: opts.Namespace,
Clock: clock.RealClock{},
Metrics: metrics.New(log),
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),
ACMEOptions: controller.ACMEOptions{
HTTP01SolverImage: opts.ACMEHTTP01SolverImage,
HTTP01SolverResourceRequestCPU: HTTP01SolverResourceRequestCPU,
@@ -223,14 +223,6 @@ rules:
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
{{- if .Values.global.rbac.allowIstioResourceAccess -}}
# 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"]
{{- end }}
# 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
-4
View File
@@ -12,10 +12,6 @@ global:
priorityClassName: ""
rbac:
create: true
# Allow cert-manager to manage Istio VirtualService resources, used for
# solving HTTP01 Istio challenges. When set to false, cert-manager will
# not support solving ACME HTTP01 challenges using VirtualServices.
allowIstioResourceAccess: true
podSecurityPolicy:
enabled: false
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -37,8 +37,6 @@ 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: |
;
-44
View File
@@ -1,44 +0,0 @@
#!/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"
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"
-14
View File
@@ -1,14 +0,0 @@
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: ingress
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
-31
View File
@@ -1,31 +0,0 @@
#!/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}" "$@"
+1 -3
View File
@@ -34,13 +34,12 @@ 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 //hack/bin:istioctl
bazel build //hack/bin:helm //hack/bin:kind //hack/bin:kubectl //hack/bin:kustomize //devel/bin:ginkgo
if [[ "$IS_OPENSHIFT" == "true" ]] ; then
bazel build //hack/bin:oc3
fi
@@ -49,7 +48,6 @@ 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
-1
View File
@@ -46,5 +46,4 @@ 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" \
"$@"
+1 -3
View File
@@ -31,9 +31,6 @@ source "${SCRIPT_ROOT}/lib/lib.sh"
# Configure PATH to use bazel provided e2e tools
setup_tools
echo "Installing Istio into the cluster..."
"${SCRIPT_ROOT}/addon/istio/install.sh"
echo "Installing cert-manager into the cluster..."
"${SCRIPT_ROOT}/addon/certmanager/install.sh"
@@ -57,3 +54,4 @@ echo "Loading vault into the cluster..."
echo "Installing sample-external-issuer into the cluster..."
"${SCRIPT_ROOT}/addon/sample-external-issuer/install.sh"
-1
View File
@@ -49,7 +49,6 @@ 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
+2 -14
View File
@@ -124,8 +124,6 @@ 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=
@@ -186,10 +184,8 @@ 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.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=
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=
@@ -295,7 +291,6 @@ 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=
@@ -944,11 +939,9 @@ 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=
@@ -1011,10 +1004,6 @@ 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=
@@ -1024,7 +1013,6 @@ 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=
-12
View File
@@ -80,18 +80,6 @@ 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({
-33
View File
@@ -23,7 +23,6 @@ def install():
install_staticcheck()
install_helm()
install_kubectl()
install_istioctl()
install_oc3()
install_kind()
install_kustomize()
@@ -233,38 +232,6 @@ 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():
+4 -21
View File
@@ -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:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=",
version = "v0.9.4",
sum = "h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=",
version = "v0.9.1-0.20191026205805-5f8ba28d4473",
)
go_repository(
name = "com_github_envoyproxy_protoc_gen_validate",
@@ -3063,23 +3063,6 @@ 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",
@@ -3373,8 +3356,8 @@ def go_repositories():
build_file_generation = "on",
build_file_proto_mode = "disable",
importpath = "google.golang.org/grpc",
sum = "h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k=",
version = "v1.28.1",
sum = "h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=",
version = "v1.27.0",
)
go_repository(
name = "org_golang_google_grpc_examples",
+4 -5
View File
@@ -96,10 +96,9 @@ func SetIssuerCondition(i cmapi.GenericIssuer, observedGeneration int64, conditi
}
// CertificateHasCondition will return true if the given Certificate has a
// condition matching the provided CertificateCondition with a ObservedGeneration
// that is bigger or equal to the ObservedGeneration of the provided CertificateCondition.
// Only the Type, Status and ObservedGeneration field will be used in the comparison,
// meaning that this function will return 'true' even if the Reason, Message and
// condition matching the provided CertificateCondition.
// Only the Type and Status field will be used in the comparison, meaning that
// this function will return 'true' even if the Reason, Message and
// LastTransitionTime fields do not match.
func CertificateHasCondition(crt *cmapi.Certificate, c cmapi.CertificateCondition) bool {
if crt == nil {
@@ -107,7 +106,7 @@ func CertificateHasCondition(crt *cmapi.Certificate, c cmapi.CertificateConditio
}
existingConditions := crt.Status.Conditions
for _, cond := range existingConditions {
if c.Type == cond.Type && c.Status == cond.Status && c.ObservedGeneration <= cond.ObservedGeneration {
if c.Type == cond.Type && c.Status == cond.Status {
return true
}
}
-27
View File
@@ -204,14 +204,6 @@ 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 {
@@ -313,25 +305,6 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct {
Labels map[string]string `json:"labels,omitempty"`
}
type ACMEChallengeSolverHTTP01Istio struct {
// Optional service type for Kubernetes solver service
// +optional
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
// The names of the gateways that are used to generate the virtualservice
// that configures the HTTP01 challenge routes.
// `<gateway namespace>/<gateway name>`; specifying a gateway with no
// namespace qualifier is the same as specifying the VirtualService's
// namespace.
// ref: https://github.com/istio/api/blob/24c65c0415b63a6ebca18059c60fc8fccf041e9a/networking/v1beta1/virtual_service.pb.go#L233-L246
Gateways []string `json:"gateways,omitempty"`
// 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.
-31
View File
@@ -170,11 +170,6 @@ 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
}
@@ -349,32 +344,6 @@ 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.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*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
-28
View File
@@ -204,14 +204,6 @@ 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 {
@@ -313,26 +305,6 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct {
Labels map[string]string `json:"labels,omitempty"`
}
type ACMEChallengeSolverHTTP01Istio struct {
// Optional service type for Kubernetes solver service
// +optional
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
// The names of the gateways that are used to generate the virtualservice
// that configures the HTTP01 challenge routes.
// `<gateway namespace>/<gateway name>`; specifying a gateway with no
// namespace qualifier is the same as specifying the VirtualService's
// namespace.
// ref: https://github.com/istio/api/blob/24c65c0415b63a6ebca18059c60fc8fccf041e9a/networking/v1beta1/virtual_service.pb.go#L233-L246
// +optional
Gateways []string `json:"gateways,omitempty"`
// 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.
@@ -170,11 +170,6 @@ 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
}
@@ -349,32 +344,6 @@ 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.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*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
-27
View File
@@ -204,14 +204,6 @@ 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 {
@@ -313,25 +305,6 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct {
Labels map[string]string `json:"labels,omitempty"`
}
type ACMEChallengeSolverHTTP01Istio struct {
// Optional service type for Kubernetes solver service
// +optional
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
// The names of the gateways that are used to generate the virtualservice
// that configures the HTTP01 challenge routes.
// `<gateway namespace>/<gateway name>`; specifying a gateway with no
// namespace qualifier is the same as specifying the VirtualService's
// namespace.
// ref: https://github.com/istio/api/blob/24c65c0415b63a6ebca18059c60fc8fccf041e9a/networking/v1beta1/virtual_service.pb.go#L233-L246
Gateways []string `json:"gateways,omitempty"`
// 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.
@@ -170,11 +170,6 @@ 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
}
@@ -349,32 +344,6 @@ 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.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*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
-27
View File
@@ -204,14 +204,6 @@ 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 {
@@ -313,25 +305,6 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct {
Labels map[string]string `json:"labels,omitempty"`
}
type ACMEChallengeSolverHTTP01Istio struct {
// Optional service type for Kubernetes solver service
// +optional
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
// The names of the gateways that are used to generate the virtualservice
// that configures the HTTP01 challenge routes.
// `<gateway namespace>/<gateway name>`; specifying a gateway with no
// namespace qualifier is the same as specifying the VirtualService's
// namespace.
// ref: https://github.com/istio/api/blob/24c65c0415b63a6ebca18059c60fc8fccf041e9a/networking/v1beta1/virtual_service.pb.go#L233-L246
Gateways []string `json:"gateways,omitempty"`
// 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.
@@ -170,11 +170,6 @@ 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
}
@@ -349,32 +344,6 @@ 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.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*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
-3
View File
@@ -25,9 +25,6 @@ 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_apiserver//pkg/registry/generic/registry: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",
@@ -25,7 +25,6 @@ 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",
@@ -38,7 +38,6 @@ 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"
)
@@ -98,7 +97,6 @@ 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{
@@ -110,11 +108,6 @@ 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()
-10
View File
@@ -21,8 +21,6 @@ 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"
@@ -50,8 +48,6 @@ 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
@@ -60,16 +56,10 @@ 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
-3
View File
@@ -23,10 +23,7 @@ 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",
+1 -32
View File
@@ -26,11 +26,7 @@ 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"
@@ -61,7 +57,6 @@ type Builder struct {
T *testing.T
KubeObjects []runtime.Object
DynamicObjects []runtime.Object
CertManagerObjects []runtime.Object
ExpectedActions []Action
ExpectedEvents []string
@@ -103,8 +98,7 @@ const informerResyncPeriod = time.Millisecond * 10
func (b *Builder) Init() {
if b.Context == nil {
b.Context = &controller.Context{
RootContext: context.Background(),
IstioEnabled: true,
RootContext: context.Background(),
}
}
if b.StringGenerator == nil {
@@ -112,15 +106,12 @@ 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)
@@ -144,14 +135,6 @@ 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)
}
@@ -286,7 +269,6 @@ 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()
@@ -296,9 +278,6 @@ 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())
}
@@ -325,16 +304,6 @@ 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 {
-27
View File
@@ -186,14 +186,6 @@ 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 {
@@ -280,25 +272,6 @@ type ACMEChallengeSolverHTTP01IngressObjectMeta struct {
Labels map[string]string
}
type ACMEChallengeSolverHTTP01Istio struct {
// Optional service type for Kubernetes solver service
// +optional
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
// The names of the gateways that are used to generate the virtualservice
// that configures the HTTP01 challenge routes.
// `<gateway namespace>/<gateway name>`; specifying a gateway with no
// namespace qualifier is the same as specifying the VirtualService's
// namespace.
// ref: https://github.com/istio/api/blob/24c65c0415b63a6ebca18059c60fc8fccf041e9a/networking/v1beta1/virtual_service.pb.go#L233-L246
Gateways []string `json:"gateways,omitempty"`
// 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.
@@ -151,16 +151,6 @@ 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 {
@@ -490,7 +480,6 @@ 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
}
@@ -501,7 +490,6 @@ 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
}
@@ -664,30 +652,6 @@ 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.ServiceType = corev1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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.ServiceType = corev1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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?
@@ -151,16 +151,6 @@ 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 {
@@ -490,7 +480,6 @@ 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
}
@@ -501,7 +490,6 @@ 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
}
@@ -664,30 +652,6 @@ 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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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?
@@ -151,16 +151,6 @@ 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 {
@@ -490,7 +480,6 @@ 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
}
@@ -501,7 +490,6 @@ 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
}
@@ -664,30 +652,6 @@ 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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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?
@@ -151,16 +151,6 @@ 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 {
@@ -490,7 +480,6 @@ 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
}
@@ -501,7 +490,6 @@ 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
}
@@ -664,30 +652,6 @@ 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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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.ServiceType = v1.ServiceType(in.ServiceType)
out.Gateways = *(*[]string)(unsafe.Pointer(&in.Gateways))
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?
@@ -170,11 +170,6 @@ 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
}
@@ -349,32 +344,6 @@ 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.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*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
@@ -164,12 +164,8 @@ func ValidateACMEIssuerChallengeSolverHTTP01Config(http01 *cmacme.ACMEChallengeS
numDefined++
el = append(el, ValidateACMEIssuerChallengeSolverHTTP01IngressConfig(http01.Ingress, fldPath.Child("ingress"))...)
}
if http01.Istio != nil {
numDefined++
el = append(el, ValidateACMEIssuerChallengeSolverHTTP01IstioConfig(http01.Istio, fldPath.Child("istio"))...)
}
if numDefined != 1 {
el = append(el, field.Required(fldPath, "exactly 1 HTTP01 solver type must be configured"))
if numDefined == 0 {
el = append(el, field.Required(fldPath, "no HTTP01 solver type configured"))
}
return el
@@ -190,18 +186,6 @@ func ValidateACMEIssuerChallengeSolverHTTP01IngressConfig(ingress *cmacme.ACMECh
return el
}
func ValidateACMEIssuerChallengeSolverHTTP01IstioConfig(ingress *cmacme.ACMEChallengeSolverHTTP01Istio, fldPath *field.Path) field.ErrorList {
el := field.ErrorList{}
switch ingress.ServiceType {
case "", corev1.ServiceTypeClusterIP, corev1.ServiceTypeNodePort:
default:
el = append(el, field.Invalid(fldPath.Child("serviceType"), ingress.ServiceType, `must be empty, "ClusterIP" or "NodePort"`))
}
return el
}
func ValidateCAIssuerConfig(iss *certmanager.CAIssuer, fldPath *field.Path) field.ErrorList {
el := field.ErrorList{}
if len(iss.SecretName) == 0 {
@@ -219,7 +219,7 @@ func TestValidateACMEIssuerConfig(t *testing.T) {
},
},
errs: []*field.Error{
field.Required(fldPath.Child("solvers").Index(0).Child("http01"), "exactly 1 HTTP01 solver type must be configured"),
field.Required(fldPath.Child("solvers").Index(0).Child("http01"), "no HTTP01 solver type configured"),
},
},
"acme solver with valid http01 config": {
@@ -465,7 +465,7 @@ func TestValidateACMEIssuerHTTP01Config(t *testing.T) {
"no solver config type specified": {
cfg: &cmacme.ACMEChallengeSolverHTTP01{},
errs: []*field.Error{
field.Required(fldPath, "exactly 1 HTTP01 solver type must be configured"),
field.Required(fldPath, "no HTTP01 solver type configured"),
},
},
"both fields specified": {
-7
View File
@@ -5,7 +5,6 @@ go_library(
srcs = [
"http.go",
"ingress.go",
"istio.go",
"pod.go",
"service.go",
],
@@ -15,11 +14,9 @@ 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",
@@ -28,7 +25,6 @@ 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",
@@ -40,7 +36,6 @@ go_test(
srcs = [
"http_test.go",
"ingress_test.go",
"istio_test.go",
"pod_test.go",
"service_test.go",
"util_test.go",
@@ -49,7 +44,6 @@ 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",
@@ -74,7 +68,6 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/issuer/acme/http/internal/istio:all-srcs",
"//pkg/issuer/acme/http/solver:all-srcs",
],
tags = ["automanaged"],
+14 -56
View File
@@ -19,7 +19,6 @@ package http
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io/ioutil"
"net"
@@ -30,16 +29,13 @@ 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"
@@ -61,10 +57,9 @@ var (
type Solver struct {
*controller.Context
podLister corev1listers.PodLister
serviceLister corev1listers.ServiceLister
ingressLister networkingv1beta1listers.IngressLister
virtualServiceLister dynamiclister.Lister
podLister corev1listers.PodLister
serviceLister corev1listers.ServiceLister
ingressLister networkingv1beta1listers.IngressLister
testReachability reachabilityTest
requiredPasses int
@@ -75,47 +70,28 @@ 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 {
solver := Solver{
Context: ctx,
podLister: ctx.KubeSharedInformerFactory.Core().V1().Pods().Lister(),
serviceLister: ctx.KubeSharedInformerFactory.Core().V1().Services().Lister(),
ingressLister: ctx.KubeSharedInformerFactory.Networking().V1beta1().Ingresses().Lister(),
virtualServiceLister: nil,
testReachability: testReachability,
requiredPasses: 5,
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,
}
if ctx.IstioEnabled {
dynamicInformer := ctx.DynamicSharedInformerFactory.ForResource(istio.VirtualServiceGvr())
solver.virtualServiceLister = dynamiclister.New(dynamicInformer.Informer().GetIndexer(), istio.VirtualServiceGvr())
}
return &solver
}
func http01LogCtx(ctx context.Context) context.Context {
return logf.NewContext(ctx, nil, "http01")
}
func httpIngressForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) {
func httpDomainCfgForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) {
if ch.Spec.Solver.HTTP01 == nil || ch.Spec.Solver.HTTP01.Ingress == nil {
return nil, errors.New("challenge's 'solver' field is specified but no HTTP01 ingress config provided. " +
return nil, fmt.Errorf("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 ch.Spec.Solver.HTTP01.Istio.ServiceType, 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).
@@ -127,23 +103,8 @@ func (s *Solver) Present(ctx context.Context, issuer v1.GenericIssuer, ch *cmacm
if svcErr != nil {
return utilerrors.NewAggregate([]error{podErr, svcErr})
}
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 {
// TODO: add support for dynamic Istio support detection (start / stop the VirtualService lister as necessary)
istioErr = errors.New("Istio support was not detected on startup, try restarting cert-manager")
}
}
return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr, istioErr})
_, ingressErr := s.ensureIngress(ctx, ch, svc.Name)
return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr})
}
func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
@@ -192,9 +153,6 @@ 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))
if s.IstioEnabled {
errs = append(errs, s.cleanupVirtualServices(ctx, ch))
}
return utilerrors.NewAggregate(errs)
}
+4 -9
View File
@@ -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 := httpIngressForChallenge(ch)
httpDomainCfg, err := httpDomainCfgForChallenge(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 := httpIngressForChallenge(ch)
httpDomainCfg, err := httpDomainCfgForChallenge(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 := httpIngressForChallenge(ch)
httpDomainCfg, err := httpDomainCfgForChallenge(ch)
if err != nil {
return nil, err
}
@@ -265,12 +265,7 @@ 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")
// 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)
httpDomainCfg, err := httpDomainCfgForChallenge(ch)
if err != nil {
return err
}
@@ -1,33 +0,0 @@
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"],
)
@@ -1,76 +0,0 @@
/*
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.
// Based on: https://github.com/istio/client-go/blob/4c970a7c677150c96c4381118821b36c52e4c7b7/pkg/apis/networking/v1beta1/types.gen.go#L249-L269
// TODO: remove this file in favour of Istio API types without client-go dependency https://github.com/istio/api/issues/1959
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
}
@@ -1,88 +0,0 @@
/*
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.
// Based on: https://github.com/istio/client-go/blob/4c970a7c677150c96c4381118821b36c52e4c7b7/pkg/apis/networking/v1beta1/zz_generated.deepcopy.gen.go#L269-L328
// TODO: remove this file in favour of Istio API types without client-go dependency https://github.com/istio/api/issues/1959
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
}
-175
View File
@@ -1,175 +0,0 @@
/*
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: http01Istio.Gateways,
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},
},
},
},
},
},
}
}
-181
View File
@@ -1,181 +0,0 @@
/*
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"
"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{
Gateways: []string{fmt.Sprintf("%s/test-gateway", defaultTestNamespace)},
},
},
},
},
}
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)
})
}
}
+4 -6
View File
@@ -144,12 +144,10 @@ 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 {
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)
}
if ch.Spec.Solver.HTTP01 != nil &&
ch.Spec.Solver.HTTP01.Ingress != nil {
pod = s.mergePodObjectMetaWithPodTemplate(pod,
ch.Spec.Solver.HTTP01.Ingress.PodTemplate)
}
return pod
+3 -3
View File
@@ -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)
serviceType, err := serviceTypeForChallenge(ch)
httpDomainCfg, err := httpDomainCfgForChallenge(ch)
if err != nil {
return nil, err
}
if serviceType != "" {
service.Spec.Type = serviceType
if httpDomainCfg.ServiceType != "" {
service.Spec.Type = httpDomainCfg.ServiceType
}
return service, nil
-1
View File
@@ -11,7 +11,6 @@ go_library(
"ginkgo.go",
"helm.go",
"ingress_controller.go",
"istio.go",
"samplewebhook.go",
"suite.go",
"tiller.go",
+1 -3
View File
@@ -24,14 +24,12 @@ 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 Ingress challenges")
fs.StringVar(&p.IstioIP, "acme-istio-ip", "10.0.0.14", "IP of the ingress server that solves HTTP01 ACME Istio challenges")
fs.StringVar(&p.IngressIP, "acme-ingress-ip", "10.0.0.15", "IP of the ingress server that solves HTTP01 ACME challenges")
}
func (p *ACMEServer) Validate() []error {
+1 -7
View File
@@ -33,13 +33,9 @@ type Addons struct {
ACMEServer ACMEServer
// IngressController contains configuration for the ingress controller
// being used during ACME HTTP01 Ingress tests.
// being used during ACME HTTP01 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
@@ -56,7 +52,6 @@ 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)
@@ -68,7 +63,6 @@ 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()...)
-41
View File
@@ -1,41 +0,0 @@
/*
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
// Gateway is the name of the gateway resource used for the HTTP01 ACME validation tests.
Gateway 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.Gateway, "istio-gateway", "istio-system/ingress", "The name of the gateway resource used for the HTTP01 ACME validation tests.")
}
func (n *Istio) Validate() []error {
return nil
}
-1
View File
@@ -25,7 +25,6 @@ go_library(
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/framework/helper/validations:go_default_library",
"//test/e2e/framework/log:go_default_library",
"//test/e2e/util:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
+49 -21
View File
@@ -28,6 +28,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
@@ -35,35 +36,62 @@ import (
"github.com/jetstack/cert-manager/pkg/util"
"github.com/jetstack/cert-manager/pkg/util/pki"
"github.com/jetstack/cert-manager/test/e2e/framework/log"
e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
)
// WaitForCertificateReady waits for the certificate resource to enter a Ready
// state.
func (h *Helper) WaitForCertificateReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
return e2eutil.WaitForCertificateCondition(h.CMClient.CertmanagerV1().Certificates(ns), name, cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionTrue,
}, timeout)
var certificate *cmapi.Certificate
err := wait.PollImmediate(time.Second, timeout,
func() (bool, error) {
var err error
log.Logf("Waiting for Certificate %v to be ready", name)
certificate, err = h.CMClient.CertmanagerV1().Certificates(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
}
isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionTrue,
})
if !isReady {
log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
return false, nil
}
return true, nil
},
)
// return certificate even when error to use for debugging
return certificate, err
}
// WaitForCertificateReadyUpdate waits for the certificate resource to enter a Ready
// state. If the provided cert was in a Ready state already, the function waits for a state transition to have happened.
func (h *Helper) WaitForCertificateReadyUpdate(cert *cmapi.Certificate, timeout time.Duration) (*cmapi.Certificate, error) {
return e2eutil.WaitForCertificateCondition(h.CMClient.CertmanagerV1().Certificates(cert.Namespace), cert.Name, cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionTrue,
ObservedGeneration: cert.Generation,
}, timeout)
}
// WaitForCertificateNotReady waits for the certificate resource to enter a
// non-Ready state.
func (h *Helper) WaitForCertificateNotReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
var certificate *cmapi.Certificate
err := wait.PollImmediate(time.Second, timeout,
func() (bool, error) {
var err error
log.Logf("Waiting for Certificate %v to be ready", name)
certificate, err = h.CMClient.CertmanagerV1().Certificates(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
}
isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionFalse,
})
if !isReady {
log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
return false, nil
}
return true, nil
},
)
// WaitForCertificateNotReady waits for the certificate resource to enter a Ready False state.
func (h *Helper) WaitForCertificateNotReadyUpdate(cert *cmapi.Certificate, timeout time.Duration) (*cmapi.Certificate, error) {
return e2eutil.WaitForCertificateCondition(h.CMClient.CertmanagerV1().Certificates(cert.Namespace), cert.Name, cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionFalse,
ObservedGeneration: cert.Generation,
}, timeout)
// return certificate even when error to use for debugging
return certificate, err
}
// ValidateIssuedCertificate will ensure that the given Certificate has a
@@ -127,10 +127,6 @@ const (
// with only SANs set
OnlySAN = "OnlySAN"
// OnlyValidACMEDNSName denotes whether the target issuer checks the
// requested DNS Name to be a valid ACME DNS Name
OnlyValidACMEDNSName = "OnlyValidACMEDNSName"
// SaveCAToSecret denotes whether the target issuer returns a CA
// certificate which can be stored in the ca.crt field of the Secret.
SaveCAToSecret = "SaveCAToSecret"
-26
View File
@@ -18,8 +18,6 @@ package helper
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"time"
@@ -59,27 +57,3 @@ 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
}
@@ -17,7 +17,6 @@ go_library(
"//test/e2e/framework/helper:go_default_library",
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/framework/helper/validations:go_default_library",
"//test/e2e/framework/matcher:go_default_library",
"//test/e2e/util:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
@@ -47,6 +47,7 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
// unsupportedHTTP01Features is a list of features that are not supported by the ACME
// issuer type using HTTP01
var unsupportedHTTP01Features = featureset.NewFeatureSet(
featureset.IPAddressFeature,
featureset.DurationFeature,
featureset.WildcardsFeature,
featureset.URISANsFeature,
@@ -78,22 +79,11 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
(&certificates.Suite{
Name: "ACME HTTP01 Issuer",
IPAddressType: certificates.IngressIPAddressType,
DomainSuffixType: certificates.IngressDomainSuffixType,
CreateIssuerFunc: provisionerHTTP01.createHTTP01Issuer,
DeleteIssuerFunc: provisionerHTTP01.delete,
UnsupportedFeatures: unsupportedHTTP01Features,
}).Define()
(&certificates.Suite{
Name: "ACME HTTP01 Issuer on Istio",
IPAddressType: certificates.IstioIPAddressType,
DomainSuffixType: certificates.IstioDomainSuffixType,
CreateIssuerFunc: provisionerHTTP01.createHTTP01IssuerOnIstio,
DeleteIssuerFunc: provisionerHTTP01.delete,
UnsupportedFeatures: unsupportedHTTP01Features,
}).Define()
(&certificates.Suite{
Name: "ACME DNS01 Issuer",
DomainSuffix: "dns01.example.com",
@@ -104,8 +94,6 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
(&certificates.Suite{
Name: "ACME HTTP01 ClusterIssuer",
IPAddressType: certificates.IngressIPAddressType,
DomainSuffixType: certificates.IngressDomainSuffixType,
CreateIssuerFunc: provisionerHTTP01.createHTTP01ClusterIssuer,
DeleteIssuerFunc: provisionerHTTP01.delete,
UnsupportedFeatures: unsupportedHTTP01Features,
@@ -164,27 +152,6 @@ 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)
@@ -233,34 +200,6 @@ func (a *acmeIssuerProvisioner) createHTTP01IssuerSpec(serverURL string) cmapi.I
}
}
func (a *acmeIssuerProvisioner) createHTTP01IssuerOnIstioSpec(serverURL string) cmapi.IssuerSpec {
const TestGateway = "istio-system/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{
Gateways: []string{TestGateway},
},
},
},
},
},
},
}
}
func (a *acmeIssuerProvisioner) createDNS01Issuer(f *framework.Framework) cmmeta.ObjectReference {
a.ensureEABSecret(f, f.Namespace.Name)
@@ -9,7 +9,6 @@ go_library(
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/suite/conformance/certificates:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
@@ -27,28 +27,21 @@ import (
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"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/suite/conformance/certificates"
)
var _ = framework.ConformanceDescribe("Certificates", func() {
var unsupportedFeatures = featureset.NewFeatureSet(
featureset.OnlyValidACMEDNSName,
)
caIssuer := new(ca)
(&certificates.Suite{
Name: "CA Issuer",
CreateIssuerFunc: caIssuer.createCAIssuer,
UnsupportedFeatures: unsupportedFeatures,
Name: "CA Issuer",
CreateIssuerFunc: caIssuer.createCAIssuer,
}).Define()
caClusterIssuer := new(ca)
(&certificates.Suite{
Name: "CA ClusterIssuer",
CreateIssuerFunc: caClusterIssuer.createCAClusterIssuer,
DeleteIssuerFunc: caClusterIssuer.deleteCAClusterIssuer,
UnsupportedFeatures: unsupportedFeatures,
Name: "CA ClusterIssuer",
CreateIssuerFunc: caClusterIssuer.createCAClusterIssuer,
DeleteIssuerFunc: caClusterIssuer.deleteCAClusterIssuer,
}).Define()
})
@@ -43,7 +43,6 @@ var _ = framework.ConformanceDescribe("Certificates", func() {
featureset.DurationFeature,
featureset.KeyUsagesFeature,
featureset.SaveCAToSecret,
featureset.OnlyValidACMEDNSName,
)
issuerBuilder := newIssuerBuilder("Issuer")
@@ -9,7 +9,6 @@ go_library(
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/suite/conformance/certificates:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
@@ -26,26 +26,19 @@ import (
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"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/suite/conformance/certificates"
)
var _ = framework.ConformanceDescribe("Certificates", func() {
var unsupportedFeatures = featureset.NewFeatureSet(
featureset.OnlyValidACMEDNSName,
)
(&certificates.Suite{
Name: "SelfSigned Issuer",
CreateIssuerFunc: createSelfSignedIssuer,
UnsupportedFeatures: unsupportedFeatures,
Name: "SelfSigned Issuer",
CreateIssuerFunc: createSelfSignedIssuer,
}).Define()
(&certificates.Suite{
Name: "SelfSigned ClusterIssuer",
CreateIssuerFunc: createSelfSignedClusterIssuer,
DeleteIssuerFunc: deleteSelfSignedClusterIssuer,
UnsupportedFeatures: unsupportedFeatures,
Name: "SelfSigned ClusterIssuer",
CreateIssuerFunc: createSelfSignedClusterIssuer,
DeleteIssuerFunc: deleteSelfSignedClusterIssuer,
}).Define()
})
@@ -28,14 +28,6 @@ import (
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
)
const (
IstioDomainSuffixType = "istio"
IngressDomainSuffixType = "ingress"
IstioIPAddressType = "istio"
IngressIPAddressType = "ingress"
)
// Suite defines a reusable conformance test suite that can be used against any
// Issuer implementation.
type Suite struct {
@@ -64,21 +56,6 @@ 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
// IPAddress is an IP used on all IPAddress requests.
// This is useful when the issuer being tested requires special
// configuration for a set of IPAddresses in order for certificates to be
// issued, such as the ACME issuer.
// If not set, this will be defaulted to "127.0.0.1".
IPAddress string
// IPAddressType is a string used to detect what IPAddress to use
// in case IPAddress is left empty.
IPAddressType 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
@@ -91,36 +68,12 @@ type Suite struct {
// complete will validate configuration and set default values.
func (s *Suite) complete(f *framework.Framework) {
if s.Name == "" {
Fail("Name must be set")
}
if s.CreateIssuerFunc == nil {
Fail("CreateIssuerFunc must be set")
}
// 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.DomainSuffix == "" {
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.IPAddress == "" {
switch s.IPAddressType {
case IngressIPAddressType:
s.IPAddress = f.Config.Addons.ACMEServer.IngressIP
case IstioIPAddressType:
s.IPAddress = f.Config.Addons.ACMEServer.IstioIP
case "":
s.IPAddress = "127.0.0.1"
default:
Fail("IPAddress type not recognised")
}
s.DomainSuffix = f.Config.Addons.IngressController.Domain
}
if s.UnsupportedFeatures == nil {
@@ -185,7 +138,3 @@ 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)
}
@@ -32,7 +32,6 @@ import (
"github.com/jetstack/cert-manager/pkg/util/pki"
"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/matcher"
e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -80,31 +79,6 @@ func (s *Suite) Define() {
Expect(err).NotTo(HaveOccurred())
}, featureset.OnlySAN)
s.it(f, "should issue a basic, defaulted certificate for a single distinct DNS subsubdomain", func(issuerRef cmmeta.ObjectReference) {
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
IssuerRef: issuerRef,
DNSNames: []string{s.newDomainDepth(2)},
},
}
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", f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...)
Expect(err).NotTo(HaveOccurred())
}, featureset.OnlySAN)
s.it(f, "should issue an ECDSA, defaulted certificate for a single distinct dnsName", func(issuerRef cmmeta.ObjectReference) {
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
@@ -207,7 +181,7 @@ func (s *Suite) Define() {
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
CommonName: cn,
IPAddresses: []string{s.IPAddress},
IPAddresses: []string{"127.0.0.1"},
IssuerRef: issuerRef,
},
}
@@ -224,59 +198,6 @@ func (s *Suite) Define() {
Expect(err).NotTo(HaveOccurred())
}, featureset.CommonNameFeature, featureset.IPAddressFeature)
s.it(f, "should issue a certificate that defines an IP Address", func(issuerRef cmmeta.ObjectReference) {
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
IPAddresses: []string{s.IPAddress},
IssuerRef: issuerRef,
},
}
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", f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...)
Expect(err).NotTo(HaveOccurred())
}, featureset.IPAddressFeature)
s.it(f, "should issue a certificate that defines an IP Address and a DNS Name", func(issuerRef cmmeta.ObjectReference) {
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
IPAddresses: []string{s.IPAddress},
IssuerRef: issuerRef,
DNSNames: []string{
s.newDomain(),
},
},
}
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", f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...)
Expect(err).NotTo(HaveOccurred())
}, featureset.IPAddressFeature, featureset.OnlySAN)
s.it(f, "should issue a certificate that defines an Email Address", func(issuerRef cmmeta.ObjectReference) {
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
@@ -345,8 +266,7 @@ func (s *Suite) Define() {
},
}
testCertificate.Spec.DNSNames = []string{
testCertificate.Spec.CommonName,
s.newDomain(),
testCertificate.Spec.CommonName, s.newDomain(),
}
By("Creating a Certificate")
@@ -433,33 +353,7 @@ func (s *Suite) Define() {
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
IssuerRef: issuerRef,
DNSNames: []string{"*." + s.newDomain()},
},
}
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", f.Helper().ValidationSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...)
Expect(err).NotTo(HaveOccurred())
}, featureset.WildcardsFeature, featureset.OnlySAN)
s.it(f, "should issue a certificate which has a wildcard DNS name and apex domain defined", func(issuerRef cmmeta.ObjectReference) {
apexDomain := s.newDomain()
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
IssuerRef: issuerRef,
DNSNames: []string{"*." + apexDomain, apexDomain},
DNSNames: []string{"foo." + s.newDomain()},
},
}
By("Creating a Certificate")
@@ -680,149 +574,5 @@ 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 Ready condition to be updated")
_, err = f.Helper().WaitForCertificateReadyUpdate(cert, 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)
s.it(f, "should fail to obtain a certificate for an invalid ACME 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{"google.com"},
IssuerRef: issuerRef,
},
}
By("Creating a Certificate")
err := f.CRClient.Create(ctx, testCertificate)
Expect(err).NotTo(HaveOccurred())
notReadyCondition := cmapi.CertificateCondition{
Type: cmapi.CertificateConditionReady,
Status: cmmeta.ConditionFalse,
}
Eventually(testCertificate, "30s", "1s").Should(HaveCondition(f, notReadyCondition))
Consistently(testCertificate, "1m", "10s").Should(HaveCondition(f, notReadyCondition))
}, featureset.OnlySAN, featureset.OnlyValidACMEDNSName)
s.it(f, "should allow updating the dns name of a failing certificate that had an incorrect 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{"google.com"},
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 not ready")
_, err = f.Helper().WaitForCertificateNotReadyUpdate(testCertificate, 30*time.Second)
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("Replacing DNS Names with a valid DNS Name")
cert.Spec.DNSNames = []string{s.newDomain()}
By("Updating the Certificate in the apiserver")
err = f.CRClient.Update(context.TODO(), cert)
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to have the Ready=True condition")
_, err = f.Helper().WaitForCertificateReadyUpdate(cert, 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, featureset.OnlyValidACMEDNSName)
})
}
@@ -44,7 +44,6 @@ var _ = framework.ConformanceDescribe("Certificates", func() {
var unsupportedFeatures = featureset.NewFeatureSet(
featureset.KeyUsagesFeature,
featureset.SaveRootCAToSecret,
featureset.OnlyValidACMEDNSName,
)
provisioner := new(vaultAppRoleProvisioner)
@@ -49,7 +49,6 @@ var _ = framework.ConformanceDescribe("Certificates", func() {
featureset.IPAddressFeature,
// Venafi doesn't allow certs with empty CN & DN
featureset.OnlySAN,
featureset.OnlyValidACMEDNSName,
)
provisioner := new(venafiProvisioner)
@@ -46,7 +46,6 @@ var _ = framework.ConformanceDescribe("[Feature:Issuers:Venafi:Cloud] Certificat
featureset.URISANsFeature,
// Venafi doesn't allow certs with empty CN & DN
featureset.OnlySAN,
featureset.OnlyValidACMEDNSName,
)
provisioner := new(venafiProvisioner)
+2
View File
@@ -16,6 +16,7 @@ go_library(
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/suite/issuers/acme/certificate:go_default_library",
"//test/e2e/suite/issuers/acme/certificaterequest:go_default_library",
"//test/e2e/util:go_default_library",
"//test/unit/gen:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
@@ -37,6 +38,7 @@ filegroup(
srcs = [
":package-srcs",
"//test/e2e/suite/issuers/acme/certificate:all-srcs",
"//test/e2e/suite/issuers/acme/certificaterequest:all-srcs",
"//test/e2e/suite/issuers/acme/dnsproviders:all-srcs",
],
tags = ["automanaged"],
@@ -3,8 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"http01_ingress.go",
"http01_istio.go",
"dns01.go",
"http01.go",
"notafter.go",
"webhook.go",
],
@@ -16,11 +16,15 @@ go_library(
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/client/clientset/versioned:go_default_library",
"//pkg/util:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon:go_default_library",
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/framework/log:go_default_library",
"//test/e2e/framework/matcher:go_default_library",
"//test/e2e/framework/util:go_default_library",
"//test/e2e/suite/issuers/acme/dnsproviders:go_default_library",
"//test/e2e/util:go_default_library",
"//test/unit/gen:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
@@ -0,0 +1,190 @@
/*
Copyright 2020 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"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
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"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/addon"
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
"github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/dnsproviders"
"github.com/jetstack/cert-manager/test/e2e/util"
"github.com/jetstack/cert-manager/test/unit/gen"
)
type dns01Provider interface {
Details() *dnsproviders.Details
addon.Addon
}
var _ = framework.CertManagerDescribe("ACME Certificate (DNS01)", func() {
// TODO: add better logic to handle other DNS providers
testRFC2136DNSProvider()
})
func testRFC2136DNSProvider() bool {
name := "rfc2136"
return Context("With "+name+" credentials configured", func() {
f := framework.NewDefaultFramework("create-acme-certificate-dns01-" + name)
issuerName := "test-acme-issuer"
certificateName := "test-acme-certificate"
certificateSecretName := "test-acme-certificate"
p := &dnsproviders.RFC2136{}
f.RequireAddon(p)
dnsDomain := ""
// 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() {
By("Creating an Issuer")
dnsDomain = p.Details().NewTestDomain()
issuer := gen.Issuer(issuerName,
gen.SetIssuerACME(cmacme.ACMEIssuer{
SkipTLSVerify: true,
Server: f.Config.Addons.ACMEServer.URL,
Email: testingACMEEmail,
PrivateKey: cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: testingACMEPrivateKey,
},
},
Solvers: []cmacme.ACMEChallengeSolver{
{
DNS01: &p.Details().ProviderConfig,
},
},
}))
issuer.Namespace = f.Namespace.Name
issuer, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, 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))
}
})
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{})
f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), certificateSecretName, metav1.DeleteOptions{})
})
It("should obtain a signed certificate for a regular domain", func() {
By("Creating a Certificate")
certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name)
cert := gen.Certificate(certificateName,
gen.SetCertificateSecretName(certificateSecretName),
gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
gen.SetCertificateDNSNames(dnsDomain),
)
cert.Namespace = f.Namespace.Name
cert, 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 for a wildcard domain", func() {
By("Creating a Certificate")
cert := gen.Certificate(certificateName,
gen.SetCertificateSecretName(certificateSecretName),
gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
gen.SetCertificateDNSNames("*."+dnsDomain),
)
cert.Namespace = f.Namespace.Name
cert, err := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name).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 for a wildcard and apex domain", func() {
By("Creating a Certificate")
cert := gen.Certificate(certificateName,
gen.SetCertificateSecretName(certificateSecretName),
gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
gen.SetCertificateDNSNames("*."+dnsDomain, dnsDomain),
)
cert.Namespace = f.Namespace.Name
cert, err := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name).Create(context.TODO(), cert, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
// use a longer timeout for this, as it requires performing 2 dns validations in serial
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*10)
Expect(err).NotTo(HaveOccurred())
By("Validating the issued Certificate...")
err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName, validations...)
Expect(err).NotTo(HaveOccurred())
})
})
}
@@ -0,0 +1,677 @@
/*
Copyright 2020 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/tls"
"crypto/x509"
"fmt"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"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 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 acmeIngressDomain string
issuerName := "test-acme-issuer"
certificateName := "test-acme-certificate"
certificateSecretName := "test-acme-certificate"
// fixedIngressName is the name of an ingress resource that is configured
// with a challenge solve.
// To utilise this solver, add the 'testing.cert-manager.io/fixed-ingress: "true"' label.
fixedIngressName := "testingress"
// 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{
Ingress: &cmacme.ACMEChallengeSolverHTTP01Ingress{
Class: &f.Config.Addons.IngressController.IngressClass,
},
},
},
{
Selector: &cmacme.CertificateDNSNameSelector{
MatchLabels: map[string]string{
"testing.cert-manager.io/fixed-ingress": "true",
},
},
HTTP01: &cmacme.ACMEChallengeSolverHTTP01{
Ingress: &cmacme.ACMEChallengeSolverHTTP01Ingress{
Name: fixedIngressName,
},
},
},
}
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.IngressController.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() {
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 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)
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 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)
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 = h.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 := findDNSNames(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 obtain a signed certificate with a single CN from the ACME server when putting an annotation on an ingress resource", func() {
ingClient := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace.Name)
certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name)
By("Creating an Ingress with the issuer name annotation set")
_, err := ingClient.Create(context.TODO(), util.NewIngress(certificateSecretName, certificateSecretName, map[string]string{
"cert-manager.io/issuer": issuerName,
}, acmeIngressDomain), metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for Certificate to exist")
err = util.WaitForCertificateToExist(certClient, certificateSecretName, foreverTestTimeout)
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 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,
// but I haven't been able to make this happen. Create a TLS cert via
// the self-sign issuer to make it have a "proper" TLS cert
// TODO: investigate if we still need to use the self-signed issuer here
issuer := gen.Issuer("selfsign",
gen.SetIssuerNamespace(f.Namespace.Name),
gen.SetIssuerSelfSigned(v1.SelfSignedIssuer{}))
_, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for (selfsign) 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())
const dummycert = "dummy-tls"
const secretname = "dummy-tls-secret"
selfcert := util.NewCertManagerBasicCertificate("dummy-tls", secretname, "selfsign", v1.IssuerKind, nil, nil, acmeIngressDomain)
_, err = certClient.Create(context.TODO(), selfcert, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssued(f.Namespace.Name, dummycert, time.Minute*5)
Expect(err).NotTo(HaveOccurred())
By("Validating the issued Certificate...")
err = f.Helper().ValidateCertificate(f.Namespace.Name, dummycert, validations...)
Expect(err).NotTo(HaveOccurred())
// create an ingress that points at nothing, but has the TLS redirect annotation set
// using the TLS secret that we just got from the self-sign
ingress := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace.Name)
_, err = ingress.Create(context.TODO(), &networkingv1beta1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: fixedIngressName,
Annotations: map[string]string{
"nginx.ingress.kubernetes.io/force-ssl-redirect": "true",
"kubernetes.io/ingress.class": "nginx",
},
},
Spec: networkingv1beta1.IngressSpec{
TLS: []networkingv1beta1.IngressTLS{
{
Hosts: []string{acmeIngressDomain},
SecretName: secretname,
},
},
Rules: []networkingv1beta1.IngressRule{
{
Host: acmeIngressDomain,
IngressRuleValue: networkingv1beta1.IngressRuleValue{
HTTP: &networkingv1beta1.HTTPIngressRuleValue{
Paths: []networkingv1beta1.HTTPIngressPath{
{
Path: "/",
Backend: networkingv1beta1.IngressBackend{
ServiceName: "doesnotexist",
ServicePort: intstr.FromInt(443),
},
},
},
},
},
},
},
},
}, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Creating a Certificate")
// This is a special cert for the test suite, where we specify an ingress rather than a
// class
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
cert.Labels = map[string]string{
"testing.cert-manager.io/fixed-ingress": "true",
}
_, 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 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.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 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
}
@@ -1,167 +0,0 @@
/*
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"
"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"
"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"
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{
Gateways: []string{f.Config.Addons.Istio.Gateway},
},
},
},
}
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 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())
})
})
@@ -0,0 +1,44 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"dns01.go",
"http01.go",
],
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/certificaterequest",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/acme/v1:go_default_library",
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/util:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon:go_default_library",
"//test/e2e/framework/log:go_default_library",
"//test/e2e/framework/matcher:go_default_library",
"//test/e2e/framework/util:go_default_library",
"//test/e2e/suite/issuers/acme/dnsproviders:go_default_library",
"//test/e2e/util:go_default_library",
"//test/unit/gen:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_apimachinery//pkg/util/wait: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"],
)
@@ -0,0 +1,160 @@
/*
Copyright 2020 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"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
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"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/addon"
"github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/dnsproviders"
"github.com/jetstack/cert-manager/test/e2e/util"
"github.com/jetstack/cert-manager/test/unit/gen"
)
type dns01Provider interface {
Details() *dnsproviders.Details
addon.Addon
}
const testingACMEEmail = "e2e@cert-manager.io"
const testingACMEPrivateKey = "test-acme-private-key"
var _ = framework.CertManagerDescribe("ACME CertificateRequest (DNS01)", func() {
// TODO: add better logic to handle other DNS providers
testRFC2136DNSProvider()
})
func testRFC2136DNSProvider() bool {
name := "rfc2136"
return Context("With "+name+" credentials configured", func() {
f := framework.NewDefaultFramework("create-acme-certificate-request-dns01-" + name)
h := f.Helper()
issuerName := "test-acme-issuer"
certificateRequestName := "test-acme-certificate-request"
dnsDomain := ""
p := &dnsproviders.RFC2136{}
f.RequireAddon(p)
BeforeEach(func() {
By("Creating an Issuer")
dnsDomain = p.Details().NewTestDomain()
issuer := gen.Issuer(issuerName,
gen.SetIssuerACME(cmacme.ACMEIssuer{
SkipTLSVerify: true,
Server: f.Config.Addons.ACMEServer.URL,
Email: testingACMEEmail,
PrivateKey: cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: testingACMEPrivateKey,
},
},
Solvers: []cmacme.ACMEChallengeSolver{
{
DNS01: &p.Details().ProviderConfig,
},
},
}))
issuer.Namespace = f.Namespace.Name
issuer, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, 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))
}
})
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 for a regular domain", func() {
By("Creating a CertificateRequest")
crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name)
cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
[]string{dnsDomain}, nil, nil, x509.RSA)
Expect(err).NotTo(HaveOccurred())
cr, 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 for a wildcard domain", func() {
By("Creating a CertificateRequest")
cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
[]string{"*." + dnsDomain}, 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())
err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key)
Expect(err).NotTo(HaveOccurred())
})
It("should obtain a signed certificate for a wildcard and apex domain", func() {
By("Creating a CertificateRequest")
cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
[]string{"*." + dnsDomain, dnsDomain}, 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())
// use a longer timeout for this, as it requires performing 2 dns validations in serial
err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*10, key)
Expect(err).NotTo(HaveOccurred())
})
})
}
@@ -18,49 +18,41 @@ package certificate
import (
"context"
"crypto/x509"
"fmt"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"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 testingACMEEmail = "e2e@cert-manager.io"
const testingACMEPrivateKey = "test-acme-private-key"
const foreverTestTimeout = time.Second * 60
var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01) Ingress", func() {
f := framework.NewDefaultFramework("create-acme-certificate-http01-ingress")
var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01)", func() {
f := framework.NewDefaultFramework("create-acme-certificate-request-http01")
h := f.Helper()
var acmeIngressDomain string
issuerName := "test-acme-issuer"
certificateName := "test-acme-certificate"
certificateSecretName := "test-acme-certificate"
certificateRequestName := "test-acme-certificate-request"
// fixedIngressName is the name of an ingress resource that is configured
// with a challenge solve.
// To utilise this solver, add the 'testing.cert-manager.io/fixed-ingress: "true"' label.
fixedIngressName := "testingress"
// 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{
{
@@ -129,120 +121,97 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01) Ingress", func(
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 when redirected", func() {
certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name)
It("should obtain a signed certificate with a single CN from the ACME server", func() {
crClient := f.CertManagerClientSet.CertmanagerV1().CertificateRequests(f.Namespace.Name)
// force-ssl-redirect should make every request turn into a redirect,
// but I haven't been able to make this happen. Create a TLS cert via
// the self-sign issuer to make it have a "proper" TLS cert
// TODO: investigate if we still need to use the self-signed issuer here
issuer := gen.Issuer("selfsign",
gen.SetIssuerNamespace(f.Namespace.Name),
gen.SetIssuerSelfSigned(v1.SelfSignedIssuer{}))
_, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for (selfsign) Issuer to become Ready")
err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name),
issuerName,
v1.IssuerCondition{
Type: v1.IssuerConditionReady,
Status: cmmeta.ConditionTrue,
})
By("Creating a CertificateRequest")
cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
[]string{acmeIngressDomain}, nil, nil, x509.RSA)
Expect(err).NotTo(HaveOccurred())
const dummycert = "dummy-tls"
const secretname = "dummy-tls-secret"
selfcert := util.NewCertManagerBasicCertificate("dummy-tls", secretname, "selfsign", v1.IssuerKind, nil, nil, acmeIngressDomain)
_, err = certClient.Create(context.TODO(), selfcert, metav1.CreateOptions{})
cr, err = crClient.Create(context.TODO(), cr, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssued(f.Namespace.Name, dummycert, time.Minute*5)
Expect(err).NotTo(HaveOccurred())
By("Validating the issued Certificate...")
err = f.Helper().ValidateCertificate(f.Namespace.Name, dummycert, validations...)
Expect(err).NotTo(HaveOccurred())
// create an ingress that points at nothing, but has the TLS redirect annotation set
// using the TLS secret that we just got from the self-sign
ingress := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace.Name)
_, err = ingress.Create(context.TODO(), &networkingv1beta1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: fixedIngressName,
Annotations: map[string]string{
"nginx.ingress.kubernetes.io/force-ssl-redirect": "true",
"kubernetes.io/ingress.class": "nginx",
},
},
Spec: networkingv1beta1.IngressSpec{
TLS: []networkingv1beta1.IngressTLS{
{
Hosts: []string{acmeIngressDomain},
SecretName: secretname,
},
},
Rules: []networkingv1beta1.IngressRule{
{
Host: acmeIngressDomain,
IngressRuleValue: networkingv1beta1.IngressRuleValue{
HTTP: &networkingv1beta1.HTTPIngressRuleValue{
Paths: []networkingv1beta1.HTTPIngressPath{
{
Path: "/",
Backend: networkingv1beta1.IngressBackend{
ServiceName: "doesnotexist",
ServicePort: intstr.FromInt(443),
},
},
},
},
},
},
},
},
}, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Creating a Certificate")
// This is a special cert for the test suite, where we specify an ingress rather than a
// class
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
cert.Labels = map[string]string{
"testing.cert-manager.io/fixed-ingress": "true",
}
_, 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...)
By("Verifying the Certificate is valid")
err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key)
Expect(err).NotTo(HaveOccurred())
})
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)
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 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{})
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")
@@ -277,12 +246,8 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01) Ingress", func(
// 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...)
By("Verifying the CertificateRequest is valid")
err = h.WaitCertificateRequestIssuedValid(f.Namespace.Name, certificateRequestName, time.Minute*5, key)
Expect(err).NotTo(HaveOccurred())
})
})
+1
View File
@@ -18,4 +18,5 @@ package acme
import (
_ "github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/certificate"
_ "github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/certificaterequest"
)
+1 -1
View File
@@ -90,7 +90,7 @@ var _ = framework.CertManagerDescribe("CA Injector", func() {
cert.Namespace = f.Namespace.Name
Expect(f.CRClient.Create(context.Background(), cert)).To(Succeed())
_, err := util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name), "serving-certs", certmanager.CertificateCondition{
err := util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name), "serving-certs", certmanager.CertificateCondition{
Type: certmanager.CertificateConditionReady,
Status: cmmeta.ConditionTrue,
}, time.Second*30)
+6 -10
View File
@@ -144,23 +144,19 @@ func wrapErrorWithClusterIssuerStatusCondition(client clientset.ClusterIssuerInt
// WaitForCertificateCondition waits for the status of the named Certificate to contain
// a condition whose type and status matches the supplied one.
func WaitForCertificateCondition(client clientset.CertificateInterface, name string, condition v1.CertificateCondition, timeout time.Duration) (*v1.Certificate, error) {
var certificate *v1.Certificate
err := wait.PollImmediate(500*time.Millisecond, timeout,
func WaitForCertificateCondition(client clientset.CertificateInterface, name string, condition v1.CertificateCondition, timeout time.Duration) error {
pollErr := wait.PollImmediate(500*time.Millisecond, timeout,
func() (bool, error) {
log.Logf("Waiting for Certificate %v to have contition %v %v", name, condition.Type, condition.Status)
log.Logf("Waiting for Certificate %v condition %#v", name, condition)
certificate, err := client.Get(context.TODO(), name, metav1.GetOptions{})
if nil != err {
return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
}
if !apiutil.CertificateHasCondition(certificate, condition) {
log.Logf("Expected Certificate to have condition %v %v %v but it has: %v", condition.Type, condition.Status, condition.ObservedGeneration, certificate.Status.Conditions)
return false, nil
}
return true, nil
return apiutil.CertificateHasCondition(certificate, condition), nil
},
)
return certificate, err
return wrapErrorWithCertificateStatusCondition(client, pollErr, name, condition.Type)
}
// WaitForCertificateEvent waits for an event on the named Certificate to contain