---
# System prepended metadata

title: Introduction to cert-manager for Kubernetes

---

# 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.
![](https://i.imgur.com/lvqE24E.png)

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

```
