{"id":902,"date":"2022-03-16T14:59:48","date_gmt":"2022-03-16T14:59:48","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=902"},"modified":"2022-03-16T14:59:48","modified_gmt":"2022-03-16T14:59:48","slug":"configure-ingress-tls-kubernetes","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=902","title":{"rendered":"How To Configure Ingress TLS\/SSL Certificates in Kubernetes"},"content":{"rendered":"<p>In this blog, you will learn how to configure ingress TLS certificates for Kubernetes Ingress resources.<\/p>\n<p>This blog is based on an actual demo done using <code>demo.mlopshub.com<\/code> public DNS and its self-signed certificate. If you do not have a domain name, you can use the workstation host file for DNS resolution or the curl resolve command.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note<\/strong><\/b>: SSL &amp; TLS are the same. SSL is the old name. TLS is the updated version of SSL. Dont get confused \ud83d\ude42<\/div>\n<\/div>\n<h2 id=\"prerequisites-and-assumptions\">Prerequisites and Assumptions<\/h2>\n<p>For this blog, the assumption is you have a working ingress controller setup, and you want to configure TLS for your ingress resource.<\/p>\n<p>This blog is part of the Kubernetes Ingress series. If you do not have an ingress controllers setup or want to understand Kubernetes ingress concepts in detail, please go through the following blogs first.<\/p>\n<ol>\n<li><a href=\"https:\/\/devopscube.com\/kubernetes-ingress-tutorial\/\" rel=\"noreferrer noopener\">Kubernetes Ingress Tutorial <\/a>&#8211; Covers all Ingress concepts<\/li>\n<li><a href=\"https:\/\/devopscube.com\/setup-ingress-kubernetes-nginx-controller\/\" rel=\"noreferrer noopener\">Setup Nginx Kubernetes Ingress controller<\/a> &#8211; Detailed guide on ingress controller<\/li>\n<\/ol>\n<h2 id=\"obtaining-kubernetes-ingress-ssltls-certificates\">Obtaining Kubernetes Ingress SSL\/TLS Certificates<\/h2>\n<p>The basic requirement for ingress TLS is a <strong>TLS\/SSL certificate<\/strong>. You can obtain these certificates in the following ways.<\/p>\n<ol>\n<li><strong>Self-Signed Certificates:<\/strong> TLS certificate created and signed by our own Certificage Authority. It is great optionfor development environments where you can share the rootCA with the team so that browsers can trust the certificate. Check out <a href=\"https:\/\/devopscube.com\/create-self-signed-certificates-openssl\/\" rel=\"noreferrer noopener\">create self-signed certificate<\/a> blog to create your own certificates.<\/li>\n<li><strong>Purchase an SSL Certificate:<\/strong> You need to buy an SSL certificate from a well-known certificate authority trusted by browsers &amp; operating systems for production use cases. Check out the <a href=\"https:\/\/devopscube.com\/recommends\/top-ssl-companies\/\" rel=\"noreferrer noopener\">top SSL Providers<\/a> for more information.<\/li>\n<li><strong>Use Letsencrpt Certificate:<\/strong> <a href=\"https:\/\/letsencrypt.org\/?ref=devopscube.com\" rel=\"noreferrer noopener\">Letsencrypt<\/a> is a non-profit trusted certificate authority that provides free TLS certificates.<\/li>\n<\/ol>\n<p>Every SSL certificate comes with an expiry date. So you need to rotate the certificate before it expires. For example, Letsecrypt certificates expire every three months. I will talk about automated certificate rotation towards the end of the article.<\/p>\n<p>Also, if you are working on an internal application, most organizations have their own PKI infrastructure for providing SSL certificates for internal applications. You can request the network\/security team to provide the certificates.<\/p>\n<h2 id=\"how-does-ingress-tlsssl-work\">How Does Ingress TLS\/SSL Work?<\/h2>\n<p>Adding TLS to ingress is pretty simple. All you have to do is,<\/p>\n<ol>\n<li>Create a Kubernetes secret with <code>server.crt<\/code> certificate and server.key private key file.<\/li>\n<li>Add the TLS block to the ingress resource with the exact hostname used to generate cert that matches the TLS certificate.<\/li>\n<\/ol>\n<p>SSL is<strong> handled by the ingress controller, not the ingress resource<\/strong>. Meaning, when you add TLS certificates to the ingress resource as a kubernetes secret, the ingress controller access it and makes it part of its configuration.<\/p>\n<p>For example, in the Nginx controller, the <strong>SSL certificates are dynamically handled<\/strong> by the following block in <code>nginx.conf<\/code><\/p>\n<pre><code>ssl_certificate_by_lua_block {\n\t\t\tcertificate.call()\n\t\t}<\/code><\/pre>\n<p>The following diagram shows the high-level ingress TLS workflow.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/ingress-tls-1-1.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"777\" height=\"870\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/ingress-tls-1-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/ingress-tls-1-1.png 777w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"configure-ingress-tlsssl-certificates\">Configure Ingress TLS\/SSL Certificates<\/h2>\n<p>Let&#8217;s look a the steps in configuring TLS in ingress.<\/p>\n<h4 id=\"deploy-a-test-application\">Deploy a Test Application<\/h4>\n<p>Let&#8217;s begin by deploying a sample application. We will use this application to test our ingress TLS.<\/p>\n<p>Create a dev namespace.<\/p>\n<pre><code>kubectl create ns dev<\/code><\/pre>\n<p>Save the following YAML as <code>hello-app.yaml<\/code>. It has a deployment and service object.<\/p>\n<pre><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: hello-app\n  namespace: dev\nspec:\n  selector:\n    matchLabels:\n      app: hello\n  replicas: 2\n  template:\n    metadata:\n      labels:\n        app: hello\n    spec:\n      containers:\n      - name: hello\n        image: \"gcr.io\/google-samples\/hello-app:2.0\"\n\n---\n\napiVersion: v1\nkind: Service\nmetadata:\n  name: hello-service\n  namespace: dev\n  labels:\n    app: hello\nspec:\n  type: ClusterIP\n  selector:\n    app: hello\n  ports:\n  - port: 80\n    targetPort: 8080\n    protocol: TCP\n<\/code><\/pre>\n<p>Deploy the test application.<\/p>\n<pre><code>kubectl apply -f hello-app.yaml <\/code><\/pre>\n<h4 id=\"create-a-kubernetes-tls-secret\">Create a Kubernetes TLS Secret<\/h4>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note<\/strong><\/b>: Here the assumption is you have the <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">server.crt<\/code> and <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">server.key<\/code> SSL files from a Certificate authority or your organization or self-signed.<\/div>\n<\/div>\n<p>The SSL certificate should be added as a Kubernetes secret. It will be then referred to the ingress resources TLS block.<\/p>\n<p>Let&#8217;s create a Kubernetes secret of type TLS with the <code>server.crt<\/code> and <code>server.key<\/code> files (SSL certificates). We are creating the secret in the dev namespace where we have a hello app deployment.<\/p>\n<p>Execute the following kubectl command from the directory where you have the <code>server.crt<\/code> and key files or provide the absolute path of the files . <code>hello-app-tls<\/code> is an arbitrary name.<\/p>\n<pre><code>kubectl create secret tls hello-app-tls \\\n    --namespace dev \\\n    --key server.key \\\n    --cert server.crt<\/code><\/pre>\n<p>Following is the equivalent <code>YAML<\/code> file where you have to add the crt and key file contents.<\/p>\n<pre><code>apiVersion: v1\nkind: Secret\nmetadata:\n  name: hello-app-tls\n  namespace: dev\ntype: kubernetes.io\/tls\ndata:\n  server.crt: |\n       &lt;crt contents here&gt;\n  server.key: |\n       &lt;private key contents here&gt;<\/code><\/pre>\n<h4 id=\"add-tls-block-to-ingress-object\">Add TLS block to Ingress Object<\/h4>\n<p>The ingress resource with TLS has to be created in the same namespace where you have the application deployed. So we create the<strong> example ingress TLS resource<\/strong> in  <code>dev<\/code> namespace.<\/p>\n<p>Save the following YAML as <code>ingress.yaml<\/code>. Replace <code>demo.mlopshub.com<\/code> with your hostname.<\/p>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: hello-app-ingress\n  namespace: dev\nspec:\n  ingressClassName: nginx\n  tls:\n  - hosts:\n    - demo.mlopshub.com\n    secretName: hello-app-tls\n  rules:\n  - host: \"demo.mlopshub.com\"\n    http:\n      paths:\n        - pathType: Prefix\n          path: \"\/\"\n          backend:\n            service:\n              name: hello-service\n              port:\n                number: 80<\/code><\/pre>\n<p>As you can see, I have <strong>added the TLS block<\/strong> with the hostname (<code>demo.mlopshub.com<\/code>) and tls secret we created in the previous step. I have created the self-signed TLS certificate with <code>emo.mlopshub.com<\/code> domain.<\/p>\n<pre><code>tls:\n  - hosts:\n    - demo.mlopshub.com\n    secretName: hello-app-tls<\/code><\/pre>\n<p>The host in the TLS block and rules block should match.<\/p>\n<p>\ud83c\udf89  Congratulations you have deployed Ingress with TLS.<\/p>\n<h2 id=\"validate-ingress-tls\">Validate Ingress TLS<\/h2>\n<p>You can validate the Ingress TLS using the curl command as well as the browser.<\/p>\n<p>From the CLI, run the curl command as given below with your domain name.<\/p>\n<pre><code>curl https:\/\/demo.mlopshub.com -kv<\/code><\/pre>\n<p>In the output, under server certificate, you can validate the certificate details as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-13-38.png\" class=\"kg-image\" alt=\"validate ingress TLS using curl\" loading=\"lazy\" width=\"561\" height=\"350\"><\/figure>\n<p>From the browser, access the domain and click the Lock icon to view the certificate details. If you have a valid certificate, you will see the information as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-11-42.png\" class=\"kg-image\" alt=\"validate ingress TLS using the browser.\" loading=\"lazy\" width=\"472\" height=\"235\"><\/figure>\n<p>If you don&#8217;t have a valid certificate or if the ingress TLS configuration is wrong, you will see &#8220;Your connection is not private&#8221; security warning and if you check the certificate details, you will see the certificate name as &#8220;<strong>Kubernetes Ingress Controller Fake Certificate<\/strong>&#8220;.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-12-37.png\" class=\"kg-image\" alt=\"Kubernetes Ingress Controller Fake Certificate issue\" loading=\"lazy\" width=\"477\" height=\"243\"><\/figure>\n<p><strong>Kubernetes Ingress Controller Fake Certificate<\/strong> is the default SSL certificate that comes with the Nginx ingress controller. If you check the <code>nginx.conf of the Nginx<\/code> controller, you will see the configured default certificates as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-10-51.png\" class=\"kg-image\" alt=\"default Nginx ingress SSL certificates.\" loading=\"lazy\" width=\"764\" height=\"245\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-10-51.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-10-51.png 764w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"ingress-ssl-termination\">Ingress SSL Termination<\/h2>\n<p>By default, SSL gets terminated in ingress the controller<\/p>\n<p>So all the traffic from the controller to the pod will be without TLS (decrypted traffic)<\/p>\n<p>If you want full SSL, you can add the supported annotation by the ingress controller you are using. For example, In the Nginx ingress controller, to allow SSL traffic till the application, you can use the<code> nginx.ingress.kubernetes.io\/backend-protocol: \"HTTPS\"<\/code> annotation. For this, your application should have SSL configured.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>In this blog, we have learned to configure ingress TLS certificates with <strong>kubernetes <\/strong>ingress TLS <strong>example<\/strong><\/p>\n<p>Also, you can <strong>configure more TLS parameters using annotations<\/strong>. The annotations differ between different ingress controllers.<\/p>\n<p>Also, if you are learning Kubernetes, you can check out my <a href=\"https:\/\/devopscube.com\/kubernetes-tutorials-beginners\/\" rel=\"noreferrer noopener\">Kubernetes tutorials for beginners<\/a>.<\/p>\n<p>Drop a comment if you need any clarification or tips to share.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/configure-ingress-tls-kubernetes\/\" target=\"_blank\" rel=\"noopener noreferrer\">How To Configure Ingress TLS\/SSL Certificates in Kubernetes \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/configure-ingress-tls-kubernetes\/<\/p>\n","protected":false},"author":1,"featured_media":903,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-902","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=902"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/902\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/903"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}