Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f143a34954 | |||
| 4d78692298 | |||
| dfa2e7f205 | |||
| 89deb39e81 | |||
| e2d1e1c355 | |||
| 95a1557538 | |||
| b62f1cf632 | |||
| cfc6360ffc | |||
| 9b1fde11a2 | |||
| 8c1403a87b | |||
| 9d4d1a1d03 | |||
| cdaa33a539 | |||
| aaa26cf714 | |||
| e64faa0ab1 | |||
| 2612fb7733 | |||
| ffa1368f78 | |||
| a9c3ae7661 | |||
| 373cb7ffde | |||
| 625cd71ef7 | |||
| 2664ae3f11 | |||
| 4c0ef13c61 | |||
| ac9a9fd796 | |||
| 7bd3f5769a | |||
| 84ac6d4d27 | |||
| 52583c3e12 | |||
| 382418418b | |||
| 661abf8df2 | |||
| 4c7c0b121a | |||
| ef409187de | |||
|
|
33b74ccc20 | ||
|
|
b818887966 | ||
|
|
970e5fb44e | ||
| 5785110ea0 | |||
| aaa5f621e4 | |||
|
|
41edd7368c | ||
|
|
61bcd3d286 | ||
|
|
f63550ff6f |
172
.github/workflows/main.yml
vendored
172
.github/workflows/main.yml
vendored
@@ -1,172 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
- '!v0.1.*'
|
||||
|
||||
jobs:
|
||||
base:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
go_version: ${{ steps.get_versions.outputs.go_version }}
|
||||
build_version: ${{ steps.get_versions.outputs.build_version }}
|
||||
chart_version: ${{ steps.get_versions.outputs.chart_version }}
|
||||
go_updated: ${{ steps.file_updates.outputs.go }}
|
||||
yaml_updated: ${{ steps.file_updates.outputs.yaml }}
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get versions
|
||||
id: get_versions
|
||||
run: |
|
||||
echo ::set-output name=go_version::$(go mod edit -json | grep -Po '"Go":\s+"([0-9.]+)"' | sed -E 's/.+"([0-9.]+)"/\1/')
|
||||
echo ::set-output name=build_version::${GITHUB_REF#refs/tags/v}
|
||||
echo ::set-output name=chart_version::${GITHUB_REF#refs/tags/}
|
||||
|
||||
- name: Get last release
|
||||
id: last_release
|
||||
shell: bash
|
||||
run: |
|
||||
tag=$(gh release list | sed -n '1 p' | awk '{print $(NF -1);}')
|
||||
sha=$(git show-ref --tags | grep $tag | awk '{print $1;}')
|
||||
echo ::set-output name=sha::$sha
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check updated files
|
||||
id: file_updates
|
||||
uses: dorny/paths-filter@v2
|
||||
with:
|
||||
base: ${{ steps.last_release.outputs.sha }}
|
||||
filters: |
|
||||
go:
|
||||
- '*.go'
|
||||
- 'go.*'
|
||||
yaml:
|
||||
- 'deploy/cert-manager-webhook-gandi/*.yaml'
|
||||
- 'deploy/cert-manager-webhook-gandi/templates/*.yaml'
|
||||
|
||||
build:
|
||||
needs: base
|
||||
if: ${{ needs.base.outputs.go_updated == 'true' }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
tag_commit: ${{ steps.update_image.outputs.commit }}
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Set up Docker buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
target: image
|
||||
push: true
|
||||
build-args: GO_VERSION=${{ needs.base.outputs.go_version }}
|
||||
tags: bwolf/cert-manager-webhook-gandi:latest,bwolf/cert-manager-webhook-gandi:${{ needs.base.outputs.build_version }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
||||
|
||||
# Temp fix
|
||||
# https://github.com/docker/build-push-action/issues/252
|
||||
# https://github.com/moby/buildkit/issues/1896
|
||||
- name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||
|
||||
- name: Update Helm image tag
|
||||
id: update_image
|
||||
uses: fjogeleit/yaml-update-action@master
|
||||
with:
|
||||
valueFile: 'deploy/cert-manager-webhook-gandi/values.yaml'
|
||||
propertyPath: 'image.tag'
|
||||
value: ${{ needs.base.outputs.build_version }}
|
||||
message: 'Update image tag to ${{ needs.base.outputs.build_version }}'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release:
|
||||
needs:
|
||||
- base
|
||||
- build
|
||||
|
||||
if: |
|
||||
always() && needs.base.result == 'success' &&
|
||||
((needs.build.result == 'success' && needs.build.outputs.tag_commit != '' ) || (needs.build.result == 'skipped' && needs.base.outputs.yaml_updated == 'true'))
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Retrieve commit ref
|
||||
id: commit_ref
|
||||
run: |
|
||||
if [[ '${{ needs.build.outputs.tag_commit }}' = '' ]]; then
|
||||
sha=${{ github.sha }}
|
||||
else
|
||||
sha=${{ needs.build.outputs.tag_commit }}
|
||||
fi
|
||||
|
||||
echo ::set-output name=sha::$sha
|
||||
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ steps.commit_ref.outputs.sha }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
- name: Update Helm chart version
|
||||
uses: fjogeleit/yaml-update-action@master
|
||||
with:
|
||||
valueFile: 'deploy/cert-manager-webhook-gandi/Chart.yaml'
|
||||
propertyPath: 'version'
|
||||
value: ${{ needs.base.outputs.chart_version }}
|
||||
message: 'Update chart version to ${{ needs.base.outputs.chart_version }}'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
updateFile: true
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v1
|
||||
with:
|
||||
version: v3.4.0
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.2.1
|
||||
with:
|
||||
charts_dir: deploy
|
||||
env:
|
||||
CR_RELEASE_NAME_TEMPLATE: '{{ .Version }}'
|
||||
CR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
93
.github/workflows/release.yaml
vendored
Normal file
93
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: Release workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v[0-9]+.[0-9]+.[0-9]+
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check version
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check version
|
||||
run: |
|
||||
version="$(awk '/^version: /{ print $2 }' deploy/cert-manager-webhook-gandi/Chart.yaml)"
|
||||
if [ "$version" != "$GITHUB_REF_NAME" ]; then
|
||||
echo "Chart.yaml is not up to date"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chart:
|
||||
name: Publish Helm chart
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install docker
|
||||
uses: actions/docker-install@v1
|
||||
|
||||
- name: Install helm
|
||||
uses: actions/helm-install@v1
|
||||
|
||||
- name: Login to registry
|
||||
uses: actions/docker-login@v2
|
||||
with:
|
||||
registry: git.mug.lv
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build & publish Helm chart
|
||||
run: |
|
||||
helm package ./deploy/cert-manager-webhook-gandi
|
||||
helm push \
|
||||
cert-manager-webhook-gandi-*.tgz \
|
||||
oci://git.mug.lv/galen
|
||||
|
||||
image:
|
||||
name: Publish Docker image
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get versions
|
||||
id: version
|
||||
run: |
|
||||
chart="$(awk '/^version: /{ print $2 }' deploy/cert-manager-webhook-gandi/Chart.yaml)"
|
||||
chart="${chart//v/}"
|
||||
go="$(awk '/^go /{ print $2 }' go.mod)"
|
||||
cat <<EOF >>"$GITHUB_OUTPUT"
|
||||
chart=$chart
|
||||
go=$go
|
||||
EOF
|
||||
|
||||
- name: Install docker
|
||||
uses: actions/docker-install@v1
|
||||
|
||||
- name: Login to registry
|
||||
uses: actions/docker-login@v2
|
||||
with:
|
||||
registry: git.mug.lv
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Setup buildx
|
||||
uses: actions/docker-setup-buildx@v2
|
||||
|
||||
- name: Build image
|
||||
uses: actions/docker-build-push@v4
|
||||
with:
|
||||
push: true
|
||||
tags: git.mug.lv/${{ github.repository }}-server:${{ steps.version.outputs.chart }}
|
||||
build-args: GO_VERSION=${{ steps.version.outputs.go }}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -16,9 +16,8 @@
|
||||
|
||||
# Ignore the built binary
|
||||
cert-manager-webhook-gandi
|
||||
|
||||
# Ignore the Helm chart
|
||||
/charts/
|
||||
# But not the Helm chart
|
||||
!deploy/cert-manager-webhook-gandi
|
||||
|
||||
# JetBrains
|
||||
.idea
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# CHANGELOG
|
||||
| Date | Version | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| 2021-10-11 | v0.2.0 | add chart-releaser GitHub action |
|
||||
| 2021-10-06 | v0.2.0 | update cert-manager to 1.5.4<br>update k8s API version to 0.22.2<br>migrate to new LiveDNS API (https://api.gandi.net)<br>add Helm repo with GitHub pages<br>simplify Dockerfile & switch to Buildx<br>update make test target (remove shell script)<br>update README.md with changes made<br>update GitHub workflow with Buildx<br>add k8s APF support (k8s >= 1.20) |
|
||||
| 2020-02-26 | v0.1.1 | switch to Docker Hub |
|
||||
| 2020-02-26 | v0.1.0 | initial release |
|
||||
12
Makefile
12
Makefile
@@ -9,9 +9,6 @@ endif
|
||||
|
||||
GO_VERSION ?= $(shell go mod edit -json | grep -${GREP_PREGEX_FLAG}o '"Go":\s+"([0-9.]+)"' | sed -E 's/.+"([0-9.]+)"/\1/')
|
||||
|
||||
IMAGE_NAME := bwolf/cert-manager-webhook-gandi
|
||||
IMAGE_TAG := 0.2.0
|
||||
|
||||
OUT := $(shell pwd)/_out
|
||||
|
||||
KUBEBUILDER_VERSION=2.3.2
|
||||
@@ -37,16 +34,9 @@ clean: clean-kubebuilder
|
||||
clean-kubebuilder:
|
||||
rm -Rf _test/kubebuilder
|
||||
|
||||
build:
|
||||
docker buildx build --target=image --platform=linux/amd64 --output=type=docker,name=${IMAGE_NAME}:${IMAGE_TAG} --tag=${IMAGE_NAME}:latest --build-arg=GO_VERSION=${GO_VERSION} .
|
||||
|
||||
package:
|
||||
helm package deploy/cert-manager-webhook-gandi -d charts/
|
||||
helm repo index charts/ --url https://bwolf.github.io/cert-manager-webhook-gandi
|
||||
|
||||
.PHONY: rendered-manifest.yaml
|
||||
rendered-manifest.yaml:
|
||||
helm template \
|
||||
--set image.repository=${IMAGE_NAME} \
|
||||
--set image.tag=${IMAGE_TAG} \
|
||||
deploy/cert-manager-webhook-gandi > "${OUT}/rendered-manifest.yaml"
|
||||
deploy/cert-manager-webhook-gandi > "${OUT}/rendered-manifest.yaml"
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
# ACME webhook for Gandi (cert-manager-webhook-gandi)
|
||||
|
||||
Forked from [bwolf/cert-manager-webhook-gandi](https://github.com/bwolf/cert-manager-webhook-gandi), with additional patches applied from pull requests.
|
||||
|
||||
---
|
||||
|
||||
`cert-manager-webhook-gandi` is an ACME webhook for [cert-manager]. It provides an ACME (read: Let's Encrypt) webhook for [cert-manager], which allows to use a `DNS-01` challenge with [Gandi]. This allows to provide Let's Encrypt certificates to [Kubernetes] for service protocols other than HTTP and furthermore to request wildcard certificates. Internally it uses the [Gandi LiveDNS API] to communicate with Gandi.
|
||||
|
||||
Quoting the [ACME DNS-01 challenge]:
|
||||
@@ -94,7 +99,7 @@ This webhook has been tested with [cert-manager] v1.5.4 and Kubernetes v1.22.2 o
|
||||
To deploy using the Helm repository (for example using the `v0.2.0` version):
|
||||
|
||||
helm install cert-manager-webhook-gandi \
|
||||
--repo https://bwolf.github.io/cert-manager-webhook-gandi
|
||||
--repo https://bwolf.github.io/cert-manager-webhook-gandi \
|
||||
--version v0.2.0 \
|
||||
--namespace cert-manager \
|
||||
--set features.apiPriorityAndFairness=true \
|
||||
@@ -202,4 +207,4 @@ make clean
|
||||
[image tags]: https://hub.docker.com/r/bwolf/cert-manager-webhook-gandi
|
||||
[Kubernetes]: https://kubernetes.io/
|
||||
[setting-nameservers-for-dns01-self-check]: https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check
|
||||
[cert-manager-uninstall]: https://cert-manager.io/docs/installation/uninstall/kubernetes/
|
||||
[cert-manager-uninstall]: https://cert-manager.io/docs/installation/uninstall/kubernetes/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v2
|
||||
description: A Helm chart for cert-manager-webhook-gandi
|
||||
name: cert-manager-webhook-gandi
|
||||
version: v0.1.1
|
||||
version: v0.4.6
|
||||
|
||||
@@ -31,6 +31,26 @@ Create chart name and version as used by the chart label.
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "cert-manager-webhook-gandi.labels" -}}
|
||||
helm.sh/chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
{{ include "cert-manager-webhook-gandi.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "cert-manager-webhook-gandi.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "cert-manager-webhook-gandi.selfSignedIssuer" -}}
|
||||
{{ printf "%s-selfsign" (include "cert-manager-webhook-gandi.fullname" .) }}
|
||||
{{- end -}}
|
||||
@@ -45,4 +65,4 @@ Create chart name and version as used by the chart label.
|
||||
|
||||
{{- define "cert-manager-webhook-gandi.servingCertificate" -}}
|
||||
{{ printf "%s-webhook-tls" (include "cert-manager-webhook-gandi.fullname" .) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -3,10 +3,7 @@ kind: APIService
|
||||
metadata:
|
||||
name: v1alpha1.{{ .Values.groupName }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: "{{ .Values.certManager.namespace }}/{{ include "cert-manager-webhook-gandi.servingCertificate" . }}"
|
||||
spec:
|
||||
@@ -16,4 +13,4 @@ spec:
|
||||
service:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
version: v1alpha1
|
||||
version: v1alpha1
|
||||
|
||||
@@ -4,28 +4,24 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- include "cert-manager-webhook-gandi.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- include "cert-manager-webhook-gandi.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
image: {{ .Values.image.repository }}:{{ default .Values.image.tag (trimPrefix "v" .Chart.Version) }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
args:
|
||||
- --secure-port={{ .Values.containerport }}
|
||||
- --tls-cert-file=/tls/tls.crt
|
||||
- --tls-private-key-file=/tls/tls.key
|
||||
{{- if .Values.logLevel }}
|
||||
@@ -36,7 +32,7 @@ spec:
|
||||
value: {{ .Values.groupName | quote }}
|
||||
ports:
|
||||
- name: https
|
||||
containerPort: 443
|
||||
containerPort: {{ .Values.containerport }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -53,20 +49,20 @@ spec:
|
||||
mountPath: /tls
|
||||
readOnly: true
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: certs
|
||||
secret:
|
||||
secretName: {{ include "cert-manager-webhook-gandi.servingCertificate" . }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -7,10 +7,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.selfSignedIssuer" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
@@ -21,10 +18,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.rootCACertificate" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ include "cert-manager-webhook-gandi.rootCACertificate" . }}
|
||||
duration: 43800h # 5y
|
||||
@@ -40,10 +34,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.rootCAIssuer" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
ca:
|
||||
secretName: {{ include "cert-manager-webhook-gandi.rootCACertificate" . }}
|
||||
@@ -55,10 +46,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.servingCertificate" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ include "cert-manager-webhook-gandi.servingCertificate" . }}
|
||||
duration: 8760h # 1y
|
||||
@@ -67,4 +55,4 @@ spec:
|
||||
dnsNames:
|
||||
- {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
- {{ include "cert-manager-webhook-gandi.fullname" . }}.{{ .Values.certManager.namespace }}
|
||||
- {{ include "cert-manager-webhook-gandi.fullname" . }}.{{ .Values.certManager.namespace }}.svc
|
||||
- {{ include "cert-manager-webhook-gandi.fullname" . }}.{{ .Values.certManager.namespace }}.svc
|
||||
|
||||
@@ -4,10 +4,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
---
|
||||
# Grant the webhook permission to read the ConfigMap containing the Kubernetes
|
||||
# apiserver's requestheader-ca-certificate
|
||||
@@ -18,10 +15,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:webhook-authentication-reader
|
||||
namespace: kube-system
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
@@ -39,10 +33,7 @@ kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:auth-delegator
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
@@ -59,10 +50,7 @@ kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:domain-solver
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- {{ .Values.groupName }}
|
||||
@@ -76,10 +64,7 @@ kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:domain-solver
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
@@ -130,10 +115,7 @@ kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:flowcontrol-solver
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- "flowcontrol.apiserver.k8s.io"
|
||||
@@ -149,10 +131,7 @@ kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}:flowcontrol-solver
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
@@ -162,4 +141,4 @@ subjects:
|
||||
kind: ServiceAccount
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -4,10 +4,7 @@ metadata:
|
||||
name: {{ include "cert-manager-webhook-gandi.fullname" . }}
|
||||
namespace: {{ .Values.certManager.namespace | quote }}
|
||||
labels:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
chart: {{ include "cert-manager-webhook-gandi.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- include "cert-manager-webhook-gandi.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
@@ -16,5 +13,4 @@ spec:
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
app: {{ include "cert-manager-webhook-gandi.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- include "cert-manager-webhook-gandi.selectorLabels" . | nindent 4 }}
|
||||
|
||||
@@ -1,51 +1,21 @@
|
||||
# The GroupName here is used to identify your company or business unit that
|
||||
# created this webhook.
|
||||
# For example, this may be "acme.mycompany.com".
|
||||
# This name will need to be referenced in each Issuer's `webhook` stanza to
|
||||
# inform cert-manager of where to send ChallengePayload resources in order to
|
||||
# solve the DNS01 challenge.
|
||||
# This group name should be **unique**, hence using your own company's domain
|
||||
# here is recommended.
|
||||
groupName: acme.bwolf.me
|
||||
|
||||
logLevel: 6
|
||||
|
||||
certManager:
|
||||
namespace: cert-manager
|
||||
serviceAccountName: cert-manager
|
||||
|
||||
image:
|
||||
repository: bwolf/cert-manager-webhook-gandi
|
||||
tag: v0.1.1
|
||||
repository: git.mug.lv/galen/cert-manager-webhook-gandi-server
|
||||
# tag: X.Y.Z defaults to app version
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
nameOverride: ''
|
||||
fullnameOverride: ''
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 443
|
||||
|
||||
containerport: 8443
|
||||
features:
|
||||
# API Priority and Fairness should be enabled from Kubernetes 1.20
|
||||
# https://kubernetes.io/docs/concepts/cluster-administration/flow-control/
|
||||
apiPriorityAndFairness: false
|
||||
|
||||
resources:
|
||||
{}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
resources: {}
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
184
gandiclient.go
184
gandiclient.go
@@ -1,184 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
GandiLiveDnsBaseUrl = "https://api.gandi.net/v5/livedns"
|
||||
)
|
||||
|
||||
type GandiClient struct {
|
||||
apiKey string
|
||||
dumpRequestResponse bool
|
||||
}
|
||||
|
||||
type GandiRRSet struct {
|
||||
Type string `json:"rrset_type"`
|
||||
TTL int `json:"rrset_ttl"`
|
||||
Name string `json:"rrset_name"`
|
||||
Values []string `json:"rrset_values"`
|
||||
}
|
||||
|
||||
type GandiRRSetValues struct {
|
||||
TTL int `json:"rrset_ttl"`
|
||||
Values []string `json:"rrset_values"`
|
||||
}
|
||||
|
||||
func NewGandiClient(apiKey string) *GandiClient {
|
||||
return &GandiClient{
|
||||
apiKey: apiKey,
|
||||
dumpRequestResponse: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GandiClient) gandiRecordsUrl(domain string) string {
|
||||
return fmt.Sprintf("%s/domains/%s/records", GandiLiveDnsBaseUrl, domain)
|
||||
}
|
||||
|
||||
func (c *GandiClient) doRequest(req *http.Request, readResponseBody bool) (int, []byte, error) {
|
||||
if c.dumpRequestResponse {
|
||||
dump, _ := httputil.DumpRequest(req, true)
|
||||
fmt.Printf("Request: %q\n", dump)
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Apikey %s", c.apiKey))
|
||||
client := http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if c.dumpRequestResponse {
|
||||
dump, _ := httputil.DumpResponse(res, true)
|
||||
fmt.Printf("Response: %q\n", dump)
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusOK && readResponseBody {
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return res.StatusCode, data, nil
|
||||
}
|
||||
|
||||
return res.StatusCode, nil, nil
|
||||
}
|
||||
|
||||
func (c *GandiClient) HasTxtRecord(domain *string, name *string) (bool, error) {
|
||||
// curl -X GET -H "Content-Type: application/json" \
|
||||
// -H "Authorization: Apikey $APIKEY" \
|
||||
// https://api.gandi.net/v5/livedns/domains/<DOMAIN>/records/<NAME>/<TYPE>
|
||||
url := fmt.Sprintf("%s/%s/TXT", c.gandiRecordsUrl(*domain), *name)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
status, _, err := c.doRequest(req, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if status == http.StatusNotFound {
|
||||
return false, nil
|
||||
} else if status == http.StatusOK {
|
||||
// Maybe parse response body here to really ensure that the record is present
|
||||
return true, nil
|
||||
} else {
|
||||
return false, fmt.Errorf("unexpected HTTP status: %d", status)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GandiClient) CreateTxtRecord(domain *string, name *string, value *string, ttl int) error {
|
||||
// curl -X POST -H "Content-Type: application/json" \
|
||||
// -H "Authorization: Apikey $APIKEY" \
|
||||
// -d '{"rrset_name": "<NAME>", "rrset_type": "<TYPE>", "rrset_ttl": 10800, "rrset_values": ["<VALUE>"]}' \
|
||||
// https://api.gandi.net/v5/livedns/domains/<DOMAIN>/records
|
||||
rrs := GandiRRSet{Name: *name, Type: "TXT", TTL: ttl, Values: []string{*value}}
|
||||
body, err := json.Marshal(rrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot marshall to json: %v", err)
|
||||
}
|
||||
|
||||
url := c.gandiRecordsUrl(*domain)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
status, _, err := c.doRequest(req, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status != http.StatusCreated && status != http.StatusOK {
|
||||
return fmt.Errorf("failed creating TXT record: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GandiClient) UpdateTxtRecord(domain *string, name *string, value *string, ttl int) error {
|
||||
// curl -X PUT -H "Content-Type: application/json" \
|
||||
// -H "Authorization: Apikey $APIKEY" \
|
||||
// -d '{"rrset_ttl": 10800, "rrset_values":["<VALUE>"]}' \
|
||||
// https://api.gandi.net/v5/livedns/domains/<DOMAIN>/records/<NAME>/<TYPE>
|
||||
rrs := GandiRRSetValues{TTL: ttl, Values: []string{*value}}
|
||||
body, err := json.Marshal(rrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot marshall to json: %v", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/TXT", c.gandiRecordsUrl(*domain), *name)
|
||||
req, err := http.NewRequest("PUT", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
status, _, err := c.doRequest(req, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status != http.StatusCreated && status != http.StatusOK {
|
||||
return fmt.Errorf("failed updating TXT record: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GandiClient) DeleteTxtRecord(domain *string, name *string) error {
|
||||
// curl -X DELETE -H "Content-Type: application/json" \
|
||||
// -H "Authorization: Apikey $APIKEY" \
|
||||
// https://api.gandi.net/v5/livedns/domains/<DOMAIN>/records/<NAME>/<TYPE>
|
||||
url := fmt.Sprintf("%s/%s/TXT", c.gandiRecordsUrl(*domain), *name)
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status, _, err := c.doRequest(req, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status != http.StatusOK && status != http.StatusNoContent {
|
||||
return fmt.Errorf("failed deleting TXT record: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
170
go.mod
170
go.mod
@@ -1,113 +1,117 @@
|
||||
module github.com/bwolf/cert-manager-webhook-gandi
|
||||
|
||||
go 1.17
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/cert-manager/cert-manager v1.12.1
|
||||
github.com/go-gandi/go-gandi v0.6.0
|
||||
k8s.io/apiextensions-apiserver v0.27.2
|
||||
k8s.io/apimachinery v0.27.2
|
||||
k8s.io/client-go v0.27.2
|
||||
k8s.io/klog/v2 v2.100.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful v2.15.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/go-logr/logr v0.4.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/cel-go v0.12.6 // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jetstack/cert-manager v1.5.4
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/miekg/dns v1.1.34 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/peterhellberg/link v1.2.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.31.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/spf13/cobra v1.2.1 // indirect
|
||||
github.com/prometheus/client_golang v1.15.1 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.8.1 // indirect
|
||||
github.com/spf13/cobra v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
|
||||
go.opentelemetry.io/contrib v0.20.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v0.20.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.7 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.39.0 // indirect
|
||||
go.opentelemetry.io/otel v1.15.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.15.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.15.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/net v0.16.0 // indirect
|
||||
golang.org/x/oauth2 v0.5.0 // indirect
|
||||
golang.org/x/sync v0.4.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211001223012-bfb93cce50d9 // indirect
|
||||
google.golang.org/grpc v1.41.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
|
||||
google.golang.org/grpc v1.54.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/api v0.22.2 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.22.2
|
||||
k8s.io/apimachinery v0.22.2
|
||||
k8s.io/apiserver v0.22.2 // indirect
|
||||
k8s.io/client-go v0.22.2
|
||||
k8s.io/component-base v0.22.2 // indirect
|
||||
k8s.io/klog/v2 v2.9.0
|
||||
k8s.io/kube-aggregator v0.22.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210929172449-94abcedd1aa4 // indirect
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.24 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.9.2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.27.2 // indirect
|
||||
k8s.io/apiserver v0.27.2 // indirect
|
||||
k8s.io/component-base v0.27.2 // indirect
|
||||
k8s.io/kms v0.27.2 // indirect
|
||||
k8s.io/kube-aggregator v0.27.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230515203736-54b630e78af5 // indirect
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.15.0 // indirect
|
||||
sigs.k8s.io/gateway-api v0.7.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// Force packages versions over versions used by https://github.com/kubernetes/apiserver v0.22.2
|
||||
replace (
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v0.4.0
|
||||
go.opentelemetry.io/contrib => go.opentelemetry.io/contrib v0.20.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0
|
||||
go.opentelemetry.io/otel => go.opentelemetry.io/otel v0.20.0
|
||||
go.opentelemetry.io/otel/exporters/otlp => go.opentelemetry.io/otel/exporters/otlp v0.20.0
|
||||
go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v0.20.0
|
||||
go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v0.20.0
|
||||
go.opentelemetry.io/otel/sdk/export/metric => go.opentelemetry.io/otel/sdk/export/metric v0.20.0
|
||||
go.opentelemetry.io/otel/sdk/metric => go.opentelemetry.io/otel/sdk/metric v0.20.0
|
||||
go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v0.20.0
|
||||
go.opentelemetry.io/proto/otlp => go.opentelemetry.io/proto/otlp v0.7.0
|
||||
k8s.io/klog/v2 => k8s.io/klog/v2 v2.9.0
|
||||
)
|
||||
replace github.com/go-gandi/go-gandi => git.mug.lv/galen/go-gandi v0.0.0-20231017185104-ac95d5a2c330
|
||||
|
||||
117
main.go
117
main.go
@@ -3,13 +3,20 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"github.com/jetstack/cert-manager/pkg/acme/webhook/cmd"
|
||||
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
|
||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/cmd"
|
||||
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
|
||||
"github.com/go-gandi/go-gandi"
|
||||
"github.com/go-gandi/go-gandi/config"
|
||||
"github.com/go-gandi/go-gandi/livedns"
|
||||
"github.com/go-gandi/go-gandi/types"
|
||||
extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -21,7 +28,10 @@ const (
|
||||
GandiMinTtl = 300 // Gandi reports an error for values < this value
|
||||
)
|
||||
|
||||
var GroupName = os.Getenv("GROUP_NAME")
|
||||
var (
|
||||
DebugHTTP = os.Getenv("DEBUG_HTTP")
|
||||
GroupName = os.Getenv("GROUP_NAME")
|
||||
)
|
||||
|
||||
func main() {
|
||||
if GroupName == "" {
|
||||
@@ -40,7 +50,7 @@ func main() {
|
||||
|
||||
// gandiDNSProviderSolver implements the provider-specific logic needed to
|
||||
// 'present' an ACME challenge TXT record for your own DNS provider.
|
||||
// To do so, it must implement the `github.com/jetstack/cert-manager/pkg/acme/webhook.Solver`
|
||||
// To do so, it must implement the `github.com/cert-manager/cert-manager/pkg/acme/webhook.Solver`
|
||||
// interface.
|
||||
type gandiDNSProviderSolver struct {
|
||||
client *kubernetes.Clientset
|
||||
@@ -85,38 +95,30 @@ func (c *gandiDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
|
||||
klog.V(6).Infof("call function Present: namespace=%s, zone=%s, fqdn=%s",
|
||||
ch.ResourceNamespace, ch.ResolvedZone, ch.ResolvedFQDN)
|
||||
|
||||
cfg, err := loadConfig(ch.Config)
|
||||
client, err := c.newClient(ch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
return fmt.Errorf("failed to initialize client: %w", err)
|
||||
}
|
||||
|
||||
klog.V(6).Infof("decoded configuration %v", cfg)
|
||||
|
||||
apiKey, err := c.getApiKey(&cfg, ch.ResourceNamespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get API key: %v", err)
|
||||
}
|
||||
|
||||
gandiClient := NewGandiClient(*apiKey)
|
||||
|
||||
entry, domain := c.getDomainAndEntry(ch)
|
||||
klog.V(6).Infof("present for entry=%s, domain=%s", entry, domain)
|
||||
|
||||
present, err := gandiClient.HasTxtRecord(&domain, &entry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to check TXT record: %v", err)
|
||||
klog.V(6).Infof("present for entry=%s, domain=%s", entry, domain)
|
||||
present := true
|
||||
_, err = client.GetDomainRecordByNameAndType(domain, entry, "TXT")
|
||||
var reqErr *types.RequestError
|
||||
if errors.As(err, &reqErr) && reqErr.StatusCode == http.StatusNotFound {
|
||||
present = false
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to get record: %w", err)
|
||||
}
|
||||
|
||||
txtValues := []string{fmt.Sprintf(`"%s"`, ch.Key)}
|
||||
if present {
|
||||
err := gandiClient.UpdateTxtRecord(&domain, &entry, &ch.Key, GandiMinTtl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to change TXT record: %v", err)
|
||||
}
|
||||
_, err = client.UpdateDomainRecordByNameAndType(domain, entry, "TXT", GandiMinTtl, txtValues)
|
||||
} else {
|
||||
err := gandiClient.CreateTxtRecord(&domain, &entry, &ch.Key, GandiMinTtl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create TXT record: %v", err)
|
||||
}
|
||||
_, err = client.CreateDomainRecord(domain, entry, "TXT", GandiMinTtl, txtValues)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set record: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -132,31 +134,19 @@ func (c *gandiDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
||||
klog.V(6).Infof("call function CleanUp: namespace=%s, zone=%s, fqdn=%s",
|
||||
ch.ResourceNamespace, ch.ResolvedZone, ch.ResolvedFQDN)
|
||||
|
||||
cfg, err := loadConfig(ch.Config)
|
||||
client, err := c.newClient(ch)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to initialize client: %w", err)
|
||||
}
|
||||
|
||||
apiKey, err := c.getApiKey(&cfg, ch.ResourceNamespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get API key: %v", err)
|
||||
}
|
||||
|
||||
gandiClient := NewGandiClient(*apiKey)
|
||||
|
||||
entry, domain := c.getDomainAndEntry(ch)
|
||||
|
||||
present, err := gandiClient.HasTxtRecord(&domain, &entry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to check TXT record: %v", err)
|
||||
}
|
||||
|
||||
if present {
|
||||
klog.V(6).Infof("deleting entry=%s, domain=%s", entry, domain)
|
||||
err := gandiClient.DeleteTxtRecord(&domain, &entry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to remove TXT record: %v", err)
|
||||
}
|
||||
klog.V(6).Infof("deleting entry=%s, domain=%s", entry, domain)
|
||||
err = client.DeleteDomainRecord(domain, entry, "TXT")
|
||||
var reqErr *types.RequestError
|
||||
if errors.As(err, &reqErr) && reqErr.StatusCode == http.StatusNotFound {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to delete record: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -204,23 +194,40 @@ func (c *gandiDNSProviderSolver) getDomainAndEntry(ch *v1alpha1.ChallengeRequest
|
||||
return entry, domain
|
||||
}
|
||||
|
||||
func (c *gandiDNSProviderSolver) newClient(ch *v1alpha1.ChallengeRequest) (*livedns.LiveDNS, error) {
|
||||
cfg, err := loadConfig(ch.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiKey, err := c.getApiKey(&cfg, ch.ResourceNamespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get API key: %v", err)
|
||||
}
|
||||
|
||||
return gandi.NewLiveDNSClient(config.Config{
|
||||
Token: apiKey,
|
||||
Timeout: time.Second * 30,
|
||||
Debug: DebugHTTP != "",
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Get Gandi API key from Kubernetes secret.
|
||||
func (c *gandiDNSProviderSolver) getApiKey(cfg *gandiDNSProviderConfig, namespace string) (*string, error) {
|
||||
func (c *gandiDNSProviderSolver) getApiKey(cfg *gandiDNSProviderConfig, namespace string) (string, error) {
|
||||
secretName := cfg.APIKeySecretRef.LocalObjectReference.Name
|
||||
|
||||
klog.V(6).Infof("try to load secret `%s` with key `%s`", secretName, cfg.APIKeySecretRef.Key)
|
||||
|
||||
sec, err := c.client.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get secret `%s`; %v", secretName, err)
|
||||
return "", fmt.Errorf("unable to get secret `%s`; %v", secretName, err)
|
||||
}
|
||||
|
||||
secBytes, ok := sec.Data[cfg.APIKeySecretRef.Key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key %q not found in secret \"%s/%s\"", cfg.APIKeySecretRef.Key,
|
||||
return "", fmt.Errorf("key %q not found in secret \"%s/%s\"", cfg.APIKeySecretRef.Key,
|
||||
cfg.APIKeySecretRef.LocalObjectReference.Name, namespace)
|
||||
}
|
||||
|
||||
apiKey := string(secBytes)
|
||||
return &apiKey, nil
|
||||
return string(secBytes), nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/jetstack/cert-manager/test/acme/dns"
|
||||
"github.com/cert-manager/cert-manager/test/acme"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
33
scripts/release.sh
Executable file
33
scripts/release.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh -eux
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
version="$(yq '.version' ../deploy/cert-manager-webhook-gandi/Chart.yaml)"
|
||||
version="${version#v}"
|
||||
major="$(echo "$version" | cut -d'.' -f1)"
|
||||
minor="$(echo "$version" | cut -d'.' -f2)"
|
||||
patch="$(echo "$version" | cut -d'.' -f3)"
|
||||
case "${1:-""}" in
|
||||
major)
|
||||
major=$((major + 1))
|
||||
minor=0
|
||||
patch=0
|
||||
;;
|
||||
minor)
|
||||
minor=$((minor + 1))
|
||||
patch=0
|
||||
;;
|
||||
patch)
|
||||
patch=$((patch + 1))
|
||||
;;
|
||||
*)
|
||||
echo "Unknown release type"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
version="$major.$minor.$patch"
|
||||
|
||||
yq -i ".version |= \"v$version\"" ../deploy/cert-manager-webhook-gandi/Chart.yaml
|
||||
git add ../deploy/
|
||||
git commit -m "Bump version to v$version"
|
||||
git tag -a "v$version"
|
||||
Reference in New Issue
Block a user