Sync Kubernetes cert-manager TLS Secrets to Aliyun CAS and bind certificates to Aliyun CDN domains.
The binary supports two adapter modes:
memory: local/dev mode with in-memory Kubernetes and Aliyun adapters.api: live mode using Kubernetes API and Aliyun RPC APIs.
Set mode in config (runtime.adapterMode) or env (CDN_CERT_SYNC_ADAPTER_MODE).
Default build (no Kubernetes client-go integration):
go build ./...Build the container image locally:
docker build -t aliyun-cdn-cert-sync:local .Build with Kubernetes client-go integration:
go mod tidy
go build -tags clientgo ./...Unit tests:
go test ./...Aliyun live integration tests are opt-in and excluded from normal test runs. To use them:
- Copy
internal/aliyun/testdata/aliyun-live.env.exampletointernal/aliyun/testdata/aliyun-live.env - Fill in real Aliyun credentials, endpoints, and a known certificate fingerprint
- Optionally set:
ALIYUN_LIVE_CERT_IDandALIYUN_LIVE_CDN_DOMAINfor the live CDN binding testALIYUN_LIVE_UPLOAD_CERT_PATHandALIYUN_LIVE_UPLOAD_KEY_PATHfor the live CAS upload+cleanup test
- Run:
go test -tags integration ./internal/aliyunOr use the Makefile shortcut:
make test-integrationThese integration tests make real Aliyun API calls. The CDN binding test can update the configured domain's certificate binding, and the upload test creates a real CAS certificate before deleting it during cleanup.
The CDN live binding test only runs if ALIYUN_LIVE_CERT_ID and ALIYUN_LIVE_CDN_DOMAIN are set. The upload+cleanup CAS test only runs if ALIYUN_LIVE_UPLOAD_CERT_PATH and ALIYUN_LIVE_UPLOAD_KEY_PATH are set.
GitHub Actions builds the container image for every pull request and every push to main using .github/workflows/image-build.yml.
- The workflow only validates image builds; it does not publish to any registry.
- Image metadata is deterministic and derived from Git refs and
github.sha. - No registry credentials or repository secrets are required for the build job.
Local prerequisites for container builds:
- Docker with BuildKit support enabled.
- Repository files present as checked in, including
Dockerfile,go.mod,cmd/,internal/, andconfigs/config.example.yaml.
Start from configs/config.example.yaml.
Required in api mode:
kubernetes.secretNamespacekubernetes.secretNamealiyun.regionaliyun.credentialSource(envsupported)aliyun.casEndpointaliyun.cdnEndpointaliyun.resourceGroupId(optional, but recommended when CAS certificates are scoped to a resource group)aliyun.cdnDomains(non-empty)sync.stateFile
When aliyun.credentialSource=env, set:
CDN_CERT_SYNC_ALIYUN_ACCESS_KEY_IDCDN_CERT_SYNC_ALIYUN_ACCESS_KEY_SECRETCDN_CERT_SYNC_ALIYUN_RESOURCE_GROUP_ID
Other supported overrides:
CDN_CERT_SYNC_K8S_SECRET_NAMESPACECDN_CERT_SYNC_K8S_SECRET_NAMECDN_CERT_SYNC_CDN_DOMAINS(comma-separated)CDN_CERT_SYNC_MAX_RETRIESCDN_CERT_SYNC_RETRY_BASE_MILLISCDN_CERT_SYNC_STATE_FILE
Local dry run:
go run ./cmd/cdn-cert-sync --adapter-mode memory --config ./configs/config.example.yamlLive run with in-cluster Kubernetes config:
go run -tags clientgo ./cmd/cdn-cert-sync --adapter-mode api --in-cluster=true --config ./configs/config.example.yamlLive run with kubeconfig:
go run -tags clientgo ./cmd/cdn-cert-sync --adapter-mode api --in-cluster=false --kubeconfig ~/.kube/config --config ./configs/config.example.yamlSample Kubernetes manifests live under deploy/.
deploy/cronjob.yamlruns the sync as a scheduledCronJob.deploy/rbac.yamlcreates the service account and Secret-read RBAC.deploy/configmap.yamlprovides a non-secret config file.deploy/secret.example.yamlshows the expected Aliyun credential Secret shape.
See deploy/README.md for deployment steps and customization notes.