<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Platform by Design]]></title><description><![CDATA[Writing about DevOps and platform engineering—covering Kubernetes, infrastructure as code, CI/CD, security, observability, and real-world system design trade-of]]></description><link>https://blog.thisisaditya.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1769327852224/98aec601-74ae-49a6-bd38-8a5f4133c58d.png</url><title>Platform by Design</title><link>https://blog.thisisaditya.com</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 23:30:06 GMT</lastBuildDate><atom:link href="https://blog.thisisaditya.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Secure Secret Management in Kubernetes: Exploring Different Approaches]]></title><description><![CDATA["Security is not a product, but a process." - Bruce Schneier.

Introduction
Secrets are an important aspect of any application, containing sensitive information such as passwords, API keys, and certificates. Storing and managing secrets securely is c...]]></description><link>https://blog.thisisaditya.com/secure-secret-management-in-kubernetes-exploring-different-approaches</link><guid isPermaLink="true">https://blog.thisisaditya.com/secure-secret-management-in-kubernetes-exploring-different-approaches</guid><category><![CDATA[Security]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Aditya Sutar]]></dc:creator><pubDate>Sun, 30 Apr 2023 04:30:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1bjsASjhfkE/upload/4848b48faa14d359cd17ff789228608d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"Security is not a product, but a process." - Bruce Schneier.</p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>Secrets are an important aspect of any application, containing sensitive information such as passwords, API keys, and certificates. Storing and managing secrets securely is crucial to maintaining the overall security of an application. While Kubernetes provides a built-in secrets management solution, it has been deemed least secure due to the way it stores secrets in a base64 encoded format. To address this issue, several key management services have been developed, such as AWS KMS, Azure Key Vault, and Hashicorp Vault, that offer a more secure way of storing secrets. However, the challenge remains on how to pass these secrets to the application securely. In this blog, we will explore three different approaches for securely passing secrets to applications in Kubernetes.</p>
<h2 id="heading-kubernetes-built-in-secrets">Kubernetes Built-in Secrets</h2>
<p>Kubernetes has built-in support for secrets management through the Secrets API. This API allows you to store and manage sensitive information such as passwords, API keys, and TLS certificates in your Kubernetes cluster.</p>
<p>However, it's important to note that the default storage format for Kubernetes secrets is base64-encoded, which provides only a basic level of obfuscation. Anyone with access to the Kubernetes API can easily decode the secret and retrieve the sensitive information.</p>
<p>Additionally, Kubernetes secrets have some limitations, such as a maximum size of 1MB per secret and no built-in support for rotating secrets. As a result, using Kubernetes built-in secrets may not be sufficient for more complex security requirements.</p>
<p>For these reasons, it's recommended to consider other options for storing and managing secrets, such as using external key management services. However, even when using external key management services, it's still important to securely pass the secrets to the application. In the following sections, we'll explore three approaches for doing so.</p>
<h2 id="heading-key-management-services">Key Management Services</h2>
<p>One of the best ways to securely store secrets is by using Key Management Services (KMS) provided by cloud providers or third-party vendors. KMS provides a centralized and secure way to manage keys, certificates, and secrets. These services allow for the secure storage of secrets and control over who can access them.</p>
<p>AWS KMS, Azure Key Vault, Google Cloud KMS, and HashiCorp Vault are some of the popular key management services that can be integrated with Kubernetes for secure secret management.</p>
<h2 id="heading-approach-1-volumes">Approach 1 - Volumes</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682765697031/3a7533dc-4a20-46a3-b08a-bcff5b1856ff.png" alt class="image--center mx-auto" /></p>
<p>One way to securely pass secrets to your application in Kubernetes is to use volumes. This approach involves storing secrets in an external service, such as a Key Management Service (KMS), and then mounting the secret data into a volume in the pod. The application can then read the secrets from the mounted volume.</p>
<p>However, cloud-native applications generally like to receive secrets via environment variables, rather than from files. To address this, Kubernetes provides a CSI (Container Storage Interface) driver to sync Kubernetes secrets with the external storage provider. Using this driver, we can mount the secret data as a volume and expose it as environment variables to the application.</p>
<p>While this approach allows us to keep secrets secure in an external service, it still requires storing the secret data in Kubernetes secrets, which are stored in base64-encoded format and may not be the most secure option.</p>
<h2 id="heading-approach-2-sidecar-container">Approach 2 - Sidecar Container</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682767117607/690ed2b8-eea6-4ec4-a696-5db963cd07a9.png" alt class="image--center mx-auto" /></p>
<p>Another approach to securely pass secrets to an application in Kubernetes is by using sidecar containers. With this approach, a sidecar container is added to the pod that is responsible for retrieving the secrets from an external service and passing them to the main application container via a shared volume or environment variables.</p>
<p>The sidecar container can be configured to retrieve the secrets from a Key Management Service or any other external service that is responsible for securely storing secrets. The main application container can then read the secrets from the shared volume or environment variables provided by the sidecar container.</p>
<p>As an example, we can use the Vault sidecar container with the official HashiCorp Vault Kubernetes integration. The sidecar container is responsible for retrieving the secrets from Vault, and the main application container can read the secrets from the shared volume or environment variables provided by the sidecar container.</p>
<p>This approach ensures that secrets are never stored in the pod's file system and are only passed securely to the main container.</p>
<p>However, it's important to note that while we are passing secrets securely to the container, if someone gains access to the container, they can access the secrets as well. So, it's important to implement additional security measures such as pod security policies and container runtime security to minimize the risk of unauthorized access to the secrets.</p>
<h2 id="heading-approach-3-secret-injector">Approach 3 - Secret Injector</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682767682885/621f9821-ba51-40bf-bb87-6c769bf7dbd1.png" alt class="image--center mx-auto" /></p>
<p>Another approach to securely pass secrets to applications in Kubernetes is by using a secret injector. This approach involves using a Kubernetes admission controller to automatically inject secrets into pods at runtime. One popular example of this approach is the Azure Key Vault to Kubernetes (akv2k8s) project. The akv2k8s project retrieves secrets from Azure Key Vault and injects them into pods using Kubernetes mutating webhooks.</p>
<p>When a pod is created or updated, the admission controller intercepts the pod creation request and adds the necessary environment variables and volumes to the pod specification. The environment variables and volumes are then populated with the secret values at runtime, ensuring that the application running inside the pod has access to the secrets.</p>
<p>One of the main advantages of this approach is that the secrets are not even accessible by the container running in the pod. Instead, only the application process running inside the container receives the secrets, which are injected at runtime.</p>
<p>This approach provides an extra layer of security as the secrets are never stored in the pod or container, and access to the secrets is strictly controlled by the Kubernetes API server.</p>
<p>However, it's important to note that the security of the secrets still relies on the security of the external service used. Any security issues or vulnerabilities in the external service can compromise the security of the secrets. It's also important to ensure that the Kubernetes admission controller is configured securely to prevent unauthorized access to the secrets during the injection.</p>
<p>Overall, the secret injector approach can be a powerful tool for securely passing secrets to applications in Kubernetes, and the akv2k8s project is a popular and well-maintained implementation of this approach.</p>
<h2 id="heading-best-practices">Best Practices</h2>
<p>While using Kubernetes for secret management, it is important to follow best practices to ensure the security of your secrets. Here are some best practices that you should consider:</p>
<ol>
<li><p>Avoid using Kubernetes built-in secrets: As mentioned earlier, Kubernetes built-in secrets are not secure as secret data is stored in base64-encoded format. It is recommended to use a third-party secret management solution like Key Management Services.</p>
</li>
<li><p>Use RBAC for secret access control: Kubernetes provides Role-Based Access Control (RBAC) to control access to secrets. You should use RBAC to restrict access to secrets to only the necessary users or services.</p>
</li>
<li><p>Use short-lived secrets: Avoid using long-lived secrets, as it increases the risk of unauthorized access. Instead, use short-lived secrets that expire after a certain time.</p>
</li>
<li><p>Use secret rotation: Regularly rotate secrets, such as passwords and certificates, to minimize the risk of unauthorized access.</p>
</li>
<li><p>Use TLS for communication: Use Transport Layer Security (TLS) to encrypt communication between Kubernetes components and secret management systems.</p>
</li>
<li><p>Use encryption for secret data at rest: Encrypt the secret data at rest using encryption tools and techniques.</p>
</li>
<li><p>Implement least privilege access: Use the principle of least privilege to grant access to secret management systems, tools, and APIs.</p>
</li>
<li><p>Use container image scanning: Use container image scanning to detect and fix vulnerabilities in container images before deploying them to Kubernetes.</p>
</li>
</ol>
<p>By following these best practices, you can ensure the security and confidentiality of your secrets in Kubernetes.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, secret management is an essential aspect of Kubernetes application deployment. While Kubernetes provides a built-in secrets management solution, it is not very secure and lacks some important features that are necessary for secure secret management.</p>
<p>Key Management Services such as AWS KMS, Azure Key Vault, and HashiCorp Vault provide a more secure and reliable way of storing secrets. To pass these secrets securely to the application, we explored three approaches: volumes, sidecar containers, and secret injectors. Each approach has its own advantages and limitations, and the choice of approach depends on the specific use case.</p>
<p>In addition to these approaches, there are also some best practices that can be followed for secure secret management, such as minimizing secret access, rotating secrets regularly, and implementing multi-factor authentication.</p>
<p>Overall, secure secret management is critical for the security and integrity of applications running in Kubernetes, and it is important to choose the right approach and follow best practices to ensure that secrets are kept safe and secure.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p>Kubernetes Documentation on Secrets: <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/secret/"><strong>https://kubernetes.io/docs/concepts/configuration/secret/</strong></a></p>
</li>
<li><p>Kubernetes Secrets Best Practices: <a target="_blank" href="https://kubernetes.io/docs/concepts/security/secrets-good-practices/"><strong>https://kubernetes.io/docs/concepts/security/secrets-good-practices/</strong></a></p>
</li>
<li><p>Using Azure Key Vault with Kubernetes: <a target="_blank" href="https://docs.microsoft.com/en-us/azure/key-vault/general/key-vault-integrate-kubernetes"><strong>https://docs.microsoft.com/en-us/azure/key-vault/general/key-vault-integrate-kubernetes</strong></a></p>
</li>
<li><p>Azure Key Vault to Kubernetes (akv2k8s) Project: <a target="_blank" href="https://github.com/Azure/akv2k8s"><strong>https://github.com/Azure/akv2k8s</strong></a></p>
</li>
<li><p>HashiCorp Vault Kubernetes Integration: <a target="_blank" href="https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-sidecar#inject-secrets-into-the-pod"><strong>https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-sidecar#inject-secrets-into-the-pod</strong></a></p>
</li>
<li><p>Google Cloud Secrets Management: <a target="_blank" href="https://cloud.google.com/secret-manager"><strong>https://cloud.google.com/secret-manager</strong></a></p>
</li>
<li><p>AWS Secrets Manager: <a target="_blank" href="https://aws.amazon.com/secrets-manager/"><strong>https://aws.amazon.com/secrets-manager/</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Authentication & Authorization in Kubernetes - Nginx Plus Ingress Controller with OIDC policy]]></title><description><![CDATA["Secure your applications, not your network. Verify identity and enforce access controls in the application itself, where they can travel with the application wherever it goes." - John Kindervag, creator of the Zero Trust security model.

Introductio...]]></description><link>https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-nginx-plus-ingress-controller-with-oidc-policy</link><guid isPermaLink="true">https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-nginx-plus-ingress-controller-with-oidc-policy</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[nginx]]></category><category><![CDATA[OIDC]]></category><dc:creator><![CDATA[Aditya Sutar]]></dc:creator><pubDate>Sun, 19 Mar 2023 04:30:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679137472518/3c71ef90-e0b7-4e91-9a41-f05af6a0aa89.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"Secure your applications, not your network. Verify identity and enforce access controls in the application itself, where they can travel with the application wherever it goes." - John Kindervag, creator of the Zero Trust security model.</p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>In today's digital age, securing your applications and services is more critical than ever. One of the essential aspects of application security is authentication and authorization, which ensure that only authorized users have access to resources. Kubernetes is a popular container orchestration platform that is widely used to deploy and manage cloud-native applications. When deploying Kubernetes clusters, it is crucial to ensure that authentication and authorization are properly configured to protect your applications and services. In this article, we will explore the use of the Nginx Plus Ingress Controller with OpenID Connect (OIDC) policy for authentication and authorization in Kubernetes. We will dive into how to configure Nginx Plus Ingress Controller with OIDC policy to authenticate users.</p>
<h2 id="heading-why-oidc-policy">Why OIDC Policy?</h2>
<p>In the <a target="_blank" href="https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-using-oauth2-proxy-as-authentication-proxy">previous article</a>, we explored how to configure the oauth2 proxy as an external authentication proxy with the Nginx ingress controller. Although this solution can work well, it requires managing the oauth2 proxy instance running in the cluster, including its security patches, and scalability, and relying on community support if anything goes wrong. In production environments, such solutions are not always ideal.</p>
<p>Nginx Plus ingress controller offers various authentication mechanisms out of the box, including OIDC authentication using OIDC policy. In this approach, the Ingress Controller handles authentication logic and session management without relying on an external authentication proxy.</p>
<p>This approach offers two significant advantages. First, we don't have to manage an external authentication proxy like the oauth2 proxy and its security. Second, we can perform authentication and authorization directly at the Nginx ingress controller, saving network traffic generated for each request as requests do not leave the ingress controller. This makes the process more efficient and secure.</p>
<h2 id="heading-how-does-oidc-policy-work">How does OIDC Policy work?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679127251110/bc7499d9-3d49-4c22-afd4-689f8a3d3daf.png" alt class="image--center mx-auto" /></p>
<p>When a user tries to access a protected resource, the Nginx Plus Ingress Controller first checks for a session cookie in the request. If a session cookie is present, it verifies the user's session details and returns a successful response, allowing the user to access the resource.</p>
<p>However, if the session cookie is not present, the Nginx Plus Ingress Controller redirects the user to the login page of the configured IdP (such as Google, GitHub, Azure AD, etc.). After the user logs in to the IdP and is redirected back to Ingress Controller's callback URL <code>/_codexch</code>, the Nginx plus ingress controller exchanges the code for user information with the IdP. It then creates a new session for the user using this information and sets a session cookie in the response.</p>
<p>With a valid session cookie, the user can access the requested resource through the Nginx ingress controller without being redirected to the IdP for subsequent requests.</p>
<h2 id="heading-oidc-policy-configuration">OIDC Policy Configuration</h2>
<p>To implement OIDC authentication with the Nginx Plus Ingress Controller, we need to create an OIDC policy. Before we do that, we need to create a Secret to store the client secret required for the OIDC flow.</p>
<p>First, create a new file called <code>client-secret.yaml</code> and paste the following into it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Secret</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oidc-secret</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">nginx.org/oidc</span>
<span class="hljs-attr">data:</span>
  <span class="hljs-attr">client-secret:</span> <span class="hljs-string">&lt;client-secret-in-base64-format&gt;</span>
</code></pre>
<p>Make sure to replace <code>&lt;client-secret-in-base64-format&gt;</code> with your client secret in base64 format. You can convert your secret to base64 format using the following command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> -n &lt;client-secret&gt; | base64
</code></pre>
<p>Once you have your client secret in base64 format, you can deploy the Secret by executing the following command:</p>
<pre><code class="lang-bash">kubectl apply -f client-secret.yaml
</code></pre>
<p>Next, we will create and deploy the OIDC policy. Create a new file called <code>oidc-policy.yaml</code> and paste the following into it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">k8s.nginx.org/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Policy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oidc-policy</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">oidc:</span>
    <span class="hljs-attr">clientID:</span> <span class="hljs-string">&lt;client-id&gt;</span>
    <span class="hljs-attr">clientSecret:</span> <span class="hljs-string">oidc-secret</span>
    <span class="hljs-attr">authEndpoint:</span> <span class="hljs-string">&lt;idp-auth-url&gt;</span>
    <span class="hljs-attr">tokenEndpoint:</span> <span class="hljs-string">&lt;idp-token-url&gt;</span>
    <span class="hljs-attr">jwksURI:</span> <span class="hljs-string">&lt;idp-jwt-key-set-url&gt;</span>
    <span class="hljs-attr">scope:</span> <span class="hljs-string">openid+profile+email</span>
</code></pre>
<p>Replace the following fields with the corresponding values:</p>
<ul>
<li><p><code>&lt;client-id&gt;</code>: the client ID provided by your IdP</p>
</li>
<li><p><code>&lt;idp-auth-url&gt;</code>: the authorization URL that will be used to check if the user is authenticated or not</p>
</li>
<li><p><code>&lt;idp-token-url&gt;</code>: the token URL used to exchange the code for an access token and ID token</p>
</li>
<li><p><code>&lt;idp-jwt-key-set-url&gt;</code>: the JWT encryption key set URL for decrypting the JWT token</p>
</li>
</ul>
<p>Optionally, you can customize the scope by modifying the <code>scope</code> field. The default scope includes <code>openid</code>, <code>profile</code>, and <code>email</code>. For more information on OIDC scopes, check out the <a target="_blank" href="https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes"><strong>Auth0 documentation on scopes</strong></a>.</p>
<p>For example, if your IdP is Auth0, your OIDC policy would look similar to this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">k8s.nginx.org/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Policy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oidc-policy</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">oidc:</span>
    <span class="hljs-attr">clientID:</span> <span class="hljs-string">&lt;client-id&gt;</span>
    <span class="hljs-attr">clientSecret:</span> <span class="hljs-string">oidc-secret</span>
    <span class="hljs-attr">authEndpoint:</span> <span class="hljs-string">https://mydomain.us.auth0.com/authorize</span>
    <span class="hljs-attr">tokenEndpoint:</span> <span class="hljs-string">https://mydomain.us.auth0.com/oauth/token</span>
    <span class="hljs-attr">jwksURI:</span> <span class="hljs-string">https://mydomain.us.auth0.com/.well-known/jwks.json</span>
    <span class="hljs-attr">scope:</span> <span class="hljs-string">openid+profile+email</span>
</code></pre>
<p>Once you have created the OIDC policy file, you can deploy it using the following command:</p>
<pre><code class="lang-bash">kubectl apply -f oidc-policy.yaml
</code></pre>
<p>With the OIDC policy deployed, the Nginx Plus Ingress Controller will handle the authentication logic and session management for you, without the need for an external authentication proxy.</p>
<h2 id="heading-nginx-plus-ingress-controller-configuration">Nginx Plus Ingress Controller Configuration</h2>
<p>Before we can use the newly deployed OIDC Policy, two prerequisite configurations need to be made in the Nginx Plus Ingress Controller: Zone synchronization and Resolver setup.</p>
<p>Zone synchronization ensures that the OIDC policy works properly across multiple replicas of the Ingress Controller. To enable this, we first need to create a headless service in the Nginx ingress controller namespace. Create a new file called <code>nginx-ingress-headless.yaml</code> and paste the following into it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">nginx-ingress-headless</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">nginx-ingress</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">clusterIP:</span> <span class="hljs-string">None</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">nginx-ingress</span>
</code></pre>
<p>Make sure to specify the correct selector label for your Nginx ingress controller deployment. Deploy this service using the following command:</p>
<pre><code class="lang-bash">kubectl apply -f nginx-ingress-headless.yaml
</code></pre>
<p>Next, we need to add extra configuration to the Nginx ingress controller using a ConfigMap. Create a new file called <code>nginx-config.yaml</code> and paste the following into it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">kind:</span> <span class="hljs-string">ConfigMap</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">nginx-config</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">nginx-ingress</span>
<span class="hljs-attr">data:</span>
  <span class="hljs-comment"># Zone Synchronization setup</span>
  <span class="hljs-attr">stream-snippets:</span> <span class="hljs-string">|
    server {
        listen 12345;
        listen [::]:12345;
        zone_sync;
        zone_sync_server nginx-ingress-headless.nginx-ingress.svc.cluster.local:12345 resolve;
    }
</span>  <span class="hljs-comment"># Resolver setup</span>
  <span class="hljs-attr">resolver-addresses:</span> <span class="hljs-string">&lt;kube-dns-ip&gt;</span>
  <span class="hljs-attr">resolver-valid:</span> <span class="hljs-string">5s</span>
</code></pre>
<p>This configuration sets up zone synchronization and resolver setup for the OIDC policy. Make sure to replace <code>&lt;kube-dns-ip&gt;</code> with the cluster IP of the kube-dns service running inside your cluster. You can find the kube-dns cluster IP by running the following command:</p>
<pre><code class="lang-bash">kubectl -n kube-system get service kube-dns
</code></pre>
<p>Once you've created this configuration, you can deploy it using the following command:</p>
<pre><code class="lang-bash">kubectl apply -f nginx-config.yaml
</code></pre>
<p>With the prerequisite configurations in place, the next step is to create a Virtual Server and apply the OIDC policy to it.</p>
<h2 id="heading-virtual-server-configuration">Virtual Server Configuration</h2>
<p>The virtual server is a custom resource definition provided by Nginx that offers more features compared to the standard Ingress resource. In combination with the OIDC policy, it enables secure access to your application. To create a virtual server, create a new file named <code>virtual-server.yaml</code> and add the following configuration to it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">k8s.nginx.org/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">VirtualServer</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">app-vs</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">host:</span> <span class="hljs-string">&lt;your-domain&gt;</span>
  <span class="hljs-attr">upstreams:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app</span>
      <span class="hljs-attr">service:</span> <span class="hljs-string">&lt;app-service-name&gt;</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
  <span class="hljs-attr">policies:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">oidc-policy</span>
  <span class="hljs-attr">routes:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>
      <span class="hljs-attr">action:</span>
        <span class="hljs-attr">proxy:</span>
          <span class="hljs-attr">upstream:</span> <span class="hljs-string">demo-app</span>
</code></pre>
<p>Make sure to replace <code>&lt;your-domain&gt;</code> with a valid domain name and <code>&lt;app-service-name&gt;</code> with the name of the service you want to protect using the OIDC policy.</p>
<p>Execute the following command to deploy the virtual server and attach the OIDC policy to it:</p>
<pre><code class="lang-bash">kubectl apply -f virtual-server.yaml
</code></pre>
<p>Now, when a user tries to access your application, they will be redirected to the IdP configured in the OIDC policy. Only after successful authentication will the user be redirected to the application. Congratulations, you have successfully configured secure access to your application using Nginx plus Ingress Controller and OIDC policy!</p>
<h2 id="heading-what-if">What If...?</h2>
<h3 id="heading-you-want-to-provide-additional-user-information-to-the-application">You want to provide additional user information to the application</h3>
<p>By default, the OIDC policy provides the <code>sub</code> claim data via the header <code>username</code> to the application. However, if you need to pass other claim data to the application, you can add a custom location snippet inside the virtual server configuration.</p>
<p>For example, to add a custom header named <code>email</code> and pass the <code>email</code> claim information to the application, you can modify the virtual server configuration as follows:</p>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
<span class="hljs-attr">routes:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>
      <span class="hljs-attr">location-snippets:</span> <span class="hljs-string">proxy_set_header</span> <span class="hljs-string">email</span> <span class="hljs-string">$jwt_claim_email;</span>
      <span class="hljs-attr">action:</span>
        <span class="hljs-attr">proxy:</span>
          <span class="hljs-attr">upstream:</span> <span class="hljs-string">demo-app</span>
<span class="hljs-string">...</span>
</code></pre>
<p>This will add a new custom header named "email" and pass the email claim data to the application.</p>
<h3 id="heading-you-want-to-provide-a-custom-logout-url">You want to provide a custom logout URL</h3>
<p>When using the default <code>/logout</code> endpoint, a user will log out of the application. However, in some cases, you may also want the user to log out of the Identity Provider (IdP) or perform additional operations after the logout process. To achieve this, you can create a server snippet and specify a custom logout URL that the user will be redirected to after logging out of the application.</p>
<p>Here's an example server snippet that sets a custom logout redirect URL:</p>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
<span class="hljs-attr">host:</span> <span class="hljs-string">&lt;your-domain&gt;</span>
  <span class="hljs-attr">server-snippets:</span> <span class="hljs-string">|
    set $logout_redirect "https://myidp.com/logout";
</span>  <span class="hljs-attr">upstreams:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app</span>
      <span class="hljs-attr">service:</span> <span class="hljs-string">demo-app-svc</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
<span class="hljs-string">...</span>
</code></pre>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p>Use HTTPS: Always use HTTPS when configuring the OIDC policy as it ensures secure communication between the application and IdP.</p>
</li>
<li><p>Keep IdP secrets safe: Store the IdP secrets securely in a key vault or a secure location accessible only to authorized personnel.</p>
</li>
<li><p>Avoid using custom snippets: Custom snippets can introduce unnecessary complexity and potential security risks to your configuration. Try to use the built-in features and directives provided by Nginx Ingress Controller whenever possible.</p>
</li>
<li><p>Use multiple replicas of the Ingress Controller to ensure high availability - this helps to prevent downtime if one replica fails.</p>
</li>
<li><p>Consider using a commercial version of Nginx Ingress Controller for enterprise-level support, advanced features, and improved scalability.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, implementing OpenID Connect (OIDC) authentication with Nginx Plus Ingress Controller can provide a secure and reliable way to protect your applications from unauthorized access. With OIDC, you can take advantage of various identity providers such as Google, Facebook, Okta, etc., and enable Single Sign-On (SSO) for your users. Additionally, Nginx Plus Ingress Controller offers powerful features such as Virtual Servers and OIDC Policies to simplify the configuration process and ensure scalability.</p>
<p>However, it is important to keep in mind the best practices and potential pitfalls when using Nginx Plus Ingress Controller with OIDC. By following the recommended practices, such as avoiding custom snippets, keeping the configuration simple, and using Kubernetes best practices, you can ensure a smooth and secure deployment of your application.</p>
<p>Overall, the combination of Nginx Plus Ingress Controller and OIDC provides a powerful toolset for securing your applications and delivering a seamless user experience.</p>
<p>To explore other approaches for securing applications in a Kubernetes cluster, you can check out our previous blog post on Authentication &amp; Authorization in Kubernetes Cluster — <a target="_blank" href="https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster"><strong>https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster</strong></a>.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p>OpenID Connect Official Documentation - <a target="_blank" href="https://openid.net/connect/">https://openid.net/connect/</a></p>
</li>
<li><p>Nginx Ingress Controller Official Documentation - <a target="_blank" href="https://docs.nginx.com/nginx-ingress-controller/intro/overview/">https://docs.nginx.com/nginx-ingress-controller/intro/overview/</a></p>
</li>
<li><p>OIDC Policy Official Documentation - <a target="_blank" href="https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#oidc">https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#oidc</a></p>
</li>
<li><p>OIDC policy example by Nginx - <a target="_blank" href="https://github.com/nginxinc/kubernetes-ingress/tree/v3.0.2/examples/custom-resources/oidc">https://github.com/nginxinc/kubernetes-ingress/tree/v3.0.2/examples/custom-resources/oidc</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Authentication & Authorization in Kubernetes - Oauth2 Proxy with Dex IdP]]></title><description><![CDATA["Authentication and authorization represent the new perimeter in a world where identity is the new control plane." - Satya Nadella, CEO of Microsoft.

Introduction
In our previous article, we explored how Oauth2 Proxy can be used as an external authe...]]></description><link>https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-oauth2-proxy-with-dex-idp</link><guid isPermaLink="true">https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-oauth2-proxy-with-dex-idp</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[OIDC]]></category><category><![CDATA[nginx]]></category><dc:creator><![CDATA[Aditya Sutar]]></dc:creator><pubDate>Sun, 05 Mar 2023 12:08:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677915345162/6f6ede36-57c4-422c-bf40-69c83ce0bd8f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"Authentication and authorization represent the new perimeter in a world where identity is the new control plane." - Satya Nadella, CEO of Microsoft.</p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>In our <a target="_blank" href="https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-using-oauth2-proxy-as-authentication-proxy">previous article</a>, we explored how Oauth2 Proxy can be used as an external authentication proxy to secure applications within a Kubernetes cluster. While this is a good solution for simple use cases with a single IdP, Oauth2 Proxy comes with some limitations:</p>
<ul>
<li><p>Oauth2 Proxy cannot integrate with SAML IdP, which is commonly used in enterprise systems for authentication and authorization.</p>
</li>
<li><p>In B2B enterprise systems, client organizations may want to use their own IdP for authentication without disrupting the host organization's IdP - multiple IdP integration - which Oauth2 Proxy cannot handle.</p>
</li>
<li><p>Oauth2 Proxy only supports a limited set of identity providers, such as OAuth2/OIDC providers.</p>
</li>
</ul>
<p>This is where Dex IdP comes into play. In this article, We are going to see the integration of Dex IdP with Oauth2 Proxy.</p>
<h2 id="heading-why-dex-idp">Why Dex IdP?</h2>
<p>Dex IdP is an open-source identity provider that can be used to federate authentication across multiple systems, making it an ideal choice for larger and more complex Kubernetes deployments. It allows you to integrate multiple identity providers, including OAuth2/OIDC providers, SAML, LDAP, and Active Directory, into one centralized system. Dex acts as a bridge between your applications and the identity providers, providing a seamless and secure authentication and authorization experience.</p>
<h2 id="heading-how-does-dex-idp-work">How does Dex IdP work?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677865833369/15ee3683-736c-40f5-ab17-c932fe8857fb.png" alt class="image--center mx-auto" /></p>
<p>When a user tries to log in to a system that is protected by Dex IdP:</p>
<ol>
<li><p>Dex provides the user with multiple Identity Provider (IdP) options from which they can choose to log in to their respective IdP.</p>
</li>
<li><p>The user selects the particular IdP in which their account is present, and Dex redirects the user to that IdP.</p>
</li>
<li><p>The user logs in to the IdP, and after successful authentication, the IdP redirects the user back to Dex.</p>
</li>
<li><p>Dex creates a session for the user and redirects the user to the particular application they were trying to access.</p>
</li>
</ol>
<h2 id="heading-installation-and-configuration-of-dex-idp">Installation and Configuration of Dex IdP</h2>
<p>There are multiple ways to install Dex on a Kubernetes cluster, but in this article, we will be using Helm Charts.</p>
<p>To get started, add the Dex Helm Charts repository:</p>
<pre><code class="lang-bash">helm repo add dex https://charts.dexidp.io
</code></pre>
<p>In this example, we will integrate two IdPs: SAML IdP and OIDC IdP in Dex. To do this, create a new <code>values.yaml</code> file and paste the following example configuration into it:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Configures the ingress for Dex</span>
<span class="hljs-attr">ingress:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">className:</span> <span class="hljs-string">nginx</span>
  <span class="hljs-attr">hosts:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">host:</span> <span class="hljs-string">"&lt;your-domain&gt;"</span>
      <span class="hljs-attr">paths:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/dex</span>
          <span class="hljs-attr">pathType:</span> <span class="hljs-string">Prefix</span>

<span class="hljs-comment"># Configures the Dex instance          </span>
<span class="hljs-attr">config:</span>
  <span class="hljs-attr">issuer:</span> <span class="hljs-string">https://&lt;your-domain&gt;/dex</span>
  <span class="hljs-attr">storage:</span>
    <span class="hljs-attr">type:</span> <span class="hljs-string">kubernetes</span>
    <span class="hljs-attr">config:</span>
      <span class="hljs-attr">inCluster:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">web:</span>
    <span class="hljs-attr">http:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-string">:8080</span>
  <span class="hljs-attr">oauth2:</span>
    <span class="hljs-attr">responseTypes:</span> [<span class="hljs-string">"code"</span>, <span class="hljs-string">"token"</span>, <span class="hljs-string">"id_token"</span>]
  <span class="hljs-comment"># Configures the connections for Dex</span>
  <span class="hljs-attr">connectors:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">saml</span>
      <span class="hljs-attr">id:</span> <span class="hljs-string">saml</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">"Example SAML connection"</span>
      <span class="hljs-attr">config:</span>
        <span class="hljs-attr">entityIssuer:</span> <span class="hljs-string">https://&lt;your-domain&gt;/dex/callback</span>
        <span class="hljs-attr">ssoURL:</span> <span class="hljs-string">&lt;saml-login-url&gt;</span>
        <span class="hljs-attr">caData:</span> <span class="hljs-string">&lt;ca-certificate-in-base-64&gt;</span>
        <span class="hljs-attr">redirectURI:</span> <span class="hljs-string">https://&lt;your-domain&gt;/dex/callback</span>
        <span class="hljs-comment"># map your attributes here</span>
        <span class="hljs-attr">usernameAttr:</span> <span class="hljs-string">username</span> 
        <span class="hljs-attr">emailAttr:</span> <span class="hljs-string">email</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">microsoft</span>
      <span class="hljs-attr">id:</span> <span class="hljs-string">microsoft</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">"Example Azure AD OIDC connection"</span>
      <span class="hljs-attr">config:</span>
        <span class="hljs-attr">clientID:</span> <span class="hljs-string">"&lt;client-id&gt;"</span>
        <span class="hljs-attr">clientSecret:</span> <span class="hljs-string">"&lt;client-secret&gt;"</span>
        <span class="hljs-attr">redirectURI:</span> <span class="hljs-string">https://&lt;your-domain&gt;/dex/callback</span>
        <span class="hljs-attr">tenant:</span> <span class="hljs-string">&lt;tenant-id&gt;</span>

  <span class="hljs-comment"># Configures the Client configuration</span>
  <span class="hljs-attr">staticClients:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">id:</span> <span class="hljs-string">&lt;dex-client-id&gt;</span>
      <span class="hljs-attr">secret:</span> <span class="hljs-string">&lt;dex-client-secret&gt;</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">"Oauth2 Proxy Static Client"</span>
      <span class="hljs-attr">redirectURIs:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">https://&lt;your-domain&gt;/oauth2/callback</span>
</code></pre>
<p>There are several important modifications to make:</p>
<ul>
<li><p><code>host</code>: Replace with your domain name.</p>
</li>
<li><p><code>issuer</code>: Replace with the issuer URL that will be used by your authentication method.</p>
</li>
</ul>
<p>For SAML IdP:</p>
<ul>
<li><p><code>entityIssuer</code>: Set to the Issuer value you want to send during AuthnRequest.</p>
</li>
<li><p><code>ssoURL</code>: Set to the SAML login URL.</p>
</li>
<li><p><code>caData</code>: Set to the CA certificate in base64 format.</p>
</li>
<li><p><code>redirectURI</code>: Set to the redirect URI that your IdP will call after successful authentication.</p>
</li>
<li><p><code>usernameAttr</code> and <code>emailAttr</code>: check attributes configured for SAML IdP and map accordingly here (e.g. if the SAML IdP is configured to return the username attribute as "uid", then set usernameAttr: "uid" in the config, and if the email attribute is configured as "mail", then set emailAttr: "mail").</p>
</li>
</ul>
<p>For Azure AD OIDC IdP:</p>
<ul>
<li><p><code>clientID</code>: Set to the Client ID provided by your IdP.</p>
</li>
<li><p><code>clientSecret</code>: Set to the Client Secret provided by your IdP.</p>
</li>
<li><p><code>redirectURI</code>: Set to the redirect URI that your IdP will call after successful authentication.</p>
</li>
<li><p><code>tenant</code>: Set to the Azure Tenant ID.</p>
</li>
</ul>
<p>For Static Client (Oauth2 Proxy):</p>
<ul>
<li><p><code>id</code>: Set to the Client ID that will be used by the Oauth2 Proxy when connecting to Dex IdP.</p>
</li>
<li><p><code>secret</code>: Set to the Client Secret that will be used by the Oauth2 Proxy when connecting to Dex IdP.</p>
</li>
<li><p><code>redirectURIs</code>: Set to the callback URI of the Oauth2 Proxy.</p>
</li>
</ul>
<p>To deploy Dex, run the following command:</p>
<pre><code class="lang-bash">helm upgrade --install -n dex dex dex/dex --values values.yaml
</code></pre>
<p>This command will install and configure Dex on your Kubernetes cluster. Dex will be hosted at <strong>"http://&lt;your-domain&gt;/dex".</strong></p>
<p>For more information on configuring Dex to work with your specific identity provider, check out the official documentation at <a target="_blank" href="https://dexidp.io/docs/connectors/"><strong>https://dexidp.io/docs/connectors/</strong></a>.</p>
<h2 id="heading-configuration-of-oauth2-proxy">Configuration of Oauth2 Proxy</h2>
<p>To configure Oauth2 Proxy, you will follow similar steps as you did for configuring other IdPs inside Oauth2 Proxy. The difference will be that you will replace specific properties in the Deployment of Oauth2 Proxy with those that correspond to your Dex instance.</p>
<p>You will need to replace the following properties:</p>
<ul>
<li><p>oidc-issuer-url: This is the issuer URL you specified in Dex.</p>
</li>
<li><p>OAUTH2_PROXY_CLIENT_ID: This is the static client ID you specified in Dex.</p>
</li>
<li><p>OAUTH2_PROXY_CLIENT_SECRET: This is the static client secret you specified in Dex.</p>
</li>
</ul>
<p>Here's an example Deployment file for Oauth2 Proxy that shows how these values can be replaced:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">oauth2-proxy-ns</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">args:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--provider=oidc</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--oidc-issuer-url=http://&lt;your-domain&gt;/dex</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--scope=openid</span> <span class="hljs-string">profile</span> <span class="hljs-string">email</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--email-domain=*</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--upstream=static://200</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--http-address=0.0.0.0:4180</span>
        <span class="hljs-attr">env:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_CLIENT_ID</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">&lt;dex-client-id&gt;</span> <span class="hljs-comment"># Replace with the client ID from Dex</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_CLIENT_SECRET</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">&lt;dex-client-secret&gt;</span> <span class="hljs-comment"># Replace with the client secret from Dex</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_COOKIE_SECRET</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">"bVbMfxlt8Wmq4E1OYTICqS_AZHTeVDUEdFP5LGbY05c"</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">quay.io/oauth2-proxy/oauth2-proxy:latest</span>
        <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
        <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">4180</span>
          <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
        <span class="hljs-attr">resources:</span>
          <span class="hljs-attr">limits:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">100m</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">128Mi</span>
          <span class="hljs-attr">requests:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">100m</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">128Mi</span>
</code></pre>
<p>After configuring and deploying Oauth2 Proxy with the values from your Dex instance, you will be able to use Dex as your identity provider.</p>
<h2 id="heading-final-result">Final Result</h2>
<p>With Dex IdP and Oauth2 Proxy configured and deployed, you can now test the example by navigating to the domain specified in the manifest file for the host attribute. For example, if you set “<a target="_blank" href="http://example.com">example.com</a>” as the host, visit <a target="_blank" href="http://example.com/"><strong>http://example.com/</strong></a> in your web browser.</p>
<p>After hitting the URL, you will be redirected to the Dex login page where you can choose an IdP to authenticate with from the options configured in Dex. The login page will look similar to this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677875112882/2267f307-a4ea-431a-9f26-f28d9dae79eb.png" alt class="image--center mx-auto" /></p>
<p>Select any one option to proceed with authentication. Once you have successfully logged in, you will be redirected back to the demo application, and you can begin to interact with it.</p>
<p>Congratulations, you have successfully integrated Dex IdP with Oauth2 Proxy! You can now use Dex to authenticate users to your web applications and APIs protected by Oauth2 Proxy.</p>
<h2 id="heading-authorization-using-dex-idp">Authorization using Dex IdP</h2>
<p>In addition to authentication, Dex also supports authorization through the use of groups. When the <code>groups</code> claim is configured for an IdP, it is possible to require a user to be a member of a particular group to be successfully authenticated in Dex. Inside the connector configuration YAML file, we can pass groups to which access should be granted. Here is an example of how this can be done for a Microsoft OIDC connection:</p>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">microsoft</span>
      <span class="hljs-attr">id:</span> <span class="hljs-string">microsoft</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">"Example Azure AD OIDC connection"</span>
      <span class="hljs-attr">config:</span>
        <span class="hljs-attr">clientID:</span> <span class="hljs-string">"&lt;client-id&gt;"</span>
        <span class="hljs-attr">clientSecret:</span> <span class="hljs-string">"&lt;client-secret&gt;"</span>
        <span class="hljs-attr">redirectURI:</span> <span class="hljs-string">https://&lt;your-domain&gt;/dex/callback</span>
        <span class="hljs-attr">tenant:</span> <span class="hljs-string">&lt;tenant-id&gt;</span>
        <span class="hljs-comment"># Mention which groups are allowed access</span>
        <span class="hljs-attr">groups:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">admin</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">developer</span>
<span class="hljs-string">...</span>
</code></pre>
<p>In this example, the <code>groups</code> property specifies that only users who are members of the <code>admin</code> or <code>developer</code> groups in the Azure AD instance will be allowed to access the protected resource. This way, you can perform authorization in Dex based on group membership.</p>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Keep your certificates and secrets secure</strong>: Certificates and secrets play a crucial role in securing your authentication flow. Ensure that you store them in a secure location and rotate them frequently.</p>
</li>
<li><p><strong>Use the latest versions</strong>: Always use the latest versions of Dex IdP and Oauth2 Proxy to take advantage of bug fixes and security patches.</p>
</li>
<li><p><strong>Test thoroughly</strong>: Test your integration thoroughly before deploying it in production to ensure that everything is working as expected.</p>
</li>
<li><p><strong>Use automation tools</strong>: Consider using automation tools to streamline the deployment and configuration of Dex IdP and Oauth2 Proxy, as it can save time and reduce the risk of manual errors.</p>
</li>
<li><p><strong>Keep your configuration simple</strong>: Avoid overcomplicating your configuration. Keep your configuration simple and easy to maintain, and only include the necessary features.</p>
</li>
</ol>
<p>By following these best practices, you can ensure that your Dex IdP and Oauth2 Proxy integration is secure, reliable, and easy to maintain.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, integrating Dex and OAuth2 Proxy provides a secure and flexible solution for authenticating and authorizing users accessing your applications. Dex provides a centralized authentication service for your organization, while OAuth2 Proxy allows you to easily add authentication to your applications without needing to modify their code.</p>
<p>By following the steps outlined in this guide, you should now have a good understanding of how to integrate Dex and OAuth2 Proxy in your Kubernetes cluster. Remember to follow best practices when implementing this solution, such as regularly updating and securing your configurations, and testing thoroughly before deploying in production.</p>
<p>Overall, integrating Dex and OAuth2 Proxy can greatly enhance the security and usability of your applications, and enable your organization to better manage access control for your resources.</p>
<p>To explore other approaches for securing applications in a Kubernetes cluster, you can check out our previous blog post on Authentication &amp; Authorization in Kubernetes Cluster — <a target="_blank" href="https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster"><strong>https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster</strong></a>.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p>Dex official documentation: <a target="_blank" href="https://dexidp.io/docs/"><strong>https://dexidp.io/docs/</strong></a></p>
</li>
<li><p>Oauth2 Proxy official documentation: <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/"><strong>https://oauth2-proxy.github.io/oauth2-proxy/</strong></a></p>
</li>
<li><p>Kubernetes official documentation: <a target="_blank" href="https://kubernetes.io/docs/home/"><strong>https://kubernetes.io/docs/home/</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Authentication & Authorization in Kubernetes - Using Oauth2 Proxy as Authentication Proxy]]></title><description><![CDATA["OAuth 2.0 and OpenID Connect (OIDC) have become the de facto standards for authentication and authorization in modern web applications and APIs. In the world of Kubernetes, these technologies provide a powerful framework for securing access to your ...]]></description><link>https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-using-oauth2-proxy-as-authentication-proxy</link><guid isPermaLink="true">https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-using-oauth2-proxy-as-authentication-proxy</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[OAuth2]]></category><category><![CDATA[nginx]]></category><dc:creator><![CDATA[Aditya Sutar]]></dc:creator><pubDate>Sun, 26 Feb 2023 18:14:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677328246658/8484bdcd-dcb5-4edd-9d0e-2fad61400c9b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"OAuth 2.0 and OpenID Connect (OIDC) have become the de facto standards for authentication and authorization in modern web applications and APIs. In the world of Kubernetes, these technologies provide a powerful framework for securing access to your cluster resources and applications." - Jeff Atwood, co-founder of Stack Overflow</p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>Securing a Kubernetes cluster involves implementing authentication and authorization at either the ingress layer or the application layer. Authenticating (and sometimes authorizing) users at the ingress layer can be more efficient, as it offloads authentication logic from applications. Multiple approaches exist for implementing ingress-level authentication and authorization, and one of the most popular options is to use an external authentication proxy. Oauth2 proxy is a powerful and open-source authentication proxy that can simplify the implementation of secure authentication and authorization in Kubernetes. In this article, we are going to see the integration of Oauth2 Proxy with the NGINX ingress controller (both open source and NGINX plus version).</p>
<h2 id="heading-why-oauth2-proxy">Why Oauth2 Proxy?</h2>
<p>Oauth2 Proxy provides a simple and configurable way to authenticate users using OAuth2 providers such as Google, GitHub, and Okta. It also offers authorization features based on email validation, domain check or group membership. OAuth2 Proxy is containerized, making it easy to deploy and manage in Kubernetes clusters. Additionally, it's open-source software with a thriving community that consistently updates and maintains the project.</p>
<h2 id="heading-how-does-oauth2-proxy-work">How does Oauth2 Proxy work?</h2>
<p><img src="https://oauth2-proxy.github.io/oauth2-proxy/assets/images/architecture-08b382c30c02b227fa4c86cb158b600e.png" alt class="image--center mx-auto" /></p>
<p><em>source -</em> <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/assets/images/architecture-08b382c30c02b227fa4c86cb158b600e.png"><em>https://oauth2-proxy.github.io/oauth2-proxy/</em></a></p>
<ol>
<li><p>When a user tries to access a protected resource, the NGINX ingress controller sends the request to OAuth2 Proxy to check if the user is authenticated.</p>
</li>
<li><p>OAuth2 Proxy checks for a session cookie in the request, and if present, verifies the user's session details and returns a successful response.</p>
</li>
<li><p>If the session cookie is not present, OAuth2 Proxy redirects the user to the login page of the configured IdP (such as Google or GitHub).</p>
</li>
<li><p>The user logs in to the IdP and is redirected back to OAuth2 Proxy, which receives the user's information from the IdP.</p>
</li>
<li><p>OAuth2 Proxy creates a new session for the user using this information and sets a session cookie in the response.</p>
</li>
<li><p>The NGINX ingress controller receives the successful response from OAuth2 Proxy and allows the user to access the requested resource.</p>
</li>
</ol>
<h2 id="heading-installation-and-configuration-of-oauth2-proxy">Installation and Configuration of Oauth2 Proxy</h2>
<p>There are multiple ways to install Oauth2 Proxy, you can check them out at https://oauth2-proxy.github.io/oauth2-proxy/docs/. Here we are going with Kubernetes manifest files.</p>
<p>Create a new file <code>oauth2-proxy.yaml</code> and paste the following manifest into it. Make sure to change values annotated with comments according to your IdP configuration.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">oauth2-proxy-ns</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">args:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--provider=oidc</span>
        <span class="hljs-comment"># if using azure provide tenant id, other wise remove line below</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--azure-tenant=&lt;tenant-id&gt;</span> <span class="hljs-comment"># replace with your tenant id</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--oidc-issuer-url=&lt;issuer-url&gt;</span> <span class="hljs-comment"># replace with your OIDC IdP's issuer url</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--scope=openid</span> <span class="hljs-string">groups</span> <span class="hljs-string">profile</span> <span class="hljs-string">email</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--email-domain=*</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--upstream=static://200</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">--http-address=0.0.0.0:4180</span>
        <span class="hljs-attr">env:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_CLIENT_ID</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">&lt;client-id&gt;</span> <span class="hljs-comment"># replace with client id</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_CLIENT_SECRET</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">&lt;client-secret&gt;</span> <span class="hljs-comment"># replace with client secret</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OAUTH2_PROXY_COOKIE_SECRET</span>
          <span class="hljs-attr">value:</span> <span class="hljs-string">"bVbMfxlt8Wmq4E1OYTICqS_AZHTeVDUEdFP5LGbY05c"</span> <span class="hljs-comment"># replace with value of: python -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">quay.io/oauth2-proxy/oauth2-proxy:latest</span>
        <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
        <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">4180</span>
          <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
        <span class="hljs-attr">resources:</span>
          <span class="hljs-attr">limits:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">100m</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">128Mi</span>
          <span class="hljs-attr">requests:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">100m</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">128Mi</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">oauth2-proxy-ns</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">ports:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">http</span>
    <span class="hljs-attr">port:</span> <span class="hljs-number">4180</span>
    <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
    <span class="hljs-attr">targetPort:</span> <span class="hljs-number">4180</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">k8s-app:</span> <span class="hljs-string">oauth2-proxy</span>

<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">networking.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Ingress</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">oauth2-proxy-ns</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-comment"># For ingress-nginx (open source nginx ingress controller) only.</span>
    <span class="hljs-attr">nginx.ingress.kubernetes.io/proxy-body-size:</span> <span class="hljs-string">"2000m"</span>
    <span class="hljs-attr">nginx.ingress.kubernetes.io/proxy-buffer-size:</span> <span class="hljs-string">"32k"</span>
    <span class="hljs-comment"># For nginx-ingress (NGINX plus ingress controller) only.</span>
    <span class="hljs-attr">nginx.org/client-max-body-size:</span> <span class="hljs-string">"2000m"</span>
    <span class="hljs-attr">nginx.org/proxy-buffer-size:</span> <span class="hljs-string">"32k"</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">ingressClassName:</span> <span class="hljs-string">nginx</span>
  <span class="hljs-attr">rules:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">host:</span> <span class="hljs-string">"example.com"</span> <span class="hljs-comment"># change to your domain</span>
    <span class="hljs-attr">http:</span>
      <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/oauth2</span>
        <span class="hljs-attr">pathType:</span> <span class="hljs-string">Prefix</span>
        <span class="hljs-attr">backend:</span>
          <span class="hljs-attr">service:</span>
            <span class="hljs-attr">name:</span> <span class="hljs-string">oauth2-proxy</span>
            <span class="hljs-attr">port:</span>
              <span class="hljs-attr">number:</span> <span class="hljs-number">4180</span>
</code></pre>
<p>There are several important modifications to make:</p>
<ul>
<li><p><code>azure-tenant</code>: If you're using Azure as your identity provider, you'll need to specify the tenant ID of your Azure account. If you're not using Azure, you can remove this line from the manifest.</p>
</li>
<li><p><code>oidc-issuer-url</code>: The issuer URL is typically specified in your identity provider's portal. For example, the issuer URL for Azure is <a target="_blank" href="https://sts.windows.net/%3Ctenant-id%3E/"><code>https://sts.windows.net/&lt;tenant-id&gt;/</code></a>.</p>
</li>
<li><p><code>OAUTH2_PROXY_CLIENT_ID</code>: This is the client ID provided by your identity provider. For example, in Azure, your client ID will be the application ID of the enterprise application you created.</p>
</li>
<li><p><code>OAUTH2_PROXY_CLIENT_SECRET</code>: This is the client secret provided/generated by your identity provider. For example, in Azure, you can create a secret in the Enterprise application by going to the Certificates and Secrets section and providing it here as the client secret.</p>
</li>
<li><p><code>OAUTH2_PROXY_COOKIE_SECRET</code>: This secret is used during cookie data encryption. You can provide a random secret, or generate one by running the following command on a Python-installed machine:</p>
</li>
</ul>
<pre><code class="lang-bash">python -c <span class="hljs-string">'import os,base64;print(base64.urlsafe_b64encode(os.urandom(32)).decode())'</span>
</code></pre>
<ul>
<li><p><code>host</code>: Change the hostname to your specific domain name.</p>
</li>
<li><p>Make sure to use annotations specified for your particular version of the NGINX Ingress Controller. These annotations are helpful when the cookie size is larger than usual. For example, Azure’s cookies are often larger than normal.</p>
</li>
</ul>
<p>To deploy OAuth2 Proxy in your Kubernetes cluster, simply run the following command:</p>
<pre><code class="lang-bash">kubectl apply -f oauth2-proxy.yaml
</code></pre>
<p>Once deployed, OAuth2 Proxy will be hosted at “<a target="_blank" href="http://example.com/oauth2">http://example.com/oauth2</a>".</p>
<p>For more information on configuring OAuth2 Proxy to work with your specific identity provider, check out the official documentation at <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider">https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider</a>.</p>
<h2 id="heading-configuration-of-nginx-ingress-controller">Configuration of NGINX Ingress Controller</h2>
<p>Now that you have successfully installed and configured Oauth2 Proxy, it's time to configure the NGINX ingress controller. The NGINX ingress controller comes in two versions: the open-source version (commonly referred to as ingress-nginx) and the plus version (commonly referred to as nginx-ingress). Both versions offer similar base features, but the plus version includes additional features and an SLA, making it suitable for production use.</p>
<p>To enable authentication with Oauth2 Proxy, the NGINX ingress controller provides several annotations that can be used to integrate Oauth2 Proxy as an external authentication proxy. These annotations are applied per ingress, which means that you can use different authentication methods for different applications. For this example, create a new file called <code>demo-app.yaml</code> and paste the following manifest into it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">demo-app-ns</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">demo-app</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">demo-app</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">demo-app</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">nginx</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
        <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">http</span>
          <span class="hljs-attr">containerPort:</span> <span class="hljs-number">80</span>
        <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">IfNotPresent</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app-svc</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">demo-app-ns</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">demo-app</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">demo-app</span>
  <span class="hljs-attr">ports:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">targetPort:</span> <span class="hljs-number">80</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">networking.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Ingress</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">nginx.ingress.kubernetes.io/auth-url:</span> <span class="hljs-string">"https://$host/oauth2/auth"</span>
    <span class="hljs-attr">nginx.ingress.kubernetes.io/auth-signin:</span> <span class="hljs-string">"https://$host/oauth2/start?rd=$escaped_request_uri"</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app-ingress</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">demo-app-ns</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">ingressClassName:</span> <span class="hljs-string">nginx</span>
  <span class="hljs-attr">rules:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">host:</span> <span class="hljs-string">"example.com"</span>
    <span class="hljs-attr">http:</span>
      <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>
        <span class="hljs-attr">pathType:</span> <span class="hljs-string">Prefix</span>
        <span class="hljs-attr">backend:</span>
          <span class="hljs-attr">service:</span>
            <span class="hljs-attr">name:</span> <span class="hljs-string">demo-app-svc</span>
            <span class="hljs-attr">port:</span>
              <span class="hljs-attr">number:</span> <span class="hljs-number">80</span>
</code></pre>
<ul>
<li><p><a target="_blank" href="http://nginx.ingress.kubernetes.io/auth-url"><strong>nginx.ingress.kubernetes.io/auth-url</strong></a>: This annotation specifies the URL where the ingress controller will forward authentication requests. In our example, we set it to Oauth2 Proxy’s <code>/auth</code> endpoint, which returns a <code>202 Accepted</code> or <code>401 Unauthorized</code> response.</p>
</li>
<li><p><a target="_blank" href="http://nginx.ingress.kubernetes.io/auth-signin"><strong>nginx.ingress.kubernetes.io/auth-signin</strong></a>: This annotation specifies the URL where users will be redirected when authentication is required. In our example, we redirect users to the <code>/start</code> endpoint, where Oauth2 Proxy will begin the Oauth cycle and authenticate the user.</p>
</li>
</ul>
<p>To deploy the demo application, execute the following command:</p>
<pre><code class="lang-bash">kubectl apply -f demo-app.yaml
</code></pre>
<p>This will deploy the demo application in your Kubernetes cluster and make it accessible at <a target="_blank" href="http://example.com">http://example.com</a>.</p>
<h2 id="heading-final-result">Final Result</h2>
<p>With the NGINX ingress controller and demo application configured, we can now test out our example. Navigate to the domain you specified in the manifest file for the host attribute. For instance, if you set “<a target="_blank" href="http://example.com">example.com</a>” as the host, visit <a target="_blank" href="http://example.com/">http://example.com/</a> in your web browser.</p>
<p>Upon accessing the application URL, you will be automatically redirected to the login page of your Identity Provider (IdP) to authenticate. For example, the Azure AD IdPs login page would be like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677331050441/d6c34f31-995e-41b3-80dc-bd5b01b2a9e3.png" alt class="image--center mx-auto" /></p>
<p>Once you have successfully logged in, you will be redirected back to the demo application, and you can begin to interact with it.</p>
<p>Congratulations, you have successfully integrated OAuth2 Proxy with the NGINX ingress controller to provide secure external access to your Kubernetes application.</p>
<h2 id="heading-authorization-using-oauth2-proxy">Authorization using Oauth2 Proxy</h2>
<p>OAuth2 proxy provides powerful authorization features that can help you to restrict access to your applications. You can use one or more of the following query parameters in the /auth endpoint to configure the authorization settings:</p>
<p><strong>allowed_emails</strong>: This parameter allows you to specify a comma-separated list of email addresses that are allowed to access the application. For example:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">nginx.ingress.kubernetes.io/auth-url:</span> <span class="hljs-string">“https://$host/oauth2/auth?allowed_emails=dev1@example.com,dev2@example.com"</span>
</code></pre>
<p>When a user logs in, their email address is checked against the list of allowed email addresses. If it matches one of the email addresses on the list, access is granted.</p>
<p><strong>allowed_email_domains</strong>: This parameter allows you to specify a comma-separated list of email domains that are allowed to access the application. For example:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">nginx.ingress.kubernetes.io/auth-url:</span> <span class="hljs-string">“https://$host/oauth2/auth?allowed_email_domains=example.com,foobar.com"</span>
</code></pre>
<p>When a user logs in, their email domain is checked against the list of allowed email domains. If it matches one of the domains on the list, access is granted.</p>
<p><strong>allowed_groups</strong>: This parameter allows you to specify a comma-separated list of groups whose members are allowed to access the application. For example:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">nginx.ingress.kubernetes.io/auth-url:</span> <span class="hljs-string">“https://$host/oauth2/auth?allowed_groups=admin,mgmt"</span>
</code></pre>
<p>After a user logs in, the OAuth2 proxy checks if they are a member of one of the allowed groups. If they are a member of one of the groups on the list, access is granted.</p>
<p>By using one or more of these parameters, you can control who has access to your applications and ensure that only authorized users can log in.</p>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p>Keep OAuth2 Proxy and Nginx Ingress Controller up-to-date with the latest releases to ensure the security of your environment.</p>
</li>
<li><p>Use separate OAuth2 Proxy instances for different Kubernetes namespaces or applications to increase the security of your environment.</p>
</li>
<li><p>Use a dedicated service account for OAuth2 Proxy and grant it only the necessary permissions to limit its access to the cluster.</p>
</li>
<li><p>Avoid storing OAuth2 Proxy secrets, such as client ID and secret, in plain text files or environment variables. Use Kubernetes secrets to store them securely.</p>
</li>
<li><p>Use HTTPS for all communication between OAuth2 Proxy and Nginx Ingress Controller to protect against eavesdropping and data tampering.</p>
</li>
<li><p>Use appropriate timeouts and limits for OAuth2 Proxy and Nginx Ingress Controller to prevent denial-of-service attacks and optimize resource utilization.</p>
</li>
<li><p>When configuring OAuth2 Proxy authorization, choose the most restrictive method possible for your use case. For example, use email validation instead of allowing all users from a particular domain, or use group membership validation instead of allowing all authenticated users.</p>
</li>
<li><p>When using group membership validation, use unique group names that are specific to your application. Avoid using common group names like “admin” or “user” as this can cause conflicts with other applications or services.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, we have seen how to secure Kubernetes applications using OAuth2 Proxy and Nginx Ingress Controller. By integrating external authentication and authorization mechanisms, we can enhance the security of our applications and protect them from unauthorized access. We have learned how to install and configure OAuth2 Proxy and Nginx Ingress Controller, how to use annotations to customize their behaviour, and how to apply best practices to ensure the security of our environment.</p>
<p>Implementing these techniques will help you to build a robust and secure Kubernetes infrastructure that meets the highest standards of security and compliance. We encourage you to experiment with these tools and explore their full potential to create a safe and efficient environment for your applications. Thank you for reading, and we hope this article has been helpful to you!</p>
<p>To explore other approaches for securing applications in a Kubernetes cluster, you can check out our previous blog post on Authentication &amp; Authorization in Kubernetes Cluster — <a target="_blank" href="https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster">https://adityaoo7.hashnode.dev/authentication-authorization-in-kubernetes-cluster</a>.</p>
<h2 id="heading-references">References</h2>
<ol>
<li><p>The official OAuth2 Proxy documentation: <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/">https://oauth2-proxy.github.io/oauth2-proxy/</a></p>
</li>
<li><p>The official Nginx Ingress Controller documentation: <a target="_blank" href="https://docs.nginx.com/nginx-ingress-controller/intro/overview/">https://docs.nginx.com/nginx-ingress-controller/intro/overview/</a></p>
</li>
<li><p>The Open Source Nginx Ingress Controller documentation: <a target="_blank" href="https://kubernetes.github.io/ingress-nginx/">https://kubernetes.github.io/ingress-nginx/</a></p>
</li>
<li><p>Oauth2 Proxy endpoints: <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/docs/features/endpoints">https://oauth2-proxy.github.io/oauth2-proxy/docs/features/endpoints</a></p>
</li>
<li><p>Kubernetes documentation on securing your cluster: <a target="_blank" href="https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/">https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Authentication & Authorization in Kubernetes Cluster]]></title><description><![CDATA[“Security is not an afterthought, it should be the foundation of any technology implementation. In the world of Kubernetes, strong authentication is key to ensuring the safety and integrity of your application and data.” — Joe Beda, Co-creator of Kub...]]></description><link>https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-cluster</link><guid isPermaLink="true">https://blog.thisisaditya.com/authentication-authorization-in-kubernetes-cluster</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[authentication]]></category><category><![CDATA[nginx]]></category><category><![CDATA[Auth0]]></category><category><![CDATA[authorization]]></category><dc:creator><![CDATA[Aditya Sutar]]></dc:creator><pubDate>Sun, 19 Feb 2023 07:56:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792844237/3add7c4d-9d11-4a1a-990d-f66da6e817af.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>“Security is not an afterthought, it should be the foundation of any technology implementation. In the world of Kubernetes, strong authentication is key to ensuring the safety and integrity of your application and data.” — Joe Beda, Co-creator of Kubernetes</p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>Kubernetes is a powerful platform that allows you to manage and deploy containerized applications. However, with all applications running on the same cluster, managing access control can be a challenge. This is where authentication &amp; authorization (or ‘authN/authZ’) comes in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792008367/7c3a5629-47e0-4a7f-bf85-4fd7f4b5e652.png" alt class="image--center mx-auto" /></p>
<p>By authenticating &amp; authorizing users before accessing applications, you can manage access control more efficiently and save time by avoiding the need to implement authentication logic in every application. Additionally, authenticating users at the perimeter — or the edge of the cluster — ensures that traffic flowing inside the cluster is only from authenticated users, eliminating traffic from unauthenticated user requests and responses.</p>
<p>In this blog, we’ll explore the importance of authN/authZ in Kubernetes and the different ways available to secure your applications with authentication and authorization.</p>
<h2 id="heading-authentication-amp-authorization">Authentication &amp; Authorization</h2>
<p>In a Kubernetes deployment, authentication and authorization can be configured using various methods such as X.509 client certificates, static passwords, or integrating with an IdP. By leveraging an IdP, you can centralize user management and ensure that your Kubernetes cluster is integrated with your existing identity and access management (IAM) infrastructure.</p>
<p>Two popular options are SAML and OIDC, which are often used as single sign-on (SSO) solutions. SAML handles both authentication and authorization by using a SAML Assertion token, while OIDC is built on top of the OAuth 2.0 protocol. With OIDC, the OIDC layer handles authentication (who the user is) and OAuth 2.0 handles authorization (what the user can access) by using an access token.</p>
<h2 id="heading-approaches-to-kubernetes-authnauthz">Approaches to Kubernetes AuthN/AuthZ</h2>
<p>There are several perimeter solutions available for securing applications deployed in Kubernetes, including Ingress controllers and Service Mesh. In this article, we will focus on the Nginx Ingress controller, both the open-source and Nginx Plus versions. We will explore four approaches that can be used to integrate AuthN/AuthZ with the Nginx Ingress controller to secure our applications:</p>
<p><strong>Approach 1</strong> — Oauth2-proxy as an authentication proxy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792265028/b4b41e10-2700-4b14-a7d6-83360430074c.png" alt class="image--center mx-auto" /></p>
<p>This approach leverages the Oauth2-proxy (<a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/">https://oauth2-proxy.github.io/oauth2-proxy/</a>) to handle authentication and pass authenticated requests to the Nginx Ingress controller. Oauth2-proxy is a reverse proxy that provides authentication service using integrating various Oauth2.0-supported IdPs. Advantages of this approach include:</p>
<ul>
<li><p>Easy integration with any OIDC IdP</p>
</li>
<li><p>Access control based on email or group</p>
</li>
</ul>
<p>However, there are some disadvantages to consider:</p>
<ul>
<li><p>*Support for only OIDC IdP, not SAML</p>
</li>
<li><p>*Integration with only a single IdP at a time</p>
</li>
<li><p>Need to manage this service and its security</p>
</li>
</ul>
<p>*there’s a solution for this, refer to Approach 5</p>
<p><strong>Approach 2</strong> — Oauth2-proxy with Dex.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792393237/4e5c7fa9-623b-46a3-88dd-d0a31f9eecc6.png" alt class="image--center mx-auto" /></p>
<p>This approach builds upon Approach 1 by integrating the dex IdP (<a target="_blank" href="https://dexidp.io/">https://dexidp.io/</a>) to allow for more advanced authentication scenarios. Dex is an identity service that provides authN/authZ to applications by integrating multiple IdPs of various types. Advantages of this approach include:</p>
<ul>
<li><p>Support for multi-IdP (multi-tenancy) scenarios</p>
</li>
<li><p>More granular access control</p>
</li>
</ul>
<p>However, there are some disadvantages to consider:</p>
<ul>
<li><p>Support for SAML is deprecated</p>
</li>
<li><p>Need to manage this service and its security</p>
</li>
</ul>
<p><strong>Approach 3</strong> — Nginx Plus Ingress Controller with OIDC policy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792445217/3e347aaa-0d58-4e52-8ade-bafa76860647.png" alt class="image--center mx-auto" /></p>
<p>This approach integrates an OIDC provider directly within the ingress controller itself by utilizing the OIDC policy provided by nginx plus ingress controller. Advantages of this approach include:</p>
<ul>
<li><p>Authentication is directly integrated into the ingress controller, so no need to manage separate services for authN</p>
</li>
<li><p>A robust way to integrate with the ingress controller</p>
</li>
</ul>
<p>However, there are some disadvantages to consider:</p>
<ul>
<li><p>*Support for only OIDC IdP, not SAML.</p>
</li>
<li><p>*Integration with only a single IdP at a time.</p>
</li>
<li><p>No access control based on the user’s role or group</p>
</li>
</ul>
<p>*there’s a solution for this, refer to Approach 5</p>
<p><strong>Approach 4</strong> — Nginx Plus Ingress Controller with Istio Service Mesh.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792526546/503788b3-bbeb-4c5a-ab46-59d3cee6268a.png" alt class="image--center mx-auto" /></p>
<p>This approach provides additional features, such as RBAC authorization, traffic management, and observability, in addition to the advantages of Approach 3 by using Istio service mesh (<a target="_blank" href="https://istio.io/">https://istio.io/</a>). Advantages of this approach include:</p>
<ul>
<li><p>All of the advantages of Approach 3</p>
</li>
<li><p>Access control based on roles</p>
</li>
<li><p>More features such as traffic management and observability</p>
</li>
</ul>
<p>However, there is one disadvantage to consider:</p>
<ul>
<li><p>*Support for only OIDC IdP, not SAML.</p>
</li>
<li><p>*Integration with only a single IdP at a time.</p>
</li>
<li><p>Need to manage both the ingress controller and service mesh.</p>
</li>
</ul>
<p>*there’s a solution for this, refer to Approach 5</p>
<p><strong>Approach 5</strong> — Auth0 as External Identity Provider</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676792580783/1ce36aa8-4ab4-49ea-a4bb-b8b98ec73db3.png" alt class="image--center mx-auto" /></p>
<p>This approach involves using Auth0 (<a target="_blank" href="https://auth0.com/">https://auth0.com/</a>) as an external identity provider to handle user authentication and authorization. Auth0 supports multiple IdPs, including OIDC and SAML, providing flexibility in choosing an appropriate IdP. Advantages of this approach include:</p>
<ul>
<li><p>Allows you to connect to multiple IdPs</p>
</li>
<li><p>Supports a wide range of IdPs</p>
</li>
</ul>
<p>However, there is one disadvantage to consider:</p>
<ul>
<li>Need to manage authorization at client side — Ingress Controller / Oauth2-Proxy.</li>
</ul>
<h2 id="heading-best-practices">Best Practices</h2>
<p>Based on the approaches discussed, here are some best practices for configuring Kubernetes authentication using Nginx Ingress:</p>
<ol>
<li><p><strong>Use a supported IdP</strong>: While all of the approaches discussed support OIDC, Approach 1 and Approach 2 are the only ones that support SAML. When selecting an IdP, ensure that it is supported by the approach you choose.</p>
</li>
<li><p><strong>Secure your authentication proxies</strong>: With Approach 1 and Approach 2, you will be managing a separate authentication proxy. It’s important to secure this service to ensure that unauthorized users cannot access your applications.</p>
</li>
<li><p><strong>Consider your access control needs</strong>: Access control is an important aspect of authentication, and different approaches provide different levels of granularity. Consider your access control needs when selecting an approach.</p>
</li>
<li><p><strong>Leverage the Nginx Plus OIDC policy</strong>: Approach 3 is a robust way to integrate with the ingress controller, but it has limited access control capabilities. Consider using the Nginx Plus OIDC policy for a more streamlined approach to authentication.</p>
</li>
<li><p><strong>Use a service mesh for additional features</strong>: Approach 4 provides additional features like RBAC authorization, traffic management, and observability. Consider using a service mesh if these features are important for your use case.</p>
</li>
<li><p><strong>Regularly review and update your authentication configuration</strong>: As with any security configuration, it’s important to regularly review and update your authentication configuration to ensure that it remains secure and up-to-date with the latest best practices.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, securing applications in Kubernetes requires careful consideration of different authentication and authorization options, as well as understanding solutions like Ingress controllers and Service Mesh. We explored different approaches for integrating AuthN/AuthZ, each with its own advantages and disadvantages. When selecting a solution, it’s important to consider the specific needs of your application and deployment. As a best practice, we recommend using a centralized identity provider for managing user authentication and access control across your Kubernetes cluster.</p>
<p>Thank you for reading! In upcoming articles, we will explore the implementation of each approach in greater detail. Stay tuned for more insights on this topic!</p>
<h2 id="heading-references">References</h2>
<p>Configure Oauth2-Proxy with IdPs — <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider">https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider</a></p>
<p>Connect Oauth2-Proxy with Dex — <a target="_blank" href="https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider#dex">https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider#dex</a></p>
<p>Nginx Plus Ingress Controller OIDC Policy — <a target="_blank" href="https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#oidc">https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#oidc</a></p>
<p>Integrate Nginx Ingress Controller with Istio Service Mesh — <a target="_blank" href="https://docs.nginx.com/nginx-ingress-controller/tutorials/nginx-ingress-istio/">https://docs.nginx.com/nginx-ingress-controller/tutorials/nginx-ingress-istio/</a></p>
<p>SSO with Auth0 in nginx plus — <a target="_blank" href="https://docs.nginx.com/nginx/deployment-guides/single-sign-on/auth0/">https://docs.nginx.com/nginx/deployment-guides/single-sign-on/auth0/</a></p>
<p>AuthN/AuthZ using Auth0 and Istio — <a target="_blank" href="https://auth0.com/blog/securing-kubernetes-clusters-with-istio-and-auth0/">https://auth0.com/blog/securing-kubernetes-clusters-with-istio-and-auth0/</a></p>
]]></content:encoded></item></channel></rss>