├── .github └── workflows │ ├── release-charts.yml │ └── release-docker.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── charts └── alidns-webhook │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── apiservice.yaml │ ├── deployment.yaml │ ├── pki.yaml │ ├── rbac.yaml │ └── service.yaml │ └── values.yaml ├── go.mod ├── go.sum ├── main.go ├── main_test.go └── testdata └── alidns-solver ├── alidns-secret.yaml └── config.json /.github/workflows/release-charts.yml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Configure Git 18 | run: | 19 | git config user.name "$GITHUB_ACTOR" 20 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 21 | 22 | - name: Run chart-releaser 23 | uses: helm/chart-releaser-action@v1.0.0 24 | env: 25 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -------------------------------------------------------------------------------- /.github/workflows/release-docker.yml: -------------------------------------------------------------------------------- 1 | name: Release Image 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | main: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Inject slug/short variables 14 | uses: rlespinasse/github-slug-action@v3.x 15 | - name: Setup Go 16 | uses: actions/setup-go@v2 17 | with: 18 | go-version: '1.20' 19 | #- name: Tests 20 | # run: | 21 | # go version 22 | # scripts/fetch-test-binaries.sh 23 | # TEST_ZONE_NAME=example.com. go test . 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v1 26 | - name: Log in to GitHub Docker Registry 27 | uses: docker/login-action@v1 28 | with: 29 | registry: ghcr.io 30 | username: ${{ github.actor }} 31 | password: ${{ secrets.GITHUB_TOKEN }} 32 | logout: true 33 | - name: Build and push 34 | id: docker_build 35 | uses: docker/build-push-action@v6 36 | with: 37 | platforms: linux/amd64,linux/arm64 38 | push: true 39 | tags: ghcr.io/${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG }}/${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG }}/cert-manager-alidns-webhook:${{ env.GITHUB_REF_SLUG }} 40 | -------------------------------------------------------------------------------- /.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 | .idea 15 | kubebuilder 16 | 17 | testdata/alidns-solver/alidns-secret.yaml 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20.0-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 | OS ?= $(shell go env GOOS) 2 | ARCH ?= $(shell go env GOARCH) 3 | 4 | IMAGE_NAME := "webhook" 5 | IMAGE_TAG := "latest" 6 | 7 | OUT := $(shell pwd)/_out 8 | 9 | KUBE_VERSION=1.30.0 10 | 11 | $(shell mkdir -p "$(OUT)") 12 | export TEST_ASSET_ETCD=_test/kubebuilder/bin/etcd 13 | export TEST_ASSET_KUBE_APISERVER=_test/kubebuilder/bin/kube-apiserver 14 | export TEST_ASSET_KUBECTL=_test/kubebuilder/bin/kubectl 15 | 16 | test: _test/kubebuilder 17 | go test -v . 18 | 19 | _test/kubebuilder: 20 | curl -fsSL https://go.kubebuilder.io/test-tools/$(KUBE_VERSION)/$(OS)/$(ARCH) -o kubebuilder-tools.tar.gz 21 | mkdir -p _test/kubebuilder 22 | tar -xvf kubebuilder-tools.tar.gz 23 | mv kubebuilder/bin _test/kubebuilder/ 24 | rm kubebuilder-tools.tar.gz 25 | rm -R kubebuilder 26 | 27 | clean: clean-kubebuilder 28 | 29 | clean-kubebuilder: 30 | rm -Rf _test/kubebuilder 31 | 32 | build: 33 | docker build -t "$(IMAGE_NAME):$(IMAGE_TAG)" . 34 | 35 | .PHONY: rendered-manifest.yaml 36 | rendered-manifest.yaml: 37 | helm template \ 38 | --name alidns-webhook \ 39 | --set image.repository=$(IMAGE_NAME) \ 40 | --set image.tag=$(IMAGE_TAG) \ 41 | deploy/alidns-webhook > "$(OUT)/rendered-manifest.yaml" 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alibaba Cloud DNS ACME webhook 2 | 3 | This project is based on code initialy commited in https://github.com/go-acme/lego 4 | 5 | This is an webhook implementation for Cert-Manager to use with Alibaba Cloud DNS (aka AliDNS). 6 | See the cert-manager's documentation for more details on webhook : https://cert-manager.io/docs/concepts/webhook/ 7 | 8 | ## Usage 9 | ### Installation 10 | 11 | ``` 12 | helm repo add cert-manager-alidns-webhook https://devmachine-fr.github.io/cert-manager-alidns-webhook 13 | helm repo update 14 | helm install alidns-webhook cert-manager-alidns-webhook/alidns-webhook 15 | ``` 16 | 17 | Create the secret holding alibaba credential, access-token need input AccessKeyId, secret-key need input AccessKeySecret: 18 | ``` 19 | kubectl create secret generic alidns-secrets --from-literal="access-token=yourtoken" --from-literal="secret-key=yoursecretkey" 20 | ``` 21 | 22 | ### Create an issuer 23 | 24 | The name of solver to use is `alidns-solver`. You can create an issuer as below : 25 | ``` 26 | apiVersion: cert-manager.io/v1 27 | kind: Issuer 28 | metadata: 29 | name: letsencrypt 30 | namespace: default 31 | spec: 32 | acme: 33 | email: contact@example.com 34 | privateKeySecretRef: 35 | name: letsencrypt 36 | server: https://acme-staging-v02.api.letsencrypt.org/directory 37 | solvers: 38 | - dns01: 39 | webhook: 40 | config: 41 | accessTokenSecretRef: 42 | key: access-token 43 | name: alidns-secrets 44 | regionId: cn-beijing 45 | secretKeySecretRef: 46 | key: secret-key 47 | name: alidns-secrets 48 | groupName: example.com 49 | solverName: alidns-solver 50 | selector: 51 | dnsNames: 52 | - example.com 53 | - '*.example.com' 54 | ``` 55 | 56 | Or you can create an ClusterIssuer as below : 57 | ``` 58 | apiVersion: cert-manager.io/v1 59 | kind: ClusterIssuer 60 | metadata: 61 | name: letsencrypt 62 | spec: 63 | acme: 64 | email: contact@example.com 65 | server: https://acme-staging-v02.api.letsencrypt.org/directory 66 | privateKeySecretRef: 67 | name: letsencrypt 68 | solvers: 69 | - dns01: 70 | webhook: 71 | config: 72 | accessTokenSecretRef: 73 | key: access-token 74 | name: alidns-secrets 75 | regionId: cn-beijing 76 | secretKeySecretRef: 77 | key: secret-key 78 | name: alidns-secrets 79 | groupName: example.com # groupName must match the one configured on webhook deployment (see Helm chart's values) ! 80 | solverName: alidns-solver 81 | ``` 82 | 83 | See cert-manager documentation for more information : https://cert-manager.io/docs/configuration/acme/dns01/ 84 | 85 | ### Create the certification 86 | 87 | Then create the certificate which will use this issuer : https://cert-manager.io/docs/usage/certificate/ 88 | 89 | 90 | Create an certification using Issuer as below : 91 | ``` 92 | apiVersion: cert-manager.io/v1 93 | kind: Certificate 94 | metadata: 95 | name: example-tls 96 | spec: 97 | secretName: example-com-tls 98 | commonName: example.com 99 | dnsNames: 100 | - example.com 101 | - "*.example.com" 102 | issuerRef: 103 | name: letsencrypt 104 | kind: Issuer 105 | ``` 106 | 107 | Or create an certification using ClusterIssuer as below : 108 | ``` 109 | apiVersion: cert-manager.io/v1 110 | kind: Certificate 111 | metadata: 112 | name: example-tls 113 | spec: 114 | secretName: example-com-tls 115 | commonName: example.com 116 | dnsNames: 117 | - example.com 118 | - "*.example.com" 119 | issuerRef: 120 | name: letsencrypt 121 | kind: ClusterIssuer 122 | ``` 123 | 124 | 125 | 126 | ## Tests 127 | 128 | Modify testdata/alidns-solver to add a valid token for alidns. 129 | 130 | ``` 131 | # replace example.com with a zone which belongs to given credentials 132 | TEST_ASSET_ETCD=kubebuilder/bin/etcd TEST_ASSET_KUBE_APISERVER=kubebuilder/bin/kube-apiserver TEST_ASSET_KUBECTL=kubebuilder/bin/kubectl TEST_ZONE_NAME=example.com. make test . 133 | ``` 134 | 135 | ## Build 136 | 137 | Build and publish the docker image: 138 | ``` 139 | docker build . -t /alidns-webhook:latest 140 | docker push /alidns-webhook 141 | ``` 142 | 143 | Use the helm chart in charts directory. 144 | ``` 145 | helm template charts --set image.repository= --set image.tag=latest 146 | ``` 147 | -------------------------------------------------------------------------------- /charts/alidns-webhook/.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 | -------------------------------------------------------------------------------- /charts/alidns-webhook/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "0.8.3" 3 | description: Deploys alidns webhook for cert-manager. 4 | name: alidns-webhook 5 | version: 0.8.3 6 | -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DEVmachine-fr/cert-manager-alidns-webhook/50949b9985c5dd8714dcc3880832c8373adc883b/charts/alidns-webhook/templates/NOTES.txt -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "alidns-webhook.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 "alidns-webhook.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 "alidns-webhook.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{- define "alidns-webhook.selfSignedIssuer" -}} 35 | {{ printf "%s-selfsign" (include "alidns-webhook.fullname" .) }} 36 | {{- end -}} 37 | 38 | {{- define "alidns-webhook.rootCAIssuer" -}} 39 | {{ printf "%s-ca" (include "alidns-webhook.fullname" .) }} 40 | {{- end -}} 41 | 42 | {{- define "alidns-webhook.rootCACertificate" -}} 43 | {{ printf "%s-ca" (include "alidns-webhook.fullname" .) }} 44 | {{- end -}} 45 | 46 | {{- define "alidns-webhook.servingCertificate" -}} 47 | {{ printf "%s-webhook-tls" (include "alidns-webhook.fullname" .) }} 48 | {{- end -}} 49 | -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/apiservice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiregistration.k8s.io/v1 2 | kind: APIService 3 | metadata: 4 | name: v1alpha1.{{ .Values.groupName }} 5 | labels: 6 | app: {{ include "alidns-webhook.name" . }} 7 | chart: {{ include "alidns-webhook.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | annotations: 11 | cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/{{ include "alidns-webhook.servingCertificate" . }}" 12 | spec: 13 | group: {{ .Values.groupName }} 14 | groupPriorityMinimum: 1000 15 | versionPriority: 15 16 | service: 17 | name: {{ include "alidns-webhook.fullname" . }} 18 | namespace: {{ .Release.Namespace }} 19 | version: v1alpha1 20 | -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "alidns-webhook.fullname" . }} 5 | labels: 6 | app: {{ include "alidns-webhook.name" . }} 7 | chart: {{ include "alidns-webhook.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.replicaCount }} 12 | selector: 13 | matchLabels: 14 | app: {{ include "alidns-webhook.name" . }} 15 | release: {{ .Release.Name }} 16 | template: 17 | metadata: 18 | labels: 19 | app: {{ include "alidns-webhook.name" . }} 20 | release: {{ .Release.Name }} 21 | spec: 22 | serviceAccountName: {{ include "alidns-webhook.fullname" . }} 23 | {{- with .Values.securityContext }} 24 | securityContext: 25 | {{- . | toYaml | nindent 8 }} 26 | {{- end }} 27 | containers: 28 | - name: {{ .Chart.Name }} 29 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 30 | imagePullPolicy: {{ .Values.image.pullPolicy }} 31 | args: 32 | - --tls-cert-file=/tls/tls.crt 33 | - --tls-private-key-file=/tls/tls.key 34 | - --secure-port={{ .Values.securePort }} 35 | env: 36 | - name: GROUP_NAME 37 | value: {{ .Values.groupName | quote }} 38 | {{- if .Values.extraEnv }} 39 | {{- toYaml .Values.extraEnv | nindent 12 }} 40 | {{- end }} 41 | ports: 42 | - name: https 43 | containerPort: {{ .Values.securePort }} 44 | protocol: TCP 45 | livenessProbe: 46 | httpGet: 47 | scheme: HTTPS 48 | path: /healthz 49 | port: https 50 | readinessProbe: 51 | httpGet: 52 | scheme: HTTPS 53 | path: /healthz 54 | port: https 55 | volumeMounts: 56 | - name: certs 57 | mountPath: /tls 58 | readOnly: true 59 | resources: 60 | {{ toYaml .Values.resources | indent 12 }} 61 | {{ if .Values.image.privateRegistry.enabled }} 62 | imagePullSecrets: 63 | - name: {{ .Values.image.privateRegistry.dockerRegistrySecret }} 64 | {{ end }} 65 | volumes: 66 | - name: certs 67 | secret: 68 | secretName: {{ include "alidns-webhook.servingCertificate" . }} 69 | {{- with .Values.nodeSelector }} 70 | nodeSelector: 71 | {{ toYaml . | indent 8 }} 72 | {{- end }} 73 | {{- with .Values.affinity }} 74 | affinity: 75 | {{ toYaml . | indent 8 }} 76 | {{- end }} 77 | {{- with .Values.tolerations }} 78 | tolerations: 79 | {{ toYaml . | indent 8 }} 80 | {{- end }} 81 | -------------------------------------------------------------------------------- /charts/alidns-webhook/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: cert-manager.io/v1 5 | kind: Issuer 6 | metadata: 7 | name: {{ include "alidns-webhook.selfSignedIssuer" . }} 8 | namespace: {{ .Release.Namespace | quote }} 9 | labels: 10 | app: {{ include "alidns-webhook.name" . }} 11 | chart: {{ include "alidns-webhook.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: cert-manager.io/v1 21 | kind: Certificate 22 | metadata: 23 | name: {{ include "alidns-webhook.rootCACertificate" . }} 24 | namespace: {{ .Release.Namespace | quote }} 25 | labels: 26 | app: {{ include "alidns-webhook.name" . }} 27 | chart: {{ include "alidns-webhook.chart" . }} 28 | release: {{ .Release.Name }} 29 | heritage: {{ .Release.Service }} 30 | spec: 31 | secretName: {{ include "alidns-webhook.rootCACertificate" . }} 32 | duration: 43800h0m0s # 5y 33 | issuerRef: 34 | name: {{ include "alidns-webhook.selfSignedIssuer" . }} 35 | commonName: "ca.alidns-webhook.cert-manager" 36 | isCA: true 37 | 38 | --- 39 | 40 | # Create an Issuer that uses the above generated CA certificate to issue certs 41 | apiVersion: cert-manager.io/v1 42 | kind: Issuer 43 | metadata: 44 | name: {{ include "alidns-webhook.rootCAIssuer" . }} 45 | namespace: {{ .Release.Namespace | quote }} 46 | labels: 47 | app: {{ include "alidns-webhook.name" . }} 48 | chart: {{ include "alidns-webhook.chart" . }} 49 | release: {{ .Release.Name }} 50 | heritage: {{ .Release.Service }} 51 | spec: 52 | ca: 53 | secretName: {{ include "alidns-webhook.rootCACertificate" . }} 54 | 55 | --- 56 | 57 | # Finally, generate a serving certificate for the webhook to use 58 | apiVersion: cert-manager.io/v1 59 | kind: Certificate 60 | metadata: 61 | name: {{ include "alidns-webhook.servingCertificate" . }} 62 | namespace: {{ .Release.Namespace | quote }} 63 | labels: 64 | app: {{ include "alidns-webhook.name" . }} 65 | chart: {{ include "alidns-webhook.chart" . }} 66 | release: {{ .Release.Name }} 67 | heritage: {{ .Release.Service }} 68 | spec: 69 | secretName: {{ include "alidns-webhook.servingCertificate" . }} 70 | duration: 8760h0m0s # 1y 71 | issuerRef: 72 | name: {{ include "alidns-webhook.rootCAIssuer" . }} 73 | dnsNames: 74 | - {{ include "alidns-webhook.fullname" . }} 75 | - {{ include "alidns-webhook.fullname" . }}.{{ .Release.Namespace }} 76 | - {{ include "alidns-webhook.fullname" . }}.{{ .Release.Namespace }}.svc 77 | -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "alidns-webhook.fullname" . }} 5 | labels: 6 | app: {{ include "alidns-webhook.name" . }} 7 | chart: {{ include "alidns-webhook.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | --- 11 | # Grant permissions to read secrets inside the cluster to allow to have issuer in another namespace than the webhook 12 | apiVersion: rbac.authorization.k8s.io/v1 13 | kind: ClusterRole 14 | metadata: 15 | name: {{ include "alidns-webhook.fullname" . }}:secrets-reader 16 | labels: 17 | app: {{ include "alidns-webhook.name" . }} 18 | chart: {{ include "alidns-webhook.chart" . }} 19 | release: {{ .Release.Name }} 20 | heritage: {{ .Release.Service }} 21 | rules: 22 | - apiGroups: 23 | - '' 24 | resources: 25 | - 'secrets' 26 | verbs: 27 | - 'get' 28 | --- 29 | # Bind the previously created role to the webhook service account to allow reading from secrets in all namespaces 30 | apiVersion: rbac.authorization.k8s.io/v1 31 | kind: ClusterRoleBinding 32 | metadata: 33 | name: {{ include "alidns-webhook.fullname" . }}:secrets-reader 34 | labels: 35 | app: {{ include "alidns-webhook.name" . }} 36 | chart: {{ include "alidns-webhook.chart" . }} 37 | release: {{ .Release.Name }} 38 | heritage: {{ .Release.Service }} 39 | roleRef: 40 | apiGroup: rbac.authorization.k8s.io 41 | kind: ClusterRole 42 | name: {{ include "alidns-webhook.fullname" . }}:secrets-reader 43 | subjects: 44 | - apiGroup: "" 45 | kind: ServiceAccount 46 | name: {{ include "alidns-webhook.fullname" . }} 47 | namespace: {{ .Release.Namespace }} 48 | --- 49 | # Grant the webhook permission to read the ConfigMap containing the Kubernetes 50 | # apiserver's requestheader-ca-certificate. 51 | # This ConfigMap is automatically created by the Kubernetes apiserver. 52 | apiVersion: rbac.authorization.k8s.io/v1 53 | kind: RoleBinding 54 | metadata: 55 | name: {{ include "alidns-webhook.fullname" . }}:webhook-authentication-reader 56 | namespace: kube-system 57 | labels: 58 | app: {{ include "alidns-webhook.name" . }} 59 | chart: {{ include "alidns-webhook.chart" . }} 60 | release: {{ .Release.Name }} 61 | heritage: {{ .Release.Service }} 62 | roleRef: 63 | apiGroup: rbac.authorization.k8s.io 64 | kind: Role 65 | name: extension-apiserver-authentication-reader 66 | subjects: 67 | - apiGroup: "" 68 | kind: ServiceAccount 69 | name: {{ include "alidns-webhook.fullname" . }} 70 | namespace: {{ .Release.Namespace }} 71 | --- 72 | # apiserver gets the auth-delegator role to delegate auth decisions to 73 | # the core apiserver 74 | apiVersion: rbac.authorization.k8s.io/v1 75 | kind: ClusterRoleBinding 76 | metadata: 77 | name: {{ include "alidns-webhook.fullname" . }}:auth-delegator 78 | labels: 79 | app: {{ include "alidns-webhook.name" . }} 80 | chart: {{ include "alidns-webhook.chart" . }} 81 | release: {{ .Release.Name }} 82 | heritage: {{ .Release.Service }} 83 | roleRef: 84 | apiGroup: rbac.authorization.k8s.io 85 | kind: ClusterRole 86 | name: system:auth-delegator 87 | subjects: 88 | - apiGroup: "" 89 | kind: ServiceAccount 90 | name: {{ include "alidns-webhook.fullname" . }} 91 | namespace: {{ .Release.Namespace }} 92 | --- 93 | # Grant cert-manager permission to validate using our apiserver 94 | apiVersion: rbac.authorization.k8s.io/v1 95 | kind: ClusterRole 96 | metadata: 97 | name: {{ include "alidns-webhook.fullname" . }}:domain-solver 98 | labels: 99 | app: {{ include "alidns-webhook.name" . }} 100 | chart: {{ include "alidns-webhook.chart" . }} 101 | release: {{ .Release.Name }} 102 | heritage: {{ .Release.Service }} 103 | rules: 104 | - apiGroups: 105 | - {{ .Values.groupName }} 106 | resources: 107 | - '*' 108 | verbs: 109 | - 'create' 110 | --- 111 | apiVersion: rbac.authorization.k8s.io/v1 112 | kind: ClusterRoleBinding 113 | metadata: 114 | name: {{ include "alidns-webhook.fullname" . }}:domain-solver 115 | labels: 116 | app: {{ include "alidns-webhook.name" . }} 117 | chart: {{ include "alidns-webhook.chart" . }} 118 | release: {{ .Release.Name }} 119 | heritage: {{ .Release.Service }} 120 | roleRef: 121 | apiGroup: rbac.authorization.k8s.io 122 | kind: ClusterRole 123 | name: {{ include "alidns-webhook.fullname" . }}:domain-solver 124 | subjects: 125 | - apiGroup: "" 126 | kind: ServiceAccount 127 | name: {{ .Values.certManager.serviceAccountName }} 128 | namespace: {{ .Values.certManager.namespace }} 129 | -------------------------------------------------------------------------------- /charts/alidns-webhook/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "alidns-webhook.fullname" . }} 5 | labels: 6 | app: {{ include "alidns-webhook.name" . }} 7 | chart: {{ include "alidns-webhook.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | type: {{ .Values.service.type }} 12 | ports: 13 | - port: {{ .Values.service.port }} 14 | targetPort: https 15 | protocol: TCP 16 | name: https 17 | selector: 18 | app: {{ include "alidns-webhook.name" . }} 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /charts/alidns-webhook/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 must match the one set in issuer ! 10 | groupName: example.com 11 | 12 | certManager: 13 | namespace: cert-manager 14 | serviceAccountName: cert-manager 15 | 16 | image: 17 | repository: ghcr.io/devmachine-fr/cert-manager-alidns-webhook/cert-manager-alidns-webhook 18 | tag: 0.3.1 19 | pullPolicy: IfNotPresent 20 | privateRegistry: 21 | enabled: false 22 | dockerRegistrySecret: alibaba-container-registry 23 | 24 | nameOverride: "" 25 | fullnameOverride: "" 26 | 27 | securePort: 443 28 | 29 | service: 30 | type: ClusterIP 31 | port: 443 32 | 33 | resources: 34 | {} 35 | # We usually recommend not to specify default resources and to leave this as a conscious 36 | # choice for the user. This also increases chances charts run on environments with little 37 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 38 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 39 | # limits: 40 | # cpu: 100m 41 | # memory: 128Mi 42 | # requests: 43 | # cpu: 100m 44 | # memory: 128Mi 45 | 46 | nodeSelector: {} 47 | 48 | tolerations: [] 49 | 50 | affinity: {} 51 | 52 | 53 | # Optional additional envs for the webhook container 54 | extraEnv: [] 55 | # - name: ALIDNS_WEBHOOK_ENV_VAR_1 56 | # value: "env_var_1" 57 | # - name: ALIDNS_WEBHOOK_ENV_VAR_2 58 | # value: "env_var_2" 59 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/olivierboudet/cert-manager-alidns-webhook 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/aliyun/alibaba-cloud-sdk-go v1.62.737 7 | github.com/cert-manager/cert-manager v1.14.5 8 | github.com/pkg/errors v0.9.1 9 | k8s.io/apiextensions-apiserver v0.29.0 10 | k8s.io/apimachinery v0.29.0 11 | k8s.io/client-go v0.29.0 12 | ) 13 | 14 | require ( 15 | github.com/NYTimes/gziphandler v1.1.1 // indirect 16 | github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect 17 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 18 | github.com/beorn7/perks v1.0.1 // indirect 19 | github.com/blang/semver/v4 v4.0.0 // indirect 20 | github.com/cenkalti/backoff/v4 v4.2.1 // indirect 21 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 22 | github.com/coreos/go-semver v0.3.1 // indirect 23 | github.com/coreos/go-systemd/v22 v22.5.0 // indirect 24 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 25 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 26 | github.com/evanphx/json-patch v5.7.0+incompatible // indirect 27 | github.com/evanphx/json-patch/v5 v5.7.0 // indirect 28 | github.com/felixge/httpsnoop v1.0.4 // indirect 29 | github.com/fsnotify/fsnotify v1.7.0 // indirect 30 | github.com/go-logr/logr v1.4.1 // indirect 31 | github.com/go-logr/stdr v1.2.2 // indirect 32 | github.com/go-logr/zapr v1.3.0 // indirect 33 | github.com/go-openapi/jsonpointer v0.20.2 // indirect 34 | github.com/go-openapi/jsonreference v0.20.4 // indirect 35 | github.com/go-openapi/swag v0.22.7 // indirect 36 | github.com/gogo/protobuf v1.3.2 // indirect 37 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 38 | github.com/golang/protobuf v1.5.3 // indirect 39 | github.com/google/cel-go v0.17.7 // indirect 40 | github.com/google/gnostic-models v0.6.8 // indirect 41 | github.com/google/go-cmp v0.6.0 // indirect 42 | github.com/google/gofuzz v1.2.0 // indirect 43 | github.com/google/uuid v1.5.0 // indirect 44 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect 45 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect 46 | github.com/imdario/mergo v0.3.16 // indirect 47 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 48 | github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect 49 | github.com/josharian/intern v1.0.0 // indirect 50 | github.com/json-iterator/go v1.1.12 // indirect 51 | github.com/mailru/easyjson v0.7.7 // indirect 52 | github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect 53 | github.com/miekg/dns v1.1.57 // indirect 54 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 55 | github.com/modern-go/reflect2 v1.0.2 // indirect 56 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 57 | github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect 58 | github.com/prometheus/client_golang v1.18.0 // indirect 59 | github.com/prometheus/client_model v0.5.0 // indirect 60 | github.com/prometheus/common v0.45.0 // indirect 61 | github.com/prometheus/procfs v0.12.0 // indirect 62 | github.com/spf13/cobra v1.8.0 // indirect 63 | github.com/spf13/pflag v1.0.5 // indirect 64 | github.com/stoewer/go-strcase v1.3.0 // indirect 65 | go.etcd.io/etcd/api/v3 v3.5.11 // indirect 66 | go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect 67 | go.etcd.io/etcd/client/v3 v3.5.11 // indirect 68 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect 69 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect 70 | go.opentelemetry.io/otel v1.21.0 // indirect 71 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect 72 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect 73 | go.opentelemetry.io/otel/metric v1.21.0 // indirect 74 | go.opentelemetry.io/otel/sdk v1.21.0 // indirect 75 | go.opentelemetry.io/otel/trace v1.21.0 // indirect 76 | go.opentelemetry.io/proto/otlp v1.0.0 // indirect 77 | go.uber.org/multierr v1.11.0 // indirect 78 | go.uber.org/zap v1.26.0 // indirect 79 | golang.org/x/crypto v0.22.0 // indirect 80 | golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect 81 | golang.org/x/mod v0.14.0 // indirect 82 | golang.org/x/net v0.24.0 // indirect 83 | golang.org/x/oauth2 v0.15.0 // indirect 84 | golang.org/x/sync v0.5.0 // indirect 85 | golang.org/x/sys v0.19.0 // indirect 86 | golang.org/x/term v0.19.0 // indirect 87 | golang.org/x/text v0.14.0 // indirect 88 | golang.org/x/time v0.5.0 // indirect 89 | golang.org/x/tools v0.16.1 // indirect 90 | google.golang.org/appengine v1.6.8 // indirect 91 | google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect 92 | google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect 93 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect 94 | google.golang.org/grpc v1.60.1 // indirect 95 | google.golang.org/protobuf v1.33.0 // indirect 96 | gopkg.in/inf.v0 v0.9.1 // indirect 97 | gopkg.in/ini.v1 v1.67.0 // indirect 98 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 99 | gopkg.in/yaml.v2 v2.4.0 // indirect 100 | gopkg.in/yaml.v3 v3.0.1 // indirect 101 | k8s.io/api v0.29.0 // indirect 102 | k8s.io/apiserver v0.29.0 // indirect 103 | k8s.io/component-base v0.29.0 // indirect 104 | k8s.io/klog/v2 v2.110.1 // indirect 105 | k8s.io/kms v0.29.0 // indirect 106 | k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 // indirect 107 | k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect 108 | sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect 109 | sigs.k8s.io/controller-runtime v0.16.3 // indirect 110 | sigs.k8s.io/gateway-api v1.0.0 // indirect 111 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 112 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 113 | sigs.k8s.io/yaml v1.4.0 // indirect 114 | ) 115 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= 2 | cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= 3 | cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= 4 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 6 | github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= 7 | github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= 8 | github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= 9 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 10 | github.com/aliyun/alibaba-cloud-sdk-go v1.62.737 h1:ZJQHOp8O0RpldZ8XQwCSlpiDMkiYwcqi1rTAs/7oxQY= 11 | github.com/aliyun/alibaba-cloud-sdk-go v1.62.737/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= 12 | github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= 13 | github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= 14 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= 15 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 16 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 17 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 18 | github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= 19 | github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= 20 | github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= 21 | github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 22 | github.com/cert-manager/cert-manager v1.14.5 h1:uuM1O2g2S80nxiH3eW2cZYMGiL2zmDFVdAzg8sibWuc= 23 | github.com/cert-manager/cert-manager v1.14.5/go.mod h1:fmr/cU5jiLxWj69CroDggSOa49RljUK+dU583TaQUXM= 24 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 25 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 26 | github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= 27 | github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= 28 | github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= 29 | github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= 30 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 31 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 32 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 33 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 34 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 35 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 36 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 37 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 38 | github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= 39 | github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 40 | github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= 41 | github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= 42 | github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 43 | github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= 44 | github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= 45 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 46 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 47 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 48 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 49 | github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 50 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 51 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 52 | github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 53 | github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 54 | github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 55 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 56 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 57 | github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= 58 | github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= 59 | github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= 60 | github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= 61 | github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= 62 | github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= 63 | github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= 64 | github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= 65 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 66 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 67 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 68 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 69 | github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= 70 | github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= 71 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 72 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 73 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 74 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 75 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 76 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 77 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 78 | github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= 79 | github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= 80 | github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= 81 | github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= 82 | github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 83 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 84 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 85 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 86 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 87 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 88 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 89 | github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= 90 | github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 91 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= 92 | github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= 93 | github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 94 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 95 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= 96 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= 97 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 98 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= 99 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= 100 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= 101 | github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= 102 | github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= 103 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 104 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 105 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 106 | github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= 107 | github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 108 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 109 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 110 | github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= 111 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 112 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 113 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 114 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 115 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 116 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 117 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 118 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 119 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 120 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 121 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 122 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 123 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 124 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 125 | github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= 126 | github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 127 | github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= 128 | github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= 129 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 130 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 131 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 132 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 133 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 134 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 135 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 136 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 137 | github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= 138 | github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= 139 | github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= 140 | github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= 141 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 142 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 143 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 144 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 145 | github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= 146 | github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= 147 | github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= 148 | github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 149 | github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= 150 | github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= 151 | github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= 152 | github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= 153 | github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= 154 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 155 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 156 | github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= 157 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= 158 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 159 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 160 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 161 | github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= 162 | github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= 163 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 164 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 165 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 166 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 167 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 168 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 169 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 170 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 171 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 172 | github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= 173 | github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= 174 | github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= 175 | github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= 176 | github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= 177 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= 178 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 179 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 180 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 181 | go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= 182 | go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E= 183 | go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= 184 | go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A= 185 | go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= 186 | go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= 187 | go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU= 188 | go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE= 189 | go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= 190 | go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= 191 | go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= 192 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= 193 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= 194 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= 195 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= 196 | go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= 197 | go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= 198 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= 199 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= 200 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= 201 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= 202 | go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= 203 | go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= 204 | go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= 205 | go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= 206 | go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= 207 | go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= 208 | go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= 209 | go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 210 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 211 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= 212 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 213 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 214 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 215 | go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= 216 | go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= 217 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 218 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 219 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 220 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 221 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 222 | golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= 223 | golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 224 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 225 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 226 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 227 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 228 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 229 | golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= 230 | golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= 231 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 232 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 233 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 234 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 235 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 236 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 237 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 238 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 239 | golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= 240 | golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 241 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 242 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 243 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 244 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 245 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 246 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 247 | golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= 248 | golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 249 | golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= 250 | golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= 251 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 252 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 253 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 254 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 255 | golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= 256 | golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 257 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 258 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 259 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 260 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 261 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 262 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 263 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 264 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 265 | golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= 266 | golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 267 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 268 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 269 | golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= 270 | golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 271 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 272 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 273 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 274 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 275 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 276 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 277 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= 278 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 279 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 280 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 281 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 282 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 283 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 284 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 285 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 286 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 287 | golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= 288 | golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 289 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 290 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 291 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 292 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 293 | gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= 294 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 295 | gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= 296 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 297 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 298 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= 299 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 300 | google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= 301 | google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= 302 | google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= 303 | google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= 304 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= 305 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= 306 | google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= 307 | google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= 308 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 309 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 310 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 311 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 312 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 313 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 314 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 315 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 316 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 317 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 318 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 319 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= 320 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 321 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 322 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 323 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 324 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 325 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 326 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 327 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 328 | k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= 329 | k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= 330 | k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= 331 | k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= 332 | k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= 333 | k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= 334 | k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= 335 | k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= 336 | k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= 337 | k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= 338 | k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= 339 | k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= 340 | k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= 341 | k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= 342 | k8s.io/kms v0.29.0 h1:KJ1zaZt74CgvgV3NR7tnURJ/mJOKC5X3nwon/WdwgxI= 343 | k8s.io/kms v0.29.0/go.mod h1:mB0f9HLxRXeXUfHfn1A7rpwOlzXI1gIWu86z6buNoYA= 344 | k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 h1:avRdiaB03v88Mfvum2S3BBwkNuTlmuar4LlfO9Hajko= 345 | k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022/go.mod h1:sIV51WBTkZrlGOJMCDZDA1IaPBUDTulPpD4y7oe038k= 346 | k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= 347 | k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 348 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 349 | sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= 350 | sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= 351 | sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= 352 | sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= 353 | sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= 354 | sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= 355 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= 356 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= 357 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= 358 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= 359 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= 360 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 361 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | 8 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 9 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" 10 | "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" 11 | "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" 12 | 13 | "os" 14 | "strings" 15 | 16 | "github.com/pkg/errors" 17 | 18 | extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | "k8s.io/client-go/kubernetes" 21 | "k8s.io/client-go/rest" 22 | 23 | "github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" 24 | "github.com/cert-manager/cert-manager/pkg/acme/webhook/cmd" 25 | cmmetav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" 26 | "github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util" 27 | ) 28 | 29 | var GroupName = os.Getenv("GROUP_NAME") 30 | 31 | func main() { 32 | if GroupName == "" { 33 | panic("GROUP_NAME must be specified") 34 | } 35 | 36 | // This will register our custom DNS provider with the webhook serving 37 | // library, making it available as an API under the provided GroupName. 38 | // You can register multiple DNS provider implementations with a single 39 | // webhook, where the Name() method will be used to disambiguate between 40 | // the different implementations. 41 | cmd.RunWebhookServer(GroupName, 42 | &aliDNSProviderSolver{}, 43 | ) 44 | } 45 | 46 | // customDNSProviderSolver implements the provider-specific logic needed to 47 | // 'present' an ACME challenge TXT record for your own DNS provider. 48 | // To do so, it must implement the `github.com/cert-manager/cert-manager/pkg/acme/webhook.Solver` 49 | // interface. 50 | type aliDNSProviderSolver struct { 51 | // If a Kubernetes 'clientset' is needed, you must: 52 | // 1. uncomment the additional `client` field in this structure below 53 | // 2. uncomment the "k8s.io/client-go/kubernetes" import at the top of the file 54 | // 3. uncomment the relevant code in the Initialize method below 55 | // 4. ensure your webhook's service account has the required RBAC role 56 | // assigned to it for interacting with the Kubernetes APIs you need. 57 | client *kubernetes.Clientset 58 | aliDNSClient *alidns.Client 59 | } 60 | 61 | // customDNSProviderConfig is a structure that is used to decode into when 62 | // solving a DNS01 challenge. 63 | // This information is provided by cert-manager, and may be a reference to 64 | // additional configuration that's needed to solve the challenge for this 65 | // particular certificate or issuer. 66 | // This typically includes references to Secret resources containing DNS 67 | // provider credentials, in cases where a 'multi-tenant' DNS solver is being 68 | // created. 69 | // If you do *not* require per-issuer or per-certificate configuration to be 70 | // provided to your webhook, you can skip decoding altogether in favour of 71 | // using CLI flags or similar to provide configuration. 72 | // You should not include sensitive information here. If credentials need to 73 | // be used by your provider here, you should reference a Kubernetes Secret 74 | // resource and fetch these credentials using a Kubernetes clientset. 75 | type aliDNSProviderConfig struct { 76 | // Change the two fields below according to the format of the configuration 77 | // to be decoded. 78 | // These fields will be set by users in the 79 | // `issuer.spec.acme.dns01.providers.webhook.config` field. 80 | 81 | AccessToken cmmetav1.SecretKeySelector `json:"accessTokenSecretRef"` 82 | SecretToken cmmetav1.SecretKeySelector `json:"secretKeySecretRef"` 83 | Regionid string `json:"regionId"` 84 | } 85 | 86 | // Name is used as the name for this DNS solver when referencing it on the ACME 87 | // Issuer resource. 88 | // This should be unique **within the group name**, i.e. you can have two 89 | // solvers configured with the same Name() **so long as they do not co-exist 90 | // within a single webhook deployment**. 91 | // For example, `cloudflare` may be used as the name of a solver. 92 | func (c *aliDNSProviderSolver) Name() string { 93 | return "alidns-solver" 94 | } 95 | 96 | // Present is responsible for actually presenting the DNS record with the 97 | // DNS provider. 98 | // This method should tolerate being called multiple times with the same value. 99 | // cert-manager itself will later perform a self check to ensure that the 100 | // solver has correctly configured the DNS provider. 101 | func (c *aliDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error { 102 | cfg, err := loadConfig(ch.Config) 103 | if err != nil { 104 | return err 105 | } 106 | 107 | // TODO: do something more useful with the decoded configuration 108 | fmt.Printf("Decoded configuration: %v\n", cfg) 109 | 110 | accessToken, err := c.loadSecretData(cfg.AccessToken, ch.ResourceNamespace) 111 | if err != nil { 112 | return err 113 | } 114 | secretKey, err := c.loadSecretData(cfg.SecretToken, ch.ResourceNamespace) 115 | if err != nil { 116 | return err 117 | } 118 | 119 | conf := sdk.NewConfig() 120 | credential := credentials.NewAccessKeyCredential(string(accessToken), string(secretKey)) 121 | 122 | client, err := alidns.NewClientWithOptions(cfg.Regionid, conf, credential) 123 | if err != nil { 124 | return err 125 | } 126 | c.aliDNSClient = client 127 | 128 | zoneName, err := c.getHostedZone(ch.ResolvedZone) 129 | if err != nil { 130 | return fmt.Errorf("alicloud: error getting hosted zones: %v", err) 131 | } 132 | 133 | recordAttributes := c.newTxtRecord(zoneName, ch.ResolvedFQDN, ch.Key) 134 | 135 | _, err = c.aliDNSClient.AddDomainRecord(recordAttributes) 136 | if err != nil { 137 | return fmt.Errorf("alicloud: error adding domain record: %v", err) 138 | } 139 | return nil 140 | } 141 | 142 | // CleanUp should delete the relevant TXT record from the DNS provider console. 143 | // If multiple TXT records exist with the same record name (e.g. 144 | // _acme-challenge.example.com) then **only** the record with the same `key` 145 | // value provided on the ChallengeRequest should be cleaned up. 146 | // This is in order to facilitate multiple DNS validations for the same domain 147 | // concurrently. 148 | func (c *aliDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { 149 | records, err := c.findTxtRecords(ch.ResolvedZone, ch.ResolvedFQDN) 150 | if err != nil { 151 | return fmt.Errorf("alicloud: error finding txt records: %v", err) 152 | } 153 | 154 | _, err = c.getHostedZone(ch.ResolvedZone) 155 | if err != nil { 156 | return fmt.Errorf("alicloud: %v", err) 157 | } 158 | 159 | for _, rec := range records { 160 | if ch.Key == rec.Value { 161 | request := alidns.CreateDeleteDomainRecordRequest() 162 | request.RecordId = rec.RecordId 163 | _, err = c.aliDNSClient.DeleteDomainRecord(request) 164 | if err != nil { 165 | return fmt.Errorf("alicloud: error deleting domain record: %v", err) 166 | } 167 | } 168 | } 169 | return nil 170 | } 171 | 172 | // Initialize will be called when the webhook first starts. 173 | // This method can be used to instantiate the webhook, i.e. initialising 174 | // connections or warming up caches. 175 | // Typically, the kubeClientConfig parameter is used to build a Kubernetes 176 | // client that can be used to fetch resources from the Kubernetes API, e.g. 177 | // Secret resources containing credentials used to authenticate with DNS 178 | // provider accounts. 179 | // The stopCh can be used to handle early termination of the webhook, in cases 180 | // where a SIGTERM or similar signal is sent to the webhook process. 181 | func (c *aliDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error { 182 | cl, err := kubernetes.NewForConfig(kubeClientConfig) 183 | if err != nil { 184 | return err 185 | } 186 | 187 | c.client = cl 188 | 189 | return nil 190 | } 191 | 192 | // loadConfig is a small helper function that decodes JSON configuration into 193 | // the typed config struct. 194 | func loadConfig(cfgJSON *extapi.JSON) (aliDNSProviderConfig, error) { 195 | cfg := aliDNSProviderConfig{} 196 | // handle the 'base case' where no configuration has been provided 197 | if cfgJSON == nil { 198 | return cfg, nil 199 | } 200 | if err := json.Unmarshal(cfgJSON.Raw, &cfg); err != nil { 201 | return cfg, fmt.Errorf("error decoding solver config: %v", err) 202 | } 203 | 204 | return cfg, nil 205 | } 206 | 207 | func (c *aliDNSProviderSolver) getHostedZone(resolvedZone string) (string, error) { 208 | request := alidns.CreateDescribeDomainsRequest() 209 | 210 | var domains []string 211 | startPage := 1 212 | 213 | for { 214 | request.PageNumber = requests.NewInteger(startPage) 215 | 216 | response, err := c.aliDNSClient.DescribeDomains(request) 217 | if err != nil { 218 | return "", fmt.Errorf("alicloud: error describing domains: %v", err) 219 | } 220 | 221 | for _, domain := range response.Domains.Domain { 222 | domains = append(domains, domain.DomainName) 223 | } 224 | 225 | if response.PageNumber*response.PageSize >= response.TotalCount { 226 | break 227 | } 228 | 229 | startPage++ 230 | } 231 | 232 | var hostedZone string 233 | for _, zone := range domains { 234 | if zone == util.UnFqdn(resolvedZone) { 235 | hostedZone = zone 236 | } 237 | } 238 | 239 | if hostedZone == "" { 240 | return "", fmt.Errorf("zone %s not found in AliDNS", resolvedZone) 241 | } 242 | return hostedZone, nil 243 | } 244 | 245 | func (c *aliDNSProviderSolver) newTxtRecord(zone, fqdn, value string) *alidns.AddDomainRecordRequest { 246 | request := alidns.CreateAddDomainRecordRequest() 247 | request.Type = "TXT" 248 | request.DomainName = zone 249 | request.RR = c.extractRecordName(fqdn, zone) 250 | request.Value = value 251 | return request 252 | } 253 | 254 | func (c *aliDNSProviderSolver) findTxtRecords(domain string, fqdn string) ([]alidns.Record, error) { 255 | zoneName, err := c.getHostedZone(domain) 256 | if err != nil { 257 | return nil, err 258 | } 259 | 260 | request := alidns.CreateDescribeDomainRecordsRequest() 261 | request.DomainName = zoneName 262 | request.PageSize = requests.NewInteger(500) 263 | 264 | var records []alidns.Record 265 | 266 | result, err := c.aliDNSClient.DescribeDomainRecords(request) 267 | if err != nil { 268 | return records, fmt.Errorf("alicloud: error describing domain records: %v", err) 269 | } 270 | 271 | recordName := c.extractRecordName(fqdn, zoneName) 272 | for _, record := range result.DomainRecords.Record { 273 | if record.RR == recordName { 274 | records = append(records, record) 275 | } 276 | } 277 | return records, nil 278 | } 279 | 280 | func (c *aliDNSProviderSolver) extractRecordName(fqdn, domain string) string { 281 | name := util.UnFqdn(fqdn) 282 | if idx := strings.LastIndex(name, "."+domain); idx != -1 { 283 | return name[:idx] 284 | } 285 | return name 286 | } 287 | 288 | func (c *aliDNSProviderSolver) loadSecretData(selector cmmetav1.SecretKeySelector, ns string) ([]byte, error) { 289 | secret, err := c.client.CoreV1().Secrets(ns).Get(context.TODO(), selector.Name, metav1.GetOptions{}) 290 | if err != nil { 291 | return nil, errors.Wrapf(err, "failed to load secret %q", ns+"/"+selector.Name) 292 | } 293 | 294 | if data, ok := secret.Data[selector.Key]; ok { 295 | return data, nil 296 | } 297 | 298 | return nil, errors.Errorf("no key %q in secret %q", selector.Key, ns+"/"+selector.Name) 299 | } 300 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | dns "github.com/cert-manager/cert-manager/test/acme" 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(&aliDNSProviderSolver{}, 20 | dns.SetDNSName(zone), 21 | dns.SetResolvedZone(zone), 22 | dns.SetAllowAmbientCredentials(false), 23 | dns.SetManifestPath("testdata/alidns-solver"), 24 | dns.SetDNSServer("ns7.alidns.com:53"), 25 | ) 26 | 27 | //need to uncomment and RunConformance delete runBasic and runExtended once https://github.com/cert-manager/cert-manager/pull/4835 is merged 28 | //fixture.RunConformance(t) 29 | fixture.RunBasic(t) 30 | fixture.RunExtended(t) 31 | } 32 | -------------------------------------------------------------------------------- /testdata/alidns-solver/alidns-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: alidns-secret 5 | data: 6 | access-token: your-base64-encoded-access-token 7 | secret-key: your-base64-encoded-secret-key -------------------------------------------------------------------------------- /testdata/alidns-solver/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "regionId": "cn-beijing", 3 | "accessTokenSecretRef": { 4 | "name": "alidns-secret", 5 | "key": "access-token" 6 | }, 7 | "secretKeySecretRef": { 8 | "name": "alidns-secret", 9 | "key": "secret-key" 10 | } 11 | } 12 | --------------------------------------------------------------------------------