Deploying the Nginx Ingress in On-prem Kubernetes for bare-metal and EC2 instance(Standalone) with Letz Encrypt(Auto-Renew certificate).

Introduction

Kubernetes Ingresses allow you to flexibly route traffic from outside your Kubernetes cluster to Services inside of your cluster. This is accomplished using Ingress Resources, which define rules for routing HTTP and HTTPS traffic to Kubernetes Services, and Ingress Controllers, which implement the rules by load balancing traffic and routing it to the appropriate backend Services.

In this guide, we’ll set up the Kubernetes-maintained Nginx Ingress Controller(hostNetwork configuration), and create some Ingress Resources to route traffic to several dummy backend services. Once we’ve set up the Ingress, we’ll install a cert-manager into our cluster to manage and provision TLS certificates for encrypting HTTP traffic to the Ingress.

This will make sure zero cost for your certificate and less maintenance

Pre-requisites

Before we get started installing the Ingress controller

* Ensure you have Kubernetes 1.15+ cluster on bare-metal or in ec2 instance.

* The wget command-line utility installed on your local machine. You can install wget using the package manager built into your operating system.

Installation and configuration

Clone the project locally to your Linux machine.

git clone git@github.com:ahamedyaserarafath/zerocost-kube-https.git

Step 1 Setting Up Dummy Backend Services(Change it according to your service)

We’ll first create and roll out dummy echo Services to which we’ll route external traffic using the Ingress.

kubectl apply -f http_ingress.yaml
kubectl get svc echo1

Verify that the Service started correctly by confirming that it has a ClusterIP, the internal IP on which the Service is exposed.

Output
service/echo1 created
deployment.apps/echo1 created

Now that our dummy echo web services are up and running, we can move on to rolling out the Nginx Ingress Controller.

Step 2 – Setting Up the Kubernetes Nginx Ingress Controller with HostNetwork

In this step, we’ll roll out v0.43.0 of the Kubernetes-maintained Nginx Ingress Controller. Note that there are several Nginx Ingress Controllers; the Kubernetes community maintains the one used in this guide and Nginx Inc. maintains Kubernetes-ingress. The instructions in this tutorial are based on those from the official Kubernetes Nginx Ingress Controller Installation Guide.

In this ingress controller, we added host network is enabled by default

kubectl apply -f ingress_controler.yaml

We use apply here so that in the future we can incrementally apply changes to the Ingress Controller objects instead of completely overwriting them. To learn more about applying, consult Managing Resources from the official Kubernetes docs.

You should see the following output:

Output
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created

Confirm that the Ingress Controller Pods have started:

kubectl get pods -n ingress-nginx \
  -l app.kubernetes.io/name=ingress-nginx --watchOutput
NAME                                       READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-xtbbt       0/1     Completed   0          32s
ingress-nginx-admission-patch-wb8mk        0/1     Completed   1          32s
ingress-nginx-controller-9b98b6577-xrq4k   1/1     Running     0          40s

Hit CTRL+C to return to your prompt.

Now, confirm that the NodePort was successfully created by fetching the Service details with kubectl:

kubectl get svc --namespace=ingress-nginxOutput
NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.109.108.65   <none>        80:30228/TCP,443:30028/TCP   65s
ingress-nginx-controller-admission   ClusterIP   10.103.80.152   <none>        443/TCP                      65s

Step 3 – Setting Up the Kubernetes Nginx Ingress Resource(HTTP)

Let’s begin by creating a minimal Ingress Resource to route traffic directed at a given subdomain to a corresponding backend Service.

Here, we’ve specified that we’d like to create an Ingress Resource called sample-ingress, and route traffic based on the Host header. An HTTP request Host header specifies the domain name of the target server.

Sample for your reference

  rules:
    - host: app.sample.com
      http:
        paths:

to

  rules:
    - host: <your_domain>
      http:
        paths:

You can now create the Ingress using kubectl:

kubectl apply -f http_ingress.yaml

You’ll see the following output confirming the Ingress creation:

Output
ingress.networking.k8s.io/sample-ingress created

Note: Wait for few mins till the external IP is assigned to ingress, you can check that by the below commands

kubectl get ingress

You’ll see the following output confirming the Ingress created with Nodeport IP:

NAME             CLASS    HOSTS            ADDRESS       PORTS   AGE
sample-ingress   <none>   app.sample.com   192.168.0.7   80      5s

To test the Ingress, navigate to your DNS management service and create A records for app.sample.com(<your_domain>) pointing to the Node IP(In case of EC2 instance open the 80 Port)

Once you’ve created the necessary app.sample.com(<your_domain>) DNS records, you can test the Ingress Controller and Resource you’ve created using the curl command-line utility.

From your local machine, curl the echo1 Service:

curl http://app.sample.com

You should get the following response from the echo1 service:

Output
echo1

From your local machine, curl the echo1 Service if the domain is not mapped:

curl -kv http://localhost -H 'Host: app.sample.com'

You should get the following response from the echo1 service:

Output
* Rebuilt URL to: localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: app.sample.com
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 30 Jan 2021 18:13:51 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 6
< Connection: keep-alive
< X-App-Name: http-echo
< X-App-Version: 0.2.3
<
echo1

Step 4 — Installing and Configuring Cert-Manager

In this step, we’ll install v0.16.1 of cert-manager into our cluster. cert-manager is a Kubernetes add-on that provisions TLS certificates from Let’s Encrypt and other certificate authorities (CAs) and manages their lifecycles. Certificates can be automatically requested and configured by annotating Ingress Resources, appending a TLS section to the Ingress spec, and configuring one or more Issuers or ClusterIssuers to specify your preferred certificate authority. To learn more about Issuer and ClusterIssuer objects, consult the official cert-manager documentation on Issuers.

Install cert-manager and its Custom Resource Definitions (CRDs) like Issuers and ClusterIssuers by following the official installation instructions. Note that a namespace called cert-manager will be created into which the cert-manager objects will be created:

kubectl apply --validate=false -f cert-manager.yaml
or 
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.16.1/cert-manager.yaml

You should see the following output:

Output
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
. . .
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created

To verify our installation, check the cert-manager Namespace for running pods:

kubectl get pods --namespace cert-managerOutput

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-271ad6d964-hb512              1/1     Running   0          20s
cert-manager-cainjector-1eeee9dd7c-f46gf   1/1     Running   0          90s
cert-manager-webhook-589b9w9ddd-wf9l6      1/1     Running   0          98s

This indicates that the cert-manager installation succeeded.

Before we begin issuing certificates for our echo1.example.com and echo2.example.com domains, we need to create an Issuer, which specifies the certificate authority from which signed x509 certificates can be obtained. In this guide, we’ll use the Let’s Encrypt certificate authority, which provides free TLS certificates and offers both a staging server for testing your certificate configuration and a production server for rolling out verifiable TLS certificates.

We then specify an email address to register the certificate and create a Kubernetes Secret called letsencrypt-prod to store the ACME account’s private key. We also use the HTTP-01 challenge mechanism. To learn more about these parameters, consult the official cert-manager documentation on Issuers.

Note: If you reached these steps make sure your domain is mapped to NodePort otherwise certification will not be issued by letsencrypt and make sure 80 and 443 port is open.

Open a file called prod_issuer.yaml in your favorite editor and edit the email id:

  ...
    email: <your_email_address_here>
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
  ...

Roll out this Issuer using kubectl:

kubectl create -f prod_issuer.yaml

You should see the following output:

Output
clusterissuer.cert-manager.io/letsencrypt-prod created

Now that we’ve created our Let’s Encrypt staging and prod ClusterIssuers, we’re ready to modify the Ingress Resource we created above and enable TLS encryption for the echo1.example.com(<your_domain>) paths.

Step 5 — Issuing Production Let’s Encrypt Certificates

To issue a staging TLS certificate for our domains, we’ll annotate https_ingress_letzencrypt.yaml with the ClusterIssuer created in Step 4. This will use ingress-shim to automatically create and issue certificates for the domains specified in the Ingress manifest.

Open up echo_ingress.yaml in your favorite editor:

...
  - hosts:
    - app.sample.com
    secretName: app-secret
  rules:
    - host: app.sample.com
      http:
...

to

...
  - hosts:
    - <your_domain>
    secretName: app-secret
  rules:
    - host: <your_domain>
      http:
...

We also add a tls block to specify the hosts for which we want to acquire certificates and specify a secretName. This secret will contain the TLS private key and issued certificate. Be sure to swap out app.sample.com with the domain for which you’ve created DNS records.

When you’re done making changes, save and close the file.

We’ll now push this update to the existing Ingress object using kubectl apply:

kubectl apply -f echo_ingress.yaml

You should see the following output:

Output
ingress.networking.k8s.io/sample-ingress configured

You can use kubectl describe to track the state of the Ingress changes you’ve just applied:

kubectl describe ingress

Once the certificate has been successfully created, you can run a describe on it to further confirm its successful creation:

kubectl describe certificate

Once you see the following output, the certificate has been issued successfully:

Output
  Normal  Issuing    28s                 cert-manager  Issuing certificate as Secret was previously issued by ClusterIssuer.cert-manager.io/letsencrypt-prod
  Normal  Reused     28s                 cert-manager  Reusing private key stored in existing Secret resource "app-secret"
  Normal  Requested  28s                 cert-manager  Created new CertificateRequest resource "app-secret-90agn"
  Normal  Issuing    2s (x2 over 4m52s)  cert-manager  The certificate has been successfully issued

We’ll now perform a test using curl to verify that HTTPS is working correctly:

curl http://app.sample.com
or 
curl -kv http://localhost -H 'Host: app.sample.com'

You should see the following:

Output
<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx/1.15.9</center>
</body>
</html>

This indicates that HTTP requests are being redirected to use HTTPS.

Run curl on HTTPS:

curl https://app.sample.com
or
curl -kv https://localhost -H 'Host: app.sample.com'

You should now see the following output:

Output
echo1

You can run the previous command with the verbose -v flag to dig deeper into the certificate handshake and to verify the certificate information.

At this point, you’ve successfully configured HTTPS using a Let’s Encrypt certificate for your Nginx Ingress.

Conclusion

In this guide, you set up an Nginx Ingress to load balance and route external requests to backend Services inside of your On-prem/EC2 Kubernetes cluster.

You also secured the Ingress by installing the cert-manager certificate provisioner and setting up a Let’s Encrypt certificate

There are many alternatives to the Nginx Ingress Controller. To learn more, consult Ingress controllers from the official Kubernetes documentation.

https://github.com/ahamedyaserarafath/zerocost-kube-https

GitHub Link, Please feel free to fork and use it

Categorized in:

Tagged in:

,