├── .ci
├── build
├── pipeline_definitions
├── prepare_release
├── test
└── verify
├── .dockerignore
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── enhancement_request.md
├── dependabot.yaml
└── pull_request_template.md
├── .gitignore
├── .golangci.yaml
├── .idea
└── copyright
│ ├── Gardener.xml
│ └── profiles_settings.xml
├── .reuse
└── dep5
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── LICENSES
├── Apache-2.0.txt
└── CC-BY-4.0.txt
├── Makefile
├── OWNERS
├── OWNERS_ALIASES
├── README.md
├── VERSION
├── charts
└── cert-management
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── templates
│ ├── 0helpers.tpl
│ ├── ca-certificates-configmap.yaml
│ ├── cert.gardener.cloud_certificaterevocations.yaml
│ ├── cert.gardener.cloud_certificates.yaml
│ ├── cert.gardener.cloud_issuers.yaml
│ ├── clusterrole.yaml
│ ├── clusterrolebinding.yaml
│ ├── deployment.yaml
│ ├── role.yaml
│ ├── rolebinding.yaml
│ └── serviceaccount.yaml
│ └── values.yaml
├── cmd
├── cert-controller-manager
│ ├── .import-restrictions
│ └── main.go
└── certman2
│ ├── .import-restrictions
│ ├── app
│ └── app.go
│ └── main.go
├── docs
├── development
│ ├── getting-started.md
│ └── testing.md
└── usage
│ └── tutorials
│ ├── gateway-api-gateways.md
│ └── istio-gateways.md
├── examples
├── 10-crds.yaml
├── 11-dns.gardener.cloud_dnsentries.yaml
├── 20-issuer-ca.yaml
├── 20-issuer-productive.yaml
├── 20-issuer-selfsigned.yaml
├── 20-issuer-staging.yaml
├── 21-issuer-acme-eab.yaml
├── 30-cert-ca.yaml
├── 30-cert-csr.yaml
├── 30-cert-selfsigned.yaml
├── 30-cert-simple-with-keystores.yaml
├── 30-cert-simple.yaml
├── 30-cert-wildcard.yaml
├── 40-gateway-gateway-api.yaml
├── 40-gateway-istio.yaml
├── 40-ingress-echoheaders.yaml
├── 40-service-loadbalancer.yaml
└── 50-certificate-revocation.yaml
├── go.mod
├── go.sum
├── hack
├── LICENSE_BOILERPLATE.txt
├── check-cert-secret.sh
├── copy-crds.sh
├── generate-code
├── generate-renovate-ignore-deps.sh
├── generateChartOptions.py
├── go-test.sh
├── kind
│ ├── certman
│ │ ├── certman-down.sh
│ │ ├── issuer-down.sh
│ │ └── issuer-up.sh
│ ├── common.sh
│ ├── dns-controller-manager
│ │ └── dns-controller-manager-up.sh
│ ├── kind-create-cluster.sh
│ ├── kind-delete-cluster.sh
│ ├── knot-dns
│ │ ├── crd-dnsprovider.yaml
│ │ ├── knot-dns-certman-support.yaml.template
│ │ ├── knot-dns-service.yaml
│ │ ├── knot-dns-up.sh
│ │ ├── patch-coredns.sh
│ │ └── patch-deployment-coredns.yaml
│ ├── local-issuer
│ │ ├── local-issuer-down.sh
│ │ └── local-issuer-up.sh
│ ├── pebble
│ │ └── pebble-up.sh
│ ├── registry
│ │ ├── base
│ │ │ ├── kustomization.yaml
│ │ │ └── registry.yaml
│ │ ├── docker
│ │ │ └── kustomization.yaml
│ │ ├── europe-docker-pkg-dev
│ │ │ └── kustomization.yaml
│ │ ├── ghcr
│ │ │ └── kustomization.yaml
│ │ ├── k8s
│ │ │ └── kustomization.yaml
│ │ ├── kustomization.yaml
│ │ └── namespace.yaml
│ ├── skaffold-after-hock.sh
│ ├── skaffold-run.sh
│ └── test-functional-local.sh
├── sast.sh
└── tools.go
├── pkg
├── apis
│ ├── .import-restrictions
│ └── cert
│ │ ├── crds
│ │ ├── cert.gardener.cloud_certificaterevocations.yaml
│ │ ├── cert.gardener.cloud_certificates.yaml
│ │ ├── cert.gardener.cloud_issuers.yaml
│ │ └── zz_generated_crds.go
│ │ ├── register.go
│ │ └── v1alpha1
│ │ ├── doc.go
│ │ ├── register.go
│ │ ├── state.go
│ │ ├── types.go
│ │ └── zz_generated.deepcopy.go
├── cert
│ ├── .import-restrictions
│ ├── client
│ │ └── scheme.go
│ ├── source
│ │ ├── certinfo.go
│ │ ├── controller.go
│ │ ├── defaults.go
│ │ ├── interface.go
│ │ ├── reconciler.go
│ │ ├── slaves.go
│ │ └── utils.go
│ └── utils
│ │ ├── domainrange.go
│ │ ├── domainrange_test.go
│ │ ├── issuerkey.go
│ │ ├── issuerkey_test.go
│ │ ├── mock
│ │ ├── doc.go
│ │ └── mocks.go
│ │ ├── utils_certificate.go
│ │ ├── utils_certificate_test.go
│ │ ├── utils_issuer.go
│ │ ├── utils_mod.go
│ │ ├── utils_mod_test.go
│ │ └── utils_suite_test.go
├── certman2
│ ├── .import-restrictions
│ ├── apis
│ │ ├── cert
│ │ │ ├── crd-cert.gardener.cloud_certificaterevocations.yaml
│ │ │ ├── crd-cert.gardener.cloud_certificates.yaml
│ │ │ ├── crd-cert.gardener.cloud_issuers.yaml
│ │ │ └── register.go
│ │ └── config
│ │ │ ├── doc.go
│ │ │ ├── register.go
│ │ │ ├── types.go
│ │ │ ├── v1alpha1
│ │ │ ├── defaults.go
│ │ │ ├── defaults_test.go
│ │ │ ├── doc.go
│ │ │ ├── register.go
│ │ │ ├── types.go
│ │ │ ├── v1alpha1_suite_test.go
│ │ │ ├── zz_generated.conversion.go
│ │ │ ├── zz_generated.deepcopy.go
│ │ │ └── zz_generated.defaults.go
│ │ │ └── zz_generated.deepcopy.go
│ ├── client
│ │ ├── clusteraccess.go
│ │ └── scheme.go
│ ├── controller
│ │ ├── certificate
│ │ │ ├── add.go
│ │ │ ├── certificate_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_delete.go
│ │ │ └── reconciler_reconcile.go
│ │ ├── issuer
│ │ │ └── controlplane
│ │ │ │ ├── acme
│ │ │ │ ├── handler.go
│ │ │ │ ├── handler_test.go
│ │ │ │ └── issuer_suite_test.go
│ │ │ │ ├── add.go
│ │ │ │ ├── ca
│ │ │ │ ├── handler.go
│ │ │ │ ├── handler_test.go
│ │ │ │ └── issuer_suite_test.go
│ │ │ │ ├── issuer_suite_test.go
│ │ │ │ └── reconciler.go
│ │ ├── predicate.go
│ │ └── source
│ │ │ ├── add.go
│ │ │ ├── common
│ │ │ ├── certinput.go
│ │ │ ├── certinput_collector.go
│ │ │ ├── constants.go
│ │ │ └── reconcilerbase.go
│ │ │ ├── gateways_crd_watchdog
│ │ │ ├── add.go
│ │ │ ├── add_test.go
│ │ │ ├── crd_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_test.go
│ │ │ └── testdata
│ │ │ │ ├── crd-gateways.gateway.networking.k8s.io_v1.yaml
│ │ │ │ ├── crd-gateways.gateway.networking.k8s.io_v1beta1.yaml
│ │ │ │ ├── crd-gateways.networking.istio.io_v1.yaml
│ │ │ │ ├── crd-gateways.networking.istio.io_v1beta1.yaml
│ │ │ │ ├── crd-httproutes.gateway.networking.k8s.io_v1.yaml
│ │ │ │ ├── crd-httproutes.gateway.networking.k8s.io_v1beta1.yaml
│ │ │ │ ├── crd-virtualservices.networking.istio.io_v1.yaml
│ │ │ │ └── crd-virtualservices.networking.istio.io_v1beta1.yaml
│ │ │ ├── ingress
│ │ │ ├── add.go
│ │ │ ├── add_test.go
│ │ │ ├── ingress_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_reconcile.go
│ │ │ └── reconciler_test.go
│ │ │ ├── istio_gateway
│ │ │ ├── add.go
│ │ │ ├── add_test.go
│ │ │ ├── istio_gateway_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_certinputmap_test.go
│ │ │ ├── reconciler_reconcile.go
│ │ │ ├── reconciler_test.go
│ │ │ └── versions.go
│ │ │ ├── k8s_gateway
│ │ │ ├── add.go
│ │ │ ├── add_test.go
│ │ │ ├── k8s_gateway_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_certinputmap_test.go
│ │ │ ├── reconciler_reconcile.go
│ │ │ ├── reconciler_test.go
│ │ │ └── versions.go
│ │ │ └── service
│ │ │ ├── add.go
│ │ │ ├── add_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── reconciler_reconcile.go
│ │ │ ├── reconciler_test.go
│ │ │ └── service_suite_test.go
│ ├── core
│ │ ├── associatedObjects.go
│ │ ├── const.go
│ │ ├── issuerDNSSelections.go
│ │ ├── keys.go
│ │ ├── objectnameset.go
│ │ ├── quotas.go
│ │ ├── referencedSecrets.go
│ │ ├── referencedSecrets_test.go
│ │ ├── state.go
│ │ ├── support.go
│ │ ├── utils.go
│ │ └── wrappedregistration.go
│ └── testutils
│ │ └── assert_events.go
├── client
│ ├── .import-restrictions
│ └── cert
│ │ ├── clientset
│ │ └── versioned
│ │ │ ├── clientset.go
│ │ │ ├── fake
│ │ │ ├── clientset_generated.go
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ ├── scheme
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ └── typed
│ │ │ └── cert
│ │ │ └── v1alpha1
│ │ │ ├── cert_client.go
│ │ │ ├── certificate.go
│ │ │ ├── certificaterevocation.go
│ │ │ ├── doc.go
│ │ │ ├── fake
│ │ │ ├── doc.go
│ │ │ ├── fake_cert_client.go
│ │ │ ├── fake_certificate.go
│ │ │ ├── fake_certificaterevocation.go
│ │ │ └── fake_issuer.go
│ │ │ ├── generated_expansion.go
│ │ │ └── issuer.go
│ │ ├── informers
│ │ └── externalversions
│ │ │ ├── cert
│ │ │ ├── interface.go
│ │ │ └── v1alpha1
│ │ │ │ ├── certificate.go
│ │ │ │ ├── certificaterevocation.go
│ │ │ │ ├── interface.go
│ │ │ │ └── issuer.go
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ └── internalinterfaces
│ │ │ └── factory_interfaces.go
│ │ └── listers
│ │ └── cert
│ │ └── v1alpha1
│ │ ├── certificate.go
│ │ ├── certificaterevocation.go
│ │ ├── expansion_generated.go
│ │ └── issuer.go
├── controller
│ ├── .import-restrictions
│ ├── common.go
│ ├── issuer
│ │ ├── acme
│ │ │ └── handler.go
│ │ ├── ca
│ │ │ └── handler.go
│ │ ├── certificate
│ │ │ ├── backupsecret.go
│ │ │ ├── certificate_suite_test.go
│ │ │ ├── reconciler.go
│ │ │ ├── utils.go
│ │ │ └── utils_test.go
│ │ ├── controller.go
│ │ ├── core
│ │ │ ├── associatedObjects.go
│ │ │ ├── const.go
│ │ │ ├── core_suite_test.go
│ │ │ ├── issuerDNSSelections.go
│ │ │ ├── objectnameset.go
│ │ │ ├── quotas.go
│ │ │ ├── referencedSecrets.go
│ │ │ ├── referencedSecrets_test.go
│ │ │ ├── state.go
│ │ │ ├── support.go
│ │ │ ├── support_test.go
│ │ │ └── wrappedregistration.go
│ │ ├── reconciler.go
│ │ ├── revocation
│ │ │ └── reconciler.go
│ │ └── selfSigned
│ │ │ ├── handler.go
│ │ │ ├── handler_test.go
│ │ │ └── selfSigned_suite_test.go
│ └── source
│ │ ├── gateways
│ │ ├── crdwatch
│ │ │ └── controller.go
│ │ ├── gatewayapi
│ │ │ ├── controller.go
│ │ │ ├── gateway_suite_test.go
│ │ │ ├── handler.go
│ │ │ ├── handler_test.go
│ │ │ ├── httproutesReconciler.go
│ │ │ ├── state.go
│ │ │ └── state_test.go
│ │ └── istio
│ │ │ ├── controller.go
│ │ │ ├── handler.go
│ │ │ ├── handler_test.go
│ │ │ ├── istio_gateway_suite_test.go
│ │ │ ├── state.go
│ │ │ ├── state_test.go
│ │ │ ├── targetSourcesReconciler.go
│ │ │ └── virtualservicesReconciler.go
│ │ ├── helper.go
│ │ ├── ingress
│ │ ├── controller.go
│ │ └── handler.go
│ │ └── service
│ │ ├── controller.go
│ │ └── handler.go
└── shared
│ ├── .import-restrictions
│ ├── const.go
│ ├── dns_utils.go
│ ├── dns_utils_test.go
│ ├── issuerinfo.go
│ ├── issuerkeyitf.go
│ ├── legobridge
│ ├── cakeypair.go
│ ├── cakeypair_test.go
│ ├── certificate.go
│ ├── certificate_test.go
│ ├── delegatingprovider.go
│ ├── delegatingprovider_test.go
│ ├── dnscontrollerprovider.go
│ ├── dnsrecordprovider.go
│ ├── keystores.go
│ ├── keystores_test.go
│ ├── legobridge_suite_test.go
│ ├── pending.go
│ ├── pending_test.go
│ ├── pki.go
│ ├── pki_test.go
│ └── reguser.go
│ ├── metrics
│ └── metrics.go
│ ├── shared_suite_test.go
│ ├── utils_certificate.go
│ └── utils_certificate_test.go
├── renovate.json5
├── skaffold.yaml
└── test
├── certman2
├── .import-restrictions
└── integration
│ └── controller
│ ├── issuer
│ ├── issuer_suite_test.go
│ └── issuer_test.go
│ └── source
│ ├── source_suite_test.go
│ ├── source_test.go
│ └── testdata
│ ├── crd-gateways.gateway.networking.k8s.io_v1.yaml
│ ├── crd-gateways.networking.istio.io_v1.yaml
│ ├── crd-httproutes.gateway.networking.k8s.io_v1.yaml
│ └── crd-virtualservices.networking.istio.io_v1.yaml
├── functional
├── .import-restrictions
├── basics.go
├── config
│ ├── config.go
│ └── utils.go
├── dnsrecords.go
├── functest-config-kind.yaml
├── functest-config.yaml
├── resources
│ └── 10-crd-extensions.gardener.cloud_dnsrecords.yaml
├── run.sh
├── suite.go
└── suite_test.go
├── integration
├── .import-restrictions
└── controller
│ └── issuer
│ ├── certificate_test.go
│ ├── issuer_suite_test.go
│ └── issuer_test.go
└── utils
├── generate_cert.go
├── logbridge.go
└── pebble.go
/.ci/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2018 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 |
9 | cd "$(dirname "$0")/.."
10 | echo "running build..."
11 | make release
12 |
--------------------------------------------------------------------------------
/.ci/prepare_release:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | #
3 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 |
9 |
10 | # add full-fleshed tar and helm
11 | BASE_URL="https://get.helm.sh"
12 | HELM_VERSION=v2.17.0
13 | TAR_FILE="helm-${HELM_VERSION}-linux-amd64.tar.gz"
14 |
15 | apk add --update --no-cache curl ca-certificates tar
16 | curl -L ${BASE_URL}/${TAR_FILE} |tar xvz
17 | mv linux-amd64/helm /usr/bin/helm
18 | chmod +x /usr/bin/helm
19 |
20 |
21 | if [[ -z "${SOURCE_PATH}" ]]; then
22 | export SOURCE_PATH="$(readlink -f "$(dirname ${0})/..")"
23 | else
24 | export SOURCE_PATH="$(readlink -f "${SOURCE_PATH}")"
25 | fi
26 |
27 | ## currently disabled, as controller registration happens per shoot by extension-shoot-cert-service
28 | #"${SOURCE_PATH}/hack/generate-controller-registration.sh" \
29 | # cert-management \
30 | # "${SOURCE_PATH}/charts/cert-management/" \
31 | # "${SOURCE_PATH}/examples/gardener-controllerregistration.yaml" \
32 | # Issuer:gardener
33 |
34 | VERSION_FILE="$(readlink -f "${SOURCE_PATH}/VERSION")"
35 | VERSION="$(cat "${VERSION_FILE}")"
36 | VERSIONTAG="${VERSION//-dev/-master}"
37 |
38 | sed -i -e "s/ tag: .*/ tag: ${VERSIONTAG}/" "${SOURCE_PATH}/charts/cert-management/values.yaml"
39 |
--------------------------------------------------------------------------------
/.ci/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2018 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 |
9 | cd "$(dirname "$0")/.."
10 | echo "Running tests..."
11 | make test
12 |
--------------------------------------------------------------------------------
/.ci/verify:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o errexit
4 | set -o nounset
5 | set -o pipefail
6 |
7 | cd "$(dirname $0)/.."
8 |
9 | git config --global user.email "gardener@sap.com"
10 | git config --global user.name "Gardener CI/CD"
11 |
12 | export GOTOOLCHAIN=auto
13 | make verify-extended
14 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | **
3 |
4 | # Exclude folders relevant for build
5 | !.git
6 | !.dockerignore
7 | !charts/
8 | !cmd/
9 | !pkg/
10 | !hack/
11 | !go.mod
12 | !go.sum
13 | !Makefile
14 | !VERSION
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Report a bug
4 | labels: kind/bug
5 |
6 | ---
7 |
8 | **What happened**:
9 |
10 | **What you expected to happen**:
11 |
12 | **How to reproduce it (as minimally and precisely as possible)**:
13 |
14 | **Anything else we need to know**:
15 |
16 | **Environment**:
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Enhancement Request
3 | about: Suggest an enhancement
4 | labels: kind/enhancement
5 |
6 | ---
7 |
8 | **What would you like to be added**:
9 |
10 | **Why is this needed**:
11 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Create PRs for golang version updates
4 | - package-ecosystem: docker
5 | directory: /
6 | schedule:
7 | interval: daily
8 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | **How to categorize this PR?**
2 |
12 | /kind TODO
13 |
14 | **What this PR does / why we need it**:
15 |
16 | **Which issue(s) this PR fixes**:
17 | Fixes #
18 |
19 | **Special notes for your reviewer**:
20 |
21 | **Release note**:
22 |
31 | ```other operator
32 |
33 | ```
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | .idea/
3 | !.idea/copyright/
4 | *.sw[pq]
5 | tmp/
6 | /dev/
7 | /local/
8 | /cmd/cert-controller-manager/cert-controller-manager
9 | /cert-controller-manager
10 | /certman2
11 | .vscode/
12 | .kubeconfig-kind-integration
13 |
14 | *.coverprofile
15 | *.html
16 |
17 | # gosec
18 | gosec-report.sarif
19 |
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | run:
3 | concurrency: 4
4 | linters:
5 | enable:
6 | - copyloopvar
7 | - ginkgolinter
8 | - importas
9 | - nilerr
10 | - revive
11 | - whitespace
12 | settings:
13 | loggercheck:
14 | require-string-key: true
15 | no-printf-like: true
16 | revive:
17 | rules:
18 | - name: duplicated-imports
19 | - name: unused-parameter
20 | - name: unreachable-code
21 | - name: context-as-argument
22 | - name: early-return
23 | - name: exported
24 | exclusions:
25 | generated: lax
26 | rules:
27 | - linters:
28 | - staticcheck
29 | text: 'SA1019:'
30 | - linters:
31 | - staticcheck
32 | text: 'ST1001:' # should not use dot imports
33 | - path: (.+)\.go$
34 | text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked
35 | - path: (.+)\.go$
36 | text: var-naming
37 | - path: (.+)\.go$
38 | text: dot-imports
39 | - path: (.+)\.go$
40 | text: package-comments
41 | - path: (.+)\.go$
42 | text: unexported-return
43 | - path: (.+)\.go$
44 | text: indent-error-flow
45 | - path: (.+)\.go$
46 | text: 'exported: (type|func) name will be used as .* by other packages, and that stutters;'
47 | - path: (.+)\.go$
48 | text: 'undeclared name: `.*`'
49 | - path: (.+)\.go$
50 | text: '".*" imported but not used'
51 | - path: (.+)\.go$
52 | text: 'structured logging message should be capitalized: "garden(er-apiserver|er-controller-manager|er-admission-controller|er-operator|er-resource-manager|let)'
53 | paths:
54 | - zz_generated.*\.go$
55 | - test/functional/config
56 | - third_party$
57 | - builtin$
58 | - examples$
59 | formatters:
60 | exclusions:
61 | generated: lax
62 | paths:
63 | - third_party$
64 | - builtin$
65 | - examples$
66 |
--------------------------------------------------------------------------------
/.idea/copyright/Gardener.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.reuse/dep5:
--------------------------------------------------------------------------------
1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: Gardener cert-management
3 | Upstream-Contact: The Gardener project
4 | Source: https://github.com/gardener/cert-management
5 |
6 | # --------------------------------------------------
7 | # source code
8 |
9 | Files: *
10 | Copyright: 2017-2024 SAP SE or an SAP affiliate company and Gardener contributors
11 | License: Apache-2.0
12 |
13 | # --------------------------------------------------
14 | # documentation
15 |
16 | Files: *.md
17 | Copyright: 2017-2024 SAP SE or an SAP affiliate company and Gardener contributors
18 | License: CC-BY-4.0
19 |
20 | # --------------------------------------------------
21 | # third-party
22 |
23 | # --- copied source code ---
24 | # Files:
25 | # Copyright:
26 | # License:
27 |
28 | # --- vendor folder dependencies ---
29 | # Files:
30 | # Copyright:
31 | # License:
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Please refer to the [Gardener contributor guide](https://gardener.cloud/docs/contribute).
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2018 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ############# builder #############
6 | FROM golang:1.24.3 AS builder
7 |
8 | WORKDIR /build
9 |
10 | # Copy go mod and sum files
11 | COPY go.mod go.sum ./
12 | # Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
13 | RUN go mod download
14 |
15 | COPY . .
16 |
17 | RUN make release
18 |
19 | ############# base
20 | FROM gcr.io/distroless/static-debian12:nonroot AS base
21 |
22 | ############# cert-controller-manager #############
23 | FROM base AS cert-controller-manager
24 |
25 | WORKDIR /
26 | COPY --from=builder /build/cert-controller-manager /cert-controller-manager
27 |
28 | ENTRYPOINT ["/cert-controller-manager"]
29 |
--------------------------------------------------------------------------------
/OWNERS:
--------------------------------------------------------------------------------
1 | # See the OWNERS docs at https://go.k8s.io/owners
2 |
3 | reviewers:
4 | - cert-management-reviewers
5 | approvers:
6 | - cert-management-approvers
7 |
--------------------------------------------------------------------------------
/OWNERS_ALIASES:
--------------------------------------------------------------------------------
1 | # See the OWNERS docs at https://go.k8s.io/owners
2 |
3 | aliases:
4 | cert-management-reviewers:
5 | - MartinWeindel
6 | - marc1404
7 | cert-management-approvers:
8 | - MartinWeindel
9 | - marc1404
10 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | v0.17.7-dev
--------------------------------------------------------------------------------
/charts/cert-management/.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 | .vscode/
23 |
--------------------------------------------------------------------------------
/charts/cert-management/Chart.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: v1
6 | appVersion: "1.0"
7 | description: A Helm chart for the cert-management component
8 | name: cert-management
9 | version: 0.1.0
10 |
--------------------------------------------------------------------------------
/charts/cert-management/templates/0helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "cert-management.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 "cert-management.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 "cert-management.chart" -}}
31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
32 | {{- end -}}
33 |
34 | {{- define "image" -}}
35 | {{- if hasPrefix "sha256:" (required "$.tag is required" $.tag) -}}
36 | {{ required "$.repository is required" $.repository }}@{{ required "$.tag is required" $.tag }}
37 | {{- else -}}
38 | {{ required "$.repository is required" $.repository }}:{{ required "$.tag is required" $.tag }}
39 | {{- end -}}
40 | {{- end -}}
41 |
--------------------------------------------------------------------------------
/charts/cert-management/templates/ca-certificates-configmap.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | {{- if .Values.configuration.caCertificates }}
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: {{ include "cert-management.fullname" . }}-ca-certificates
7 | namespace: {{ .Release.Namespace }}
8 | labels:
9 | helm.sh/chart: {{ include "cert-management.chart" . }}
10 | app.kubernetes.io/name: {{ include "cert-management.name" . }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | app.kubernetes.io/managed-by: {{ .Release.Service }}
13 | data:
14 | certs.pem: {{- toYaml .Values.configuration.caCertificates | indent 2 }}
15 | {{- end}}
--------------------------------------------------------------------------------
/charts/cert-management/templates/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ---
6 | apiVersion: rbac.authorization.k8s.io/v1
7 | kind: ClusterRoleBinding
8 | metadata:
9 | name: {{ include "cert-management.fullname" . }}
10 | labels:
11 | helm.sh/chart: {{ include "cert-management.chart" . }}
12 | app.kubernetes.io/name: {{ include "cert-management.name" . }}
13 | app.kubernetes.io/instance: {{ .Release.Name }}
14 | app.kubernetes.io/managed-by: {{ .Release.Service }}
15 | roleRef:
16 | apiGroup: rbac.authorization.k8s.io
17 | kind: ClusterRole
18 | name: {{ include "cert-management.fullname" . }}
19 | subjects:
20 | - kind: ServiceAccount
21 | name: {{ include "cert-management.fullname" . }}
22 | namespace: {{ .Release.Namespace }}
23 |
--------------------------------------------------------------------------------
/charts/cert-management/templates/role.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ---
6 | apiVersion: rbac.authorization.k8s.io/v1
7 | kind: Role
8 | metadata:
9 | name: {{ include "cert-management.fullname" . }}
10 | namespace: {{ .Release.Namespace }}
11 | labels:
12 | helm.sh/chart: {{ include "cert-management.chart" . }}
13 | app.kubernetes.io/name: {{ include "cert-management.name" . }}
14 | app.kubernetes.io/instance: {{ .Release.Name }}
15 | app.kubernetes.io/managed-by: {{ .Release.Service }}
16 | rules:
17 | - apiGroups:
18 | - ""
19 | resources:
20 | - configmaps
21 | resourceNames:
22 | - {{ include "cert-management.fullname" . }}-controllers
23 | verbs:
24 | - get
25 | - update
26 | - apiGroups:
27 | - ""
28 | resources:
29 | - configmaps
30 | verbs:
31 | - create
32 | - apiGroups:
33 | - coordination.k8s.io
34 | resources:
35 | - leases
36 | verbs:
37 | - create
38 | - apiGroups:
39 | - coordination.k8s.io
40 | resources:
41 | - leases
42 | resourceNames:
43 | - {{ include "cert-management.fullname" . }}-controllers
44 | verbs:
45 | - get
46 | - watch
47 | - update
48 |
--------------------------------------------------------------------------------
/charts/cert-management/templates/rolebinding.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ---
6 | apiVersion: rbac.authorization.k8s.io/v1
7 | kind: RoleBinding
8 | metadata:
9 | name: {{ include "cert-management.fullname" . }}
10 | namespace: {{ .Release.Namespace }}
11 | labels:
12 | helm.sh/chart: {{ include "cert-management.chart" . }}
13 | app.kubernetes.io/name: {{ include "cert-management.name" . }}
14 | app.kubernetes.io/instance: {{ .Release.Name }}
15 | app.kubernetes.io/managed-by: {{ .Release.Service }}
16 | roleRef:
17 | apiGroup: rbac.authorization.k8s.io
18 | kind: Role
19 | name: {{ include "cert-management.fullname" . }}
20 | subjects:
21 | - kind: ServiceAccount
22 | name: {{ include "cert-management.fullname" . }}
23 | namespace: {{ .Release.Namespace }}
24 |
--------------------------------------------------------------------------------
/charts/cert-management/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ---
6 | apiVersion: v1
7 | kind: ServiceAccount
8 | metadata:
9 | name: {{ include "cert-management.fullname" . }}
10 | namespace: {{ .Release.Namespace }}
11 | labels:
12 | helm.sh/chart: {{ include "cert-management.chart" . }}
13 | app.kubernetes.io/name: {{ include "cert-management.name" . }}
14 | app.kubernetes.io/instance: {{ .Release.Name }}
15 | app.kubernetes.io/managed-by: {{ .Release.Service }}
16 |
--------------------------------------------------------------------------------
/cmd/cert-controller-manager/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/cmd/certman2/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - github.com/gardener/cert-management/cmd/certman2
5 | - github.com/gardener/cert-management/pkg/apis
6 | - github.com/gardener/cert-management/pkg/certman2
7 | - github.com/gardener/cert-management/pkg/shared
8 | - selectorRegexp: github[.]com/gardener/controller-manager-library
9 | forbiddenPrefixes:
10 | - ''
11 |
--------------------------------------------------------------------------------
/cmd/certman2/main.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package main
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/gardener/gardener/cmd/utils"
12 | "sigs.k8s.io/controller-runtime/pkg/manager/signals"
13 |
14 | "github.com/gardener/cert-management/cmd/certman2/app"
15 | )
16 |
17 | func main() {
18 | utils.DeduplicateWarnings()
19 |
20 | if err := app.NewCommand().ExecuteContext(signals.SetupSignalHandler()); err != nil {
21 | fmt.Println(err)
22 | os.Exit(1)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/10-crds.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # required CRDs will be deployed automatically by the controllers
3 | # therefore there is no need to deploy those CRDs manually.
4 | #
--------------------------------------------------------------------------------
/examples/20-issuer-ca.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: v1
6 | data:
7 | tls.crt: ...
8 | tls.key: ...
9 | kind: Secret
10 | metadata:
11 | name: issuer-ca-secret
12 | type: kubernetes.io/tls
13 | ---
14 | apiVersion: cert.gardener.cloud/v1alpha1
15 | kind: Issuer
16 | metadata:
17 | name: issuer-ca
18 | namespace: default
19 | spec:
20 | ca:
21 | privateKeySecretRef:
22 | name: issuer-ca-secret
23 | namespace: default
24 |
--------------------------------------------------------------------------------
/examples/20-issuer-productive.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Issuer
7 | metadata:
8 | name: issuer-prod
9 | namespace: default
10 | spec:
11 | acme:
12 | server: https://acme-v02.api.letsencrypt.org/directory
13 | email: some.user@mydomain.com
14 | autoRegistration: true
15 |
--------------------------------------------------------------------------------
/examples/20-issuer-selfsigned.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: cert.gardener.cloud/v1alpha1
2 | kind: Issuer
3 | metadata:
4 | name: issuer-selfsigned
5 | namespace: default
6 | spec:
7 | selfSigned: {}
8 |
--------------------------------------------------------------------------------
/examples/20-issuer-staging.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Issuer
7 | metadata:
8 | name: issuer-staging
9 | namespace: default
10 | spec:
11 | acme:
12 | server: https://acme-staging-v02.api.letsencrypt.org/directory
13 | email: some.user@mydomain.com
14 | autoRegistration: true
15 | # with 'autoRegistration: true' a new account will be created if the secretRef is not existing
16 | privateKeySecretRef:
17 | name: issuer-staging-secret
18 | namespace: default
--------------------------------------------------------------------------------
/examples/21-issuer-acme-eab.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Issuer
7 | metadata:
8 | name: issuer-with-external-account
9 | namespace: default
10 | spec:
11 | acme:
12 | server: https://some.acme.provider.com/directory
13 | email: some.user@mydomain.com
14 | autoRegistration: true
15 | externalAccountBinding:
16 | keyID: mykey
17 | keySecretRef:
18 | # the secret must contain the data key 'hmacKey'
19 | name: issuer-external-account-secret
20 | namespace: default
21 | # For some special setups, the DNS challenges are only performed pro forma. In this case the
22 | # DNS Entry creation and DNS propagation check can be disabled with 'skipDNSChallengeValidation: true'
23 | # skipDNSChallengeValidation: true
24 |
25 | # optionally restrict domain ranges for which certificates can be requested
26 | # domains:
27 | # include:
28 | # - sub1.mydomain.com
29 | # - sub2.mydomain.com
30 | # exclude:
31 | # - private.sub1.mydomain.com
--------------------------------------------------------------------------------
/examples/30-cert-ca.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Certificate
7 | metadata:
8 | name: cert-ca
9 | namespace: default
10 | spec:
11 | commonName: cert1.mydomain.com
12 | dnsNames:
13 | - cert1.my-other-domain.com
14 | # if issuer is not specified, the default issuer is used
15 | issuerRef:
16 | name: issuer-ca
17 | # optionally specify secret to store certificate
18 | secretRef:
19 | name: cert-ca-secret
20 | namespace: default
21 |
--------------------------------------------------------------------------------
/examples/30-cert-csr.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Certificate
7 | metadata:
8 | name: cert-csr
9 | namespace: default
10 | spec:
11 | csr: ...
12 | issuerRef:
13 | name: issuer-staging
14 | # optionally specify secret to store certificate
15 | secretRef:
16 | name: cert-csr-secret
17 | namespace: default
--------------------------------------------------------------------------------
/examples/30-cert-selfsigned.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: cert.gardener.cloud/v1alpha1
2 | kind: Certificate
3 | metadata:
4 | name: cert-selfsigned
5 | namespace: default
6 | spec:
7 | commonName: ca1.mydomain.com
8 | isCA: true
9 | # optional: default is 90 days (2160h). Must be at least 2*30 days (1440h) with the default renewal window of 30 days.
10 | # duration: 1440h
11 | # optional defaults to RSA 2048
12 | # privateKey:
13 | # algorithm: ECDSA
14 | # size: 384
15 | # CSR can also be specified
16 | # csr: ...
17 | issuerRef:
18 | name: issuer-selfsigned
19 | namespace: default # must be specified when issuer runs in shoot!
20 | # optional: secret where the certificate should be stored
21 | #secretRef:
22 | # name: cert-selfsigned-foo
23 | # namespace: default
24 |
--------------------------------------------------------------------------------
/examples/30-cert-simple-with-keystores.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Certificate
7 | metadata:
8 | annotations:
9 | # class annotation only needed if cert-controller-manager is started with --cert-class=myclass
10 | #cert.gardener.cloud/class: myclass
11 | name: cert-simple-with-keystores
12 | namespace: default
13 | spec:
14 | commonName: cert1.mydomain.com
15 | dnsNames:
16 | - cert1.my-other-domain.com
17 | # optionally specify secret to store certificate
18 | secretRef:
19 | name: cert-simple-secret
20 | namespace: default
21 | # optionally set labels for the secret
22 | #secretLabels:
23 | # key1: value1
24 | # key2: value2
25 |
26 | # enable keystore creation for both JKS and PKCS#12
27 | # This will create additional data entries in the certificate secret named `keystore.jks`, `truststore.jks` for JKS
28 | # and `keystore.p12`, `truststore.p12` for PKCS#12
29 | keystores:
30 | jks:
31 | create: true
32 | passwordSecretRef:
33 | secretName: keystore-secret
34 | key: password
35 | pkcs12:
36 | create: true
37 | passwordSecretRef:
38 | secretName: keystore-secret
39 | key: password
40 | ---
41 | apiVersion: v1
42 | kind: Secret
43 | metadata:
44 | name: keystore-secret
45 | namespace: default
46 | data:
47 | password: cGFzcw== # example password is `pass`
--------------------------------------------------------------------------------
/examples/30-cert-simple.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Certificate
7 | metadata:
8 | annotations:
9 | # class annotation only needed if cert-controller-manager is started with --cert-class=myclass
10 | #cert.gardener.cloud/class: myclass
11 | # annotations needed when using DNSRecords
12 | #cert.gardener.cloud/dnsrecord-provider-type: aws-route53
13 | #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret
14 | #cert.gardener.cloud/dnsrecord-class: garden # optional, only required on Garden runtime cluster
15 | name: cert-simple
16 | namespace: default
17 | spec:
18 | commonName: cert1.mydomain.com
19 | dnsNames:
20 | - cert1.my-other-domain.com
21 | # if issuer is not specified, the default issuer is used
22 | issuerRef:
23 | name: issuer-staging
24 | # for shoot issuers, the namespace must be specified
25 | #namespace: my-ns
26 | # optionally specify secret to store certificate
27 | secretRef:
28 | name: cert-simple-secret
29 | namespace: default
30 | # optionally set labels for the secret
31 | #secretLabels:
32 | # key1: value1
33 | # key2: value2
34 |
35 | # If delegated domain for DNS01 challenge should be used. This has only an effect if a CNAME record is set for
36 | # either '_acme-challenge.cert1.mydomain.com' or '_acme-challenge.cert1.my-other-domain.com'.
37 | # For example: If a CNAME record exists '_acme-challenge.cert1.mydomain.com' => '_acme-challenge.writable.domain.com',
38 | # the DNS challenge will be written to '_acme-challenge.writable.domain.com'.
39 | # followCNAME: true
40 |
41 | # Optionally specify the preferred certificate chain: if the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used.
42 | # preferredChain: "ISRG Root X1"
43 |
44 | # Optionally specify algorithm and key size for private key
45 | # privateKey:
46 | # algorithm: ECDSA
47 | # size: 384
--------------------------------------------------------------------------------
/examples/30-cert-wildcard.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: Certificate
7 | metadata:
8 | name: cert-wildcard
9 | namespace: default
10 | spec:
11 | commonName: "*.cert2.martin.mydomain.com"
12 | issuerRef:
13 | name: issuer-staging
14 | # optionally specify secret to store certificate
15 | secretRef:
16 | name: cert-wildcard-secret
17 | namespace: default
18 | # optionally set labels for the secret
19 | #secretLabels:
20 | # key1: value1
21 | # key2: value2
--------------------------------------------------------------------------------
/examples/40-gateway-gateway-api.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: Gateway
3 | metadata:
4 | annotations:
5 | cert.gardener.cloud/purpose: managed
6 | #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from spec.tls[].hosts is used as common name
7 | #cert.gardener.cloud/dnsnames: "" # optional, if not specified the names from spec.tls[].hosts are used
8 | #cert.gardener.cloud/follow-cname: "true" # optional, to activate CNAME following for the DNS challenge
9 | #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret
10 | #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers)
11 | #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer)
12 | #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA'
13 | #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384"
14 | # annotations needed when using DNSRecords
15 | #cert.gardener.cloud/dnsrecord-provider-type: aws-route53
16 | #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret
17 | name: my-gateway
18 | namespace: default
19 | spec:
20 | gatewayClassName: my-gateway-class
21 | listeners:
22 | - allowedRoutes:
23 | namespaces:
24 | from: Selector
25 | selector:
26 | matchLabels:
27 | shared-gateway-access: "true"
28 | hostname: foo.example.com
29 | name: https
30 | port: 443
31 | protocol: HTTPS
32 | tls:
33 | certificateRefs:
34 | - name: my-tls-secret # note: listeners are only considered if they have exactly one certificateRefs item
--------------------------------------------------------------------------------
/examples/40-gateway-istio.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1
2 | kind: Gateway
3 | metadata:
4 | annotations:
5 | cert.gardener.cloud/purpose: managed
6 | #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from spec.tls[].hosts is used as common name
7 | #cert.gardener.cloud/dnsnames: "" # optional, if not specified the names from spec.tls[].hosts are used
8 | #cert.gardener.cloud/follow-cname: "true" # optional, to activate CNAME following for the DNS challenge
9 | #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret
10 | #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers)
11 | #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer)
12 | #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA'
13 | #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384"
14 | #cert.gardener.cloud/secret-namespace: "istio-system" # optional to specify the namespace where the certificate secret should be created
15 | name: my-gateway
16 | namespace: default
17 | spec:
18 | selector:
19 | istio: ingressgateway
20 | servers:
21 | - hosts:
22 | - uk.example.com
23 | - eu.example.com
24 | port:
25 | name: https-443
26 | number: 443
27 | protocol: HTTPS
28 | tls: # this server is ignored by the cert-controller-manager, as `tls.credentialName` is not set
29 | mode: SIMPLE
30 | privateKey: /etc/certs/privatekey.pem
31 | serverCertificate: /etc/certs/servercert.pem
32 | - hosts:
33 | - bookinfo-namespace/*.example2.com
34 | port:
35 | name: https-9443
36 | number: 9443
37 | protocol: HTTPS
38 | tls:
39 | credentialName: my-secret # only servers with credentialName will be considered
40 | mode: SIMPLE
--------------------------------------------------------------------------------
/examples/40-ingress-echoheaders.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: networking.k8s.io/v1
6 | kind: Ingress
7 | metadata:
8 | name: echoheaders
9 | namespace: default
10 | annotations:
11 | cert.gardener.cloud/purpose: managed
12 | #dns.gardener.cloud/class: garden # needed on Gardener shoot clusters for managed DNS record creation
13 | #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from spec.tls[].hosts is used as common name
14 | #cert.gardener.cloud/dnsnames: "" # optional, if not specified the names from spec.tls[].hosts are used
15 | #cert.gardener.cloud/follow-cname: "true" # optional, same as spec.followCNAME in certificates
16 | #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret
17 | #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers)
18 | #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer)
19 | #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA'
20 | #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384"
21 | # annotations needed when using DNSRecords
22 | #cert.gardener.cloud/dnsrecord-provider-type: aws-route53
23 | #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret
24 | spec:
25 | tls:
26 | - hosts:
27 | - echoheaders.demo.mydomain.com
28 | secretName: cert-echoheaders
29 | rules:
30 | - host: echoheaders.demo.mydomain.com
31 | http:
32 | paths:
33 | - backend:
34 | service:
35 | name: echoheaders
36 | port:
37 | number: 80
38 | path: /
39 | pathType: Prefix
40 |
--------------------------------------------------------------------------------
/examples/40-service-loadbalancer.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: v1
6 | kind: Service
7 | metadata:
8 | annotations:
9 | cert.gardener.cloud/secretname: test-service-secret
10 | dns.gardener.cloud/dnsnames: test-service.demo.mydomain.com
11 | dns.gardener.cloud/ttl: "600"
12 | #dns.gardener.cloud/class: garden # needed on Gardener shoot clusters for managed DNS record creation
13 | #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from dns.gardener.cloud/dnsnames is used as common name
14 | #cert.gardener.cloud/dnsnames: "" # optional, if specified overrides dns.gardener.cloud/dnsnames annotation for certificate names
15 | #cert.gardener.cloud/follow-cname: "true" # optional, same as spec.followCNAME in certificates
16 | #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret
17 | #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers)
18 | #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer)
19 | #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA'
20 | #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384"
21 | #cert.gardener.cloud/secret-namespace: "my-namespace" # optional to specify the namespace where the certificate secret should be created
22 |
23 | # annotations needed when using DNSRecords
24 | #cert.gardener.cloud/dnsrecord-provider-type: aws-route53
25 | #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret
26 |
27 | name: test-service
28 | namespace: default
29 | spec:
30 | ports:
31 | - name: http
32 | port: 80
33 | protocol: TCP
34 | targetPort: 8080
35 | type: LoadBalancer
--------------------------------------------------------------------------------
/examples/50-certificate-revocation.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | apiVersion: cert.gardener.cloud/v1alpha1
6 | kind: CertificateRevocation
7 | metadata:
8 | name: revoke-sample
9 | namespace: default
10 | spec:
11 | certificateRef:
12 | name: mycert
13 | namespace: default
14 |
15 | # Uncomment the following line if the certificate should be renewed before revoking the old one(s)
16 | #renew: true
17 |
18 | # Optionally specify a qualifying date. All certificates requested before this date will be revoked.
19 | # If not specified, the current time is used by default.
20 | #qualifyingDate: "2020-12-22T17:00:35Z"
21 |
--------------------------------------------------------------------------------
/hack/LICENSE_BOILERPLATE.txt:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
--------------------------------------------------------------------------------
/hack/copy-crds.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 |
8 | set -e
9 |
10 | source_dir="$(dirname "$0")/../pkg/apis/cert/crds"
11 | destination_dir="$(dirname "$0")/../charts/cert-management/templates/"
12 |
13 | # Function to update the metadata section and copy to destination
14 | update_and_copy() {
15 | local source_file="$1"
16 | local dest_file="$2"
17 |
18 | # Use awk to update the metadata and copy to destination
19 | awk '/^metadata:/ {
20 | print
21 | metadata_found = 1
22 | if ($0 == "metadata:") {
23 | print " labels:"
24 | print " helm.sh/chart: {{ include \"cert-management.chart\" . }}"
25 | print " app.kubernetes.io/name: {{ include \"cert-management.name\" . }}"
26 | print " app.kubernetes.io/instance: {{ .Release.Name }}"
27 | print " app.kubernetes.io/managed-by: {{ .Release.Service }}"
28 | }
29 | next
30 | }
31 | metadata_found == 1 { metadata_found = 0 }
32 | {print}' "$source_file" > "$dest_file"
33 | }
34 |
35 | # Function to add header and footer lines
36 | add_header_and_footer() {
37 | local source_file="$1"
38 | local temp_file="$(mktemp)"
39 |
40 | # Add header, original content, and footer to a temporary file
41 | {
42 | if [[ "$source_file" == *"cert.gardener.cloud_issuers.yaml" ]]; then
43 | echo '{{- if .Values.createCRDs.issuers }}'
44 | else
45 | echo '{{- if .Values.createCRDs.certificates }}'
46 | fi
47 | cat "$source_file"
48 | echo '{{- end }}'
49 | } > "$temp_file"
50 |
51 | # Move the temporary file to the original source file
52 | mv "$temp_file" "$source_file"
53 | }
54 |
55 | # Iterate through each YAML file in the source directory
56 | for source_file in "$source_dir"/*.yaml; do
57 | if [ -f "$source_file" ]; then
58 | dest_file="$destination_dir/$(basename "$source_file")"
59 | update_and_copy "$source_file" "$dest_file"
60 | add_header_and_footer "$dest_file"
61 | fi
62 | done
63 |
--------------------------------------------------------------------------------
/hack/generate-code:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 |
9 | SOURCE_PATH="$(readlink -f "$(dirname ${0})/..")"
10 |
11 | PROJECT_ROOT=$(dirname $0)/..
12 |
13 | # setup virtual GOPATH
14 | export REPO_ROOT=${REPO_ROOT}
15 | source "$GARDENER_HACK_DIR"/vgopath-setup.sh
16 |
17 | # cleanup generated files
18 | rm -f ${GOPATH}/bin/*-gen
19 | rm -rf "${SOURCE_PATH}/pkg/client/cert"
20 |
21 | CODE_GEN_DIR=$(go list -m -f '{{.Dir}}' k8s.io/code-generator)
22 | source "${CODE_GEN_DIR}/kube_codegen.sh"
23 |
24 | kube::codegen::gen_helpers \
25 | --boilerplate "${PROJECT_ROOT}/hack/LICENSE_BOILERPLATE.txt" \
26 | "${PROJECT_ROOT}/pkg/apis"
27 |
28 | kube::codegen::gen_helpers \
29 | --boilerplate "${PROJECT_ROOT}/hack/LICENSE_BOILERPLATE.txt" \
30 | --extra-peer-dir k8s.io/apimachinery/pkg/apis/meta/v1 \
31 | --extra-peer-dir k8s.io/apimachinery/pkg/conversion \
32 | --extra-peer-dir k8s.io/component-base/config \
33 | --extra-peer-dir k8s.io/component-base/config/v1alpha1 \
34 | "${PROJECT_ROOT}/pkg/certman2/apis/config"
35 |
36 | kube::codegen::gen_client \
37 | --with-watch \
38 | --one-input-api "cert/v1alpha1" \
39 | --output-dir "${PROJECT_ROOT}/pkg/client/cert" \
40 | --output-pkg "github.com/gardener/cert-management/pkg/client/cert" \
41 | --boilerplate "${PROJECT_ROOT}/hack/LICENSE_BOILERPLATE.txt" \
42 | "${PROJECT_ROOT}/pkg/apis"
43 |
--------------------------------------------------------------------------------
/hack/generate-renovate-ignore-deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | # Takes the content of a go.mod file and an array to add the extracted dependencies to.
8 | extract_dependencies() {
9 | local go_mod=$1
10 | local dependencies=$2
11 |
12 | while IFS= read -r line; do
13 | dependency=$(echo "$line" | awk '{print $1}') # Splits the line by spaces and takes the first part omitting the version and the //indirect comment.
14 | eval "$dependencies+=('$dependency')"
15 | done <<< "$go_mod"
16 | }
17 |
18 | echo "🪧 Generating ignoreDeps section for 'renovate.json5'"
19 | echo "🛜 Downloading the latest 'go.mod' from gardener/gardener..."
20 |
21 | # Only the dependencies in a `go.mod` file are indented with a tab.
22 | certman_go_mod=$(grep -P '^\t' go.mod) # Uses Perl-style regular expressions to match a tab at the beginning of a line.
23 | gardener_go_mod=$(curl -s https://raw.githubusercontent.com/gardener/gardener/refs/heads/master/go.mod | grep -P '^\t')
24 |
25 | certman_dependencies=()
26 | gardener_dependencies=()
27 |
28 | extract_dependencies "$certman_go_mod" certman_dependencies
29 | extract_dependencies "$gardener_go_mod" gardener_dependencies
30 |
31 | echo "📜 Found ${#certman_dependencies[@]} cert-manager dependencies."
32 | echo "🚜 Found ${#gardener_dependencies[@]} gardener dependencies."
33 |
34 | # Extract the intersection of the two arrays by iterating over them in a nested fashion.
35 | common_dependencies=()
36 |
37 | for certman_dependency in "${certman_dependencies[@]}"; do
38 | for gardener_dependency in "${gardener_dependencies[@]}"; do
39 | if [[ "$certman_dependency" == "$gardener_dependency" ]]; then
40 | common_dependencies+=("$certman_dependency")
41 | break # Continue with the next element of the outer loop.
42 | fi
43 | done
44 | done
45 |
46 | echo "☯️ Found ${#common_dependencies[@]} common dependencies."
47 |
48 | ignore_deps=$(printf ',"%s"' "${common_dependencies[@]}") # Add a comma to the beginning of each element and concatenate them.
49 | ignore_deps="[${ignore_deps:1}]" # Remove the leading comma and wrap the string in square brackets to format it as a JSON array.
50 |
51 | # Format the JSON array as a string, indent it, and use sed to replace the lines between the markers
52 | echo "$ignore_deps" | yq -o json '.[]' | sed 's/^/ /; s/$/,/' | sed -i -e ' / ignoreDeps: \[/, /\]/{//!d;}' -e ' / ignoreDeps: \[/r /dev/stdin' renovate.json5
53 |
--------------------------------------------------------------------------------
/hack/generateChartOptions.py:
--------------------------------------------------------------------------------
1 | #!/bin/python
2 |
3 | # SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | # helper script to regenerate helm chart file: partial of charts/cert-management/templates/deployment.yaml
8 |
9 |
10 | import re
11 | import os
12 |
13 | helpFilename = "/tmp/cert-controller-manager-help.txt"
14 | rc = os.system("make build-local && ./cert-controller-manager --help | grep ' --' > {}".format(helpFilename))
15 | if rc != 0:
16 | exit(rc)
17 | f = open(helpFilename,"r")
18 | options = f.read()
19 | os.remove(helpFilename)
20 |
21 | def toCamelCase(name):
22 | str = ''.join(x.capitalize() for x in re.split("[.-]", name))
23 | str = str[0].lower() + str[1:]
24 | return str
25 |
26 | excluded = {"name", "help"}
27 | for line in options.split("\n"):
28 | m = re.match(r"\s+(?:-[^-]+)?--(\S+)\s", line)
29 | if m:
30 | name = m.group(1)
31 | if name != "" and not name in excluded:
32 | camelCase = toCamelCase(name)
33 | txt = """ {{- if .Values.configuration.%s }}
34 | - --%s={{ .Values.configuration.%s }}
35 | {{- end }}""" % (camelCase, name, camelCase)
36 | print(txt)
37 |
38 | print("\n\n\n")
39 |
40 | defaultValues = {
41 | "serverPortHttp": "8080"
42 | }
43 |
44 | print("configuration:")
45 | for line in options.split("\n"):
46 | m = re.match(r"\s+(?:-[^-]+)?--(\S+)\s", line)
47 | if m:
48 | name = m.group(1)
49 | if name != "" and not name in excluded:
50 | camelCase = toCamelCase(name)
51 | if camelCase in defaultValues:
52 | txt = " %s: %s" % (camelCase, defaultValues[camelCase])
53 | else:
54 | txt = "# %s:" % camelCase
55 | print(txt)
--------------------------------------------------------------------------------
/hack/go-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 | set -u
9 | set -o pipefail
10 |
11 | go test $@ | grep -v 'no test files'
12 |
--------------------------------------------------------------------------------
/hack/kind/certman/certman-down.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | kubectl delete -f ${SOURCE_PATH}/dev/manifests.yaml
13 |
--------------------------------------------------------------------------------
/hack/kind/certman/issuer-down.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | kubectl delete issuer kind-issuer
13 |
--------------------------------------------------------------------------------
/hack/kind/certman/issuer-up.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | kubectl apply -f ${SOURCE_PATH}/pkg/apis/cert/crds/cert.gardener.cloud_issuers.yaml
13 |
14 | kubectl wait crd issuers.cert.gardener.cloud --for=condition=NamesAccepted
15 |
16 | cat << EOF | kubectl apply -f -
17 | apiVersion: cert.gardener.cloud/v1alpha1
18 | kind: Issuer
19 | metadata:
20 | name: kind-issuer
21 | namespace: default
22 | spec:
23 | acme:
24 | server: https://acme.certman-support.svc.cluster.local/dir
25 | email: some.user@certman.kind
26 | autoRegistration: true
27 | precheckNameservers:
28 | - 10.96.0.10:53 # service kube-system/kube-dns (coredns)
29 | EOF
30 |
--------------------------------------------------------------------------------
/hack/kind/common.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | # For the check step concourse will set the following environment variables:
8 | # SOURCE_PATH - path to component repository root directory.
9 | if [[ -z "${SOURCE_PATH}" ]]; then
10 | export SOURCE_PATH="$(readlink -f "$(dirname ${0})/../..${1}")"
11 | else
12 | export SOURCE_PATH="$(readlink -f ${SOURCE_PATH})"
13 | fi
14 |
15 | mkdir -p ${SOURCE_PATH}/dev
16 | export KUBECONFIG=${SOURCE_PATH}/dev/kind-kubeconfig.yaml
--------------------------------------------------------------------------------
/hack/kind/dns-controller-manager/dns-controller-manager-up.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | VERSION=v0.18.6
11 |
12 | source $(dirname ${0})/../common.sh /..
13 |
14 | target_dir=${SOURCE_PATH}/dev/external-dns-management-${VERSION#v}
15 |
16 | download_external_dns_management_helm_charts()
17 | {
18 | if [ -d $target_dir ]; then
19 | echo "charts already at $target_dir"
20 | return
21 | fi
22 |
23 | curl -sL "https://github.com/gardener/external-dns-management/archive/refs/tags/$VERSION.tar.gz" | tar xvz -C ${SOURCE_PATH}/dev external-dns-management-${VERSION#v}/charts/external-dns-management
24 | }
25 |
26 | install_dns_controller_manager()
27 | {
28 | kubectl get ns certman-support >/dev/null 2>&1 || kubectl create ns certman-support
29 | helm template $target_dir/charts/external-dns-management -n certman-support \
30 | --set configuration.identifier="host-$(hostname)" \
31 | --set createCRDs=true \
32 | --set vpa.enabled=false \
33 | | kubectl apply -f -
34 | }
35 |
36 | download_external_dns_management_helm_charts
37 | install_dns_controller_manager
--------------------------------------------------------------------------------
/hack/kind/kind-delete-cluster.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/common.sh ''
11 |
12 | export KUBECONFIG=${SOURCE_PATH}/dev/kind-kubeconfig.yaml
13 |
14 | kind delete cluster --name cert-management
15 |
16 | rm -f $KUBECONFIG
17 |
--------------------------------------------------------------------------------
/hack/kind/knot-dns/knot-dns-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | annotations:
5 | dns.gardener.cloud/dnsnames: dns.certman.kind
6 | labels:
7 | app.kubernetes.io/instance: knot-dns
8 | app.kubernetes.io/name: knot-dns
9 | name: knot-dns
10 | namespace: certman-support
11 | spec:
12 | ports:
13 | - name: dns-tcp
14 | port: 53
15 | protocol: TCP
16 | targetPort: 53
17 | nodePort: 30053
18 | - name: dns-udp
19 | port: 53
20 | protocol: UDP
21 | targetPort: 53
22 | nodePort: 30053
23 | selector:
24 | app.kubernetes.io/instance: knot-dns
25 | app.kubernetes.io/name: knot-dns
26 | type: NodePort
--------------------------------------------------------------------------------
/hack/kind/knot-dns/knot-dns-up.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | # dummy password
13 | PASSWORD="123456"
14 | PASSWORD_BASE64=$(echo -n $PASSWORD | base64 -w0)
15 |
16 | wait_for_service()
17 | {
18 | timeout=15
19 |
20 | echo looking up IP address for knot-dns service
21 | for ((i=0; i<$timeout; i++)); do
22 | set +e
23 | SERVICE_IP_ADDRESS=$(kubectl get svc knot-dns -n certman-support '-ojsonpath={.spec.clusterIP}' 2> /dev/null)
24 | set -e
25 | if [ -n "$SERVICE_IP_ADDRESS" ]; then
26 | echo
27 | echo "knot-dns service IP address: $SERVICE_IP_ADDRESS"
28 | return 0
29 | fi
30 | echo -n .
31 | sleep 1
32 | done
33 | echo failed
34 | return 1
35 | }
36 |
37 | kubectl apply -f $(dirname ${0})/crd-dnsprovider.yaml
38 | kubectl get ns certman-support >/dev/null 2>&1 || kubectl create ns certman-support
39 | kubectl apply -f $(dirname ${0})/knot-dns-service.yaml
40 | wait_for_service
41 | kubectl apply -f <(sed -e "s/#secret-injection/$PASSWORD_BASE64/g" $(dirname ${0})/knot-dns-certman-support.yaml.template | \
42 | sed -e "s/#server-injection/$SERVICE_IP_ADDRESS/g")
43 |
44 | # patch coredns on all clusters
45 | $(dirname ${0})/patch-coredns.sh $SERVICE_IP_ADDRESS &
46 |
--------------------------------------------------------------------------------
/hack/kind/knot-dns/patch-coredns.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | knot_dns_ip=$1
8 |
9 | echo patching deployment kube-system/coredns on cluster $(kubectl config current-context)
10 |
11 | # patch configmap coredns to contain "import custom/*.override" and "import custom/*.server"
12 | corefileOrg=$(kubectl -n kube-system get cm coredns '-ojsonpath={.data.Corefile}')
13 | if ! [[ "$corefileOrg" == *"import custom/"* ]]; then
14 | tmp="${corefileOrg/%\}/}"
15 | tmp="${tmp//$'\n'/$'\n' }"
16 | cat < 0 )); then
51 | kubectl -n kube-system delete pod -l k8s-app=kube-dns
52 | else
53 | kubectl -n kube-system patch deploy coredns --patch-file $(dirname ${0})/patch-deployment-coredns.yaml
54 | fi
55 |
56 | echo ""
57 |
--------------------------------------------------------------------------------
/hack/kind/knot-dns/patch-deployment-coredns.yaml:
--------------------------------------------------------------------------------
1 | spec:
2 | template:
3 | spec:
4 | containers:
5 | - name: coredns
6 | volumeMounts:
7 | - mountPath: /etc/coredns/custom
8 | name: custom-config-volume
9 | readOnly: true
10 | volumes:
11 | - configMap:
12 | defaultMode: 420
13 | name: coredns-custom
14 | optional: true
15 | name: custom-config-volume
16 |
--------------------------------------------------------------------------------
/hack/kind/local-issuer/local-issuer-down.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | kubectl delete issuer local-issuer
13 |
--------------------------------------------------------------------------------
/hack/kind/local-issuer/local-issuer-up.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source $(dirname ${0})/../common.sh /..
11 |
12 | kubectl apply -f ${SOURCE_PATH}/pkg/apis/cert/crds/cert.gardener.cloud_issuers.yaml
13 |
14 | kubectl wait crd issuers.cert.gardener.cloud --for=condition=NamesAccepted
15 |
16 | cat << EOF | kubectl apply -f -
17 | apiVersion: cert.gardener.cloud/v1alpha1
18 | kind: Issuer
19 | metadata:
20 | name: local-issuer
21 | namespace: default
22 | spec:
23 | acme:
24 | server: https://localhost:5443/dir
25 | email: some.user@certman.kind
26 | autoRegistration: true
27 | precheckNameservers:
28 | - 127.0.0.1:5053
29 | EOF
30 |
31 | cat << EOF > ${SOURCE_PATH}/dev/source-lego-env.sh
32 | export LEGO_CA_CERTIFICATES=${SOURCE_PATH}/dev/pebble-cert.pem
33 | export LEGO_CA_SYSTEM_CERT_POOL=true
34 | EOF
35 |
36 | echo For running cert-controller-manager outside of the kind cluster,
37 | echo please add these environment variables:
38 | echo
39 | cat ${SOURCE_PATH}/dev/source-lego-env.sh
40 | echo
41 | echo or run "'"source ${SOURCE_PATH}/dev/source-lego-env.sh"'"
--------------------------------------------------------------------------------
/hack/kind/registry/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 | resources:
5 | - registry.yaml
6 |
--------------------------------------------------------------------------------
/hack/kind/registry/base/registry.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: registry
6 | spec:
7 | replicas: 1
8 | strategy:
9 | type: Recreate
10 | template:
11 | spec:
12 | automountServiceAccountToken: false
13 | containers:
14 | - name: registry
15 | image: europe-docker.pkg.dev/gardener-project/releases/3rd/registry:2.8.3
16 | imagePullPolicy: IfNotPresent
17 | ports:
18 | - name: registry
19 | containerPort: 5001
20 | env:
21 | - name: REGISTRY_HTTP_ADDR
22 | value: :5001
23 | volumeMounts:
24 | - name: cache
25 | mountPath: /var/lib/registry
26 | hostNetwork: true
27 | nodeSelector:
28 | node-role.kubernetes.io/control-plane: ""
29 | tolerations:
30 | - effect: NoExecute
31 | operator: Exists
32 | - effect: NoSchedule
33 | operator: Exists
34 | volumes:
35 | - name: cache
36 | hostPath:
37 | path: /var/local-registry
38 | type: DirectoryOrCreate
39 |
--------------------------------------------------------------------------------
/hack/kind/registry/docker/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 |
5 | resources:
6 | - ../base
7 |
8 | patches:
9 | - patch: |
10 | - op: replace
11 | path: /metadata/name
12 | value: docker-io
13 | - op: replace
14 | path: /spec/template/spec/containers/0/env
15 | value:
16 | - name: REGISTRY_PROXY_REMOTEURL
17 | value: https://registry-1.docker.io
18 | - name: REGISTRY_HTTP_ADDR
19 | value: :5009
20 | - op: replace
21 | path: /spec/template/spec/containers/0/ports/0/containerPort
22 | value: 5009
23 | - op: replace
24 | path: /spec/template/spec/volumes/0/hostPath/path
25 | value: /var/local-registry/docker
26 | target:
27 | group: apps
28 | kind: Deployment
29 | name: registry
30 | labels:
31 | - includeSelectors: true
32 | pairs:
33 | upstream: k8s
34 |
--------------------------------------------------------------------------------
/hack/kind/registry/europe-docker-pkg-dev/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 |
5 | resources:
6 | - ../base
7 |
8 | patches:
9 | - patch: |
10 | - op: replace
11 | path: /metadata/name
12 | value: registry-europe-docker-pkg-dev
13 | - op: replace
14 | path: /spec/template/spec/containers/0/env
15 | value:
16 | - name: REGISTRY_PROXY_REMOTEURL
17 | value: https://europe-docker.pkg.dev
18 | - name: REGISTRY_HTTP_ADDR
19 | value: :5008
20 | - op: replace
21 | path: /spec/template/spec/containers/0/ports/0/containerPort
22 | value: 5008
23 | - op: replace
24 | path: /spec/template/spec/volumes/0/hostPath/path
25 | value: /var/local-registry/europe-docker-pkg-dev
26 | target:
27 | group: apps
28 | kind: Deployment
29 | name: registry
30 | labels:
31 | - includeSelectors: true
32 | pairs:
33 | upstream: europe-docker-pkg-dev
34 |
--------------------------------------------------------------------------------
/hack/kind/registry/ghcr/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 |
5 | resources:
6 | - ../base
7 |
8 | patches:
9 | - patch: |
10 | - op: replace
11 | path: /metadata/name
12 | value: registry-ghcr
13 | - op: replace
14 | path: /spec/template/spec/containers/0/env
15 | value:
16 | - name: REGISTRY_PROXY_REMOTEURL
17 | value: https://ghcr.io
18 | - name: REGISTRY_HTTP_ADDR
19 | value: :5005
20 | - op: replace
21 | path: /spec/template/spec/containers/0/ports/0/containerPort
22 | value: 5005
23 | - op: replace
24 | path: /spec/template/spec/volumes/0/hostPath/path
25 | value: /var/ghcr
26 | target:
27 | group: apps
28 | kind: Deployment
29 | name: registry
30 | labels:
31 | - includeSelectors: true
32 | pairs:
33 | upstream: ghcr
34 |
--------------------------------------------------------------------------------
/hack/kind/registry/k8s/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 |
5 | resources:
6 | - ../base
7 |
8 | patches:
9 | - patch: |
10 | - op: replace
11 | path: /metadata/name
12 | value: registry-k8s
13 | - op: replace
14 | path: /spec/template/spec/containers/0/env
15 | value:
16 | - name: REGISTRY_PROXY_REMOTEURL
17 | value: https://registry.k8s.io
18 | - name: REGISTRY_HTTP_ADDR
19 | value: :5006
20 | - op: replace
21 | path: /spec/template/spec/containers/0/ports/0/containerPort
22 | value: 5006
23 | - op: replace
24 | path: /spec/template/spec/volumes/0/hostPath/path
25 | value: /var/local-registry/k8s
26 | target:
27 | group: apps
28 | kind: Deployment
29 | name: registry
30 | labels:
31 | - includeSelectors: true
32 | pairs:
33 | upstream: k8s
34 |
--------------------------------------------------------------------------------
/hack/kind/registry/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 | namespace: registry
5 |
6 | resources:
7 | - namespace.yaml
8 | - docker
9 | - ghcr
10 | - k8s
11 | - europe-docker-pkg-dev
12 | labels:
13 | - includeSelectors: true
14 | pairs:
15 | app: registry
16 |
--------------------------------------------------------------------------------
/hack/kind/registry/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: registry
5 |
--------------------------------------------------------------------------------
/hack/kind/skaffold-after-hock.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | helm template charts/cert-management -n default \
11 | --set createCRDs.issuers=true \
12 | --set createCRDs.certificates=true \
13 | --set image.repository=local-skaffold/cert-controller-manager \
14 | --set image.tag=$SKAFFOLD_IMAGE_TAG \
15 | --set configuration.defaultIssuer=kind-issuer \
16 | --set configuration.caCertificates="$(cat dev/pebble-cert.pem)" \
17 | --set configuration.precheckAdditionalWait=1s \
18 | --set configuration..configuration.issuerDefaultPoolSize=5 \
19 | > dev/manifests.yaml
20 |
21 | helm template charts/cert-management -n default \
22 | --set createCRDs.issuers=true \
23 | --set createCRDs.certificates=true \
24 | --set image.repository=local-skaffold/cert-controller-manager \
25 | --set image.tag=$SKAFFOLD_IMAGE_TAG \
26 | --set configuration.defaultIssuer=kind-issuer \
27 | --set configuration.caCertificates="$(cat dev/pebble-cert.pem)" \
28 | --set configuration.precheckAdditionalWait=1s \
29 | --set configuration..configuration.issuerDefaultPoolSize=5 \
30 | --set configuration.useDnsrecords=true \
31 | > dev/manifests-dnsrecords.yaml
32 |
--------------------------------------------------------------------------------
/hack/kind/skaffold-run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source "$(dirname ${0})/common.sh" ''
11 |
12 | touch "$SOURCE_PATH/dev/manifests.yaml"
13 | touch "$SOURCE_PATH/dev/manifests-dnsrecords.yaml"
14 | skaffold run "$@"
15 |
--------------------------------------------------------------------------------
/hack/kind/test-functional-local.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | set -o errexit
8 | set -o pipefail
9 |
10 | source "$(dirname ${0})/common.sh" ''
11 |
12 | cd "$SOURCE_PATH/test/functional"
13 |
14 | FUNCTEST_CONFIG=functest-config-kind.yaml DNS_KUBECONFIG=$KUBECONFIG DNS_DOMAIN=functest.certman.kind USE_DNSRECORDS=$USE_DNSRECORDS ginkgo --succinct
15 |
--------------------------------------------------------------------------------
/hack/sast.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | set -e
8 |
9 | report_dir="$(git rev-parse --show-toplevel)"
10 |
11 | gosec_report="false"
12 | gosec_report_parse_flags=""
13 | exclude_dirs="hack"
14 |
15 | parse_flags() {
16 | while test $# -gt 1; do
17 | case "$1" in
18 | --gosec-report)
19 | shift; gosec_report="$1"
20 | ;;
21 | --report-dir)
22 | shift; report_dir="$1"
23 | ;;
24 | --exclude-dirs)
25 | shift; exclude_dirs="$1"
26 | ;;
27 | *)
28 | echo "Unknown argument: $1"
29 | exit 1
30 | ;;
31 | esac
32 | shift
33 | done
34 | }
35 |
36 | parse_flags "$@"
37 |
38 | echo "> Running gosec"
39 | gosec --version
40 | if [[ "$gosec_report" != "false" ]]; then
41 | echo "Exporting report to ${report_dir}/gosec-report.sarif"
42 | gosec_report_parse_flags="-track-suppressions -fmt=sarif -out=${report_dir}/gosec-report.sarif -stdout"
43 | fi
44 |
45 | # Gardener uses code-generators https://github.com/kubernetes/code-generator and https://github.com/protocolbuffers/protobuf
46 | # which create lots of G103 (CWE-242: Use of unsafe calls should be audited) & G104 (CWE-703: Errors unhandled) errors.
47 | # However, those generators are best-practice in Kubernetes environment and their results are tested well.
48 | # Thus, generated code is excluded from gosec scan.
49 | # Nested go modules are not supported by gosec (see https://github.com/securego/gosec/issues/501), so the ./hack folder
50 | # is excluded too. It does not contain productive code anyway.
51 | gosec -exclude-generated $(echo "$exclude_dirs" | awk -v RS=',' '{printf "-exclude-dir %s ", $1}') $gosec_report_parse_flags ./...
52 |
--------------------------------------------------------------------------------
/hack/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | // SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
5 | //
6 | // SPDX-License-Identifier: Apache-2.0
7 |
8 | // This package imports things required by build scripts, to force `go mod` to see them as dependencies
9 | package tools
10 |
11 | import (
12 | _ "github.com/ahmetb/gen-crd-api-reference-docs"
13 | _ "github.com/onsi/ginkgo/v2/ginkgo"
14 | _ "github.com/onsi/gomega"
15 | _ "golang.org/x/lint/golint"
16 | _ "k8s.io/code-generator"
17 | _ "k8s.io/kube-openapi/cmd/openapi-gen"
18 | _ "sigs.k8s.io/kind"
19 |
20 | _ "github.com/gardener/controller-manager-library/hack"
21 | )
22 |
--------------------------------------------------------------------------------
/pkg/apis/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management
7 | # TODO(marc1404): controller-manager-library references should be removed
8 | # - selectorRegexp: github[.]com/gardener/controller-manager-library
9 | # forbiddenPrefixes:
10 | # - ''
11 |
--------------------------------------------------------------------------------
/pkg/apis/cert/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | //go:generate sh -c "CONTROLLER_GEN=$CONTROLLER_GEN bash $CONTROLLER_MANAGER_LIB_HACK_DIR/generate-crds"
8 |
9 | package cert
10 |
--------------------------------------------------------------------------------
/pkg/apis/cert/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | // +k8s:deepcopy-gen=package,register
8 |
9 | // Package v1alpha1 is the v1alpha1 version of the API.
10 | // +groupName=cert.gardener.cloud
11 | package v1alpha1
12 |
--------------------------------------------------------------------------------
/pkg/apis/cert/v1alpha1/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package v1alpha1
8 |
9 | import (
10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | "k8s.io/apimachinery/pkg/runtime"
12 | "k8s.io/apimachinery/pkg/runtime/schema"
13 | )
14 |
15 | const (
16 | // Version is the version of the API.
17 | Version = "v1alpha1"
18 | // GroupName is the group name of the API.
19 | GroupName = "cert.gardener.cloud"
20 |
21 | // IssuerKind is the issuer kind.
22 | IssuerKind = "Issuer"
23 |
24 | // CertificateKind is the certificate kind.
25 | CertificateKind = "Certificate"
26 |
27 | // CertificateRevocationKind is the certificate revocation kind.
28 | CertificateRevocationKind = "CertificateRevocation"
29 | )
30 |
31 | // SchemeGroupVersion is group version used to register these objects
32 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: Version}
33 |
34 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind
35 | func Kind(kind string) schema.GroupKind {
36 | return SchemeGroupVersion.WithKind(kind).GroupKind()
37 | }
38 |
39 | // Resource takes an unqualified resources and returns a Group qualified GroupResource
40 | func Resource(resource string) schema.GroupResource {
41 | return SchemeGroupVersion.WithResource(resource).GroupResource()
42 | }
43 |
44 | var (
45 | // SchemeBuilder is a new Scheme Builder which registers our API.
46 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
47 | // AddToScheme is a reference to the Scheme Builder's AddToScheme function.
48 | AddToScheme = SchemeBuilder.AddToScheme
49 | )
50 |
51 | // Adds the list of known types to Scheme.
52 | func addKnownTypes(scheme *runtime.Scheme) error {
53 | scheme.AddKnownTypes(SchemeGroupVersion,
54 | &Issuer{},
55 | &IssuerList{},
56 | &Certificate{},
57 | &CertificateList{},
58 | &CertificateRevocation{},
59 | &CertificateRevocationList{},
60 | )
61 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/apis/cert/v1alpha1/state.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package v1alpha1
8 |
9 | const (
10 | // StatePending is the pending state.
11 | StatePending = "Pending"
12 | // StateWaiting is the waiting state.
13 | StateWaiting = "Waiting"
14 | // StateError is the error state.
15 | StateError = "Error"
16 | // StateReady is the ready state.
17 | StateReady = "Ready"
18 | // StateRevoked is the revoked state.
19 | StateRevoked = "Revoked"
20 | // StateRevocationApplied is the applied state.
21 | StateRevocationApplied = "Applied"
22 | // StateRevocationPartialApplied is the partial applied state (partial success).
23 | StateRevocationPartialApplied = "PartialApplied"
24 | )
25 |
--------------------------------------------------------------------------------
/pkg/cert/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/pkg/cert/client/scheme.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package client
6 |
7 | import (
8 | dnsmanv1alpha1 "github.com/gardener/external-dns-management/pkg/apis/dns/v1alpha1"
9 | gardenerextensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
10 | istionetworkingv1 "istio.io/client-go/pkg/apis/networking/v1"
11 | istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
12 | istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
13 | apiextensionsinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
14 | "k8s.io/apimachinery/pkg/runtime"
15 | "k8s.io/apimachinery/pkg/runtime/serializer"
16 | "k8s.io/apimachinery/pkg/runtime/serializer/json"
17 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
18 | kubernetesscheme "k8s.io/client-go/kubernetes/scheme"
19 | gatewayapisv1 "sigs.k8s.io/gateway-api/apis/v1"
20 | gatewayapisv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
21 | gatewayapisv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
22 |
23 | certv1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
24 | )
25 |
26 | var (
27 | // ClusterScheme is the scheme used in garden runtime and unmanaged seed clusters.
28 | ClusterScheme = runtime.NewScheme()
29 |
30 | // ClusterSerializer is a YAML serializer using the 'ClusterScheme'.
31 | ClusterSerializer = json.NewSerializerWithOptions(json.DefaultMetaFactory, ClusterScheme, ClusterScheme, json.SerializerOptions{Yaml: true, Pretty: false, Strict: false})
32 | // ClusterCodec is a codec factory using the 'ClusterScheme'.
33 | ClusterCodec = serializer.NewCodecFactory(ClusterScheme)
34 | )
35 |
36 | func init() {
37 | clusterSchemeBuilder := runtime.NewSchemeBuilder(
38 | kubernetesscheme.AddToScheme,
39 | certv1alpha1.AddToScheme,
40 | dnsmanv1alpha1.AddToScheme,
41 | istionetworkingv1.AddToScheme,
42 | istionetworkingv1alpha3.AddToScheme,
43 | istionetworkingv1beta1.AddToScheme,
44 | gatewayapisv1.AddToScheme,
45 | gatewayapisv1alpha2.AddToScheme,
46 | gatewayapisv1beta1.AddToScheme,
47 | gardenerextensionsv1alpha1.AddToScheme,
48 | )
49 |
50 | utilruntime.Must(clusterSchemeBuilder.AddToScheme(ClusterScheme))
51 | apiextensionsinstall.Install(ClusterScheme)
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/cert/source/certinfo.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package source
8 |
9 | import (
10 | "strings"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/logger"
13 | "github.com/gardener/controller-manager-library/pkg/resources"
14 | )
15 |
16 | func (r *sourceReconciler) getCertsInfo(logger logger.LogContext, obj resources.Object, s CertSource) (*CertsInfo, CertFeedback, error) {
17 | if !r.classes.IsResponsibleFor(logger, obj) {
18 | return nil, nil, nil
19 | }
20 | info, err := s.GetCertsInfo(logger, obj.Data())
21 | return info, s.CreateCertFeedback(logger, obj), err
22 | }
23 |
24 | // DomainsString returns all domains as comma separated string (common name and DNS names)
25 | func (info CertInfo) DomainsString() string {
26 | return DomainsString(info.Domains)
27 | }
28 |
29 | // DomainsString creates a comma separated string.
30 | func DomainsString(domains []string) string {
31 | if domains == nil {
32 | return ""
33 | }
34 | return strings.Join(domains, ",")
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/cert/source/slaves.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package source
8 |
9 | import (
10 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller"
11 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller/reconcile"
12 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller/reconcile/reconcilers"
13 | "k8s.io/apimachinery/pkg/api/errors"
14 | )
15 |
16 | // SlaveReconcilerType creates a slaveReconciler.
17 | func SlaveReconcilerType(c controller.Interface) (reconcile.Interface, error) {
18 | reconciler := &slaveReconciler{
19 | controller: c,
20 | slaves: c.(*reconcilers.SlaveReconciler),
21 | }
22 | return reconciler, nil
23 | }
24 |
25 | type slaveReconciler struct {
26 | reconcile.DefaultReconciler
27 | controller controller.Interface
28 | slaves *reconcilers.SlaveReconciler
29 | }
30 |
31 | func (r *slaveReconciler) Start() {
32 | r.controller.Infof("determining dangling certificates...")
33 | cluster := r.controller.GetMainCluster()
34 | main := cluster.GetId()
35 | for k := range r.slaves.GetMasters(false) {
36 | if k.Cluster() == main {
37 | if _, err := cluster.GetCachedObject(k); errors.IsNotFound(err) {
38 | r.controller.Infof("trigger vanished origin %s", k.ObjectKey())
39 | _ = r.controller.EnqueueKey(k)
40 | } else {
41 | r.controller.Debugf("found origin %s", k.ObjectKey())
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/cert/source/utils.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package source
8 |
9 | import (
10 | "strings"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/resources"
13 | )
14 |
15 | func requireFinalizer(src resources.Object, cluster resources.Cluster) bool {
16 | return src.GetCluster() != cluster
17 | }
18 |
19 | // ExtractSecretLabels extracts label key value map from annotation.
20 | func ExtractSecretLabels(objData resources.ObjectData) (secretLabels map[string]string) {
21 | if labels, ok := resources.GetAnnotation(objData, AnnotCertSecretLabels); ok {
22 | secretLabels = map[string]string{}
23 | for _, pair := range strings.Split(labels, ",") {
24 | pair = strings.TrimSpace(pair)
25 | items := strings.SplitN(pair, "=", 2)
26 | if len(items) == 2 {
27 | secretLabels[items[0]] = items[1]
28 | }
29 | }
30 | }
31 | return
32 | }
33 |
34 | // CopyDNSRecordsAnnotations extracts DNSRecord related annotations.
35 | func CopyDNSRecordsAnnotations(data resources.ObjectData) (annotations map[string]string) {
36 | for _, annotKey := range []string{AnnotDNSRecordProviderType, AnnotDNSRecordSecretRef, AnnotDNSRecordClass} {
37 | if value := data.GetAnnotations()[annotKey]; value != "" {
38 | if annotations == nil {
39 | annotations = map[string]string{}
40 | }
41 | annotations[annotKey] = value
42 | }
43 | }
44 | return
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/cert/utils/domainrange.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package utils
8 |
9 | import "strings"
10 |
11 | // NormalizeDomainRange normalizes domain to lower case, drops wildcard and suffix dot.
12 | func NormalizeDomainRange(domainRange string) string {
13 | normalized := strings.ToLower(domainRange)
14 | if strings.HasPrefix(normalized, "*.") {
15 | normalized = normalized[1:]
16 | }
17 | normalized = strings.TrimSuffix(normalized, ".")
18 | return normalized
19 | }
20 |
21 | // IsInDomainRanges returns true if domain is in domain ranges.
22 | func IsInDomainRanges(domain string, domainRanges []string) bool {
23 | if domainRanges == nil {
24 | return true
25 | }
26 | for _, domainRange := range domainRanges {
27 | if IsInDomainRange(domain, domainRange) {
28 | return true
29 | }
30 | }
31 | return false
32 | }
33 |
34 | // BestDomainRange returns best fitting domain range value or "".
35 | func BestDomainRange(domain string, domainRanges []string) string {
36 | if domainRanges == nil {
37 | return "*"
38 | }
39 | best := ""
40 | for _, domainRange := range domainRanges {
41 | if IsInDomainRange(domain, domainRange) {
42 | if len(best) < len(domainRange) {
43 | best = domainRange
44 | }
45 | }
46 | }
47 | return best
48 | }
49 |
50 | // IsInDomainRange returns true if domain is in domain range.
51 | func IsInDomainRange(domain, domainRange string) bool {
52 | if domainRange == "" {
53 | return true
54 | }
55 | domain = strings.ToLower(domain)
56 | domain = strings.TrimSuffix(domain, ".")
57 | if !strings.HasSuffix(domain, domainRange) {
58 | return false
59 | }
60 | if len(domain) == len(domainRange) {
61 | return true
62 | }
63 |
64 | return domainRange[0] == '.' || domain[len(domain)-len(domainRange)-1] == '.'
65 | }
66 |
--------------------------------------------------------------------------------
/pkg/cert/utils/domainrange_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package utils_test
8 |
9 | import (
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 |
13 | "github.com/gardener/cert-management/pkg/cert/utils"
14 | )
15 |
16 | var _ = Describe("DomainRange", func() {
17 | DescribeTable("IsInDomainRange",
18 | func(domain, domainRange string, wanted bool) {
19 | domainRange = utils.NormalizeDomainRange(domainRange)
20 | result := utils.IsInDomainRange(domain, domainRange)
21 | Expect(result).To(Equal(wanted))
22 | },
23 | Entry("a.b in b", "a.b", "b", true),
24 | Entry("A.B in b", "A.B", "b", true),
25 | Entry("a.b in .b", "a.b", ".b", true),
26 | Entry("a.b in *.B", "a.b", "*.B", true),
27 | Entry("a.b in a.b", "a.b", "a.b", true),
28 | Entry("a.b not in c.b", "a.b", "c.b", false),
29 | Entry("a.b not in a.b.c", "a.b", "a.b.c", false),
30 | Entry("a.b.c in b.c", "a.b.c", "b.c", true),
31 | Entry("a.xb.c not in b.c", "a.xb.c", "b.c", false),
32 | Entry("a.b in b.", "a.b", "b.", true),
33 | Entry("a.b. in b", "a.b.", "b", true),
34 | Entry("Empty domain range acts as wildcard", "a.b.c", "", true),
35 | )
36 |
37 | DescribeTable("IsInDomainRanges",
38 | func(domain string, domainRanges []string, wanted bool) {
39 | for i, domainRange := range domainRanges {
40 | domainRanges[i] = utils.NormalizeDomainRange(domainRange)
41 | }
42 | result := utils.IsInDomainRanges(domain, domainRanges)
43 | Expect(result).To(Equal(wanted))
44 | },
45 | Entry("a.b in {b}", "a.b", []string{"b"}, true),
46 | Entry("a.b in {b, c}", "a.b", []string{"b", "c"}, true),
47 | Entry("a.b in {c, b}", "a.b", []string{"c", "b"}, true),
48 | Entry("a.b not in {c, d}", "a.b", []string{"c", "d"}, false),
49 | Entry("Nil acts as wildcard", "a.b", nil, true),
50 | )
51 |
52 | DescribeTable("BestDomainRange",
53 | func(domain string, domainRanges []string, wanted string) {
54 | for i, domainRange := range domainRanges {
55 | domainRanges[i] = utils.NormalizeDomainRange(domainRange)
56 | }
57 | result := utils.BestDomainRange(domain, domainRanges)
58 | Expect(result).To(Equal(wanted))
59 | },
60 | Entry("a.b in {b} returns b", "a.b", []string{"b"}, "b"),
61 | Entry("a.b in {b, c} returns b", "a.b", []string{"b", "c"}, "b"),
62 | Entry("a.b.c in {b.c., c} returns b.c", "a.b.c", []string{"b.c", "c"}, "b.c"),
63 | Entry("Nil acts as wildcard", "a.b", nil, "*"),
64 | )
65 |
66 | })
67 |
--------------------------------------------------------------------------------
/pkg/cert/utils/mock/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | //go:generate mockgen -package=mock -destination=mocks.go github.com/gardener/controller-manager-library/pkg/resources Object
6 |
7 | package mock
8 |
--------------------------------------------------------------------------------
/pkg/cert/utils/utils_issuer.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package utils
8 |
9 | import (
10 | "fmt"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/logger"
13 | "github.com/gardener/controller-manager-library/pkg/resources"
14 | "sigs.k8s.io/controller-runtime/pkg/client"
15 |
16 | api "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
17 | "github.com/gardener/cert-management/pkg/shared/legobridge"
18 | )
19 |
20 | var issuerType = (*api.Issuer)(nil)
21 |
22 | // IssuerObject encapsulates the issuer resource object.
23 | type IssuerObject struct {
24 | resources.Object
25 | }
26 |
27 | // Issuer returns the issuer.
28 | func (o *IssuerObject) Issuer() *api.Issuer {
29 | return o.Data().(*api.Issuer)
30 | }
31 |
32 | // Issuer returns the issuer object.
33 | func Issuer(o resources.Object) *IssuerObject {
34 | if o.IsA(issuerType) {
35 | return &IssuerObject{o}
36 | }
37 | return nil
38 | }
39 |
40 | // Spec returns the issuer resource object spec.
41 | func (o *IssuerObject) Spec() *api.IssuerSpec {
42 | return &o.Issuer().Spec
43 | }
44 |
45 | // Status returns the issuer resource object status.
46 | func (o *IssuerObject) Status() *api.IssuerStatus {
47 | return &o.Issuer().Status
48 | }
49 |
50 | // LoggerFactory is the logger factory for DNS challenges.
51 | func LoggerFactory(key client.ObjectKey, serial uint32) legobridge.LoggerInfof {
52 | return logger.NewContext("DNSChallengeProvider", fmt.Sprintf("dns-challenge-provider: %s-%d", key, serial))
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/cert/utils/utils_mod.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package utils
8 |
9 | import (
10 | "github.com/gardener/controller-manager-library/pkg/resources/abstract"
11 | )
12 |
13 | // AssureStringSlice handles modification of a string slice.
14 | func AssureStringSlice(mod *abstract.ModificationState, dst *[]string, value []string) {
15 | if mod == nil || dst == nil {
16 | return
17 | }
18 | if value == nil {
19 | value = []string{}
20 | }
21 | if !EqualStringSlice(*dst, value) {
22 | *dst = value
23 | mod.Modify(true)
24 | }
25 | }
26 |
27 | // EqualStringSlice compares string slices.
28 | func EqualStringSlice(a, b []string) bool {
29 | if len(a) != len(b) {
30 | return false
31 | }
32 | for i, v := range a {
33 | if v != b[i] {
34 | return false
35 | }
36 | }
37 | return true
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/cert/utils/utils_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package utils_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestUtils(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Utils Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - github.com/gardener/cert-management/pkg/apis
5 | - github.com/gardener/cert-management/pkg/certman2
6 | - github.com/gardener/cert-management/pkg/shared
7 | - selectorRegexp: github[.]com/gardener/controller-manager-library
8 | forbiddenPrefixes:
9 | - ''
10 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/cert/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | //go:generate sh -c "CONTROLLER_GEN=$CONTROLLER_GEN bash $GARDENER_HACK_DIR/generate-crds.sh -p 'crd-' cert.gardener.cloud"
8 |
9 | package cert
10 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // +k8s:deepcopy-gen=package
6 | // +groupName=config.cert.gardener.cloud
7 |
8 | package config // import "github.com/gardener/cert-management/pkg/certman2/apis/config"
9 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/register.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package config
6 |
7 | import (
8 | "k8s.io/apimachinery/pkg/runtime"
9 | "k8s.io/apimachinery/pkg/runtime/schema"
10 | )
11 |
12 | // GroupName is the group name used in this package.
13 | const GroupName = "config.cert.gardener.cloud"
14 |
15 | // SchemeGroupVersion is group version used to register these objects.
16 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
17 |
18 | // Kind takes an unqualified kind and returns a Group qualified GroupKind.
19 | func Kind(kind string) schema.GroupKind {
20 | return SchemeGroupVersion.WithKind(kind).GroupKind()
21 | }
22 |
23 | // Resource takes an unqualified resource and returns a Group qualified GroupResource.
24 | func Resource(resource string) schema.GroupResource {
25 | return SchemeGroupVersion.WithResource(resource).GroupResource()
26 | }
27 |
28 | var (
29 | // SchemeBuilder used to register the Shoot resource.
30 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
31 | // AddToScheme is a pointer to SchemeBuilder.AddToScheme.
32 | AddToScheme = SchemeBuilder.AddToScheme
33 | )
34 |
35 | // Adds the list of known types to api.Scheme.
36 | func addKnownTypes(scheme *runtime.Scheme) error {
37 | scheme.AddKnownTypes(SchemeGroupVersion,
38 | &CertManagerConfiguration{},
39 | )
40 | return nil
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // +k8s:deepcopy-gen=package
6 | // +k8s:conversion-gen=github.com/gardener/cert-management/pkg/certman2/apis/config
7 | // +k8s:openapi-gen=true
8 | // +k8s:defaulter-gen=TypeMeta
9 |
10 | package v1alpha1 // import "github.com/gardener/cert-management/pkg/certman2/apis/config/v1alpha1"
11 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/v1alpha1/register.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package v1alpha1
6 |
7 | import (
8 | "k8s.io/apimachinery/pkg/runtime"
9 | "k8s.io/apimachinery/pkg/runtime/schema"
10 | )
11 |
12 | // GroupName is the group name used in this package.
13 | const GroupName = "config.cert.gardener.cloud"
14 |
15 | // SchemeGroupVersion is group version used to register these objects.
16 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
17 |
18 | // Resource takes an unqualified resource and returns a Group qualified GroupResource.
19 | func Resource(resource string) schema.GroupResource {
20 | return SchemeGroupVersion.WithResource(resource).GroupResource()
21 | }
22 |
23 | var (
24 | // SchemeBuilder used to register the Shoot resource.
25 | SchemeBuilder runtime.SchemeBuilder
26 | localSchemeBuilder = &SchemeBuilder
27 | // AddToScheme is a pointer to SchemeBuilder.AddToScheme.
28 | AddToScheme = localSchemeBuilder.AddToScheme
29 | )
30 |
31 | func init() {
32 | // We only register manually written functions here. The registration of the
33 | // generated functions takes place in the generated files. The separation
34 | // makes the code compile even when the generated files are missing.
35 | localSchemeBuilder.Register(addDefaultingFuncs, addKnownTypes)
36 | }
37 |
38 | // Adds the list of known types to api.Scheme.
39 | func addKnownTypes(scheme *runtime.Scheme) error {
40 | scheme.AddKnownTypes(SchemeGroupVersion,
41 | &CertManagerConfiguration{},
42 | )
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/v1alpha1/v1alpha1_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package v1alpha1_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestV1alpha1(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "CertManagement APIs Config V1alpha1 Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/apis/config/v1alpha1/zz_generated.defaults.go:
--------------------------------------------------------------------------------
1 | //go:build !ignore_autogenerated
2 | // +build !ignore_autogenerated
3 |
4 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
5 | //
6 | // SPDX-License-Identifier: Apache-2.0
7 |
8 | // Code generated by defaulter-gen. DO NOT EDIT.
9 |
10 | package v1alpha1
11 |
12 | import (
13 | runtime "k8s.io/apimachinery/pkg/runtime"
14 | )
15 |
16 | // RegisterDefaults adds defaulters functions to the given scheme.
17 | // Public to allow building arbitrary schemes.
18 | // All generated defaulters are covering - they call all nested defaulters.
19 | func RegisterDefaults(scheme *runtime.Scheme) error {
20 | scheme.AddTypeDefaultingFunc(&CertManagerConfiguration{}, func(obj interface{}) { SetObjectDefaults_CertManagerConfiguration(obj.(*CertManagerConfiguration)) })
21 | return nil
22 | }
23 |
24 | func SetObjectDefaults_CertManagerConfiguration(in *CertManagerConfiguration) {
25 | SetDefaults_CertManagerConfiguration(in)
26 | if in.ClientConnection != nil {
27 | SetDefaults_ClientConnection(in.ClientConnection)
28 | }
29 | if in.ControlPlaneClientConnection != nil {
30 | SetDefaults_ControlPlaneClientConnection(in.ControlPlaneClientConnection)
31 | }
32 | if in.DNSClientConnection != nil {
33 | SetDefaults_DNSClientConnection(in.DNSClientConnection)
34 | }
35 | SetDefaults_LeaderElectionConfiguration(&in.LeaderElection)
36 | SetDefaults_ServerConfiguration(&in.Server)
37 | SetDefaults_IssuerControllerConfig(&in.Controllers.Issuer)
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/certman2/client/clusteraccess.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package client
6 |
7 | import (
8 | "github.com/gardener/gardener/pkg/client/kubernetes"
9 | "github.com/go-logr/logr"
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 | )
12 |
13 | // ClusterAccess contains clients for various connected Kubernetes clusters.
14 | type ClusterAccess struct {
15 | mainClient client.Client
16 | issuerClient client.Client
17 | dnsClient client.Client
18 | }
19 |
20 | // NewClusterAccess returns a new instance of ClusterAccess for all clusters.
21 | func NewClusterAccess(log logr.Logger, main, issuer, dns kubernetes.Interface) *ClusterAccess {
22 | if issuer == nil {
23 | issuer = main
24 | log.Info("using main cluster for provided issuers")
25 | if dns == nil {
26 | dns = main
27 | log.Info("using main cluster for DNS resources")
28 | }
29 | } else if dns == nil {
30 | dns = issuer
31 | log.Info("using issuer cluster for DNS resources")
32 | }
33 |
34 | return &ClusterAccess{
35 | mainClient: main.Client(),
36 | issuerClient: issuer.Client(),
37 | dnsClient: dns.Client(),
38 | }
39 | }
40 |
41 | // MainClient returns client for the main cluster containing certificate and source resources.
42 | func (a *ClusterAccess) MainClient() client.Client {
43 | return a.mainClient
44 | }
45 |
46 | // IssuerClient returns client for the cluster containing provided issuers.
47 | func (a *ClusterAccess) IssuerClient() client.Client {
48 | return a.issuerClient
49 | }
50 |
51 | // DNSClient returns client for the cluster used for DNSEntries or DNSRecords.
52 | func (a *ClusterAccess) DNSClient() client.Client {
53 | return a.dnsClient
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/certman2/client/scheme.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package client
6 |
7 | import (
8 | dnsmanv1alpha1 "github.com/gardener/external-dns-management/pkg/apis/dns/v1alpha1"
9 | gardenerextensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
10 | istionetworkingv1 "istio.io/client-go/pkg/apis/networking/v1"
11 | istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
12 | istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
13 | apiextensionsinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
14 | "k8s.io/apimachinery/pkg/runtime"
15 | "k8s.io/apimachinery/pkg/runtime/serializer"
16 | "k8s.io/apimachinery/pkg/runtime/serializer/json"
17 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
18 | kubernetesscheme "k8s.io/client-go/kubernetes/scheme"
19 | gatewayapisv1 "sigs.k8s.io/gateway-api/apis/v1"
20 | gatewayapisv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
21 | gatewayapisv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
22 |
23 | certmanv1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
24 | )
25 |
26 | var (
27 | // ClusterScheme is the scheme used in garden runtime and unmanaged seed clusters.
28 | ClusterScheme = runtime.NewScheme()
29 |
30 | // ClusterSerializer is a YAML serializer using the 'ClusterScheme'.
31 | ClusterSerializer = json.NewSerializerWithOptions(json.DefaultMetaFactory, ClusterScheme, ClusterScheme, json.SerializerOptions{Yaml: true, Pretty: false, Strict: false})
32 | // ClusterCodec is a codec factory using the 'ClusterScheme'.
33 | ClusterCodec = serializer.NewCodecFactory(ClusterScheme)
34 | )
35 |
36 | func init() {
37 | clusterSchemeBuilder := runtime.NewSchemeBuilder(
38 | kubernetesscheme.AddToScheme,
39 | dnsmanv1alpha1.AddToScheme,
40 | certmanv1alpha1.AddToScheme,
41 | istionetworkingv1.AddToScheme,
42 | istionetworkingv1alpha3.AddToScheme,
43 | istionetworkingv1beta1.AddToScheme,
44 | gatewayapisv1.AddToScheme,
45 | gatewayapisv1alpha2.AddToScheme,
46 | gatewayapisv1beta1.AddToScheme,
47 | gardenerextensionsv1alpha1.AddToScheme,
48 | )
49 |
50 | utilruntime.Must(clusterSchemeBuilder.AddToScheme(ClusterScheme))
51 | apiextensionsinstall.Install(ClusterScheme)
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/certificate/add.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate
6 |
7 | import (
8 | "k8s.io/utils/clock"
9 | "sigs.k8s.io/controller-runtime/pkg/builder"
10 | "sigs.k8s.io/controller-runtime/pkg/controller"
11 | "sigs.k8s.io/controller-runtime/pkg/manager"
12 |
13 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
14 | certcontroller "github.com/gardener/cert-management/pkg/certman2/controller"
15 | )
16 |
17 | // ControllerName is the name of this controller.
18 | const ControllerName = "certificate"
19 |
20 | // AddToManager adds Reconciler to the given manager.
21 | func (r *Reconciler) AddToManager(mgr manager.Manager) error {
22 | r.Client = mgr.GetClient()
23 | if r.Clock == nil {
24 | r.Clock = clock.RealClock{}
25 | }
26 | if r.Recorder == nil {
27 | r.Recorder = mgr.GetEventRecorderFor(ControllerName + "-controller")
28 | }
29 |
30 | return builder.
31 | ControllerManagedBy(mgr).
32 | Named(ControllerName).
33 | For(
34 | &v1alpha1.Certificate{},
35 | builder.WithPredicates(
36 | certcontroller.CertClassPredicate(r.Config.Class),
37 | ),
38 | ).
39 | WithOptions(controller.Options{
40 | MaxConcurrentReconciles: 1,
41 | }).
42 | Complete(r)
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/certificate/certificate_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Certificate Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/certificate/reconciler.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | apierrors "k8s.io/apimachinery/pkg/api/errors"
12 | "k8s.io/client-go/tools/record"
13 | "k8s.io/utils/clock"
14 | "sigs.k8s.io/controller-runtime/pkg/client"
15 | logf "sigs.k8s.io/controller-runtime/pkg/log"
16 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
17 |
18 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
19 | "github.com/gardener/cert-management/pkg/certman2/apis/config"
20 | )
21 |
22 | // Reconciler is a reconciler for provided Certificate resources.
23 | type Reconciler struct {
24 | Client client.Client
25 | Clock clock.Clock
26 | Recorder record.EventRecorder
27 | Config config.CertManagerConfiguration
28 | }
29 |
30 | // Reconcile reconciles Certificate resources.
31 | func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
32 | log := logf.FromContext(ctx).WithName(ControllerName)
33 |
34 | cert := &v1alpha1.Certificate{}
35 | if err := r.Client.Get(ctx, req.NamespacedName, cert); err != nil {
36 | if apierrors.IsNotFound(err) {
37 | log.V(1).Info("Object is gone, stop reconciling")
38 | return reconcile.Result{}, nil
39 | }
40 | return reconcile.Result{}, fmt.Errorf("error retrieving object from store: %w", err)
41 | }
42 |
43 | if cert.DeletionTimestamp != nil {
44 | return r.delete(ctx, log, cert)
45 | } else {
46 | return r.reconcile(ctx, log, cert)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/certificate/reconciler_delete.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | "github.com/go-logr/logr"
12 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
13 |
14 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
15 | )
16 |
17 | func (r *Reconciler) delete(
18 | _ context.Context,
19 | log logr.Logger,
20 | _ *v1alpha1.Certificate,
21 | ) (
22 | reconcile.Result,
23 | error,
24 | ) {
25 | log.Info("deleting certificate")
26 | return reconcile.Result{}, fmt.Errorf("not yet supported")
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/certificate/reconciler_reconcile.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | "github.com/go-logr/logr"
12 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
13 |
14 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
15 | )
16 |
17 | func (r *Reconciler) reconcile(
18 | ctx context.Context,
19 | log logr.Logger,
20 | landscape *v1alpha1.Certificate,
21 | ) (
22 | reconcile.Result,
23 | error,
24 | ) {
25 | log.Info("reconcile certificate")
26 | _ = ctx
27 | _ = landscape
28 | return reconcile.Result{}, fmt.Errorf("not yet supported")
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/issuer/controlplane/acme/issuer_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package acme
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "ACME Issuer Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/issuer/controlplane/ca/issuer_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package ca
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "CA Issuer Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/issuer/controlplane/issuer_suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package controlplane_test
8 |
9 | import (
10 | "testing"
11 |
12 | . "github.com/onsi/ginkgo/v2"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | func TestLandscape(t *testing.T) {
17 | RegisterFailHandler(Fail)
18 | RunSpecs(t, "Issuer-Control-Plane Controller Suite")
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/predicate.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package controller
8 |
9 | import (
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 | "sigs.k8s.io/controller-runtime/pkg/event"
12 | "sigs.k8s.io/controller-runtime/pkg/predicate"
13 |
14 | configv1alpha1 "github.com/gardener/cert-management/pkg/certman2/apis/config/v1alpha1"
15 | "github.com/gardener/cert-management/pkg/certman2/core"
16 | )
17 |
18 | // CertClassPredicate returns a predicate that filters objects by their class.
19 | func CertClassPredicate(expectedClass string) predicate.Predicate {
20 | return FilterPredicate(func(obj client.Object) bool {
21 | class := obj.GetAnnotations()[core.AnnotationClass]
22 | if class == "" {
23 | class = configv1alpha1.DefaultClass
24 | }
25 | return class == expectedClass
26 | })
27 | }
28 |
29 | // FilterPredicate returns a predicate that filters old or new objects.
30 | func FilterPredicate(filter func(obj client.Object) bool) predicate.Predicate {
31 | return predicate.Funcs{
32 | CreateFunc: func(e event.CreateEvent) bool {
33 | return filter(e.Object)
34 | },
35 | UpdateFunc: func(e event.UpdateEvent) bool {
36 | return filter(e.ObjectOld) || filter(e.ObjectNew)
37 | },
38 | DeleteFunc: func(e event.DeleteEvent) bool {
39 | return filter(e.Object)
40 | },
41 | GenericFunc: func(e event.GenericEvent) bool {
42 | return filter(e.Object)
43 | },
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/common/certinput_collector.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package common
8 |
9 | import (
10 | "context"
11 | "fmt"
12 |
13 | "github.com/go-logr/logr"
14 | "sigs.k8s.io/controller-runtime/pkg/client"
15 |
16 | "github.com/gardener/cert-management/pkg/certman2/core"
17 | )
18 |
19 | // TLSDataCollector collects TLS secret names for hosts.
20 | type TLSDataCollector func(ctx context.Context, obj client.Object) ([]*TLSData, error)
21 |
22 | // TLSData contains the collection results: secret name and host list.
23 | type TLSData struct {
24 | SecretNamespace string
25 | SecretName string
26 | Hosts []string
27 | }
28 |
29 | // GetCertInputByCollector collects data from annotations and from the resources needed for creating certificates.
30 | func GetCertInputByCollector(ctx context.Context, log logr.Logger, obj client.Object, tlsDataCollector TLSDataCollector) (CertInputMap, error) {
31 | inputMap := CertInputMap{}
32 |
33 | if obj.GetAnnotations()[AnnotationPurposeKey] != AnnotationPurposeValueManaged {
34 | return nil, nil
35 | }
36 |
37 | tlsDataArray, err := tlsDataCollector(ctx, obj)
38 | if err != nil {
39 | return inputMap, err
40 | }
41 | if tlsDataArray == nil {
42 | log.V(5).Info("No TLS data")
43 | return inputMap, nil
44 | }
45 |
46 | annotatedDomains, cn := getDomainsFromAnnotations(obj.GetAnnotations(), false)
47 | for _, tls := range tlsDataArray {
48 | if tls.SecretName == "" {
49 | err = fmt.Errorf("tls entry for hosts %s has no secretName", core.DomainsString(tls.Hosts))
50 | continue
51 | }
52 | var domains []string
53 | if annotatedDomains != nil {
54 | domains = annotatedDomains
55 | } else {
56 | domains = mergeCommonName(cn, tls.Hosts)
57 | }
58 | key := client.ObjectKey{Namespace: tls.SecretNamespace, Name: tls.SecretName}
59 | inputMap[key] = augmentFromCommonAnnotations(obj.GetAnnotations(), CertInput{
60 | SecretObjectKey: key,
61 | Domains: domains,
62 | })
63 | }
64 | return inputMap, err
65 | }
66 |
67 | func mergeCommonName(cn string, hosts []string) []string {
68 | if cn == "" {
69 | return hosts
70 | }
71 | result := []string{cn}
72 | for _, host := range hosts {
73 | if host != cn {
74 | result = append(result, host)
75 | }
76 | }
77 | return result
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/gateways_crd_watchdog/add_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package gateways_crd_watchdog_test
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 | "github.com/onsi/gomega/types"
11 | apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
12 | "sigs.k8s.io/controller-runtime/pkg/event"
13 | "sigs.k8s.io/controller-runtime/pkg/predicate"
14 |
15 | . "github.com/gardener/cert-management/pkg/certman2/controller/source/gateways_crd_watchdog"
16 | )
17 |
18 | var _ = Describe("Add", func() {
19 | Describe("#Predicate", func() {
20 | var (
21 | crdPredicate predicate.Predicate
22 | crd *apiextensionsv1.CustomResourceDefinition
23 |
24 | test func(*apiextensionsv1.CustomResourceDefinition, types.GomegaMatcher)
25 | )
26 |
27 | BeforeEach(func() {
28 | crdPredicate = Predicate()
29 |
30 | crd = &apiextensionsv1.CustomResourceDefinition{}
31 |
32 | test = func(
33 | crd *apiextensionsv1.CustomResourceDefinition,
34 | match types.GomegaMatcher,
35 | ) {
36 | Expect(crdPredicate.Create(event.CreateEvent{Object: crd})).To(match)
37 | Expect(crdPredicate.Update(event.UpdateEvent{ObjectOld: crd, ObjectNew: crd})).To(match)
38 | Expect(crdPredicate.Delete(event.DeleteEvent{Object: crd})).To(match)
39 | Expect(crdPredicate.Generic(event.GenericEvent{Object: crd})).To(BeFalse())
40 | }
41 | })
42 |
43 | It("should handle nil objects as expected", func() {
44 | test(nil, BeFalse())
45 | })
46 |
47 | It("should handle unmanaged objects as expected", func() {
48 | crd.Name = "foo"
49 | test(crd, BeFalse())
50 | })
51 |
52 | It("should handle relevant crd", func() {
53 | for _, name := range []string{
54 | "gateways.networking.istio.io",
55 | "virtualservices.networking.istio.io",
56 | "gateways.gateway.networking.k8s.io",
57 | "httproutes.gateway.networking.k8s.io",
58 | } {
59 | crd.Name = name
60 | test(crd, BeTrue())
61 | }
62 | })
63 | })
64 | })
65 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/gateways_crd_watchdog/crd_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package gateways_crd_watchdog_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "CustomResourceDefintion Watchdog Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/ingress/ingress_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package ingress_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Ingress Source Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/ingress/reconciler.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package ingress
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | networkingv1 "k8s.io/api/networking/v1"
12 | apierrors "k8s.io/apimachinery/pkg/api/errors"
13 | "k8s.io/apimachinery/pkg/runtime/schema"
14 | logf "sigs.k8s.io/controller-runtime/pkg/log"
15 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
16 |
17 | "github.com/gardener/cert-management/pkg/certman2/controller/source/common"
18 | )
19 |
20 | // Reconciler is a reconciler for provided Certificate resources.
21 | type Reconciler struct {
22 | common.ReconcilerBase
23 | }
24 |
25 | // Complete implements the option completer.
26 | func (r *Reconciler) Complete() {
27 | r.GVK = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"}
28 | }
29 |
30 | // Reconcile reconciles Service resources.
31 | func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
32 | log := logf.FromContext(ctx).WithName(ControllerName)
33 |
34 | ingress := &networkingv1.Ingress{}
35 | if err := r.Client.Get(ctx, req.NamespacedName, ingress); err != nil {
36 | if apierrors.IsNotFound(err) {
37 | log.V(1).Info("Object is gone, stop reconciling")
38 | return reconcile.Result{}, nil
39 | }
40 | return reconcile.Result{}, fmt.Errorf("error retrieving object from store: %w", err)
41 | }
42 |
43 | if ingress.Annotations[common.AnnotationPurposeKey] != common.AnnotationPurposeValueManaged {
44 | return r.DoDelete(ctx, log, ingress)
45 | } else {
46 | return r.reconcile(ctx, log, ingress)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/ingress/reconciler_reconcile.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package ingress
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | "github.com/go-logr/logr"
12 | corev1 "k8s.io/api/core/v1"
13 | networkingv1 "k8s.io/api/networking/v1"
14 | "sigs.k8s.io/controller-runtime/pkg/client"
15 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
16 |
17 | "github.com/gardener/cert-management/pkg/certman2/controller/source/common"
18 | )
19 |
20 | func (r *Reconciler) reconcile(
21 | ctx context.Context,
22 | log logr.Logger,
23 | ingress *networkingv1.Ingress,
24 | ) (
25 | reconcile.Result,
26 | error,
27 | ) {
28 | log.Info("reconcile")
29 |
30 | var certInputMap common.CertInputMap
31 | if isRelevant(ingress, r.Class) {
32 | var err error
33 | certInputMap, err = r.getCertificateInputMap(ctx, log, ingress)
34 | if err != nil {
35 | r.Recorder.Eventf(ingress, corev1.EventTypeWarning, "Invalid", "%s", err)
36 | return reconcile.Result{}, err
37 | }
38 | }
39 |
40 | return r.DoReconcile(ctx, log, ingress, certInputMap)
41 | }
42 |
43 | func (r *Reconciler) getCertificateInputMap(ctx context.Context, log logr.Logger, ingress *networkingv1.Ingress) (common.CertInputMap, error) {
44 | return common.GetCertInputByCollector(ctx, log, ingress, func(_ context.Context, obj client.Object) ([]*common.TLSData, error) {
45 | data, ok := obj.(*networkingv1.Ingress)
46 | if !ok {
47 | return nil, fmt.Errorf("unexpected ingress type: %t", obj)
48 | }
49 | if data.Spec.TLS == nil {
50 | return nil, nil
51 | }
52 | var array []*common.TLSData
53 | for _, item := range data.Spec.TLS {
54 | array = append(array, &common.TLSData{
55 | SecretNamespace: obj.GetNamespace(),
56 | SecretName: item.SecretName,
57 | Hosts: item.Hosts,
58 | })
59 | }
60 | return array, nil
61 | })
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/istio_gateway/istio_gateway_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package istio_gateway
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Istio Gateway Source Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/k8s_gateway/k8s_gateway_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package k8s_gateway
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Kubernetes Gateway Source Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/k8s_gateway/versions.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package k8s_gateway
8 |
9 | import (
10 | "strings"
11 |
12 | apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
13 | "k8s.io/apimachinery/pkg/util/sets"
14 | "sigs.k8s.io/controller-runtime/pkg/client"
15 | gatewayapisv1 "sigs.k8s.io/gateway-api/apis/v1"
16 | gatewayapisv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
17 | )
18 |
19 | // Version is the version of the istio gateway.
20 | type Version string
21 |
22 | const (
23 | // VersionV1 is the v1 version of the Kubernetes Gateway API gateway.
24 | VersionV1 Version = "v1"
25 | // VersionV1beta1 is the v1beta1 version of the Kubernetes Gateway API gateway.
26 | VersionV1beta1 Version = "v1beta1"
27 | // VersionNone is zero version of the Kubernetes Gateway API gateway.
28 | VersionNone Version = ""
29 | )
30 |
31 | // GetPreferredVersion retrieves the preferred version from the custom resource definition.
32 | func GetPreferredVersion(crd *apiextensionsv1.CustomResourceDefinition) Version {
33 | if !strings.HasSuffix(crd.GetName(), "gateway.networking.k8s.io") {
34 | return VersionNone
35 | }
36 |
37 | versions := sets.Set[string]{}
38 | for _, v := range crd.Spec.Versions {
39 | if !v.Served {
40 | continue
41 | }
42 | versions.Insert(v.Name)
43 | }
44 | for _, vv := range []Version{VersionV1, VersionV1beta1} {
45 | if versions.Has(string(vv)) {
46 | return vv
47 | }
48 | }
49 | return VersionNone
50 | }
51 |
52 | func newGateway(version Version) client.Object {
53 | switch version {
54 | case VersionV1:
55 | return &gatewayapisv1.Gateway{}
56 | case VersionV1beta1:
57 | return &gatewayapisv1beta1.Gateway{}
58 | default:
59 | return nil
60 | }
61 | }
62 |
63 | func newHTTPRoute(version Version) client.Object {
64 | switch version {
65 | case VersionV1:
66 | return &gatewayapisv1.HTTPRoute{}
67 | case VersionV1beta1:
68 | return &gatewayapisv1beta1.HTTPRoute{}
69 | default:
70 | return nil
71 | }
72 | }
73 |
74 | func newHTTPRouteList(version Version) client.ObjectList {
75 | switch version {
76 | case VersionV1:
77 | return &gatewayapisv1.HTTPRouteList{}
78 | case VersionV1beta1:
79 | return &gatewayapisv1beta1.HTTPRouteList{}
80 | default:
81 | return nil
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/service/reconciler.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package service
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | corev1 "k8s.io/api/core/v1"
12 | apierrors "k8s.io/apimachinery/pkg/api/errors"
13 | "k8s.io/apimachinery/pkg/runtime/schema"
14 | logf "sigs.k8s.io/controller-runtime/pkg/log"
15 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
16 |
17 | "github.com/gardener/cert-management/pkg/certman2/controller/source/common"
18 | )
19 |
20 | // Reconciler is a reconciler for provided Certificate resources.
21 | type Reconciler struct {
22 | common.ReconcilerBase
23 | }
24 |
25 | // Complete implements the option completer.
26 | func (r *Reconciler) Complete() {
27 | r.GVK = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}
28 | }
29 |
30 | // Reconcile reconciles Service resources.
31 | func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
32 | log := logf.FromContext(ctx).WithName(ControllerName)
33 |
34 | service := &corev1.Service{}
35 | if err := r.Client.Get(ctx, req.NamespacedName, service); err != nil {
36 | if apierrors.IsNotFound(err) {
37 | log.V(1).Info("Object is gone, stop reconciling")
38 | return reconcile.Result{}, nil
39 | }
40 | return reconcile.Result{}, fmt.Errorf("error retrieving object from store: %w", err)
41 | }
42 |
43 | if service.Spec.Type != corev1.ServiceTypeLoadBalancer {
44 | return r.DoDelete(ctx, log, service)
45 | } else {
46 | return r.reconcile(ctx, log, service)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/service/reconciler_reconcile.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package service
6 |
7 | import (
8 | "context"
9 | "fmt"
10 |
11 | "github.com/go-logr/logr"
12 | corev1 "k8s.io/api/core/v1"
13 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
14 |
15 | "github.com/gardener/cert-management/pkg/certman2/controller/source/common"
16 | )
17 |
18 | func (r *Reconciler) reconcile(
19 | ctx context.Context,
20 | log logr.Logger,
21 | service *corev1.Service,
22 | ) (
23 | reconcile.Result,
24 | error,
25 | ) {
26 | log.Info("reconcile")
27 |
28 | var certInputMap common.CertInputMap
29 | if isRelevant(service, r.Class) {
30 | // build certificate from service annotations
31 | var err error
32 | certInputMap, err = r.getCertificateInputMap(log, service)
33 | if err != nil {
34 | r.Recorder.Eventf(service, corev1.EventTypeWarning, "Invalid", "%s", err)
35 | return reconcile.Result{}, err
36 | }
37 | }
38 |
39 | return r.DoReconcile(ctx, log, service, certInputMap)
40 | }
41 |
42 | func (r *Reconciler) getCertificateInputMap(log logr.Logger, service *corev1.Service) (common.CertInputMap, error) {
43 | inputMap, err := common.GetCertSourceSpecForService(log, service)
44 | if err != nil {
45 | return nil, err
46 | }
47 | if len(inputMap) > 1 {
48 | return nil, fmt.Errorf("expected one certificate source, found %d", len(inputMap))
49 | }
50 | return inputMap, nil
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/certman2/controller/source/service/service_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package service_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestLandscape(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Service Source Controller Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/core/const.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | const (
10 | // ACMEType is the type name for ACME.
11 | ACMEType = "acme"
12 | // CAType is the type name for CA.
13 | CAType = "ca"
14 | )
15 |
16 | const (
17 | // AnnotationClass is the annotation to set the cert class.
18 | AnnotationClass = "cert.gardener.cloud/class"
19 | )
20 |
--------------------------------------------------------------------------------
/pkg/certman2/core/issuerDNSSelections.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sync"
11 |
12 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
13 | )
14 |
15 | // NewIssuerDNSSelections creates an IssuerDNSSelections
16 | func NewIssuerDNSSelections() *IssuerDNSSelections {
17 | return &IssuerDNSSelections{
18 | selections: map[IssuerKey]*v1alpha1.DNSSelection{},
19 | }
20 | }
21 |
22 | // IssuerDNSSelections stores last known DNS selection for an issuer
23 | type IssuerDNSSelections struct {
24 | lock sync.Mutex
25 | selections map[IssuerKey]*v1alpha1.DNSSelection
26 | }
27 |
28 | // Add adds a DNS selection
29 | func (s *IssuerDNSSelections) Add(key IssuerKey, sel *v1alpha1.DNSSelection) {
30 | s.lock.Lock()
31 | defer s.lock.Unlock()
32 |
33 | s.selections[key] = sel
34 | }
35 |
36 | // Remove removes a DNS selection
37 | func (s *IssuerDNSSelections) Remove(key IssuerKey) {
38 | s.lock.Lock()
39 | defer s.lock.Unlock()
40 |
41 | delete(s.selections, key)
42 | }
43 |
44 | // GetSelection returns the selection for the given key.
45 | func (s *IssuerDNSSelections) GetSelection(key IssuerKey) *v1alpha1.DNSSelection {
46 | s.lock.Lock()
47 | defer s.lock.Unlock()
48 |
49 | return s.selections[key]
50 | }
51 |
52 | // Issuers returns all issuer keys.
53 | func (s *IssuerDNSSelections) Issuers() []IssuerKey {
54 | s.lock.Lock()
55 | defer s.lock.Unlock()
56 |
57 | keys := []IssuerKey{}
58 | for key := range s.selections {
59 | keys = append(keys, key)
60 | }
61 | return keys
62 | }
63 |
64 | // GetAll returns a map with all selections
65 | func (s *IssuerDNSSelections) GetAll() map[IssuerKey]*v1alpha1.DNSSelection {
66 | s.lock.Lock()
67 | defer s.lock.Unlock()
68 |
69 | result := map[IssuerKey]*v1alpha1.DNSSelection{}
70 | for k, v := range s.selections {
71 | result[k] = v
72 | }
73 | return result
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/certman2/core/keys.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | corev1 "k8s.io/api/core/v1"
11 | "sigs.k8s.io/controller-runtime/pkg/client"
12 |
13 | "github.com/gardener/cert-management/pkg/shared"
14 | )
15 |
16 | // IssuerKey provides object key and cluster of an issuer.
17 | type IssuerKey struct {
18 | client.ObjectKey
19 | secondary bool
20 | }
21 |
22 | // Name provides issuer name.
23 | func (k IssuerKey) Name() string {
24 | return k.ObjectKey.Name
25 | }
26 |
27 | // Namespace provides issuer namespace.
28 | func (k IssuerKey) Namespace() string {
29 | return k.ObjectKey.Namespace
30 | }
31 |
32 | // Cluster provides cluster (from CML).
33 | func (k IssuerKey) Cluster() shared.Cluster {
34 | if k.secondary {
35 | return shared.ClusterDefault
36 | }
37 | return shared.ClusterTarget
38 | }
39 |
40 | // Secondary returns true if issuer is from secondary cluster.
41 | func (k IssuerKey) Secondary() bool {
42 | return k.secondary
43 | }
44 |
45 | func (k IssuerKey) String() string {
46 | if k.secondary {
47 | return k.ObjectKey.Name
48 | }
49 | return "target:" + k.ObjectKey.String()
50 | }
51 |
52 | var _ shared.IssuerKeyItf = IssuerKey{}
53 |
54 | // NewIssuerKey creates key for an issuer.
55 | func NewIssuerKey(key client.ObjectKey, secondary bool) IssuerKey {
56 | return IssuerKey{ObjectKey: key, secondary: secondary}
57 | }
58 |
59 | // SecretKey provides object key and cluster of a secret
60 | type SecretKey struct {
61 | client.ObjectKey
62 | secondary bool
63 | }
64 |
65 | // NewSecretKey creates key for a secret.
66 | func NewSecretKey(key client.ObjectKey, secondary bool) SecretKey {
67 | return SecretKey{ObjectKey: key, secondary: secondary}
68 | }
69 |
70 | // IsFromSecondaryCluster returns true if secret is from secondary cluster.
71 | func (k SecretKey) IsFromSecondaryCluster() bool {
72 | return k.secondary
73 | }
74 |
75 | // ObjectKeyFromSecretReference returns an ObjectKey for a secret reference.
76 | func ObjectKeyFromSecretReference(secretRef *corev1.SecretReference) client.ObjectKey {
77 | return client.ObjectKey{Namespace: secretRef.Namespace, Name: secretRef.Name}
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/certman2/core/objectnameset.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sort"
11 | "strings"
12 | "sync"
13 |
14 | "k8s.io/apimachinery/pkg/util/sets"
15 | "sigs.k8s.io/controller-runtime/pkg/client"
16 | )
17 |
18 | // newObjectKeySet creates a synced Set[client.ObjectKey]
19 | func newObjectKeySet() *objectKeySet {
20 | return &objectKeySet{
21 | set: sets.Set[client.ObjectKey]{},
22 | }
23 | }
24 |
25 | // objectKeySet is a synced ObjectNameSet.
26 | type objectKeySet struct {
27 | lock sync.Mutex
28 | set sets.Set[client.ObjectKey]
29 | }
30 |
31 | // Add a name.
32 | func (s *objectKeySet) Add(key client.ObjectKey) bool {
33 | s.lock.Lock()
34 | defer s.lock.Unlock()
35 |
36 | old := len(s.set)
37 | s.set.Insert(key)
38 | return len(s.set) != old
39 | }
40 |
41 | // Remove a name.
42 | func (s *objectKeySet) Remove(key client.ObjectKey) bool {
43 | s.lock.Lock()
44 | defer s.lock.Unlock()
45 |
46 | oldLen := len(s.set)
47 | return len(s.set.Delete(key)) != oldLen
48 | }
49 |
50 | // UnsortedList returns copy of members as array
51 | func (s *objectKeySet) UnsortedList() []client.ObjectKey {
52 | s.lock.Lock()
53 | defer s.lock.Unlock()
54 |
55 | return s.set.UnsortedList()
56 | }
57 |
58 | func (s *objectKeySet) String() string {
59 | s.lock.Lock()
60 | defer s.lock.Unlock()
61 |
62 | array := s.UnsortedList()
63 | sort.Slice(array, func(i, j int) bool {
64 | if array[i].Namespace < array[j].Namespace {
65 | return true
66 | } else if array[i].Namespace > array[j].Namespace {
67 | return false
68 | } else {
69 | return array[i].Name < array[j].Name
70 | }
71 | })
72 | strs := make([]string, len(array))
73 | for i, obj := range array {
74 | strs[i] = obj.String()
75 | }
76 | return strings.Join(strs, ",")
77 | }
78 |
79 | func (s *objectKeySet) Size() int {
80 | s.lock.Lock()
81 | defer s.lock.Unlock()
82 |
83 | return len(s.set)
84 | }
85 |
--------------------------------------------------------------------------------
/pkg/certman2/core/quotas.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sync"
11 |
12 | "k8s.io/client-go/util/flowcontrol"
13 | )
14 |
15 | // NewQuotas create a Quotas
16 | func NewQuotas() *Quotas {
17 | return &Quotas{
18 | issuerToQuotas: map[IssuerKey]quotas{},
19 | }
20 | }
21 |
22 | type quotas struct {
23 | rateLimiter flowcontrol.RateLimiter
24 | requestsPerDay int
25 | }
26 |
27 | // Quotas stores references issuer quotas.
28 | type Quotas struct {
29 | lock sync.Mutex
30 | issuerToQuotas map[IssuerKey]quotas
31 | }
32 |
33 | // RememberQuotas stores the requests per days quota and creates a new ratelimiter if the quota changed.
34 | func (q *Quotas) RememberQuotas(issuerKey IssuerKey, requestsPerDay int) {
35 | q.lock.Lock()
36 | defer q.lock.Unlock()
37 |
38 | if quotas, ok := q.issuerToQuotas[issuerKey]; ok {
39 | if quotas.requestsPerDay == requestsPerDay {
40 | return
41 | }
42 | }
43 |
44 | qps := float32(requestsPerDay) / 86400
45 | burst := requestsPerDay / 4
46 | if burst < 1 {
47 | burst = 1
48 | }
49 |
50 | q.issuerToQuotas[issuerKey] = quotas{
51 | rateLimiter: flowcontrol.NewTokenBucketRateLimiter(qps, burst),
52 | requestsPerDay: requestsPerDay,
53 | }
54 | }
55 |
56 | // TryAccept tries to accept a certificate request according to the quotas.
57 | // Returns true if accepted and the requests per days quota value
58 | func (q *Quotas) TryAccept(issuerKey IssuerKey) (bool, int) {
59 | q.lock.Lock()
60 | defer q.lock.Unlock()
61 |
62 | if quotas, ok := q.issuerToQuotas[issuerKey]; ok {
63 | return quotas.rateLimiter.TryAccept(), quotas.requestsPerDay
64 | }
65 | return false, 0
66 | }
67 |
68 | // RemoveIssuer removes all secretRefs for an issuer.
69 | func (q *Quotas) RemoveIssuer(issuerKey IssuerKey) {
70 | q.lock.Lock()
71 | defer q.lock.Unlock()
72 |
73 | delete(q.issuerToQuotas, issuerKey)
74 | }
75 |
76 | // RequestsPerDay gets the request per day quota
77 | func (q *Quotas) RequestsPerDay(issuerName IssuerKey) int {
78 | q.lock.Lock()
79 | defer q.lock.Unlock()
80 |
81 | quotas, ok := q.issuerToQuotas[issuerName]
82 | if !ok {
83 | return 0
84 | }
85 | return quotas.requestsPerDay
86 | }
87 |
--------------------------------------------------------------------------------
/pkg/certman2/core/utils.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import "strings"
10 |
11 | // DomainsString creates a comma separated string.
12 | func DomainsString(domains []string) string {
13 | if domains == nil {
14 | return ""
15 | }
16 | return strings.Join(domains, ",")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/certman2/core/wrappedregistration.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "encoding/json"
11 |
12 | "github.com/go-acme/lego/v4/registration"
13 | "k8s.io/apimachinery/pkg/runtime"
14 | )
15 |
16 | type wrappedRegistration struct {
17 | registration.Resource `json:",inline"`
18 | SecretHash *string `json:"secretHash,omitempty"`
19 | }
20 |
21 | // WrapRegistration wraps registration.
22 | func WrapRegistration(raw []byte, secretHash string) ([]byte, error) {
23 | reg := &wrappedRegistration{}
24 | err := json.Unmarshal(raw, reg)
25 | if err != nil {
26 | return nil, err
27 | }
28 | reg.SecretHash = &secretHash
29 | return json.Marshal(®)
30 | }
31 |
32 | // WrapRegistrationFromResource unmarshalls a wrapped registration.
33 | func WrapRegistrationFromResource(raw []byte) (*wrappedRegistration, error) {
34 | reg := &wrappedRegistration{}
35 | err := json.Unmarshal(raw, reg)
36 | if err != nil {
37 | return nil, err
38 | }
39 | return reg, nil
40 | }
41 |
42 | // IsSameExistingRegistration returns true if status ACME has same secret hash.
43 | func IsSameExistingRegistration(raw *runtime.RawExtension, realSecretHash string) bool {
44 | if raw == nil || raw.Raw == nil {
45 | return false
46 | }
47 | reg := &wrappedRegistration{}
48 | if err := json.Unmarshal(raw.Raw, reg); err == nil && reg.SecretHash != nil {
49 | return *reg.SecretHash == realSecretHash
50 | }
51 | return false
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/certman2/testutils/assert_events.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package testutils
8 |
9 | import (
10 | "fmt"
11 | "strings"
12 | "time"
13 |
14 | . "github.com/onsi/ginkgo/v2"
15 | . "github.com/onsi/gomega"
16 | )
17 |
18 | // AssertEvents checks for expected events (in the given order).
19 | func AssertEvents(actual <-chan string, expectedList ...string) {
20 | c := time.After(1 * time.Second)
21 | for _, e := range expectedList {
22 | select {
23 | case a := <-actual:
24 | if !strings.HasPrefix(a, e) {
25 | Expect(a).To(ContainSubstring(e))
26 | return
27 | }
28 | case <-c:
29 | Fail(fmt.Sprintf("Expected event %q, got nothing", e))
30 | // continue iterating to print all expected events
31 | }
32 | }
33 | for {
34 | select {
35 | case a := <-actual:
36 | Fail(fmt.Sprintf("Unexpected event: %q", a))
37 | default:
38 | return // No more events, as expected.
39 | }
40 | }
41 | }
42 |
43 | // AssertUnorderedEvents checks for expected events (any order).
44 | func AssertUnorderedEvents(actual <-chan string, expectedList ...string) {
45 | c := time.After(1 * time.Second)
46 | var actualList []string
47 | for _, e := range expectedList {
48 | select {
49 | case a := <-actual:
50 | actualList = append(actualList, a)
51 | case <-c:
52 | Fail(fmt.Sprintf("Expected event %q, got nothing", e))
53 | // continue iterating to print all expected events
54 | }
55 | }
56 | outer:
57 | for {
58 | select {
59 | case a := <-actual:
60 | actualList = append(actualList, a)
61 | default:
62 | break outer // No more events, as expected.
63 | }
64 | }
65 |
66 | missing := []string{}
67 | outer2:
68 | for _, e := range expectedList {
69 | for i, a := range actualList {
70 | if strings.HasPrefix(a, e) {
71 | actualList = append(actualList[:i], actualList[i+1:]...)
72 | continue outer2
73 | }
74 | }
75 | missing = append(missing, e)
76 | }
77 | // show mismatches
78 | Expect(missing).To(Equal(actualList))
79 | }
80 |
--------------------------------------------------------------------------------
/pkg/client/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | // This package has the automatically generated fake clientset.
8 | package fake
9 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package fake
8 |
9 | import (
10 | certv1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | runtime "k8s.io/apimachinery/pkg/runtime"
13 | schema "k8s.io/apimachinery/pkg/runtime/schema"
14 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
15 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
16 | )
17 |
18 | var scheme = runtime.NewScheme()
19 | var codecs = serializer.NewCodecFactory(scheme)
20 |
21 | var localSchemeBuilder = runtime.SchemeBuilder{
22 | certv1alpha1.AddToScheme,
23 | }
24 |
25 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
26 | // of clientsets, like in:
27 | //
28 | // import (
29 | // "k8s.io/client-go/kubernetes"
30 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
31 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
32 | // )
33 | //
34 | // kclientset, _ := kubernetes.NewForConfig(c)
35 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
36 | //
37 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
38 | // correctly.
39 | var AddToScheme = localSchemeBuilder.AddToScheme
40 |
41 | func init() {
42 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
43 | utilruntime.Must(AddToScheme(scheme))
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | // This package contains the scheme of the automatically generated clientset.
8 | package scheme
9 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package scheme
8 |
9 | import (
10 | certv1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | runtime "k8s.io/apimachinery/pkg/runtime"
13 | schema "k8s.io/apimachinery/pkg/runtime/schema"
14 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
15 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
16 | )
17 |
18 | var Scheme = runtime.NewScheme()
19 | var Codecs = serializer.NewCodecFactory(Scheme)
20 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
21 | var localSchemeBuilder = runtime.SchemeBuilder{
22 | certv1alpha1.AddToScheme,
23 | }
24 |
25 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
26 | // of clientsets, like in:
27 | //
28 | // import (
29 | // "k8s.io/client-go/kubernetes"
30 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
31 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
32 | // )
33 | //
34 | // kclientset, _ := kubernetes.NewForConfig(c)
35 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
36 | //
37 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
38 | // correctly.
39 | var AddToScheme = localSchemeBuilder.AddToScheme
40 |
41 | func init() {
42 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
43 | utilruntime.Must(AddToScheme(Scheme))
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | // This package has the automatically generated typed clients.
8 | package v1alpha1
9 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/fake/doc.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | // Package fake has the automatically generated clients.
8 | package fake
9 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/fake/fake_cert_client.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package fake
8 |
9 | import (
10 | v1alpha1 "github.com/gardener/cert-management/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1"
11 | rest "k8s.io/client-go/rest"
12 | testing "k8s.io/client-go/testing"
13 | )
14 |
15 | type FakeCertV1alpha1 struct {
16 | *testing.Fake
17 | }
18 |
19 | func (c *FakeCertV1alpha1) Certificates(namespace string) v1alpha1.CertificateInterface {
20 | return newFakeCertificates(c, namespace)
21 | }
22 |
23 | func (c *FakeCertV1alpha1) CertificateRevocations(namespace string) v1alpha1.CertificateRevocationInterface {
24 | return newFakeCertificateRevocations(c, namespace)
25 | }
26 |
27 | func (c *FakeCertV1alpha1) Issuers(namespace string) v1alpha1.IssuerInterface {
28 | return newFakeIssuers(c, namespace)
29 | }
30 |
31 | // RESTClient returns a RESTClient that is used to communicate
32 | // with API server by this client implementation.
33 | func (c *FakeCertV1alpha1) RESTClient() rest.Interface {
34 | var ret *rest.RESTClient
35 | return ret
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/fake/fake_certificate.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package fake
8 |
9 | import (
10 | v1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | certv1alpha1 "github.com/gardener/cert-management/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1"
12 | gentype "k8s.io/client-go/gentype"
13 | )
14 |
15 | // fakeCertificates implements CertificateInterface
16 | type fakeCertificates struct {
17 | *gentype.FakeClientWithList[*v1alpha1.Certificate, *v1alpha1.CertificateList]
18 | Fake *FakeCertV1alpha1
19 | }
20 |
21 | func newFakeCertificates(fake *FakeCertV1alpha1, namespace string) certv1alpha1.CertificateInterface {
22 | return &fakeCertificates{
23 | gentype.NewFakeClientWithList[*v1alpha1.Certificate, *v1alpha1.CertificateList](
24 | fake.Fake,
25 | namespace,
26 | v1alpha1.SchemeGroupVersion.WithResource("certificates"),
27 | v1alpha1.SchemeGroupVersion.WithKind("Certificate"),
28 | func() *v1alpha1.Certificate { return &v1alpha1.Certificate{} },
29 | func() *v1alpha1.CertificateList { return &v1alpha1.CertificateList{} },
30 | func(dst, src *v1alpha1.CertificateList) { dst.ListMeta = src.ListMeta },
31 | func(list *v1alpha1.CertificateList) []*v1alpha1.Certificate {
32 | return gentype.ToPointerSlice(list.Items)
33 | },
34 | func(list *v1alpha1.CertificateList, items []*v1alpha1.Certificate) {
35 | list.Items = gentype.FromPointerSlice(items)
36 | },
37 | ),
38 | fake,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/fake/fake_certificaterevocation.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package fake
8 |
9 | import (
10 | v1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | certv1alpha1 "github.com/gardener/cert-management/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1"
12 | gentype "k8s.io/client-go/gentype"
13 | )
14 |
15 | // fakeCertificateRevocations implements CertificateRevocationInterface
16 | type fakeCertificateRevocations struct {
17 | *gentype.FakeClientWithList[*v1alpha1.CertificateRevocation, *v1alpha1.CertificateRevocationList]
18 | Fake *FakeCertV1alpha1
19 | }
20 |
21 | func newFakeCertificateRevocations(fake *FakeCertV1alpha1, namespace string) certv1alpha1.CertificateRevocationInterface {
22 | return &fakeCertificateRevocations{
23 | gentype.NewFakeClientWithList[*v1alpha1.CertificateRevocation, *v1alpha1.CertificateRevocationList](
24 | fake.Fake,
25 | namespace,
26 | v1alpha1.SchemeGroupVersion.WithResource("certificaterevocations"),
27 | v1alpha1.SchemeGroupVersion.WithKind("CertificateRevocation"),
28 | func() *v1alpha1.CertificateRevocation { return &v1alpha1.CertificateRevocation{} },
29 | func() *v1alpha1.CertificateRevocationList { return &v1alpha1.CertificateRevocationList{} },
30 | func(dst, src *v1alpha1.CertificateRevocationList) { dst.ListMeta = src.ListMeta },
31 | func(list *v1alpha1.CertificateRevocationList) []*v1alpha1.CertificateRevocation {
32 | return gentype.ToPointerSlice(list.Items)
33 | },
34 | func(list *v1alpha1.CertificateRevocationList, items []*v1alpha1.CertificateRevocation) {
35 | list.Items = gentype.FromPointerSlice(items)
36 | },
37 | ),
38 | fake,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/fake/fake_issuer.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package fake
8 |
9 | import (
10 | v1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | certv1alpha1 "github.com/gardener/cert-management/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1"
12 | gentype "k8s.io/client-go/gentype"
13 | )
14 |
15 | // fakeIssuers implements IssuerInterface
16 | type fakeIssuers struct {
17 | *gentype.FakeClientWithList[*v1alpha1.Issuer, *v1alpha1.IssuerList]
18 | Fake *FakeCertV1alpha1
19 | }
20 |
21 | func newFakeIssuers(fake *FakeCertV1alpha1, namespace string) certv1alpha1.IssuerInterface {
22 | return &fakeIssuers{
23 | gentype.NewFakeClientWithList[*v1alpha1.Issuer, *v1alpha1.IssuerList](
24 | fake.Fake,
25 | namespace,
26 | v1alpha1.SchemeGroupVersion.WithResource("issuers"),
27 | v1alpha1.SchemeGroupVersion.WithKind("Issuer"),
28 | func() *v1alpha1.Issuer { return &v1alpha1.Issuer{} },
29 | func() *v1alpha1.IssuerList { return &v1alpha1.IssuerList{} },
30 | func(dst, src *v1alpha1.IssuerList) { dst.ListMeta = src.ListMeta },
31 | func(list *v1alpha1.IssuerList) []*v1alpha1.Issuer { return gentype.ToPointerSlice(list.Items) },
32 | func(list *v1alpha1.IssuerList, items []*v1alpha1.Issuer) {
33 | list.Items = gentype.FromPointerSlice(items)
34 | },
35 | ),
36 | fake,
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/client/cert/clientset/versioned/typed/cert/v1alpha1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by client-gen. DO NOT EDIT.
6 |
7 | package v1alpha1
8 |
9 | type CertificateExpansion interface{}
10 |
11 | type CertificateRevocationExpansion interface{}
12 |
13 | type IssuerExpansion interface{}
14 |
--------------------------------------------------------------------------------
/pkg/client/cert/informers/externalversions/cert/interface.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by informer-gen. DO NOT EDIT.
6 |
7 | package cert
8 |
9 | import (
10 | v1alpha1 "github.com/gardener/cert-management/pkg/client/cert/informers/externalversions/cert/v1alpha1"
11 | internalinterfaces "github.com/gardener/cert-management/pkg/client/cert/informers/externalversions/internalinterfaces"
12 | )
13 |
14 | // Interface provides access to each of this group's versions.
15 | type Interface interface {
16 | // V1alpha1 provides access to shared informers for resources in V1alpha1.
17 | V1alpha1() v1alpha1.Interface
18 | }
19 |
20 | type group struct {
21 | factory internalinterfaces.SharedInformerFactory
22 | namespace string
23 | tweakListOptions internalinterfaces.TweakListOptionsFunc
24 | }
25 |
26 | // New returns a new Interface.
27 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
28 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
29 | }
30 |
31 | // V1alpha1 returns a new v1alpha1.Interface.
32 | func (g *group) V1alpha1() v1alpha1.Interface {
33 | return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/client/cert/informers/externalversions/cert/v1alpha1/interface.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by informer-gen. DO NOT EDIT.
6 |
7 | package v1alpha1
8 |
9 | import (
10 | internalinterfaces "github.com/gardener/cert-management/pkg/client/cert/informers/externalversions/internalinterfaces"
11 | )
12 |
13 | // Interface provides access to all the informers in this group version.
14 | type Interface interface {
15 | // Certificates returns a CertificateInformer.
16 | Certificates() CertificateInformer
17 | // CertificateRevocations returns a CertificateRevocationInformer.
18 | CertificateRevocations() CertificateRevocationInformer
19 | // Issuers returns a IssuerInformer.
20 | Issuers() IssuerInformer
21 | }
22 |
23 | type version struct {
24 | factory internalinterfaces.SharedInformerFactory
25 | namespace string
26 | tweakListOptions internalinterfaces.TweakListOptionsFunc
27 | }
28 |
29 | // New returns a new Interface.
30 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
31 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
32 | }
33 |
34 | // Certificates returns a CertificateInformer.
35 | func (v *version) Certificates() CertificateInformer {
36 | return &certificateInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
37 | }
38 |
39 | // CertificateRevocations returns a CertificateRevocationInformer.
40 | func (v *version) CertificateRevocations() CertificateRevocationInformer {
41 | return &certificateRevocationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
42 | }
43 |
44 | // Issuers returns a IssuerInformer.
45 | func (v *version) Issuers() IssuerInformer {
46 | return &issuerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/client/cert/informers/externalversions/generic.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by informer-gen. DO NOT EDIT.
6 |
7 | package externalversions
8 |
9 | import (
10 | fmt "fmt"
11 |
12 | v1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
13 | schema "k8s.io/apimachinery/pkg/runtime/schema"
14 | cache "k8s.io/client-go/tools/cache"
15 | )
16 |
17 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
18 | // sharedInformers based on type
19 | type GenericInformer interface {
20 | Informer() cache.SharedIndexInformer
21 | Lister() cache.GenericLister
22 | }
23 |
24 | type genericInformer struct {
25 | informer cache.SharedIndexInformer
26 | resource schema.GroupResource
27 | }
28 |
29 | // Informer returns the SharedIndexInformer.
30 | func (f *genericInformer) Informer() cache.SharedIndexInformer {
31 | return f.informer
32 | }
33 |
34 | // Lister returns the GenericLister.
35 | func (f *genericInformer) Lister() cache.GenericLister {
36 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
37 | }
38 |
39 | // ForResource gives generic access to a shared informer of the matching type
40 | // TODO extend this to unknown resources with a client pool
41 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
42 | switch resource {
43 | // Group=cert.gardener.cloud, Version=v1alpha1
44 | case v1alpha1.SchemeGroupVersion.WithResource("certificates"):
45 | return &genericInformer{resource: resource.GroupResource(), informer: f.Cert().V1alpha1().Certificates().Informer()}, nil
46 | case v1alpha1.SchemeGroupVersion.WithResource("certificaterevocations"):
47 | return &genericInformer{resource: resource.GroupResource(), informer: f.Cert().V1alpha1().CertificateRevocations().Informer()}, nil
48 | case v1alpha1.SchemeGroupVersion.WithResource("issuers"):
49 | return &genericInformer{resource: resource.GroupResource(), informer: f.Cert().V1alpha1().Issuers().Informer()}, nil
50 |
51 | }
52 |
53 | return nil, fmt.Errorf("no informer found for %v", resource)
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/client/cert/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by informer-gen. DO NOT EDIT.
6 |
7 | package internalinterfaces
8 |
9 | import (
10 | time "time"
11 |
12 | versioned "github.com/gardener/cert-management/pkg/client/cert/clientset/versioned"
13 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14 | runtime "k8s.io/apimachinery/pkg/runtime"
15 | cache "k8s.io/client-go/tools/cache"
16 | )
17 |
18 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
19 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
20 |
21 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
22 | type SharedInformerFactory interface {
23 | Start(stopCh <-chan struct{})
24 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
25 | }
26 |
27 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
28 | type TweakListOptionsFunc func(*v1.ListOptions)
29 |
--------------------------------------------------------------------------------
/pkg/client/cert/listers/cert/v1alpha1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by lister-gen. DO NOT EDIT.
6 |
7 | package v1alpha1
8 |
9 | // CertificateListerExpansion allows custom methods to be added to
10 | // CertificateLister.
11 | type CertificateListerExpansion interface{}
12 |
13 | // CertificateNamespaceListerExpansion allows custom methods to be added to
14 | // CertificateNamespaceLister.
15 | type CertificateNamespaceListerExpansion interface{}
16 |
17 | // CertificateRevocationListerExpansion allows custom methods to be added to
18 | // CertificateRevocationLister.
19 | type CertificateRevocationListerExpansion interface{}
20 |
21 | // CertificateRevocationNamespaceListerExpansion allows custom methods to be added to
22 | // CertificateRevocationNamespaceLister.
23 | type CertificateRevocationNamespaceListerExpansion interface{}
24 |
25 | // IssuerListerExpansion allows custom methods to be added to
26 | // IssuerLister.
27 | type IssuerListerExpansion interface{}
28 |
29 | // IssuerNamespaceListerExpansion allows custom methods to be added to
30 | // IssuerNamespaceLister.
31 | type IssuerNamespaceListerExpansion interface{}
32 |
--------------------------------------------------------------------------------
/pkg/client/cert/listers/cert/v1alpha1/issuer.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | // Code generated by lister-gen. DO NOT EDIT.
6 |
7 | package v1alpha1
8 |
9 | import (
10 | certv1alpha1 "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
11 | labels "k8s.io/apimachinery/pkg/labels"
12 | listers "k8s.io/client-go/listers"
13 | cache "k8s.io/client-go/tools/cache"
14 | )
15 |
16 | // IssuerLister helps list Issuers.
17 | // All objects returned here must be treated as read-only.
18 | type IssuerLister interface {
19 | // List lists all Issuers in the indexer.
20 | // Objects returned here must be treated as read-only.
21 | List(selector labels.Selector) (ret []*certv1alpha1.Issuer, err error)
22 | // Issuers returns an object that can list and get Issuers.
23 | Issuers(namespace string) IssuerNamespaceLister
24 | IssuerListerExpansion
25 | }
26 |
27 | // issuerLister implements the IssuerLister interface.
28 | type issuerLister struct {
29 | listers.ResourceIndexer[*certv1alpha1.Issuer]
30 | }
31 |
32 | // NewIssuerLister returns a new IssuerLister.
33 | func NewIssuerLister(indexer cache.Indexer) IssuerLister {
34 | return &issuerLister{listers.New[*certv1alpha1.Issuer](indexer, certv1alpha1.Resource("issuer"))}
35 | }
36 |
37 | // Issuers returns an object that can list and get Issuers.
38 | func (s *issuerLister) Issuers(namespace string) IssuerNamespaceLister {
39 | return issuerNamespaceLister{listers.NewNamespaced[*certv1alpha1.Issuer](s.ResourceIndexer, namespace)}
40 | }
41 |
42 | // IssuerNamespaceLister helps list and get Issuers.
43 | // All objects returned here must be treated as read-only.
44 | type IssuerNamespaceLister interface {
45 | // List lists all Issuers in the indexer for a given namespace.
46 | // Objects returned here must be treated as read-only.
47 | List(selector labels.Selector) (ret []*certv1alpha1.Issuer, err error)
48 | // Get retrieves the Issuer from the indexer for a given namespace and name.
49 | // Objects returned here must be treated as read-only.
50 | Get(name string) (*certv1alpha1.Issuer, error)
51 | IssuerNamespaceListerExpansion
52 | }
53 |
54 | // issuerNamespaceLister implements the IssuerNamespaceLister
55 | // interface.
56 | type issuerNamespaceLister struct {
57 | listers.ResourceIndexer[*certv1alpha1.Issuer]
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/controller/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/pkg/controller/common.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package controller
8 |
9 | import (
10 | "github.com/gardener/controller-manager-library/pkg/controllermanager/cluster"
11 | )
12 |
13 | const (
14 | // ControllerGroupCert is the controller group for certificates and issuers
15 | ControllerGroupCert = "certcontrollers"
16 | // ControllerGroupSource is the controller group for sources (ingress and services)
17 | ControllerGroupSource = "certsources"
18 | // DNSCluster is the name of the DNS cluster
19 | DNSCluster = "dns"
20 | // SourceCluster is the name of the source cluster
21 | SourceCluster = "source"
22 | // TargetCluster is the name of the target cluster
23 | TargetCluster = "target"
24 | // DefaultCluster is the name of the default cluster
25 | DefaultCluster = cluster.DEFAULT
26 | )
27 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/certificate/certificate_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestCertificate(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Certificate Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/certificate/utils_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package certificate
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 |
11 | api "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
12 | )
13 |
14 | var _ = Describe("Utils", func() {
15 | Context("#hasMultipleIssuerTypes", func() {
16 | var issuer *api.Issuer
17 |
18 | BeforeEach(func() {
19 | issuer = &api.Issuer{}
20 | })
21 |
22 | It("should return false if no issuer type is specified", func() {
23 | Expect(hasMultipleIssuerTypes(issuer)).To(BeFalse())
24 | })
25 |
26 | It("should return false if only one issuer type is specified", func() {
27 | issuer.Spec.ACME = &api.ACMESpec{}
28 | Expect(hasMultipleIssuerTypes(issuer)).To(BeFalse())
29 | })
30 |
31 | It("should return true if multiple issuer types are specified", func() {
32 | issuer.Spec.ACME = &api.ACMESpec{}
33 | issuer.Spec.SelfSigned = &api.SelfSignedSpec{}
34 | Expect(hasMultipleIssuerTypes(issuer)).To(BeTrue())
35 | })
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/core/core_suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core_test
8 |
9 | import (
10 | "testing"
11 |
12 | . "github.com/onsi/ginkgo/v2"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | func TestCore(t *testing.T) {
17 | RegisterFailHandler(Fail)
18 | RunSpecs(t, "Issuer Core Suite")
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/core/issuerDNSSelections.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sync"
11 |
12 | "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
13 | "github.com/gardener/cert-management/pkg/cert/utils"
14 | )
15 |
16 | // NewIssuerDNSSelections creates an IssuerDNSSelections
17 | func NewIssuerDNSSelections() *IssuerDNSSelections {
18 | return &IssuerDNSSelections{
19 | selections: map[utils.IssuerKey]*v1alpha1.DNSSelection{},
20 | }
21 | }
22 |
23 | // IssuerDNSSelections stores last known DNS selection for an issuer
24 | type IssuerDNSSelections struct {
25 | lock sync.Mutex
26 | selections map[utils.IssuerKey]*v1alpha1.DNSSelection
27 | }
28 |
29 | // Add adds a DNS selection
30 | func (s *IssuerDNSSelections) Add(key utils.IssuerKey, sel *v1alpha1.DNSSelection) {
31 | s.lock.Lock()
32 | defer s.lock.Unlock()
33 |
34 | s.selections[key] = sel
35 | }
36 |
37 | // Remove removes a DNS selection
38 | func (s *IssuerDNSSelections) Remove(key utils.IssuerKey) {
39 | s.lock.Lock()
40 | defer s.lock.Unlock()
41 |
42 | delete(s.selections, key)
43 | }
44 |
45 | // GetSelection returns the selection for the given key.
46 | func (s *IssuerDNSSelections) GetSelection(key utils.IssuerKey) *v1alpha1.DNSSelection {
47 | s.lock.Lock()
48 | defer s.lock.Unlock()
49 |
50 | return s.selections[key]
51 | }
52 |
53 | // Issuers returns all issuer keys.
54 | func (s *IssuerDNSSelections) Issuers() []utils.IssuerKey {
55 | s.lock.Lock()
56 | defer s.lock.Unlock()
57 |
58 | keys := []utils.IssuerKey{}
59 | for key := range s.selections {
60 | keys = append(keys, key)
61 | }
62 | return keys
63 | }
64 |
65 | // GetAll returns a map with all selections
66 | func (s *IssuerDNSSelections) GetAll() map[utils.IssuerKey]*v1alpha1.DNSSelection {
67 | s.lock.Lock()
68 | defer s.lock.Unlock()
69 |
70 | result := map[utils.IssuerKey]*v1alpha1.DNSSelection{}
71 | for k, v := range s.selections {
72 | result[k] = v
73 | }
74 | return result
75 | }
76 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/core/objectnameset.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sync"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/resources"
13 | )
14 |
15 | // newObjectNameSet creates a synced ObjectNameSet
16 | func newObjectNameSet() *objectNameSet {
17 | return &objectNameSet{
18 | set: resources.ObjectNameSet{},
19 | }
20 | }
21 |
22 | // objectNameSet is a synced ObjectNameSet.
23 | type objectNameSet struct {
24 | lock sync.Mutex
25 | set resources.ObjectNameSet
26 | }
27 |
28 | // Add a name.
29 | func (s *objectNameSet) Add(name resources.ObjectName) bool {
30 | s.lock.Lock()
31 | defer s.lock.Unlock()
32 |
33 | old := len(s.set)
34 | s.set.Add(name)
35 | return len(s.set) != old
36 | }
37 |
38 | // Remove a name.
39 | func (s *objectNameSet) Remove(name resources.ObjectName) bool {
40 | s.lock.Lock()
41 | defer s.lock.Unlock()
42 |
43 | old := len(s.set)
44 | s.set.Remove(name)
45 | return len(s.set) != old
46 | }
47 |
48 | // AsArray returns copy of members as array
49 | func (s *objectNameSet) AsArray() []resources.ObjectName {
50 | s.lock.Lock()
51 | defer s.lock.Unlock()
52 |
53 | return s.set.AsArray()
54 | }
55 |
56 | func (s *objectNameSet) String() string {
57 | s.lock.Lock()
58 | defer s.lock.Unlock()
59 |
60 | return s.set.String()
61 | }
62 |
63 | func (s *objectNameSet) Size() int {
64 | s.lock.Lock()
65 | defer s.lock.Unlock()
66 |
67 | return len(s.set)
68 | }
69 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/core/quotas.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "sync"
11 |
12 | "k8s.io/client-go/util/flowcontrol"
13 |
14 | "github.com/gardener/cert-management/pkg/cert/utils"
15 | )
16 |
17 | // NewQuotas create a Quotas
18 | func NewQuotas() *Quotas {
19 | return &Quotas{
20 | issuerToQuotas: map[utils.IssuerKey]quotas{},
21 | }
22 | }
23 |
24 | type quotas struct {
25 | rateLimiter flowcontrol.RateLimiter
26 | requestsPerDay int
27 | }
28 |
29 | // Quotas stores references issuer quotas.
30 | type Quotas struct {
31 | lock sync.Mutex
32 | issuerToQuotas map[utils.IssuerKey]quotas
33 | }
34 |
35 | // RememberQuotas stores the requests per days quota and creates a new ratelimiter if the quota changed.
36 | func (q *Quotas) RememberQuotas(issuerKey utils.IssuerKey, requestsPerDay int) {
37 | q.lock.Lock()
38 | defer q.lock.Unlock()
39 |
40 | if quotas, ok := q.issuerToQuotas[issuerKey]; ok {
41 | if quotas.requestsPerDay == requestsPerDay {
42 | return
43 | }
44 | }
45 |
46 | qps := float32(requestsPerDay) / 86400
47 | burst := requestsPerDay / 4
48 | if burst < 1 {
49 | burst = 1
50 | }
51 |
52 | q.issuerToQuotas[issuerKey] = quotas{
53 | rateLimiter: flowcontrol.NewTokenBucketRateLimiter(qps, burst),
54 | requestsPerDay: requestsPerDay,
55 | }
56 | }
57 |
58 | // TryAccept tries to accept a certificate request according to the quotas.
59 | // Returns true if accepted and the requests per days quota value
60 | func (q *Quotas) TryAccept(issuerKey utils.IssuerKey) (bool, int) {
61 | q.lock.Lock()
62 | defer q.lock.Unlock()
63 |
64 | if quotas, ok := q.issuerToQuotas[issuerKey]; ok {
65 | return quotas.rateLimiter.TryAccept(), quotas.requestsPerDay
66 | }
67 | return false, 0
68 | }
69 |
70 | // RemoveIssuer removes all secretRefs for an issuer.
71 | func (q *Quotas) RemoveIssuer(issuerKey utils.IssuerKey) {
72 | q.lock.Lock()
73 | defer q.lock.Unlock()
74 |
75 | delete(q.issuerToQuotas, issuerKey)
76 | }
77 |
78 | // RequestsPerDay gets the request per day quota
79 | func (q *Quotas) RequestsPerDay(issuerName utils.IssuerKey) int {
80 | q.lock.Lock()
81 | defer q.lock.Unlock()
82 |
83 | quotas, ok := q.issuerToQuotas[issuerName]
84 | if !ok {
85 | return 0
86 | }
87 | return quotas.requestsPerDay
88 | }
89 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/core/wrappedregistration.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package core
8 |
9 | import (
10 | "encoding/json"
11 |
12 | "github.com/go-acme/lego/v4/registration"
13 | "k8s.io/apimachinery/pkg/runtime"
14 | )
15 |
16 | type wrappedRegistration struct {
17 | registration.Resource `json:",inline"`
18 | SecretHash *string `json:"secretHash,omitempty"`
19 | }
20 |
21 | // WrapRegistration wraps registration
22 | func WrapRegistration(raw []byte, secretHash string) ([]byte, error) {
23 | reg := &wrappedRegistration{}
24 | err := json.Unmarshal(raw, reg)
25 | if err != nil {
26 | return nil, err
27 | }
28 | reg.SecretHash = &secretHash
29 | return json.Marshal(®)
30 | }
31 |
32 | // IsSameExistingRegistration returns true if status ACME has same secret hash
33 | // or if it has in the old format without secret hash (for migration)
34 | func IsSameExistingRegistration(raw *runtime.RawExtension, realSecretHash string) bool {
35 | if raw == nil || raw.Raw == nil {
36 | return false
37 | }
38 | reg := &wrappedRegistration{}
39 | if err := json.Unmarshal(raw.Raw, reg); err == nil && reg.SecretHash != nil {
40 | return *reg.SecretHash == realSecretHash
41 | }
42 | return true
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/selfSigned/handler.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package selfSigned
8 |
9 | import (
10 | "fmt"
11 | "math"
12 |
13 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller/reconcile"
14 | "github.com/gardener/controller-manager-library/pkg/logger"
15 | "github.com/gardener/controller-manager-library/pkg/resources"
16 | "k8s.io/utils/ptr"
17 |
18 | api "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
19 | "github.com/gardener/cert-management/pkg/controller/issuer/core"
20 | )
21 |
22 | var selfSignedType = core.SelfSignedType
23 |
24 | // NewSelfSignedIssuerHandler creates an SelfSigned IssuerHandler.
25 | func NewSelfSignedIssuerHandler(support *core.Support) (core.IssuerHandler, error) {
26 | return &selfSignedIssuerHandler{
27 | support: support,
28 | }, nil
29 | }
30 |
31 | type selfSignedIssuerHandler struct {
32 | support *core.Support
33 | }
34 |
35 | func (h *selfSignedIssuerHandler) Type() string {
36 | return core.SelfSignedType
37 | }
38 |
39 | func (h *selfSignedIssuerHandler) CanReconcile(issuer *api.Issuer) bool {
40 | return issuer != nil && issuer.Spec.SelfSigned != nil
41 | }
42 |
43 | func (h *selfSignedIssuerHandler) Reconcile(logger logger.LogContext, obj resources.Object, issuer *api.Issuer) reconcile.Status {
44 | logger.Infof("reconciling")
45 |
46 | selfSigned := issuer.Spec.SelfSigned
47 | if selfSigned == nil {
48 | return h.support.Failed(logger, obj, api.StateError, &selfSignedType, fmt.Errorf("missing selfSigned spec"), false)
49 | }
50 | issuer.Spec.RequestsPerDayQuota = ptr.To(math.MaxInt64)
51 |
52 | return h.support.SucceedSelfSignedIssuer(logger, obj, &selfSignedType)
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/selfSigned/handler_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package selfSigned_test
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 |
11 | api "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1"
12 | "github.com/gardener/cert-management/pkg/controller/issuer/selfSigned"
13 | )
14 |
15 | var _ = Describe("Handler", func() {
16 | h, _ := selfSigned.NewSelfSignedIssuerHandler(nil)
17 |
18 | Context("#CanReconcile", func() {
19 | It("should return false if issuer is nil", func() {
20 | Expect(h.CanReconcile(nil)).To(BeFalse())
21 | })
22 |
23 | It("should return false if issuer type is unset", func() {
24 | issuer := &api.Issuer{}
25 | Expect(h.CanReconcile(issuer)).To(BeFalse())
26 | })
27 |
28 | It("should return false if issuer type is not self-signed", func() {
29 | issuer := &api.Issuer{Spec: api.IssuerSpec{ACME: &api.ACMESpec{}}}
30 | Expect(h.CanReconcile(issuer)).To(BeFalse())
31 | })
32 |
33 | It("should return true if issuer type is self-signed", func() {
34 | issuer := &api.Issuer{Spec: api.IssuerSpec{SelfSigned: &api.SelfSignedSpec{}}}
35 | Expect(h.CanReconcile(issuer)).To(BeTrue())
36 | })
37 | })
38 | })
39 |
--------------------------------------------------------------------------------
/pkg/controller/issuer/selfSigned/selfSigned_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package selfSigned_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestSelfSigned(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "SelfSigned Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/gatewayapi/controller.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package gatewayapi
6 |
7 | import (
8 | "strings"
9 |
10 | "github.com/gardener/controller-manager-library/pkg/resources"
11 |
12 | "github.com/gardener/cert-management/pkg/cert/source"
13 | ctrl "github.com/gardener/cert-management/pkg/controller"
14 | )
15 |
16 | // Group is the group of the Gateway API.
17 | const Group = "gateway.networking.k8s.io"
18 |
19 | var (
20 | // GroupKindGateway is the GroupKind for the Gateway resource.
21 | GroupKindGateway = resources.NewGroupKind(Group, "Gateway")
22 | // GroupKindHTTPRoute is the GroupKind for the HTTPRoute resource.
23 | GroupKindHTTPRoute = resources.NewGroupKind(Group, "HTTPRoute")
24 | )
25 |
26 | func init() {
27 | source.CertSourceController(source.NewCertSourceTypeForCreator("k8s-gateways-dns", GroupKindGateway, NewGatewaySource), nil).
28 | FinalizerDomain("cert.gardener.cloud").
29 | RequireLease(ctrl.SourceCluster).
30 | DeactivateOnCreationErrorCheck(deactivateOnMissingMainResource).
31 | Reconciler(httpRoutesReconciler, "httproutes").
32 | WorkerPool("httproutes", 2, 0).
33 | ReconcilerWatchesByGK("httproutes", GroupKindHTTPRoute).
34 | MustRegister(ctrl.ControllerGroupSource)
35 | }
36 |
37 | func deactivateOnMissingMainResource(err error) bool {
38 | return strings.Contains(err.Error(), "gardener/cml/resources/UNKNOWN_RESOURCE") &&
39 | (strings.Contains(err.Error(), GroupKindGateway.String()) || strings.Contains(err.Error(), GroupKindHTTPRoute.String()))
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/gatewayapi/gateway_suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | *
7 | */
8 |
9 | package gatewayapi_test
10 |
11 | import (
12 | "testing"
13 |
14 | ginkgov2 "github.com/onsi/ginkgo/v2"
15 | . "github.com/onsi/gomega"
16 | )
17 |
18 | func TestUtilsSuite(t *testing.T) {
19 | RegisterFailHandler(ginkgov2.Fail)
20 | ginkgov2.RunSpecs(t, "Networking Kubernetes Gateway Suite")
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/gatewayapi/state.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package gatewayapi
6 |
7 | import (
8 | "sync"
9 |
10 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller"
11 | "github.com/gardener/controller-manager-library/pkg/ctxutil"
12 | "github.com/gardener/controller-manager-library/pkg/resources"
13 | )
14 |
15 | var stateKey = ctxutil.SimpleKey("gatewayapi-gateways-state")
16 |
17 | type routesState struct {
18 | lock sync.Mutex
19 |
20 | routesToGateways map[resources.ObjectName][]resources.ObjectName
21 | }
22 |
23 | func newState() *routesState {
24 | return &routesState{
25 | routesToGateways: map[resources.ObjectName][]resources.ObjectName{},
26 | }
27 | }
28 |
29 | func getOrCreateSharedState(c controller.Interface) (*routesState, error) {
30 | state := c.GetEnvironment().GetOrCreateSharedValue(stateKey, func() interface{} {
31 | return newState()
32 | }).(*routesState)
33 |
34 | return state, nil
35 | }
36 |
37 | func (s *routesState) AddRoute(route resources.ObjectName, gateways resources.ObjectNameSet) []resources.ObjectName {
38 | s.lock.Lock()
39 | defer s.lock.Unlock()
40 |
41 | oldGateways := s.routesToGateways[route]
42 | if len(gateways) == 0 {
43 | delete(s.routesToGateways, route)
44 | return oldGateways
45 | }
46 |
47 | s.routesToGateways[route] = gateways.AsArray()
48 | return oldGateways
49 | }
50 |
51 | func (s *routesState) RemoveRoute(route resources.ObjectName) {
52 | s.lock.Lock()
53 | defer s.lock.Unlock()
54 |
55 | delete(s.routesToGateways, route)
56 | }
57 |
58 | func (s *routesState) MatchingGatewaysByRoute(route resources.ObjectName) []resources.ObjectName {
59 | s.lock.Lock()
60 | defer s.lock.Unlock()
61 |
62 | if array := s.routesToGateways[route]; array != nil {
63 | value := make([]resources.ObjectName, len(array))
64 | copy(value, array)
65 | return value
66 | }
67 | return nil
68 | }
69 |
70 | func (s *routesState) RoutesCount() int {
71 | s.lock.Lock()
72 | defer s.lock.Unlock()
73 | return len(s.routesToGateways)
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/istio/controller.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package istio
6 |
7 | import (
8 | "strings"
9 |
10 | "github.com/gardener/controller-manager-library/pkg/resources"
11 |
12 | "github.com/gardener/cert-management/pkg/cert/source"
13 | ctrl "github.com/gardener/cert-management/pkg/controller"
14 | "github.com/gardener/cert-management/pkg/controller/source/ingress"
15 | "github.com/gardener/cert-management/pkg/controller/source/service"
16 | )
17 |
18 | var (
19 | // GroupKindGateway is the GroupKind for the Gateway resource.
20 | GroupKindGateway = resources.NewGroupKind("networking.istio.io", "Gateway")
21 | // GroupKindVirtualService is the GroupKind for the VirtualService resource.
22 | GroupKindVirtualService = resources.NewGroupKind("networking.istio.io", "VirtualService")
23 | )
24 |
25 | func init() {
26 | source.CertSourceController(source.NewCertSourceTypeForCreator("istio-gateways-dns", GroupKindGateway, newGatewaySource), nil).
27 | FinalizerDomain("cert.gardener.cloud").
28 | RequireLease(ctrl.SourceCluster).
29 | DeactivateOnCreationErrorCheck(deactivateOnMissingMainResource).
30 | Reconciler(newTargetSourcesReconciler, "targetsources").
31 | Reconciler(newVirtualServicesReconciler, "virtualservices").
32 | WorkerPool("targetsources", 2, 0).
33 | ReconcilerWatchesByGK("targetsources", service.MainResource, ingress.MainResource).
34 | WorkerPool("virtualservices", 2, 0).
35 | ReconcilerWatchesByGK("virtualservices", GroupKindVirtualService).
36 | MustRegister(ctrl.ControllerGroupSource)
37 | }
38 |
39 | func deactivateOnMissingMainResource(err error) bool {
40 | return strings.Contains(err.Error(), "gardener/cml/resources/UNKNOWN_RESOURCE") &&
41 | (strings.Contains(err.Error(), GroupKindGateway.String()) || strings.Contains(err.Error(), GroupKindVirtualService.String()))
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/istio/istio_gateway_suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | *
7 | */
8 |
9 | package istio
10 |
11 | import (
12 | "testing"
13 |
14 | ginkgov2 "github.com/onsi/ginkgo/v2"
15 | . "github.com/onsi/gomega"
16 | )
17 |
18 | func TestUtilsSuite(t *testing.T) {
19 | RegisterFailHandler(ginkgov2.Fail)
20 | ginkgov2.RunSpecs(t, "Istio Gateway Suite")
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/controller/source/gateways/istio/targetSourcesReconciler.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package istio
6 |
7 | import (
8 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller"
9 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller/reconcile"
10 | "github.com/gardener/controller-manager-library/pkg/logger"
11 | "github.com/gardener/controller-manager-library/pkg/resources"
12 | )
13 |
14 | func newTargetSourcesReconciler(c controller.Interface) (reconcile.Interface, error) {
15 | state, err := getOrCreateSharedState(c)
16 | if err != nil {
17 | return nil, err
18 | }
19 | return &targetSourcesReconciler{controller: c, state: state}, nil
20 | }
21 |
22 | var _ reconcile.Interface = &targetSourcesReconciler{}
23 |
24 | type targetSourcesReconciler struct {
25 | reconcile.DefaultReconciler
26 | controller controller.Interface
27 | state *resourcesState
28 | }
29 |
30 | func (r *targetSourcesReconciler) Reconcile(logger logger.LogContext, obj resources.Object) reconcile.Status {
31 | r.triggerGateways(obj.ClusterKey())
32 | return reconcile.Succeeded(logger)
33 | }
34 |
35 | func (r *targetSourcesReconciler) Delete(logger logger.LogContext, obj resources.Object) reconcile.Status {
36 | r.triggerGateways(obj.ClusterKey())
37 | return reconcile.Succeeded(logger)
38 | }
39 |
40 | func (r *targetSourcesReconciler) Deleted(logger logger.LogContext, key resources.ClusterObjectKey) reconcile.Status {
41 | r.triggerGateways(key)
42 | return reconcile.Succeeded(logger)
43 | }
44 |
45 | func (r *targetSourcesReconciler) triggerGateways(source resources.ClusterObjectKey) {
46 | gateways := r.state.MatchingGatewaysByTargetSource(source.ObjectKey())
47 | for _, g := range gateways {
48 | _ = r.controller.EnqueueKey(resources.NewClusterKeyForObject(source.Cluster(), g.ForGroupKind(GroupKindGateway)))
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/controller/source/ingress/controller.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package ingress
8 |
9 | import (
10 | "github.com/gardener/controller-manager-library/pkg/resources"
11 |
12 | "github.com/gardener/cert-management/pkg/cert/source"
13 | ctrl "github.com/gardener/cert-management/pkg/controller"
14 | )
15 |
16 | // MainResource is the GroupKind for the ingress resource.
17 | var MainResource = resources.NewGroupKind("networking.k8s.io", "Ingress")
18 |
19 | func init() {
20 | source.CertSourceController(source.NewCertSourceTypeForCreator("ingress-cert", MainResource, NewIngressSource), nil).
21 | FinalizerDomain("cert.gardener.cloud").
22 | RequireLease(ctrl.SourceCluster).
23 | MustRegister(ctrl.ControllerGroupSource)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/controller/source/ingress/handler.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package ingress
8 |
9 | import (
10 | "fmt"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/controllermanager/controller"
13 | "github.com/gardener/controller-manager-library/pkg/logger"
14 | "github.com/gardener/controller-manager-library/pkg/resources"
15 | networkingv1 "k8s.io/api/networking/v1"
16 | networkingv1beta1 "k8s.io/api/networking/v1beta1"
17 |
18 | "github.com/gardener/cert-management/pkg/cert/source"
19 | ctrlsource "github.com/gardener/cert-management/pkg/controller/source"
20 | )
21 |
22 | // CIngressSource is the ingress CertSource
23 | type CIngressSource struct {
24 | source.DefaultCertSource
25 | }
26 |
27 | // NewIngressSource creates a CertSource
28 | func NewIngressSource(_ controller.Interface) (source.CertSource, error) {
29 | return &CIngressSource{DefaultCertSource: source.DefaultCertSource{Events: map[resources.ClusterObjectKey]map[string]string{}}}, nil
30 | }
31 |
32 | // GetCertsInfo returns CertsInfo for the given object
33 | func (s *CIngressSource) GetCertsInfo(logger logger.LogContext, objData resources.ObjectData) (*source.CertsInfo, error) {
34 | return ctrlsource.GetCertsInfoByCollector(logger, objData, func(data resources.ObjectData) ([]*ctrlsource.TLSData, error) {
35 | var array []*ctrlsource.TLSData
36 | switch data := data.(type) {
37 | case *networkingv1beta1.Ingress:
38 | if data.Spec.TLS == nil {
39 | return nil, nil
40 | }
41 | for _, item := range data.Spec.TLS {
42 | array = append(array, &ctrlsource.TLSData{
43 | SecretName: item.SecretName,
44 | Hosts: item.Hosts,
45 | })
46 | }
47 | return array, nil
48 | case *networkingv1.Ingress:
49 | if data.Spec.TLS == nil {
50 | return nil, nil
51 | }
52 | for _, item := range data.Spec.TLS {
53 | array = append(array, &ctrlsource.TLSData{
54 | SecretName: item.SecretName,
55 | Hosts: item.Hosts,
56 | })
57 | }
58 | return array, nil
59 | default:
60 | return nil, fmt.Errorf("unexpected ingress type: %#v", data)
61 | }
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/controller/source/service/controller.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package service
8 |
9 | import (
10 | "github.com/gardener/controller-manager-library/pkg/resources"
11 |
12 | "github.com/gardener/cert-management/pkg/cert/source"
13 | ctrl "github.com/gardener/cert-management/pkg/controller"
14 | )
15 |
16 | // MainResource is the service resource.
17 | var MainResource = resources.NewGroupKind("core", "Service")
18 |
19 | func init() {
20 | source.CertSourceController(source.NewCertSourceTypeForExtractor("service-cert", MainResource, GetSecretName), nil).
21 | FinalizerDomain("cert.gardener.cloud").
22 | RequireLease(ctrl.SourceCluster).
23 | MustRegister(ctrl.ControllerGroupSource)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/controller/source/service/handler.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package service
8 |
9 | import (
10 | "fmt"
11 |
12 | "github.com/gardener/controller-manager-library/pkg/logger"
13 | "github.com/gardener/controller-manager-library/pkg/resources"
14 | api "k8s.io/api/core/v1"
15 | "k8s.io/apimachinery/pkg/types"
16 |
17 | "github.com/gardener/cert-management/pkg/cert/source"
18 | )
19 |
20 | // GetSecretName finds the secret name from the object annotations
21 | func GetSecretName(_ logger.LogContext, objData resources.ObjectData) (types.NamespacedName, error) {
22 | var zero types.NamespacedName
23 | svc := objData.(*api.Service)
24 | if svc.Spec.Type != api.ServiceTypeLoadBalancer {
25 | return zero, fmt.Errorf("service is not of type LoadBalancer")
26 | }
27 |
28 | secretName, _ := resources.GetAnnotation(svc, source.AnnotSecretname)
29 | if secretName == "" {
30 | return zero, fmt.Errorf("missing annotation '%s'", source.AnnotSecretname)
31 | }
32 | secretNamespace, _ := resources.GetAnnotation(svc, source.AnnotSecretNamespace)
33 | if secretNamespace == "" {
34 | secretNamespace = svc.GetNamespace()
35 | }
36 | return types.NamespacedName{Namespace: secretNamespace, Name: secretName}, nil
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/shared/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - github.com/gardener/cert-management/pkg/apis
5 | - github.com/gardener/cert-management/pkg/shared
6 | - selectorRegexp: github[.]com/gardener/controller-manager-library
7 | forbiddenPrefixes:
8 | - ''
9 |
--------------------------------------------------------------------------------
/pkg/shared/const.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package shared
8 |
9 | const (
10 | // AnnotDNSClass is the annotation for the dns class
11 | AnnotDNSClass = "dns.gardener.cloud/class"
12 | // AnnotACMEDNSChallenge is the annotation for marking DNSEntries for DNS challenges
13 | AnnotACMEDNSChallenge = "cert.gardener.cloud/acme-dns-challenge"
14 | )
15 |
--------------------------------------------------------------------------------
/pkg/shared/dns_utils_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package shared_test
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 |
11 | "github.com/gardener/cert-management/pkg/shared"
12 | )
13 |
14 | var _ = Describe("DnsUtils", func() {
15 | Describe("PreparePrecheckNameservers", func() {
16 | It("should return given nameservers if they are valid", func() {
17 | nameservers := []string{"1.1.1.1:53", "1.1.1.2:53"}
18 | Expect(shared.PreparePrecheckNameservers(nameservers)).To(Equal(nameservers))
19 | })
20 |
21 | It("should return given nameservers if they are valid and adds missing ports", func() {
22 | nameservers := []string{"1.1.1.1", "1.1.1.2"}
23 | nameserversExpected := []string{"1.1.1.1:53", "1.1.1.2:53"}
24 | Expect(shared.PreparePrecheckNameservers(nameservers)).To(Equal(nameserversExpected))
25 | })
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/pkg/shared/issuerinfo.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package shared
8 |
9 | const (
10 | // IssuerTypeACME is the issuer type ACME
11 | IssuerTypeACME = "acme"
12 | // IssuerTypeCA is the issuer type CA
13 | IssuerTypeCA = "ca"
14 | // IssuerTypeSelfSigned is the issuer type selfsigned
15 | IssuerTypeSelfSigned = "selfSigned"
16 | )
17 |
18 | // IssuerInfo provides name and type of an issuer
19 | type IssuerInfo struct {
20 | key IssuerKeyItf
21 | issuertype string
22 | }
23 |
24 | // NewACMEIssuerInfo creates info for an ACME issuer
25 | func NewACMEIssuerInfo(key IssuerKeyItf) IssuerInfo {
26 | return IssuerInfo{key: key, issuertype: IssuerTypeACME}
27 | }
28 |
29 | // NewCAIssuerInfo creates info for an CA issuer
30 | func NewCAIssuerInfo(key IssuerKeyItf) IssuerInfo {
31 | return IssuerInfo{key: key, issuertype: IssuerTypeCA}
32 | }
33 |
34 | // NewSelfSignedIssuerInfo creates info for a selfSigned issuer.
35 | func NewSelfSignedIssuerInfo(key IssuerKeyItf) IssuerInfo {
36 | return IssuerInfo{key: key, issuertype: IssuerTypeSelfSigned}
37 | }
38 |
39 | // Key returns the issuer key
40 | func (i *IssuerInfo) Key() IssuerKeyItf {
41 | return i.key
42 | }
43 |
44 | // IssuerType returns the issuer type
45 | func (i *IssuerInfo) IssuerType() string {
46 | return i.issuertype
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/shared/issuerkeyitf.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package shared
8 |
9 | // Cluster is an enum for default and target cluster
10 | type Cluster int
11 |
12 | const (
13 | // ClusterDefault is the default cluster (= secondary)
14 | ClusterDefault Cluster = iota
15 | // ClusterTarget is the target cluster (= primary)
16 | ClusterTarget
17 | )
18 |
19 | // IssuerKeyItf abstracts IssuerKey to simplify code reuse.
20 | type IssuerKeyItf interface {
21 | Name() string
22 | Namespace() string
23 | Cluster() Cluster
24 | Secondary() bool
25 | String() string
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/shared/legobridge/delegatingprovider_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package legobridge
6 |
7 | import (
8 | "errors"
9 | "time"
10 |
11 | . "github.com/onsi/ginkgo/v2"
12 | . "github.com/onsi/gomega"
13 | "k8s.io/apimachinery/pkg/util/wait"
14 | )
15 |
16 | var _ = Describe("Delegating Provider", func() {
17 | Describe("retryOnUpdateEroor", func() {
18 | BeforeEach(func() {
19 | // Override the default backoff settings to speed up the tests
20 | backoff = wait.Backoff{
21 | Steps: 4,
22 | Duration: 10 * time.Millisecond,
23 | Factor: 1.1,
24 | Jitter: 0.1,
25 | Cap: 100 * time.Millisecond,
26 | }
27 | })
28 |
29 | It("should succeed without error", func() {
30 | err := retryOnUpdateError(func() error {
31 | return nil
32 | })
33 | Expect(err).NotTo(HaveOccurred())
34 | })
35 |
36 | It("should succeed after a few retries if updateError occurs", func() {
37 | var i int
38 | err := retryOnUpdateError(func() error {
39 | i++
40 | if i < 3 {
41 | return &updateError{"failed"}
42 | }
43 | return nil
44 | })
45 | Expect(err).NotTo(HaveOccurred())
46 | })
47 |
48 | It("should fail if some other error occurs and return the error", func() {
49 | var i int
50 | err := retryOnUpdateError(func() error {
51 | i++
52 | if i < 3 {
53 | return errors.New("failed")
54 | }
55 | return nil
56 | })
57 | Expect(err).To(MatchError("failed"))
58 | })
59 |
60 | It("should fail after timeout", func() {
61 | err := retryOnUpdateError(func() error {
62 | return &updateError{"failed"}
63 | })
64 | Expect(err).To(HaveOccurred())
65 | })
66 | })
67 | })
68 |
--------------------------------------------------------------------------------
/pkg/shared/legobridge/keystores_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package legobridge_test
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 | corev1 "k8s.io/api/core/v1"
11 |
12 | "github.com/gardener/cert-management/pkg/shared/legobridge"
13 | )
14 |
15 | var _ = Describe("Pending", func() {
16 | Describe("RemoveKeystoresFromSecret", func() {
17 | It("should do nothing if secret is nil", func() {
18 | Expect(func() {
19 | legobridge.RemoveKeystoresFromSecret(nil)
20 | }).NotTo(Panic())
21 | })
22 |
23 | It("should do nothing if the data in the secret is nil", func() {
24 | secret := &corev1.Secret{}
25 | legobridge.RemoveKeystoresFromSecret(secret)
26 | Expect(secret.Data).To(BeNil())
27 | })
28 |
29 | It("should remove the keystore data from the secret", func() {
30 | secret := &corev1.Secret{
31 | Data: map[string][]byte{
32 | "Field1": []byte("Field1"),
33 | "Field2": []byte("Field2"),
34 | legobridge.PKCS12SecretKey: []byte(legobridge.PKCS12SecretKey),
35 | legobridge.PKCS12TruststoreKey: []byte(legobridge.PKCS12TruststoreKey),
36 | legobridge.JKSSecretKey: []byte(legobridge.JKSSecretKey),
37 | legobridge.JKSTruststoreKey: []byte(legobridge.JKSTruststoreKey),
38 | },
39 | }
40 | legobridge.RemoveKeystoresFromSecret(secret)
41 | Expect(secret.Data).To(Equal(map[string][]byte{
42 | "Field1": []byte("Field1"),
43 | "Field2": []byte("Field2"),
44 | }))
45 | })
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/pkg/shared/legobridge/legobridge_suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package legobridge_test
8 |
9 | import (
10 | "testing"
11 |
12 | . "github.com/onsi/ginkgo/v2"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | func TestCore(t *testing.T) {
17 | RegisterFailHandler(Fail)
18 | RunSpecs(t, "Legobridge Suite")
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/shared/legobridge/pending.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package legobridge
8 |
9 | import (
10 | "sync"
11 | "time"
12 |
13 | "sigs.k8s.io/controller-runtime/pkg/client"
14 | )
15 |
16 | // PendingCertificateRequests contains the pending certificate requests.
17 | type PendingCertificateRequests struct {
18 | lock sync.Mutex
19 | requests map[client.ObjectKey]time.Time
20 | }
21 |
22 | // NewPendingRequests creates a new PendingCertificateRequests
23 | func NewPendingRequests() *PendingCertificateRequests {
24 | return &PendingCertificateRequests{requests: map[client.ObjectKey]time.Time{}}
25 | }
26 |
27 | // Add adds a certificate object name.
28 | func (pr *PendingCertificateRequests) Add(name client.ObjectKey) {
29 | pr.lock.Lock()
30 | defer pr.lock.Unlock()
31 |
32 | pr.requests[name] = time.Now()
33 | }
34 |
35 | // Contains check if a certificate object name is pending.
36 | func (pr *PendingCertificateRequests) Contains(name client.ObjectKey) bool {
37 | pr.lock.Lock()
38 | defer pr.lock.Unlock()
39 |
40 | t, ok := pr.requests[name]
41 | return ok && !t.Add(5*time.Minute).Before(time.Now())
42 | }
43 |
44 | // Remove removes a certificate object name from the pending list.
45 | func (pr *PendingCertificateRequests) Remove(name client.ObjectKey) {
46 | pr.lock.Lock()
47 | defer pr.lock.Unlock()
48 |
49 | delete(pr.requests, name)
50 | }
51 |
52 | // PendingResults caches the ObtainOutput results.
53 | type PendingResults struct {
54 | lock sync.Mutex
55 | results map[client.ObjectKey]*ObtainOutput
56 | }
57 |
58 | // NewPendingResults creates a new PendingResults.
59 | func NewPendingResults() *PendingResults {
60 | return &PendingResults{results: map[client.ObjectKey]*ObtainOutput{}}
61 | }
62 |
63 | // Add adds a object name / ObtainOutput pair.
64 | func (pr *PendingResults) Add(name client.ObjectKey, result *ObtainOutput) {
65 | pr.lock.Lock()
66 | defer pr.lock.Unlock()
67 |
68 | pr.results[name] = result
69 | }
70 |
71 | // Peek fetches a pending result by object name.
72 | func (pr *PendingResults) Peek(name client.ObjectKey) *ObtainOutput {
73 | pr.lock.Lock()
74 | defer pr.lock.Unlock()
75 |
76 | return pr.results[name]
77 | }
78 |
79 | // Remove removes a pending result by object name.
80 | func (pr *PendingResults) Remove(name client.ObjectKey) {
81 | pr.lock.Lock()
82 | defer pr.lock.Unlock()
83 |
84 | delete(pr.results, name)
85 | }
86 |
--------------------------------------------------------------------------------
/pkg/shared/legobridge/pending_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package legobridge_test
6 |
7 | import (
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 |
12 | "github.com/gardener/cert-management/pkg/shared/legobridge"
13 | )
14 |
15 | var _ = Describe("Pending", func() {
16 | It("should add an object to PendingCertificateRequests and remove it afterwards", func() {
17 | name := client.ObjectKey{Namespace: "test", Name: "test-cert"}
18 | pendingRequests := legobridge.NewPendingRequests()
19 | By("Adding the Object")
20 | pendingRequests.Add(name)
21 | Expect(pendingRequests.Contains(name)).To(BeTrue())
22 |
23 | By("Removing the Object")
24 | pendingRequests.Remove(name)
25 | Expect(pendingRequests.Contains(name)).To(BeFalse())
26 | })
27 |
28 | It("should add an object to PendingResults and remove it afterwards", func() {
29 | name := client.ObjectKey{Namespace: "test", Name: "test-cert"}
30 | pendingResults := legobridge.NewPendingResults()
31 | result := &legobridge.ObtainOutput{}
32 |
33 | By("Adding the Object")
34 | pendingResults.Add(name, result)
35 | Expect(pendingResults.Peek(name)).To(Equal(result))
36 |
37 | By("Removing the Object")
38 | pendingResults.Remove(name)
39 | Expect(pendingResults.Peek(name)).To(BeNil())
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/pkg/shared/shared_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package shared_test
6 |
7 | import (
8 | "testing"
9 |
10 | . "github.com/onsi/ginkgo/v2"
11 | . "github.com/onsi/gomega"
12 | )
13 |
14 | func TestUtils(t *testing.T) {
15 | RegisterFailHandler(Fail)
16 | RunSpecs(t, "Shared Suite")
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/shared/utils_certificate.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package shared
8 |
9 | import (
10 | "crypto/x509"
11 | "encoding/pem"
12 | "fmt"
13 | )
14 |
15 | // ExtractCommonNameAnDNSNames extracts values from a CSR (Certificate Signing Request).
16 | func ExtractCommonNameAnDNSNames(csr []byte) (cn *string, san []string, err error) {
17 | certificateRequest, err := extractCertificateRequest(csr)
18 | if err != nil {
19 | err = fmt.Errorf("parsing CSR failed: %w", err)
20 | return
21 | }
22 | cnvalue := certificateRequest.Subject.CommonName
23 | if cnvalue != "" {
24 | cn = &cnvalue
25 | }
26 | san = certificateRequest.DNSNames[:]
27 | for _, ip := range certificateRequest.IPAddresses {
28 | san = append(san, ip.String())
29 | }
30 | return
31 | }
32 |
33 | func extractCertificateRequest(csr []byte) (*x509.CertificateRequest, error) {
34 | block, _ := pem.Decode(csr)
35 | if block == nil {
36 | return nil, fmt.Errorf("decoding CSR failed")
37 | }
38 | return x509.ParseCertificateRequest(block.Bytes)
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/shared/utils_certificate_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package shared_test
6 |
7 | import (
8 | "crypto/rand"
9 | "crypto/rsa"
10 | "crypto/x509"
11 | "crypto/x509/pkix"
12 | "encoding/pem"
13 | "net"
14 |
15 | . "github.com/onsi/ginkgo/v2"
16 | . "github.com/onsi/gomega"
17 |
18 | "github.com/gardener/cert-management/pkg/shared"
19 | )
20 |
21 | var _ = Describe("ExtractCommonNameAnDNSNames", func() {
22 | var (
23 | exampleCn string
24 | exampleSan []string
25 | exampleIPs []net.IP
26 | )
27 |
28 | BeforeEach(func() {
29 | exampleCn = "example.com"
30 | exampleSan = []string{"www.example.com", "example.org"}
31 | exampleIPs = []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("10.0.0.1")}
32 | })
33 |
34 | It("should extract cn, san, and IP addresses if Common Name (cn), Subject Alternative Name (san), and IP Addresses are set", func() {
35 | csr := _createCSR(exampleCn, exampleSan, exampleIPs)
36 | cn, san, err := shared.ExtractCommonNameAnDNSNames(csr)
37 | Expect(err).ToNot(HaveOccurred())
38 | Expect(*cn).To(Equal(exampleCn))
39 | Expect(san).To(ContainElements(append(exampleSan, "192.168.1.1", "10.0.0.1")))
40 | })
41 |
42 | It("should only return the san and IP addresses if Common Name is not set", func() {
43 | csr := _createCSR("", exampleSan, exampleIPs)
44 | cn, san, err := shared.ExtractCommonNameAnDNSNames(csr)
45 | Expect(err).ToNot(HaveOccurred())
46 | Expect(cn).To(BeNil())
47 | Expect(san).To(ContainElements(append(exampleSan, "192.168.1.1", "10.0.0.1")))
48 | })
49 |
50 | It("should fail with an error if CSR is not parseable", func() {
51 | csr := []byte("invalid csr")
52 | cn, san, err := shared.ExtractCommonNameAnDNSNames(csr)
53 | Expect(err).To(HaveOccurred())
54 | Expect(err).To(MatchError("parsing CSR failed: decoding CSR failed"))
55 | Expect(cn).To(BeNil())
56 | Expect(san).To(BeEmpty())
57 | })
58 | })
59 |
60 | func _createCSR(cn string, san []string, ips []net.IP) []byte {
61 | key, _ := rsa.GenerateKey(rand.Reader, 2048)
62 | template := &x509.CertificateRequest{
63 | Subject: pkix.Name{
64 | CommonName: cn,
65 | },
66 | DNSNames: san,
67 | IPAddresses: ips,
68 | }
69 | csr, _ := x509.CreateCertificateRequest(rand.Reader, template, key)
70 | return pem.EncodeToMemory(&pem.Block{
71 | Type: "CERTIFICATE REQUEST",
72 | Bytes: csr,
73 | })
74 | }
75 |
--------------------------------------------------------------------------------
/skaffold.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: skaffold/v4beta9
2 | kind: Config
3 | metadata:
4 | name: cert-management
5 | build:
6 | local:
7 | useBuildkit: true
8 | push: false
9 | artifacts:
10 | - image: local-skaffold/cert-controller-manager
11 | docker:
12 | dockerfile: Dockerfile
13 | cacheFrom:
14 | - local-skaffold/cert-controller-manager
15 | hooks:
16 | after:
17 | - command: [ "sh", "-c", "hack/kind/skaffold-after-hock.sh" ]
18 | manifests:
19 | rawYaml:
20 | - dev/manifests.yaml
21 | deploy:
22 | kubectl: {}
23 | profiles:
24 | - name: dnsrecords
25 | patches:
26 | - op: replace
27 | path: /manifests/rawYaml/0
28 | value: dev/manifests-dnsrecords.yaml
29 | - op: add
30 | path: /manifests/rawYaml/-
31 | value: test/functional/resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml
32 |
--------------------------------------------------------------------------------
/test/certman2/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - github.com/gardener/cert-management/pkg/apis
5 | - github.com/gardener/cert-management/pkg/certman2
6 | - github.com/gardener/cert-management/pkg/shared
7 | - selectorRegexp: github[.]com/gardener/controller-manager-library
8 | forbiddenPrefixes:
9 | - ''
10 |
--------------------------------------------------------------------------------
/test/certman2/integration/controller/issuer/issuer_suite_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package source_test
6 |
7 | import (
8 | "context"
9 | "path/filepath"
10 | "testing"
11 | "time"
12 |
13 | "github.com/gardener/gardener/pkg/logger"
14 | "github.com/go-logr/logr"
15 | . "github.com/onsi/ginkgo/v2"
16 | . "github.com/onsi/gomega"
17 | "k8s.io/apimachinery/pkg/runtime"
18 | "k8s.io/client-go/rest"
19 | "sigs.k8s.io/controller-runtime/pkg/client"
20 | "sigs.k8s.io/controller-runtime/pkg/envtest"
21 | logf "sigs.k8s.io/controller-runtime/pkg/log"
22 | "sigs.k8s.io/controller-runtime/pkg/log/zap"
23 |
24 | certmanclient "github.com/gardener/cert-management/pkg/certman2/client"
25 | )
26 |
27 | func TestIssuerController(t *testing.T) {
28 | RegisterFailHandler(Fail)
29 | RunSpecs(t, "Integrationtest suite for issuers")
30 | }
31 |
32 | const testID = "issuer-controller-test"
33 |
34 | var (
35 | ctx = context.Background()
36 | log logr.Logger
37 |
38 | restConfig *rest.Config
39 | testEnv *envtest.Environment
40 | testClient client.Client
41 |
42 | scheme *runtime.Scheme
43 | )
44 |
45 | var _ = BeforeSuite(func() {
46 | // a lot of CPU-intensive stuff is happening in this test, so to
47 | // prevent flakes we have to increase the timeout here manually
48 | SetDefaultEventuallyTimeout(5 * time.Second)
49 |
50 | logf.SetLogger(logger.MustNewZapLogger(logger.DebugLevel, logger.FormatJSON, zap.WriteTo(GinkgoWriter)))
51 | log = logf.Log.WithName(testID)
52 |
53 | By("Start test environment")
54 | testEnv = &envtest.Environment{
55 | CRDInstallOptions: envtest.CRDInstallOptions{
56 | Paths: []string{
57 | filepath.Join("..", "..", "..", "..", "..", "pkg", "certman2", "apis", "cert", "crd-cert.gardener.cloud_issuers.yaml"),
58 | },
59 | },
60 | ErrorIfCRDPathMissing: true,
61 | }
62 |
63 | var err error
64 | restConfig, err = testEnv.Start()
65 | Expect(err).NotTo(HaveOccurred())
66 | Expect(restConfig).NotTo(BeNil())
67 |
68 | DeferCleanup(func() {
69 | By("Stop test environment")
70 | Expect(testEnv.Stop()).To(Succeed())
71 | })
72 |
73 | By("Create test client")
74 | scheme = certmanclient.ClusterScheme
75 |
76 | testClient, err = client.New(restConfig, client.Options{Scheme: scheme})
77 | Expect(err).NotTo(HaveOccurred())
78 | })
79 |
--------------------------------------------------------------------------------
/test/functional/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/test/functional/functest-config-kind.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | issuers:
6 | - name: functest-kind
7 | type: acme
8 | autoRegistration: true
9 | server: https://acme.certman-support.svc.cluster.local/dir
10 | email: some.user@mydomain.com
11 | precheckNameservers:
12 | - 10.96.0.10:53
--------------------------------------------------------------------------------
/test/functional/functest-config.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | issuers:
6 | - name: functest-staging
7 | type: acme
8 | autoRegistration: true
9 | server: https://acme-staging-v02.api.letsencrypt.org/directory
10 | email: some.user@mydomain.com
11 |
--------------------------------------------------------------------------------
/test/functional/suite.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package functional
8 |
9 | import (
10 | "sync"
11 |
12 | "github.com/gardener/cert-management/test/functional/config"
13 | )
14 |
15 | var _config *config.Config
16 | var lock sync.Mutex
17 |
18 | func addIssuerTests(testFactory issuerTestFactory) {
19 | lock.Lock()
20 | defer lock.Unlock()
21 |
22 | if _config == nil {
23 | _config = config.InitConfig()
24 | }
25 |
26 | for _, issuer := range _config.Issuers {
27 | testFactory(_config, issuer)
28 | }
29 | }
30 |
31 | type issuerTestFactory func(config *config.Config, issuer *config.IssuerConfig)
32 |
--------------------------------------------------------------------------------
/test/functional/suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package functional
8 |
9 | import (
10 | "testing"
11 |
12 | . "github.com/onsi/ginkgo/v2"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | var _ = BeforeSuite(func() {
17 | })
18 |
19 | func TestFunctionalTests(t *testing.T) {
20 | RegisterFailHandler(Fail)
21 | RunSpecs(t, "Functional Test Suite for Cert Controller Manager")
22 | }
23 |
24 | var _ = AfterSuite(func() {
25 | })
26 |
--------------------------------------------------------------------------------
/test/integration/.import-restrictions:
--------------------------------------------------------------------------------
1 | rules:
2 | - selectorRegexp: github[.]com/gardener/cert-management
3 | allowedPrefixes:
4 | - ''
5 | forbiddenPrefixes:
6 | - github.com/gardener/cert-management/pkg/certman2
7 |
--------------------------------------------------------------------------------
/test/utils/logbridge.go:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors
2 | //
3 | // SPDX-License-Identifier: Apache-2.0
4 |
5 | package testutils
6 |
7 | import (
8 | "log"
9 | "strings"
10 |
11 | "github.com/go-logr/logr"
12 | )
13 |
14 | type logBridge struct {
15 | logr logr.Logger
16 | }
17 |
18 | func (logBridge *logBridge) Write(p []byte) (n int, err error) {
19 | message := strings.TrimSpace(string(p))
20 |
21 | logBridge.logr.Info(message)
22 |
23 | return len(p), nil
24 | }
25 |
26 | // NewLogBridge creates a new log.Logger that forwards all log messages to the given logr.Logger.
27 | func NewLogBridge(logr logr.Logger) *log.Logger {
28 | writer := &logBridge{logr}
29 |
30 | return log.New(writer, "", 0)
31 | }
32 |
--------------------------------------------------------------------------------