# SSL/TLS Certificate Management This directory contains Kubernetes manifests for managing SSL/TLS certificates using cert-manager and Let's Encrypt. ## Components ### cert-manager - **Purpose**: Automated certificate management - **Namespace**: cert-manager - **Installation**: Via official cert-manager release ### ClusterIssuers - **letsencrypt-prod**: Production Let's Encrypt issuer - **letsencrypt-staging**: Staging Let's Encrypt issuer (for testing) ## Prerequisites 1. **Kubernetes cluster** with ingress controller (nginx-ingress recommended) 2. **cert-manager** installed in the cluster 3. **DNS records** pointing to your ingress controller 4. **Ingress controller** with HTTP-01 challenge support ## Installation ### 1. Install cert-manager ```bash # Install cert-manager CRDs kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.crds.yaml # Install cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml # Or using Helm helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set installCRDs=true ``` ### 2. Verify cert-manager Installation ```bash # Check cert-manager pods kubectl get pods -n cert-manager # Check ClusterIssuers kubectl get clusterissuers ``` ### 3. Configure Let's Encrypt Issuers **Important**: Update the email address in `letsencrypt-issuer.yaml`: ```yaml email: ops@veza.com # Change to your email ``` Then apply: ```bash kubectl apply -f k8s/certificates/letsencrypt-issuer.yaml ``` ### 4. Verify ClusterIssuers ```bash # Check ClusterIssuers status kubectl get clusterissuers # Describe to see details kubectl describe clusterissuer letsencrypt-prod ``` ## Usage ### Automatic Certificate via Ingress The easiest way is to use Ingress annotations. The ingress is already configured in `k8s/ingress.yaml`: ```yaml annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - app.veza.com - api.veza.com secretName: veza-tls ``` When you apply the ingress, cert-manager will automatically: 1. Create a Certificate resource 2. Request certificate from Let's Encrypt 3. Store it in the specified secret 4. Renew it automatically before expiration ### Manual Certificate Request You can also create a Certificate resource manually: ```bash kubectl apply -f k8s/certificates/certificate-example.yaml ``` ## Verification ### Check Certificate Status ```bash # List certificates kubectl get certificates -n veza-production # Describe certificate to see status kubectl describe certificate veza-tls -n veza-production # Check certificate events kubectl get events -n veza-production --field-selector involvedObject.name=veza-tls ``` ### Check Certificate Secret ```bash # List TLS secrets kubectl get secrets -n veza-production | grep tls # View certificate details (base64 encoded) kubectl get secret veza-tls -n veza-production -o yaml ``` ### Test Certificate ```bash # Port forward to ingress kubectl port-forward service/ingress-nginx-controller 8443:443 -n ingress-nginx # Test with curl curl -v https://localhost:8443 -k --resolve app.veza.com:8443:127.0.0.1 # Or check certificate expiration echo | openssl s_client -servername app.veza.com -connect app.veza.com:443 2>/dev/null | openssl x509 -noout -dates ``` ## Staging vs Production ### Use Staging for Testing When testing certificate issuance, use the staging issuer first: ```yaml annotations: cert-manager.io/cluster-issuer: letsencrypt-staging ``` Staging certificates: - Don't count against rate limits - Are not trusted by browsers (expected) - Useful for testing the setup ### Switch to Production Once staging works, switch to production: ```yaml annotations: cert-manager.io/cluster-issuer: letsencrypt-prod ``` ## Troubleshooting ### Certificate Not Issued 1. **Check cert-manager logs**: ```bash kubectl logs -n cert-manager deployment/cert-manager kubectl logs -n cert-manager deployment/cert-manager-webhook kubectl logs -n cert-manager deployment/cert-manager-cainjector ``` 2. **Check Certificate status**: ```bash kubectl describe certificate veza-tls -n veza-production ``` 3. **Check CertificateRequest**: ```bash kubectl get certificaterequests -n veza-production kubectl describe certificaterequest -n veza-production ``` 4. **Check Challenge**: ```bash kubectl get challenges -n veza-production kubectl describe challenge -n veza-production ``` ### Common Issues **Issue**: Certificate pending - **Cause**: DNS not pointing to ingress, or ingress controller not accessible - **Solution**: Verify DNS records and ingress controller accessibility **Issue**: Rate limit exceeded - **Cause**: Too many certificate requests to Let's Encrypt - **Solution**: Use staging issuer for testing, wait for rate limit reset **Issue**: HTTP-01 challenge failing - **Cause**: Ingress not accessible on port 80, or wrong ingress class - **Solution**: Verify ingress controller is accessible and annotation matches **Issue**: Certificate secret not created - **Cause**: Certificate request failed - **Solution**: Check certificate status and cert-manager logs ### Debug Commands ```bash # Check all cert-manager resources kubectl get certificates,certificaterequests,challenges -n veza-production # Check ClusterIssuer status kubectl describe clusterissuer letsencrypt-prod # Check ingress annotations kubectl get ingress veza-ingress -n veza-production -o yaml # Check cert-manager pods kubectl get pods -n cert-manager # View cert-manager controller logs kubectl logs -n cert-manager -l app=cert-manager --tail=100 ``` ## Certificate Renewal cert-manager automatically renews certificates before expiration (default: 30 days before expiry). ### Manual Renewal ```bash # Delete the certificate to force renewal kubectl delete certificate veza-tls -n veza-production # cert-manager will automatically recreate it ``` ### Check Expiration ```bash # View certificate expiration kubectl get certificate veza-tls -n veza-production -o jsonpath='{.status.notAfter}' # Or decode and view kubectl get secret veza-tls -n veza-production -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates ``` ## Best Practices 1. **Use staging first**: Test with staging issuer before production 2. **Monitor certificates**: Set up alerts for certificate expiration 3. **Backup secrets**: Backup certificate secrets for disaster recovery 4. **Multiple domains**: Use wildcard certificates for multiple subdomains 5. **DNS-01 for wildcards**: Use DNS-01 challenge for wildcard certificates ## Additional Resources - [cert-manager Documentation](https://cert-manager.io/docs/) - [Let's Encrypt Documentation](https://letsencrypt.org/docs/) - [cert-manager GitHub](https://github.com/cert-manager/cert-manager)