0. Entrée

There is an amazing post on software architecture named The Architecture Behind A One-Person Tech Startup which you should check it out. I’m almost using same tech architecture for my projects.

There is one thing however that I want to tweak:

Since Cloudflare proxying all external traffic to my Load Balancer(Ingress controlled Load Balancer) with default browser side SSL ceritificate;

cloudflare-full-ssl

I only need Origin Server TLS certificate for a full SSL tunnel:

cloudflare-full-ssl

As Cloudflare mentioned in End-to-end HTTPS with Cloudflare - Part 3: SSL options, you can provide your self-signed certificate for Full mode or you can provide a Cloudflare Origin CA certificate (or a valid certificate purchased from a CA) to enable Full (strict) mode:

cloudflare-full-ssl

So I don’t need Let’s Encrypt to grant me SSL certificate for my site. Yes, I am grateful for their free ACME certificates but in our case it’s better to not load extra work to Lets’ Encrypt while Cloudflare is also a CA.

Note

There are 2 prerequisites in order to follow this article. Please ensure that they are already deployed into your cluster(s).

  • cert-manager - Automatically provision and manage TLS certificates in Kubernetes.
  • external-dns - Configure external DNS servers (AWS Route53, Google CloudDNS and others) for Kubernetes Ingresses and Services.

1. Origin CA

OK, We saw what we need but how we’re going to issue and add an Origin CA ceritificate to our origin server?

The default way is like this: Managing Cloudflare Origin CA certificates. Although it’s manual, rquires a lot effort and we need to regenerate and revoke our own certificates. We don’t like to use this way for our kubernetes clusters for sure.

1.0. origin-ca-issuer

The solution comes from Cloudflare team: origin-ca-issuer.

Origin CA Issuer is a cert-manager CertificateRequest controller for Cloudflare’s Origin CA feature. It handles above mentioned default way by itself.

1.1. Installing

Clone the origin-ca-issuer github repo and apply manifests to install Origin CA Issuer to your cluster:

$ kubectl apply \
    -f deploy/crds \
    -f deploy/rbac \
    -f deploy/manifests

By default the Origin CA Issuer will be deployed in the origin-ca-issuer namespace.

1.2. Adding an OriginIssuer

Get your Origin CA Key from API Token section of your Cloudflare dashboard and create a secret yaml for it:

$ kubectl create secret generic \
    origin-ca-key \
    -n default \
    --from-literal key=v1.0-FFFFFFF-FFFFFFFF \
    --dry-run=client \
    -o yaml > origin-ca-key.yaml

Change default namespace related to your need, then create issuer.yaml like below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# issuer.yaml
apiVersion: cert-manager.k8s.cloudflare.com/v1
kind: OriginIssuer
metadata:
  name: prod-issuer
  namespace: default
spec:
  requestType: OriginECC
  auth:
    serviceKeyRef:
      name: origin-ca-key
      key: key

Apply these manifests to your cluster:

$ kubectl apply \
    -f origin-ca-key.yaml \
    -f issuer.yaml

OriginIssuer resource will be updated once the Origin CA Issuer is ready.

After this creation you can deploy your Ingress resources. Below you can find an example Ingress resource manifest, update it according to your services:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# example-ingress.yaml
apiVersion: networking/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    # ssl certificate
    cert-manager.io/issuer: prod-issuer
    cert-manager.io/issuer-kind: OriginIssuer
    cert-manager.io/issuer-group: cert-manager.k8s.cloudflare.com
    # dns record
    external-dns.alpha.kubernetes.io/hostname: example.com
    external-dns.alpha.kubernetes.io/cloudflare-proxied: "true"
  name: example-ingress
  namespace: default
spec:
  rules:
    - host: example.com
      http:
        paths:
         - pathType: Prefix
           path: /
           backend:
              service:
                name: example-svc
                port:
                  number: 80
  tls:
    # specifying a host in the TLS section will tell cert-manager what
    # DNS SANs should be on the created certificate.
    - hosts:
        - example.com
      # cert-manager will create this secret
      secretName: example-tls

Apply this manifest to your cluster as well:

$ kubectl apply -f example-ingress.yaml

After this, now you should have:

  • DNS record for example.com proxied by Cloudflare
  • SSL certificate for your origin server signed by Cloudflare
  • Full (strict) mode enabled
  • Orange Cloud enabled

And you’re ready to go.

All done!


P.S:

  • I wish origin-ca-issuer had a Helm Repo so we can install it via helm install, and they had ClusterOriginIssuer instead of namespace scoped OriginIssuer. Fortunately there are related issues on the repo and they are already working on them.
  • How much I tried I couldn’t make origin-ca-issuer work by ingress-traefik. If someone achieves that I’ll be happy to learn.

Changelog

  • 2022-05-08 : Added prerequisites note. Fixed sub-headers. Added more clear explanations for Ingress resource.