├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── deploy ├── rendered-manifest.yaml └── webhook-alidns │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── apiservice.yaml │ ├── deployment.yaml │ ├── pki.yaml │ ├── rbac.yaml │ └── service.yaml │ └── values.yaml ├── go.mod ├── go.sum ├── ingress-2.yaml ├── ingress.yaml ├── letsencrypt-clusterissuer-2.yaml ├── letsencrypt-clusterissuer.yaml ├── main.go ├── main_test.go ├── scripts ├── deploy.sh └── fetch-test-binaries.sh └── testdata └── alidns ├── README.md └── config.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Ignore the built binary 15 | cert-manager-webhook-alidns 16 | _out/ 17 | 18 | # idea 19 | .idea/ 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.4-alpine AS build_deps 2 | 3 | RUN apk add --no-cache git 4 | 5 | WORKDIR /workspace 6 | ENV GO111MODULE=on 7 | 8 | COPY go.mod . 9 | COPY go.sum . 10 | 11 | RUN go mod download 12 | 13 | FROM build_deps AS build 14 | 15 | COPY . . 16 | 17 | RUN CGO_ENABLED=0 go build -o webhook -ldflags '-w -extldflags "-static"' . 18 | 19 | FROM alpine:3.9 20 | 21 | RUN apk add --no-cache ca-certificates 22 | 23 | COPY --from=build /workspace/webhook /usr/local/bin/webhook 24 | 25 | ENTRYPOINT ["webhook"] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IMAGE_NAME := "webhook" 2 | IMAGE_TAG := "latest" 3 | 4 | OUT := $(shell pwd)/_out 5 | 6 | $(shell mkdir -p "$(OUT)") 7 | 8 | verify: 9 | go test -v . 10 | 11 | build: 12 | docker build -t "$(IMAGE_NAME):$(IMAGE_TAG)" . 13 | 14 | .PHONY: rendered-manifest.yaml 15 | rendered-manifest.yaml: 16 | helm template \ 17 | --name example-webhook \ 18 | --set image.repository=$(IMAGE_NAME) \ 19 | --set image.tag=$(IMAGE_TAG) \ 20 | deploy/example-webhook > "$(OUT)/rendered-manifest.yaml" 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACME webhook for alidns 2 | For details please link to 3 | https://blog.csdn.net/lwlfox/article/details/100989175 4 | 5 | ## Installation 6 | 7 | ```bash 8 | $ helm install --name cert-manager-webhook-alidns --namespace=cert-manager ./deploy/webhook-alidns 9 | or 10 | $ hell install --name cert-manager-webhook-alidns --namespace=cert-manager --set image.repository=/cert-manager-webhook-alidns \ 11 | --set image.tag=latest ./deploy/webhook-alidns 12 | 13 | ``` 14 | ## Build docker image 15 | ```bash 16 | $ docker build -t /cert-manager-webhook-alidns . 17 | #For users in china, you have to use vpn as some resources have been blocked in china 18 | #docker host should has 2G memory minimum 19 | ``` 20 | ## Issuer 21 | 22 | secret 23 | 24 | ```bash 25 | $ kubectl -n cert-manager create secret generic alidns-credentials --from-literal=accessKeySecret='your alidns accesskeySecret' 26 | ``` 27 | 28 | ClusterIssuer 29 | 30 | ```yaml 31 | apiVersion: certmanager.k8s.io/v1alpha1 32 | kind: ClusterIssuer 33 | metadata: 34 | name: letsencrypt-prod 35 | spec: 36 | acme: 37 | server: https://acme-v02.api.letsencrypt.org/directory 38 | email: 39 | privateKeySecretRef: 40 | name: letsencrypt-prod 41 | solvers: 42 | - selector: 43 | dnsNames: 44 | - '*.example.cn' 45 | dns01: 46 | webhook: 47 | config: 48 | accessKeyId: 49 | accessKeySecretRef: 50 | key: accessKeySecret 51 | name: alidns-credentials 52 | regionId: "cn-beijing" 53 | ttl: 600 54 | groupName: certmanager.webhook.alidns 55 | solverName: alidns 56 | ``` 57 | 58 | Ingress 59 | 60 | ```yaml 61 | apiVersion: extensions/v1beta1 62 | kind: Ingress 63 | metadata: 64 | name: example-ingress 65 | namespace: default 66 | annotations: 67 | certmanager.k8s.io/cluster-issuer: "letsencrypt-prod" 68 | spec: 69 | tls: 70 | - hosts: 71 | - '*.example.cn' 72 | secretName: wildcard-example-cn-tls 73 | rules: 74 | - host: demo.example.cn 75 | http: 76 | paths: 77 | - path: / 78 | backend: 79 | serviceName: backend-service 80 | servicePort: 80 81 | ``` 82 | 83 | ## Development 84 | 85 | ### Running the test suite 86 | 87 | 88 | 89 | All DNS providers **must** run the DNS01 provider conformance testing suite, 90 | else they will have undetermined behaviour when used with cert-manager. 91 | 92 | **It is essential that you configure and run the test suite when creating a 93 | DNS01 webhook.** 94 | 95 | An example Go test file has been provided in [main_test.go](). 96 | 97 | > Prepare 98 | 99 | ```bash 100 | $ scripts/fetch-test-binaries.sh 101 | ``` 102 | 103 | You can run the test suite with: 104 | 105 | ```bash 106 | $ TEST_ZONE_NAME=example.com go test . 107 | ``` 108 | 109 | The example file has a number of areas you must fill in and replace with your 110 | own options in order for tests to pass. 111 | -------------------------------------------------------------------------------- /deploy/rendered-manifest.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Source: webhook-alidns/templates/rbac.yaml 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: cert-manager-webhook-alidns 7 | labels: 8 | app: webhook-alidns 9 | chart: webhook-alidns-0.1.0 10 | release: cert-manager-webhook-alidns 11 | heritage: Tiller 12 | --- 13 | # Grant the webhook permission to read the ConfigMap containing the Kubernetes 14 | # apiserver's requestheader-ca-certificate. 15 | # This ConfigMap is automatically created by the Kubernetes apiserver. 16 | apiVersion: rbac.authorization.k8s.io/v1beta1 17 | kind: RoleBinding 18 | metadata: 19 | name: cert-manager-webhook-alidns:webhook-authentication-reader 20 | namespace: kube-system 21 | labels: 22 | app: webhook-alidns 23 | chart: webhook-alidns-0.1.0 24 | release: cert-manager-webhook-alidns 25 | heritage: Tiller 26 | roleRef: 27 | apiGroup: rbac.authorization.k8s.io 28 | kind: Role 29 | name: extension-apiserver-authentication-reader 30 | subjects: 31 | - apiGroup: "" 32 | kind: ServiceAccount 33 | name: cert-manager-webhook-alidns 34 | namespace: default 35 | --- 36 | # apiserver gets the auth-delegator role to delegate auth decisions to 37 | # the core apiserver 38 | apiVersion: rbac.authorization.k8s.io/v1beta1 39 | kind: ClusterRoleBinding 40 | metadata: 41 | name: cert-manager-webhook-alidns:auth-delegator 42 | labels: 43 | app: webhook-alidns 44 | chart: webhook-alidns-0.1.0 45 | release: cert-manager-webhook-alidns 46 | heritage: Tiller 47 | roleRef: 48 | apiGroup: rbac.authorization.k8s.io 49 | kind: ClusterRole 50 | name: system:auth-delegator 51 | subjects: 52 | - apiGroup: "" 53 | kind: ServiceAccount 54 | name: cert-manager-webhook-alidns 55 | namespace: default 56 | --- 57 | # Grant cert-manager permission to validate using our apiserver 58 | apiVersion: rbac.authorization.k8s.io/v1beta1 59 | kind: ClusterRole 60 | metadata: 61 | name: cert-manager-webhook-alidns:domain-solver 62 | labels: 63 | app: webhook-alidns 64 | chart: webhook-alidns-0.1.0 65 | release: cert-manager-webhook-alidns 66 | heritage: Tiller 67 | rules: 68 | - apiGroups: 69 | - acme.lin07.me 70 | resources: 71 | - '*' 72 | verbs: 73 | - 'create' 74 | --- 75 | apiVersion: rbac.authorization.k8s.io/v1beta1 76 | kind: ClusterRoleBinding 77 | metadata: 78 | name: cert-manager-webhook-alidns:domain-solver 79 | labels: 80 | app: webhook-alidns 81 | chart: webhook-alidns-0.1.0 82 | release: cert-manager-webhook-alidns 83 | heritage: Tiller 84 | roleRef: 85 | apiGroup: rbac.authorization.k8s.io 86 | kind: ClusterRole 87 | name: cert-manager-webhook-alidns:domain-solver 88 | subjects: 89 | - apiGroup: "" 90 | kind: ServiceAccount 91 | name: cert-manager 92 | namespace: cert-manager 93 | 94 | --- 95 | # Source: webhook-alidns/templates/service.yaml 96 | apiVersion: v1 97 | kind: Service 98 | metadata: 99 | name: cert-manager-webhook-alidns 100 | labels: 101 | app: webhook-alidns 102 | chart: webhook-alidns-0.1.0 103 | release: cert-manager-webhook-alidns 104 | heritage: Tiller 105 | spec: 106 | type: ClusterIP 107 | ports: 108 | - port: 443 109 | targetPort: https 110 | protocol: TCP 111 | name: https 112 | selector: 113 | app: webhook-alidns 114 | release: cert-manager-webhook-alidns 115 | 116 | --- 117 | # Source: webhook-alidns/templates/deployment.yaml 118 | apiVersion: apps/v1beta2 119 | kind: Deployment 120 | metadata: 121 | name: cert-manager-webhook-alidns 122 | labels: 123 | app: webhook-alidns 124 | chart: webhook-alidns-0.1.0 125 | release: cert-manager-webhook-alidns 126 | heritage: Tiller 127 | spec: 128 | replicas: 129 | selector: 130 | matchLabels: 131 | app: webhook-alidns 132 | release: cert-manager-webhook-alidns 133 | template: 134 | metadata: 135 | labels: 136 | app: webhook-alidns 137 | release: cert-manager-webhook-alidns 138 | spec: 139 | serviceAccountName: cert-manager-webhook-alidns 140 | containers: 141 | - name: webhook-alidns 142 | image: "lin07/cert-manager-webhook-alidns:latest" 143 | imagePullPolicy: IfNotPresent 144 | args: 145 | - --tls-cert-file=/tls/tls.crt 146 | - --tls-private-key-file=/tls/tls.key 147 | env: 148 | - name: GROUP_NAME 149 | value: "acme.lin07.me" 150 | ports: 151 | - name: https 152 | containerPort: 443 153 | protocol: TCP 154 | livenessProbe: 155 | httpGet: 156 | scheme: HTTPS 157 | path: /healthz 158 | port: https 159 | readinessProbe: 160 | httpGet: 161 | scheme: HTTPS 162 | path: /healthz 163 | port: https 164 | volumeMounts: 165 | - name: certs 166 | mountPath: /tls 167 | readOnly: true 168 | resources: 169 | {} 170 | 171 | volumes: 172 | - name: certs 173 | secret: 174 | secretName: cert-manager-webhook-alidns-webhook-tls 175 | 176 | --- 177 | # Source: webhook-alidns/templates/apiservice.yaml 178 | apiVersion: apiregistration.k8s.io/v1beta1 179 | kind: APIService 180 | metadata: 181 | name: v1alpha1.acme.lin07.me 182 | labels: 183 | app: webhook-alidns 184 | chart: webhook-alidns-0.1.0 185 | release: cert-manager-webhook-alidns 186 | heritage: Tiller 187 | annotations: 188 | certmanager.k8s.io/inject-ca-from: "default/cert-manager-webhook-alidns-webhook-tls" 189 | spec: 190 | group: acme.lin07.me 191 | groupPriorityMinimum: 1000 192 | versionPriority: 15 193 | service: 194 | name: cert-manager-webhook-alidns 195 | namespace: default 196 | version: v1alpha1 197 | 198 | --- 199 | # Source: webhook-alidns/templates/pki.yaml 200 | --- 201 | # Create a selfsigned Issuer, in order to create a root CA certificate for 202 | # signing webhook serving certificates 203 | apiVersion: certmanager.k8s.io/v1alpha1 204 | kind: Issuer 205 | metadata: 206 | name: cert-manager-webhook-alidns-selfsign 207 | namespace: "default" 208 | labels: 209 | app: webhook-alidns 210 | chart: webhook-alidns-0.1.0 211 | release: cert-manager-webhook-alidns 212 | heritage: Tiller 213 | spec: 214 | selfSigned: {} 215 | 216 | --- 217 | 218 | # Generate a CA Certificate used to sign certificates for the webhook 219 | apiVersion: certmanager.k8s.io/v1alpha1 220 | kind: Certificate 221 | metadata: 222 | name: cert-manager-webhook-alidns-ca 223 | namespace: "default" 224 | labels: 225 | app: webhook-alidns 226 | chart: webhook-alidns-0.1.0 227 | release: cert-manager-webhook-alidns 228 | heritage: Tiller 229 | spec: 230 | secretName: cert-manager-webhook-alidns-ca 231 | duration: 43800h # 5y 232 | issuerRef: 233 | name: cert-manager-webhook-alidns-selfsign 234 | commonName: "ca.webhook-alidns.cert-manager" 235 | isCA: true 236 | 237 | --- 238 | 239 | # Create an Issuer that uses the above generated CA certificate to issue certs 240 | apiVersion: certmanager.k8s.io/v1alpha1 241 | kind: Issuer 242 | metadata: 243 | name: cert-manager-webhook-alidns-ca 244 | namespace: "default" 245 | labels: 246 | app: webhook-alidns 247 | chart: webhook-alidns-0.1.0 248 | release: cert-manager-webhook-alidns 249 | heritage: Tiller 250 | spec: 251 | ca: 252 | secretName: cert-manager-webhook-alidns-ca 253 | 254 | --- 255 | 256 | # Finally, generate a serving certificate for the webhook to use 257 | apiVersion: certmanager.k8s.io/v1alpha1 258 | kind: Certificate 259 | metadata: 260 | name: cert-manager-webhook-alidns-webhook-tls 261 | namespace: "default" 262 | labels: 263 | app: webhook-alidns 264 | chart: webhook-alidns-0.1.0 265 | release: cert-manager-webhook-alidns 266 | heritage: Tiller 267 | spec: 268 | secretName: cert-manager-webhook-alidns-webhook-tls 269 | duration: 8760h # 1y 270 | issuerRef: 271 | name: cert-manager-webhook-alidns-ca 272 | dnsNames: 273 | - cert-manager-webhook-alidns 274 | - cert-manager-webhook-alidns.default 275 | - cert-manager-webhook-alidns.default.svc 276 | 277 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for Kubernetes 4 | name: webhook-alidns 5 | version: 0.1.0 6 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinniu666/cert-manager-webhook-alidns/23f4c05083f93ee01f71ecd976a8f6849c0ac2f1/deploy/webhook-alidns/templates/NOTES.txt -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "webhook-alidns.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "webhook-alidns.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "webhook-alidns.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{- define "webhook-alidns.selfSignedIssuer" -}} 35 | {{ printf "%s-selfsign" (include "webhook-alidns.fullname" .) }} 36 | {{- end -}} 37 | 38 | {{- define "webhook-alidns.rootCAIssuer" -}} 39 | {{ printf "%s-ca" (include "webhook-alidns.fullname" .) }} 40 | {{- end -}} 41 | 42 | {{- define "webhook-alidns.rootCACertificate" -}} 43 | {{ printf "%s-ca" (include "webhook-alidns.fullname" .) }} 44 | {{- end -}} 45 | 46 | {{- define "webhook-alidns.servingCertificate" -}} 47 | {{ printf "%s-webhook-tls" (include "webhook-alidns.fullname" .) }} 48 | {{- end -}} 49 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/apiservice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiregistration.k8s.io/v1beta1 2 | kind: APIService 3 | metadata: 4 | name: v1alpha1.{{ .Values.groupName }} 5 | labels: 6 | app: {{ include "webhook-alidns.name" . }} 7 | chart: {{ include "webhook-alidns.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | annotations: 11 | certmanager.k8s.io/inject-ca-from: "{{ .Release.Namespace }}/{{ include "webhook-alidns.servingCertificate" . }}" 12 | spec: 13 | group: {{ .Values.groupName }} 14 | groupPriorityMinimum: 1000 15 | versionPriority: 15 16 | service: 17 | name: {{ include "webhook-alidns.fullname" . }} 18 | namespace: {{ .Release.Namespace }} 19 | version: v1alpha1 20 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta2 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "webhook-alidns.fullname" . }} 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app: {{ include "webhook-alidns.name" . }} 8 | chart: {{ include "webhook-alidns.chart" . }} 9 | release: {{ .Release.Name }} 10 | heritage: {{ .Release.Service }} 11 | spec: 12 | replicas: {{ .Values.replicaCount }} 13 | selector: 14 | matchLabels: 15 | app: {{ include "webhook-alidns.name" . }} 16 | release: {{ .Release.Name }} 17 | template: 18 | metadata: 19 | labels: 20 | app: {{ include "webhook-alidns.name" . }} 21 | release: {{ .Release.Name }} 22 | spec: 23 | serviceAccountName: {{ include "webhook-alidns.fullname" . }} 24 | containers: 25 | - name: {{ .Chart.Name }} 26 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 27 | imagePullPolicy: {{ .Values.image.pullPolicy }} 28 | args: 29 | - --tls-cert-file=/tls/tls.crt 30 | - --tls-private-key-file=/tls/tls.key 31 | env: 32 | - name: GROUP_NAME 33 | value: {{ .Values.groupName | quote }} 34 | ports: 35 | - name: https 36 | containerPort: 443 37 | protocol: TCP 38 | livenessProbe: 39 | httpGet: 40 | scheme: HTTPS 41 | path: /healthz 42 | port: https 43 | readinessProbe: 44 | httpGet: 45 | scheme: HTTPS 46 | path: /healthz 47 | port: https 48 | volumeMounts: 49 | - name: certs 50 | mountPath: /tls 51 | readOnly: true 52 | resources: 53 | {{ toYaml .Values.resources | indent 12 }} 54 | volumes: 55 | - name: certs 56 | secret: 57 | secretName: {{ include "webhook-alidns.servingCertificate" . }} 58 | {{- with .Values.nodeSelector }} 59 | nodeSelector: 60 | {{ toYaml . | indent 8 }} 61 | {{- end }} 62 | {{- with .Values.affinity }} 63 | affinity: 64 | {{ toYaml . | indent 8 }} 65 | {{- end }} 66 | {{- with .Values.tolerations }} 67 | tolerations: 68 | {{ toYaml . | indent 8 }} 69 | {{- end }} 70 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/pki.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create a selfsigned Issuer, in order to create a root CA certificate for 3 | # signing webhook serving certificates 4 | apiVersion: certmanager.k8s.io/v1alpha1 5 | kind: Issuer 6 | metadata: 7 | name: {{ include "webhook-alidns.selfSignedIssuer" . }} 8 | namespace: {{ .Release.Namespace | quote }} 9 | labels: 10 | app: {{ include "webhook-alidns.name" . }} 11 | chart: {{ include "webhook-alidns.chart" . }} 12 | release: {{ .Release.Name }} 13 | heritage: {{ .Release.Service }} 14 | spec: 15 | selfSigned: {} 16 | 17 | --- 18 | 19 | # Generate a CA Certificate used to sign certificates for the webhook 20 | apiVersion: certmanager.k8s.io/v1alpha1 21 | kind: Certificate 22 | metadata: 23 | name: {{ include "webhook-alidns.rootCACertificate" . }} 24 | namespace: {{ .Release.Namespace | quote }} 25 | labels: 26 | app: {{ include "webhook-alidns.name" . }} 27 | chart: {{ include "webhook-alidns.chart" . }} 28 | release: {{ .Release.Name }} 29 | heritage: {{ .Release.Service }} 30 | spec: 31 | secretName: {{ include "webhook-alidns.rootCACertificate" . }} 32 | duration: 43800h # 5y 33 | issuerRef: 34 | name: {{ include "webhook-alidns.selfSignedIssuer" . }} 35 | commonName: "ca.webhook-alidns.cert-manager" 36 | isCA: true 37 | 38 | --- 39 | 40 | # Create an Issuer that uses the above generated CA certificate to issue certs 41 | apiVersion: certmanager.k8s.io/v1alpha1 42 | kind: Issuer 43 | metadata: 44 | name: {{ include "webhook-alidns.rootCAIssuer" . }} 45 | namespace: {{ .Release.Namespace | quote }} 46 | labels: 47 | app: {{ include "webhook-alidns.name" . }} 48 | chart: {{ include "webhook-alidns.chart" . }} 49 | release: {{ .Release.Name }} 50 | heritage: {{ .Release.Service }} 51 | spec: 52 | ca: 53 | secretName: {{ include "webhook-alidns.rootCACertificate" . }} 54 | 55 | --- 56 | 57 | # Finally, generate a serving certificate for the webhook to use 58 | apiVersion: certmanager.k8s.io/v1alpha1 59 | kind: Certificate 60 | metadata: 61 | name: {{ include "webhook-alidns.servingCertificate" . }} 62 | namespace: {{ .Release.Namespace | quote }} 63 | labels: 64 | app: {{ include "webhook-alidns.name" . }} 65 | chart: {{ include "webhook-alidns.chart" . }} 66 | release: {{ .Release.Name }} 67 | heritage: {{ .Release.Service }} 68 | spec: 69 | secretName: {{ include "webhook-alidns.servingCertificate" . }} 70 | duration: 8760h # 1y 71 | issuerRef: 72 | name: {{ include "webhook-alidns.rootCAIssuer" . }} 73 | dnsNames: 74 | - {{ include "webhook-alidns.fullname" . }} 75 | - {{ include "webhook-alidns.fullname" . }}.{{ .Release.Namespace }} 76 | - {{ include "webhook-alidns.fullname" . }}.{{ .Release.Namespace }}.svc 77 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "webhook-alidns.fullname" . }} 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app: {{ include "webhook-alidns.name" . }} 8 | chart: {{ include "webhook-alidns.chart" . }} 9 | release: {{ .Release.Name }} 10 | heritage: {{ .Release.Service }} 11 | --- 12 | #Define the ClusterRole which has the access tls secrets 13 | apiVersion: rbac.authorization.k8s.io/v1beta1 14 | kind: ClusterRole 15 | metadata: 16 | name: {{ include "webhook-alidns.fullname" . }}:secret-reader 17 | rules: 18 | - apiGroups: 19 | - '' 20 | resources: 21 | - 'secrets' 22 | resourceNames: 23 | - 'alidns-credentials' 24 | verbs: 25 | - 'get' 26 | - 'watch' 27 | --- 28 | apiVersion: rbac.authorization.k8s.io/v1beta1 29 | kind: ClusterRoleBinding 30 | metadata: 31 | name: {{ include "webhook-alidns.fullname" . }}:secret-reader 32 | roleRef: 33 | apiGroup: rbac.authorization.k8s.io 34 | kind: ClusterRole 35 | name: {{ include "webhook-alidns.fullname" . }}:secret-reader 36 | subjects: 37 | - apiGroup: "" 38 | kind: ServiceAccount 39 | name: {{ include "webhook-alidns.fullname" . }} 40 | namespace: {{ .Release.Namespace | quote }} 41 | --- 42 | # Grant the webhook permission to read the ConfigMap containing the Kubernetes 43 | # apiserver's requestheader-ca-certificate. 44 | # This ConfigMap is automatically created by the Kubernetes apiserver. 45 | apiVersion: rbac.authorization.k8s.io/v1beta1 46 | kind: RoleBinding 47 | metadata: 48 | name: {{ include "webhook-alidns.fullname" . }}:webhook-authentication-reader 49 | namespace: kube-system 50 | labels: 51 | app: {{ include "webhook-alidns.name" . }} 52 | chart: {{ include "webhook-alidns.chart" . }} 53 | release: {{ .Release.Name }} 54 | heritage: {{ .Release.Service }} 55 | roleRef: 56 | apiGroup: rbac.authorization.k8s.io 57 | kind: Role 58 | name: extension-apiserver-authentication-reader 59 | subjects: 60 | - apiGroup: "" 61 | kind: ServiceAccount 62 | name: {{ include "webhook-alidns.fullname" . }} 63 | namespace: {{ .Release.Namespace }} 64 | --- 65 | # apiserver gets the auth-delegator role to delegate auth decisions to 66 | # the core apiserver 67 | apiVersion: rbac.authorization.k8s.io/v1beta1 68 | kind: ClusterRoleBinding 69 | metadata: 70 | name: {{ include "webhook-alidns.fullname" . }}:auth-delegator 71 | labels: 72 | app: {{ include "webhook-alidns.name" . }} 73 | chart: {{ include "webhook-alidns.chart" . }} 74 | release: {{ .Release.Name }} 75 | heritage: {{ .Release.Service }} 76 | roleRef: 77 | apiGroup: rbac.authorization.k8s.io 78 | kind: ClusterRole 79 | name: system:auth-delegator 80 | subjects: 81 | - apiGroup: "" 82 | kind: ServiceAccount 83 | name: {{ include "webhook-alidns.fullname" . }} 84 | namespace: {{ .Release.Namespace }} 85 | --- 86 | # Grant cert-manager permission to validate using our apiserver 87 | apiVersion: rbac.authorization.k8s.io/v1beta1 88 | kind: ClusterRole 89 | metadata: 90 | name: {{ include "webhook-alidns.fullname" . }}:domain-solver 91 | labels: 92 | app: {{ include "webhook-alidns.name" . }} 93 | chart: {{ include "webhook-alidns.chart" . }} 94 | release: {{ .Release.Name }} 95 | heritage: {{ .Release.Service }} 96 | rules: 97 | - apiGroups: 98 | - {{ .Values.groupName }} 99 | resources: 100 | - '*' 101 | verbs: 102 | - 'create' 103 | --- 104 | apiVersion: rbac.authorization.k8s.io/v1beta1 105 | kind: ClusterRoleBinding 106 | metadata: 107 | name: {{ include "webhook-alidns.fullname" . }}:domain-solver 108 | labels: 109 | app: {{ include "webhook-alidns.name" . }} 110 | chart: {{ include "webhook-alidns.chart" . }} 111 | release: {{ .Release.Name }} 112 | heritage: {{ .Release.Service }} 113 | roleRef: 114 | apiGroup: rbac.authorization.k8s.io 115 | kind: ClusterRole 116 | name: {{ include "webhook-alidns.fullname" . }}:domain-solver 117 | subjects: 118 | - apiGroup: "" 119 | kind: ServiceAccount 120 | name: {{ .Values.certManager.serviceAccountName }} 121 | namespace: {{ .Values.certManager.namespace }} 122 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "webhook-alidns.fullname" . }} 5 | namespace: {{ .Release.Namespace | quote }} 6 | labels: 7 | app: {{ include "webhook-alidns.name" . }} 8 | chart: {{ include "webhook-alidns.chart" . }} 9 | release: {{ .Release.Name }} 10 | heritage: {{ .Release.Service }} 11 | spec: 12 | type: {{ .Values.service.type }} 13 | ports: 14 | - port: {{ .Values.service.port }} 15 | targetPort: https 16 | protocol: TCP 17 | name: https 18 | selector: 19 | app: {{ include "webhook-alidns.name" . }} 20 | release: {{ .Release.Name }} 21 | -------------------------------------------------------------------------------- /deploy/webhook-alidns/values.yaml: -------------------------------------------------------------------------------- 1 | # The GroupName here is used to identify your company or business unit that 2 | # created this webhook. 3 | # For example, this may be "acme.mycompany.com". 4 | # This name will need to be referenced in each Issuer's `webhook` stanza to 5 | # inform cert-manager of where to send ChallengePayload resources in order to 6 | # solve the DNS01 challenge. 7 | # This group name should be **unique**, hence using your own company's domain 8 | # here is recommended. 9 | groupName: certmanager.webhook.alidns 10 | 11 | certManager: 12 | namespace: cert-manager 13 | serviceAccountName: cert-manager 14 | 15 | image: 16 | repository: kevinniu666/cert-manager-webhook-alidns 17 | tag: latest 18 | pullPolicy: Always 19 | 20 | nameOverride: "" 21 | fullnameOverride: "" 22 | 23 | service: 24 | type: ClusterIP 25 | port: 443 26 | 27 | resources: {} 28 | # We usually recommend not to specify default resources and to leave this as a conscious 29 | # choice for the user. This also increases chances charts run on environments with little 30 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 31 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 32 | # limits: 33 | # cpu: 100m 34 | # memory: 128Mi 35 | # requests: 36 | # cpu: 100m 37 | # memory: 128Mi 38 | 39 | nodeSelector: {} 40 | 41 | tolerations: [] 42 | 43 | affinity: {} 44 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jetstack/cert-manager-webhook-example 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190625101801-175e03dc8791 7 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 8 | github.com/google/martian v2.1.0+incompatible 9 | github.com/imdario/mergo v0.3.7 // indirect 10 | github.com/jetstack/cert-manager v0.8.0-alpha.0 11 | golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect 12 | k8s.io/apiextensions-apiserver v0.0.0-20190413053546-d0acb7a76918 13 | k8s.io/apimachinery v0.0.0-20190413052414-40a3f73b0fa2 14 | k8s.io/client-go v0.0.0-20190413052642-108c485f896e 15 | ) 16 | 17 | replace github.com/evanphx/json-patch => github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550 18 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 | cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= 5 | github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 6 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 7 | github.com/Azure/go-autorest v11.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= 8 | github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 9 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 10 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 11 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 12 | github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= 13 | github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= 14 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= 15 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 16 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= 17 | github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= 18 | github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 19 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= 20 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 21 | github.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPEkMo= 22 | github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= 23 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 24 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 25 | github.com/Venafi/vcert v0.0.0-20181029235941-5068538d4d65/go.mod h1:3dpfrCI+31cDZosD+1UX8GFziVFORaegByXtzT1dwNo= 26 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 27 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 28 | github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190625101801-175e03dc8791 h1:XeWRQyfBBYQzxJYxGUg/bx5rB/y0a9hrzVINMQCuxQA= 29 | github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190625101801-175e03dc8791/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= 30 | github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= 31 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 32 | github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M= 33 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 34 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 35 | github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 36 | github.com/aws/aws-sdk-go v0.0.0-20170809071707-58f4800ac6e7/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= 37 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= 38 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 39 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 40 | github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= 41 | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= 42 | github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 43 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 44 | github.com/cloudflare/cloudflare-go v0.8.5/go.mod h1:8KhU6K+zHUEWOSU++mEQYf7D9UZOcQcibUoSm6vCUz4= 45 | github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 46 | github.com/coreos/bbolt v1.3.1-coreos.6 h1:uTXKg9gY70s9jMAKdfljFQcuh4e/BXOM+V+d00KFj3A= 47 | github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 48 | github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= 49 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 50 | github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= 51 | github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a h1:WqY2Kv7eI1jeoU3pC05YYK/kK4tdXyLzzaBzCR51r9M= 52 | github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 53 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= 54 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 55 | github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= 56 | github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 57 | github.com/cpu/goacmedns v0.0.0-20180701200144-565ecf2a84df/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= 58 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 59 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 60 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 61 | github.com/denisenkom/go-mssqldb v0.0.0-20190412130859-3b1d194e553a/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= 62 | github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 63 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 64 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 65 | github.com/digitalocean/godo v1.6.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= 66 | github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 67 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 68 | github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 69 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 70 | github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= 71 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 72 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 73 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 74 | github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 75 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 76 | github.com/emicklei/go-restful v2.9.3+incompatible h1:2OwhVdhtzYUp5P5wuGsVDPagKSRd9JK72sJCHVCXh5g= 77 | github.com/emicklei/go-restful v2.9.3+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 78 | github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550 h1:mV9jbLoSW/8m4VK16ZkHTozJa8sesK5u5kTMFysTYac= 79 | github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 80 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 81 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 82 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 83 | github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 84 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 85 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 86 | github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= 87 | github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= 88 | github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 89 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 90 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 91 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 92 | github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= 93 | github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= 94 | github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= 95 | github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= 96 | github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= 97 | github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= 98 | github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= 99 | github.com/go-openapi/jsonpointer v0.19.0 h1:FTUMcX77w5rQkClIzDtTxvn6Bsa894CcrzNj2MMfeg8= 100 | github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= 101 | github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= 102 | github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk= 103 | github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= 104 | github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= 105 | github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= 106 | github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= 107 | github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= 108 | github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= 109 | github.com/go-openapi/spec v0.17.2 h1:eb2NbuCnoe8cWAxhtK6CfMWUYmiFEZJ9Hx3Z2WRwJ5M= 110 | github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= 111 | github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= 112 | github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 113 | github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 114 | github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8= 115 | github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 116 | github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= 117 | github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= 118 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 119 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 120 | github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= 121 | github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= 122 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 123 | github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= 124 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 125 | github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= 126 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 127 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 128 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= 129 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 130 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 131 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 132 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 133 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 134 | github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 135 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 136 | github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 137 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= 138 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 139 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 140 | github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 141 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 142 | github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= 143 | github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 144 | github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 145 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 146 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 147 | github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= 148 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 149 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 150 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= 151 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 152 | github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= 153 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 154 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 155 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 156 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 157 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c h1:Lh2aW+HnU2Nbe1gqD9SOJLJxW1jBMmQOktN2acDyJk8= 158 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 159 | github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= 160 | github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 161 | github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79 h1:lR9ssWAqp9qL0bALxqEEkuudiP1eweOdv9jsRK3e7lE= 162 | github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 163 | github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611 h1:f5vL2EW5pL274ztMNnizZAEa457nKyKPEaN/sm/kdBk= 164 | github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 165 | github.com/grpc-ecosystem/grpc-gateway v1.3.0 h1:HJtP6RRwj2EpPCD/mhAWzSvLL/dFTdPm1UrWwanoFos= 166 | github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= 167 | github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= 168 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 169 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 170 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 171 | github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 172 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 173 | github.com/hashicorp/go-memdb v1.0.0/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= 174 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 175 | github.com/hashicorp/go-plugin v1.0.0/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= 176 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 177 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 178 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 179 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 180 | github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= 181 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 182 | github.com/hashicorp/golang-math-big v0.0.0-20180316142257-561262b71329/go.mod h1:eBwVNKMPVQvPzsL2kU1sgH+Wf3xcmgFCvFSyGDEUSgc= 183 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 184 | github.com/hashicorp/vault v0.9.6/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= 185 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 186 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 187 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 188 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 189 | github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= 190 | github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 191 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 192 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 193 | github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= 194 | github.com/jetstack/cert-manager v0.8.0-alpha.0 h1:GENCzL+VW7eF/Cgy1XQeaDJUBpP38OFEWcpBdF9+9rA= 195 | github.com/jetstack/cert-manager v0.8.0-alpha.0/go.mod h1:GsWWdhRdDmHDL/GvVQt82/N/Hr4R6GQfNjZV2BwOPfY= 196 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= 197 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 198 | github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c h1:XpRROA6ssPlTwJI8/pH+61uieOkcJhmAFz25cu0B94Y= 199 | github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 200 | github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE= 201 | github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 202 | github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= 203 | github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 204 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 205 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 206 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 207 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 208 | github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= 209 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 210 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 211 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 212 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 213 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 214 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 215 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 216 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 217 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 218 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 219 | github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= 220 | github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 221 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 222 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 223 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 224 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 225 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 226 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 227 | github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab/go.mod h1:y1pL58r5z2VvAjeG1VLGc8zOQgSOzbKN7kMHPvFXJ+8= 228 | github.com/miekg/dns v0.0.0-20170721150254-0f3adef2e220 h1:XMdRBCTXUEnj/+IMBiv3IsARZaMcx3KUkRUdxZn5t4I= 229 | github.com/miekg/dns v0.0.0-20170721150254-0f3adef2e220/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 230 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 231 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 232 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 233 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 234 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 235 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 236 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 237 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 238 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 239 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 240 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 241 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= 242 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 243 | github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 h1:10VrZWOtDSvWhgViCi2J6VUp4p/B3pOA/efiMH3KjjI= 244 | github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 245 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 246 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 247 | github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= 248 | github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= 249 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 250 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 251 | github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= 252 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 253 | github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 254 | github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= 255 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 256 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 257 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 258 | github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 259 | github.com/openshift/generic-admission-server v1.14.0/go.mod h1:GD9KN/W4KxqRQGVMbqQHpHzb2XcQVvLCaBaSciqXvfM= 260 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 261 | github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= 262 | github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 263 | github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 264 | github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= 265 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 266 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 267 | github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= 268 | github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 269 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 270 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 271 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 272 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 273 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 274 | github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= 275 | github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20 h1:7sBb9iOkeq+O7AXlVoH/8zpIcRXX523zMkKKspHjjx8= 276 | github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= 277 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 278 | github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= 279 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= 280 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 281 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 282 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= 283 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 284 | github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 285 | github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= 286 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 287 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 288 | github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 289 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= 290 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 291 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 292 | github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= 293 | github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= 294 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 295 | github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0/go.mod h1:Ad7IjTpvzZO8Fl0vh9AzQ+j/jYZfyp2diGwI8m5q+ns= 296 | github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= 297 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 298 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 299 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 300 | github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= 301 | github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 302 | github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss= 303 | github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 304 | github.com/spf13/cobra v0.0.0-20170905172051-b78744579491/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 305 | github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937 h1:+ryWjMVzFAkEz5zT+Ms49aROZwxlJce3x3zLTFpkz3Y= 306 | github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 307 | github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= 308 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 309 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 310 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 311 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 312 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 313 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 314 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 315 | github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8= 316 | github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= 317 | github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 318 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= 319 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 320 | github.com/ugorji/go v0.0.0-20171019201919-bdcc60b419d1 h1:UvhxfNjNqlZ/x3cDyqxMhoiUpemd3zXkVQApN6bM/lg= 321 | github.com/ugorji/go v0.0.0-20171019201919-bdcc60b419d1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= 322 | github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 h1:MPPkRncZLN9Kh4MEFmbnK4h3BD7AUmskWv2+EeZJCCs= 323 | github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 324 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 325 | go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569 h1:nSQar3Y0E3VQF/VdZ8PTAilaXpER+d7ypdABCrpwMdg= 326 | go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 327 | go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df h1:shvkWr0NAZkg4nPuE3XrKP0VuBPijjk3TfX6Y6acFNg= 328 | go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 329 | go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 330 | go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= 331 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 332 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 333 | golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 334 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 335 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 336 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 337 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g= 338 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 339 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 340 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 341 | golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 342 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 343 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 344 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 345 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 346 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 347 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 348 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 349 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 350 | golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 351 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 352 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 353 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 354 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 355 | golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 356 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 357 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 358 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 359 | golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 360 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 361 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 362 | golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= 363 | golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 364 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 365 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 366 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= 367 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 368 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= 369 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 370 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 371 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 372 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 373 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 374 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 375 | golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 376 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 377 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 378 | golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= 379 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 380 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= 381 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 382 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 383 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 384 | golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= 385 | golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 386 | golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 387 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 388 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= 389 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 390 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 391 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 392 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 393 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 394 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 395 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 396 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 397 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 398 | gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= 399 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 400 | gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= 401 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 402 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 403 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 404 | google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= 405 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 406 | google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 407 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 408 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 409 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo= 410 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 411 | google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 412 | google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 413 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 414 | google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= 415 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 416 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 417 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 418 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 419 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 420 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 421 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 422 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 423 | gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= 424 | gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 425 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 426 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 427 | gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= 428 | gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 429 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 430 | gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7 h1:986b60BAz5vO2Vaf48yQaq+wb2bU4JsXxKu1+itW6x8= 431 | gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 432 | gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= 433 | gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 434 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 435 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 436 | gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= 437 | gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= 438 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 439 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 440 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 441 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 442 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 443 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 444 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 445 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 446 | k8s.io/api v0.0.0-20190413052509-3cc1b3fb6d0f h1:wrTt9gCsmxJNmIPLK38QdHrUTTAVkjXkGYPD5MTxcgk= 447 | k8s.io/api v0.0.0-20190413052509-3cc1b3fb6d0f/go.mod h1:ZQJMVsOricQ70XeVqHESzHGdfvp99Z+62MQogxPVWLE= 448 | k8s.io/apiextensions-apiserver v0.0.0-20190111034747-7d26de67f177/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= 449 | k8s.io/apiextensions-apiserver v0.0.0-20190413053546-d0acb7a76918 h1:nXUPc6KDWwzyZygykHyxCWkqKJr7nT6d9RcJMLR2Tug= 450 | k8s.io/apiextensions-apiserver v0.0.0-20190413053546-d0acb7a76918/go.mod h1:O1IFI8uOQgVLLhiLgJvXVH25AvZNZe2X2ZI+ckia76o= 451 | k8s.io/apimachinery v0.0.0-20190413052414-40a3f73b0fa2 h1:5EaBeH2ttVa0wgvLCmExPuss83UOpGnlSd84f2NvDy4= 452 | k8s.io/apimachinery v0.0.0-20190413052414-40a3f73b0fa2/go.mod h1:89khKZ4rbtSMZapCb0ZnL3e/0GDb/yfOROD9A2LXO8o= 453 | k8s.io/apiserver v0.0.0-20190413053200-5b6ebd80335e h1:m/sSZ1rPGfDS6vjEE10ZK/DwLsEDcmka32KlfGKOVdI= 454 | k8s.io/apiserver v0.0.0-20190413053200-5b6ebd80335e/go.mod h1:/6/6fIsCxHaQ0wJzRGiLM7XI6sWK+pMTwXwBH6n4Fkk= 455 | k8s.io/client-go v0.0.0-20190413052642-108c485f896e h1:iOcgHVq3ZTcnoze9lobuWiaiE3fh73iyoYfhy+FCoeY= 456 | k8s.io/client-go v0.0.0-20190413052642-108c485f896e/go.mod h1:54AdMyAr4MW55R7spR3CgxLIGHI4roHQ7vqiF6x3mCs= 457 | k8s.io/code-generator v0.0.0-20181117043124-c2090bec4d9b/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= 458 | k8s.io/code-generator v0.0.0-20190413052309-5c40078c1b12/go.mod h1:HURHo+BaZvrjm6DIST3jWY+eeitiILOLFd/uQL1jxWE= 459 | k8s.io/component-base v0.0.0-20190413053003-a7e0d79a8811 h1:42sMs4XHbyboOIL9EIUMqoC4wcp5VA8GZ3WezgfTbRM= 460 | k8s.io/component-base v0.0.0-20190413053003-a7e0d79a8811/go.mod h1:gp2Y+J3k6aFs2p67Rw82MgfFfHWEl5Xm/Y/7V0v4FJo= 461 | k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 462 | k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 463 | k8s.io/klog v0.0.0-20190306015804-8e90cee79f82 h1:SHucoAy7lRb+w5oC/hbXyZg+zX+Wftn6hD4tGzHCVqA= 464 | k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 465 | k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= 466 | k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 467 | k8s.io/kube-aggregator v0.0.0-20190222095010-0b78038fe9e5/go.mod h1:8sbzT4QQKDEmSCIbfqjV0sd97GpUT7A4W626sBiYJmU= 468 | k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30 h1:TRb4wNWoBVrH9plmkp2q86FIDppkbrEXdXlxU3a3BMI= 469 | k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= 470 | k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= 471 | k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= 472 | modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= 473 | modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= 474 | modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= 475 | modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= 476 | modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= 477 | sigs.k8s.io/controller-runtime v0.0.0-20190222182021-68ae79ea094a/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= 478 | sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2 h1:9r5DY45ef9LtcA6BnkhW8MPV7OKAfbf2AUwUhq3LeRk= 479 | sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 480 | sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= 481 | sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= 482 | sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= 483 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 484 | -------------------------------------------------------------------------------- /ingress-2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: demo-ingress-2 5 | namespace: default 6 | annotations: 7 | certmanager.k8s.io/cluster-issuer: "letsencrypt-prod-2" 8 | spec: 9 | tls: 10 | - hosts: 11 | - '*.yourdomain2.com' 12 | secretName: yourdomain2-com-tls 13 | rules: 14 | - host: www.yourdomain2.com 15 | http: 16 | paths: 17 | - path: / 18 | backend: 19 | serviceName: nginx 20 | servicePort: 80 21 | --- 22 | apiVersion: apps/v1beta1 23 | kind: Deployment 24 | metadata: 25 | name: nginx 26 | labels: 27 | component: nginx 28 | spec: 29 | replicas: 1 30 | template: 31 | metadata: 32 | labels: 33 | component: nginx 34 | spec: 35 | containers: 36 | - name: nginx 37 | image: nginx 38 | imagePullPolicy: IfNotPresent 39 | resources: 40 | requests: 41 | cpu: 0.25 42 | limits: 43 | cpu: 1 44 | ports: 45 | - containerPort: 80 46 | name: http 47 | livenessProbe: 48 | tcpSocket: 49 | port: http 50 | initialDelaySeconds: 20 51 | periodSeconds: 10 52 | readinessProbe: 53 | httpGet: 54 | path: / 55 | port: http 56 | initialDelaySeconds: 20 57 | timeoutSeconds: 5 58 | --- 59 | apiVersion: v1 60 | kind: Service 61 | metadata: 62 | name: nginx 63 | labels: 64 | component: nginx 65 | spec: 66 | selector: 67 | component: nginx 68 | ports: 69 | - name: http 70 | port: 80 71 | targetPort: 80 72 | -------------------------------------------------------------------------------- /ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: demo-ingress 5 | namespace: default 6 | annotations: 7 | certmanager.k8s.io/cluster-issuer: "letsencrypt-prod" 8 | spec: 9 | tls: 10 | - hosts: 11 | - '*.yourdomain.com' 12 | secretName: yourdomain-com-tls 13 | rules: 14 | - host: www.yourdomain.com 15 | http: 16 | paths: 17 | - path: / 18 | backend: 19 | serviceName: nginx 20 | servicePort: 80 21 | --- 22 | apiVersion: apps/v1beta1 23 | kind: Deployment 24 | metadata: 25 | name: nginx 26 | labels: 27 | component: nginx 28 | spec: 29 | replicas: 1 30 | template: 31 | metadata: 32 | labels: 33 | component: nginx 34 | spec: 35 | containers: 36 | - name: nginx 37 | image: nginx 38 | imagePullPolicy: IfNotPresent 39 | resources: 40 | requests: 41 | cpu: 0.25 42 | limits: 43 | cpu: 1 44 | ports: 45 | - containerPort: 80 46 | name: http 47 | livenessProbe: 48 | tcpSocket: 49 | port: http 50 | initialDelaySeconds: 20 51 | periodSeconds: 10 52 | readinessProbe: 53 | httpGet: 54 | path: / 55 | port: http 56 | initialDelaySeconds: 20 57 | timeoutSeconds: 5 58 | --- 59 | apiVersion: v1 60 | kind: Service 61 | metadata: 62 | name: nginx 63 | labels: 64 | component: nginx 65 | spec: 66 | selector: 67 | component: nginx 68 | ports: 69 | - name: http 70 | port: 80 71 | targetPort: 80 72 | -------------------------------------------------------------------------------- /letsencrypt-clusterissuer-2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: certmanager.k8s.io/v1alpha1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-prod-2 5 | spec: 6 | acme: 7 | server: https://acme-v02.api.letsencrypt.org/directory 8 | email: youremail@163.com 9 | privateKeySecretRef: 10 | name: letsencrypt-prod-2 11 | solvers: 12 | - selector: 13 | dnsNames: 14 | - '*.yourdomain2.com' 15 | dns01: 16 | webhook: 17 | config: 18 | accessKeyId: yourAKID 19 | accessKeySecretRef: 20 | key: accessKeySecret 21 | name: alidns-credentials-2 22 | regionId: "cn-shenzhen" 23 | ttl: 600 24 | groupName: certmanager.webhook.alidns 25 | solverName: alidns 26 | -------------------------------------------------------------------------------- /letsencrypt-clusterissuer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: certmanager.k8s.io/v1alpha1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-prod 5 | spec: 6 | acme: 7 | server: https://acme-v02.api.letsencrypt.org/directory 8 | email: youremail@163.com 9 | privateKeySecretRef: 10 | name: letsencrypt-prod 11 | solvers: 12 | - selector: 13 | dnsNames: 14 | - '*.yourdomain.com' 15 | dns01: 16 | webhook: 17 | config: 18 | accessKeyId: yourAKID 19 | accessKeySecretRef: 20 | key: accessKeySecret 21 | name: alidns-credentials 22 | regionId: "cn-shenzhen" 23 | ttl: 600 24 | groupName: certmanager.webhook.alidns 25 | solverName: alidns 26 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" 7 | "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" 8 | certmanager_v1alpha1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1" 9 | "github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util" 10 | extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" 11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | "k8s.io/client-go/kubernetes" 13 | "k8s.io/client-go/rest" 14 | "os" 15 | "strings" 16 | 17 | "github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" 18 | "github.com/jetstack/cert-manager/pkg/acme/webhook/cmd" 19 | ) 20 | 21 | var GroupName = os.Getenv("GROUP_NAME") 22 | 23 | func main() { 24 | if GroupName == "" { 25 | panic("GROUP_NAME must be specified") 26 | } 27 | 28 | // This will register our custom DNS provider with the webhook serving 29 | // library, making it available as an API under the provided GroupName. 30 | // You can register multiple DNS provider implementations with a single 31 | // webhook, where the Name() method will be used to disambiguate between 32 | // the different implementations. 33 | cmd.RunWebhookServer(GroupName, 34 | &aliyunDNSProviderSolver{}, 35 | ) 36 | } 37 | 38 | // aliyunDNSProviderSolver implements the provider-specific logic needed to 39 | // 'present' an ACME challenge TXT record for your own DNS provider. 40 | // To do so, it must implement the `github.com/jetstack/cert-manager/pkg/acme/webhook.Solver` 41 | // interface. 42 | type aliyunDNSProviderSolver struct { 43 | client *kubernetes.Clientset 44 | dnsClients map[string]*alidns.Client 45 | } 46 | 47 | // aliyunDNSProviderConfig is a structure that is used to decode into when 48 | // solving a DNS01 challenge. 49 | // This information is provided by cert-manager, and may be a reference to 50 | // additional configuration that's needed to solve the challenge for this 51 | // particular certificate or issuer. 52 | // This typically includes references to Secret resources containing DNS 53 | // provider credentials, in cases where a 'multi-tenant' DNS solver is being 54 | // created. 55 | // If you do *not* require per-issuer or per-certificate configuration to be 56 | // provided to your webhook, you can skip decoding altogether in favour of 57 | // using CLI flags or similar to provide configuration. 58 | // You should not include sensitive information here. If credentials need to 59 | // be used by your provider here, you should reference a Kubernetes Secret 60 | // resource and fetch these credentials using a Kubernetes clientset. 61 | type aliyunDNSProviderConfig struct { 62 | RegionId string `json:"regionId"` 63 | AccessKeyId string `json:"accessKeyId"` 64 | AccessKeySecret string `json:"accessKeySecret"` 65 | AccessKeySecretRef certmanager_v1alpha1.SecretKeySelector `json:"accessKeySecretRef"` 66 | TTL *int `json:"ttl"` 67 | } 68 | 69 | // Name is used as the name for this DNS solver when referencing it on the ACME 70 | // Issuer resource. 71 | // This should be unique **within the group name**, i.e. you can have two 72 | // solvers configured with the same Name() **so long as they do not co-exist 73 | // within a single webhook deployment**. 74 | // For example, `cloudflare` may be used as the name of a solver. 75 | func (c *aliyunDNSProviderSolver) Name() string { 76 | return "alidns" 77 | } 78 | 79 | // Present is responsible for actually presenting the DNS record with the 80 | // DNS provider. 81 | // This method should tolerate being called multiple times with the same value. 82 | // cert-manager itself will later perform a self check to ensure that the 83 | // solver has correctly configured the DNS provider. 84 | func (c *aliyunDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error { 85 | cfg, err := loadConfig(ch.Config) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | fmt.Printf("Decoded configuration %v", cfg) 91 | 92 | client, err := c.getDnsClient(ch, cfg) 93 | if err != nil { 94 | return err 95 | } 96 | fmt.Printf("fqdn:[%s] zone:[%s]\n", ch.ResolvedFQDN, ch.ResolvedZone) 97 | domainName := c.extractDomainName(ch.ResolvedZone) 98 | request := alidns.CreateAddDomainRecordRequest() 99 | request.DomainName = domainName 100 | request.RR = c.extractRecordName(ch.ResolvedFQDN, domainName) 101 | request.Type = "TXT" 102 | request.Value = ch.Key 103 | request.TTL = requests.NewInteger(*cfg.TTL) 104 | response, err := client.AddDomainRecord(request) 105 | 106 | if err != nil { 107 | return err 108 | } 109 | 110 | fmt.Printf("Response: %v", response) 111 | return nil 112 | } 113 | 114 | // CleanUp should delete the relevant TXT record from the DNS provider console. 115 | // If multiple TXT records exist with the same record name (e.g. 116 | // _acme-challenge.example.com) then **only** the record with the same `key` 117 | // value provided on the ChallengeRequest should be cleaned up. 118 | // This is in order to facilitate multiple DNS validations for the same domain 119 | // concurrently. 120 | func (c *aliyunDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { 121 | cfg, err := loadConfig(ch.Config) 122 | if err != nil { 123 | return err 124 | } 125 | 126 | fmt.Printf("Decoded configuration %v", cfg) 127 | 128 | client, err := c.getDnsClient(ch, cfg) 129 | if err != nil { 130 | return err 131 | } 132 | records, err := c.findTxtRecords(client, ch.ResolvedZone, ch.ResolvedFQDN) 133 | if err != nil { 134 | return err 135 | } 136 | for _, record := range records { 137 | if record.Value != ch.Key { 138 | continue 139 | } 140 | request := alidns.CreateDeleteDomainRecordRequest() 141 | request.RecordId = record.RecordId 142 | _, err = client.DeleteDomainRecord(request) 143 | if err != nil { 144 | return fmt.Errorf("alidns: %v", err) 145 | } 146 | } 147 | return nil 148 | } 149 | 150 | // Initialize will be called when the webhook first starts. 151 | // This method can be used to instantiate the webhook, i.e. initialising 152 | // connections or warming up caches. 153 | // Typically, the kubeClientConfig parameter is used to build a Kubernetes 154 | // client that can be used to fetch resources from the Kubernetes API, e.g. 155 | // Secret resources containing credentials used to authenticate with DNS 156 | // provider accounts. 157 | // The stopCh can be used to handle early termination of the webhook, in cases 158 | // where a SIGTERM or similar signal is sent to the webhook process. 159 | func (c *aliyunDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error { 160 | ///// UNCOMMENT THE BELOW CODE TO MAKE A KUBERNETES CLIENTSET AVAILABLE TO 161 | ///// YOUR CUSTOM DNS PROVIDER 162 | 163 | cl, err := kubernetes.NewForConfig(kubeClientConfig) 164 | if err != nil { 165 | return err 166 | } 167 | 168 | c.client = cl 169 | 170 | ///// END OF CODE TO MAKE KUBERNETES CLIENTSET AVAILABLE 171 | 172 | c.dnsClients = make(map[string]*alidns.Client) 173 | 174 | return nil 175 | } 176 | 177 | // loadConfig is a small helper function that decodes JSON configuration into 178 | // the typed config struct. 179 | func loadConfig(cfgJSON *extapi.JSON) (aliyunDNSProviderConfig, error) { 180 | cfg := aliyunDNSProviderConfig{} 181 | // handle the 'base case' where no configuration has been provided 182 | if cfgJSON == nil { 183 | return cfg, nil 184 | } 185 | if err := json.Unmarshal(cfgJSON.Raw, &cfg); err != nil { 186 | return cfg, fmt.Errorf("error decoding solver config: %v", err) 187 | } 188 | 189 | return cfg, nil 190 | } 191 | 192 | func (c *aliyunDNSProviderSolver) getDnsClient(ch *v1alpha1.ChallengeRequest, cfg aliyunDNSProviderConfig) (*alidns.Client, error) { 193 | accessKeyId := cfg.AccessKeyId 194 | client, ok := c.dnsClients[accessKeyId] 195 | 196 | if ok { 197 | return client, nil 198 | } 199 | 200 | accessKeySecret := cfg.AccessKeySecret 201 | if accessKeySecret == "" { 202 | ref := cfg.AccessKeySecretRef 203 | if ref.Key == "" { 204 | return nil, fmt.Errorf("no accessKeySecret for %q in secret '%s/%s'", ref.Name, ref.Key, ch.ResourceNamespace) 205 | } 206 | if ref.Name == "" { 207 | return nil, fmt.Errorf("no accessKeySecret for %q in secret '%s/%s'", ref.Name, ref.Key, ch.ResourceNamespace) 208 | } 209 | secret, err := c.client.CoreV1().Secrets(ch.ResourceNamespace).Get(ref.Name, metav1.GetOptions{}) 210 | if err != nil { 211 | return nil, err 212 | } 213 | 214 | accessKeySecretRef, ok := secret.Data[ref.Key] 215 | if !ok { 216 | return nil, fmt.Errorf("no accessKeySecret for %q in secret '%s/%s'", ref.Name, ref.Key, ch.ResourceNamespace) 217 | } 218 | accessKeySecret = fmt.Sprintf("%s", accessKeySecretRef) 219 | } 220 | client, err := alidns.NewClientWithAccessKey( 221 | cfg.RegionId, // 您的可用区ID 222 | accessKeyId, // 您的Access Key ID 223 | accessKeySecret, 224 | ) 225 | 226 | if err != nil { 227 | return nil, err 228 | } 229 | c.dnsClients[cfg.AccessKeyId] = client 230 | 231 | client.OpenLogger() 232 | return client, nil 233 | } 234 | 235 | func (c *aliyunDNSProviderSolver) findTxtRecords(client *alidns.Client, zone, fqdn string) ([]alidns.Record, error) { 236 | _, zoneName, err := c.getHostedZone(client, zone) 237 | if err != nil { 238 | return nil, err 239 | } 240 | 241 | request := alidns.CreateDescribeDomainRecordsRequest() 242 | request.DomainName = zoneName 243 | request.PageSize = requests.NewInteger(500) 244 | 245 | var records []alidns.Record 246 | 247 | result, err := client.DescribeDomainRecords(request) 248 | if err != nil { 249 | return records, fmt.Errorf("API call has failed: %v", err) 250 | } 251 | 252 | recordName := c.extractRecordName(fqdn, zoneName) 253 | for _, record := range result.DomainRecords.Record { 254 | if record.RR == recordName { 255 | records = append(records, record) 256 | } 257 | } 258 | return records, nil 259 | } 260 | 261 | func (c *aliyunDNSProviderSolver) getHostedZone(client *alidns.Client, zone string) (string, string, error) { 262 | request := alidns.CreateDescribeDomainsRequest() 263 | 264 | var domains []alidns.Domain 265 | startPage := 1 266 | 267 | for { 268 | request.PageNumber = requests.NewInteger(startPage) 269 | 270 | response, err := client.DescribeDomains(request) 271 | if err != nil { 272 | return "", "", fmt.Errorf("API call failed: %v", err) 273 | } 274 | 275 | domains = append(domains, response.Domains.Domain...) 276 | 277 | if response.PageNumber*response.PageSize >= response.TotalCount { 278 | break 279 | } 280 | 281 | startPage++ 282 | } 283 | 284 | authZone, err := util.FindZoneByFqdn(zone, util.RecursiveNameservers) 285 | if err != nil { 286 | return "", "", err 287 | } 288 | 289 | var hostedZone alidns.Domain 290 | for _, zone := range domains { 291 | if zone.DomainName == util.UnFqdn(authZone) { 292 | hostedZone = zone 293 | } 294 | } 295 | 296 | if hostedZone.DomainId == "" { 297 | return "", "", fmt.Errorf("zone %s not found in AliDNS for domain %s", authZone, zone) 298 | } 299 | return fmt.Sprintf("%v", hostedZone.DomainId), hostedZone.DomainName, nil 300 | } 301 | 302 | func (c *aliyunDNSProviderSolver) extractRecordName(fqdn, domain string) string { 303 | if idx := strings.Index(fqdn, "."+domain); idx != -1 { 304 | return fqdn[:idx] 305 | } 306 | return util.UnFqdn(fqdn) 307 | } 308 | 309 | func (c *aliyunDNSProviderSolver) extractDomainName(zone string) string { 310 | authZone, err := util.FindZoneByFqdn(zone, util.RecursiveNameservers) 311 | if err != nil { 312 | return zone 313 | } 314 | return util.UnFqdn(authZone) 315 | } 316 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/jetstack/cert-manager/test/acme/dns" 8 | ) 9 | 10 | var ( 11 | zone = os.Getenv("TEST_ZONE_NAME") 12 | ) 13 | 14 | func TestRunsSuite(t *testing.T) { 15 | // The manifest path should contain a file named config.json that is a 16 | // snippet of valid configuration that should be included on the 17 | // ChallengeRequest passed as part of the test cases. 18 | 19 | fixture := dns.NewFixture(&aliyunDNSProviderSolver{}, 20 | dns.SetResolvedZone(zone), 21 | dns.SetAllowAmbientCredentials(false), 22 | dns.SetManifestPath("testdata/alidns"), 23 | dns.SetBinariesPath("_out/kubebuilder/bin"), 24 | ) 25 | 26 | fixture.RunConformance(t) 27 | } 28 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | IMAGE_NAME="lin07/cert-manager-webhook-alidns" 4 | IMAGE_TAG="latest" 5 | 6 | OUT=`pwd`/deploy 7 | 8 | helm template \ 9 | --name cert-manager-webhook-alidns \ 10 | --set image.repository=$IMAGE_NAME \ 11 | --set image.tag=$IMAGE_TAG \ 12 | deploy/webhook-alidns > "$OUT/rendered-manifest.yaml" -------------------------------------------------------------------------------- /scripts/fetch-test-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | #hack_dir=$(dirname ${BASH_SOURCE}) 6 | #source ${hack_dir}/common.sh 7 | 8 | k8s_version=1.14.1 9 | goarch=amd64 10 | goos="unknown" 11 | 12 | if [[ "$OSTYPE" == "linux-gnu" ]]; then 13 | goos="linux" 14 | elif [[ "$OSTYPE" == "darwin"* ]]; then 15 | goos="darwin" 16 | fi 17 | 18 | if [[ "$goos" == "unknown" ]]; then 19 | echo "OS '$OSTYPE' not supported. Aborting." >&2 20 | exit 1 21 | fi 22 | 23 | tmp_root=./_out 24 | kb_root_dir=$tmp_root/kubebuilder 25 | 26 | # Turn colors in this script off by setting the NO_COLOR variable in your 27 | # environment to any value: 28 | # 29 | # $ NO_COLOR=1 test.sh 30 | NO_COLOR=${NO_COLOR:-""} 31 | if [ -z "$NO_COLOR" ]; then 32 | header=$'\e[1;33m' 33 | reset=$'\e[0m' 34 | else 35 | header='' 36 | reset='' 37 | fi 38 | 39 | function header_text { 40 | echo "$header$*$reset" 41 | } 42 | 43 | # fetch k8s API gen tools and make it available under kb_root_dir/bin. 44 | function fetch_kb_tools { 45 | header_text "fetching tools" 46 | mkdir -p $tmp_root 47 | kb_tools_archive_name="kubebuilder-tools-$k8s_version-$goos-$goarch.tar.gz" 48 | kb_tools_download_url="https://storage.googleapis.com/kubebuilder-tools/$kb_tools_archive_name" 49 | 50 | kb_tools_archive_path="$tmp_root/$kb_tools_archive_name" 51 | if [ ! -f $kb_tools_archive_path ]; then 52 | curl -sL ${kb_tools_download_url} -o "$kb_tools_archive_path" 53 | fi 54 | tar -zvxf "$kb_tools_archive_path" -C "$tmp_root/" 55 | } 56 | 57 | header_text "using tools" 58 | fetch_kb_tools 59 | 60 | header_text "kubebuilder tools (etcd, kubectl, kube-apiserver)used to perform local tests installed under $tmp_root/kubebuilder/bin/" 61 | exit 0 -------------------------------------------------------------------------------- /testdata/alidns/README.md: -------------------------------------------------------------------------------- 1 | # Solver testdata directory 2 | 3 | ```json 4 | { 5 | "accessKeyId": "your aliyun accessKeyId", 6 | "accessKeySecret": "your aliyun accessKeySecret", 7 | "regionId": "your region id", 8 | "ttl": 600 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /testdata/alidns/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "accessKeyId": "your aliyun accessKeyId", 3 | "accessKeySecret": "your aliyun accessKeySecret", 4 | "regionId": "your region id", 5 | "ttl": 600 6 | } --------------------------------------------------------------------------------