8.5 KiB
8.5 KiB
cert-manager-stack
A wrapper Helm chart that bundles cert-manager with pre-configured Cloudflare DNS-01 solver and Let's Encrypt ClusterIssuer for GitOps deployments.
📋 Overview
This chart provides a production-ready cert-manager deployment by:
- Using cert-manager as a dependency (pristine upstream chart, easily upgradable)
- Adding custom resources (Cloudflare API Secret, Let's Encrypt ClusterIssuer)
- Single configuration file (
manifests/cert-manager-stack/values.yaml) - GitOps-friendly (works seamlessly with ArgoCD)
🏗️ Architecture
cert-manager-stack (wrapper chart)
├── Dependency: cert-manager (embedded in charts/cert-manager/)
│ ├── CRDs (Certificate, ClusterIssuer, etc.)
│ ├── cert-manager controller
│ ├── cert-manager webhook
│ └── cert-manager cainjector
└── Custom Resources (from wrapper templates)
├── Secret: cloudflare-api-token
└── ClusterIssuer: letsencrypt
📁 Files Structure
charts/cert-manager-stack/
├── Chart.yaml # Wrapper chart definition
├── values.yaml # Default values (DO NOT EDIT)
├── charts/ # Embedded dependencies
│ └── cert-manager/ # cert-manager chart
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
├── templates/
│ ├── _helpers.tpl # Template helpers
│ ├── cloudflare-api-token-secret.yaml # Cloudflare API Secret
│ ├── clusterissuer-letsencrypt.yaml # Let's Encrypt ClusterIssuer
│ └── NOTES.txt # Post-install notes
└── README.md # This file
manifests/cert-manager-stack/
└── values.yaml # ✏️ EDIT THIS FILE
⚙️ Configuration
Single Source of Truth
manifests/cert-manager-stack/values.yaml is the only file you need to edit.
Configuration Structure
# cert-manager upstream chart values
certManager:
enabled: true
crds:
enabled: true
prometheus:
enabled: false
# Cloudflare DNS provider
cloudflare:
enabled: true
apiToken: "YOUR_CLOUDFLARE_API_TOKEN"
secretName: cloudflare-api-token
namespace: cert-manager
# Let's Encrypt ClusterIssuer
clusterIssuer:
enabled: true
name: letsencrypt
email: dvirlabs@gmail.com
server: https://acme-v02.api.letsencrypt.org/directory
🚀 ArgoCD Integration
Create an ArgoCD Application:
# argocd-apps/cert-manager-stack.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cert-manager-stack
namespace: argocd
spec:
project: default
source:
repoURL: <your-git-repo>
targetRevision: HEAD
path: charts/cert-manager-stack
helm:
valueFiles:
- ../../manifests/cert-manager-stack/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: cert-manager
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
ArgoCD will:
- Read the wrapper chart from
charts/cert-manager-stack/ - Load cert-manager dependency from embedded
charts/cert-manager-stack/charts/cert-manager/ - Apply values from
manifests/cert-manager-stack/values.yaml - Deploy everything as a unified Helm release
📦 Installation
Manual Installation (for testing)
# Navigate to chart directory
cd charts/cert-manager-stack
# Update dependencies
helm dependency update
# Install
helm install cert-manager-stack . \
--namespace cert-manager \
--create-namespace \
--values ../../manifests/cert-manager-stack/values.yaml
GitOps Installation (recommended)
- Update your Cloudflare API token in
manifests/cert-manager-stack/values.yaml - Commit and push to Git
- ArgoCD will automatically sync and deploy
🔄 Upgrading cert-manager
To upgrade to a newer cert-manager version:
- Replace the embedded cert-manager chart in
charts/cert-manager-stack/charts/cert-manager/ - Edit
charts/cert-manager-stack/Chart.yaml - Update the dependency version to match:
dependencies: - name: cert-manager version: "v1.21.0" # Update this to match embedded chart version alias: certManager - Commit and push
- ArgoCD will handle the upgrade
✅ Why This Approach?
❌ What We're NOT Doing:
- Forking/modifying the upstream cert-manager chart
- Manual
kubectl applyfor Secret/ClusterIssuer - Embedding resources in cert-manager's values
- Using hacks like
extraObjects
✅ What We ARE Doing:
- Clean dependency management - cert-manager stays pristine
- Single Helm release - all resources managed together
- GitOps native - no manual steps
- Helm best practices - proper dependency and values structure
- Easy upgrades - just bump the version number
- Migration-ready - clean path to External Secrets/Vault
Benefits Over Modifying Upstream Chart:
- Upgradability: Can upgrade cert-manager without merge conflicts
- Clarity: Separation between upstream and custom resources
- Maintainability: Upstream chart bugs/fixes don't affect custom logic
- Reusability: Can apply same pattern to other charts
- Audibility: Clear distinction in Git history
📝 Usage Examples
Create a Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-app-tls
namespace: my-app
spec:
secretName: my-app-tls-secret
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- myapp.example.com
- "*.myapp.example.com"
Use with Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
🔐 Migrating to External Secrets
When ready to move from raw Secrets to External Secrets:
-
Create a new template
templates/cloudflare-external-secret.yaml:{{- if .Values.cloudflare.useExternalSecret }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: cloudflare-api-token namespace: cert-manager spec: secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: cloudflare-api-token data: - secretKey: api-token remoteRef: key: cloudflare/api-token {{- end }} -
Update
manifests/cert-manager-stack/values.yaml:cloudflare: enabled: false # Disable raw Secret useExternalSecret: true # Enable ExternalSecret secretName: cloudflare-api-token # Keep same name -
No changes needed to ClusterIssuer (references same secret name)
🔍 Troubleshooting
Check cert-manager logs
kubectl logs -n cert-manager deploy/cert-manager-stack-certManager
Check ClusterIssuer status
kubectl describe clusterissuer letsencrypt
kubectl get clusterissuer letsencrypt -o yaml
Check Certificate status
kubectl describe certificate my-app-tls -n my-app
kubectl get certificaterequest -n my-app
Verify Cloudflare secret
kubectl get secret cloudflare-api-token -n cert-manager
kubectl describe secret cloudflare-api-token -n cert-manager
Check ACME challenges
kubectl get challenges --all-namespaces
kubectl describe challenge <challenge-name> -n <namespace>
📚 References
- cert-manager Documentation
- Cloudflare DNS-01 Challenge
- Let's Encrypt Documentation
- Helm Dependencies
🤝 Contributing
To improve this wrapper chart:
- Edit files in
charts/cert-manager-stack/ - Test with
helm templateorhelm install --dry-run - Update
manifests/cert-manager-stack/values.yamlif needed - Commit and create a PR
📄 License
This wrapper chart follows the same license as cert-manager (Apache 2.0).