<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CSR (Certificate Signing Request) on Digi Hunch</title><link>https://static.digihunch.com/tags/csr-certificate-signing-request/</link><description>Recent content in CSR (Certificate Signing Request) on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 13:22:24 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tags/csr-certificate-signing-request/index.xml" rel="self" type="application/rss+xml"/><item><title>Creating X.509 TLS certificate for workload on Kubernetes</title><link>https://static.digihunch.com/2021/08/creating-tls-certificate-kubernetes/</link><pubDate>Sun, 29 Aug 2021 23:19:00 -0400</pubDate><guid>https://static.digihunch.com/2021/08/creating-tls-certificate-kubernetes/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-x509.webp" alt="Featured image of post Creating X.509 TLS certificate for workload on Kubernetes" /&gt;&lt;p class="wp-block-paragraph"&gt;In deployment automation, I often had to create self-signed X.509 certificate for testing TLS traffic into Kubernetes. Sometimes self-signed, sometimes signed by a CA. This post summarized the approaches I&amp;#8217;ve taken.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="create-self-signed-certificate-with-openssl"&gt;Create self-signed certificate with OpenSSL&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Traditionally, this is done in three OpenSSL commands:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days &lt;span style="color:#ae81ff"&gt;356&lt;/span&gt; -nodes -subj &lt;span style="color:#e6db74"&gt;&amp;#39;/CN=Health Certificate Authority&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj &lt;span style="color:#e6db74"&gt;&amp;#39;/CN=*.orthweb.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl x509 -req -sha256 -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -in server.csr -CA ca.crt -CAkey ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out server.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;I have an older post to cover the basics of cryptography in TLS certificate and PKI. In the three commands above, the first produces a private key and self-signed certificate for a CA. The second creates a private key and a CSR for the web site. The third one uses the CA&amp;#8217;s signing private key to sign the CSR from the website. The output is the certificate for the website. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Workloads running in Kubernetes typically consume certificates stored in Kubernetes Secret. The cons of this approach is that it usually requires an extra step to import the certificate files into Kubernetes Secret. For example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create -n orthweb secret generic orthweb-cred --from-file&lt;span style="color:#f92672"&gt;=&lt;/span&gt;tls.key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;server.key --from-file&lt;span style="color:#f92672"&gt;=&lt;/span&gt;tls.crt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;server.crt --from-file&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ca.crt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note, people use the term self-signed certificate loosely. It sometimes means literally a certificate that is self-signed, like the one generated above. Sometimes, I had to self-sign a CA, then use the CA to sign one certificate for the server and one for the client. Because the application being tested requires that the client and server&amp;#8217;s certificates both under the same CA. This would involve a few more commands, for example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Self-sign a CA&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -x509 -sha256 -newkey rsa:4096 -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -nodes -subj /C&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CA/ST&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Ontario/L&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Waterloo/O&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Digihunch/OU&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Imaging/CN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;issuer.digihunch.com/emailAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;info@www.digihunch.com -keyout /tmp/ca.key -out /tmp/ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generate a CSR for server&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -new -newkey rsa:4096 -nodes -subj /C&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CA/ST&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Ontario/L&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Waterloo/O&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Digihunch/OU&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Imaging/CN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;server.digihunch.com/emailAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;orthweb@www.digihunch.com -addext extendedKeyUsage&lt;span style="color:#f92672"&gt;=&lt;/span&gt;serverAuth -addext subjectAltName&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DNS:orthweb.digihunch.com,DNS:server2.digihunch.com -keyout /tmp/server.key -out /tmp/server.csr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Use the self-signed CA to issue a certificate to the server&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl x509 -req -sha256 -days &lt;span style="color:#ae81ff"&gt;3650&lt;/span&gt; -in /tmp/server.csr -CA /tmp/ca.crt -CAkey /tmp/ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out /tmp/server.crt -extfile &amp;lt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;echo subjectAltName&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DNS:orthweb.digihunch.com,DNS:server2.digihunch.com&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generate a CSR for clietn&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -new -newkey rsa:4096 -nodes -subj /C&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CA/ST&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Ontario/L&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Waterloo/O&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Digihunch/OU&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Imaging/CN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;client.digihunch.com/emailAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;client@www.digihunch.com -keyout /tmp/client.key -out /tmp/client.csr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Use the self-signed CA to issue a certificate to the client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl x509 -req -sha256 -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -in /tmp/client.csr -CA /tmp/ca.crt -CAkey /tmp/ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out /tmp/client.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In the example above, it is important to note that even though the server&amp;#8217;s CSR contains subject alternative name (SAN), I still have to specify the SAN again when signing the certificate for the server. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Similar to OpenSSL there are other toolkits such as CFSSL that supports specifying configuration files. However, the steps in Shell command are generally not always easy to automate.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="create-self-signed-certificate-with-helm"&gt;Create self-signed certificate with Helm&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Moving to the context of workload deployment in Kubernetes, running openSSL command isn&amp;#8217;t always a viable option. For example, generating a certificate in the middle of deployment using a Helm Chart. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In &lt;a href="https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/"&gt;Helm&lt;/a&gt;, template functions is for this purpose. In my Korthweb &lt;a href="https://github.com/digihunch/korthweb/blob/6480dad21490c0bfae27316093e533d68ecf04a2/orthanc/templates/tls-secrets.yaml#L4"&gt;project&lt;/a&gt; I used genSignedCert to create self-signed certificate and then store the key, certificate and CA certificate as Kubernetes Secret:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{{&lt;/span&gt;- $dbtlscert :&lt;span style="color:#f92672"&gt;=&lt;/span&gt; genSignedCert .Values.dbtls.certCommonName nil &lt;span style="color:#f92672"&gt;(&lt;/span&gt;list .Values.dbtls.certCommonName&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; $ca &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apiVersion: v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kind: Secret&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;metadata:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: &lt;span style="color:#f92672"&gt;{{&lt;/span&gt; .Values.dbtls.certCommonName | quote &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; namespace: &lt;span style="color:#f92672"&gt;{{&lt;/span&gt; $.Release.Namespace | quote &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type: kubernetes.io/tls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls.crt: &lt;span style="color:#f92672"&gt;{{&lt;/span&gt; $dbtlscert.Cert | b64enc | quote &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls.key: &lt;span style="color:#f92672"&gt;{{&lt;/span&gt; $dbtlscert.Key | b64enc | quote &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ca.crt: &lt;span style="color:#f92672"&gt;{{&lt;/span&gt; $ca.Cert | b64enc | quote &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{{&lt;/span&gt;- end &lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The cons of this approach is that the syntax is not straightforward. As indicated in Helm &lt;a href="https://helm.sh/docs/topics/charts/#templates-and-values"&gt;documentation&lt;/a&gt;: Helm Chart templates are written in the&amp;nbsp;&lt;a href="https://golang.org/pkg/text/template/" target="_blank" rel="noreferrer noopener"&gt;Go template language&lt;/a&gt;, with the addition of 50 or so add-on template functions&amp;nbsp;&lt;a href="https://github.com/Masterminds/sprig" target="_blank" rel="noreferrer noopener"&gt;from the Sprig library&lt;/a&gt;&amp;nbsp;and a few other&amp;nbsp;&lt;a href="https://helm.sh/docs/howto/charts_tips_and_tricks/"&gt;specialized functions&lt;/a&gt;. While we talk about the &amp;#8220;&lt;a href="https://helm.sh/docs/chart_template_guide/functions_and_pipelines/#helm"&gt;Helm template language&lt;/a&gt;&amp;#8221; as if it is Helm-specific, it is actually a combination of the Go template language, some extra functions, and a variety of wrappers to expose certain objects to the templates. Many resources on Go templates may be helpful as you learn about templating.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="create-self-signed-certificate-with-cert-manager"&gt;Create self-signed certificate with Cert-Manager&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://cert-manager.io/docs/"&gt;Cert Manager&lt;/a&gt; project is very popular to produce X.509 certificates directly in Kubernetes secret. We can install cert manager using Helm:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create namespace cert-manager&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo add jetstack https://charts.jetstack.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.0.3 --set installCRDs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get pods -n cert-manager&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get crd | grep cert-manager.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Alternatively, FluxCD&amp;#8217;s documentation on &lt;a href="https://fluxcd.io/docs/components/kustomize/kustomization/#kustomization-dependencies"&gt;Kustomization dependency&lt;/a&gt; uses Cert Manager as an example. It is a good way of installing cert-manager if you have GitOps pattern.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Creating self-signed certificate for website is fairly simple. It starts with &lt;a href="https://cert-manager.io/docs/configuration/selfsigned/#bootstrapping-ca-issuers"&gt;bootstrapping&lt;/a&gt; a CA issuer. Take the manifest below as an example. When creating the first certificate, make sure to specify isCA=true, so it stores the signing private key along with its own certificate in the ca-secret. Then use the newly created CA as issuer to create the X.509 certificate for the website.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;selfsigned-issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;selfSigned&lt;/span&gt;: {}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Certificate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-ca&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;isCA&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;commonName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-ca&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ca-secret&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKey&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;algorithm&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ECDSA&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;issuerRef&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;selfsigned-issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;group&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-ca-issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ca&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ca-secret&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Certificate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb-cert&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;commonName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthweb-secret&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;duration&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2160h&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;renewBefore&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;72h&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;subject&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;organizations&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;digihunch&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dnsNames&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;web.orthweb.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;dcm.orthweb.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKey&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;algorithm&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ECDSA&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;issuerRef&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-ca-issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Issuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;group&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The site certificate is directly stored in Kubernetes Secret as specified in the secretName field. To fetch the certificate text, we need to decode the secret entry, for example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n orthweb get secret orthweb-secret -o jsonpath&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{.data.ca\.crt}&amp;#39;&lt;/span&gt; | base64 -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that the example above uses ECDSA algorithm with size 256 for private key and certificate. It requires that the TLS client to support ECDSA algorithm as well. For more supportability, you can use RSA algorithm (2048 or 4096 size).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to creating self-signed certificate, Cert Manager supports a number of other issuer types. For example, the support of &lt;a href="https://cert-manager.io/docs/configuration/acme/"&gt;ACME&lt;/a&gt; issuer type enables integration with Let&amp;#8217;s Encrypt. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Cert Manager can secure Kubernetes Ingress resources with a sub-component called &lt;strong&gt;ingress-shim&lt;/strong&gt;. It is configured via annotation on the &lt;a href="https://cert-manager.io/docs/usage/ingress/"&gt;Ingress&lt;/a&gt; resource.&lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img decoding="async" src="https://cert-manager.io/images/high-level-overview.svg" alt="High level overview diagram explaining cert-manager architecture" style="width:752px;height:432px"/&gt;&lt;figcaption class="wp-element-caption"&gt;Cert Manager&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h2 class="wp-block-heading" id="create-ca-signed-certificate-manually"&gt;Create CA-signed certificate manually&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For a certificate signed by a CA, there are may paid options, from manual, to self-help, to automated. The classic manual way is using OpenSSL, generating key, CSR. The CA takes CSR to sign a X.509 certificate returned to the website administration.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many CA websites charges for a fee and makes it easy. For example, this site currently uses certificate from SSLs.com. Apart from the fee-for-cert option, there is a website named &amp;#8220;&lt;a href="https://www.sslforfree.com/"&gt;SSL for free&lt;/a&gt;&amp;#8220;, a CA with free option for 90-day single-domain, non-wildcard certificate and we can request it simply on their website, with proof of domain ownership. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The other popular free option is Let&amp;#8217;s Encrypt, which also employs &lt;a href="https://static.digihunch.com/2021/04/public-key-infrastructure-pki/"&gt;ACME&lt;/a&gt; protocol. The protocol requires ACME challenges to be satisfied in order to proof domain ownership. There are a few types of &lt;a href="https://letsencrypt.org/docs/challenge-types/"&gt;challenges&lt;/a&gt;: &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;HTTP-01 challenge &lt;/li&gt;&#10;&lt;li&gt;DNS-01 challenge&lt;/li&gt;&#10;&lt;li&gt;TLS-SNI-01 challenge&lt;/li&gt;&#10;&lt;li&gt;TLS-ALPN-01 challenge&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I have used the HTTP-01 and DNS-01 challenges. The DNS-01 challenge requires adding TXT records to DNS configuration. The HTTP-01 challenge requires adding a DNS A-record to resolve to the server, then two URIs with pre-defined value.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When I first set up this site I used certbot (the client program for letsencrypt) to create certificate every 90 days from the wordpress server, following &lt;a href="https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-using-lets-encrypt-certificates-with-wordpress"&gt;this&lt;/a&gt; guide, including solving DNS-01 challenges.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="create-ca-signed-certificate-automatically-with-cert-manager-and-letsencrypt"&gt;Create CA-signed certificate automatically with cert manager and letsencrypt&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With Kubernetes, &lt;a href="https://cert-manager.io/docs/"&gt;cert-manager&lt;/a&gt; has the ability to integrate with let&amp;#8217;s encrypt for full automation. &lt;a href="https://medium.com/@rd.petrusek/kubernetes-istio-cert-manager-and-lets-encrypt-c3e0822a3aaf"&gt;Here&lt;/a&gt; is a good blog post on this. &lt;span style="text-decoration: underline;"&gt;Domain verification is still required&lt;/span&gt; but it can be done automatically. We first need to register an A record that resolves host name to the Ingress IP to enable this automation. The domain ownership validation may use the ACME protocol. This should also work on private networks with private DNS and ACME protocol using a private boulder server.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Take domain name demo1.digihunch.com for example, if ingress exposes a public IP address which the domain name resolves to, then we can configure certificate with the following manifest:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;IngressClass&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;istio&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;controller&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;istio.io/ingress-controller&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;acme&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKeySecretRef&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://acme-staging-v02.api.letsencrypt.org/directory&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;solvers&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;http01&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ingress&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;istio&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Certificate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;demo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dnsNames&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;demo1.digihunch.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;issuerRef&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;demo-tls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This example uses Istio as ingress controller but the method works regardless of the controller technology behind Ingress. In the ClusterIssuer object, we&amp;#8217;re telling it to use the staging server from letsencrypt. We also specify http01 as challenge type, and that the ingress type is istio. In the Certificate object, we provided dnsName and specified ClusterIssuser. We also tell it to store the credentials to a secret named &lt;em&gt;demo-tls&lt;/em&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we apply the resources above, the ClusterIssuer connects to letsencrypt server via ACME protocol. Since the DNS name already resolves to the Public IP that the ingress is hosting, the ClusterIssuer configures the required Ingress, Services and Pods accordingly so the &lt;a href="https://letsencrypt.org/docs/challenge-types/#http-01-challenge"&gt;token&lt;/a&gt; to satisfy the challenge is presented at the designated URI. Instead of a staging server, we can also use production ACME server for production deployment. Note that the production ACME endpoint has a stricter rate limit.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When the ACME validation is in progress, it is important to ensure that port 80 is open and there is no other mechanism (such as routing rule, authorization requirement, mandatory redirect to 443) that blocks access from letsencrypt server.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="bottom-line"&gt;Bottom line&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Cert Manager is deployed in Kubernetes, supporting a variety of issuer types. As a Kubernetes-native tool, it is a no-brainer for Kubernetes workload for X.509 certificate. Compared with using template function in Helm, it is not dependent on template function and the syntax is consistent (YAML). Compared with OpenSSL or other binary tools, it is easy to integrate with the platform.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/08/docker-desktop-a-single-node-kubernetes-cluster/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Single-node Kubernetes cluster – docker desktop&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/09/log-shipping-in-kubernetes-with-efk/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Log Shipping in Kubernetes with EFK stack&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Public Key Infrastructure (PKI) – Introduction</title><link>https://static.digihunch.com/2021/04/public-key-infrastructure-pki/</link><pubDate>Thu, 08 Apr 2021 22:07:00 -0400</pubDate><guid>https://static.digihunch.com/2021/04/public-key-infrastructure-pki/</guid><description>&lt;p class="wp-block-paragraph"&gt;A public-key infrastructure (PKI) is a set of roles, policies, hardware, software and procedures needed to create, manage, distribute, use, store and revoke digital certificates and manage public-key encryption. The algorithms are based on Publick-key cryptography. The format of the digital certificate is defined in X.509 standard.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Certificate Authority&lt;/strong&gt; &amp;#8211; CA digitally signs and publishes the public key to user. Website requesting certificates start with a key pair. It then converts public key into CSR (certificate signing request), including the identity. Once the identity of requestor is validated, CA will sign the public key of requestor, using its own private key. The output of this is the certificate.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Registration Authority&lt;/strong&gt; &amp;#8211; CA may delegate some roles to registration authority (RA). RA is responsible for accepting requests for certificates and authenticating the entity making the request. However, RAs do not have the signing authority of a CA. Note that Microsoft may have referred to a subordinate CA as an RA, which is incorrect according to X.509 PKI standards.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-validation-types"&gt;Validation types&lt;/h3&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Domain Validation: domain ownerships is usually verified via DNS record.&lt;/li&gt;&#10;&lt;li&gt;Organization Validation: the organization name and address are verified and put into the certificate.&lt;/li&gt;&#10;&lt;li&gt;Extended Validation: verifies existence and location of the legal entity, as well as domain ownership. EV cannot be issued as a wildcard certificate.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-private-certificate-authorities"&gt;Private Certificate Authorities&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can create private CA and use it to sign certificates. Your user need to manually install and trust your private CA so that all certificates issued from the CA will inherit that trust. For revocation, you will also need to maintain an HTTP server for the certificate revocation list, or an OCSP responder.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-certificate-revocation-list-crl"&gt;Certificate Revocation List (CRL)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SSL certificates include information on how to access a certificate revocation list. Client will download and check this list to make sure the certificate has not been revoked. This mechanism has largely been replaced by OCSP responders.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-online-certificate-status-protocol-ocsp"&gt;Online Certificate Status Protocol (OCSP)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The OCSP protocol is a replacement for CRLs, with the benefit of being more real-time and requiring less bandwidth. The general operation is similar: clients are to query to OCSP responder to check if a certificate has been revoked.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-commercial-vs-non-profit-ca"&gt;Commercial vs non-profit CA&lt;/h3&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e7f5fe"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Commercial (e.g. SSLs.com)&lt;/td&gt;&lt;td&gt;Non-profit (e.g. Let&amp;#8217;s Encrypt)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Validation&lt;/td&gt;&lt;td&gt;DV, OV and EV&lt;/td&gt;&lt;td&gt;DV only&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wildcard&lt;/td&gt;&lt;td&gt;Supported&lt;/td&gt;&lt;td&gt;Supported (using DNS-01 challenge via ACME v2)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cost&lt;/td&gt;&lt;td&gt;Not Free&lt;/td&gt;&lt;td&gt;Free&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Expiration&lt;/td&gt;&lt;td&gt;1-3 years&lt;/td&gt;&lt;td&gt;90 days&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading" id="h-acme-protocol"&gt;ACME protocol&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Traditionally, there are several command-line utilities such as openssl, cfssl, or keytool (Java) to manage certificate related tasks. The process are mostly manual. The Internet Security Research Group (ISRG) developed the ACME (Automated Certificate management Environment) protocol.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this protocol, there is a certificate management agent (client) on the given web server. The agent generates a key pair and shares it with the CA at the outset of the validation process. Once validation is finished and the agent is verified as the proven owner of the key pair. It can use its key to digitally sign the CSRs it generates and sends to the CA via HTTPS requests. The CA uses the CSR, along with its associated public key, to issue the certificate and send it back to the agent. The agent downloads and installs it, then notifies the designated contact.&amp;nbsp;The agent can be automated to check in with the CA at given intervals to rotate certificates and keys.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s encrypt adopts ACME protocol by using &lt;a class="rank-math-link" href="https://github.com/letsencrypt/boulder"&gt;Boulder&lt;/a&gt; on the server side, and the most commonly used client is &lt;a class="rank-math-link" href="https://github.com/certbot/certbot"&gt;certbot&lt;/a&gt;. Smallstep also introduced ACME support in step CA in 2019.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Lets Encrypt&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I have used let&amp;#8217;s encrypt several times because it is free and easy to manage with &lt;strong&gt;certbot&lt;/strong&gt;, which can be installed using &lt;code&gt;brew&lt;/code&gt; on Mac. Here&amp;#8217;s how I quickly generate certificate manually:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DOMAIN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;orthwebdemo.digihunch.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo $DOMAIN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo certbot -d $DOMAIN --manual --preferred-challenges dns certonly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# get ready to change txt record&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls /etc/letsencrypt/live/orthwebdemo.digihunch.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The &lt;code&gt;--manual&lt;/code&gt; switch starts interactive prompts, which includes configuring TXT record and wait for the update.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-open-source-implementations"&gt;Open source implementations&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is a list of open-source implementations of PKI management:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://wiki.openssl.org/index.php/Main_Page" class="rank-math-link"&gt;OpenSSL&lt;/a&gt;: classic tool for PKI management. The Mac/BSD implementation and GNU implementation are slightly different.&lt;/li&gt;&#10;&lt;li&gt;Keytool: Java&amp;#8217;s Key and Certificate Management Tool that supports formats used in &lt;a href="https://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html" class="rank-math-link"&gt;Java&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Cfssl: introduced by &lt;a href="https://blog.cloudflare.com/introducing-cfssl/" class="rank-math-link"&gt;CloudFlare&lt;/a&gt; to simplify the &lt;a href="https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/" class="rank-math-link"&gt;PKI management&lt;/a&gt; process. On Ubuntu, the apt package name is golang-cfssl&lt;/li&gt;&#10;&lt;li&gt;Hashicorp Vault: CA, secret management and encryption.&lt;/li&gt;&#10;&lt;li&gt;Boulder: implemented in Go based on ACME protocol. Let&amp;#8217;s Encrypt uses Boulder on the server side. &lt;/li&gt;&#10;&lt;li&gt;EJBCA: a full-featured, enterprise-grade implementation in Java, managed by Swedish company PrimeKey Solutions AB.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-managed-ca-as-service"&gt;Managed CA as service&lt;/h3&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;AWS Certificate Manager: [Update] as of Sep 2022, the managed CA capability was spun off as a new service called &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/09/aws-certificate-manager-private-certificate-authority-now-aws-private-ca/"&gt;AWS Private Certificate Authority&lt;/a&gt;, to distinguish from the certificate management capability. &lt;/li&gt;&#10;&lt;li&gt;EJBCA Enterprise, as Azure Market place&lt;/li&gt;&#10;&lt;li&gt;Google Cloud Certificate Authority Service API&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/03/intro-to-data-analytics-platform/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Intro to Data Analytics Platform on Azure&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Certified Kubernetes Administrator (CKA) Exam&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>