This guide explains how to use the mTLS Certificate Operator to manage tenant certificates and implement mTLS authentication in your applications.
- Managing Tenants
- Certificate Management
- Implementing mTLS Authentication
- Testing and Verification
- Troubleshooting
Create a tenant by applying a Tenant custom resource:
apiVersion: mtls.invoisight.com/v1
kind: Tenant
metadata:
name: example-tenant
spec:
name: example-tenant
revoked: falseThis will automatically:
- Generate an intermediate CA certificate
- Create a client certificate
- Update the CA chain
To revoke a tenant's certificates:
kubectl patch tenant example-tenant --type=merge -p '{"spec":{"revoked":true}}'To unrevoke a previously revoked tenant:
kubectl patch tenant example-tenant --type=merge -p '{"spec":{"revoked":false}}'kubectl delete tenant example-tenantView tenant status:
kubectl get tenants
# Detailed view
kubectl describe tenant example-tenantStatus fields:
state: Current state (Creating, Active, Revoked, Failed)isRevoked: Revocation statusmessage: Additional status information
Certificates are stored in Kubernetes secrets:
- Intermediate CA:
<tenant-name>-intermediate-ca-secret - Client Certificate:
<tenant-name>-client-cert-secret - CA Chain:
ca-chain-secret
Extract client certificates:
# Extract client certificate
kubectl get secret example-tenant-client-cert-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > client.crt
kubectl get secret example-tenant-client-cert-secret -o jsonpath='{.data.tls\.key}' | base64 -d > client.key
# Extract CA chain
kubectl get secret ca-chain-secret -o jsonpath='{.data.ca\.crt}' | base64 -d > ca-chain.crtVerify a certificate against the CA chain:
openssl verify -CAfile ca-chain.crt client.crtExample NGINX ingress configuration with mTLS:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-chain-secret"
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
nginx.ingress.kubernetes.io/auth-tls-verify-depth: "3"
nginx.ingress.kubernetes.io/auth-tls-set-header: "True"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-Org-Id $ssl_client_s_dn_cn;
spec:
# ... rest of ingress configurationUsing curl:
curl --cert client.crt \
--key client.key \
--cacert ca-chain.crt \
https://your-service.example.comUsing Python requests:
import requests
response = requests.get(
'https://your-service.example.com',
cert=('client.crt', 'client.key'),
verify='ca-chain.crt'
)The repository includes a comprehensive test script:
./test/e2e/test-mtls.shAvailable commands:
./test/e2e/test-mtls.sh create # Create test tenants
./test/e2e/test-mtls.sh extract # Extract certificates
./test/e2e/test-mtls.sh test # Test tenant access
./test/e2e/test-mtls.sh setup # Full setup-
Deploy the test server:
kubectl apply -f config/samples/test-server/
-
Create a tenant and test:
# Create tenant kubectl apply -f config/samples/mtls_v1_tenant.yaml # Extract certificates kubectl get secret tenant1-client-cert-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > client.crt kubectl get secret tenant1-client-cert-secret -o jsonpath='{.data.tls\.key}' | base64 -d > client.key kubectl get secret ca-chain-secret -o jsonpath='{.data.ca\.crt}' | base64 -d > ca-chain.crt # Test curl --cert client.crt --key client.key --cacert ca-chain.crt https://myserver.invoisight.com
-
Certificate Not Being Issued
- Check cert-manager logs
- Verify root CA exists and is ready
- Check tenant status
-
mTLS Authentication Failures
- Verify CA chain is up to date
- Check certificate revocation status
- Verify ingress configuration
-
Client Connection Issues
- Verify certificate paths
- Check certificate permissions
- Validate CA chain
-
Check operator logs:
kubectl logs -l app=tenant-operator
-
Check tenant status:
kubectl describe tenant <tenant-name>
-
Verify certificate chain:
openssl verify -CAfile ca-chain.crt client.crt
-
Check certificate details:
openssl x509 -in client.crt -text -noout
If you encounter issues:
- Check this documentation for similar issues
- Review operator logs
- Submit an issue on GitHub with:
- Description of the problem
- Relevant logs
- Steps to reproduce
- Environment details