# Introduction to cert-manager for Kubernetes
cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters and simplifies obtaining, renewing and using those certificates.

I am gonna be discussing the two examples of cert-manager which would be selfsigned and ACME.
**We need a Kubernetes cluster**
Lets create a Kubernetes cluster to play with using kind
`kind create cluster --name certmanager --image kindest/node:v1.19.1`
**Concepts**
It's important to understand the various concepts and new Kubernetes resources that cert-manager introduces.
Issuers [docs](https://cert-manager.io/docs/concepts/issuer/)
Certificate [docs](https://cert-manager.io/docs/concepts/certificate/)
CertificateRequests [docs](https://cert-manager.io/docs/concepts/certificaterequest/)
Orders and Challenges [docs](https://cert-manager.io/docs/concepts/acme-orders-challenges/)
**Installation**
You can find the latest release for cert-manager on their GitHub Releases page
```
# Get a container to work in
# mount our kubeconfig file and source code
docker run -it --rm -v ${HOME}:/root/ -v ${PWD}:/work -w /work --net host alpine sh
# install kubectl for mac
brew install kubectl
# or for Linux
apk add --no-cache curl
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
```
### test cluster access:
```
kubectl get nodes
NAME STATUS ROLES AGE VERSION
certmanager-control-plane Ready master 3m6s v1.19.1
# get cert-manager
cd cert-manager
curl -LO https://github.com/jetstack/cert-manager/releases/download/v1.10.0/cert-manager.yaml
mv cert-manager.yaml cert-manager-1.10.0.yaml
# install cert-manager
kubectl apply --validate=false -f cert-manager-1.10.0.yaml
```
## Cert Manager Resources
We can see our components deployed
```
kubectl -n cert-manager get all
NAME READY STATUS RESTARTS AGE
pod/cert-manager-86548b886-2b8x7 1/1 Running 0 77s
pod/cert-manager-cainjector-6d59c8d4f7-hrs2v 1/1 Running 0 77s
pod/cert-manager-webhook-578954cdd-tphpj 1/1 Running 0 77s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cert-manager ClusterIP 10.96.87.136 <none> 9402/TCP 77s
service/cert-manager-webhook ClusterIP 10.104.59.25 <none> 443/TCP 77s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/cert-manager 1/1 1 1 77s
deployment.apps/cert-manager-cainjector 1/1 1 1 77s
deployment.apps/cert-manager-webhook 1/1 1 1 77s
NAME DESIRED CURRENT READY AGE
replicaset.apps/cert-manager-86548b886 1 1 1 77s
replicaset.apps/cert-manager-cainjector-6d59c8d4f7 1 1 1 77s
replicaset.apps/cert-manager-webhook-578954cdd 1 1 1 77
```
## Test Certificate Issuing
Let's create some test certificates
./cert-manager/selfsigned/issuer.yaml
```
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-example
spec:
selfSigned: {}
```
./cert-manager/selfsigned/certificate.yaml
```
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-example
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
```
Now lets apply the issuer and certificate in our kubernetes cluster.
```
kubectl create ns cert-manager-example
kubectl apply -f ./selfsigned/issuer.yaml
kubectl apply -f ./selfsigned/certificate.yaml
kubectl describe certificate -n cert-manager-example
kubectl get secrets -n cert-manager-example
kubectl delete ns cert-manager-example
```
## Configuration
https://cert-manager.io/docs/configuration/
# Example 2: Creating a Basic ACME Issuer
./cert-manager/certificate.yaml
```
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-app
namespace: default
spec:
dnsNames:
- marcel.guru
secretName: example-app-tls
issuerRef:
name: letsencrypt-cluster-issuer
kind: ClusterIssuer
```
./cert-manager/ingress.yaml
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: example-app
spec:
tls:
- hosts:
- marcel.guru
secretName: example-app-tls
rules:
- host: marcel.guru
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
```
./cert-manager/cert-issuer-nginx-ingress.yaml
```
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@email.com
privateKeySecretRef:
name: letsencrypt-cluster-issuer-key
solvers:
- http01:
ingress:
class: nginx
```
## Ingress Controller
Let's deploy an Ingress controller:
```
kubectl create ns ingress-nginx
kubectl -n ingress-nginx apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.41.2/deploy/static/provider/cloud/deploy.yaml
kubectl -n ingress-nginx get pods
kubectl -n ingress-nginx --address 0.0.0.0 port-forward svc/ingress-nginx-controller 80
kubectl -n ingress-nginx --address 0.0.0.0 port-forward svc/ingress-nginx-controller 443
```
We should be able to access NGINX in the browser and see a 404 Not Found page: http://localhost/ This indicates there are no routes to / and the ingress controller is running
## Setup my DNS
In my container, I can get the public IP address of my computer by running a simple command:
`curl ifconfig.co`
I can log into my DNS provider and point my DNS A record to my IP.
Also setup my router to allow 80 and 443 to come to my PC
If you are running in the cloud, your Ingress controller and Cloud provider will give you a public IP and you can point your DNS to that accordingly.
Create Let's Encrypt Issuer for our cluster
We create a ClusterIssuer that allows us to issue certs in any namespace
```
kubectl apply -f cert-issuer-nginx-ingress.yaml
# check the issuer
kubectl describe clusterissuer letsencrypt-cluster-issuer
```
## Deploy a pod that uses SSL
./deployments/deployment.yaml
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-deploy
labels:
app: example-app
test: test
spec:
selector:
matchLabels:
app: example-app
replicas: 2
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: example-app
image: aimvector/python:1.0.4
imagePullPolicy: Always
ports:
- containerPort: 5000
```
./services/service.yaml
```
apiVersion: v1
kind: Service
metadata:
name: example-service
labels:
app: example-app
spec:
type: LoadBalancer
selector:
app: example-app
ports:
- protocol: TCP
name: http
port: 80
targetPort: 5000
```
```
kubectl apply -f deployments/deployment.yaml
kubectl apply -f services/service.yaml
kubectl get pods
# deploy an ingress route
kubectl apply -f ingress.yaml
Issue Certificate
kubectl apply -f certificate.yaml
# check the cert has been issued
kubectl describe certificate example-app
```
```
# TLS created as a secret
kubectl get secrets
NAME TYPE DATA AGE
example-app-tls kubernetes.io/tls 2 84m
```